Point to new device name (we all love gratuitous changes)
[gregoa/zavai.git] / src / clock.vala
1 /*
2  * clock - clock resource for zavai
3  *
4  * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace clock {
25
26 public enum SourceType
27 {
28         SYSTEM,
29         GPS
30 }
31
32 public class Alarm : Object
33 {
34         public signal void trigger(Alarm a);
35
36         public time_t deadline;
37         public string label;
38
39         public Alarm(time_t deadline, string label)
40         {
41                 this.deadline = deadline;
42                 this.label = label;
43         }
44 }
45
46 private int alarm_compare(void* a, void* b)
47 {
48         return (int)(((Alarm*)a)->deadline - ((Alarm*)b)->deadline);
49 }
50
51 [DBus (name = "org.freesmartphone.Notification")]
52 public class AlarmNotification : Object {
53         public void Alarm () {
54                 clock.check_alarms();
55         }
56 }
57
58 public class Clock: zavai.Service
59 {
60         protected time_t last_gps_time;
61         protected time_t last_gps_time_system_time;
62         protected time_t last_system_time;
63         protected dynamic DBus.Object gps_time;
64         protected uint system_time_timeout;
65         protected time_t last_minute;
66         protected time_t chosen_time;
67         protected SourceType chosen_type;
68         protected AlarmNotification listener;
69
70         protected dynamic DBus.Object otimed_alarm;
71         protected dynamic DBus.Object rtc;
72         protected SList<Alarm> alarms;
73
74         // Ticks once a minute
75         public signal void minute_changed(long time, SourceType source);
76         public signal void schedule_changed();
77
78         public Clock()
79         {
80                 name = "clock";
81                 alarms = null;
82                 listener = new AlarmNotification();
83                 last_minute = 0;
84                 last_gps_time = 0;
85                 last_gps_time_system_time = 0;
86                 last_system_time = time_t();
87                 chosen_time = last_system_time;
88
89                 gps_time = zavai.registry.sbus.get_object(
90                                 "org.freesmartphone.ogpsd",
91                                 "/org/freedesktop/Gypsy",
92                                 "org.freedesktop.Gypsy.Time");
93
94                 // FSO alarm system
95                 otimed_alarm = zavai.registry.sbus.get_object(
96                                 "org.freesmartphone.otimed",
97                                 "/org/freesmartphone/Time/Alarm",
98                                 "org.freesmartphone.Time.Alarm");
99
100                 rtc = zavai.registry.sbus.get_object(
101                                 "org.freesmartphone.odeviced",
102                                 "/org/freesmartphone/Device/RTC/0",
103                                 "org.freesmartphone.Device.RTC");
104
105                 zavai.registry.sbus.register_object("/", listener);
106
107         }
108
109         public Alarm? next_alarm()
110         {
111                 if (alarms == null)
112                         return null;
113                 return alarms.data;
114         }
115
116         public void schedule(Alarm a)
117         {
118                 alarms.insert_sorted(a, alarm_compare);
119                 otimed_reschedule();
120         }
121
122         private void otimed_reschedule()
123         {
124                 if (alarms != null)
125                 {
126                         zavai.log.info("Scheduling next alarm: " + alarms.data.label + " at " + Time.local(alarms.data.deadline).to_string());
127                         zavai.log.info("Scheduling at abs " + "%d".printf((int)alarms.data.deadline));
128
129                         try {
130                                 otimed_alarm.ClearAlarm(zavai.registry.bus_name);
131                         } catch (Error e) {
132                                 zavai.log.error("Cannot clear alarms: " + e.message);
133                         }
134                         try {
135                                 otimed_alarm.SetAlarm(zavai.registry.bus_name, (int)alarms.data.deadline);
136                         } catch (Error e) {
137                                 zavai.log.error("Cannot reschedule alarms: " + e.message);
138                         }
139
140                         string t = rtc.GetCurrentTime();
141                         stderr.printf("Current time: %d, RTC time: %s\n", (int)time_t(), t);
142                         t = rtc.GetWakeupTime();
143                         stderr.printf("Scheduled alarm: %d, RTC wakeup time: %s\n", (int)alarms.data.deadline, t);
144                 } else
145                         zavai.log.info("No alarms left to reschedule");
146                 schedule_changed();
147         }
148
149         public void check_alarms()
150         {
151                 last_system_time = time_t();
152                 update_time();
153                 while (alarms != null && alarms.data.deadline <= chosen_time)
154                 {
155                         Alarm a = alarms.data;
156                         alarms.remove(a);
157                         zavai.log.info("Triggering " + a.label);
158                         a.trigger(a);
159                 }
160
161                 otimed_reschedule();
162         }
163
164         private void on_gps_time(dynamic DBus.Object pos, int t)
165         {
166                 if (t == 0)
167                 {
168                         last_gps_time_system_time = 0;
169                         update_time();
170                 } else {
171                         last_gps_time = (time_t)t;
172                         last_gps_time_system_time = time_t();
173                         update_time();
174                 }
175         }
176
177         private bool on_system_time()
178         {
179                 last_system_time = time_t();
180                 update_time();
181                 return true;
182         }
183
184         private void update_time()
185         {
186                 if (last_gps_time_system_time + 10 > last_system_time)
187                 {
188                         chosen_time = last_gps_time;
189                         chosen_type = SourceType.GPS;
190                 }
191                 else
192                 {
193                         chosen_time = last_system_time;
194                         chosen_type = SourceType.SYSTEM;
195                 }
196                 if (chosen_time / 60 != last_minute)
197                 {
198                         last_minute = chosen_time / 60;
199                         minute_changed(chosen_time, chosen_type);
200                 }
201         }
202
203         /// Request GPS resource
204         public override void start()
205         {
206                 if (started) return;
207
208                 system_time_timeout = Timeout.add(5000, on_system_time);
209                 gps_time.TimeChanged += on_gps_time;
210                 last_system_time = time_t();
211                 update_time();
212
213                 base.start();
214         }
215
216         public override void stop()
217         {
218                 if (!started) return;
219
220                 Source.remove(system_time_timeout);
221                 gps_time.TimeChanged -= on_gps_time;
222
223                 base.stop();
224         }
225 }
226
227 public Clock clock = null;
228
229 public void init()
230 {
231         clock = new Clock();
232
233         zavai.registry.register_service(clock);
234 }
235
236 }
237 }