Try complaining if alarm is null
[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();
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 public class Clock: zavai.Service
52 {
53     protected time_t last_gps_time;
54     protected time_t last_gps_time_system_time;
55     protected time_t last_system_time;
56         protected dynamic DBus.Object gps_time;
57     protected uint system_time_timeout;
58     protected time_t last_minute;
59     protected time_t chosen_time;
60     protected SourceType chosen_type;
61
62         protected dynamic DBus.Object otimed_alarm;
63         protected dynamic DBus.Object notification;
64     protected SList<Alarm> alarms;
65
66     // Ticks once a minute
67     public signal void minute_changed(long time, SourceType source);
68
69         public Clock()
70         {
71                 name = "clock";
72         alarms = null;
73         last_minute = 0;
74         last_gps_time = 0;
75         last_gps_time_system_time = 0;
76         last_system_time = time_t();
77         chosen_time = last_system_time;
78         
79                 gps_time = zavai.registry.sbus.get_object(
80                         "org.freesmartphone.ogpsd",
81                         "/org/freedesktop/Gypsy",
82                         "org.freedesktop.Gypsy.Time");
83
84         // FSO alarm system
85             otimed_alarm = zavai.registry.sbus.get_object(
86                         "org.freesmartphone.otimed",
87                         "/org/freesmartphone/Time/Alarm",
88                         "org.freesmartphone.Time.Alarm");
89         if (otimed_alarm == null)
90             zavai.log.error("ALARM IS NULL");
91         notification = zavai.registry.sbus.get_object(
92             "org.freesmartphone",
93             "org/freesmartphone/Notification",
94             "org.freesmartphone.Notification");
95         notification.Alarm += on_alarm;
96         }
97
98     public void schedule(Alarm a)
99     {
100         alarms.insert_sorted(a, alarm_compare);
101         zavai.log.info("Next alarm: " + alarms.data.label + " at " + Time.local(alarms.data.deadline).to_string());
102         otimed_reschedule();
103     }
104
105     private void otimed_reschedule()
106     {
107         if (alarms != null)
108         {
109             try {
110                 otimed_alarm.ClearAlarm(zavai.registry.bus_name);
111             } catch (Error e) {
112                 zavai.log.error("Cannot clear alarms: " + e.message);
113             }
114             try {
115                 otimed_alarm.SetAlarm(zavai.registry.bus_name, alarms.data.deadline);
116             } catch (Error e) {
117                 zavai.log.error("Cannot reschedule alarms: " + e.message);
118             }
119         }
120     }
121
122     private void on_alarm()
123     {
124         check_alarms();
125     }
126
127     public void check_alarms()
128     {
129         last_system_time = time_t();
130         update_time();
131         while (alarms != null && alarms.data.deadline <= chosen_time)
132         {
133             Alarm a = alarms.data;
134             alarms.remove(a);
135             zavai.log.info("Triggering " + a.label);
136             a.trigger();
137         }
138
139         otimed_reschedule();
140     }
141
142         private void on_gps_time(dynamic DBus.Object pos, int t)
143         {
144         if (t == 0)
145         {
146             last_gps_time_system_time = 0;
147             update_time();
148         } else {
149             last_gps_time = (time_t)t;
150             last_gps_time_system_time = time_t();
151             update_time();
152         }
153         }
154
155     private bool on_system_time()
156     {
157         last_system_time = time_t();
158         update_time();
159         return true;
160     }
161
162     private void update_time()
163     {
164         if (last_gps_time_system_time + 10 > last_system_time)
165         {
166             chosen_time = last_gps_time;
167             chosen_type = SourceType.GPS;
168         }
169         else
170         {
171             chosen_time = last_system_time;
172             chosen_type = SourceType.SYSTEM;
173         }
174         if (chosen_time / 60 != last_minute)
175         {
176             last_minute = chosen_time / 60;
177             minute_changed(chosen_time, chosen_type);
178         }
179     }
180
181         /// Request GPS resource
182         public override void start()
183         {
184                 if (started) return;
185
186         system_time_timeout = Timeout.add(5000, on_system_time);
187                 gps_time.TimeChanged += on_gps_time;
188         last_system_time = time_t();
189         update_time();
190
191                 base.start();
192         }
193
194         public override void stop()
195         {
196                 if (!started) return;
197
198         Source.remove(system_time_timeout);
199                 gps_time.TimeChanged -= on_gps_time;
200
201                 base.stop();
202         }
203 }
204
205 public Clock clock = null;
206
207 public void init()
208 {
209     clock = new Clock();
210
211         zavai.registry.register_service(clock);
212 }
213
214 }
215 }