Mercurial > louis > mq > lightsd
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;