Merge pull request #218 from mrkusypl/v5_fix

Code refactoring; improvements to K5Viewer and the UI
This commit is contained in:
Armel FAUVEAU authored and GitHub committed 2026-03-17 00:30:07 +01:00
commit 7d5e5b7d97
14 files changed
+238 -278

No files matched your search

+11 -16
View File
@@ -331,10 +331,6 @@ void AIRCOPY_StorePacket(void)
static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld || !bKeyPressed) {
return;
}
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_AIRCOPY;
@@ -379,10 +375,6 @@ static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
static void AIRCOPY_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld || !bKeyPressed) {
return;
}
if (gInputBoxIndex == 0) {
gAircopyStep = 1;
gFSKWriteIndex = 0;
@@ -405,10 +397,6 @@ static void AIRCOPY_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
static void AIRCOPY_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld || !bKeyPressed) {
return;
}
gAircopyStep = 1;
gFSKWriteIndex = 0;
gAirCopyBlockNumber = 0;
@@ -427,10 +415,6 @@ static void AIRCOPY_Key_MENU(bool bKeyPressed, bool bKeyHeld)
static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
{
if (bKeyHeld || !bKeyPressed) {
return;
}
if (!gEeprom.SET_NAV) {
Direction = -Direction;
}
@@ -450,6 +434,14 @@ static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Directio
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld || !bKeyPressed) {
return;
}
if (Key != KEY_PTT) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
switch (Key) {
case KEY_0...KEY_9:
AIRCOPY_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
@@ -464,7 +456,10 @@ void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
case KEY_DOWN:
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
break;
case KEY_PTT:
break;
default:
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
}
+7 -3
View File
@@ -1609,9 +1609,11 @@ void APP_TimeSlice500ms(void)
}
#endif
const int m = UI_MENU_GetCurrentMenuId();
if (gBacklightCountdown_500ms > 0 && !gAskToSave && !gCssBackgroundScan
// don't turn off backlight if user is in backlight menu option
&& !(gScreenToDisplay == DISPLAY_MENU && (UI_MENU_GetCurrentMenuId() == MENU_ABR || UI_MENU_GetCurrentMenuId() == MENU_ABR_MAX))
&& !(gScreenToDisplay == DISPLAY_MENU && (m == MENU_ABR || m == MENU_ABR_MAX || m == MENU_ABR_MIN))
&& --gBacklightCountdown_500ms == 0
&& gEeprom.BACKLIGHT_TIME < 61
) {
@@ -1729,8 +1731,10 @@ void APP_TimeSlice500ms(void)
if (exit_menu) {
gMenuCountdown = 0;
if (gEeprom.BACKLIGHT_TIME == 0) {
BACKLIGHT_TurnOff();
const int m = UI_MENU_GetCurrentMenuId();
if (gScreenToDisplay == DISPLAY_MENU && (m == MENU_ABR || m == MENU_ABR_MAX || m == MENU_ABR_MIN)) {
BACKLIGHT_TurnOn();
}
if (gInputBoxIndex > 0 || gDTMF_InputMode) {
+42 -45
View File
@@ -99,16 +99,15 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
{
uint8_t Vfo = gEeprom.TX_VFO;
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
if(Key == 2) { // Enable A/B only
gVfoConfigureMode = VFO_CONFIGURE;
COMMON_SwitchVFOs();
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return; // prevent F function if MENU LOCK is true
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true && Key != 2) {
gUpdateStatus = true;
gWasFKeyPressed = false;
return;
}
#endif
@@ -128,7 +127,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
if (!IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gWasFKeyPressed = false;
gUpdateStatus = true;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
#ifdef ENABLE_COPY_CHAN_TO_VFO
if (!gEeprom.VFO_OPEN || gCssBackgroundScan) {
@@ -192,9 +190,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
gRequestDisplayScreen = DISPLAY_MAIN;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
case KEY_2:
@@ -202,8 +197,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
gVfoConfigureMode = VFO_CONFIGURE;
#endif
COMMON_SwitchVFOs();
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
case KEY_3:
@@ -211,8 +204,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
gVfoConfigureMode = VFO_CONFIGURE;
#endif
COMMON_SwitchVFOMode();
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
@@ -222,8 +213,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gUpdateStatus = true;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
SCANNER_Start(false);
gRequestDisplayScreen = DISPLAY_SCANNER;
@@ -550,7 +539,13 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
return;
}
gKeyInputCountdown = (gInputBoxIndex == totalDigits) ? (key_input_timeout_500ms / 16) : (key_input_timeout_500ms / 3);
gKeyInputCountdown = (gInputBoxIndex >= totalDigits) ? (key_input_timeout_500ms / 16) : (key_input_timeout_500ms / 3);
if (gInputBoxIndex >= totalDigits) {
gInputBoxIndex = totalDigits;
return;
}
const char *inputStr = INPUTBOX_GetAscii();
uint8_t inputLength = gInputBoxIndex;
@@ -643,6 +638,12 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gWasFKeyPressed = false;
gUpdateStatus = true;
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true && Key != 2) {
return;
}
#endif
if(Key == 8)
{
ACTION_BackLightOnDemand();
@@ -656,11 +657,6 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
#ifdef ENABLE_FEAT_F4HWN_GAME
else if(Key == 7)
{
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
return;
}
#endif
APP_RunBreakout();
return;
}
@@ -839,7 +835,12 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
}
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == false) {
if(gEeprom.MENU_LOCK == true) {
gUpdateStatus = true;
gWasFKeyPressed = false;
return;
}
#endif
gFlagRefreshSetting = true;
@@ -847,10 +848,6 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_MENU;
#endif
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
}
#endif
}
else {
gRequestDisplayScreen = DISPLAY_MAIN;
@@ -860,13 +857,6 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
{
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
return; // prevent F function if MENU LOCK is true
}
#endif
if (gCurrentFunction == FUNCTION_TRANSMIT)
return;
@@ -876,6 +866,20 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
return;
}
if (!bKeyHeld && bKeyPressed) { // star key pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; // beep when key is pressed
return; // don't use the key till it's released
}
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
gUpdateStatus = true;
gWasFKeyPressed = false;
return; // prevent F function if MENU LOCK is true
}
#endif
if (bKeyHeld && !gWasFKeyPressed){ // long press
if (!bKeyPressed) // released
return;
@@ -898,12 +902,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
if (bKeyPressed) { // just pressed
return;
}
// just released
if (!gWasFKeyPressed) // pressed without the F-key
{
@@ -916,7 +914,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
#endif
)
{ // start entering a DTMF string
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
memcpy(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
gDTMF_InputBox_Index = 0;
gDTMF_InputMode = true;
@@ -958,7 +955,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
#ifdef ENABLE_FEAT_F4HWN // Set Squelch F + UP or Down
if(gWasFKeyPressed) {
processFKeyFunction(Direction == 1 ? KEY_UP : KEY_DOWN, false);
processFKeyFunction(Direction == 1 ? KEY_UP : KEY_DOWN, true);
return;
}
#endif
+49 -34
View File
@@ -1547,12 +1547,14 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
return;
}
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
UI_MENU_GetCurrentMenuId() == MENU_1_CALL ||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 ||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2 ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
const int m = UI_MENU_GetCurrentMenuId();
if (m == MENU_MEM_CH ||
m == MENU_DEL_CH ||
m == MENU_1_CALL ||
m == MENU_S_PRI_CH_1 ||
m == MENU_S_PRI_CH_2 ||
m == MENU_MEM_NAME)
{ // enter 4-digit channel number
if (gInputBoxIndex < 4)
@@ -1692,19 +1694,21 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
if (!gIsInSubMenu)
{
const int m = UI_MENU_GetCurrentMenuId();
#ifdef ENABLE_VOICE
if (UI_MENU_GetCurrentMenuId() != MENU_SCR)
if (m != MENU_SCR)
gAnotherVoiceID = MenuList[gMenuCursor].voice_id;
#endif
if (UI_MENU_GetCurrentMenuId() == MENU_UPCODE
|| UI_MENU_GetCurrentMenuId() == MENU_DWCODE
if (m == MENU_UPCODE
|| m == MENU_DWCODE
#ifdef ENABLE_DTMF_CALLING
|| UI_MENU_GetCurrentMenuId() == MENU_ANI_ID
|| m == MENU_ANI_ID
#endif
)
return;
#if 1
if (UI_MENU_GetCurrentMenuId() == MENU_DEL_CH || UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
if (m == MENU_DEL_CH || m == MENU_MEM_NAME)
if (!RADIO_CheckValidChannel(gSubMenuSelection, false, 0))
return; // invalid channel
#endif
@@ -1712,7 +1716,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
gAskForConfirmation = 0;
gIsInSubMenu = true;
// if (UI_MENU_GetCurrentMenuId() != MENU_D_LIST)
// if (m != MENU_D_LIST)
{
gInputBoxIndex = 0;
edit_index = -1;
@@ -1763,10 +1767,12 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
if (gIsInSubMenu)
{
if (UI_MENU_GetCurrentMenuId() == MENU_RESET ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
const int m = UI_MENU_GetCurrentMenuId();
if (m == MENU_RESET ||
m == MENU_MEM_CH ||
m == MENU_DEL_CH ||
m == MENU_MEM_NAME)
{
switch (gAskForConfirmation)
{
@@ -1853,7 +1859,8 @@ static void MENU_Key_STAR(const bool bKeyPressed, const bool bKeyHeld)
if (gRxVfo->Modulation == MODULATION_FM)
#endif
{
if ((UI_MENU_GetCurrentMenuId() == MENU_R_CTCS || UI_MENU_GetCurrentMenuId() == MENU_R_DCS) && gIsInSubMenu)
const int m = UI_MENU_GetCurrentMenuId();
if ((m == MENU_R_CTCS || m == MENU_R_DCS) && gIsInSubMenu)
{ // scan CTCSS or DCS to find the tone/code of the incoming signal
if (!SCANNER_IsScanning())
MENU_StartCssScan();
@@ -1925,9 +1932,11 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
gRequestDisplayScreen = DISPLAY_MENU;
if (UI_MENU_GetCurrentMenuId() != MENU_ABR
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MIN
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MAX
const int m = UI_MENU_GetCurrentMenuId();
if (m != MENU_ABR
&& m != MENU_ABR_MIN
&& m != MENU_ABR_MAX
&& gEeprom.BACKLIGHT_TIME == 0) // backlight always off and not in the backlight menu
{
BACKLIGHT_TurnOff();
@@ -1953,8 +1962,10 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
}
VFO = 0;
const int m = UI_MENU_GetCurrentMenuId();
switch (UI_MENU_GetCurrentMenuId())
switch (m)
{
case MENU_DEL_CH:
case MENU_1_CALL:
@@ -1970,19 +1981,21 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
return;
}
if(UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 || UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2)
if(m == MENU_S_PRI_CH_1 || m == MENU_S_PRI_CH_2)
{
static int16_t last;
if(Direction > 0 && gSubMenuSelection == MR_CHANNELS_MAX)
{
gSubMenuSelection = -1;
last = -1;
}
else if(Direction < 0 && gSubMenuSelection == MR_CHANNELS_MAX)
{
gSubMenuSelection = MR_CHANNELS_MAX;
last = MR_CHANNELS_MAX;
if(gSubMenuSelection == MR_CHANNELS_MAX) {
if(Direction > 0)
{
gSubMenuSelection = -1;
last = -1;
}
else if(Direction < 0)
{
gSubMenuSelection = MR_CHANNELS_MAX;
last = MR_CHANNELS_MAX;
}
}
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
@@ -2067,11 +2080,13 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
if (gScreenToDisplay == DISPLAY_MENU)
{
if (UI_MENU_GetCurrentMenuId() == MENU_VOL ||
const int m = UI_MENU_GetCurrentMenuId();
if (m == MENU_VOL ||
#ifdef ENABLE_F_CAL_MENU
UI_MENU_GetCurrentMenuId() == MENU_F_CALI ||
m == MENU_F_CALI ||
#endif
UI_MENU_GetCurrentMenuId() == MENU_BATCAL)
m == MENU_BATCAL)
{
gMenuCountdown = menu_timeout_long_500ms;
}
+52 -10
View File
@@ -36,30 +36,72 @@ bool gWasFKeyPressed = false;
// Must exceed key_repeat_delay_10ms (40) to trigger ProcessKey(key, true, true).
#define SERIAL_KEY_LONG_POLLS 45
// Packet types for serial key injection (K5Viewer → radio)
#define SERIAL_KEY_TYPE 0x03
#define SERIAL_KEY_TYPE_LONG 0x04
volatile KEY_Code_t gKeyFromSerial = KEY_INVALID;
static uint8_t gSerialKeyHoldCount = 0;
static uint8_t gSerialKeyLong = 0; // 0 = short press, 1 = long press
// Inject a short press from serial (UART or VCP).
// Inject a short or long press from serial (UART or VCP).
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
void KEYBOARD_InjectKey(uint8_t keyCode)
void KEYBOARD_InjectKey(uint8_t keyCode, bool keyLong)
{
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
gKeyFromSerial = (KEY_Code_t)keyCode;
gSerialKeyHoldCount = 0;
gSerialKeyLong = 0;
gSerialKeyLong = keyLong;
}
}
// Inject a long press from serial (UART or VCP).
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
void KEYBOARD_InjectKeyLong(uint8_t keyCode)
bool KEYBOARD_ProcessProtocolByte(ParseState_t *state, uint8_t b)
{
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
gKeyFromSerial = (KEY_Code_t)keyCode;
gSerialKeyHoldCount = 0;
gSerialKeyLong = 1;
bool connected = false;
switch (*state)
{
case STATE_IDLE:
if (b == 0x55) *state = STATE_KA_1;
else if (b == 0xAA) *state = STATE_KEY_1;
break;
case STATE_KA_1:
*state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
break;
case STATE_KA_2:
*state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
break;
case STATE_KA_3:
if (b == 0x00) connected = true;
*state = STATE_IDLE;
break;
case STATE_KEY_1:
*state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
break;
case STATE_KEY_2:
if (b == SERIAL_KEY_TYPE) *state = STATE_KEY_3;
else if (b == SERIAL_KEY_TYPE_LONG) *state = STATE_KEY_3L;
else *state = STATE_IDLE;
break;
case STATE_KEY_3:
case STATE_KEY_3L:
KEYBOARD_InjectKey(b, *state == STATE_KEY_3L);
connected = true;
*state = STATE_IDLE;
break;
default:
*state = STATE_IDLE;
break;
}
return connected;
}
#endif
+14 -5
View File
@@ -45,6 +45,17 @@ enum KEY_Code_e {
};
typedef enum KEY_Code_e KEY_Code_t;
typedef enum {
STATE_IDLE = 0,
STATE_KA_1,
STATE_KA_2,
STATE_KA_3,
STATE_KEY_1,
STATE_KEY_2,
STATE_KEY_3,
STATE_KEY_3L,
} ParseState_t;
extern KEY_Code_t gKeyReading0;
extern KEY_Code_t gKeyReading1;
extern uint16_t gDebounceCounter;
@@ -54,11 +65,9 @@ extern bool gWasFKeyPressed;
// Serial-injected key (written by UART/VCP parser, consumed by KEYBOARD_Poll).
extern volatile KEY_Code_t gKeyFromSerial;
// Inject a short press received from serial (UART or VCP).
void KEYBOARD_InjectKey(uint8_t keyCode);
// Inject a long press received from serial (UART or VCP).
void KEYBOARD_InjectKeyLong(uint8_t keyCode);
// Inject a short or long press received from serial (UART or VCP).
void KEYBOARD_InjectKey(uint8_t keyCode, bool keyLong);
bool KEYBOARD_ProcessProtocolByte(ParseState_t *state, uint8_t b);
#endif
KEY_Code_t KEYBOARD_Poll(void);
+2 -52
View File
@@ -25,9 +25,6 @@
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
#include "driver/keyboard.h"
// Packet types for serial key injection (K5Viewer → radio)
#define UART_TYPE_KEY 0x03
#define UART_TYPE_KEY_LONG 0x04
#endif
#define USARTx USART1
@@ -155,17 +152,6 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
bool UART_IsCableConnected(void) {
typedef enum {
STATE_IDLE = 0,
STATE_KA_1,
STATE_KA_2,
STATE_KA_3,
STATE_KEY_1,
STATE_KEY_2,
STATE_KEY_3,
STATE_KEY_3L,
} ParseState_t;
static uint8_t read_ptr = 0;
static ParseState_t state = STATE_IDLE;
@@ -182,44 +168,8 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
// read_ptr wraps naturally at 256 since it's uint8_t
processed++;
switch (state)
{
case STATE_IDLE:
if (b == 0x55) state = STATE_KA_1;
else if (b == 0xAA) state = STATE_KEY_1;
break;
case STATE_KA_1:
state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
break;
case STATE_KA_2:
state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
break;
case STATE_KA_3:
if (b == 0x00) connected = true;
state = STATE_IDLE;
break;
case STATE_KEY_1:
state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
break;
case STATE_KEY_2:
if (b == UART_TYPE_KEY) state = STATE_KEY_3;
else if (b == UART_TYPE_KEY_LONG) state = STATE_KEY_3L;
else state = STATE_IDLE;
break;
case STATE_KEY_3:
KEYBOARD_InjectKey(b);
connected = true;
state = STATE_IDLE;
break;
case STATE_KEY_3L:
KEYBOARD_InjectKeyLong(b);
connected = true;
state = STATE_IDLE;
break;
default:
state = STATE_IDLE;
break;
}
if(KEYBOARD_ProcessProtocolByte(&state, b))
connected = true;
}
return connected;
+7 -64
View File
@@ -20,9 +20,6 @@
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
#include "driver/keyboard.h"
// Packet types for serial key injection (K5Viewer → radio)
#define VCP_TYPE_KEY 0x03
#define VCP_TYPE_KEY_LONG 0x04
#endif
uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE];
@@ -63,25 +60,14 @@ bool VCP_ScreenshotPing(void)
// KEY_1 → 0x55 → KEY_2 (else IDLE)
// KEY_2 → 0x03 → KEY_3 (short press, else check long)
// KEY_2 → 0x04 → KEY_3L (long press, else IDLE)
// KEY_3 → <b> → InjectKey(b), IDLE
// KEY_3L → <b> → InjectKeyLong(b), IDLE
// KEY_3 → <b> → KEYBOARD_InjectKey(b, false), IDLE
// KEY_3L → <b> → KEYBOARD_InjectKey(b, true), IDLE
typedef enum {
STATE_IDLE = 0,
STATE_KA_1,
STATE_KA_2,
STATE_KA_3,
STATE_KEY_1,
STATE_KEY_2,
STATE_KEY_3,
STATE_KEY_3L,
} ParseState_t;
static uint32_t read_ptr = 0;
static uint8_t read_ptr = 0;
static ParseState_t state = STATE_IDLE;
bool connected = false;
uint32_t write_ptr = VCP_RxBufPointer; // snapshot once — ISR may update concurrently
uint8_t write_ptr = VCP_RxBufPointer; // snapshot once — ISR may update concurrently
// Cap bytes processed per call to VCP_RX_BUF_SIZE.
// Prevents unbounded loop if the ISR write pointer laps read_ptr
@@ -91,57 +77,14 @@ bool VCP_ScreenshotPing(void)
while (read_ptr != write_ptr && processed < VCP_RX_BUF_SIZE)
{
uint8_t b = VCP_RxBuf[read_ptr];
read_ptr++;
if (read_ptr >= VCP_RX_BUF_SIZE)
read_ptr = 0;
processed++;
switch (state)
{
case STATE_IDLE:
if (b == 0x55) state = STATE_KA_1;
else if (b == 0xAA) state = STATE_KEY_1;
break;
case STATE_KA_1:
state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
break;
case STATE_KA_2:
state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
break;
case STATE_KA_3:
if (b == 0x00) connected = true;
state = STATE_IDLE;
break;
case STATE_KEY_1:
state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
break;
case STATE_KEY_2:
if (b == VCP_TYPE_KEY) state = STATE_KEY_3;
else if (b == VCP_TYPE_KEY_LONG) state = STATE_KEY_3L;
else state = STATE_IDLE;
break;
case STATE_KEY_3:
KEYBOARD_InjectKey(b);
connected = true;
state = STATE_IDLE;
break;
case STATE_KEY_3L:
KEYBOARD_InjectKeyLong(b);
connected = true;
state = STATE_IDLE;
break;
default:
state = STATE_IDLE;
break;
}
if(KEYBOARD_ProcessProtocolByte(&state, b))
connected = true;
}
return connected;
+12
View File
@@ -634,4 +634,16 @@ void MR_PrintCacheStats(void)
// cache_hits, cache_misses, MR_GetCacheHitRate());
}
#endif
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
bool SCREENSHOT_IsLocked(void)
{
if (gUART_LockScreenshot > 0) {
gUART_LockScreenshot--;
return true;
}
return false;
}
#endif
+2
View File
@@ -323,6 +323,8 @@ extern volatile bool gTxTimeoutReached;
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
extern volatile uint8_t gUART_LockScreenshot; // lock screenshot if Chirp is used
extern bool gUSB_ScreenshotEnabled;
bool SCREENSHOT_IsLocked(void);
#endif
#endif
+11 -20
View File
@@ -26,17 +26,19 @@
// - No currentFrame or deltaFrame static buffers
static uint8_t previousFrame[1024] = {0};
static uint8_t forcedBlock = 0;
static uint8_t keepAlive = 10;
static bool wasConnected = false;
static uint8_t keepAlive = 0;
void SCREENSHOT_ParseInput(void)
{
if (SCREENSHOT_IsLocked())
return;
if (UART_IsCableConnected()) {
keepAlive = 10;
keepAlive = 15;
gUSB_ScreenshotEnabled = false;
}
if (VCP_ScreenshotPing()) {
keepAlive = 10;
else if (VCP_ScreenshotPing()) {
keepAlive = 15;
gUSB_ScreenshotEnabled = true;
}
}
@@ -58,21 +60,10 @@ void SCREENSHOT_Update(bool force)
uint16_t index = 0;
uint8_t acc = 0;
uint8_t bitCount = 0;
static bool wasConnected = false;
if (gUART_LockScreenshot > 0) {
gUART_LockScreenshot--;
if (SCREENSHOT_IsLocked())
return;
}
if (UART_IsCableConnected()) {
keepAlive = 10;
gUSB_ScreenshotEnabled = false;
}
if (VCP_ScreenshotPing()) {
keepAlive = 10;
gUSB_ScreenshotEnabled = true;
}
if (keepAlive > 0) {
if (--keepAlive == 0) {
@@ -97,7 +88,7 @@ void SCREENSHOT_Update(bool force)
uint8_t bit = (gStatusLine[i] >> b) & 0x01;
acc |= (bit << bitCount++);
if (bitCount == 8) {
frameBuffer[index++] = acc;
frameBuffer[index++] = gSetting_set_inv ? ~acc : acc;
acc = 0;
bitCount = 0;
}
@@ -111,7 +102,7 @@ void SCREENSHOT_Update(bool force)
uint8_t bit = (gFrameBuffer[l][i] >> b) & 0x01;
acc |= (bit << bitCount++);
if (bitCount == 8) {
frameBuffer[index++] = acc;
frameBuffer[index++] = gSetting_set_inv ? ~acc : acc;
acc = 0;
bitCount = 0;
}
+6
View File
@@ -35,6 +35,12 @@ void UI_DisplayFM(void)
char *pPrintStr = String;
UI_DisplayClear();
#ifdef ENABLE_FEAT_F4HWN
if (gEeprom.KEY_LOCK && gKeypadLocked > 0) {
UI_PrintStringSmallBold("UNLOCK KEYBOARD", 12, 0, 5);
}
#endif
UI_PrintString("FM", 2, 0, 0, 8);
sprintf(String, "%d%s-%dM",
+20 -26
View File
@@ -173,31 +173,32 @@ void UI_DisplayStatus()
else
#endif
{
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
memcpy(line + x + 2, gFontRO, sizeof(gFontRO));
}
else
{
#endif
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
if(gDualWatchActive)
memcpy(line + x + (dw==1?0:2), gFontDWR, sizeof(gFontDWR) - (dw==1?0:5));
else
memcpy(line + x + 3, gFontHold, sizeof(gFontHold));
}
else if(dw == 2) { // XB - crossband
memcpy(line + x + 2, gFontXB, sizeof(gFontXB));
if(!gAirCopyBootMode) {
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gEeprom.MENU_LOCK == true) {
memcpy(line + x + 2, gFontRO, sizeof(gFontRO));
}
else
{
if(!gAirCopyBootMode)
#endif
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
if(gDualWatchActive)
memcpy(line + x + (dw==1?0:2), gFontDWR, sizeof(gFontDWR) - (dw==1?0:5));
else
memcpy(line + x + 3, gFontHold, sizeof(gFontHold));
}
else if(dw == 2) { // XB - crossband
memcpy(line + x + 2, gFontXB, sizeof(gFontXB));
}
else
{
memcpy(line + x + 2, gFontMO, sizeof(gFontMO));
}
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
}
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
#endif
}
#endif
}
}
x += sizeof(gFontDWR) + 3;
@@ -239,15 +240,8 @@ void UI_DisplayStatus()
size = sizeof(gFontKeyLock);
}
else if (gWasFKeyPressed) {
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if (!gEeprom.MENU_LOCK) {
src = gFontF;
size = sizeof(gFontF);
}
#else
src = gFontF;
size = sizeof(gFontF);
#endif
}
#ifdef ENABLE_FEAT_F4HWN
else if (gMute) {
+3 -3
View File
@@ -221,8 +221,8 @@ void UI_DisplayWelcome(void)
//ST7565_BlitStatusLine(); // blank status line : I think it's useless
ST7565_BlitFullScreen();
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
SCREENSHOT_Update(true);
#endif
// #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
// SCREENSHOT_Update(true); // I think that's useless too
// #endif
}
}