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