diff options
Diffstat (limited to 'src/menu.c')
-rw-r--r-- | src/menu.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..51f7c31 --- /dev/null +++ b/src/menu.c @@ -0,0 +1,269 @@ +#include <zeta.h> +#include <hardware.h> +#include <tty.h> +#include <input.h> +#include <stdio.h> +#include <string.h> + +struct time { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t wkday; + uint8_t date; + uint8_t month; + uint8_t year; +}; + +struct value { + uint8_t roll; + int val; + int min, max; +}; + +void +value_inc(struct value *v, int d) +{ + v->val += d; + + if (v->roll) { + if (v->val > v->max) + v->val = v->min; + else if(v->val < v->min) + v->val = v->max - 1; + } else { + v->val = clamp(v->val, v->min, v->max); + } +} + +enum item_type { + VOID, + BUTTON, + VALUE, + LABEL +}; + +void +draw_time(void) +{ + char buf[32]; + struct time time; + memset(&time, 0, sizeof(time)); + // rtc_get_bcd_time(&time); + sprintf(buf, "20%hhd%hhd-%hhd%hhd-%hhd%hhd %hhd%hhd:%hhd%hhd:%hhd%hhd", + time.year >> 4, time.year & 0xF, + time.month >> 4, time.month & 0xF, + time.date >> 4, time.date & 0xF, + time.hour >> 4, time.hour & 0xF, + time.minute >> 4, time.minute & 0xF, + time.second >> 4, time.second & 0xF); + mvaddstr(5, 1, buf); +} + +void +draw_battery(void) +{ + uint16_t soc = 100; // bat_state_of_charge(); + char buf[16]; + sprintf(buf, "%u%%", soc); + mvaddstr(7, 1, buf); +} + +void +set_time(void); + +struct item { + uint8_t type; + const char *text; + union { + void (*action)(void); + struct value value; + } v; +}; + +struct menu_entry { + const char *text; + struct item items[8]; +}; + +struct menu_entry menu[] = { + { + .text = "TIME ", + .items = { + {.type = LABEL, .v = {.action = draw_time}}, + {.type = LABEL, .v = {.action = draw_battery}}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID} + } + }, + { + .text = "CONF ", + .items = { + {.type = VALUE, .text = "SEC", .v = {.value = {1, 0, 0, 59}}}, + {.type = VALUE, .text = "MIN", .v = {.value = {1, 0, 0, 59}}}, + {.type = VALUE, .text = "HOUR", .v = {.value = {1, 0, 0, 23}}}, + {.type = VALUE, .text = "WKDAY", .v = {.value = {1, 0, 1, 7}}}, + {.type = VALUE, .text = "DATE", .v = {.value = {1, 1, 1, 31}}}, + {.type = VALUE, .text = "MONTH", .v = {.value = {1, 1, 1, 12}}}, + {.type = VALUE, .text = "YEAR", .v = {.value = {1, 0, 0, 3000}}}, + {.type = BUTTON, .text = "LOAD", .v = {.action = set_time}} + } + } +}; + +void +set_time(void) +{ + struct time time; + struct item *items = menu[1].items; + + time.second = items[0].v.value.val; + time.minute = items[1].v.value.val; + time.hour = items[2].v.value.val; + time.wkday = items[3].v.value.val; + time.date = items[4].v.value.val; + time.month = items[5].v.value.val; + time.year = items[6].v.value.val; + + // rtc_set_time(&time); +} + +enum direction { + VERTICAL, + HORIZONTAL +}; + +static uint8_t dir = HORIZONTAL; +static int menu_index = 0; +static int sub_menu_index = -1; +static int edit = 0; + +#define BUILD_VERSION "20241117" + +void +draw_menu(void) +{ + const char *build_version = BUILD_VERSION; + const int padding = (TTY_WIDTH - 8 * LENGTH(menu)) / 2; + + mvaddstr(1, 0, " ************* THE SOUTHERN STAR MK II ************* "); + mvaddch(3, 1, dir == HORIZONTAL ? '>' : '^'); + + for (int i = 0; i < LENGTH(menu); ++i) { + if (i == menu_index) { + swap_colors(); + mvaddstr(3, padding + i * 8, menu[i].text); + swap_colors(); + } else { + mvaddstr(3, padding + i * 8, menu[i].text); + } + } + + const struct menu_entry *entry = &menu[menu_index]; + + for (int i = 0; i < LENGTH(entry->items); ++i) { + mvaddstr(5 + 2 * i, 1, " "); + + if (entry->items[i].type == VOID) + continue; + + if (i == sub_menu_index && menu_index != 0) { + swap_colors(); + mvaddstr(5 + 2 * i, 1, entry->items[i].text); + swap_colors(); + } else { + mvaddstr(5 + 2 * i, 1, entry->items[i].text); + } + + if (entry->items[i].type == VALUE) { + char buf[16]; + sprintf(buf, "%8d", entry->items[i].v.value.val); + mvaddstr(5 + 2 * i, 6, buf); + } + + if (entry->items[i].type == LABEL) { + entry->items[i].v.action(); + } + } + + mvaddstr(TTY_HEIGHT - 2, TTY_WIDTH - strlen(build_version) - 1, build_version); +} + +void +dir_callback(void) +{ + if (sub_menu_index >= 0) { + struct item *item = &menu[menu_index].items[sub_menu_index]; + + switch (item->type) { + case VALUE: + edit = !edit; + break; + + case BUTTON: + if (item->v.action) + item->v.action(); + break; + } + } else { + dir = (dir + 1) & 1; + draw_menu(); + } +} + +#define CW 0x10 +#define CCW 0x20 + +typedef void (*callback)(void); +volatile callback callbacks[5] = {NULL, NULL, NULL, NULL, NULL}; + +void +_menu(void) +{ + callbacks[0] = dir_callback; + clear_screen(); + setcur(0, 0); + draw_menu(); + + while (1) { + DI; + while (!fifo_empty(&input_fifo)) { + u8 event = fifo_pop(&input_fifo); + if (event == CW) { + if (dir == HORIZONTAL) { + if (++menu_index >= LENGTH(menu)) + menu_index = 0; + } else { + if (edit) { + value_inc(&menu[menu_index].items[sub_menu_index].v.value, 1); + } else { + if (++sub_menu_index >= LENGTH(menu[0].items)) + sub_menu_index = 0; + } + } + draw_menu(); + } else if (event == CCW) { + if (dir == HORIZONTAL) { + if (--menu_index < 0) + menu_index = LENGTH(menu) - 1; + } else { + if (edit) { + value_inc(&menu[menu_index].items[sub_menu_index].v.value, -1); + } else { + if (--sub_menu_index < -1) + sub_menu_index = LENGTH(menu[0].items) - 1; + } + } + draw_menu(); + } else { + if (callbacks[event]) + callbacks[event](); + } + } + EI; + } +} |