From 5b0b659002f961f6d9ee4b210cb2e6da3473ec47 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sat, 7 Feb 2026 22:54:19 +0000 Subject: [PATCH] Add screen (event/stack) abstraction --- src/badge_screen.c | 56 ++++++++++++++++++++++++ src/led.h | 2 + src/main.c | 106 +++++++++++++++++---------------------------- src/menu.c | 106 ++++++++++++++------------------------------- src/menu.h | 5 ++- src/screen.c | 36 +++++++++++++++ src/screen.h | 31 +++++++++++++ 7 files changed, 201 insertions(+), 141 deletions(-) create mode 100644 src/badge_screen.c create mode 100644 src/screen.c create mode 100644 src/screen.h diff --git a/src/badge_screen.c b/src/badge_screen.c new file mode 100644 index 0000000..71e4b58 --- /dev/null +++ b/src/badge_screen.c @@ -0,0 +1,56 @@ +#include + +#include "screen.h" +#include "led.h" +#include "wang.h" +#include "menu.h" + +static uint16_t badge_fb[44]; + +int image_index = 0; +int frame = 0; +int subframe = 99999; + +int anim_render(uint16_t *fb, int index, int frame); +static void badge_event(struct screen_event event) { + if (event.type == SE_TICK) { + if (!flash_header_valid) { + screen_push(&menu_screen); + return; + } + + subframe++; + if (subframe > 33 && flash_header_valid) { + screen_dirty = 1; + subframe = 0; + if (anim_render(badge_fb, image_index, frame++)) { + frame = 0; + } + } + } else if (event.type == SE_BUTTON_PRESS) { + if (event.data == 0) { + display_brightness = (display_brightness + 1) % 16; + } else if (event.data == 1) { + if (flash_header_valid) { + image_index++; + if (!flash_header.widths[image_index]) image_index = 0; + frame = 0; + subframe = 99999; + } + } + } else if (event.type == SE_BUTTON_HOLD) { + if (event.data == 0) { + display_brightness = (display_brightness + 15) % 16; + screen_push(&menu_screen); + } + } +} + +static void badge_draw(struct row_buf *buf) { + display_make_buf_all(badge_fb, buf); +} + +struct screen badge_screen = { + badge_draw, + badge_event, +}; diff --git a/src/led.h b/src/led.h index 298d8ca..1316798 100644 --- a/src/led.h +++ b/src/led.h @@ -1,5 +1,7 @@ #pragma once +#include + extern uint32_t pa_mask; extern uint32_t pb_mask; diff --git a/src/main.c b/src/main.c index 0c96327..3c3ebe9 100644 --- a/src/main.c +++ b/src/main.c @@ -12,8 +12,7 @@ #include "cdc.h" #include "wang.h" #include "platform.h" - -int anim_render(uint16_t *fb, int index, int frame); +#include "screen.h" enum usb_control_resp bl_handler(enum usb_control_state state) { if ((usb_control_request.bmRequestType & 0x7f) != 0x43) return USB_CONTROL_RESP_PASS; @@ -26,61 +25,10 @@ enum usb_control_resp bl_handler(enum usb_control_state state) { } -int button_was_pressed[BUTTON_COUNT] = {0}; +static int button_was_pressed[BUTTON_COUNT] = {0}; +static int button_hold[BUTTON_COUNT] = {0}; -int image_index = 0; - -int frame = 0; -int subframe = 99999; - -int main_handler(void) { - - #define TIMER(btn0, btn1, v, count) if (button_pressed[0] != btn0 || button_pressed[1] != btn1) { v = 0; } else if (v < count) { v += 1; } else - static int menu_timer = 0; - TIMER(1, 0, menu_timer, 500) { - display_brightness = (display_brightness + 15) % 16; - menu_timer = 0; - menu_switch(); - return 1; - } - - if (button_pressed[0] && !button_was_pressed[0]) { - display_brightness = (display_brightness + 1) % 16; - } - - if (button_pressed[1] && !button_was_pressed[1]) { - if (flash_header_valid) { - image_index++; - if (!flash_header.widths[image_index]) image_index = 0; - frame = 0; - subframe = 99999; - } - display_flip(); - } - - subframe++; - if (subframe > 33 && flash_header_valid) { - // approximately 30fps - subframe = 0; - - uint16_t fb[44]; - if (anim_render(fb, image_index, frame)) { - frame = 0; - } else { - frame++; - } - display_make_buf_all(fb, display_screen); - display_flip(); - } - - for (int i = 0; i < BUTTON_COUNT; i++) { - button_was_pressed[i] = button_pressed[i]; - } - - if (!flash_header_valid) return 1; - - return 0; -} +extern struct screen badge_screen; int main() { @@ -102,13 +50,14 @@ int main() PFIC_EnableIRQ(TMR3_IRQn); wang_init(); - main_handler(); usb_register_handler(bl_handler); usb_init(); ble_init(); + screen_push(&badge_screen); + while (1) { WWDG_SetCounter(0x7F); static int btldr_timer = 0; @@ -119,17 +68,42 @@ int main() btldr_timer = 0; } - static int cur_handler = 0; - if (cur_handler) { - cur_handler = menu_handler(); - if (!cur_handler) { - for (int i = 0; i < BUTTON_COUNT; i++) { - button_was_pressed[i] = button_pressed[i]; + struct screen_event ev = { + SE_TICK, + 0 + }; + current_screen->event_handler(ev); + + for (int i = 0; i < BUTTON_COUNT; i++) { + int is_pressed = button_pressed[i]; + if (button_was_pressed[i] && is_pressed) { + button_hold[i]++; + if (button_hold[i] == 500) { + ev.type = SE_BUTTON_HOLD; + ev.data = i; + current_screen->event_handler(ev); + } else if (button_hold[i] > 500) { + button_hold[i] = 501; } - subframe = 99999; + } else if (is_pressed && !button_was_pressed[i]) { + ev.type = SE_BUTTON_PRESS; + ev.data = i; + current_screen->event_handler(ev); + button_was_pressed[i] = 1; + button_hold[i] = 0; + } else if (!is_pressed && button_was_pressed[i]) { + ev.type = button_hold[i] >= 500 ? SE_BUTTON_RELEASE_HOLD : SE_BUTTON_RELEASE_SHORT; + ev.data = i; + current_screen->event_handler(ev); + button_was_pressed[i] = 0; } - } else - cur_handler = main_handler(); + } + + if (screen_dirty) { + screen_dirty = 0; + current_screen->draw_handler(display_screen); + display_flip(); + } TMOS_SystemProcess(); cdc_tick(); diff --git a/src/menu.c b/src/menu.c index 07f03ed..c5a0fed 100644 --- a/src/menu.c +++ b/src/menu.c @@ -9,6 +9,7 @@ #include "ble.h" #include "input.h" #include "wang.h" +#include "screen.h" #include "img/menu.xbm" @@ -53,11 +54,33 @@ static void render_xbm(uint8_t *bits, struct row_buf *b) { display_make_buf_all(fb, b); } -int menu_index = 0; +static int menu_index = 0; -static int was_button_pressed[BUTTON_COUNT] = {0}; - -void menu_render(void) { +static int menu_ticks = 0; +static void menu_event(struct screen_event event) { + if (event.type == SE_TICK) { + if (menu_ticks++ > 125) { + screen_dirty = 1; + } + } else if (event.type == SE_BUTTON_PRESS) { + if (event.data == 0) { + menu_index = (menu_index + 1) % 3; + if (!flash_header_valid && !menu_index) menu_index = 1; + screen_dirty = 1; + } else if (event.data == 1) { + if (menu_index == 0) { + screen_pop(); + return; + } else if (menu_index == 1) { + ble_toggle(); + screen_dirty = 1; + } else if (menu_index == 2) { + boop(); + } + } + } +} +static void menu_draw(struct row_buf *rb) { uint8_t buffer[(48 * 11) / 8]; memcpy(buffer, menu_bits, sizeof(buffer)); int invert_index = 1 + menu_index * 13; @@ -98,74 +121,11 @@ void menu_render(void) { } } - render_xbm(buffer, display_screen); - display_flip(); -} - -void menu_switch(void) { - for (int i = 0; i < BUTTON_COUNT; i++) { - was_button_pressed[i] = button_pressed[i]; - } - menu_index = flash_header_valid ? 0 : 1; - - menu_render(); -} - -int menu_handler(void) { - static int btldr_timer = 0; - static int render_ticks = 0; - render_ticks++; - - if (button_pressed[1] && button_pressed[0]) { - btldr_timer++; - if (btldr_timer > 2000) asm volatile("j 0x00"); - } else { - btldr_timer = 0; - } - - if (button_pressed[0] && !was_button_pressed[0] && !button_pressed[1]) { - menu_index = (menu_index + 1) % 3; - if (!flash_header_valid && !menu_index) menu_index = 1; - menu_render(); - render_ticks = 0; - } - - #if BUTTON_COUNT == 4 - if (button_pressed[2] && !was_button_pressed[2]) { - menu_index = (menu_index + 2) % 3; - if (!flash_header_valid && !menu_index) menu_index = 2; - menu_render(); - render_ticks = 0; - } - if (button_pressed[3] && !was_button_pressed[3]) { - menu_index = (menu_index + 1) % 3; - if (!flash_header_valid && !menu_index) menu_index = 1; - menu_render(); - render_ticks = 0; - } - #endif - - if (button_pressed[1] && !was_button_pressed[1] && !button_pressed[0]) { - if (menu_index == 0) { - return 0; - } else if (menu_index == 1) { - ble_toggle(); - menu_render(); - render_ticks = 0; - } else if (menu_index == 2) { - boop(); - } - } - - if (render_ticks > 125) { - render_ticks = 0; - menu_render(); - } - - for (int i = 0; i < BUTTON_COUNT; i++) { - was_button_pressed[i] = button_pressed[i]; - } - - return 1; + render_xbm(buffer, rb); + menu_ticks = 0; } +struct screen menu_screen = { + menu_draw, + menu_event, +}; diff --git a/src/menu.h b/src/menu.h index 57f21ae..f7b2468 100644 --- a/src/menu.h +++ b/src/menu.h @@ -1,4 +1,5 @@ #pragma once -void menu_switch(void); -int menu_handler(void); +#include "screen.h" + +extern struct screen menu_screen; diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..5f72935 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,36 @@ +#include "screen.h" + +static void blank_draw_handler(struct row_buf *buf) { +} + +static void blank_event_handler(struct screen_event event) { +} + +static struct screen blank_screen = { + blank_draw_handler, + blank_event_handler, +}; + +struct screen *current_screen = &blank_screen; +static struct screen *screen_stack[4] = {0}; +static int screen_stack_idx = 0; + +void screen_push(struct screen *screen) { + screen_stack[screen_stack_idx++] = current_screen; + current_screen = screen; + screen_dirty = 1; +} + +void screen_replace(struct screen *screen) { + current_screen = screen; +} + +void screen_pop() { + if (screen_stack_idx == 0) { + current_screen = &blank_screen; + } else { + current_screen = screen_stack[--screen_stack_idx]; + } +} + +int screen_dirty = 0; diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..b65025b --- /dev/null +++ b/src/screen.h @@ -0,0 +1,31 @@ +#pragma once + +#include "led.h" + +enum screen_event_type { + SE_TICK = 0, + SE_BUTTON_PRESS = 1, + SE_BUTTON_RELEASE_SHORT = 2, + SE_BUTTON_HOLD = 3, + SE_BUTTON_RELEASE_HOLD = 4, +}; + +struct screen_event { + enum screen_event_type type; + uint8_t data; +}; + +typedef void (*screen_draw)(struct row_buf *); +typedef void (*screen_event)(struct screen_event); + +struct screen { + screen_draw draw_handler; + screen_event event_handler; +}; + +void screen_push(struct screen *); +void screen_replace(struct screen *); +void screen_pop(); + +extern struct screen *current_screen; +extern int screen_dirty;