changeset 486:5afd4568a2f6

Wip, timers are hard
author Louis Opter <kalessin@kalessin.fr>
date Sat, 09 Jul 2016 23:40:12 -0700
parents 0062162318d2
children 630881a97943
files add_power_transition.patch
diffstat 1 files changed, 94 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/add_power_transition.patch	Sat Jul 09 19:17:07 2016 -0700
+++ b/add_power_transition.patch	Sat Jul 09 23:40:12 2016 -0700
@@ -1,5 +1,5 @@
 # HG changeset patch
-# Parent  b711b804c1c54e31174c68fc13e3227967f16786
+# Parent  a3f7765c23828e1238a17d89252445769fb928db
 Add a transition argument to the power functions
 
 Unlike LIFX's implementation, lightsd will properly get the bulbs to
@@ -59,7 +59,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/core/effect.c
-@@ -0,0 +1,243 @@
+@@ -0,0 +1,281 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -114,13 +114,83 @@
 +}
 +
 +static void
++lgtd_effect_timer_callback(struct lgtd_timer *timer, union lgtd_timer_ctx ctx)
++{
++    (void)timer;
++
++    struct lgtd_effect *effect = (struct lgtd_effect *)ctx.as_ptr;
++
++    lgtd_time_mono_t now = lgtd_time_monotonic_msecs();
++
++    if (effect->apply_left < 0) {
++        lgtd_info(
++            "ignoring extraneous timer callback for effect %s, id=%p, "
++            "now=%ju, apply_left=%d",
++            effect->name, effect, (uintmax_t)now, effect->apply_left
++        );
++        return;
++    }
++
++    if (effect->ends_at && now > effect->ends_at
++        && now - effect->ends_at > LGTD_EFFECT_STALE_THRESHOLD_MS) {
++        // check if the effect is stale (e.g: the computer went to sleep)
++        // and stop it if it is the case:
++        lgtd_warnx(
++            "stopping stale periodic effect %s created %jums ago, "
++            "id=%p, duration=%jums",
++            effect->name, (uintmax_t)(now - effect->created_at), effect,
++            (uintmax_t)(effect->ends_at - effect->created_at)
++        );
++        lgtd_effect_stop(effect);
++        return;
++    }
++
++    lgtd_info(
++        "calling apply callback for effect %s, id=%p, apply_left=%d",
++        effect->name, effect, effect->apply_left
++    );
++    assert(effect->apply_cb);
++    effect->apply_cb(effect);
++    effect->apply_cnt++;
++    if (effect->apply_left == 0) {
++        lgtd_timer_stop(effect->timer);
++        effect->timer = NULL;
++    }
++    effect->apply_left--;
++}
++
++static void
 +lgtd_effect_duration_callback(struct lgtd_timer *timer, union lgtd_timer_ctx ctx)
 +{
 +    (void)timer;
 +
 +    struct lgtd_effect *effect = (struct lgtd_effect *)ctx.as_ptr;
++
++    lgtd_time_mono_t now = lgtd_time_monotonic_msecs();
++
++    if (now < effect->ends_at
++        && effect->ends_at - now >= LGTD_EFFECT_TIMER_RESCHEDULE_THRESHOLD_MS) {
++        lgtd_time_mono_t timeout = effect->ends_at - now;
++        lgtd_info(
++            "re-scheduling duration callback for effect %s, id=%p in %jums "
++            "(now=%ju, ends_at=%ju)",
++            effect->name, effect, (uintmax_t)timeout,
++            (uintmax_t)now, (uintmax_t)effect->ends_at
++        );
++        struct timeval tv = LGTD_MSECS_TO_TIMEVAL(timeout);
++        lgtd_timer_reschedule(timer, &tv);
++        if (effect->timer && effect->apply_left >= 0) {
++            lgtd_info(
++                "force-calling timer callback after rescheduling the duration "
++                "callback for effect %s, id=%p",
++                effect->name, effect
++            );
++            lgtd_effect_timer_callback(effect->timer, ctx);
++        }
++        return;
++    }
++
 +    if (effect->duration_cb) {
-+        lgtd_time_mono_t now = lgtd_time_monotonic_msecs();
 +        if (effect->ends_at < now || // let's not go negative with unsigned ints
 +            effect->ends_at - now < LGTD_EFFECT_STALE_THRESHOLD_MS) {
 +            lgtd_info(
@@ -140,43 +210,6 @@
 +    lgtd_effect_stop(effect);
 +}
 +
-+static void
-+lgtd_effect_timer_callback(struct lgtd_timer *timer, union lgtd_timer_ctx ctx)
-+{
-+    (void)timer;
-+
-+    struct lgtd_effect *effect = (struct lgtd_effect *)ctx.as_ptr;
-+
-+    lgtd_time_mono_t now = lgtd_time_monotonic_msecs();
-+    if (effect->ends_at && now > effect->ends_at) {
-+        // check if the effect is stale (e.g: the computer went to sleep)
-+        // and stop it if it is the case:
-+        if (now - effect->ends_at > LGTD_EFFECT_STALE_THRESHOLD_MS) {
-+            lgtd_warnx(
-+                "stopping stale periodic effect %s created %jums ago, "
-+                "id=%p, duration=%jums",
-+                effect->name, (uintmax_t)(now - effect->created_at), effect,
-+                (uintmax_t)(effect->ends_at - effect->created_at)
-+            );
-+            lgtd_effect_stop(effect);
-+            return;
-+        }
-+        // if a duration callback pending then just stop the periodic timer:
-+        if (event_pending(effect->duration_timer->event, EV_TIMEOUT, NULL)) {
-+            lgtd_timer_stop(effect->timer);
-+            effect->timer = NULL;
-+            return;
-+        }
-+    }
-+
-+    lgtd_info(
-+        "calling apply callback for effect %s, id=%p", effect->name, effect
-+    );
-+    assert(effect->apply_cb);
-+    effect->apply_cb(effect);
-+    effect->apply_cnt++;
-+}
-+
 +struct lgtd_effect *
 +lgtd_effect_start(const char *name,
 +                  int duration,
@@ -236,6 +269,11 @@
 +            );
 +            goto err;
 +        }
++        if (duration && (timer_flags & LGTD_TIMER_PERSISTENT)) {
++            effect->apply_left = duration / timer_ms;
++        } else if (!(timer_flags & LGTD_TIMER_PERSISTENT)) {
++            effect->apply_left = 1;
++        }
 +        timer_flags |= LGTD_TIMER_EVENT_PRIORITY_HIGHEST;
 +        effect->timer = lgtd_timer_start(
 +            timer_flags, timer_ms, lgtd_effect_timer_callback, timer_ctx
@@ -270,12 +308,12 @@
 +                name, effect, (uintmax_t)effect->created_at
 +            );
 +        }
-+        if (effect->apply_cb) {
-+            effect->apply_cb(effect);
++        if (apply_cb) {
++            apply_cb(effect);
 +        }
 +        if (!duration) { // instant effect
-+            if (effect->duration_cb) {
-+                effect->duration_cb(effect);
++            if (duration_cb) {
++                duration_cb(effect);
 +            }
 +            lgtd_effect_stop(effect);
 +            return NULL;
@@ -307,7 +345,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/core/effect.h
-@@ -0,0 +1,61 @@
+@@ -0,0 +1,64 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -341,14 +379,17 @@
 +    void                            (*duration_cb)(const struct lgtd_effect *);
 +    struct lgtd_timer               *timer;
 +    void                            (*apply_cb)(const struct lgtd_effect *);
-+    // number of times apply_cb has been called (therefore this will be 0 the
-+    // first time apply_cb is called):
-+    uint32_t                        apply_cnt;
++    // how many times apply_cb will be called again or 0 if your effect
++    // is infinite (duration == 0 and timer_ms > 0) or doesn't use a
++    // timer (timer_ms == 0):
++    int                             apply_left;
++    int                             apply_cnt;
 +    union lgtd_effect_ctx           ctx;
 +};
 +LIST_HEAD(lgtd_effect_list, lgtd_effect);
 +
 +enum { LGTD_EFFECT_STALE_THRESHOLD_MS = 2000 };
++enum { LGTD_EFFECT_TIMER_RESCHEDULE_THRESHOLD_MS = 30 };
 +
 +extern struct lgtd_effect_list lgtd_effects;
 +
@@ -1057,7 +1098,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/effects/power_transition.c
-@@ -0,0 +1,345 @@
+@@ -0,0 +1,346 @@
 +// Copyright (c) 2015, Louis Opter <kalessin@kalessin.fr>
 +//
 +// This file is part of lighstd.
@@ -1280,7 +1321,8 @@
 +            continue;
 +        }
 +
-+        if (!bulb->expected_power_on) {
++        if (!bulb->expected_power_on
++            && bulb->state.power == LGTD_LIFX_POWER_OFF) {
 +            // only set the brightness to 0 if the bulbs is off at the
 +            // beginning of the transition, otherwise it's gonna flicker:
 +            struct lgtd_lifx_packet_light_color pkt_set_brightness_to_zero = {
@@ -1436,7 +1478,7 @@
 +// flicker, so let's delay the restore for a bit once the transition is done:
 +enum {
 +    // the feels: http://diablo2.judgehype.com/screenshots/presentation/Erreursvf/baguette-magiques-en-os.jpg
-+    LGTD_EFFECT_POWER_TRANSITION_OFF_RESTORE_LIGHT_COLOR_DELAY_MSECS = 250
++    LGTD_EFFECT_POWER_TRANSITION_OFF_RESTORE_LIGHT_COLOR_DELAY_MSECS = 300
 +};
 +
 +enum { LGTD_EFFECT_POWER_TRANSITION_TIMER_MS = 250 };
@@ -1454,7 +1496,7 @@
 +struct lgtd_effect_power_transition_ctx {
 +    struct lgtd_effect_power_transition_target_list targets;
 +    // how many times the apply_cb will be called
-+    uint32_t                                        periods;
++    int                                             periods;
 +    // This doesn't include the delay to restore the light color after a
 +    // power off:
 +    lgtd_time_mono_t                                ends_at;