From 3370e5a3a79619062a5014fce1b1b004b57fe701 Mon Sep 17 00:00:00 2001 From: Federico Amedeo Izzo Date: Sat, 21 Nov 2020 10:46:39 +0100 Subject: [PATCH] Add shared state logic --- openrtx/include/state.h | 45 +++++++++++++------------ openrtx/include/ui.h | 6 ++-- openrtx/src/state.c | 24 ++++--------- openrtx/src/threads.c | 75 +++++++++++++++++++++++++++-------------- openrtx/src/ui.c | 58 ++++++++++++++++++++++--------- 5 files changed, 127 insertions(+), 81 deletions(-) diff --git a/openrtx/include/state.h b/openrtx/include/state.h index aa7c8d0e..d4b74338 100644 --- a/openrtx/include/state.h +++ b/openrtx/include/state.h @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO, * * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * @@ -21,14 +22,17 @@ #define STATE_H #include +#include +#include /** * Part of this structure has been commented because the corresponding * functionality is not yet implemented. * Uncomment once the related feature is ready */ - typedef struct state_t { + curTime_t time; + float v_bat; //enum ui_screen; //enum tuner_mode; //enum radio_mode; @@ -59,27 +63,26 @@ typedef struct state_t { } state_t; /** - * This function initialises the Radio state, acquiring the information - * needed to populate it from device drivers. + * This structure is used to mark if the state has been modified + * and by which thread. + * The threads that are watching for state updates + * check the variables of other threads, if they are set, + * they know that the state have been modified + */ +typedef struct modified_t { + bool ui_modified; + bool rtx_modified; + bool self_modified; +} modified_t; + +extern state_t state; +extern modified_t state_flags; + + +/** + * This function initializes the Radio state, acquiring the information + * needed to populate it from device drivers. */ void state_init(); -/** - * This function updates the state information by sourcing the - * updated values of the various fields of the state_t struct - * from corresponding device drivers. - */ -void state_update(); - -/** - * Fetch current state. - * @return current state. - */ -state_t state_getCurrentState(); - -/** - * This function terminates the Radio state. - */ -void state_terminate(); - #endif /* STATE_H */ diff --git a/openrtx/include/ui.h b/openrtx/include/ui.h index 29508b5a..dbe4ffbb 100644 --- a/openrtx/include/ui.h +++ b/openrtx/include/ui.h @@ -32,10 +32,12 @@ void ui_init(); /** * This function advances the User Interface FSM, basing on the - * current radio state and the keys pressed. + * current radio state and the keys pressed and redraws the GUI. + * @param last_state: A local copy of the previous radio state + * @param keys: A bitmap containing the currently pressed keys * @return true if a screen refresh is needed after the update */ -bool ui_update(state_t state, uint32_t keys); +bool ui_update(state_t last_state, uint32_t keys); /** * This function terminates the User Interface. diff --git a/openrtx/src/state.c b/openrtx/src/state.c index 5bfbc8ac..cfbab9d5 100644 --- a/openrtx/src/state.c +++ b/openrtx/src/state.c @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO, * * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * @@ -20,26 +21,15 @@ #include #include -state_t current_state; +state_t state; +modified_t state_flags; void state_init() { /*TODO: Read current state parameters from hardware, * or initialize them to sane defaults */ - current_state.rx_freq = 0.0; - current_state.tx_freq = 0.0; -} - -void state_update() -{ - -} - -state_t state_getCurrentState() -{ - return current_state; -} - -void state_terminate() -{ + state.time = rtc_getTime(); + state.v_bat = platform_getVbat(); + state.rx_freq = 0.0; + state.tx_freq = 0.0; } diff --git a/openrtx/src/threads.c b/openrtx/src/threads.c index 6880497e..6ec8fd62 100644 --- a/openrtx/src/threads.c +++ b/openrtx/src/threads.c @@ -27,6 +27,9 @@ #include #include +// Allocate state mutex +static OS_MUTEX state_mutex; + // Allocate UI task control block and stack static OS_TCB ui_tcb; static CPU_STK ui_stk[UI_TASK_STKSIZE]; @@ -50,19 +53,15 @@ static void ui_task(void *arg) (void) arg; OS_ERR os_err; - // Initialise keyboard + // Initialize keyboard kbd_init(); - - // Initialise graphics driver + // Initialize graphics driver gfx_init(); + // Initialize user interface + ui_init(); // Display splash screen - point_t splash_origin = {0, SCREEN_HEIGHT / 2 + 6}; - color_t yellow_fab413 = {250, 180, 19}; - char *splash_buf = "OpenRTX"; - gfx_clearScreen(); - gfx_print(splash_origin, "OpenRTX", FONT_SIZE_12PT, TEXT_ALIGN_CENTER, - yellow_fab413); + ui_drawSplashScreen(); gfx_render(); while(gfx_renderingInProgress()); // Wait 30ms to hide random pixels on screen @@ -71,16 +70,25 @@ static void ui_task(void *arg) // Keep the splash screen for 1 second OSTimeDlyHMSM(0u, 0u, 1u, 0u, OS_OPT_TIME_HMSM_STRICT, &os_err); - // Clear screen - gfx_clearScreen(); - gfx_render(); - while(gfx_renderingInProgress()); + // Get initial state local copy + // Wait for unlocked mutex and lock it + OSMutexPend(&state_mutex, 0u, OS_OPT_PEND_BLOCKING, 0u, &os_err); + state_t last_state = state; + // Unlock the mutex + OSMutexPost(&state_mutex, OS_OPT_POST_NONE, &os_err); while(1) { - state_t state = state_getCurrentState(); uint32_t keys = kbd_getKeys(); - bool renderNeeded = ui_update(state, keys); + // Wait for unlocked mutex and lock it + OSMutexPend(&state_mutex, 0u, OS_OPT_PEND_BLOCKING, 0u, &os_err); + // React to keypresses and redraw GUI + bool renderNeeded = ui_update(last_state, keys); + // Update state local copy + last_state = state; + // Unlock the mutex + OSMutexPost(&state_mutex, OS_OPT_POST_NONE, &os_err); + if(renderNeeded) { gfx_render(); @@ -92,25 +100,28 @@ static void ui_task(void *arg) } } - // State update task static void state_task(void *arg) { (void) arg; OS_ERR os_err; - // Initialise state - state_init(); - while(1) { - // Execute state thread every 1s - state_update(); + // Wait for unlocked mutex and lock it + OSMutexPend(&state_mutex, 0u, OS_OPT_PEND_BLOCKING, 0u, &os_err); + + state.time = rtc_getTime(); + state.v_bat = platform_getVbat(); + + // Unlock the mutex + OSMutexPost(&state_mutex, OS_OPT_POST_NONE, &os_err); + + // Execute state update thread every 1s OSTimeDlyHMSM(0u, 0u, 1u, 0u, OS_OPT_TIME_HMSM_STRICT, &os_err); } } - // RTX task static void rtx_task(void *arg) { @@ -146,9 +157,21 @@ void create_threads() { OS_ERR os_err; + // Create state mutex + OSMutexCreate((OS_MUTEX *) &state_mutex, + (CPU_CHAR *) "State Mutex", + (OS_ERR *) &os_err); + + // Wait for unlocked mutex and lock it + OSMutexPend(&state_mutex, 0u, OS_OPT_PEND_BLOCKING, 0u, &os_err); + // State initialization, execute before starting all tasks + state_init(); + // Unlock the mutex + OSMutexPost(&state_mutex, OS_OPT_POST_NONE, &os_err); + // Create UI thread OSTaskCreate((OS_TCB *) &ui_tcb, - (CPU_CHAR *) " ", + (CPU_CHAR *) "UI Task", (OS_TASK_PTR ) ui_task, (void *) 0, (OS_PRIO ) 10, @@ -163,7 +186,7 @@ void create_threads() // Create state thread OSTaskCreate((OS_TCB *) &state_tcb, - (CPU_CHAR *) " ", + (CPU_CHAR *) "State Task", (OS_TASK_PTR ) state_task, (void *) 0, (OS_PRIO ) 30, @@ -178,7 +201,7 @@ void create_threads() // Create rtx radio thread OSTaskCreate((OS_TCB *) &rtx_tcb, - (CPU_CHAR *) " ", + (CPU_CHAR *) "RTX Task", (OS_TASK_PTR ) rtx_task, (void *) 0, (OS_PRIO ) 5, @@ -193,7 +216,7 @@ void create_threads() // Create dmr radio thread OSTaskCreate((OS_TCB *) &dmr_tcb, - (CPU_CHAR *) " ", + (CPU_CHAR *) "DMR Task", (OS_TASK_PTR ) dmr_task, (void *) 0, (OS_PRIO ) 3, diff --git a/openrtx/src/ui.c b/openrtx/src/ui.c index a64cc97a..a464f35c 100644 --- a/openrtx/src/ui.c +++ b/openrtx/src/ui.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include @@ -91,8 +90,10 @@ typedef struct layout_t layout_t layout; bool layout_ready = false; +bool redraw_needed = true; color_t color_white = {255, 255, 255}; color_t color_grey = {60, 60, 60}; +color_t yellow_fab413 = {250, 180, 19}; layout_t _ui_calculateLayout() { @@ -203,19 +204,18 @@ void _ui_drawTopBar() { // Print clock on top bar char clock_buf[6] = ""; - curTime_t time = rtc_getTime(); - snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d", time.hour, time.minute); + snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d", state.time.hour, + state.time.minute); gfx_print(layout.top_pos, clock_buf, layout.top_font, TEXT_ALIGN_CENTER, color_white); // Print battery voltage on top bar, use 4 px padding // TODO: Replace with battery icon char bat_buf[6] = ""; - float v_bat = platform_getVbat(); - snprintf(bat_buf, sizeof(bat_buf), "%02.1fV ", v_bat); + snprintf(bat_buf, sizeof(bat_buf), "%02.1fV ", state.v_bat); gfx_print(layout.top_pos, bat_buf, layout.top_font, TEXT_ALIGN_RIGHT, color_white); } -void _ui_drawVFO(state_t state) +void _ui_drawVFO() { // Print VFO frequencies char freq_buf[20] = ""; @@ -232,30 +232,58 @@ void _ui_drawBottomBar() gfx_print(layout.bottom_pos, bottom_buf, layout.bottom_font, TEXT_ALIGN_CENTER, color_white); } -void ui_drawMainScreen(state_t state) +bool ui_drawMainScreen(state_t last_state) { - _ui_drawBackground(); - _ui_drawTopBar(); - _ui_drawVFO(state); - _ui_drawBottomBar(); + bool screen_update = false; + // Total GUI redraw + if(redraw_needed) + { + gfx_clearScreen(); + _ui_drawBackground(); + _ui_drawTopBar(); + _ui_drawVFO(); + _ui_drawBottomBar(); + screen_update = true; + } + // Partial GUI redraw + // TODO: until gfx_clearRows() is implemented, we need to redraw everything + else + { + gfx_clearScreen(); + _ui_drawBackground(); + _ui_drawTopBar(); + _ui_drawVFO(); + _ui_drawBottomBar(); + screen_update = true; + } + return screen_update; } void ui_init() { + redraw_needed = true; layout = _ui_calculateLayout(); layout_ready = true; } -bool ui_update(state_t state, uint32_t keys) +void ui_drawSplashScreen() +{ + point_t splash_origin = {0, SCREEN_HEIGHT / 2 + 6}; + char *splash_buf = "OpenRTX"; + gfx_clearScreen(); + gfx_print(splash_origin, "OpenRTX", FONT_SIZE_12PT, TEXT_ALIGN_CENTER, + yellow_fab413); +} + +bool ui_update(state_t last_state, uint32_t keys) { if(!layout_ready) { layout = _ui_calculateLayout(); layout_ready = true; } - gfx_clearScreen(); - ui_drawMainScreen(state); - return true; + bool screen_update = ui_drawMainScreen(last_state); + return screen_update; } void ui_terminate()