Add screen (event/stack) abstraction
This commit is contained in:
56
src/badge_screen.c
Normal file
56
src/badge_screen.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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,
|
||||||
|
};
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
extern uint32_t pa_mask;
|
extern uint32_t pa_mask;
|
||||||
extern uint32_t pb_mask;
|
extern uint32_t pb_mask;
|
||||||
|
|
||||||
|
|||||||
106
src/main.c
106
src/main.c
@@ -12,8 +12,7 @@
|
|||||||
#include "cdc.h"
|
#include "cdc.h"
|
||||||
#include "wang.h"
|
#include "wang.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "screen.h"
|
||||||
int anim_render(uint16_t *fb, int index, int frame);
|
|
||||||
|
|
||||||
enum usb_control_resp bl_handler(enum usb_control_state state) {
|
enum usb_control_resp bl_handler(enum usb_control_state state) {
|
||||||
if ((usb_control_request.bmRequestType & 0x7f) != 0x43) return USB_CONTROL_RESP_PASS;
|
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;
|
extern struct screen badge_screen;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -102,13 +50,14 @@ int main()
|
|||||||
PFIC_EnableIRQ(TMR3_IRQn);
|
PFIC_EnableIRQ(TMR3_IRQn);
|
||||||
|
|
||||||
wang_init();
|
wang_init();
|
||||||
main_handler();
|
|
||||||
|
|
||||||
usb_register_handler(bl_handler);
|
usb_register_handler(bl_handler);
|
||||||
usb_init();
|
usb_init();
|
||||||
|
|
||||||
ble_init();
|
ble_init();
|
||||||
|
|
||||||
|
screen_push(&badge_screen);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
WWDG_SetCounter(0x7F);
|
WWDG_SetCounter(0x7F);
|
||||||
static int btldr_timer = 0;
|
static int btldr_timer = 0;
|
||||||
@@ -119,17 +68,42 @@ int main()
|
|||||||
btldr_timer = 0;
|
btldr_timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cur_handler = 0;
|
struct screen_event ev = {
|
||||||
if (cur_handler) {
|
SE_TICK,
|
||||||
cur_handler = menu_handler();
|
0
|
||||||
if (!cur_handler) {
|
};
|
||||||
for (int i = 0; i < BUTTON_COUNT; i++) {
|
current_screen->event_handler(ev);
|
||||||
button_was_pressed[i] = button_pressed[i];
|
|
||||||
|
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();
|
TMOS_SystemProcess();
|
||||||
cdc_tick();
|
cdc_tick();
|
||||||
|
|||||||
106
src/menu.c
106
src/menu.c
@@ -9,6 +9,7 @@
|
|||||||
#include "ble.h"
|
#include "ble.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "wang.h"
|
#include "wang.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
#include "img/menu.xbm"
|
#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);
|
display_make_buf_all(fb, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
int menu_index = 0;
|
static int menu_index = 0;
|
||||||
|
|
||||||
static int was_button_pressed[BUTTON_COUNT] = {0};
|
static int menu_ticks = 0;
|
||||||
|
static void menu_event(struct screen_event event) {
|
||||||
void menu_render(void) {
|
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];
|
uint8_t buffer[(48 * 11) / 8];
|
||||||
memcpy(buffer, menu_bits, sizeof(buffer));
|
memcpy(buffer, menu_bits, sizeof(buffer));
|
||||||
int invert_index = 1 + menu_index * 13;
|
int invert_index = 1 + menu_index * 13;
|
||||||
@@ -98,74 +121,11 @@ void menu_render(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_xbm(buffer, display_screen);
|
render_xbm(buffer, rb);
|
||||||
display_flip();
|
menu_ticks = 0;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct screen menu_screen = {
|
||||||
|
menu_draw,
|
||||||
|
menu_event,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void menu_switch(void);
|
#include "screen.h"
|
||||||
int menu_handler(void);
|
|
||||||
|
extern struct screen menu_screen;
|
||||||
|
|||||||
36
src/screen.c
Normal file
36
src/screen.c
Normal file
@@ -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;
|
||||||
31
src/screen.h
Normal file
31
src/screen.h
Normal file
@@ -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;
|
||||||
Reference in New Issue
Block a user