Add shared state logic

This commit is contained in:
Federico Amedeo Izzo 2020-11-21 10:46:39 +01:00
parent 310f19c6b7
commit 3370e5a3a7
5 changed files with 127 additions and 81 deletions

View File

@ -1,6 +1,7 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN, * * Niccolò Izzo IU2KIN, *
* Frederik Saraci IU2NRO, *
* Silvano Seva IU2KWO * * Silvano Seva IU2KWO *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -21,14 +22,17 @@
#define STATE_H #define STATE_H
#include <datatypes.h> #include <datatypes.h>
#include <stdbool.h>
#include <rtc.h>
/** /**
* Part of this structure has been commented because the corresponding * Part of this structure has been commented because the corresponding
* functionality is not yet implemented. * functionality is not yet implemented.
* Uncomment once the related feature is ready * Uncomment once the related feature is ready
*/ */
typedef struct state_t { typedef struct state_t {
curTime_t time;
float v_bat;
//enum ui_screen; //enum ui_screen;
//enum tuner_mode; //enum tuner_mode;
//enum radio_mode; //enum radio_mode;
@ -59,27 +63,26 @@ typedef struct state_t {
} state_t; } state_t;
/** /**
* This function initialises the Radio state, acquiring the information * This structure is used to mark if the state has been modified
* needed to populate it from device drivers. * 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(); 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 */ #endif /* STATE_H */

View File

@ -32,10 +32,12 @@ void ui_init();
/** /**
* This function advances the User Interface FSM, basing on the * 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 * @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. * This function terminates the User Interface.

View File

@ -1,6 +1,7 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN, * * Niccolò Izzo IU2KIN, *
* Frederik Saraci IU2NRO, *
* Silvano Seva IU2KWO * * Silvano Seva IU2KWO *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -20,26 +21,15 @@
#include <stdio.h> #include <stdio.h>
#include <state.h> #include <state.h>
state_t current_state; state_t state;
modified_t state_flags;
void state_init() void state_init()
{ {
/*TODO: Read current state parameters from hardware, /*TODO: Read current state parameters from hardware,
* or initialize them to sane defaults */ * or initialize them to sane defaults */
current_state.rx_freq = 0.0; state.time = rtc_getTime();
current_state.tx_freq = 0.0; state.v_bat = platform_getVbat();
} state.rx_freq = 0.0;
state.tx_freq = 0.0;
void state_update()
{
}
state_t state_getCurrentState()
{
return current_state;
}
void state_terminate()
{
} }

View File

@ -27,6 +27,9 @@
#include <platform.h> #include <platform.h>
#include <hwconfig.h> #include <hwconfig.h>
// Allocate state mutex
static OS_MUTEX state_mutex;
// Allocate UI task control block and stack // Allocate UI task control block and stack
static OS_TCB ui_tcb; static OS_TCB ui_tcb;
static CPU_STK ui_stk[UI_TASK_STKSIZE]; static CPU_STK ui_stk[UI_TASK_STKSIZE];
@ -50,19 +53,15 @@ static void ui_task(void *arg)
(void) arg; (void) arg;
OS_ERR os_err; OS_ERR os_err;
// Initialise keyboard // Initialize keyboard
kbd_init(); kbd_init();
// Initialize graphics driver
// Initialise graphics driver
gfx_init(); gfx_init();
// Initialize user interface
ui_init();
// Display splash screen // Display splash screen
point_t splash_origin = {0, SCREEN_HEIGHT / 2 + 6}; ui_drawSplashScreen();
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);
gfx_render(); gfx_render();
while(gfx_renderingInProgress()); while(gfx_renderingInProgress());
// Wait 30ms to hide random pixels on screen // 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 // Keep the splash screen for 1 second
OSTimeDlyHMSM(0u, 0u, 1u, 0u, OS_OPT_TIME_HMSM_STRICT, &os_err); OSTimeDlyHMSM(0u, 0u, 1u, 0u, OS_OPT_TIME_HMSM_STRICT, &os_err);
// Clear screen // Get initial state local copy
gfx_clearScreen(); // Wait for unlocked mutex and lock it
gfx_render(); OSMutexPend(&state_mutex, 0u, OS_OPT_PEND_BLOCKING, 0u, &os_err);
while(gfx_renderingInProgress()); state_t last_state = state;
// Unlock the mutex
OSMutexPost(&state_mutex, OS_OPT_POST_NONE, &os_err);
while(1) while(1)
{ {
state_t state = state_getCurrentState();
uint32_t keys = kbd_getKeys(); 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) if(renderNeeded)
{ {
gfx_render(); gfx_render();
@ -92,25 +100,28 @@ static void ui_task(void *arg)
} }
} }
// State update task // State update task
static void state_task(void *arg) static void state_task(void *arg)
{ {
(void) arg; (void) arg;
OS_ERR os_err; OS_ERR os_err;
// Initialise state
state_init();
while(1) while(1)
{ {
// Execute state thread every 1s // Wait for unlocked mutex and lock it
state_update(); 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); OSTimeDlyHMSM(0u, 0u, 1u, 0u, OS_OPT_TIME_HMSM_STRICT, &os_err);
} }
} }
// RTX task // RTX task
static void rtx_task(void *arg) static void rtx_task(void *arg)
{ {
@ -146,9 +157,21 @@ void create_threads()
{ {
OS_ERR os_err; 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 // Create UI thread
OSTaskCreate((OS_TCB *) &ui_tcb, OSTaskCreate((OS_TCB *) &ui_tcb,
(CPU_CHAR *) " ", (CPU_CHAR *) "UI Task",
(OS_TASK_PTR ) ui_task, (OS_TASK_PTR ) ui_task,
(void *) 0, (void *) 0,
(OS_PRIO ) 10, (OS_PRIO ) 10,
@ -163,7 +186,7 @@ void create_threads()
// Create state thread // Create state thread
OSTaskCreate((OS_TCB *) &state_tcb, OSTaskCreate((OS_TCB *) &state_tcb,
(CPU_CHAR *) " ", (CPU_CHAR *) "State Task",
(OS_TASK_PTR ) state_task, (OS_TASK_PTR ) state_task,
(void *) 0, (void *) 0,
(OS_PRIO ) 30, (OS_PRIO ) 30,
@ -178,7 +201,7 @@ void create_threads()
// Create rtx radio thread // Create rtx radio thread
OSTaskCreate((OS_TCB *) &rtx_tcb, OSTaskCreate((OS_TCB *) &rtx_tcb,
(CPU_CHAR *) " ", (CPU_CHAR *) "RTX Task",
(OS_TASK_PTR ) rtx_task, (OS_TASK_PTR ) rtx_task,
(void *) 0, (void *) 0,
(OS_PRIO ) 5, (OS_PRIO ) 5,
@ -193,7 +216,7 @@ void create_threads()
// Create dmr radio thread // Create dmr radio thread
OSTaskCreate((OS_TCB *) &dmr_tcb, OSTaskCreate((OS_TCB *) &dmr_tcb,
(CPU_CHAR *) " ", (CPU_CHAR *) "DMR Task",
(OS_TASK_PTR ) dmr_task, (OS_TASK_PTR ) dmr_task,
(void *) 0, (void *) 0,
(OS_PRIO ) 3, (OS_PRIO ) 3,

View File

@ -66,7 +66,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <ui.h> #include <ui.h>
#include <rtc.h>
#include <delays.h> #include <delays.h>
#include <graphics.h> #include <graphics.h>
#include <keyboard.h> #include <keyboard.h>
@ -91,8 +90,10 @@ typedef struct layout_t
layout_t layout; layout_t layout;
bool layout_ready = false; bool layout_ready = false;
bool redraw_needed = true;
color_t color_white = {255, 255, 255}; color_t color_white = {255, 255, 255};
color_t color_grey = {60, 60, 60}; color_t color_grey = {60, 60, 60};
color_t yellow_fab413 = {250, 180, 19};
layout_t _ui_calculateLayout() layout_t _ui_calculateLayout()
{ {
@ -203,19 +204,18 @@ void _ui_drawTopBar()
{ {
// Print clock on top bar // Print clock on top bar
char clock_buf[6] = ""; char clock_buf[6] = "";
curTime_t time = rtc_getTime(); snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d", state.time.hour,
snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d", time.hour, time.minute); state.time.minute);
gfx_print(layout.top_pos, clock_buf, layout.top_font, TEXT_ALIGN_CENTER, color_white); 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 // Print battery voltage on top bar, use 4 px padding
// TODO: Replace with battery icon // TODO: Replace with battery icon
char bat_buf[6] = ""; char bat_buf[6] = "";
float v_bat = platform_getVbat(); snprintf(bat_buf, sizeof(bat_buf), "%02.1fV ", state.v_bat);
snprintf(bat_buf, sizeof(bat_buf), "%02.1fV ", v_bat);
gfx_print(layout.top_pos, bat_buf, layout.top_font, TEXT_ALIGN_RIGHT, color_white); 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 // Print VFO frequencies
char freq_buf[20] = ""; 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); 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(); bool screen_update = false;
_ui_drawTopBar(); // Total GUI redraw
_ui_drawVFO(state); if(redraw_needed)
_ui_drawBottomBar(); {
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() void ui_init()
{ {
redraw_needed = true;
layout = _ui_calculateLayout(); layout = _ui_calculateLayout();
layout_ready = true; 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) if(!layout_ready)
{ {
layout = _ui_calculateLayout(); layout = _ui_calculateLayout();
layout_ready = true; layout_ready = true;
} }
gfx_clearScreen(); bool screen_update = ui_drawMainScreen(last_state);
ui_drawMainScreen(state); return screen_update;
return true;
} }
void ui_terminate() void ui_terminate()