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 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)
{
- 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
{
- 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 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 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()
{
- 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(
- "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");
- 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()
- {
- if (alarms != null)
- {
- try {
- otimed_alarm.ClearAlarm((string)null);
- otimed_alarm.SetAlarm((string)null, alarms.data.deadline);
- } catch (Error e) {
- zavai.log.error("Cannot reschedule alarms: " + e.message);
- }
- }
- }
-
- private void on_alarm()
- {
- 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)
{
- 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;
- system_time_timeout = Timeout.add(5000, on_system_time);
+ system_time_timeout = Timeout.add(5000, on_system_time);
gps_time.TimeChanged += on_gps_time;
- last_system_time = time_t();
- update_time();
+ last_system_time = time_t();
+ update_time();
base.start();
}
{
if (!started) return;
- Source.remove(system_time_timeout);
+ Source.remove(system_time_timeout);
gps_time.TimeChanged -= on_gps_time;
base.stop();
public void init()
{
- clock = new Clock();
+ clock = new Clock();
zavai.registry.register_service(clock);
}