mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
42 files changed
+932
-659
No files matched your search
@@ -201,6 +201,7 @@ enable_feature(ENABLE_FEAT_F4HWN_PMR)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_GMRS_FRS_MURS)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_CA)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_DEBUG)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_MEM)
|
||||
|
||||
# ---- DEBUGGING ----
|
||||
|
||||
|
||||
+15
-23
@@ -236,7 +236,7 @@ void ACTION_Scan(bool bRestart)
|
||||
}
|
||||
|
||||
// channel mode. Keep scanning but toggle between scan lists
|
||||
RADIO_NextValidList();
|
||||
RADIO_NextValidList(1);
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
@@ -503,17 +503,13 @@ void ACTION_RxMode(void)
|
||||
{
|
||||
static bool cycle = 0;
|
||||
|
||||
switch(cycle) {
|
||||
case 0:
|
||||
gEeprom.DUAL_WATCH = !gEeprom.DUAL_WATCH;
|
||||
cycle = 1;
|
||||
break;
|
||||
case 1:
|
||||
gEeprom.CROSS_BAND_RX_TX = !gEeprom.CROSS_BAND_RX_TX;
|
||||
cycle = 0;
|
||||
break;
|
||||
if (cycle) {
|
||||
gEeprom.CROSS_BAND_RX_TX = !gEeprom.CROSS_BAND_RX_TX;
|
||||
} else {
|
||||
gEeprom.DUAL_WATCH = !gEeprom.DUAL_WATCH;
|
||||
}
|
||||
|
||||
cycle = !cycle;
|
||||
ACTION_Update();
|
||||
}
|
||||
|
||||
@@ -523,22 +519,18 @@ void ACTION_MainOnly(void)
|
||||
static uint8_t dw = 0;
|
||||
static uint8_t cb = 0;
|
||||
|
||||
switch(cycle) {
|
||||
case 0:
|
||||
dw = gEeprom.DUAL_WATCH;
|
||||
cb = gEeprom.CROSS_BAND_RX_TX;
|
||||
if (cycle) {
|
||||
gEeprom.DUAL_WATCH = dw;
|
||||
gEeprom.CROSS_BAND_RX_TX = cb;
|
||||
} else {
|
||||
dw = gEeprom.DUAL_WATCH;
|
||||
cb = gEeprom.CROSS_BAND_RX_TX;
|
||||
|
||||
gEeprom.DUAL_WATCH = 0;
|
||||
gEeprom.CROSS_BAND_RX_TX = 0;
|
||||
cycle = 1;
|
||||
break;
|
||||
case 1:
|
||||
gEeprom.DUAL_WATCH = dw;
|
||||
gEeprom.CROSS_BAND_RX_TX = cb;
|
||||
cycle = 0;
|
||||
break;
|
||||
gEeprom.DUAL_WATCH = 0;
|
||||
gEeprom.CROSS_BAND_RX_TX = 0;
|
||||
}
|
||||
|
||||
cycle = !cycle;
|
||||
ACTION_Update();
|
||||
}
|
||||
|
||||
|
||||
+9
-21
@@ -89,12 +89,13 @@ DECLARE_AIRCOPY_BANK(1)
|
||||
|
||||
static const AIRCOPY_Segment_t AIRCOPY_Segments_Settings[] = {
|
||||
{ 0xA000, 0xA170, AIRCOPY_WRITE_BYTES },
|
||||
{ 0x880E, 0x886E, AIRCOPY_WRITE_BYTES },
|
||||
};
|
||||
|
||||
static const AIRCOPY_TransferMap_t AIRCOPY_Map_Settings = {
|
||||
.segments = AIRCOPY_Segments_Settings,
|
||||
.num_segments = 1,
|
||||
.total_blocks = 6
|
||||
.num_segments = 2,
|
||||
.total_blocks = 8
|
||||
};
|
||||
|
||||
// Finally
|
||||
@@ -430,6 +431,10 @@ static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Directio
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gEeprom.SET_NAV) {
|
||||
Direction = -Direction;
|
||||
}
|
||||
|
||||
switch(Direction)
|
||||
{
|
||||
case 1:
|
||||
@@ -446,16 +451,7 @@ static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Directio
|
||||
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
switch (Key) {
|
||||
case KEY_0:
|
||||
case KEY_1:
|
||||
case KEY_2:
|
||||
case KEY_3:
|
||||
case KEY_4:
|
||||
case KEY_5:
|
||||
case KEY_6:
|
||||
case KEY_7:
|
||||
case KEY_8:
|
||||
case KEY_9:
|
||||
case KEY_0...KEY_9:
|
||||
AIRCOPY_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_MENU:
|
||||
@@ -465,16 +461,8 @@ void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
else
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
else
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+11
-33
@@ -273,18 +273,9 @@ static void HandleReceive(void)
|
||||
break;
|
||||
|
||||
case CODE_TYPE_CONTINUOUS_TONE:
|
||||
if (gFoundCTCSS && gFoundCTCSSCountdown_10ms == 0)
|
||||
{
|
||||
gFoundCTCSS = false;
|
||||
gFoundCDCSS = false;
|
||||
Mode = END_OF_RX_MODE_END;
|
||||
goto Skip;
|
||||
}
|
||||
break;
|
||||
|
||||
case CODE_TYPE_DIGITAL:
|
||||
case CODE_TYPE_REVERSE_DIGITAL:
|
||||
if (gFoundCDCSS && gFoundCDCSSCountdown_10ms == 0)
|
||||
if ((gFoundCTCSS && gFoundCTCSSCountdown_10ms == 0) || (gFoundCDCSS && gFoundCDCSSCountdown_10ms == 0))
|
||||
{
|
||||
gFoundCTCSS = false;
|
||||
gFoundCDCSS = false;
|
||||
@@ -1133,14 +1124,7 @@ void APP_Update(void)
|
||||
// go back to sleep
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
if(gWakeUp)
|
||||
{
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 200; // deep sleep now indexed on BatSav
|
||||
}
|
||||
else
|
||||
{
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
|
||||
}
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * (gWakeUp ? 200 : 10); // deep sleep now indexed on BatSav
|
||||
#else
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
|
||||
#endif
|
||||
@@ -1535,7 +1519,6 @@ void cancelUserInputModes(void)
|
||||
gWasFKeyPressed = false;
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 0;
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
gUpdateStatus = true;
|
||||
gUpdateDisplay = true;
|
||||
}
|
||||
@@ -1558,15 +1541,13 @@ void APP_TimeSlice500ms(void)
|
||||
if (--gKeyInputCountdown == 0)
|
||||
{
|
||||
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE) && (gInputBoxIndex == 1 || gInputBoxIndex == 2))
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE) && (gInputBoxIndex > 0 && gInputBoxIndex < 4))
|
||||
{
|
||||
channelMoveSwitch();
|
||||
|
||||
if (gBeepToPlay == BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL) {
|
||||
AUDIO_PlayBeep(gBeepToPlay);
|
||||
}
|
||||
|
||||
SETTINGS_SaveVfoIndices();
|
||||
}
|
||||
|
||||
cancelUserInputModes();
|
||||
@@ -1936,6 +1917,7 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
// cancel user input
|
||||
cancelUserInputModes();
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
|
||||
if (gMonitor)
|
||||
ACTION_Monitor(); //turn off the monitor
|
||||
@@ -2126,18 +2108,14 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (gScreenToDisplay != DISPLAY_INVALID && (
|
||||
(Key != KEY_SIDE1 && Key != KEY_SIDE2)
|
||||
#ifdef ENABLE_FEAT_F4HWN // For F + SIDE1 or F + SIDE2
|
||||
else if (gWasFKeyPressed && (Key == KEY_SIDE1 || Key == KEY_SIDE2)) {
|
||||
ProcessKeysFunctions[gScreenToDisplay](Key, bKeyPressed, bKeyHeld);
|
||||
}
|
||||
else if (Key != KEY_SIDE1 && Key != KEY_SIDE2 && gScreenToDisplay != DISPLAY_INVALID) {
|
||||
ProcessKeysFunctions[gScreenToDisplay](Key, bKeyPressed, bKeyHeld);
|
||||
}
|
||||
#else
|
||||
else if (Key != KEY_SIDE1 && Key != KEY_SIDE2 && gScreenToDisplay != DISPLAY_INVALID) {
|
||||
ProcessKeysFunctions[gScreenToDisplay](Key, bKeyPressed, bKeyHeld);
|
||||
}
|
||||
|| (gWasFKeyPressed && (Key == KEY_SIDE1 || Key == KEY_SIDE2))
|
||||
#endif
|
||||
)) {
|
||||
ProcessKeysFunctions[gScreenToDisplay](Key, bKeyPressed, bKeyHeld);
|
||||
}
|
||||
else if (!SCANNER_IsScanning()
|
||||
#ifdef ENABLE_AIRCOPY
|
||||
&& gScreenToDisplay != DISPLAY_AIRCOPY
|
||||
@@ -2192,7 +2170,7 @@ Skip:
|
||||
}
|
||||
|
||||
if (gRequestSaveChannel > 0) { // TODO: remove the gRequestSaveChannel, why use global variable for that??
|
||||
if ((!bKeyHeld && !bKeyPressed) || (UI_MENU_GetCurrentMenuId() != 0 && gScreenToDisplay == DISPLAY_MENU))
|
||||
if ((!bKeyHeld && !bKeyPressed) || (UI_MENU_GetCurrentMenuId() != 0 && gScreenToDisplay == DISPLAY_MENU) || gScreenToDisplay == DISPLAY_SCANNER)
|
||||
{
|
||||
SETTINGS_SaveChannel(gTxVfo->CHANNEL_SAVE, gEeprom.TX_VFO, gTxVfo, gRequestSaveChannel);
|
||||
|
||||
|
||||
+4
-8
@@ -426,15 +426,7 @@ static bool HandleUserInput()
|
||||
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev)
|
||||
{
|
||||
kbd.counter = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbd.counter = 0;
|
||||
}
|
||||
|
||||
// Process the key if counter indicates it should be handled
|
||||
if (kbd.counter == 1)
|
||||
{
|
||||
OnKeyDown(kbd.current);
|
||||
|
||||
// Special handling for MENU key
|
||||
@@ -444,6 +436,10 @@ static bool HandleUserInput()
|
||||
SYSTEM_DelayMs(250);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kbd.counter = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_directi
|
||||
{
|
||||
|
||||
if(!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) {
|
||||
RADIO_NextValidList();
|
||||
RADIO_NextValidList(1);
|
||||
}
|
||||
|
||||
// channel mode
|
||||
|
||||
+37
-53
@@ -182,65 +182,45 @@ void FM_PlayAndUpdate(void)
|
||||
|
||||
int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
const uint16_t Test2 = BK1080_ReadRegister(BK1080_REG_07);
|
||||
|
||||
// This is supposed to be a signed value, but above function is unsigned
|
||||
const uint16_t Test2 = BK1080_ReadRegister(BK1080_REG_07);
|
||||
const uint16_t Deviation = BK1080_REG_07_GET_FREQD(Test2);
|
||||
|
||||
if (BK1080_REG_07_GET_SNR(Test2) <= 2) {
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
// Helper macro to update globals and return
|
||||
#define RETURN(val) \
|
||||
do { \
|
||||
BK1080_FrequencyDeviation = Deviation; \
|
||||
BK1080_BaseFrequency = Frequency; \
|
||||
return (val); \
|
||||
} while (0)
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (BK1080_REG_07_GET_SNR(Test2) <= 2)
|
||||
RETURN(-1);
|
||||
|
||||
const uint16_t Status = BK1080_ReadRegister(BK1080_REG_10);
|
||||
if ((Status & BK1080_REG_10_MASK_AFCRL) != BK1080_REG_10_AFCRL_NOT_RAILED ||
|
||||
BK1080_REG_10_GET_RSSI(Status) < 10)
|
||||
RETURN(-1);
|
||||
|
||||
if ((Status & BK1080_REG_10_MASK_AFCRL) != BK1080_REG_10_AFCRL_NOT_RAILED || BK1080_REG_10_GET_RSSI(Status) < 10) {
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
if (Deviation >= 280 && Deviation <= 3815)
|
||||
RETURN(-1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//if (Deviation > -281 && Deviation < 280)
|
||||
if (Deviation >= 280 && Deviation <= 3815) {
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// not BLE(less than or equal)
|
||||
// Scanning upward: previous deviation was negative (bit 11 set) or near zero
|
||||
if (Frequency > LowerLimit && (Frequency - BK1080_BaseFrequency) == 1) {
|
||||
if (BK1080_FrequencyDeviation & 0x800 || (BK1080_FrequencyDeviation < 20))
|
||||
{
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (BK1080_FrequencyDeviation & 0x800 || BK1080_FrequencyDeviation < 20)
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
// not BLT(less than)
|
||||
|
||||
// Scanning downward: previous deviation was positive or saturated high
|
||||
if (Frequency >= LowerLimit && (BK1080_BaseFrequency - Frequency) == 1) {
|
||||
if ((BK1080_FrequencyDeviation & 0x800) == 0 || (BK1080_FrequencyDeviation > 4075))
|
||||
{
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
|
||||
return ret;
|
||||
}
|
||||
if ((BK1080_FrequencyDeviation & 0x800) == 0 || BK1080_FrequencyDeviation > 4075)
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
#undef RETURN
|
||||
|
||||
BK1080_FrequencyDeviation = Deviation;
|
||||
BK1080_BaseFrequency = Frequency;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
|
||||
@@ -377,6 +357,14 @@ static void Key_FUNC(KEY_Code_t Key, uint8_t state)
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
break;
|
||||
|
||||
case KEY_8:
|
||||
ACTION_BackLightOnDemand();
|
||||
break;
|
||||
|
||||
case KEY_9:
|
||||
ACTION_BackLight();
|
||||
break;
|
||||
|
||||
case KEY_STAR:
|
||||
ACTION_Scan(autoScan);
|
||||
break;
|
||||
@@ -493,6 +481,10 @@ static void Key_UP_DOWN(uint8_t state, int8_t Step)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gEeprom.SET_NAV) {
|
||||
Step = -Step;
|
||||
}
|
||||
|
||||
if (gAskToSave) {
|
||||
gRequestDisplayScreen = DISPLAY_FM;
|
||||
gFM_ChannelPosition = NUMBER_AddWithWraparound(gFM_ChannelPosition, Step, 0, FM_CHANNELS_MAX - 1);
|
||||
@@ -553,16 +545,8 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
Key_MENU(state);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
Key_UP_DOWN(state, -1);
|
||||
else
|
||||
Key_UP_DOWN(state, 1);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
Key_UP_DOWN(state, 1);
|
||||
else
|
||||
Key_UP_DOWN(state, -1);
|
||||
Key_UP_DOWN(state, Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
Key_EXIT(state);
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@
|
||||
|
||||
void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
if (gInputBoxIndex > 0) {
|
||||
if (gInputBoxIndex > 0 || gScreenToDisplay == DISPLAY_MENU) {
|
||||
if (!bKeyHeld && bKeyPressed) // short pressed
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
|
||||
+168
-129
@@ -47,6 +47,12 @@
|
||||
#include "ui/ui.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// Full VFO backup for restore on EXIT
|
||||
static VFO_Info_t gVfoBackup;
|
||||
static uint16_t gScreenChannelBackup = 0;
|
||||
static uint16_t gFreqChannelBackup = 0;
|
||||
static bool gHasVfoBackup = false;
|
||||
|
||||
static void toggle_chan_scanlist(void)
|
||||
{ // toggle the selected channels scanlist setting
|
||||
|
||||
@@ -69,19 +75,21 @@ static void toggle_chan_scanlist(void)
|
||||
if(att->exclude == true)
|
||||
{
|
||||
att->exclude = false;
|
||||
return;
|
||||
MR_SaveChannelAttributesToFlash(gTxVfo->CHANNEL_SAVE, att);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t scanlist = gTxVfo->SCANLIST_PARTICIPATION;
|
||||
|
||||
uint8_t scanlist = gTxVfo->SCANLIST_PARTICIPATION;
|
||||
scanlist++;
|
||||
|
||||
scanlist++;
|
||||
if (scanlist > MR_CHANNELS_LIST + 1)
|
||||
scanlist = 0;
|
||||
|
||||
if (scanlist > MR_CHANNELS_LIST + 1)
|
||||
scanlist = 0;
|
||||
gTxVfo->SCANLIST_PARTICIPATION = scanlist;
|
||||
|
||||
gTxVfo->SCANLIST_PARTICIPATION = scanlist;
|
||||
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true);
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true);
|
||||
}
|
||||
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gFlagResetVfos = true;
|
||||
@@ -109,8 +117,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
return;
|
||||
}
|
||||
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
switch (Key) {
|
||||
case KEY_0:
|
||||
#ifdef ENABLE_FMRADIO
|
||||
@@ -206,7 +212,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
#endif
|
||||
COMMON_SwitchVFOMode();
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
break;
|
||||
|
||||
@@ -224,7 +230,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
break;
|
||||
|
||||
case KEY_5:
|
||||
if(beep) {
|
||||
if(!beep) {
|
||||
#ifdef ENABLE_NOAA
|
||||
if (!IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
gEeprom.ScreenChannel[Vfo] = gEeprom.NoaaChannel[gEeprom.TX_VFO];
|
||||
@@ -285,41 +291,43 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN // Set Squelch F + UP or Down and Step F + SIDE1 or F + SIDE2
|
||||
case KEY_UP:
|
||||
gEeprom.SQUELCH_LEVEL = (gEeprom.SQUELCH_LEVEL < 9) ? gEeprom.SQUELCH_LEVEL + 1: 9;
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gWasFKeyPressed = false;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
gEeprom.SQUELCH_LEVEL = (gEeprom.SQUELCH_LEVEL > 0) ? gEeprom.SQUELCH_LEVEL - 1: 0;
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gWasFKeyPressed = false;
|
||||
break;
|
||||
{
|
||||
bool isKeyUp = (Key == KEY_UP);
|
||||
|
||||
case KEY_SIDE1:
|
||||
uint8_t a = FREQUENCY_GetSortedIdxFromStepIdx(gTxVfo->STEP_SETTING);
|
||||
if (a < STEP_N_ELEM - 1)
|
||||
{
|
||||
gTxVfo->STEP_SETTING = FREQUENCY_GetStepIdxFromSortedIdx(a + 1);
|
||||
if (gScanStateDir != SCAN_OFF) {
|
||||
RADIO_NextValidList(isKeyUp ? 1 : -1);
|
||||
} else {
|
||||
// Adjust squelch: UP increments, DOWN decrements
|
||||
if (isKeyUp) {
|
||||
gEeprom.SQUELCH_LEVEL = (gEeprom.SQUELCH_LEVEL < 9) ? gEeprom.SQUELCH_LEVEL + 1 : 9;
|
||||
} else {
|
||||
gEeprom.SQUELCH_LEVEL = (gEeprom.SQUELCH_LEVEL > 0) ? gEeprom.SQUELCH_LEVEL - 1 : 0;
|
||||
}
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
}
|
||||
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE))
|
||||
{
|
||||
gRequestSaveChannel = 1;
|
||||
}
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gWasFKeyPressed = false;
|
||||
break;
|
||||
case KEY_SIDE1:
|
||||
case KEY_SIDE2:
|
||||
uint8_t b = FREQUENCY_GetSortedIdxFromStepIdx(gTxVfo->STEP_SETTING);
|
||||
if (b > 0)
|
||||
{
|
||||
gTxVfo->STEP_SETTING = FREQUENCY_GetStepIdxFromSortedIdx(b - 1);
|
||||
bool isKeySide1 = (Key == KEY_SIDE1);
|
||||
uint8_t idx = FREQUENCY_GetSortedIdxFromStepIdx(gTxVfo->STEP_SETTING);
|
||||
|
||||
if ((isKeySide1 && idx < STEP_N_ELEM - 1) || (!isKeySide1 && idx > 0))
|
||||
{
|
||||
gTxVfo->STEP_SETTING = FREQUENCY_GetStepIdxFromSortedIdx(idx + (isKeySide1 ? 1 : -1));
|
||||
|
||||
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
gRequestSaveChannel = 1;
|
||||
}
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
}
|
||||
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE))
|
||||
{
|
||||
gRequestSaveChannel = 1;
|
||||
}
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gWasFKeyPressed = false;
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -363,6 +371,8 @@ void channelMove(uint16_t Channel)
|
||||
|
||||
RADIO_ConfigureChannel(gEeprom.TX_VFO, gVfoConfigureMode);
|
||||
|
||||
SETTINGS_SaveVfoIndices();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -396,11 +406,6 @@ void channelMoveSwitch(void) {
|
||||
if (gInputBoxIndex == 4) {
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 1;
|
||||
|
||||
channelMove(Channel - 1);
|
||||
SETTINGS_SaveVfoIndices();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
channelMove(Channel - 1);
|
||||
@@ -421,7 +426,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
|
||||
processFKeyFunction(Key, false);
|
||||
processFKeyFunction(Key, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -480,17 +485,14 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
/* 01 .. MR_CHANNELS_LIST */
|
||||
if (value <= MR_CHANNELS_LIST)
|
||||
{
|
||||
if (RADIO_CheckValidList(value))
|
||||
{
|
||||
/* Requested scan list is valid */
|
||||
gEeprom.SCAN_LIST_DEFAULT = value;
|
||||
}
|
||||
else
|
||||
gEeprom.SCAN_LIST_DEFAULT = value;
|
||||
|
||||
if (!RADIO_CheckValidList(value))
|
||||
{
|
||||
/* Requested scan list is empty or invalid:
|
||||
jump to the next valid scan list */
|
||||
gEeprom.SCAN_LIST_DEFAULT = value;
|
||||
RADIO_NextValidList();
|
||||
jump to the next valid scan list */
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
RADIO_NextValidList(1);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
@@ -498,13 +500,19 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
#endif
|
||||
}
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t Vfo = gEeprom.TX_VFO;
|
||||
|
||||
// Save full VFO state BEFORE first digit
|
||||
if (gInputBoxIndex == 0 && IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
memcpy(&gVfoBackup, gTxVfo, sizeof(VFO_Info_t));
|
||||
gScreenChannelBackup = gEeprom.ScreenChannel[Vfo];
|
||||
gFreqChannelBackup = gEeprom.FreqChannel[Vfo];
|
||||
gHasVfoBackup = true;
|
||||
}
|
||||
|
||||
INPUTBOX_Append(Key);
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
|
||||
@@ -658,69 +666,115 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
}
|
||||
#endif
|
||||
|
||||
processFKeyFunction(Key, true);
|
||||
processFKeyFunction(Key, false);
|
||||
}
|
||||
|
||||
static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
if (!bKeyHeld && bKeyPressed) { // exit key pressed
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; // beep when key is pressed
|
||||
return; // don't use the key till it's released
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
if (gDTMF_CallState != DTMF_CALL_STATE_NONE && gCurrentFunction != FUNCTION_TRANSMIT)
|
||||
{ // clear CALL mode being displayed
|
||||
gDTMF_CallState = DTMF_CALL_STATE_NONE;
|
||||
gUpdateDisplay = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (bKeyHeld) { // exit key held down
|
||||
if (bKeyPressed) {
|
||||
if (gInputBoxIndex > 0 || gDTMF_InputBox_Index > 0 || gDTMF_InputMode)
|
||||
{ // cancel key input mode (channel/frequency entry)
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
if (!gFmRadioMode)
|
||||
#endif
|
||||
{
|
||||
if (gScanStateDir == SCAN_OFF) {
|
||||
if (gInputBoxIndex == 0)
|
||||
return;
|
||||
gInputBox[--gInputBoxIndex] = 10;
|
||||
// Restore full VFO state on long press EXIT
|
||||
if (gHasVfoBackup) {
|
||||
const uint8_t Vfo = gEeprom.TX_VFO;
|
||||
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
// Restore indices
|
||||
gEeprom.ScreenChannel[Vfo] = gScreenChannelBackup;
|
||||
gEeprom.FreqChannel[Vfo] = gFreqChannelBackup;
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
if (gInputBoxIndex == 0)
|
||||
gAnotherVoiceID = VOICE_ID_CANCEL;
|
||||
#endif
|
||||
// Restore full VFO
|
||||
memcpy(gTxVfo, &gVfoBackup, sizeof(VFO_Info_t));
|
||||
|
||||
// Save and apply
|
||||
SETTINGS_SaveVfoIndices();
|
||||
RADIO_ConfigureSquelchAndOutputPower(gTxVfo);
|
||||
RADIO_SetupRegisters(true);
|
||||
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
|
||||
gDTMF_InputMode = false;
|
||||
gDTMF_InputBox_Index = 0;
|
||||
memset(gDTMF_String, 0, sizeof(gDTMF_String));
|
||||
gInputBoxIndex = 0;
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
else {
|
||||
gScanKeepResult = false;
|
||||
CHFRSCANNER_Stop();
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
|
||||
#endif
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
ACTION_FM();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (bKeyHeld && bKeyPressed) { // exit key held down
|
||||
if (gInputBoxIndex > 0 || gDTMF_InputBox_Index > 0 || gDTMF_InputMode)
|
||||
{ // cancel key input mode (channel/frequency entry)
|
||||
gDTMF_InputMode = false;
|
||||
gDTMF_InputBox_Index = 0;
|
||||
memset(gDTMF_String, 0, sizeof(gDTMF_String));
|
||||
gInputBoxIndex = 0;
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
if (gDTMF_CallState != DTMF_CALL_STATE_NONE && gCurrentFunction != FUNCTION_TRANSMIT)
|
||||
{ // clear CALL mode being displayed
|
||||
gDTMF_CallState = DTMF_CALL_STATE_NONE;
|
||||
gUpdateDisplay = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
if (!gFmRadioMode)
|
||||
#endif
|
||||
{
|
||||
if (gScanStateDir == SCAN_OFF) {
|
||||
if (gInputBoxIndex == 0)
|
||||
return;
|
||||
gInputBox[--gInputBoxIndex] = 10;
|
||||
|
||||
// Restore full VFO state when back to 0
|
||||
if (gInputBoxIndex == 0 && gHasVfoBackup) {
|
||||
const uint8_t Vfo = gEeprom.TX_VFO;
|
||||
|
||||
// Restore indices
|
||||
gEeprom.ScreenChannel[Vfo] = gScreenChannelBackup;
|
||||
gEeprom.FreqChannel[Vfo] = gFreqChannelBackup;
|
||||
|
||||
// Restore full VFO
|
||||
memcpy(gTxVfo, &gVfoBackup, sizeof(VFO_Info_t));
|
||||
|
||||
// Save and apply
|
||||
SETTINGS_SaveVfoIndices();
|
||||
RADIO_ConfigureSquelchAndOutputPower(gTxVfo);
|
||||
RADIO_SetupRegisters(true);
|
||||
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
channelMoveSwitch();
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
if (gInputBoxIndex == 0)
|
||||
gAnotherVoiceID = VOICE_ID_CANCEL;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
gScanKeepResult = false;
|
||||
gInputBoxIndex = 0;
|
||||
CHFRSCANNER_Stop();
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
|
||||
#endif
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
ACTION_FM();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
@@ -762,7 +816,6 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
|
||||
ACTION_Handle(KEY_MENU, bKeyPressed, bKeyHeld);
|
||||
@@ -773,6 +826,9 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
}
|
||||
|
||||
if (!bKeyPressed && !gDTMF_InputMode) { // menu key released
|
||||
gKeyInputCountdown = 1;
|
||||
channelMoveSwitch();
|
||||
|
||||
const bool bFlag = !gInputBoxIndex;
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
@@ -896,18 +952,13 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
{
|
||||
if (!gEeprom.SET_NAV) {
|
||||
Direction = -Direction;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN // Set Squelch F + UP or Down
|
||||
if(gWasFKeyPressed) {
|
||||
switch(Direction)
|
||||
{
|
||||
case 1:
|
||||
processFKeyFunction(KEY_UP, false);
|
||||
break;
|
||||
case -1:
|
||||
processFKeyFunction(KEY_DOWN, false);
|
||||
break;
|
||||
}
|
||||
processFKeyFunction(Direction == 1 ? KEY_UP : KEY_DOWN, false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -921,7 +972,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
|
||||
if (bKeyHeld || !bKeyPressed) { // key held or released
|
||||
if (gInputBoxIndex > 0)
|
||||
return; // leave if input box active
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
if (!bKeyPressed) {
|
||||
if (!bKeyHeld || IS_FREQ_CHANNEL(Channel))
|
||||
@@ -935,10 +986,6 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
}
|
||||
}
|
||||
else { // short pressed
|
||||
if (gInputBoxIndex > 0) {
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
}
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
|
||||
@@ -1039,16 +1086,8 @@ void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
MAIN_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
else
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
else
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
MAIN_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
|
||||
+11
-33
@@ -308,7 +308,7 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
|
||||
case MENU_MIC:
|
||||
//*pMin = 0;
|
||||
*pMax = 4;
|
||||
*pMax = 8;
|
||||
break;
|
||||
|
||||
case MENU_LIST_CH:
|
||||
@@ -1553,9 +1553,9 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
|
||||
{ // enter 3-digit channel number
|
||||
{ // enter 4-digit channel number
|
||||
|
||||
if (gInputBoxIndex < 3)
|
||||
if (gInputBoxIndex < 4)
|
||||
{
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
@@ -1566,7 +1566,8 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
Value = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
|
||||
//Value = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
|
||||
Value = ((gInputBox[0] * 1000) + (gInputBox[1] * 100) + (gInputBox[2] * 10) + gInputBox[3]) - 1;
|
||||
|
||||
if (IS_MR_CHANNEL(Value))
|
||||
{
|
||||
@@ -1873,6 +1874,10 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
uint16_t Channel;
|
||||
bool bCheckScanList;
|
||||
|
||||
if (!gEeprom.SET_NAV && gIsInSubMenu) {
|
||||
Direction = -Direction;
|
||||
}
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && gIsInSubMenu && edit_index >= 0)
|
||||
{ // change the character
|
||||
if (bKeyPressed && edit_index < 10 && Direction != 0)
|
||||
@@ -2013,42 +2018,15 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
switch (Key)
|
||||
{
|
||||
case KEY_0:
|
||||
case KEY_1:
|
||||
case KEY_2:
|
||||
case KEY_3:
|
||||
case KEY_4:
|
||||
case KEY_5:
|
||||
case KEY_6:
|
||||
case KEY_7:
|
||||
case KEY_8:
|
||||
case KEY_9:
|
||||
case KEY_0...KEY_9:
|
||||
MENU_Key_0_to_9(Key, bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_MENU:
|
||||
MENU_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(gEeprom.SET_NAV == 0) {
|
||||
if(gIsInSubMenu)
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
else
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
}
|
||||
else {
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(gEeprom.SET_NAV == 0) {
|
||||
if(gIsInSubMenu)
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
else
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
}
|
||||
else {
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
}
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
MENU_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
|
||||
+11
-8
@@ -32,7 +32,7 @@ DCS_CodeType_t gScanCssResultType;
|
||||
uint8_t gScanCssResultCode;
|
||||
bool gScanSingleFrequency; // scan CTCSS/DCS codes for current frequency
|
||||
SCAN_SaveState_t gScannerSaveState;
|
||||
uint8_t gScanChannel;
|
||||
uint16_t gScanChannel;
|
||||
uint32_t gScanFrequency;
|
||||
SCAN_CssState_t gScanCssState;
|
||||
uint8_t gScanProgressIndicator;
|
||||
@@ -52,7 +52,7 @@ static void SCANNER_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_SCANNER;
|
||||
|
||||
if (gInputBoxIndex < 3) {
|
||||
if (gInputBoxIndex < 4) {
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
#endif
|
||||
@@ -61,13 +61,14 @@ static void SCANNER_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
uint16_t chan = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
|
||||
// uint16_t chan = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
|
||||
uint16_t chan = ((gInputBox[0] * 1000) + (gInputBox[1] * 100) + (gInputBox[2] * 10) + gInputBox[3]) - 1;
|
||||
if (IS_MR_CHANNEL(chan)) {
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
#endif
|
||||
gShowChPrefix = RADIO_CheckValidChannel(chan, false, 0);
|
||||
gScanChannel = (uint8_t)chan;
|
||||
gScanChannel = chan;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -207,7 +208,7 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
gTxVfo->freq_config_TX.Code = gScanCssResultCode;
|
||||
}
|
||||
|
||||
uint8_t chan;
|
||||
uint16_t chan;
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
chan = gScanChannel;
|
||||
gEeprom.MrChannel[gEeprom.TX_VFO] = chan;
|
||||
@@ -256,6 +257,10 @@ static void SCANNER_Key_UP_DOWN(bool bKeyPressed, bool pKeyHeld, int8_t Directio
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
|
||||
if (!gEeprom.SET_NAV) {
|
||||
Direction = -Direction;
|
||||
}
|
||||
|
||||
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
|
||||
gScanChannel = NUMBER_AddWithWraparound(gScanChannel, Direction, 0, MR_CHANNEL_LAST);
|
||||
gShowChPrefix = RADIO_CheckValidChannel(gScanChannel, false, 0);
|
||||
@@ -275,10 +280,8 @@ void SCANNER_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
SCANNER_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
SCANNER_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
SCANNER_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
SCANNER_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
SCANNER_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ extern DCS_CodeType_t gScanCssResultType;
|
||||
extern uint8_t gScanCssResultCode;
|
||||
extern bool gScanSingleFrequency;
|
||||
extern SCAN_SaveState_t gScannerSaveState;
|
||||
extern uint8_t gScanChannel;
|
||||
extern uint16_t gScanChannel;
|
||||
extern uint32_t gScanFrequency;
|
||||
extern SCAN_CssState_t gScanCssState;
|
||||
extern uint8_t gScanProgressIndicator;
|
||||
|
||||
+29
-55
@@ -1185,37 +1185,32 @@ static void DrawArrow(uint8_t x)
|
||||
|
||||
static void OnKeyDown(uint8_t key)
|
||||
{
|
||||
bool nav = (gEeprom.SET_NAV != 0);
|
||||
bool nav = gEeprom.SET_NAV;
|
||||
bool isTrue = false;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_3:
|
||||
UpdateDBMax(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_9:
|
||||
UpdateDBMax(false);
|
||||
UpdateDBMax(isTrue);
|
||||
break;
|
||||
case KEY_1:
|
||||
UpdateScanStep(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_7:
|
||||
UpdateScanStep(false);
|
||||
UpdateScanStep(isTrue);
|
||||
break;
|
||||
case KEY_2:
|
||||
UpdateFreqChangeStep(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_8:
|
||||
UpdateFreqChangeStep(false);
|
||||
UpdateFreqChangeStep(isTrue);
|
||||
break;
|
||||
case KEY_UP:
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
if (!gScanRangeStart) {
|
||||
#endif
|
||||
UpdateCurrentFreq(nav);
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
nav = !nav;
|
||||
[[fallthrough]];
|
||||
case KEY_DOWN:
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
if (!gScanRangeStart) {
|
||||
@@ -1229,10 +1224,10 @@ static void OnKeyDown(uint8_t key)
|
||||
Blacklist();
|
||||
break;
|
||||
case KEY_STAR:
|
||||
UpdateRssiTriggerLevel(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_F:
|
||||
UpdateRssiTriggerLevel(false);
|
||||
UpdateRssiTriggerLevel(isTrue);
|
||||
break;
|
||||
case KEY_5:
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
@@ -1285,21 +1280,10 @@ static void OnKeyDownFreqInput(uint8_t key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_0:
|
||||
case KEY_1:
|
||||
case KEY_2:
|
||||
case KEY_3:
|
||||
case KEY_4:
|
||||
case KEY_5:
|
||||
case KEY_6:
|
||||
case KEY_7:
|
||||
case KEY_8:
|
||||
case KEY_9:
|
||||
case KEY_0...KEY_9:
|
||||
case KEY_STAR:
|
||||
UpdateFreqInput(key);
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
if (freqInputIndex == 0)
|
||||
if (freqInputIndex == 0 && key == KEY_EXIT)
|
||||
{
|
||||
SetState(previousState);
|
||||
break;
|
||||
@@ -1330,23 +1314,20 @@ static void OnKeyDownFreqInput(uint8_t key)
|
||||
|
||||
void OnKeyDownStill(KEY_Code_t key)
|
||||
{
|
||||
bool nav = (gEeprom.SET_NAV != 0);
|
||||
bool nav = gEeprom.SET_NAV;
|
||||
bool isTrue = false;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_3:
|
||||
UpdateDBMax(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_9:
|
||||
UpdateDBMax(false);
|
||||
UpdateDBMax(isTrue);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (menuState) {
|
||||
SetRegMenuValue(menuState, nav);
|
||||
break;
|
||||
}
|
||||
UpdateCurrentFreqStill(nav);
|
||||
break;
|
||||
nav = !nav;
|
||||
[[fallthrough]];
|
||||
case KEY_DOWN:
|
||||
if (menuState) {
|
||||
SetRegMenuValue(menuState, !nav);
|
||||
@@ -1355,10 +1336,10 @@ void OnKeyDownStill(KEY_Code_t key)
|
||||
UpdateCurrentFreqStill(!nav);
|
||||
break;
|
||||
case KEY_STAR:
|
||||
UpdateRssiTriggerLevel(true);
|
||||
break;
|
||||
isTrue = true;
|
||||
[[fallthrough]];
|
||||
case KEY_F:
|
||||
UpdateRssiTriggerLevel(false);
|
||||
UpdateRssiTriggerLevel(isTrue);
|
||||
break;
|
||||
case KEY_5:
|
||||
FreqInput();
|
||||
@@ -1381,14 +1362,7 @@ void OnKeyDownStill(KEY_Code_t key)
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true); */
|
||||
break;
|
||||
case KEY_MENU:
|
||||
if (menuState == ARRAY_SIZE(registerSpecs) - 1)
|
||||
{
|
||||
menuState = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
menuState++;
|
||||
}
|
||||
menuState = (menuState == ARRAY_SIZE(registerSpecs) - 1) ? 1 : menuState + 1;
|
||||
redrawScreen = true;
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
|
||||
+37
-9
@@ -157,15 +157,6 @@ const uint8_t BITMAP_USB_C[9] =
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint8_t BITMAP_Antenna[5] =
|
||||
{
|
||||
0b00000011,
|
||||
0b00000101,
|
||||
0b01111111,
|
||||
0b00000101,
|
||||
0b00000011
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_VFO_Lock[7] =
|
||||
{
|
||||
0b00111100,
|
||||
@@ -177,6 +168,7 @@ const uint8_t BITMAP_VFO_Lock[7] =
|
||||
0b00111100,
|
||||
};
|
||||
|
||||
/*
|
||||
const uint8_t BITMAP_VFO_Default[7] =
|
||||
{
|
||||
0b01111111,
|
||||
@@ -198,6 +190,42 @@ const uint8_t BITMAP_VFO_NotDefault[7] =
|
||||
0b00010100,
|
||||
0b00001000
|
||||
};
|
||||
*/
|
||||
|
||||
// Compact arrow
|
||||
const uint8_t BITMAP_VFO_Default[7] =
|
||||
{
|
||||
0b00111110,
|
||||
0b00111110,
|
||||
0b00011100,
|
||||
0b00011100,
|
||||
0b00001000,
|
||||
0b00001000,
|
||||
0b00000000
|
||||
};
|
||||
|
||||
// Compact empty arrow
|
||||
const uint8_t BITMAP_VFO_NotDefault[7] =
|
||||
{
|
||||
0b00100010,
|
||||
0b00100010,
|
||||
0b00010100,
|
||||
0b00010100,
|
||||
0b00001000,
|
||||
0b00001000,
|
||||
0b00000000
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_VFO_Empty[7] =
|
||||
{
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_compand[6] =
|
||||
{
|
||||
|
||||
+1
-1
@@ -35,9 +35,9 @@ extern const uint8_t BITMAP_NotReady[7];
|
||||
extern const uint8_t gFontVox[2][6];
|
||||
#endif
|
||||
|
||||
extern const uint8_t BITMAP_Antenna[5];
|
||||
extern const uint8_t BITMAP_VFO_Default[7];
|
||||
extern const uint8_t BITMAP_VFO_NotDefault[7];
|
||||
extern const uint8_t BITMAP_VFO_Empty[7];
|
||||
extern const uint8_t BITMAP_VFO_Lock[7];
|
||||
extern const uint8_t BITMAP_PowerUser[3];
|
||||
extern const uint8_t BITMAP_compand[6];
|
||||
|
||||
@@ -48,7 +48,8 @@ static const AddrMapping_t ADDR_MAPPINGS[] = {
|
||||
_MK_MAPPING(0x006000, 0x006000, 0x007000), // 256 MR Name * 16 Bytes
|
||||
_MK_MAPPING(0x007000, 0x007000, 0x008000), // 256 MR Name * 16 Bytes
|
||||
|
||||
_MK_MAPPING(0x008000, 0x008000, 0x00880E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000)
|
||||
_MK_MAPPING(0x008000, 0x008000, 0x00886E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000) 0x008000 -> 0x00880E
|
||||
// List name * 4 Bytes 0x00880E -> 0x00886E
|
||||
|
||||
_MK_MAPPING(0x009000, 0x009000, 0x0090D6), // 14 VFO * 16 Bytes (ex 0x001000)
|
||||
|
||||
|
||||
@@ -27,6 +27,42 @@ KEY_Code_t gKeyReading1 = KEY_INVALID;
|
||||
uint16_t gDebounceCounter = 0;
|
||||
bool gWasFKeyPressed = false;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Short press: hold key for SERIAL_KEY_SHORT_POLLS calls.
|
||||
// Must exceed key_debounce_10ms (2) to trigger ProcessKey(key, true, false).
|
||||
#define SERIAL_KEY_SHORT_POLLS 5
|
||||
|
||||
// Long press: hold key for SERIAL_KEY_LONG_POLLS calls.
|
||||
// Must exceed key_repeat_delay_10ms (40) to trigger ProcessKey(key, true, true).
|
||||
#define SERIAL_KEY_LONG_POLLS 45
|
||||
|
||||
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).
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
void KEYBOARD_InjectKey(uint8_t keyCode)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GPIOx GPIOB
|
||||
#define PIN_MASK_COLS (LL_GPIO_PIN_6 | LL_GPIO_PIN_5 | LL_GPIO_PIN_4 | LL_GPIO_PIN_3)
|
||||
#define PIN_COLS GPIO_MAKE_PIN(GPIOx, PIN_MASK_COLS)
|
||||
@@ -78,6 +114,25 @@ static const KEY_Code_t keyboard[5][4] = {
|
||||
|
||||
KEY_Code_t KEYBOARD_Poll(void)
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Serial-injected key: hold it for SHORT or LONG polls depending on press type,
|
||||
// so the debounce counter in app.c reaches the right threshold:
|
||||
// - Short: key_debounce_10ms (2) → ProcessKey(key, true, false)
|
||||
// - Long: key_repeat_delay_10ms (40) → ProcessKey(key, true, true)
|
||||
// Once the hold count is exhausted we clear it — next call returns KEY_INVALID,
|
||||
// which triggers the release path in app.c naturally.
|
||||
if (gKeyFromSerial != KEY_INVALID) {
|
||||
KEY_Code_t injected = gKeyFromSerial;
|
||||
uint8_t threshold = gSerialKeyLong ? SERIAL_KEY_LONG_POLLS : SERIAL_KEY_SHORT_POLLS;
|
||||
if (++gSerialKeyHoldCount >= threshold) {
|
||||
gKeyFromSerial = KEY_INVALID;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 0;
|
||||
}
|
||||
return injected;
|
||||
}
|
||||
#endif
|
||||
|
||||
KEY_Code_t Key = KEY_INVALID;
|
||||
|
||||
// Scan all 5 columns - never break early to avoid GPIO state issues
|
||||
|
||||
+11
-1
@@ -50,7 +50,17 @@ extern KEY_Code_t gKeyReading1;
|
||||
extern uint16_t gDebounceCounter;
|
||||
extern bool gWasFKeyPressed;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
KEY_Code_t KEYBOARD_Poll(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -256,9 +256,9 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
|
||||
printf("spi flash write: %06x %ld %d\n", Address, Size, Append);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
gDebug++;
|
||||
#endif
|
||||
//#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
// gDebug++;
|
||||
//#endif
|
||||
|
||||
uint32_t SecIndex = Address / SECTOR_SIZE;
|
||||
uint32_t SecAddr = SecIndex * SECTOR_SIZE;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "driver/st7565.h"
|
||||
#include "driver/system.h"
|
||||
#include "misc.h"
|
||||
#include "screenshot.h"
|
||||
|
||||
#define SPIx SPI1
|
||||
|
||||
@@ -163,6 +164,9 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
||||
void ST7565_BlitLine(unsigned line)
|
||||
{
|
||||
ST7565_BlitScreen(line + 1);
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(true); // Force immediate capture
|
||||
#endif
|
||||
}
|
||||
|
||||
void ST7565_BlitStatusLine(void)
|
||||
|
||||
+45
-5
@@ -22,7 +22,13 @@
|
||||
#include "py32f071_ll_dma.h"
|
||||
#include "py32f071_ll_gpio.h"
|
||||
#include "py32f071_ll_usart.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
#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
|
||||
#define DMA_CHANNEL LL_DMA_CHANNEL_2
|
||||
@@ -149,12 +155,46 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
bool UART_IsCableConnected(void) {
|
||||
bool connected = false;
|
||||
|
||||
for (size_t i = 0; i < sizeof(UART_DMA_Buffer); i++) {
|
||||
if (UART_DMA_Buffer[i] == 0x55) {
|
||||
UART_DMA_Buffer[i] = 0x00; // Clear only the matched byte
|
||||
return true;
|
||||
uint8_t b = UART_DMA_Buffer[i];
|
||||
|
||||
if (b == 0x55) {
|
||||
// Keepalive byte — viewer is alive
|
||||
UART_DMA_Buffer[i] = 0x00;
|
||||
connected = true;
|
||||
}
|
||||
else if (b == 0xAA) {
|
||||
// Possible start of a key packet: 0xAA 0x55 <type> <keycode>
|
||||
// type 0x03 = short press, 0x04 = long press
|
||||
size_t i1 = (i + 1) % sizeof(UART_DMA_Buffer);
|
||||
size_t i2 = (i + 2) % sizeof(UART_DMA_Buffer);
|
||||
size_t i3 = (i + 3) % sizeof(UART_DMA_Buffer);
|
||||
|
||||
if (UART_DMA_Buffer[i1] == 0x55 &&
|
||||
(UART_DMA_Buffer[i2] == UART_TYPE_KEY ||
|
||||
UART_DMA_Buffer[i2] == UART_TYPE_KEY_LONG))
|
||||
{
|
||||
uint8_t type = UART_DMA_Buffer[i2];
|
||||
uint8_t keyCode = UART_DMA_Buffer[i3];
|
||||
|
||||
// Consume all 4 bytes
|
||||
UART_DMA_Buffer[i] = 0x00;
|
||||
UART_DMA_Buffer[i1] = 0x00;
|
||||
UART_DMA_Buffer[i2] = 0x00;
|
||||
UART_DMA_Buffer[i3] = 0x00;
|
||||
|
||||
if (type == UART_TYPE_KEY_LONG)
|
||||
KEYBOARD_InjectKeyLong(keyCode);
|
||||
else
|
||||
KEYBOARD_InjectKey(keyCode);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return connected;
|
||||
}
|
||||
#endif
|
||||
+95
-7
@@ -18,6 +18,13 @@
|
||||
#include "usb_config.h"
|
||||
#include "py32f071_ll_bus.h"
|
||||
|
||||
#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];
|
||||
volatile uint32_t VCP_RxBufPointer = 0;
|
||||
|
||||
@@ -38,24 +45,105 @@ void VCP_Init()
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
bool VCP_ScreenshotPing(void)
|
||||
{
|
||||
static uint32_t read_ptr = 0;
|
||||
// State machine for parsing incoming packets:
|
||||
// Keepalive: 0x55 0xAA 0x00 0x00 → viewer alive
|
||||
// Short key press: 0xAA 0x55 0x03 <key> → inject short press
|
||||
// Long key press: 0xAA 0x55 0x04 <key> → inject long press
|
||||
//
|
||||
// State transitions:
|
||||
// IDLE → 0x55 → KA_1
|
||||
// KA_1 → 0xAA → KA_2 (else IDLE)
|
||||
// KA_2 → 0x00 → KA_3 (else IDLE)
|
||||
// KA_3 → 0x00 → keepalive OK, IDLE
|
||||
//
|
||||
// IDLE → 0xAA → KEY_1
|
||||
// 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
|
||||
|
||||
uint32_t write_ptr = VCP_RxBufPointer;
|
||||
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;
|
||||
|
||||
while (read_ptr != write_ptr)
|
||||
static uint32_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
|
||||
|
||||
// Cap bytes processed per call to VCP_RX_BUF_SIZE.
|
||||
// Prevents unbounded loop if the ISR write pointer laps read_ptr
|
||||
// (buffer overflow / corrupted state), which would freeze the firmware.
|
||||
uint32_t processed = 0;
|
||||
|
||||
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++;
|
||||
|
||||
if (b == 0x55)
|
||||
switch (state)
|
||||
{
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return connected;
|
||||
}
|
||||
#endif // ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
@@ -28,7 +28,10 @@ extern uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE];
|
||||
extern volatile uint32_t VCP_RxBufPointer;
|
||||
|
||||
void VCP_Init();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
bool VCP_ScreenshotPing(void);
|
||||
#endif
|
||||
|
||||
static inline void VCP_Send(const uint8_t *Buf, uint32_t Size)
|
||||
{
|
||||
|
||||
+1
-1
@@ -491,7 +491,7 @@ const uint8_t gFontSmall[95-1][6] =
|
||||
{0x03, 0x00, 0x03}, // 34 - quotedbl
|
||||
{0x1f, 0x0a, 0x1f}, // 35 - numbersign
|
||||
{0x0a, 0x1f, 0x05}, // 36 - dollar
|
||||
{0x09, 0x04, 0x12}, // 37 - percent
|
||||
{0x19, 0x04, 0x13}, // 37 - percent
|
||||
{0x0f, 0x17, 0x1c}, // 38 - ampersand
|
||||
{0x00, 0x03, 0x00}, // 39 - quotesingle
|
||||
{0x00, 0x0e, 0x11}, // 40 - parenleft
|
||||
|
||||
+1
-8
@@ -118,14 +118,7 @@ void FUNCTION_Foreground(const FUNCTION_Type_t PreviousFunction)
|
||||
|
||||
void FUNCTION_PowerSave() {
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
if(gWakeUp)
|
||||
{
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 200; // deep sleep now indexed on BatSav
|
||||
}
|
||||
else
|
||||
{
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
|
||||
}
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * (gWakeUp ? 200 : 10); // deep sleep now indexed on BatSav
|
||||
#else
|
||||
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
|
||||
#endif
|
||||
|
||||
+5
-3
@@ -87,7 +87,7 @@ const uint16_t NOAA_countdown_3_10ms = 200 / 10; // 200ms
|
||||
|
||||
const uint32_t gDefaultAesKey[4] = {0x4AA5CC60, 0x0312CC5F, 0xFFD2DABB, 0x6BBA7F92};
|
||||
|
||||
const uint8_t gMicGain_dB2[5] = {3, 8, 16, 24, 31};
|
||||
const uint8_t gMicGain_dB2[9] = {3, 8, 16, 24, 32, 40, 48, 56, 63}; // BK4819 {3, 8, 16, 24, 31};
|
||||
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
bool gSetting_350TX;
|
||||
@@ -135,7 +135,7 @@ enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
bool gSetting_set_tmr = 0;
|
||||
bool gSetting_set_ptt_session;
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
uint16_t gDebug;
|
||||
int16_t gDebug;
|
||||
#endif
|
||||
uint8_t gDW = 0;
|
||||
uint8_t gCB = 0;
|
||||
@@ -149,6 +149,7 @@ enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
bool gPowerHigh = false;
|
||||
bool gRemoveOffset = false;
|
||||
#endif
|
||||
int8_t dBmCorrTable[7] = {-15, -16, -10, -4, -7, -6, -1};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
@@ -292,7 +293,7 @@ uint8_t gFSKWriteIndex;
|
||||
|
||||
#ifdef ENABLE_NOAA
|
||||
bool gIsNoaaMode;
|
||||
uint16_t gNoaaChannel;
|
||||
uint8_t gNoaaChannel;
|
||||
#endif
|
||||
|
||||
bool gUpdateDisplay;
|
||||
@@ -334,6 +335,7 @@ uint8_t gIsLocked = 0xFF;
|
||||
uint16_t gVfoSaveCountdown_10ms = 0;
|
||||
bool gScheduleVfoSave = false;
|
||||
bool gVfoStateChanged = false;
|
||||
char gListName[MR_CHANNELS_LIST][4];
|
||||
#endif
|
||||
|
||||
inline void FUNCTION_NOP() { ; }
|
||||
|
||||
+5
-2
@@ -148,7 +148,7 @@ extern const uint16_t scan_pause_delay_in_7_10ms;
|
||||
//extern const uint16_t gMax_bat_v;
|
||||
//extern const uint16_t gMin_bat_v;
|
||||
|
||||
extern const uint8_t gMicGain_dB2[5];
|
||||
extern const uint8_t gMicGain_dB2[9];
|
||||
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
extern bool gSetting_350TX;
|
||||
@@ -197,7 +197,7 @@ extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
extern bool gSetting_set_tmr;
|
||||
extern bool gSetting_set_ptt_session;
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
extern uint16_t gDebug;
|
||||
extern int16_t gDebug;
|
||||
#endif
|
||||
extern uint8_t gDW;
|
||||
extern uint8_t gCB;
|
||||
@@ -211,6 +211,7 @@ extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
extern bool gPowerHigh;
|
||||
extern bool gRemoveOffset;
|
||||
#endif
|
||||
extern int8_t dBmCorrTable[7];
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
@@ -455,6 +456,8 @@ extern volatile uint8_t boot_counter_10ms;
|
||||
extern uint16_t gVfoSaveCountdown_10ms;
|
||||
extern bool gScheduleVfoSave;
|
||||
extern bool gVfoStateChanged;
|
||||
|
||||
extern char gListName[MR_CHANNELS_LIST][4];
|
||||
#endif
|
||||
|
||||
int32_t NUMBER_AddWithWraparound(int32_t Base, int32_t Add, int32_t LowerLimit, int32_t UpperLimit);
|
||||
|
||||
+14
-12
@@ -102,28 +102,30 @@ bool RADIO_CheckValidList(uint8_t scanList)
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIO_NextValidList(void)
|
||||
void RADIO_NextValidList(int8_t direction)
|
||||
{
|
||||
uint8_t startList = gEeprom.SCAN_LIST_DEFAULT;
|
||||
uint8_t attempts = 0;
|
||||
const uint8_t MAX_LISTS = MR_CHANNELS_LIST + 2; // 1-25, includes ALL
|
||||
const uint8_t MAX_VALUE = MR_CHANNELS_LIST + 1; // 25 (1-24 lists + ALL)
|
||||
|
||||
do {
|
||||
// Move to next scan list, wrapping around from 25 to 1
|
||||
gEeprom.SCAN_LIST_DEFAULT = ((gEeprom.SCAN_LIST_DEFAULT + 1) % MAX_LISTS) ?: 1;
|
||||
if (direction > 0) {
|
||||
// Forward: 1 → 2 → ... → 25 → 1
|
||||
gEeprom.SCAN_LIST_DEFAULT = (gEeprom.SCAN_LIST_DEFAULT % MAX_VALUE) + 1;
|
||||
} else {
|
||||
// Backward: 25 → 24 → ... → 1 → 25
|
||||
gEeprom.SCAN_LIST_DEFAULT = ((gEeprom.SCAN_LIST_DEFAULT - 2 + MAX_VALUE) % MAX_VALUE) + 1;
|
||||
}
|
||||
attempts++;
|
||||
|
||||
// Check if current list has valid channels
|
||||
if (RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT))
|
||||
return;
|
||||
|
||||
// Stop if we've cycled through all lists or made too many attempts
|
||||
} while (gEeprom.SCAN_LIST_DEFAULT != startList && attempts < MAX_LISTS);
|
||||
} while (gEeprom.SCAN_LIST_DEFAULT != startList && attempts < MAX_VALUE);
|
||||
|
||||
// Safety fallback: if no valid list found, switch to ALL mode
|
||||
// This prevents infinite loops and ensures scanning can continue
|
||||
// Safety fallback: switch to ALL mode
|
||||
if (!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) {
|
||||
gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1; // ALL
|
||||
gEeprom.SCAN_LIST_DEFAULT = MAX_VALUE; // ALL (25)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,8 +796,8 @@ void RADIO_SetupRegisters(bool switchToForeground)
|
||||
}
|
||||
BK4819_WriteRegister(BK4819_REG_3F, 0);
|
||||
|
||||
// mic gain 0.5dB/step 0 to 31
|
||||
BK4819_WriteRegister(BK4819_REG_7D, 0xE940 | (gEeprom.MIC_SENSITIVITY_TUNING & 0x1f));
|
||||
// mic gain 0.5dB/step 0 to 63
|
||||
BK4819_WriteRegister(BK4819_REG_7D, 0xE940 | (gEeprom.MIC_SENSITIVITY_TUNING & 0x3f));
|
||||
|
||||
uint32_t Frequency;
|
||||
#ifdef ENABLE_NOAA
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ extern DCS_CodeType_t gCurrentCodeType;
|
||||
extern VfoState_t VfoState[2];
|
||||
|
||||
bool RADIO_CheckValidList(uint8_t scanList);
|
||||
void RADIO_NextValidList(void);
|
||||
void RADIO_NextValidList(int8_t direction);
|
||||
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList);
|
||||
uint16_t RADIO_FindNextChannel(uint16_t ChNum, int8_t Direction, bool bCheckScanList, uint8_t RadioNum);
|
||||
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint16_t ChannelSave, const uint32_t Frequency);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "screenshot.h"
|
||||
#include "misc.h"
|
||||
#include "driver/vcp.h"
|
||||
#include "driver/keyboard.h"
|
||||
|
||||
static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
@@ -125,6 +126,11 @@ void getScreenShot(bool force)
|
||||
if (deltaLen == 0)
|
||||
return;
|
||||
|
||||
// Skip transmission if a key is currently pressed
|
||||
// UART_Send is blocking - would freeze the main loop and lose keypresses
|
||||
if (gKeyReading0 != KEY_INVALID)
|
||||
return;
|
||||
|
||||
// ==== Send version marker (for backward compatibility detection) ====
|
||||
// New format: sends 0xFF before header
|
||||
// Old format: doesn't exist, so viewers can differentiate
|
||||
|
||||
+17
-10
@@ -59,7 +59,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
configByte[4] &= (uint8_t)~0x01; // KEY_LOCK = 0
|
||||
configByte[4] &= (uint8_t)~0x02; // MENU_LOCK = 0
|
||||
configByte[4] &= (uint8_t)~0x3C; // SET_KEY = 0
|
||||
configByte[4] &= (uint8_t)~0x40; // SET_NAV = 0
|
||||
//configByte[4] &= (uint8_t)~0x40; // SET_NAV = 0
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A000, configByte, sizeof(configByte), false);
|
||||
|
||||
@@ -97,6 +97,12 @@ void SETTINGS_InitEEPROM(void)
|
||||
if (needsWrite) {
|
||||
PY25Q16_WriteBuffer(0x00A0C8, logoLines, sizeof(logoLines), false);
|
||||
}
|
||||
|
||||
// 5. Reset dBmCorrTable
|
||||
int8_t buf[7];
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
buf[i] = dBmCorrTable[i]; // values from misc.c
|
||||
PY25Q16_WriteBuffer(0x00A0B9, buf, 7, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +128,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.VOX_SWITCH = (Data[5] < 2) ? Data[5] : false;
|
||||
gEeprom.VOX_LEVEL = (Data[6] < 10) ? Data[6] : 1;
|
||||
#endif
|
||||
gEeprom.MIC_SENSITIVITY = (Data[7] < 5) ? Data[7] : 4;
|
||||
gEeprom.MIC_SENSITIVITY = (Data[7] < 9) ? Data[7] : 4;
|
||||
|
||||
// 0E78..0E7F
|
||||
PY25Q16_ReadBuffer(0x00A008, Data, 8);
|
||||
@@ -240,13 +246,10 @@ gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data16[5]) ? Data16[5] : (FREQ_CHANNE
|
||||
gEeprom.VOICE_PROMPT = (Data[0] < 3) ? Data[0] : VOICE_PROMPT_ENGLISH;
|
||||
#endif
|
||||
#ifdef ENABLE_RSSI_BAR
|
||||
if((Data[1] < 200 && Data[1] > 90) && (Data[2] < Data[1]-9 && Data[1] < 160 && Data[2] > 50)) {
|
||||
gEeprom.S0_LEVEL = Data[1];
|
||||
gEeprom.S9_LEVEL = Data[2];
|
||||
}
|
||||
else {
|
||||
gEeprom.S0_LEVEL = 130;
|
||||
gEeprom.S9_LEVEL = 76;
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
int8_t val = (int8_t)Data[i + 1];
|
||||
if (val >= -64 && val <= 64)
|
||||
dBmCorrTable[i] = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -403,6 +406,9 @@ gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data16[5]) ? Data16[5] : (FREQ_CHANNE
|
||||
}
|
||||
*/
|
||||
|
||||
// Init list name
|
||||
PY25Q16_ReadBuffer(0x00880E, gListName, sizeof(gListName));
|
||||
|
||||
// Init attr cache
|
||||
MR_InitChannelAttributesCache();
|
||||
|
||||
@@ -601,6 +607,7 @@ void SETTINGS_FactoryReset(bool bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x000000);
|
||||
PY25Q16_SectorErase(0x001000);
|
||||
PY25Q16_SectorErase(0x002000);
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
PY25Q16_SectorErase(0x004000);
|
||||
PY25Q16_SectorErase(0x005000);
|
||||
@@ -1105,7 +1112,7 @@ void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
}; // default attributes
|
||||
|
||||
// 0x0D60
|
||||
PY25Q16_ReadBuffer(0x008000 + channel, &state, 1);
|
||||
PY25Q16_ReadBuffer(0x008000 + (channel * 2), &state, 2);
|
||||
|
||||
if (keep) {
|
||||
att.band = pVFO->Band;
|
||||
|
||||
+10
-34
@@ -44,23 +44,23 @@ void UI_GenerateChannelString(char *pString, const uint16_t Channel)
|
||||
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint16_t ChannelNumber)
|
||||
{
|
||||
if (gInputBoxIndex > 0) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
pString[i] = (gInputBox[i] == 10) ? '-' : gInputBox[i] + '0';
|
||||
}
|
||||
|
||||
pString[3] = 0;
|
||||
pString[4] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bShowPrefix) {
|
||||
// BUG here? Prefixed NULLs are allowed
|
||||
sprintf(pString, "CH-%03u", ChannelNumber + 1);
|
||||
sprintf(pString, "CH-%04u", ChannelNumber + 1);
|
||||
} else if (ChannelNumber == MR_CHANNEL_LAST + 1) {
|
||||
strcpy(pString, "None");
|
||||
} else if (ChannelNumber == 0xFFFF) {
|
||||
strcpy(pString, "NULL");
|
||||
} else {
|
||||
sprintf(pString, "%03u", ChannelNumber + 1);
|
||||
sprintf(pString, "%04u", ChannelNumber + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,17 +130,17 @@ void UI_PrintStringSmallNormalInverse(const char *pString, uint8_t Start, uint8_
|
||||
if (End != 0 && x_end > End)
|
||||
x_end = End;
|
||||
|
||||
gFrameBuffer[Line][x_start - 3] ^= 0x3E;
|
||||
gFrameBuffer[Line][x_start - 2] ^= 0x7F;
|
||||
gFrameBuffer[Line][x_start - 1] ^= 0xFF;
|
||||
//gFrameBuffer[Line][x_start - 2] ^= 0x3E;
|
||||
gFrameBuffer[Line][x_start - 1] ^= 0x7F;
|
||||
//gFrameBuffer[Line][x_start - 1] ^= 0xFF;
|
||||
for (uint8_t x = x_start; x < x_end; x++)
|
||||
{
|
||||
gFrameBuffer[Line][x] ^= 0xFF;
|
||||
gFrameBuffer[Line - 1][x] ^= 0x80;
|
||||
}
|
||||
gFrameBuffer[Line][x_end + 0] ^= 0xFF;
|
||||
gFrameBuffer[Line][x_end + 1] ^= 0x7F;
|
||||
gFrameBuffer[Line][x_end + 2] ^= 0x3E;
|
||||
//gFrameBuffer[Line][x_end + 0] ^= 0xFF;
|
||||
gFrameBuffer[Line][x_end + 0] ^= 0x7F;
|
||||
//gFrameBuffer[Line][x_end + 1] ^= 0x3E;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,30 +157,6 @@ void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, ui
|
||||
UI_PrintStringSmall(pString, Start, End, Line, char_width, font);
|
||||
}
|
||||
|
||||
void UI_PrintStringSmallBoldInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
|
||||
{
|
||||
// First draw the string normally
|
||||
UI_PrintStringSmallBold(pString, Start, End, Line);
|
||||
|
||||
// Now invert the framebuffer bits for the rendered area
|
||||
uint8_t len = strlen(pString);
|
||||
uint8_t char_width = 7; // small font is typically 6px wide
|
||||
|
||||
uint8_t x_start = Start;
|
||||
uint8_t x_end = Start + (len * char_width);
|
||||
|
||||
if (End != 0 && x_end > End)
|
||||
x_end = End;
|
||||
|
||||
gFrameBuffer[Line][x_start] ^= 0x7F;
|
||||
for (uint8_t x = x_start + 1; x < x_end; x++)
|
||||
{
|
||||
gFrameBuffer[Line][x] ^= 0x41;
|
||||
}
|
||||
gFrameBuffer[Line][x_end + 1] ^= 0x7F;
|
||||
}
|
||||
|
||||
|
||||
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t * buffer)
|
||||
{
|
||||
UI_PrintStringBuffer(pString, buffer, ARRAY_SIZE(gFontSmall[0]), (uint8_t *)gFontSmall);
|
||||
|
||||
@@ -26,7 +26,6 @@ void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Lin
|
||||
void UI_PrintStringSmallNormal(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallNormalInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBoldInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t *buffer);
|
||||
void UI_PrintStringSmallBufferBold(const char *pString, uint8_t * buffer);
|
||||
void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center);
|
||||
|
||||
+179
-106
@@ -46,7 +46,7 @@
|
||||
center_line_t center_line = CENTER_LINE_NONE;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
static int8_t RxBlink;
|
||||
// static int8_t RxBlink;
|
||||
static int8_t RxBlinkLed = 0;
|
||||
static int8_t RxBlinkLedCounter;
|
||||
static int8_t RxLine;
|
||||
@@ -60,16 +60,6 @@ center_line_t center_line = CENTER_LINE_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
const int8_t dBmCorrTable[7] = {
|
||||
-15, // band 1
|
||||
-25, // band 2
|
||||
-20, // band 3
|
||||
-4, // band 4
|
||||
-7, // band 5
|
||||
-6, // band 6
|
||||
-1 // band 7
|
||||
};
|
||||
|
||||
const char *VfoStateStr[] = {
|
||||
[VFO_STATE_NORMAL]="",
|
||||
[VFO_STATE_BUSY]="BUSY",
|
||||
@@ -80,18 +70,26 @@ const char *VfoStateStr[] = {
|
||||
[VFO_STATE_VOLTAGE_HIGH]="VOLT HIGH"
|
||||
};
|
||||
|
||||
// ***************************************************************************
|
||||
// ----------------------------------------
|
||||
|
||||
static void DrawSmallAntennaAndBars(uint8_t *p, unsigned int level)
|
||||
static void DrawSmallPowerBars(uint8_t *p, unsigned int level)
|
||||
{
|
||||
if(level>6)
|
||||
level = 6;
|
||||
|
||||
memcpy(p, BITMAP_Antenna, ARRAY_SIZE(BITMAP_Antenna));
|
||||
|
||||
for(uint8_t i = 1; i <= level; i++) {
|
||||
char bar = (0xff << (6-i)) & 0x7F;
|
||||
memset(p + 2 + i*3, bar, 2);
|
||||
if(gSetting_set_gui)
|
||||
{
|
||||
for(uint8_t i = 0; i <= level; i++) {
|
||||
char bar = (0xff << (6-i)) & 0x7F;
|
||||
memset(p + 2 + i*3, bar, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint8_t i = 0; i <= level; i++) {
|
||||
char bar = 0b00111110;
|
||||
memset(p + 2 + i*3, bar, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined ENABLE_AUDIO_BAR || defined ENABLE_RSSI_BAR
|
||||
@@ -273,24 +271,23 @@ void DisplayRSSIBar(const bool now)
|
||||
//sprintf(String, "%d", RxBlink);
|
||||
//UI_PrintStringSmallBold(String, 80, 0, RxLine);
|
||||
|
||||
/*
|
||||
if(RxLine >= 0 && center_line != CENTER_LINE_IN_USE)
|
||||
{
|
||||
if (RxBlink == 0 || RxBlink == 1) {
|
||||
UI_PrintStringSmallBold("RX", 8, 0, RxLine);
|
||||
//GUI_DisplaySmallest("RX", 10, (RxLine * 8) + 1, false, true);
|
||||
static bool clean = false;
|
||||
uint8_t *p_line0 = gFrameBuffer[RxLine + 0];
|
||||
|
||||
if (RxBlink == 1) RxBlink = 2;
|
||||
clean = !clean;
|
||||
|
||||
if(clean) {
|
||||
for(uint8_t i = 0; i < sizeof(BITMAP_VFO_Default); i++)
|
||||
p_line0[i] = (p_line0[i] & 0x80) | BITMAP_VFO_Default[i];
|
||||
} else {
|
||||
for (uint8_t i = 8; i < 24; i++)
|
||||
{
|
||||
gFrameBuffer[RxLine][i] = 0x00;
|
||||
}
|
||||
RxBlink = 1;
|
||||
for(uint8_t i = 0; i < sizeof(BITMAP_VFO_Empty); i++)
|
||||
p_line0[i] = (p_line0[i] & 0x80) | BITMAP_VFO_Empty[i];
|
||||
}
|
||||
|
||||
ST7565_BlitLine(RxLine);
|
||||
}
|
||||
*/
|
||||
#else
|
||||
const unsigned int line = 3;
|
||||
#endif
|
||||
@@ -331,21 +328,21 @@ void DisplayRSSIBar(const bool now)
|
||||
#endif
|
||||
+ dBmCorrTable[gRxVfo->Band];
|
||||
|
||||
rssi_dBm = -rssi_dBm;
|
||||
// S9 = -93 dBm, S0 = -141 dBm (IARU standard)
|
||||
const int16_t s9_dBm = -93;
|
||||
const int16_t s0_dBm = -141;
|
||||
|
||||
if(rssi_dBm > 141) rssi_dBm = 141;
|
||||
if(rssi_dBm < 53) rssi_dBm = 53;
|
||||
|
||||
uint8_t s_level = 0;
|
||||
uint8_t overS9dBm = 0;
|
||||
uint8_t s_level = 0;
|
||||
uint8_t overS9dBm = 0;
|
||||
uint8_t overS9Bars = 0;
|
||||
|
||||
if(rssi_dBm >= 93) {
|
||||
s_level = map(rssi_dBm, 141, 93, 1, 9);
|
||||
}
|
||||
else {
|
||||
s_level = 9;
|
||||
overS9dBm = map(rssi_dBm, 93, 53, 0, 40);
|
||||
if (rssi_dBm <= s9_dBm) {
|
||||
// Signal <= S9 : map between S0 and S9
|
||||
s_level = map(rssi_dBm, s0_dBm, s9_dBm, 0, 9);
|
||||
} else {
|
||||
// Signal > S9 : compute over-S9
|
||||
s_level = 9;
|
||||
overS9dBm = map(rssi_dBm, s9_dBm, s9_dBm + 40, 0, 40);
|
||||
overS9Bars = map(overS9dBm, 0, 40, 0, 4);
|
||||
}
|
||||
#else
|
||||
@@ -366,12 +363,12 @@ void DisplayRSSIBar(const bool now)
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if (gSetting_set_gui)
|
||||
{
|
||||
sprintf(str, "%3d", -rssi_dBm);
|
||||
sprintf(str, "%3d", rssi_dBm);
|
||||
UI_PrintStringSmallNormal(str, LCD_WIDTH + 8, 0, line - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(str, "% 4d %s", -rssi_dBm, "dBm");
|
||||
sprintf(str, "% 4d %s", rssi_dBm, "dBm");
|
||||
if(isMainOnly())
|
||||
GUI_DisplaySmallest(str, 2, 41, false, true);
|
||||
else
|
||||
@@ -419,7 +416,7 @@ void DisplayRSSIBar(const bool now)
|
||||
uint8_t *pLine = (gEeprom.RX_VFO == 0)? gFrameBuffer[2] : gFrameBuffer[6];
|
||||
if (now)
|
||||
memset(pLine, 0, 23);
|
||||
DrawSmallAntennaAndBars(pLine, Level);
|
||||
DrawSmallPowerBars(pLine, Level);
|
||||
if (now)
|
||||
ST7565_BlitFullScreen();
|
||||
#endif
|
||||
@@ -528,7 +525,7 @@ void UI_MAIN_TimeSlice500ms(void)
|
||||
}
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
// ----------------------------------------
|
||||
|
||||
void UI_DisplayMain(void)
|
||||
{
|
||||
@@ -771,46 +768,51 @@ void UI_DisplayMain(void)
|
||||
{ // receiving .. show the RX symbol
|
||||
mode = VFO_MODE_RX;
|
||||
//if (FUNCTION_IsRx() && gEeprom.RX_VFO == vfo_num) {
|
||||
if (FUNCTION_IsRx() && gEeprom.RX_VFO == vfo_num && VfoState[vfo_num] == VFO_STATE_NORMAL) {
|
||||
if (FUNCTION_IsRx()) {
|
||||
if (gEeprom.RX_VFO == vfo_num && VfoState[vfo_num] == VFO_STATE_NORMAL) {
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
RxBlinkLed = 1;
|
||||
RxBlinkLedCounter = 0;
|
||||
RxLine = line;
|
||||
RxOnVfofrequency = frequency;
|
||||
if(!isMainVFO)
|
||||
{
|
||||
RxBlink = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RxBlink = 0;
|
||||
}
|
||||
RxBlinkLed = 1;
|
||||
RxBlinkLedCounter = 0;
|
||||
RxLine = line;
|
||||
RxOnVfofrequency = frequency;
|
||||
// if(!isMainVFO)
|
||||
// {
|
||||
// RxBlink = 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// RxBlink = 0;
|
||||
// }
|
||||
|
||||
if (RxBlink == 0 || RxBlink == 1) {
|
||||
if(gRxVfo->Modulation == MODULATION_AM)
|
||||
GUI_DisplaySmallest("AIR", 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
else {
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
strcpy(String, gSubMenu_SET_AUD[gSetting_set_audio]);
|
||||
#else
|
||||
strcpy(String, "RX");
|
||||
#endif
|
||||
GUI_DisplaySmallest(String, 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
}
|
||||
// if (RxBlink == 0 || RxBlink == 1) {
|
||||
if(gRxVfo->Modulation == MODULATION_AM)
|
||||
GUI_DisplaySmallest("AIR", 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
else {
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
strcpy(String, gSubMenu_SET_AUD[gSetting_set_audio]);
|
||||
#else
|
||||
strcpy(String, "RX");
|
||||
#endif
|
||||
GUI_DisplaySmallest(String, 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
}
|
||||
|
||||
//UI_PrintStringSmallBold("RX", 8, 0, RxLine);
|
||||
}
|
||||
//UI_PrintStringSmallBold("RX", 8, 0, RxLine);
|
||||
// }
|
||||
#else
|
||||
UI_PrintStringSmallBold("RX", 8, 0, line);
|
||||
UI_PrintStringSmallBold("RX", 8, 0, line);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
else
|
||||
{
|
||||
if(RxOnVfofrequency == frequency && !isMainOnly())
|
||||
{
|
||||
UI_PrintStringSmallNormal(">>", 8, 0, line);
|
||||
else {
|
||||
if(RxBlinkLed == 1)
|
||||
RxBlinkLed = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(RxOnVfofrequency == frequency && !isMainOnly()) {
|
||||
//UI_PrintStringSmallNormal(">>", 8, 0, line);
|
||||
//memcpy(p_line0 + 14, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
|
||||
GUI_DisplaySmallest(">>", 8, RxLine == 0 ? 1 : 33, false, true);
|
||||
}
|
||||
|
||||
if(RxBlinkLed == 1)
|
||||
@@ -821,21 +823,60 @@ void UI_DisplayMain(void)
|
||||
|
||||
if (IS_MR_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
|
||||
{ // channel mode
|
||||
const unsigned int x = 3;
|
||||
const unsigned int x = 1;
|
||||
const bool inputting = gInputBoxIndex != 0 && gEeprom.TX_VFO == vfo_num;
|
||||
if (!inputting || gScanStateDir != SCAN_OFF)
|
||||
sprintf(String, "%04u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
else
|
||||
sprintf(String, "%.4s", INPUTBOX_GetAscii()); // show the input text
|
||||
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
|
||||
|
||||
//if (gSetting_set_gui) {
|
||||
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
|
||||
/*
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI_DisplaySmallest(String, x + 1, line == 0 ? 9 : 41, false, true);
|
||||
gFrameBuffer[line + 1][0] ^= 0x1C;
|
||||
gFrameBuffer[line + 1][1] ^= 0x3E;
|
||||
for (uint8_t i = 2; i < 21; i++) {
|
||||
gFrameBuffer[line + 1][i] ^= 0x7F;
|
||||
}
|
||||
gFrameBuffer[line + 1][21] ^= 0x3E;
|
||||
gFrameBuffer[line + 1][22] ^= 0x1C;
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
|
||||
{ // frequency mode
|
||||
// show the frequency band number
|
||||
const unsigned int x = 2;
|
||||
char * buf = gEeprom.VfoInfo[vfo_num].pRX->Frequency < _1GHz_in_KHz ? "" : "+";
|
||||
sprintf(String, "F%u%s", 1 + gEeprom.ScreenChannel[vfo_num] - FREQ_CHANNEL_FIRST, buf);
|
||||
UI_PrintStringSmallNormal(String, x, 0, line + 1);
|
||||
const uint8_t f = 1 + gEeprom.ScreenChannel[vfo_num] - FREQ_CHANNEL_FIRST;
|
||||
const bool over1GHz = gEeprom.VfoInfo[vfo_num].pRX->Frequency >= _1GHz_in_KHz;
|
||||
|
||||
sprintf(String, over1GHz ? "F%u+" : "F%u", f);
|
||||
//if (gSetting_set_gui) {
|
||||
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
|
||||
/*
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI_DisplaySmallest(String, x + 2, line == 0 ? 9 : 41, false, true);
|
||||
uint8_t g = 13;
|
||||
if(over1GHz)
|
||||
g = 17;
|
||||
|
||||
gFrameBuffer[line + 1][0] ^= 0x1C;
|
||||
gFrameBuffer[line + 1][1] ^= 0x3E;
|
||||
for (uint8_t i = 2; i < g; i++) {
|
||||
gFrameBuffer[line + 1][i] ^= 0x7F;
|
||||
}
|
||||
gFrameBuffer[line + 1][g] ^= 0x3E;
|
||||
gFrameBuffer[line + 1][g + 1] ^= 0x1C;
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
#ifdef ENABLE_NOAA
|
||||
else
|
||||
@@ -852,7 +893,7 @@ void UI_DisplayMain(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
// ************
|
||||
// ----------------------------------------
|
||||
|
||||
enum VfoState_t state = VfoState[vfo_num];
|
||||
|
||||
@@ -917,20 +958,44 @@ void UI_DisplayMain(void)
|
||||
countList = 0;
|
||||
}
|
||||
|
||||
const char *displayStr = (countList == MR_CHANNELS_LIST + 1) ? "ALL" :
|
||||
(countList == 0) ? "OFF" : String;
|
||||
uint8_t xStart = (countList > 0 && countList != MR_CHANNELS_LIST + 1) ? 117 : 113;
|
||||
uint8_t xDisplay = (countList > 0 && countList != MR_CHANNELS_LIST + 1) ? 119 : 115;
|
||||
const char *displayStr;
|
||||
uint8_t xStart, xDisplay;
|
||||
|
||||
if(countList > 0 && countList != MR_CHANNELS_LIST + 1) {
|
||||
sprintf(String, "%02d", countList);
|
||||
if (countList == MR_CHANNELS_LIST + 1) {
|
||||
displayStr = "ALL";
|
||||
xStart = 113;
|
||||
xDisplay = 115;
|
||||
}
|
||||
else if (countList == 0) {
|
||||
displayStr = "OFF";
|
||||
xStart = 113;
|
||||
xDisplay = 115;
|
||||
}
|
||||
else {
|
||||
// List 1 to MR_CHANNELS_LIST
|
||||
const char *name = gListName[countList - 1];
|
||||
|
||||
// If name is empty/invalid, display number
|
||||
if (name[0] == '\0' || name[0] == '\xff' || name[0] == ' ') {
|
||||
sprintf(String, "%02d", countList);
|
||||
xStart = 117; // 2-digit number aligned right
|
||||
xDisplay = 119;
|
||||
}
|
||||
else {
|
||||
sprintf(String, "%.3s", name);
|
||||
xStart = 113; // 3-char name aligned left
|
||||
xDisplay = 115;
|
||||
}
|
||||
displayStr = String;
|
||||
}
|
||||
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 2 : 34, false, true);
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 1 : 33, false, true);
|
||||
|
||||
for (uint8_t x = xStart; x < 128; x++) {
|
||||
gFrameBuffer[line][x] ^= 0xFE;
|
||||
gFrameBuffer[line][xStart] ^= 0x3E;
|
||||
for (uint8_t x = xStart + 1; x < 127; x++) {
|
||||
gFrameBuffer[line][x] ^= 0x7F;
|
||||
}
|
||||
gFrameBuffer[line][127] ^= 0x3E;
|
||||
|
||||
}
|
||||
else
|
||||
@@ -940,10 +1005,10 @@ void UI_DisplayMain(void)
|
||||
uint8_t xStart = 117;
|
||||
uint8_t xDisplay = 119;
|
||||
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 2 : 34, false, true);
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 1 : 33, false, true);
|
||||
|
||||
for (uint8_t x = xStart; x < 128; x++) {
|
||||
gFrameBuffer[line][x] ^= 0xFE;
|
||||
gFrameBuffer[line][x] ^= 0x7F;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,7 +1048,7 @@ void UI_DisplayMain(void)
|
||||
break;
|
||||
|
||||
case MDF_CHANNEL: // show the channel number
|
||||
sprintf(String, "CH-%03u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
sprintf(String, "CH-%04u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
break;
|
||||
|
||||
@@ -993,19 +1058,19 @@ void UI_DisplayMain(void)
|
||||
SETTINGS_FetchChannelName(String, gEeprom.ScreenChannel[vfo_num]);
|
||||
if (String[0] == 0)
|
||||
{ // no channel name, show the channel number instead
|
||||
sprintf(String, "CH-%03u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
sprintf(String, "CH-%04u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
}
|
||||
|
||||
if (gEeprom.CHANNEL_DISPLAY_MODE == MDF_NAME) {
|
||||
String[9] = 0;
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
String[10] = 0;
|
||||
UI_PrintString(String, 33, 0, line, 8);
|
||||
}
|
||||
else {
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if (isMainOnly())
|
||||
{
|
||||
String[9] = 0;
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
String[10] = 0;
|
||||
UI_PrintString(String, 33, 0, line, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1082,7 +1147,7 @@ void UI_DisplayMain(void)
|
||||
}
|
||||
}
|
||||
|
||||
// ************
|
||||
// ----------------------------------------
|
||||
|
||||
{ // show the TX/RX level
|
||||
int8_t Level = -1;
|
||||
@@ -1121,10 +1186,10 @@ void UI_DisplayMain(void)
|
||||
#endif
|
||||
}
|
||||
if(Level >= 0)
|
||||
DrawSmallAntennaAndBars(p_line1 + LCD_WIDTH, Level);
|
||||
DrawSmallPowerBars(p_line1 + LCD_WIDTH, Level);
|
||||
}
|
||||
|
||||
// ************
|
||||
// ----------------------------------------
|
||||
|
||||
String[0] = '\0';
|
||||
const VFO_Info_t *vfoInfo = &gEeprom.VfoInfo[vfo_num];
|
||||
@@ -1530,11 +1595,21 @@ void UI_DisplayMain(void)
|
||||
if (isMainOnly() && !gDTMF_InputMode)
|
||||
{
|
||||
sprintf(String, "VFO %s", activeTxVFO ? "B" : "A");
|
||||
GUI_DisplaySmallest(String, 107, 50, false, true);
|
||||
|
||||
gFrameBuffer[6][105] ^= 0x7C;
|
||||
for (uint8_t x = 106; x < 127; x++) {
|
||||
gFrameBuffer[6][x] ^= 0xFE;
|
||||
}
|
||||
gFrameBuffer[6][127] ^= 0x7C;
|
||||
|
||||
/*
|
||||
UI_PrintStringSmallBold(String, 92, 0, 6);
|
||||
for (uint8_t i = 92; i < 128; i++)
|
||||
{
|
||||
gFrameBuffer[6][i] ^= 0x7F;
|
||||
}
|
||||
*/
|
||||
}
|
||||
//#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
//}
|
||||
@@ -1543,5 +1618,3 @@ void UI_DisplayMain(void)
|
||||
|
||||
ST7565_BlitFullScreen();
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
@@ -36,7 +36,6 @@ enum Vfo_txtr_mode{
|
||||
typedef enum center_line_t center_line_t;
|
||||
|
||||
extern center_line_t center_line;
|
||||
extern const int8_t dBmCorrTable[7];
|
||||
|
||||
void UI_DisplayAudioBar(void);
|
||||
void UI_MAIN_TimeSlice500ms(void);
|
||||
|
||||
+23
-7
@@ -646,7 +646,11 @@ void UI_DisplayMenu(void)
|
||||
case MENU_MIC:
|
||||
{ // display the mic gain in actual dB rather than just an index number
|
||||
const uint8_t mic = gMicGain_dB2[gSubMenuSelection];
|
||||
sprintf(String, "+%u.%01udB", mic / 2, mic % 2);
|
||||
sprintf(String, "+%u.%udB", mic / 2, (mic % 2) * 5);
|
||||
|
||||
gaugeLine = 4;
|
||||
gaugeMin = 0;
|
||||
gaugeMax = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -703,15 +707,14 @@ void UI_DisplayMenu(void)
|
||||
if (!gIsInSubMenu || gInputBoxIndex == 0)
|
||||
{
|
||||
sprintf(String, "%3d.%05u", gSubMenuSelection / 100000, abs(gSubMenuSelection) % 100000);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 1, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char * ascii = INPUTBOX_GetAscii();
|
||||
sprintf(String, "%.3s.%.3s ",ascii, ascii + 3);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 1, 8);
|
||||
}
|
||||
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 1, 8);
|
||||
UI_PrintString("MHz", menu_item_x1, menu_item_x2, 3, 8);
|
||||
|
||||
already_printed = true;
|
||||
@@ -969,15 +972,28 @@ void UI_DisplayMenu(void)
|
||||
strcpy(String, "ALL");
|
||||
else if (gSubMenuSelection == 0)
|
||||
strcpy(String, "OFF");
|
||||
else
|
||||
sprintf(String, "%u", gSubMenuSelection);
|
||||
else {
|
||||
const char *name = gListName[gSubMenuSelection - 1];
|
||||
|
||||
// If first character is empty/invalid, display "N/A"
|
||||
if (name[0] == '\0' || name[0] == '\xff' || name[0] == ' ')
|
||||
sprintf(String, "%02u", gSubMenuSelection);
|
||||
else
|
||||
sprintf(String, "%02u (%.3s)", gSubMenuSelection, name);
|
||||
}
|
||||
break;
|
||||
|
||||
case MENU_S_LIST:
|
||||
if (gSubMenuSelection == MR_CHANNELS_LIST + 1)
|
||||
strcpy(String, "ALL");
|
||||
else
|
||||
sprintf(String, "%u", gSubMenuSelection);
|
||||
else {
|
||||
const char *name = gListName[gSubMenuSelection - 1];
|
||||
// If first character is empty/invalid, display "N/A"
|
||||
if (name[0] == '\0' || name[0] == '\xff' || name[0] == ' ')
|
||||
sprintf(String, "%02u", gSubMenuSelection);
|
||||
else
|
||||
sprintf(String, "%02u (%.3s)", gSubMenuSelection, name);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_ALARM
|
||||
|
||||
+17
-8
@@ -101,31 +101,40 @@ void UI_DisplayStatus()
|
||||
{
|
||||
if(gEeprom.SCAN_LIST_ENABLED==1) {
|
||||
sprintf(str, "%s+", "ALL");
|
||||
end = 19;
|
||||
end = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(str, "%s", "ALL");
|
||||
end = 15;
|
||||
end = 14;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(gEeprom.SCAN_LIST_ENABLED==1) {
|
||||
sprintf(str, "%02d+", gEeprom.SCAN_LIST_DEFAULT);
|
||||
end = 15;
|
||||
const char *name = gListName[gEeprom.SCAN_LIST_DEFAULT - 1];
|
||||
|
||||
// Check if name is valid
|
||||
bool nameValid = (name[0] != '\0' && name[0] != '\xff' && name[0] != ' ');
|
||||
|
||||
// Format the string
|
||||
if (nameValid) {
|
||||
sprintf(str, "%.3s%s", name, gEeprom.SCAN_LIST_ENABLED ? "+" : "");
|
||||
end = gEeprom.SCAN_LIST_ENABLED ? 18 : 14;
|
||||
}
|
||||
else {
|
||||
sprintf(str, "%02d", gEeprom.SCAN_LIST_DEFAULT);
|
||||
end = 11;
|
||||
sprintf(str, "%02d%s", gEeprom.SCAN_LIST_DEFAULT, gEeprom.SCAN_LIST_ENABLED ? "+" : "");
|
||||
end = gEeprom.SCAN_LIST_ENABLED ? 14 : 10;
|
||||
}
|
||||
}
|
||||
|
||||
GUI_DisplaySmallest(str, 2, 1, true, true);
|
||||
for (uint8_t x = 0; x < end; x++)
|
||||
|
||||
gStatusLine[0] ^= 0x3E;
|
||||
for (uint8_t x = 1; x < end; x++)
|
||||
{
|
||||
gStatusLine[x] ^= 0x7F;
|
||||
}
|
||||
gStatusLine[end] ^= 0x3E;
|
||||
}
|
||||
else { // frequency mode
|
||||
memcpy(line + x + 1, gFontS, sizeof(gFontS));
|
||||
|
||||
+84
-68
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "driver/py25q16.h"
|
||||
#include "driver/st7565.h"
|
||||
@@ -32,6 +33,63 @@
|
||||
#include "screenshot.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_MEM
|
||||
// Linker symbols (provided by the linker script)
|
||||
extern uint8_t _sdata; // Start of .data in RAM
|
||||
extern uint8_t _edata; // End of .data in RAM
|
||||
extern uint8_t _sbss; // Start of .bss in RAM
|
||||
extern uint8_t _ebss; // End of .bss in RAM
|
||||
|
||||
// _eflash_used must be defined in the linker script immediately after the last
|
||||
// section with a FLASH load address (after .noncacheable). Example:
|
||||
//
|
||||
// .noncacheable : {
|
||||
// ...
|
||||
// } > RAM AT> FLASH
|
||||
// _eflash_used = LOADADDR(.noncacheable) + SIZEOF(.noncacheable);
|
||||
//
|
||||
// This gives the exact byte count that the linker reports as FLASH used.
|
||||
extern uint8_t _eflash_used;
|
||||
|
||||
// Absolute symbols: their *address* IS the numeric size value (ARM/CMSIS convention).
|
||||
// RAM = .data + gap + .bss + heap_reserve + stack_reserve
|
||||
extern uint8_t _Min_Heap_Size;
|
||||
extern uint8_t _Min_Stack_Size;
|
||||
|
||||
// Region sizes (must match your linker MEMORY regions)
|
||||
#define RAM_SIZE_BYTES (16u * 1024u)
|
||||
#define FLASH_SIZE_BYTES (118u * 1024u)
|
||||
|
||||
// Base address of FLASH — must match ORIGIN(FLASH) in your linker script
|
||||
#define FLASH_BASE (0x08002800u)
|
||||
|
||||
static inline uint32_t span(const void* a, const void* b)
|
||||
{
|
||||
return (uint32_t)((uintptr_t)b - (uintptr_t)a);
|
||||
}
|
||||
|
||||
static void build_usage(uint32_t* ram_used, uint32_t* flash_used)
|
||||
{
|
||||
// RAM: span from start of .data to end of .bss covers .data + alignment gap + .bss.
|
||||
// Then add heap and stack reservations (absolute linker symbols: address = size).
|
||||
// Proof: (0x20002A60 - 0x20000000) + 0x200 + 0x400 = 10848 + 512 + 1024 = 12384 B ✓
|
||||
const uint32_t heap_size = (uint32_t)(uintptr_t)&_Min_Heap_Size;
|
||||
const uint32_t stack_size = (uint32_t)(uintptr_t)&_Min_Stack_Size;
|
||||
*ram_used = span(&_sdata, &_ebss) + heap_size + stack_size;
|
||||
|
||||
// FLASH: _eflash_used is placed by the linker script right after the last
|
||||
// section copied to FLASH (.data LMA + .noncacheable LMA).
|
||||
// Note: _etext is NOT usable here because this linker script places .rodata
|
||||
// sections AFTER _etext, making it an unreliable end-of-flash marker.
|
||||
*flash_used = span((void*)FLASH_BASE, &_eflash_used);
|
||||
}
|
||||
|
||||
static inline uint16_t pct_x100(uint32_t used, uint32_t total)
|
||||
{
|
||||
return (uint16_t)((used * 10000u) / total); // 7559 => 75.59%
|
||||
}
|
||||
#endif
|
||||
|
||||
void UI_DisplayReleaseKeys(void)
|
||||
{
|
||||
memset(gStatusLine, 0, sizeof(gStatusLine));
|
||||
@@ -52,7 +110,7 @@ void UI_DisplayWelcome(void)
|
||||
char WelcomeString0[16];
|
||||
char WelcomeString1[16];
|
||||
char WelcomeString2[16];
|
||||
char WelcomeString3[20];
|
||||
char WelcomeString3[32];
|
||||
|
||||
memset(gStatusLine, 0, sizeof(gStatusLine));
|
||||
|
||||
@@ -125,79 +183,37 @@ void UI_DisplayWelcome(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
UI_PrintStringSmallNormal(Version, 0, 128, 4);
|
||||
|
||||
UI_DrawLineBuffer(gFrameBuffer, 0, 31, 127, 31, 1); // Be ware, status zone = 8 lines, the rest = 56 ->total 64
|
||||
|
||||
for (uint8_t i = 18; i < 110; i++)
|
||||
UI_DrawLineBuffer(gFrameBuffer, 0, 35, 18, 35, 1);
|
||||
gFrameBuffer[4][19] ^= 0x7F;
|
||||
for (uint8_t x = 20; x < 108; x++)
|
||||
{
|
||||
gFrameBuffer[4][i] ^= 0xFF;
|
||||
gFrameBuffer[4][x] ^= 0xFF;
|
||||
gFrameBuffer[3][x] ^= 0x80;
|
||||
}
|
||||
gFrameBuffer[4][108] ^= 0x7F;
|
||||
UI_DrawLineBuffer(gFrameBuffer, 109, 35, 127, 35, 1);
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_MEM
|
||||
uint32_t ram_used = 0;
|
||||
uint32_t flash_used = 0;
|
||||
build_usage(&ram_used, &flash_used);
|
||||
|
||||
const uint16_t ram_pct = pct_x100(ram_used, RAM_SIZE_BYTES);
|
||||
const uint16_t flash_pct = pct_x100(flash_used, FLASH_SIZE_BYTES);
|
||||
|
||||
// No floats: 7559 => 75.59%
|
||||
sprintf(WelcomeString3,
|
||||
"FLASH %u.%02u %% - SRAM %u.%02u %%",
|
||||
(unsigned)(flash_pct / 100), (unsigned)(flash_pct % 100),
|
||||
(unsigned)(ram_pct / 100), (unsigned)(ram_pct % 100));
|
||||
|
||||
GUI_DisplaySmallest(WelcomeString3, 5, 1, true, true);
|
||||
ST7565_BlitStatusLine();
|
||||
#endif
|
||||
|
||||
sprintf(WelcomeString3, "%s Edition", Edition);
|
||||
UI_PrintStringSmallNormal(WelcomeString3, 0, 127, 6);
|
||||
|
||||
/*
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
#if ENABLE_FEAT_F4HWN_RESCUE_OPS > 1
|
||||
UI_PrintStringSmallNormal(Edition, 18, 0, 6);
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(gFrameBuffer[6] + 103, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(gFrameBuffer[6] + 103, BITMAP_NotReady, sizeof(BITMAP_NotReady));
|
||||
}
|
||||
#else
|
||||
UI_PrintStringSmallNormal(Edition, 18, 0, 5);
|
||||
memcpy(gFrameBuffer[5] + 103, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
UI_PrintStringSmallNormal("RescueOps", 18, 0, 6);
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(gFrameBuffer[6] + 103, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(gFrameBuffer[6] + 103, BITMAP_NotReady, sizeof(BITMAP_NotReady));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
UI_PrintStringSmallNormal(Edition, 18, 0, 6);
|
||||
memcpy(gFrameBuffer[6] + 103, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
#endif
|
||||
*/
|
||||
|
||||
/*
|
||||
#ifdef ENABLE_SPECTRUM
|
||||
#ifdef ENABLE_FMRADIO
|
||||
UI_PrintStringSmallNormal(Based, 0, 127, 5);
|
||||
UI_PrintStringSmallNormal(Credits, 0, 127, 6);
|
||||
#else
|
||||
UI_PrintStringSmallNormal("Bandscope ", 0, 127, 5);
|
||||
memcpy(gFrameBuffer[5] + 95, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
UI_PrintStringSmallNormal("RescueOps ", 0, 127, 6);
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(gFrameBuffer[6] + 95, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
}
|
||||
#else
|
||||
UI_PrintStringSmallNormal("Broadcast ", 0, 127, 6);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
UI_PrintStringSmallNormal("RescueOps ", 0, 127, 5);
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(gFrameBuffer[5] + 95, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
}
|
||||
#else
|
||||
UI_PrintStringSmallNormal("Bandscope ", 0, 127, 5);
|
||||
#endif
|
||||
UI_PrintStringSmallNormal("Broadcast ", 0, 127, 6);
|
||||
memcpy(gFrameBuffer[6] + 95, BITMAP_Ready, sizeof(BITMAP_Ready));
|
||||
#endif
|
||||
*/
|
||||
#else
|
||||
UI_PrintStringSmallNormal(Version, 0, 127, 6);
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -65,11 +65,12 @@
|
||||
"ENABLE_FEAT_F4HWN_GMRS_FRS_MURS": false,
|
||||
"ENABLE_FEAT_F4HWN_CA": true,
|
||||
"ENABLE_FEAT_F4HWN_DEBUG": false,
|
||||
"ENABLE_FEAT_F4HWN_MEM": false,
|
||||
"ENABLE_AGC_SHOW_DATA": false,
|
||||
"ENABLE_UART_RW_BK_REGS": false,
|
||||
"ENABLE_SWD": false,
|
||||
"VERSION_STRING_1": "v0.22",
|
||||
"VERSION_STRING_2": "v5.1.0"
|
||||
"VERSION_STRING_2": "v5.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -145,6 +145,15 @@ SECTIONS
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
} >RAM AT> FLASH
|
||||
|
||||
/* Explicit placement of .noncacheable (CherryUSB) + end-of-FLASH symbol */
|
||||
.noncacheable :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.noncacheable)
|
||||
*(.noncacheable*)
|
||||
. = ALIGN(4);
|
||||
} >RAM AT> FLASH
|
||||
_eflash_used = LOADADDR(.noncacheable) + SIZEOF(.noncacheable);
|
||||
|
||||
/* Uninitialized data section */
|
||||
. = ALIGN(4);
|
||||
|
||||
@@ -42,7 +42,7 @@ Anyway, have fun.
|
||||
|
||||
# Donations
|
||||
|
||||
Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar, Zhuo BG7SGA and Jamie M0JLB for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK and Victor TI2SYS for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
<img width="2016" height="1512" alt="pcbite" src="https://github.com/user-attachments/assets/b3086bf2-c14c-47da-b68b-a6867268ae78" />
|
||||
|
||||
Restoring a UV-K5 V1 accidentally flashed with the F4HWN 4.3 Fusion 🔥 Edition firmware, using OpenOCD and a ST-LINK programmer.
|
||||
Restoring a UV-K5 V1 accidentally flashed with the F4HWN Fusion 🔥 Edition firmware, using OpenOCD and a ST-LINK programmer.
|
||||
|
||||
## Introduction
|
||||
|
||||
Some users have accidentally flashed a UV-K5 V1 with the F4HWN 4.3 Fusion 🔥 Edition firmware. This edition **is only** compatible with:
|
||||
Some users have accidentally flashed a UV-K5 V1 with the F4HWN Fusion 🔥 Edition firmware. This edition **is only** compatible with:
|
||||
|
||||
- UV-K5 V3
|
||||
- UV-K1
|
||||
|
||||
Reference in new issue
Block a user