Merge branch 'master' into alarm
[gregoa/zavai.git] / src / clock.vala
index 8504f918b717120f770fd0716da0c67006357e0f..bcd25e7fb2b9f94495cd20d787893aace7671bd6 100644 (file)
@@ -25,170 +25,228 @@ namespace clock {
 
 public enum SourceType
 {
 
 public enum SourceType
 {
-    SYSTEM,
-    GPS
+       SYSTEM,
+       GPS
 }
 
 }
 
+/*
+TODO: schedule alarms via at
+
+Uses the 'z' queue.
+
+atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
+at -c id  can be used to query a job, parsing its contents (which can have
+          comments or variables being set)
+zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
+
+Alarm needs to be able to serialize itself to an at invocation and to
+deserialize itself from the output of at -c
+
+Alarm needs to deserialize also a job with no special markers whatsoever: a
+generic at job.
+
+
+
+refresh_alarms()
+{
+       oldtime = next_alarm ? next_alarm.time : 0
+       next_alarm = the first alarm from atq
+       if (oldtime != next_alarm.time)
+       {
+               remove existing triggers
+                 (triggers can be skipped if we don't need to support non-zavai alarms)
+               schedule a trigger calling refresh_alarms() at next_alarm.time + 30 seconds
+                 (triggers can be skipped if we don't need to support non-zavai alarms)
+       }
+}
+
+at clock constructor: refresh_alarms()
+inotifywait -e close /usr/bin/at -> refresh_alarms()  (shows when someone has just used at)
+  (can be skipped if we don't need to support non-zavai alarms)
+at alarm triggered through zavai: refresh_alarms()
+
+
+*/
+
+
 public class Alarm : Object
 {
 public class Alarm : Object
 {
-    public signal void trigger();
+       // Notify of an alarm being triggered
+       //public static signal void trigger(string label);
 
 
-    public time_t deadline;
-    public string label;
+       // Schedule with at
+       public static void schedule(time_t deadline, string label);
 
 
-    public Alarm(time_t deadline, string label)
-    {
-        this.deadline = deadline;
-        this.label = label;
-    }
+       // Get the label of the job with the given at ID
+       public static string getLabel(int atID);
 }
 
 private int alarm_compare(void* a, void* b)
 {
 }
 
 private int alarm_compare(void* a, void* b)
 {
-    return (int)(((Alarm*)a)->deadline - ((Alarm*)b)->deadline);
+       return (int)(((Alarm*)a)->deadline - ((Alarm*)b)->deadline);
+}
+
+[DBus (name = "org.freesmartphone.Notification")]
+public class AlarmNotification : Object {
+       public void Alarm () {
+               clock.check_alarms();
+       }
 }
 
 public class Clock: zavai.Service
 {
 }
 
 public class Clock: zavai.Service
 {
-    protected time_t last_gps_time;
-    protected time_t last_gps_time_system_time;
-    protected time_t last_system_time;
+       protected time_t last_gps_time;
+       protected time_t last_gps_time_system_time;
+       protected time_t last_system_time;
        protected dynamic DBus.Object gps_time;
        protected dynamic DBus.Object gps_time;
-    protected uint system_time_timeout;
-    protected time_t last_minute;
-    protected time_t chosen_time;
-    protected SourceType chosen_type;
+       protected uint system_time_timeout;
+       protected time_t last_minute;
+       protected time_t chosen_time;
+       protected SourceType chosen_type;
+       protected AlarmNotification listener;
 
        protected dynamic DBus.Object otimed_alarm;
 
        protected dynamic DBus.Object otimed_alarm;
-       protected dynamic DBus.Object notification;
-    protected SList<Alarm> alarms;
+       protected dynamic DBus.Object rtc;
+       protected SList<Alarm> alarms;
 
 
-    // Ticks once a minute
-    public signal void minute_changed(long time, SourceType source);
+       // Ticks once a minute
+       public signal void minute_changed(long time, SourceType source);
+       public signal void schedule_changed();
 
        public Clock()
        {
 
        public Clock()
        {
-               name = "clock";
-        alarms = null;
-        last_minute = 0;
-        last_gps_time = 0;
-        last_gps_time_system_time = 0;
-        last_system_time = time_t();
-        chosen_time = last_system_time;
-        
+               Object(name: "clock");
+               alarms = null;
+               listener = new AlarmNotification();
+               last_minute = 0;
+               last_gps_time = 0;
+               last_gps_time_system_time = 0;
+               last_system_time = time_t();
+               chosen_time = last_system_time;
+
                gps_time = zavai.registry.sbus.get_object(
                gps_time = zavai.registry.sbus.get_object(
-                       "org.freesmartphone.ogpsd",
-                       "/org/freedesktop/Gypsy",
-                       "org.freedesktop.Gypsy.Time");
-
-        // FSO alarm system
-           otimed_alarm = zavai.registry.sbus.get_object(
-                       "org.freesmartphone.otimed",
-                       "/org/freesmartphone/Time/Alarm",
-                       "org.freesmartphone.Time.Alarm");
-        if (otimed_alarm == null)
-            zavai.log.error("ALARM IS NULL");
-        notification = zavai.registry.sbus.get_object(
-            "org.freesmartphone",
-            "org/freesmartphone/Notification",
-            "org.freesmartphone.Notification");
-        notification.Alarm += on_alarm;
+                               "org.freesmartphone.ogpsd",
+                               "/org/freedesktop/Gypsy",
+                               "org.freedesktop.Gypsy.Time");
+
+               // FSO alarm system
+               otimed_alarm = zavai.registry.sbus.get_object(
+                               "org.freesmartphone.otimed",
+                               "/org/freesmartphone/Time/Alarm",
+                               "org.freesmartphone.Time.Alarm");
+
+               rtc = zavai.registry.sbus.get_object(
+                               "org.freesmartphone.odeviced",
+                               "/org/freesmartphone/Device/RTC/0",
+                               "org.freesmartphone.Device.RealtimeClock");
+
+               zavai.registry.sbus.register_object("/", listener);
+
+       }
+
+       public Alarm? next_alarm()
+       {
+               if (alarms == null)
+                       return null;
+               return alarms.data;
+       }
+
+       public void schedule(Alarm a)
+       {
+               alarms.insert_sorted(a, alarm_compare);
+               otimed_reschedule();
+       }
+
+       private void otimed_reschedule()
+       {
+               if (alarms != null)
+               {
+                       zavai.log.info("Scheduling next alarm: " + alarms.data.label + " at " + Time.local(alarms.data.deadline).to_string());
+                       zavai.log.info("Scheduling at abs " + "%d".printf((int)alarms.data.deadline));
+
+                       try {
+                               otimed_alarm.ClearAlarm(zavai.registry.bus_name);
+                       } catch (Error e) {
+                               zavai.log.error("Cannot clear alarms: " + e.message);
+                       }
+                       try {
+                               otimed_alarm.SetAlarm(zavai.registry.bus_name, (int)alarms.data.deadline);
+                       } catch (Error e) {
+                               zavai.log.error("Cannot reschedule alarms: " + e.message);
+                       }
+
+                       int t = rtc.GetCurrentTime();
+                       stderr.printf("Current time: %d, RTC time: %d\n", (int)time_t(), t);
+                       t = rtc.GetWakeupTime();
+                       stderr.printf("Scheduled alarm: %d, RTC wakeup time: %d\n", (int)alarms.data.deadline, t);
+               } else
+                       zavai.log.info("No alarms left to reschedule");
+               schedule_changed();
        }
 
        }
 
-    public void schedule(Alarm a)
-    {
-        alarms.insert_sorted(a, alarm_compare);
-        zavai.log.info("Next alarm: " + alarms.data.label + " at " + Time.local(alarms.data.deadline).to_string());
-        otimed_reschedule();
-    }
-
-    private void otimed_reschedule()
-    {
-        stderr.printf("ALARM: %p BN %s\n", otimed_alarm, zavai.registry.bus_name);
-        if (alarms != null)
-        {
-            try {
-                otimed_alarm.ClearAlarm(zavai.registry.bus_name);
-            } catch (Error e) {
-                zavai.log.error("Cannot clear alarms: " + e.message);
-            }
-            try {
-                otimed_alarm.SetAlarm(zavai.registry.bus_name, (int)alarms.data.deadline);
-            } catch (Error e) {
-                zavai.log.error("Cannot reschedule alarms: " + e.message);
-            }
-        }
-    }
-
-    private void on_alarm()
-    {
-stderr.printf("ON ALARM\n");
-        check_alarms();
-    }
-
-    public void check_alarms()
-    {
-        last_system_time = time_t();
-        update_time();
-        while (alarms != null && alarms.data.deadline <= chosen_time)
-        {
-            Alarm a = alarms.data;
-            alarms.remove(a);
-            zavai.log.info("Triggering " + a.label);
-            a.trigger();
-        }
-
-        otimed_reschedule();
-    }
+       public void check_alarms()
+       {
+               last_system_time = time_t();
+               update_time();
+               while (alarms != null && alarms.data.deadline <= chosen_time)
+               {
+                       Alarm a = alarms.data;
+                       alarms.remove(a);
+                       zavai.log.info("Triggering " + a.label);
+                       a.trigger(a);
+               }
+
+               otimed_reschedule();
+       }
 
        private void on_gps_time(dynamic DBus.Object pos, int t)
        {
 
        private void on_gps_time(dynamic DBus.Object pos, int t)
        {
-        if (t == 0)
-        {
-            last_gps_time_system_time = 0;
-            update_time();
-        } else {
-            last_gps_time = (time_t)t;
-            last_gps_time_system_time = time_t();
-            update_time();
-        }
+               if (t == 0)
+               {
+                       last_gps_time_system_time = 0;
+                       update_time();
+               } else {
+                       last_gps_time = (time_t)t;
+                       last_gps_time_system_time = time_t();
+                       update_time();
+               }
        }
 
        }
 
-    private bool on_system_time()
-    {
-        last_system_time = time_t();
-        update_time();
-        return true;
-    }
-
-    private void update_time()
-    {
-        if (last_gps_time_system_time + 10 > last_system_time)
-        {
-            chosen_time = last_gps_time;
-            chosen_type = SourceType.GPS;
-        }
-        else
-        {
-            chosen_time = last_system_time;
-            chosen_type = SourceType.SYSTEM;
-        }
-        if (chosen_time / 60 != last_minute)
-        {
-            last_minute = chosen_time / 60;
-            minute_changed(chosen_time, chosen_type);
-        }
-    }
+       private bool on_system_time()
+       {
+               last_system_time = time_t();
+               update_time();
+               return true;
+       }
+
+       private void update_time()
+       {
+               if (last_gps_time_system_time + 10 > last_system_time)
+               {
+                       chosen_time = last_gps_time;
+                       chosen_type = SourceType.GPS;
+               }
+               else
+               {
+                       chosen_time = last_system_time;
+                       chosen_type = SourceType.SYSTEM;
+               }
+               if (chosen_time / 60 != last_minute)
+               {
+                       last_minute = chosen_time / 60;
+                       minute_changed(chosen_time, chosen_type);
+               }
+       }
 
        /// Request GPS resource
        public override void start()
        {
                if (started) return;
 
 
        /// Request GPS resource
        public override void start()
        {
                if (started) return;
 
-        system_time_timeout = Timeout.add(5000, on_system_time);
+               system_time_timeout = Timeout.add(5000, on_system_time);
                gps_time.TimeChanged += on_gps_time;
                gps_time.TimeChanged += on_gps_time;
-        last_system_time = time_t();
-        update_time();
+               last_system_time = time_t();
+               update_time();
 
                base.start();
        }
 
                base.start();
        }
@@ -197,7 +255,7 @@ stderr.printf("ON ALARM\n");
        {
                if (!started) return;
 
        {
                if (!started) return;
 
-        Source.remove(system_time_timeout);
+               Source.remove(system_time_timeout);
                gps_time.TimeChanged -= on_gps_time;
 
                base.stop();
                gps_time.TimeChanged -= on_gps_time;
 
                base.stop();
@@ -208,7 +266,7 @@ public Clock clock = null;
 
 public void init()
 {
 
 public void init()
 {
-    clock = new Clock();
+       clock = new Clock();
 
        zavai.registry.register_service(clock);
 }
 
        zavai.registry.register_service(clock);
 }