From fcc37515c5b4c6430845c24334485a4c3166a794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 8 Apr 2023 20:05:21 +0200 Subject: [PATCH] menu sliding, add knob prescaller --- Core/Src/app_gui.c | 155 +++++++++++++++++++++++++++++++-------------- Core/Src/app_gui.h | 2 +- 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/Core/Src/app_gui.c b/Core/Src/app_gui.c index 52eaf76..85fcfc5 100644 --- a/Core/Src/app_gui.c +++ b/Core/Src/app_gui.c @@ -3,6 +3,7 @@ */ #include +#include #include "app_gui.h" #include "app_heater.h" #include "app_buzzer.h" @@ -35,15 +36,19 @@ typedef void (*menu_callback_t)(int choice); */ static void screen_menu(GuiEvent event, const char **options, menu_callback_t cb); + + static struct State { float oven_temp; //float soc_temp; // manual mode controls int set_temp; - int set_temp_wheel; bool heater_enabled; + bool down_prescaller; + bool up_prescaller; + bool pushed; bool paint_needed; uint32_t last_tick_event; @@ -53,8 +58,17 @@ static struct State { bool initial_pushed; screen_t screen; - int menu_pos; - int menu_len; + + union { + struct menu_state { + int pos; + int len; + uint32_t change_time; + uint32_t slide_end_time; + uint16_t text_slide; + uint8_t tick_counter; + } menu; + } page; } s_app = {}; /** Get push time (while held) */ @@ -111,11 +125,33 @@ void app_task_gui(void *argument) } osMessageQueueGet(guiEventQueHandle, &message, NULL, ticks_remain); + if (message == GUI_EVENT_KNOB_PLUS) { + if (s_app.up_prescaller) { + s_app.up_prescaller = 0; + // let this through + } else { + // consume this + s_app.down_prescaller = 0; + s_app.up_prescaller = 1; + message = GUI_EVENT_NONE; + } + } else if (message == GUI_EVENT_KNOB_MINUS) { + if (s_app.down_prescaller) { + s_app.down_prescaller = 0; + // let this through + } else { + // consume this + s_app.up_prescaller = 0; + s_app.down_prescaller = 1; + message = GUI_EVENT_NONE; + } + } + uint32_t tickNow = xTaskGetTickCount(); // 10ms tick event if (tickNow - s_app.last_tick_event > pdMS_TO_TICKS(10)) { - s_app.screen(GUI_EVENT_TICK); + s_app.screen(GUI_EVENT_SCREEN_TICK); s_app.last_tick_event = tickNow; } @@ -161,6 +197,8 @@ void app_task_gui(void *argument) static void switch_screen(screen_t pScreen, bool init) { s_app.initial_pushed = s_app.pushed; s_app.screen = pScreen; + // clear the union field + memset(&s_app.page, 0, sizeof(s_app.page)); request_paint(); if (init) { @@ -190,6 +228,8 @@ static void input_sound_effect() static const char* main_menu_opts[] = { "Manual mode", "Calibration", + "Moderately long text", + "Very very long text that slides", NULL }; @@ -215,23 +255,9 @@ static void screen_home(GuiEvent event) // --------- manual mode screen --------------- -/** Calc set temperature from the current knob position */ -static void manual_calc_set_temp() -{ - int clamped = s_app.set_temp_wheel; - if (clamped < 0) { - clamped = 0; - } - s_app.set_temp = (clamped / 2) * 5; - if (s_app.set_temp > MAX_TEMP) { - s_app.set_temp = MAX_TEMP; - } - - app_heater_set_target((float) s_app.set_temp); -} - static void screen_manual(GuiEvent event) { + bool temp_changed = false; if (event == GUI_EVENT_SCREEN_INIT) { return; } @@ -258,23 +284,25 @@ static void screen_manual(GuiEvent event) break; case GUI_EVENT_KNOB_PLUS: - if (s_app.set_temp < MAX_TEMP) { - input_sound_effect(); - s_app.set_temp_wheel++; - manual_calc_set_temp(); - request_paint(); + if (s_app.set_temp <= MAX_TEMP - 5) { + s_app.set_temp += 5; + temp_changed = true; } break; case GUI_EVENT_KNOB_MINUS: - if (s_app.set_temp > 0) { - input_sound_effect(); - s_app.set_temp_wheel--; - manual_calc_set_temp(); - request_paint(); + if (s_app.set_temp >= 5) { + s_app.set_temp -= 5; + temp_changed = true; } break; } + + if (temp_changed) { + input_sound_effect(); + app_heater_set_target((float) s_app.set_temp); + request_paint(); + } } // --------------------------- @@ -308,48 +336,83 @@ static void screen_manual_menu(GuiEvent event) // ------------------------ static void screen_menu(GuiEvent event, const char **options, menu_callback_t cb) { + bool menu_changed = false; + uint32_t tickNow = xTaskGetTickCount(); + + struct menu_state *menu = &s_app.page.menu; + switch (event) { case GUI_EVENT_SCREEN_INIT: - s_app.menu_pos = 0; - s_app.menu_len = 0; + menu->pos = 0; + menu->len = 0; + menu->change_time = tickNow; + menu->text_slide = 0; const char **opt = options; while (*opt) { - s_app.menu_len++; + menu->len++; opt++; } + menu->pos = menu->len - 1; // FIXME temporary, for debug + break; + + case GUI_EVENT_SCREEN_TICK: + if (tickNow - menu->change_time >= pdMS_TO_TICKS(500)) { + uint32_t textlen = strlen(options[menu->pos]) * 6; + if (textlen >= FBW - 2) { + if (textlen - menu->text_slide > FBW - 2) { + menu->text_slide += 1; + if (textlen - menu->text_slide > FBW - 2) { + menu->slide_end_time = tickNow; + } + } else if (tickNow - menu->slide_end_time >= pdMS_TO_TICKS(500)) { + menu->change_time = tickNow; + menu->slide_end_time = 0; + menu->text_slide = 0; + } + request_paint(); + } + } break; case GUI_EVENT_PAINT: - for (int i = 0; i < s_app.menu_len; i++) { - fbcolor_t color = s_app.menu_pos != i; + for (int i = 0; i < menu->len; i++) { + bool current = menu->pos == i; + fbcolor_t color = !current; fbpos_t y = 27 + i * 10; - fb_rect(0, y, 64, 10, !color); - fb_text(1, y + 1, options[i], FONT_5X7, color); + fb_rect(0, y, FBW, 10, !color); + fb_text(1 - (current ? menu->text_slide : 0), y + 1, options[i], FONT_5X7, color); // ensure the text doesnt escape the screen - fb_vline(63, y, 10, !color); + fb_vline(FBW - 1, y, 10, !color); + fb_vline(0, y, 10, !color); } break; // the button is held! release is what activates the button case GUI_EVENT_KNOB_RELEASE: input_sound_effect(); - cb(s_app.menu_pos); + cb(menu->pos); break; case GUI_EVENT_KNOB_PLUS: - if (s_app.menu_pos < s_app.menu_len - 1) { - s_app.menu_pos++; - input_sound_effect(); - request_paint(); + if (menu->pos < menu->len - 1) { + menu->pos++; + menu_changed = true; } break; case GUI_EVENT_KNOB_MINUS: - if (s_app.menu_pos > 0) { - s_app.menu_pos--; - input_sound_effect(); - request_paint(); + if (menu->pos > 0) { + menu->pos--; + menu_changed = true; } break; } + + if (menu_changed) { + menu->change_time = tickNow; + menu->text_slide = 0; + menu->slide_end_time = 0; + input_sound_effect(); + request_paint(); + } } diff --git a/Core/Src/app_gui.h b/Core/Src/app_gui.h index 768cdc5..62eed30 100644 --- a/Core/Src/app_gui.h +++ b/Core/Src/app_gui.h @@ -22,7 +22,7 @@ typedef enum GuiEvent { GUI_EVENT_SCREEN_INIT = 1, /// Time tick, used to carry timing to the screen functions. /// This tick has 10ms interval - GUI_EVENT_TICK = 2, + GUI_EVENT_SCREEN_TICK = 2, /// Knob rotate CW GUI_EVENT_KNOB_PLUS, /// Knob rotate CCW