#include #include #include #include #include #include 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; } }