base of menu system

This commit is contained in:
2023-04-05 22:42:55 +02:00
parent b397856366
commit 6048bdf115
7 changed files with 276 additions and 47 deletions
+245 -33
View File
@@ -15,15 +15,55 @@
#define MAX_TEMP 400
typedef enum GuiScreen {
SCREEN_HOME,
SCREEN_MANUAL,
SCREEN_MANUAL_MENU,
} GuiScreen;
static struct State {
float oven_temp;
float soc_temp;
int set_temp;
int set_temp_wheel;
bool heater_enabled;
bool pushed;
uint32_t push_tick;
// true if the button is still held since init (i.e. the push action should not work as "enter")
bool initial_pushed;
GuiScreen screen;
int menu_pos;
int menu_len;
} s_app = {};
static void calc_set_temp() {
/** Get push time (while held) */
static uint32_t push_time() {
return s_app.pushed ? (xTaskGetTickCount() - s_app.push_tick) : 0;
}
typedef void (*screen_t)(GuiEvent event);
static void screen_home(GuiEvent event);
static void screen_manual(GuiEvent event);
static void screen_manual_menu(GuiEvent event);
static screen_t screens[] = {
[SCREEN_HOME] = screen_home,
[SCREEN_MANUAL] = screen_manual,
[SCREEN_MANUAL_MENU] = screen_manual_menu,
};
static void draw_common_overlay();
static void input_sound_effect(GuiEvent event);
static void switch_screen(GuiScreen screen, bool init);
static void calc_set_temp()
{
int clamped = s_app.set_temp_wheel;
if (clamped < 0) {
clamped = 0;
@@ -36,58 +76,230 @@ static void calc_set_temp() {
app_heater_set_target((float) s_app.set_temp);
}
void app_task_gui(void *argument) {
char tmp[100];
void app_task_gui(void *argument)
{
// Wait until inited
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
PUTS("GUI task starts\r\n");
char tmp[100];
while (1) {
s_app.oven_temp = app_temp_read_oven();
s_app.soc_temp = app_temp_read_soc();
uint32_t message = GUI_EVENT_NONE;
osMessageQueueGet(guiEventQueHandle, &message, NULL, pdMS_TO_TICKS(1000));
osMessageQueueGet(guiEventQueHandle, &message, NULL, pdMS_TO_TICKS(50));
switch (message) {
case GUI_NOTIFY_KNOB_PLUS:
s_app.set_temp_wheel++;
calc_set_temp();
case GUI_EVENT_KNOB_PRESS:
s_app.pushed = true;
s_app.push_tick = xTaskGetTickCount();
break;
case GUI_NOTIFY_KNOB_MINUS:
s_app.set_temp_wheel--;
calc_set_temp();
break;
case GUI_NOTIFY_KNOB_PRESS:
break;
case GUI_NOTIFY_KNOB_RELEASE:
s_app.heater_enabled ^= 1;
app_heater_enable(s_app.heater_enabled);
app_buzzer_beep();
case GUI_EVENT_KNOB_RELEASE:
s_app.pushed = false;
break;
default:
break;
}
fb_clear();
if (s_app.initial_pushed && message == GUI_EVENT_KNOB_RELEASE) {
s_app.initial_pushed = false;
} else {
fb_clear();
SPRINTF(tmp, "%d", s_app.screen);
fb_text(3, 80, tmp, FONT_5X7, 1);
draw_common_overlay();
SPRINTF(tmp, "T=%.1f°C", s_app.oven_temp);
fb_text(3, 3, tmp, FONT_5X7, 1);
screens[s_app.screen](message);
SPRINTF(tmp, "Cil=%d°C", s_app.set_temp);
fb_text(3, 11, tmp, FONT_5X7, 1);
SPRINTF(tmp, "Stav=%s", s_app.heater_enabled ? "ZAP" : "VYP");
fb_text(3, 19, tmp, FONT_5X7, 1);
SPRINTF(tmp, "Tsoc=%.1f°C", s_app.soc_temp);
fb_text(3, 27, tmp, FONT_5X7, 1);
if (s_app.heater_enabled) {
fb_frame(0, 0, FBW, FBH, 2, 1);
fb_blit();
}
}
}
fb_blit();
static void switch_screen(GuiScreen screen, bool init) {
s_app.initial_pushed = s_app.pushed;
s_app.screen = screen;
if (init) {
screens[screen](GUI_EVENT_SCREEN_INIT);
}
}
static void draw_common_overlay()
{
SPRINTF(tmp, "%3.1f°C →%3d°C", s_app.oven_temp, s_app.set_temp);
fb_text(3, 3, tmp, FONT_3X5, 1);
//
// SPRINTF(tmp, "Tsoc=%.1f°C", s_app.soc_temp);
// fb_text(3, 19, tmp, FONT_5X7, 1);
if (s_app.heater_enabled) {
fb_frame(0, 0, FBW, FBH, 2, 1);
}
}
static void input_sound_effect(GuiEvent event)
{
switch (event) {
case GUI_EVENT_KNOB_PLUS:
case GUI_EVENT_KNOB_MINUS:
case GUI_EVENT_KNOB_RELEASE:
app_buzzer_beep();
break;
default:
break;
}
}
static void screen_home(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
s_app.menu_pos = 0;
s_app.menu_len = 1;
// Disable heater
app_heater_enable(false);
return;
}
input_sound_effect(event);
// Menu with one item, lol
SPRINTF(tmp, "Manual mode", s_app.soc_temp);
if (s_app.menu_pos == 0) {
fb_rect(3, 27, 64, 8, 1);
}
fb_text(3, 27, tmp, FONT_5X7, s_app.menu_pos != 0);
switch (event) {
case GUI_EVENT_KNOB_RELEASE:
switch (s_app.menu_pos) {
case 0:
switch_screen(SCREEN_MANUAL, true);
break;
}
break;
case GUI_EVENT_KNOB_PLUS:
if (s_app.menu_pos < s_app.menu_len - 1) {
s_app.menu_pos++;
}
break;
case GUI_EVENT_KNOB_MINUS:
if (s_app.menu_pos > 0) {
s_app.menu_pos--;
}
break;
default:
break;
}
}
static void screen_manual(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
s_app.set_temp_wheel = 0;
return;
}
// menu activated by long push
if (push_time() >= pdMS_TO_TICKS(500)) {
switch_screen(SCREEN_MANUAL_MENU, true);
return;
}
input_sound_effect(event);
switch (event) {
case GUI_EVENT_KNOB_RELEASE:
if (s_app.initial_pushed) {
s_app.initial_pushed = false;
break;
}
s_app.heater_enabled ^= 1;
app_heater_enable(s_app.heater_enabled);
break;
case GUI_EVENT_KNOB_PLUS:
s_app.set_temp_wheel++;
calc_set_temp();
break;
case GUI_EVENT_KNOB_MINUS:
s_app.set_temp_wheel--;
calc_set_temp();
break;
default:
break;
}
}
static void screen_manual_menu(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
s_app.menu_pos = 0;
s_app.menu_len = 2;
return;
}
input_sound_effect(event);
SPRINTF(tmp, "Close menu", s_app.soc_temp);
if (s_app.menu_pos == 0) {
fb_rect(3, 27, 64, 8, 1);
}
fb_text(3, 27, tmp, FONT_5X7, s_app.menu_pos != 0);
SPRINTF(tmp, "Exit manual", s_app.soc_temp);
if (s_app.menu_pos == 1) {
fb_rect(3, 27 + 8, 64, 8, 1);
}
fb_text(3, 27 + 8, tmp, FONT_5X7, s_app.menu_pos != 1);
switch (event) {
// the button is held! release is what activates the button
case GUI_EVENT_KNOB_RELEASE:
if (s_app.initial_pushed) {
s_app.initial_pushed = false;
}
break;
case GUI_EVENT_KNOB_PRESS:
switch (s_app.menu_pos) {
case 0:
// Close menu
switch_screen(SCREEN_MANUAL, false);
break;
case 1:
// Close menu
switch_screen(SCREEN_HOME, true);
break;
}
break;
case GUI_EVENT_KNOB_PLUS:
if (s_app.menu_pos < s_app.menu_len - 1) {
s_app.menu_pos++;
}
break;
case GUI_EVENT_KNOB_MINUS:
if (s_app.menu_pos > 0) {
s_app.menu_pos--;
}
break;
default:
break;
}
}
+16 -7
View File
@@ -13,13 +13,22 @@ extern osMessageQueueId_t guiEventQueHandle;
void app_task_gui(void *argument);
// sent through the notify queue
enum GuiNotify {
typedef enum GuiEvent {
/// No event, zero; This is a default value.
GUI_EVENT_NONE = 0,
GUI_NOTIFY_KNOB_PLUS,
GUI_NOTIFY_KNOB_MINUS,
GUI_NOTIFY_KNOB_PRESS,
GUI_NOTIFY_KNOB_RELEASE,
GUI_NOTIFY_TEMP_CHANGE,
};
/// Used as the argument when initing a screen
GUI_EVENT_SCREEN_INIT = 1,
/// Knob rotate CW
GUI_EVENT_KNOB_PLUS,
/// Knob rotate CCW
GUI_EVENT_KNOB_MINUS,
/// Knob pressed
GUI_EVENT_KNOB_PRESS,
/// Knob released
GUI_EVENT_KNOB_RELEASE,
/// Temperature readings changed.
/// Not really an input event, but it should trigger a redraw
GUI_EVENT_TEMP_CHANGE,
} GuiEvent;
#endif //BLUEPILLTROUBA_APP_GUI_H
+1 -1
View File
@@ -122,7 +122,7 @@ void app_task_heater(void *argument)
state.oven_temp = app_temp_read_oven();
state.soc_temp = app_temp_read_soc();
enum GuiNotify ev = GUI_NOTIFY_TEMP_CHANGE;
enum GuiEvent ev = GUI_EVENT_TEMP_CHANGE;
xQueueSend(guiEventQueHandle, &ev, pdMS_TO_TICKS(100));
heaterEnterCritical();
+3 -3
View File
@@ -48,13 +48,13 @@ void app_knob_turn_isr()
while (wheel_change > 0) {
wheel_change--;
enum GuiNotify ev = GUI_NOTIFY_KNOB_PLUS;
enum GuiEvent ev = GUI_EVENT_KNOB_PLUS;
xQueueSendFromISR(guiEventQueHandle, &ev, &yield);
}
while (wheel_change < 0) {
wheel_change++;
enum GuiNotify ev = GUI_NOTIFY_KNOB_MINUS;
enum GuiEvent ev = GUI_EVENT_KNOB_MINUS;
xQueueSendFromISR(guiEventQueHandle, &ev, &yield);
}
@@ -87,6 +87,6 @@ void app_knob_push_isr(bool push)
void app_push_debounce(void *argument) {
bool push = (bool) argument;
enum GuiNotify ev = push ? GUI_NOTIFY_KNOB_PRESS : GUI_NOTIFY_KNOB_RELEASE;
enum GuiEvent ev = push ? GUI_EVENT_KNOB_PRESS : GUI_EVENT_KNOB_RELEASE;
xQueueSend(guiEventQueHandle, &ev, pdMS_TO_TICKS(100));
}