From c6299b268da0599c2bbce3e71efb5398ffd0a808 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Sat, 21 Jan 2017 08:09:48 -0500 Subject: action.c must desist in calling set_cpu_frequency from a tick The function is neither reentrant nor ISR callable. Instead of using a ticked-based timeout, have the button driver provide the unboost after a delay when waiting for a button. HAVE_GUI_BOOST gets immediate boost after dequeuing any message, otherwise the queue has to have at least three messages waiting for it to trigger a boost-- essentially the behavior that existed but now combined in one place. Change-Id: I1d924702840f56a1a65abe41fa92b4e753c4e75a --- firmware/drivers/button.c | 106 +++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 35 deletions(-) (limited to 'firmware/drivers/button.c') diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index d47a486b43..fe9040cef8 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -371,21 +371,75 @@ static void button_tick(void) } #ifdef HAVE_ADJUSTABLE_CPU_FREQ +static bool button_boosted = false; +static long button_unboost_tick; +#define BUTTON_UNBOOST_TMO HZ + static void button_boost(bool state) { - static bool boosted = false; - - if (state && !boosted) + if (state) { - cpu_boost(true); - boosted = true; + button_unboost_tick = current_tick + BUTTON_UNBOOST_TMO; + + if (!button_boosted) + { + button_boosted = true; + cpu_boost(true); + } } - else if (!state && boosted) + else if (!state && button_boosted) { + button_boosted = false; cpu_boost(false); - boosted = false; } } + +static void button_queue_wait(struct queue_event *evp, int timeout) +{ + /* Loop once after wait time if boosted in order to unboost and wait the + full remaining time */ + do + { + int ticks = timeout; + + if (ticks == 0) /* TIMEOUT_NOBLOCK */ + ; + else if (ticks > 0) + { + if (button_boosted && ticks > BUTTON_UNBOOST_TMO) + ticks = BUTTON_UNBOOST_TMO; + + timeout -= ticks; + } + else /* TIMEOUT_BLOCK (ticks < 0) */ + { + if (button_boosted) + ticks = BUTTON_UNBOOST_TMO; + } + + queue_wait_w_tmo(&button_queue, evp, ticks); + if (evp->id != SYS_TIMEOUT) + { + /* GUI boost build gets immediate kick, otherwise at least 3 + messages had to be there */ + #ifndef HAVE_GUI_BOOST + if (queue_count(&button_queue) >= 2) + #endif + button_boost(true); + + break; + } + + if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick)) + button_boost(false); + } + while (timeout); +} +#else /* ndef HAVE_ADJUSTABLE_CPU_FREQ */ +static inline void button_queue_wait(struct queue_event *evp, int timeout) +{ + queue_wait_w_timeout(&button_queue, evp, timeout); +} #endif /* HAVE_ADJUSTABLE_CPU_FREQ */ int button_queue_count( void ) @@ -396,44 +450,26 @@ int button_queue_count( void ) long button_get(bool block) { struct queue_event ev; - int pending_count = queue_count(&button_queue); + button_queue_wait(&ev, block ? TIMEOUT_BLOCK : TIMEOUT_NOBLOCK); -#ifdef HAVE_ADJUSTABLE_CPU_FREQ - /* Control the CPU boost trying to keep queue empty. */ - if (pending_count == 0) - button_boost(false); - else if (pending_count > 2) - button_boost(true); -#endif - - if ( block || pending_count ) - { - queue_wait(&button_queue, &ev); - + if (ev.id == SYS_TIMEOUT) + ev.id = BUTTON_NONE; + else button_data = ev.data; - return ev.id; - } - - return BUTTON_NONE; + + return ev.id; } long button_get_w_tmo(int ticks) { - struct queue_event ev; - -#ifdef HAVE_ADJUSTABLE_CPU_FREQ - /* Be sure to keep boosted state. */ - if (!queue_empty(&button_queue)) - return button_get(true); - - button_boost(false); -#endif - - queue_wait_w_tmo(&button_queue, &ev, ticks); + struct queue_event ev; + button_queue_wait(&ev, ticks); + if (ev.id == SYS_TIMEOUT) ev.id = BUTTON_NONE; else button_data = ev.data; + return ev.id; } -- cgit v1.2.3