Partially refactored UI code

This commit is contained in:
Silvano Seva 2022-08-16 21:39:47 +02:00
parent 42b262c437
commit cf842306c2
2 changed files with 371 additions and 327 deletions

View File

@ -77,45 +77,10 @@
#include <battery.h>
#include <input.h>
#include <hwconfig.h>
#include "core/voicePromptUtils.h"
#include <voicePromptUtils.h>
// 0 not latched, a positive number start timer which counts down to 0 at which
// time latch automatically disabled.
// If a subsequent key is pressed before timeout, timer restarts.
static uint16_t functionLatchTimer = 0;
// 3000 ms.
#define FUNCTION_LATCH_TIMEOUT 3000
// When a key is pressed while Moni is latched, the latch timer is restarted.
static void RestartFunctionLatchTimer()
{
if (functionLatchTimer == 0) return;
functionLatchTimer = getTick() + FUNCTION_LATCH_TIMEOUT;
}
static void ReleaseFunctionLatchIfNeeded()
{
if (functionLatchTimer == 0) return;
if (getTick() < functionLatchTimer)
return;
functionLatchTimer=0;
// Play beep for function latch release.
}
static void SetFunctionLatchTimer()
{
functionLatchTimer= getTick() + FUNCTION_LATCH_TIMEOUT;
// Play beep for set function latch.
}
static bool FunctionKeyIsLatched()
{
return (functionLatchTimer > 0) && (getTick() < functionLatchTimer);
}
/* UI main screen functions, their implementation is in "ui_main.c" */
extern void _ui_drawMainBackground();
extern void _ui_drawMainTop();
@ -288,13 +253,46 @@ static bool redraw_needed = true;
static bool standby = false;
static long long last_event_tick = 0;
static uint16_t functionLatchTimer = 0;
// UI event queue
static uint8_t evQueue_rdPos;
static uint8_t evQueue_wrPos;
static event_t evQueue[MAX_NUM_EVENTS];
layout_t _ui_calculateLayout()
static void RestartFunctionLatchTimer()
{
if (functionLatchTimer == 0)
return;
functionLatchTimer = getTick() + FUNCTION_LATCH_TIMEOUT;
}
static void ReleaseFunctionLatchIfNeeded()
{
if (functionLatchTimer == 0)
return;
if (getTick() < functionLatchTimer)
return;
functionLatchTimer = 0;
// Play beep for function latch release.
}
static void SetFunctionLatchTimer()
{
functionLatchTimer= getTick() + FUNCTION_LATCH_TIMEOUT;
// Play beep for set function latch.
}
static bool FunctionKeyIsLatched()
{
return (functionLatchTimer > 0) && (getTick() < functionLatchTimer);
}
static layout_t _ui_calculateLayout()
{
// Horizontal line height
const uint16_t hline_h = 1;
@ -447,39 +445,7 @@ layout_t _ui_calculateLayout()
return new_layout;
}
void ui_init()
{
last_event_tick = getTick();
redraw_needed = true;
layout = _ui_calculateLayout();
layout_ready = true;
// Initialize struct ui_state to all zeroes
// This syntax is called compound literal
// https://stackoverflow.com/questions/6891720/initialize-reset-struct-to-zero-null
ui_state = (const struct ui_state_t){ 0 };
}
void ui_drawSplashScreen(bool centered)
{
gfx_clearScreen();
point_t splash_origin = {0,0};
#ifdef OLD_SPLASH
if(centered)
splash_origin.y = SCREEN_HEIGHT / 2 + 6;
else
splash_origin.y = SCREEN_HEIGHT / 4;
gfx_print(splash_origin, FONT_SIZE_12PT, TEXT_ALIGN_CENTER, yellow_fab413, currentLanguage->openRTX);
#else
if(centered)
splash_origin.y = SCREEN_HEIGHT / 2 - 6;
else
splash_origin.y = SCREEN_HEIGHT / 5;
gfx_print(splash_origin, FONT_SIZE_12PT, TEXT_ALIGN_CENTER, yellow_fab413, "O P N\nR T X");
#endif
}
void _ui_drawLowBatteryScreen()
static void _ui_drawLowBatteryScreen()
{
gfx_clearScreen();
uint16_t bat_width = SCREEN_WIDTH / 2;
@ -501,7 +467,7 @@ void _ui_drawLowBatteryScreen()
currentLanguage->pressAnyButton);
}
freq_t _ui_freq_add_digit(freq_t freq, uint8_t pos, uint8_t number)
static freq_t _ui_freq_add_digit(freq_t freq, uint8_t pos, uint8_t number)
{
freq_t coefficient = 100;
for(uint8_t i=0; i < FREQ_DIGITS - pos; i++)
@ -512,7 +478,8 @@ freq_t _ui_freq_add_digit(freq_t freq, uint8_t pos, uint8_t number)
}
#ifdef RTC_PRESENT
void _ui_timedate_add_digit(datetime_t *timedate, uint8_t pos, uint8_t number)
static void _ui_timedate_add_digit(datetime_t *timedate, uint8_t pos,
uint8_t number)
{
switch(pos)
{
@ -555,7 +522,7 @@ void _ui_timedate_add_digit(datetime_t *timedate, uint8_t pos, uint8_t number)
}
#endif
bool _ui_freq_check_limits(freq_t freq)
static bool _ui_freq_check_limits(freq_t freq)
{
bool valid = false;
const hwInfo_t* hwinfo = platform_getHwInfo();
@ -576,20 +543,22 @@ bool _ui_freq_check_limits(freq_t freq)
return valid;
}
bool _ui_channel_valid(channel_t* channel)
static bool _ui_channel_valid(channel_t* channel)
{
return _ui_freq_check_limits(channel->rx_frequency) &&
_ui_freq_check_limits(channel->tx_frequency);
}
bool _ui_drawDarkOverlay() {
static bool _ui_drawDarkOverlay()
{
color_t alpha_grey = {0, 0, 0, 255};
point_t origin = {0, 0};
gfx_drawRect(origin, SCREEN_WIDTH, SCREEN_HEIGHT, alpha_grey, true);
return true;
}
int _ui_fsm_loadChannel(int16_t channel_index, bool *sync_rtx) {
static int _ui_fsm_loadChannel(int16_t channel_index, bool *sync_rtx)
{
channel_t channel;
int32_t selected_channel = channel_index;
// If a bank is active, get index from current bank
@ -601,9 +570,10 @@ int _ui_fsm_loadChannel(int16_t channel_index, bool *sync_rtx) {
return -1;
channel_index = cps_readBankData(state.bank, channel_index);
}
int result = cps_readChannel(&channel, channel_index);
// Read successful and channel is valid
if(result != -1 && _ui_channel_valid(&channel))
if((result != -1) && _ui_channel_valid(&channel))
{
// Set new channel index
state.channel_index = selected_channel;
@ -611,10 +581,11 @@ int _ui_fsm_loadChannel(int16_t channel_index, bool *sync_rtx) {
state.channel = channel;
*sync_rtx = true;
}
return result;
}
void _ui_fsm_confirmVFOInput(bool *sync_rtx)
static void _ui_fsm_confirmVFOInput(bool *sync_rtx)
{
vp_clearCurrPrompt();
// Switch to TX input
@ -647,16 +618,21 @@ void _ui_fsm_confirmVFOInput(bool *sync_rtx)
// force init to clear any prompts in progress.
// defer play because play is called at the end of the function
//due to above freq queuing.
vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit);
vp_announceFrequencies(state.channel.rx_frequency,
state.channel.tx_frequency, vpqInit);
}
else
{
vp_announceError(vpqInit);
}
state.ui_screen = MAIN_VFO;
}
vp_play();
}
void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
static void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
{
// Advance input position
ui_state.input_position += 1;
@ -676,7 +652,8 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
ui_state.new_rx_frequency = 0;
// Calculate portion of the new RX frequency
ui_state.new_rx_frequency = _ui_freq_add_digit(ui_state.new_rx_frequency,
ui_state.input_position, ui_state.input_number);
ui_state.input_position,
ui_state.input_number);
if(ui_state.input_position >= FREQ_DIGITS)
{// queue the rx freq just completed.
vp_queueFrequency(ui_state.new_rx_frequency);
@ -696,7 +673,8 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
ui_state.new_tx_frequency = 0;
// Calculate portion of the new TX frequency
ui_state.new_tx_frequency = _ui_freq_add_digit(ui_state.new_tx_frequency,
ui_state.input_position, ui_state.input_number);
ui_state.input_position,
ui_state.input_number);
if(ui_state.input_position >= FREQ_DIGITS)
{
// Save both inserted frequencies
@ -707,15 +685,18 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx)
state.channel.tx_frequency = ui_state.new_tx_frequency;
*sync_rtx = true;
// play is called at end.
vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit);
vp_announceFrequencies(state.channel.rx_frequency,
state.channel.tx_frequency, vpqInit);
}
state.ui_screen = MAIN_VFO;
}
}
vp_play();
}
void _ui_changeBrightness(int variation)
static void _ui_changeBrightness(int variation)
{
state.settings.brightness += variation;
@ -727,7 +708,8 @@ void _ui_changeBrightness(int variation)
platform_setBacklightLevel(state.settings.brightness);
}
void _ui_changeContrast(int variation)
#ifdef SCREEN_CONTRAST
static void _ui_changeContrast(int variation)
{
if(variation >= 0)
state.settings.contrast =
@ -735,10 +717,12 @@ void _ui_changeContrast(int variation)
else
state.settings.contrast =
(state.settings.contrast < -variation) ? 0 : state.settings.contrast + variation;
display_setContrast(state.settings.contrast);
}
#endif
void _ui_changeTimer(int variation)
static void _ui_changeTimer(int variation)
{
if ((state.settings.display_timer == TIMER_OFF && variation < 0) ||
(state.settings.display_timer == TIMER_1H && variation > 0))
@ -749,22 +733,23 @@ void _ui_changeTimer(int variation)
state.settings.display_timer += variation;
}
void _ui_changeVoiceLevel(int variation)
static void _ui_changeVoiceLevel(int variation)
{
if ((state.settings.vpLevel == vpNone && variation < 0) ||
(state.settings.vpLevel == vpHigh && variation > 0))
{
return;
}
state.settings.vpLevel += variation;
}
void _ui_changePhoneticSpell(bool newVal)
static void _ui_changePhoneticSpell(bool newVal)
{
state.settings.vpPhoneticSpell = newVal ? 1 : 0;
}
bool _ui_checkStandby(long long time_since_last_event)
static bool _ui_checkStandby(long long time_since_last_event)
{
if (standby)
{
@ -781,8 +766,7 @@ bool _ui_checkStandby(long long time_since_last_event)
case TIMER_20S:
case TIMER_25S:
case TIMER_30S:
return time_since_last_event >=
(5000 * state.settings.display_timer);
return time_since_last_event >= (5000 * state.settings.display_timer);
case TIMER_1M:
case TIMER_2M:
case TIMER_3M:
@ -803,7 +787,7 @@ bool _ui_checkStandby(long long time_since_last_event)
return false;
}
void _ui_enterStandby()
static void _ui_enterStandby()
{
if(standby)
return;
@ -813,7 +797,7 @@ void _ui_enterStandby()
platform_setBacklightLevel(0);
}
bool _ui_exitStandby(long long now)
static bool _ui_exitStandby(long long now)
{
last_event_tick = now;
@ -826,11 +810,12 @@ bool _ui_exitStandby(long long now)
return true;
}
void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
static void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
{
ui_state.input_number = input_getPressedNumber(msg);
if (ui_state.input_number != 0)
RestartFunctionLatchTimer(); // reset the timer.
// CTCSS Encode/Decode Selection
bool tone_tx_enable = state.channel.fm.txToneEn;
bool tone_rx_enable = state.channel.fm.rxToneEn;
@ -846,11 +831,14 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
state.channel.fm.txTone %= MAX_TONE_INDEX;
state.channel.fm.rxTone = state.channel.fm.txTone;
*sync_rtx = true;
vp_announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone,
state.channel.fm.txToneEn, state.channel.fm.txTone,
vp_announceCTCSS(state.channel.fm.rxToneEn,
state.channel.fm.rxTone,
state.channel.fm.txToneEn,
state.channel.fm.txTone,
queueFlags);
}
break;
case 2:
if(state.channel.mode == OPMODE_FM)
{
@ -870,8 +858,10 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
state.channel.fm.txToneEn = tone_tx_enable;
state.channel.fm.rxToneEn = tone_rx_enable;
*sync_rtx = true;
vp_announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone,
state.channel.fm.txToneEn, state.channel.fm.txTone,
vp_announceCTCSS(state.channel.fm.rxToneEn,
state.channel.fm.rxTone,
state.channel.fm.txToneEn,
state.channel.fm.txTone,
queueFlags);
}
break;
@ -918,7 +908,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
if(msg.keys & KNOB_LEFT || msg.keys & KNOB_RIGHT) {
state.settings.sqlLevel = platform_getChSelector() - 1;
*sync_rtx = true;
announceSquelch(state.settings.sqlLevel, queueFlags);
vp_announceSquelch(state.settings.sqlLevel, queueFlags);
RestartFunctionLatchTimer(); // reset the timer.
}
@ -953,7 +943,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx)
}
}
void _ui_menuUp(uint8_t menu_entries)
static void _ui_menuUp(uint8_t menu_entries)
{
if(ui_state.menu_selected > 0)
ui_state.menu_selected -= 1;
@ -961,7 +951,7 @@ void _ui_menuUp(uint8_t menu_entries)
ui_state.menu_selected = menu_entries - 1;
}
void _ui_menuDown(uint8_t menu_entries)
static void _ui_menuDown(uint8_t menu_entries)
{
if(ui_state.menu_selected < menu_entries - 1)
ui_state.menu_selected += 1;
@ -969,7 +959,7 @@ void _ui_menuDown(uint8_t menu_entries)
ui_state.menu_selected = 0;
}
void _ui_menuBack(uint8_t prev_state)
static void _ui_menuBack(uint8_t prev_state)
{
if(ui_state.edit_mode)
{
@ -984,7 +974,7 @@ void _ui_menuBack(uint8_t prev_state)
}
}
void _ui_textInputReset(char *buf)
static void _ui_textInputReset(char *buf)
{
ui_state.input_number = 0;
ui_state.input_position = 0;
@ -994,7 +984,8 @@ void _ui_textInputReset(char *buf)
buf[0] = '_';
}
void _ui_textInputKeypad(char *buf, uint8_t max_len, kbd_msg_t msg, bool callsign)
static void _ui_textInputKeypad(char *buf, uint8_t max_len, kbd_msg_t msg,
bool callsign)
{
if(ui_state.input_position >= max_len)
return;
@ -1037,12 +1028,12 @@ void _ui_textInputKeypad(char *buf, uint8_t max_len, kbd_msg_t msg, bool callsig
ui_state.last_keypress = now;
}
void _ui_textInputConfirm(char *buf)
static void _ui_textInputConfirm(char *buf)
{
buf[ui_state.input_position + 1] = '\0';
}
void _ui_textInputDel(char *buf)
static void _ui_textInputDel(char *buf)
{
buf[ui_state.input_position] = '\0';
// Move back input cursor
@ -1057,6 +1048,41 @@ void _ui_textInputDel(char *buf)
ui_state.input_set = 0;
}
void ui_init()
{
last_event_tick = getTick();
redraw_needed = true;
layout = _ui_calculateLayout();
layout_ready = true;
// Initialize struct ui_state to all zeroes
// This syntax is called compound literal
// https://stackoverflow.com/questions/6891720/initialize-reset-struct-to-zero-null
ui_state = (const struct ui_state_t){ 0 };
}
void ui_drawSplashScreen(bool centered)
{
gfx_clearScreen();
point_t splash_origin = {0,0};
#ifdef OLD_SPLASH
if(centered)
splash_origin.y = SCREEN_HEIGHT / 2 + 6;
else
splash_origin.y = SCREEN_HEIGHT / 4;
gfx_print(splash_origin, FONT_SIZE_12PT, TEXT_ALIGN_CENTER, yellow_fab413,
currentLanguage->openRTX);
#else
if(centered)
splash_origin.y = SCREEN_HEIGHT / 2 - 6;
else
splash_origin.y = SCREEN_HEIGHT / 5;
gfx_print(splash_origin, FONT_SIZE_12PT, TEXT_ALIGN_CENTER, yellow_fab413,
"O P N\nR T X");
#endif
}
void ui_saveState()
{
last_state = state;
@ -1170,7 +1196,8 @@ void ui_updateFSM(bool *sync_rtx)
ui_state.last_main_state = state.ui_screen;
// Open Menu
state.ui_screen = MENU_TOP;
// TODO: announce the menu name and selected item.
// TODO: announce the menu name.
// The selected item will be announced when the item is first selected.
}
else if(msg.keys & KEY_ESC)
{
@ -1183,7 +1210,9 @@ void ui_updateFSM(bool *sync_rtx)
// Switch to MEM screen
state.ui_screen = MAIN_MEM;
// anounce the active channel name.
vp_announceChannelName(&state.channel, state.channel_index, queueFlags);
vp_announceChannelName(&state.channel,
state.channel_index,
queueFlags);
}
}
else if(msg.keys & KEY_HASH)
@ -1202,7 +1231,9 @@ void ui_updateFSM(bool *sync_rtx)
state.channel.rx_frequency += 12500;
state.channel.tx_frequency += 12500;
*sync_rtx = true;
vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags);
vp_announceFrequencies(state.channel.rx_frequency,
state.channel.tx_frequency,
queueFlags);
}
}
else if(msg.keys & KEY_DOWN || msg.keys & KNOB_LEFT)
@ -1214,7 +1245,9 @@ void ui_updateFSM(bool *sync_rtx)
state.channel.rx_frequency -= 12500;
state.channel.tx_frequency -= 12500;
*sync_rtx = true;
vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags);
vp_announceFrequencies(state.channel.rx_frequency,
state.channel.tx_frequency,
queueFlags);
}
}
else if(msg.keys & KEY_F1)
@ -1233,9 +1266,10 @@ void ui_updateFSM(bool *sync_rtx)
if (state.settings.vpLevel > vpBeep)
{// quick press repeat vp, long press summary.
if (msg.long_press)
announceChannelSummary(&state.channel, 0, state.bank);
vp_announceChannelSummary(&state.channel, 0,
state.bank);
else
ReplayLastPrompt();
vp_replayLastPrompt();
f1Handled = true;
}
}
@ -1254,7 +1288,8 @@ void ui_updateFSM(bool *sync_rtx)
ui_state.input_number = input_getPressedNumber(msg);
// Calculate portion of the new frequency
ui_state.new_rx_frequency = _ui_freq_add_digit(ui_state.new_rx_frequency,
ui_state.input_position, ui_state.input_number);
ui_state.input_position,
ui_state.input_number);
}
}
break;
@ -1317,11 +1352,19 @@ void ui_updateFSM(bool *sync_rtx)
else if(msg.keys & KEY_F1)
{
if (state.settings.vpLevel > vpBeep)
{// quick press repeat vp, long press summary.
{
// Quick press repeat vp, long press summary.
if (msg.long_press)
vp_announceChannelSummary(&state.channel, state.channel_index, state.bank);
{
vp_announceChannelSummary(&state.channel,
state.channel_index,
state.bank);
}
else
{
vp_replayLastPrompt();
}
f1Handled = true;
}
}
@ -1846,7 +1889,6 @@ void ui_updateFSM(bool *sync_rtx)
{
vp_replayLastPrompt();
}
}
else if(event.type == EVENT_STATUS)
{

View File

@ -57,18 +57,20 @@ const char *display_timer_values[] =
"1 hour"
};
bool DidSelectedMenuItemChange(char* menuName, char* menuValue)
{// menu name can't be empty.
if (!menuName || !*menuName)
static bool DidSelectedMenuItemChange(char* menuName, char* menuValue)
{
// menu name can't be empty.
if ((menuName == NULL) || (*menuName == '\0'))
return false;
// If value is supplied it can't be empty but it does not have to be supplied.
if (menuValue && !*menuValue)
if ((menuValue != NULL) && (*menuValue == '\0'))
return false;
if (strcmp(menuName, priorSelectedMenuName) != 0)
{
strcpy(priorSelectedMenuName, menuName);
if (menuValue)
if (menuValue != NULL)
strcpy(priorSelectedMenuValue, menuValue);
else
*priorSelectedMenuValue = '\0'; // reset it since we've changed menu item.
@ -76,7 +78,7 @@ bool DidSelectedMenuItemChange(char* menuName, char* menuValue)
return true;
}
if (menuValue && strcmp(menuValue, priorSelectedMenuValue) != 0)
if ((menuValue != NULL) && (strcmp(menuValue, priorSelectedMenuValue) != 0))
{
strcpy(priorSelectedMenuValue, menuValue);
return true;
@ -90,10 +92,10 @@ static void announceMenuItemIfNeeded(char* name, char* value)
if (state.settings.vpLevel <= vpLow)
return;
if (!name || !*name)
if ((name == NULL) || (*name == '\0'))
return;
if (!DidSelectedMenuItemChange(name, value))
if (DidSelectedMenuItemChange(name, value) == false)
return;
// See if we are already in the middle of speaking a menu item.
@ -103,10 +105,10 @@ static void announceMenuItemIfNeeded(char* name, char* value)
// Stop any prompt in progress and clear the buffer.
vp_clearCurrPrompt();
// If no value is supplied, or, no prompt is in progress, announce the name.
if (!voicePromptWasPlaying || !value || !*value)
if ((voicePromptWasPlaying == false) || (value == NULL) || (*value == '\0'))
vp_announceText(name, vpqDefault);
if (value && *value)
if ((value != NULL) && (*value != '\0'))
vp_announceText(value, vpqDefault);
vp_play();