mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
46 files changed
+1256
-1033
No files matched your search
@@ -7,6 +7,7 @@ firmware
|
||||
.cache
|
||||
compile_commands.json
|
||||
.vscode
|
||||
.claude
|
||||
/docs
|
||||
k5_eeprom.raw
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ enable_feature(ENABLE_SQUELCH_MORE_SENSITIVE)
|
||||
enable_feature(ENABLE_FASTER_CHANNEL_SCAN)
|
||||
enable_feature(ENABLE_RSSI_BAR)
|
||||
enable_feature(ENABLE_AUDIO_BAR)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_AUDIO_SCOPE)
|
||||
enable_feature(ENABLE_COPY_CHAN_TO_VFO)
|
||||
enable_feature(ENABLE_REDUCE_LOW_MID_TX_POWER)
|
||||
enable_feature(ENABLE_BYP_RAW_DEMODULATORS)
|
||||
|
||||
+65
-58
@@ -290,6 +290,8 @@ void ACTION_SwitchDemodul(void)
|
||||
|
||||
void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
HideFKeyIcon();
|
||||
|
||||
if (gScreenToDisplay == DISPLAY_MAIN && gDTMF_InputMode){
|
||||
// entering DTMF code
|
||||
|
||||
@@ -319,19 +321,23 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
return;
|
||||
}
|
||||
|
||||
enum ACTION_OPT_t funcShort = ACTION_OPT_NONE;
|
||||
enum ACTION_OPT_t funcLong = ACTION_OPT_NONE;
|
||||
enum ACTION_OPT_t func = ACTION_OPT_NONE;
|
||||
switch(Key) {
|
||||
case KEY_SIDE1:
|
||||
funcShort = gEeprom.KEY_1_SHORT_PRESS_ACTION;
|
||||
funcLong = gEeprom.KEY_1_LONG_PRESS_ACTION;
|
||||
if (bKeyHeld)
|
||||
func = gEeprom.KEY_1_LONG_PRESS_ACTION;
|
||||
else
|
||||
func = gEeprom.KEY_1_SHORT_PRESS_ACTION;
|
||||
break;
|
||||
case KEY_SIDE2:
|
||||
funcShort = gEeprom.KEY_2_SHORT_PRESS_ACTION;
|
||||
funcLong = gEeprom.KEY_2_LONG_PRESS_ACTION;
|
||||
if (bKeyHeld)
|
||||
func = gEeprom.KEY_2_LONG_PRESS_ACTION;
|
||||
else
|
||||
func = gEeprom.KEY_2_SHORT_PRESS_ACTION;
|
||||
break;
|
||||
case KEY_MENU:
|
||||
funcLong = gEeprom.KEY_M_LONG_PRESS_ACTION;
|
||||
if (bKeyHeld)
|
||||
func = gEeprom.KEY_M_LONG_PRESS_ACTION;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -347,17 +353,46 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
if(!(bKeyHeld && !bKeyPressed)) // don't beep on released after hold
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
if (bKeyHeld || bKeyPressed) // held
|
||||
if (bKeyHeld && !bKeyPressed) // button released after hold
|
||||
{
|
||||
funcShort = funcLong;
|
||||
|
||||
if (!bKeyPressed) //ignore release if held
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// held or released after short press beyond this point
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
if (gFmRadioMode) { // do not run these actions in FM radio mode
|
||||
switch (func) {
|
||||
case ACTION_OPT_POWER:
|
||||
case ACTION_OPT_MONITOR:
|
||||
case ACTION_OPT_A_B:
|
||||
case ACTION_OPT_VFO_MR:
|
||||
case ACTION_OPT_SWITCH_DEMODUL:
|
||||
#ifdef ENABLE_VOX
|
||||
case ACTION_OPT_VOX:
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
case ACTION_OPT_RXMODE:
|
||||
case ACTION_OPT_MAINONLY:
|
||||
case ACTION_OPT_WN:
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
case ACTION_OPT_RXA:
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
case ACTION_OPT_POWER_HIGH:
|
||||
case ACTION_OPT_REMOVE_OFFSET:
|
||||
#endif
|
||||
#endif
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
|
||||
action_opt_table[funcShort]();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
action_opt_table[func]();
|
||||
}
|
||||
|
||||
|
||||
@@ -545,64 +580,36 @@ void ACTION_RxA(void)
|
||||
void ACTION_Ptt(void)
|
||||
{
|
||||
gSetting_set_ptt_session = !gSetting_set_ptt_session;
|
||||
|
||||
ACTION_Update();
|
||||
}
|
||||
|
||||
void ACTION_Wn(void)
|
||||
{
|
||||
if (gRxVfo->Modulation == MODULATION_AM)
|
||||
const bool isRx = FUNCTION_IsRx();
|
||||
VFO_Info_t *pVfo = isRx ? gRxVfo : gTxVfo;
|
||||
|
||||
pVfo->CHANNEL_BANDWIDTH = !pVfo->CHANNEL_BANDWIDTH;
|
||||
|
||||
if (pVfo->Modulation == MODULATION_AM)
|
||||
{
|
||||
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t bw = pVfo->CHANNEL_BANDWIDTH;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
bool narrower = 0;
|
||||
if (FUNCTION_IsRx())
|
||||
if (isRx && bw == BANDWIDTH_NARROW && gSetting_set_nfm == 1)
|
||||
{
|
||||
gRxVfo->CHANNEL_BANDWIDTH = (gRxVfo->CHANNEL_BANDWIDTH == 0) ? 1: 0;
|
||||
if(gRxVfo->CHANNEL_BANDWIDTH == BANDWIDTH_NARROW && gSetting_set_nfm == 1)
|
||||
{
|
||||
narrower = 1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_AM_FIX
|
||||
BK4819_SetFilterBandwidth(gRxVfo->CHANNEL_BANDWIDTH + narrower, true);
|
||||
#else
|
||||
BK4819_SetFilterBandwidth(gRxVfo->CHANNEL_BANDWIDTH + narrower, false);
|
||||
#endif
|
||||
bw++;
|
||||
}
|
||||
else
|
||||
{
|
||||
gTxVfo->CHANNEL_BANDWIDTH = (gTxVfo->CHANNEL_BANDWIDTH == 0) ? 1: 0;
|
||||
if(gTxVfo->CHANNEL_BANDWIDTH == BANDWIDTH_NARROW && gSetting_set_nfm == 1)
|
||||
{
|
||||
narrower = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AM_FIX
|
||||
BK4819_SetFilterBandwidth(gTxVfo->CHANNEL_BANDWIDTH, true);
|
||||
#else
|
||||
BK4819_SetFilterBandwidth(gTxVfo->CHANNEL_BANDWIDTH, false);
|
||||
#endif
|
||||
}
|
||||
#ifdef ENABLE_AM_FIX
|
||||
BK4819_SetFilterBandwidth(bw, true);
|
||||
#else
|
||||
if (FUNCTION_IsRx())
|
||||
{
|
||||
gRxVfo->CHANNEL_BANDWIDTH = (gRxVfo->CHANNEL_BANDWIDTH == 0) ? 1: 0;
|
||||
#ifdef ENABLE_AM_FIX
|
||||
BK4819_SetFilterBandwidth(gRxVfo->CHANNEL_BANDWIDTH, true);
|
||||
#else
|
||||
BK4819_SetFilterBandwidth(gRxVfo->CHANNEL_BANDWIDTH, false);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
gTxVfo->CHANNEL_BANDWIDTH = (gTxVfo->CHANNEL_BANDWIDTH == 0) ? 1: 0;
|
||||
#ifdef ENABLE_AM_FIX
|
||||
BK4819_SetFilterBandwidth(gTxVfo->CHANNEL_BANDWIDTH, true);
|
||||
#else
|
||||
BK4819_SetFilterBandwidth(gTxVfo->CHANNEL_BANDWIDTH, false);
|
||||
#endif
|
||||
}
|
||||
BK4819_SetFilterBandwidth(bw, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+51
-78
@@ -139,7 +139,7 @@ static void AIRCOPY_clear()
|
||||
crc[i] = 0;
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(true);
|
||||
SCREENSHOT_Update(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -167,11 +167,18 @@ static inline void AIRCOPY_CheckComplete(void)
|
||||
{
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
SCREENSHOT_Update(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline void AIRCOPY_Obfuscation(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < 34; i++) {
|
||||
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Send/Receive Functions
|
||||
// ============================================================================
|
||||
@@ -212,7 +219,7 @@ bool AIRCOPY_SendMessage(void)
|
||||
if (CurrentSegmentIndex >= map->num_segments) {
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
SCREENSHOT_Update(false);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -223,9 +230,7 @@ bool AIRCOPY_SendMessage(void)
|
||||
|
||||
g_FSK_Buffer[34] = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
|
||||
|
||||
for (unsigned int i = 0; i < 34; i++) {
|
||||
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
|
||||
}
|
||||
AIRCOPY_Obfuscation();
|
||||
|
||||
RADIO_SetTxParameters();
|
||||
|
||||
@@ -261,9 +266,7 @@ void AIRCOPY_StorePacket(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 34; i++) {
|
||||
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
|
||||
}
|
||||
AIRCOPY_Obfuscation();
|
||||
|
||||
uint16_t Crc = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
|
||||
if (g_FSK_Buffer[34] != Crc) {
|
||||
@@ -273,25 +276,9 @@ void AIRCOPY_StorePacket(void)
|
||||
}
|
||||
|
||||
uint16_t Offset = g_FSK_Buffer[1];
|
||||
const AIRCOPY_TransferMap_t *map = AIRCOPY_GetCurrentMap();
|
||||
|
||||
// Validate offset is in the map
|
||||
bool validOffset = false;
|
||||
for (uint16_t i = 0; i < map->num_segments; i++) {
|
||||
if (Offset >= map->segments[i].start_offset && Offset < map->segments[i].end_offset) {
|
||||
validOffset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validOffset) {
|
||||
gErrorsDuringAirCopy++;
|
||||
AIRCOPY_CheckComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
const AIRCOPY_Segment_t *seg = AIRCOPY_FindSegmentForOffset(Offset);
|
||||
|
||||
|
||||
if (seg == NULL) {
|
||||
gErrorsDuringAirCopy++;
|
||||
AIRCOPY_CheckComplete();
|
||||
@@ -325,20 +312,27 @@ void AIRCOPY_StorePacket(void)
|
||||
AIRCOPY_CheckComplete();
|
||||
}
|
||||
|
||||
static void AIRCOPY_InitTransfer(bool isSendMode)
|
||||
{
|
||||
gAircopyStep = 1;
|
||||
gFSKWriteIndex = 0;
|
||||
gAirCopyBlockNumber = 0;
|
||||
gInputBoxIndex = 0;
|
||||
gAirCopyIsSendMode = isSendMode;
|
||||
|
||||
AIRCOPY_clear();
|
||||
|
||||
gAircopyState = AIRCOPY_TRANSFER;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Key Processing
|
||||
// ============================================================================
|
||||
|
||||
static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
static void AIRCOPY_Key_DIGITS(KEY_Code_t Key)
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
INPUTBOX_Append(Key);
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
|
||||
if (gInputBoxIndex < 6) {
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
@@ -373,64 +367,32 @@ static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
BK4819_ResetFSK();
|
||||
return;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
}
|
||||
|
||||
static void AIRCOPY_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
|
||||
static void AIRCOPY_Key_EXIT()
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gInputBoxIndex == 0) {
|
||||
gAircopyStep = 1;
|
||||
gFSKWriteIndex = 0;
|
||||
gAirCopyBlockNumber = 0;
|
||||
gInputBoxIndex = 0;
|
||||
AIRCOPY_InitTransfer(0); // Mode: Receive
|
||||
gErrorsDuringAirCopy = lErrorsDuringAirCopy = 0;
|
||||
gAirCopyIsSendMode = 0;
|
||||
|
||||
AIRCOPY_clear();
|
||||
|
||||
BK4819_PrepareFSKReceive();
|
||||
|
||||
gAircopyState = AIRCOPY_TRANSFER;
|
||||
|
||||
} else {
|
||||
gInputBox[--gInputBoxIndex] = 10;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
}
|
||||
|
||||
static void AIRCOPY_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
static void AIRCOPY_Key_MENU()
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
gAircopyStep = 1;
|
||||
gFSKWriteIndex = 0;
|
||||
gAirCopyBlockNumber = 0;
|
||||
gInputBoxIndex = 0;
|
||||
gAirCopyIsSendMode = 1;
|
||||
AIRCOPY_InitTransfer(1); // Mode: Send
|
||||
|
||||
g_FSK_Buffer[0] = 0xABCD;
|
||||
g_FSK_Buffer[1] = 0;
|
||||
g_FSK_Buffer[35] = 0xDCBA;
|
||||
|
||||
AIRCOPY_clear();
|
||||
|
||||
GUI_DisplayScreen();
|
||||
|
||||
gAircopyState = AIRCOPY_TRANSFER;
|
||||
}
|
||||
|
||||
static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
static void AIRCOPY_Key_UP_DOWN(int8_t Direction)
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gEeprom.SET_NAV) {
|
||||
Direction = -Direction;
|
||||
}
|
||||
@@ -444,29 +406,40 @@ static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Directio
|
||||
gAircopyCurrentMapIndex = (gAircopyCurrentMapIndex + AIRCOPY_NUM_MAPS - 1) % AIRCOPY_NUM_MAPS;
|
||||
break;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
}
|
||||
|
||||
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Key != KEY_PTT) {
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
|
||||
switch (Key) {
|
||||
case KEY_0...KEY_9:
|
||||
AIRCOPY_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
|
||||
AIRCOPY_Key_DIGITS(Key);
|
||||
break;
|
||||
case KEY_MENU:
|
||||
AIRCOPY_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
AIRCOPY_Key_MENU();
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
AIRCOPY_Key_EXIT();
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, Key == KEY_UP ? 1 : -1);
|
||||
AIRCOPY_Key_UP_DOWN(Key == KEY_UP ? 1 : -1);
|
||||
break;
|
||||
case KEY_PTT:
|
||||
break;
|
||||
default:
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
break;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
}
|
||||
|
||||
#endif
|
||||
+97
-100
@@ -535,7 +535,17 @@ void APP_StartListening(FUNCTION_Type_t function)
|
||||
gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
|
||||
{ // not scanning, dual watch is enabled
|
||||
|
||||
gDualWatchCountdown_10ms = dual_watch_count_after_2_10ms;
|
||||
//gDualWatchCountdown_10ms = dual_watch_count_after_2_10ms;
|
||||
|
||||
const bool isMainTxDualRx =
|
||||
(gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) &&
|
||||
(gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF);
|
||||
|
||||
// Use a short hold only for MAIN TX DUAL RX, keep legacy hold otherwise
|
||||
gDualWatchCountdown_10ms = isMainTxDualRx
|
||||
? dual_watch_count_after_2_10ms / 4 // Short timer = 420 / 4 ...
|
||||
: dual_watch_count_after_2_10ms;
|
||||
|
||||
gScheduleDualWatch = false;
|
||||
|
||||
// when crossband is active only the main VFO should be used for TX
|
||||
@@ -882,6 +892,12 @@ static void HandleVox(void)
|
||||
|
||||
void APP_Update(void)
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Parse incoming packets on every tick so serial keys are never missed,
|
||||
// regardless of whether the screen needs redrawing.
|
||||
SCREENSHOT_ParseInput();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
if (gFlagPlayQueuedVoice) {
|
||||
AUDIO_PlayQueuedVoice();
|
||||
@@ -1149,8 +1165,21 @@ void APP_Update(void)
|
||||
}
|
||||
}
|
||||
|
||||
void StopTransmitting(void) {
|
||||
ProcessKey(KEY_PTT, false, false);
|
||||
gPttIsPressed = false;
|
||||
if (gKeyReading1 != KEY_INVALID)
|
||||
gPttWasReleased = true;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
#if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV)
|
||||
ST7565_ContrastAndInv();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// called every 10ms
|
||||
static void CheckKeys(void)
|
||||
void CheckKeys(void)
|
||||
{
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
if(gSetting_KILLED){
|
||||
@@ -1165,75 +1194,63 @@ static void CheckKeys(void)
|
||||
#endif
|
||||
|
||||
// -------------------- PTT ------------------------
|
||||
const bool serialConfigInProgress = SerialConfigInProgress();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
const bool isPressed = GPIO_IsPttPressed() && !serialConfigInProgress;
|
||||
#else
|
||||
const bool isPressed = !GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && !serialConfigInProgress;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if (gSetting_set_ptt_session)
|
||||
{
|
||||
if (GPIO_IsPttPressed() && !SerialConfigInProgress() && gPttOnePushCounter == 0)
|
||||
{ // PTT pressed
|
||||
if (++gPttDebounceCounter >= 3) // 30ms
|
||||
{ // start transmitting
|
||||
boot_counter_10ms = 0;
|
||||
if ((isPressed && (gPttOnePushCounter == 0 || gPttOnePushCounter == 2)) ||
|
||||
(!isPressed && (gPttOnePushCounter == 1 || gPttOnePushCounter == 3)) ||
|
||||
serialConfigInProgress)
|
||||
{
|
||||
if (++gPttDebounceCounter >= 3 || (serialConfigInProgress && gPttOnePushCounter > 0))
|
||||
{
|
||||
gPttDebounceCounter = 0;
|
||||
gPttIsPressed = true;
|
||||
gPttOnePushCounter = 1;
|
||||
ProcessKey(KEY_PTT, true, false);
|
||||
|
||||
if (gPttOnePushCounter == 0)
|
||||
{ // start transmitting
|
||||
boot_counter_10ms = 0;
|
||||
gPttIsPressed = true;
|
||||
gPttOnePushCounter = 1;
|
||||
ProcessKey(KEY_PTT, true, false);
|
||||
}
|
||||
else if (gPttOnePushCounter == 3 || serialConfigInProgress)
|
||||
{ // stop transmitting
|
||||
StopTransmitting();
|
||||
gPttOnePushCounter = 0;
|
||||
}
|
||||
else
|
||||
gPttOnePushCounter++;
|
||||
}
|
||||
}
|
||||
else if ((!GPIO_IsPttPressed() || SerialConfigInProgress()) && gPttOnePushCounter == 1)
|
||||
{
|
||||
// PTT released or serial comms config in progress
|
||||
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
|
||||
{ // stop transmitting
|
||||
gPttOnePushCounter = 2;
|
||||
}
|
||||
}
|
||||
else if (GPIO_IsPttPressed() && !SerialConfigInProgress() && gPttOnePushCounter == 2)
|
||||
{ // PTT pressed again
|
||||
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
|
||||
{ // stop transmitting
|
||||
gPttOnePushCounter = 3;
|
||||
}
|
||||
}
|
||||
else if ((!GPIO_IsPttPressed() || SerialConfigInProgress()) && gPttOnePushCounter == 3)
|
||||
{ // PTT released or serial comms config in progress
|
||||
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
|
||||
{ // stop transmitting
|
||||
ProcessKey(KEY_PTT, false, false);
|
||||
gPttIsPressed = false;
|
||||
if (gKeyReading1 != KEY_INVALID)
|
||||
gPttWasReleased = true;
|
||||
gPttOnePushCounter = 0;
|
||||
#if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV)
|
||||
ST7565_ContrastAndInv();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
gPttDebounceCounter = 0;
|
||||
|
||||
//gDebug = gPttOnePushCounter;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (gPttIsPressed)
|
||||
{
|
||||
if (!GPIO_IsPttPressed() || SerialConfigInProgress())
|
||||
if (!isPressed)
|
||||
{ // PTT released or serial comms config in progress
|
||||
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
|
||||
if (++gPttDebounceCounter >= 3 || serialConfigInProgress) // 30ms
|
||||
{ // stop transmitting
|
||||
ProcessKey(KEY_PTT, false, false);
|
||||
gPttIsPressed = false;
|
||||
if (gKeyReading1 != KEY_INVALID)
|
||||
gPttWasReleased = true;
|
||||
#if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV)
|
||||
ST7565_ContrastAndInv();
|
||||
#endif
|
||||
gPttDebounceCounter = 0;
|
||||
StopTransmitting();
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
gPttDebounceCounter = 0;
|
||||
}
|
||||
else if (GPIO_IsPttPressed() && !SerialConfigInProgress())
|
||||
else if (isPressed)
|
||||
{ // PTT pressed
|
||||
if (++gPttDebounceCounter >= 3) // 30ms
|
||||
{ // start transmitting
|
||||
@@ -1243,38 +1260,9 @@ static void CheckKeys(void)
|
||||
ProcessKey(KEY_PTT, true, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
gPttDebounceCounter = 0;
|
||||
}
|
||||
#else
|
||||
if (gPttIsPressed)
|
||||
{
|
||||
if (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) || SerialConfigInProgress())
|
||||
{ // PTT released or serial comms config in progress
|
||||
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
|
||||
{ // stop transmitting
|
||||
ProcessKey(KEY_PTT, false, false);
|
||||
gPttIsPressed = false;
|
||||
if (gKeyReading1 != KEY_INVALID)
|
||||
gPttWasReleased = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
gPttDebounceCounter = 0;
|
||||
}
|
||||
else if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && !SerialConfigInProgress())
|
||||
{ // PTT pressed
|
||||
if (++gPttDebounceCounter >= 3) // 30ms
|
||||
{ // start transmitting
|
||||
boot_counter_10ms = 0;
|
||||
gPttDebounceCounter = 0;
|
||||
gPttIsPressed = true;
|
||||
ProcessKey(KEY_PTT, true, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
gPttDebounceCounter = 0;
|
||||
#endif
|
||||
|
||||
// --------------------- OTHER KEYS ----------------------------
|
||||
|
||||
@@ -1348,9 +1336,9 @@ void APP_TimeSlice10ms(void)
|
||||
{
|
||||
gNextTimeslice = false;
|
||||
|
||||
if (gScheduleVfoSave) {
|
||||
SETTINGS_SaveVfoIndicesFlush();
|
||||
}
|
||||
SETTINGS_SaveVfoIndicesFlush();
|
||||
|
||||
BACKLIGHT_Update();
|
||||
|
||||
gFlashLightBlinkCounter++;
|
||||
|
||||
@@ -1376,12 +1364,18 @@ void APP_TimeSlice10ms(void)
|
||||
|
||||
if (gCurrentFunction == FUNCTION_TRANSMIT)
|
||||
{ // transmitting
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
#if defined(ENABLE_AUDIO_BAR) && !defined(ENABLE_FEAT_F4HWN_AUDIO_SCOPE)
|
||||
if (gSetting_mic_bar && (gFlashLightBlinkCounter % (150 / 10)) == 0) // once every 150ms
|
||||
UI_DisplayAudioBar();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO_SCOPE
|
||||
if (gSetting_mic_bar && (gFlashLightBlinkCounter % (20 / 10)) == 0) // once every 20ms
|
||||
// Sample audio amplitude and refresh display during TX only (FM RX has no usable audio register)
|
||||
UI_DisplayAudioScope();
|
||||
#endif
|
||||
|
||||
bool gUpdateDisplayCurrent = gUpdateDisplay;
|
||||
bool gUpdateStatusCurrent = gUpdateStatus;
|
||||
|
||||
@@ -1396,7 +1390,7 @@ void APP_TimeSlice10ms(void)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
if (gUpdateDisplayCurrent || gUpdateStatusCurrent) {
|
||||
getScreenShot(false);
|
||||
SCREENSHOT_Update(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1509,17 +1503,16 @@ void cancelUserInputModes(void)
|
||||
if (gDTMF_InputMode || gDTMF_InputBox_Index > 0)
|
||||
{
|
||||
DTMF_clear_input_box();
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
gUpdateDisplay = true;
|
||||
}
|
||||
|
||||
if (gWasFKeyPressed || gKeyInputCountdown > 0 || gInputBoxIndex > 0)
|
||||
{
|
||||
gWasFKeyPressed = false;
|
||||
HideFKeyIcon();
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 0;
|
||||
gUpdateStatus = true;
|
||||
gUpdateDisplay = true;
|
||||
}
|
||||
}
|
||||
@@ -1541,7 +1534,7 @@ void APP_TimeSlice500ms(void)
|
||||
if (--gKeyInputCountdown == 0)
|
||||
{
|
||||
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE) && (gInputBoxIndex > 0 && gInputBoxIndex < 4))
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE) && (gInputBoxIndex > 0 && gInputBoxIndex < 4) && (!gFmRadioMode))
|
||||
{
|
||||
channelMoveSwitch();
|
||||
|
||||
@@ -1551,6 +1544,7 @@ void APP_TimeSlice500ms(void)
|
||||
}
|
||||
|
||||
cancelUserInputModes();
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1593,9 +1587,11 @@ void APP_TimeSlice500ms(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (gBacklightCountdown_500ms > 0 && !gAskToSave && !gCssBackgroundScan
|
||||
// don't turn off backlight if user is in backlight menu option
|
||||
&& !(gScreenToDisplay == DISPLAY_MENU && (UI_MENU_GetCurrentMenuId() == MENU_ABR || UI_MENU_GetCurrentMenuId() == MENU_ABR_MAX))
|
||||
&& !(gScreenToDisplay == DISPLAY_MENU && (m == MENU_ABR || m == MENU_ABR_MAX || m == MENU_ABR_MIN))
|
||||
&& --gBacklightCountdown_500ms == 0
|
||||
&& gEeprom.BACKLIGHT_TIME < 61
|
||||
) {
|
||||
@@ -1713,8 +1709,10 @@ void APP_TimeSlice500ms(void)
|
||||
if (exit_menu) {
|
||||
gMenuCountdown = 0;
|
||||
|
||||
if (gEeprom.BACKLIGHT_TIME == 0) {
|
||||
BACKLIGHT_TurnOff();
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (gScreenToDisplay == DISPLAY_MENU && (m == MENU_ABR || m == MENU_ABR_MAX || m == MENU_ABR_MIN)) {
|
||||
BACKLIGHT_TurnOn();
|
||||
}
|
||||
|
||||
if (gInputBoxIndex > 0 || gDTMF_InputMode) {
|
||||
@@ -1732,13 +1730,12 @@ void APP_TimeSlice500ms(void)
|
||||
*/
|
||||
DTMF_clear_input_box();
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
HideFKeyIcon();
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
gAskToSave = false;
|
||||
gAskToDelete = false;
|
||||
|
||||
gUpdateStatus = true;
|
||||
gUpdateDisplay = true;
|
||||
|
||||
GUI_DisplayType_t disp = DISPLAY_INVALID;
|
||||
@@ -1917,7 +1914,7 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
// cancel user input
|
||||
cancelUserInputModes();
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
if (gMonitor)
|
||||
ACTION_Monitor(); //turn off the monitor
|
||||
@@ -2030,8 +2027,7 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
if (gWasFKeyPressed && (Key == KEY_PTT || Key == KEY_EXIT || Key == KEY_SIDE1 || Key == KEY_SIDE2)) {
|
||||
#endif
|
||||
// cancel the F-key
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
HideFKeyIcon();
|
||||
}
|
||||
|
||||
if (bFlag) {
|
||||
@@ -2148,6 +2144,7 @@ Skip:
|
||||
else
|
||||
flagSaveSettings = 1;
|
||||
gRequestSaveSettings = false;
|
||||
gRequestSaveSquelch = false;
|
||||
gUpdateStatus = true;
|
||||
}
|
||||
|
||||
|
||||
+33
-40
@@ -401,46 +401,35 @@ static void OnKeyDown(uint8_t key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Key
|
||||
static KEY_Code_t GetKey()
|
||||
{
|
||||
KEY_Code_t btn = KEYBOARD_Poll();
|
||||
if (btn == KEY_INVALID && GPIO_IsPttPressed())
|
||||
{
|
||||
btn = KEY_PTT;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
// HandleUserInput
|
||||
static bool HandleUserInput()
|
||||
{
|
||||
// Store previous key state
|
||||
kbd.prev = kbd.current;
|
||||
|
||||
// Get the current key
|
||||
kbd.current = GetKey();
|
||||
|
||||
// Detect valid key press continuation (same key still pressed)
|
||||
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev)
|
||||
{
|
||||
kbd.counter = 1;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Parse incoming packets on every tick so serial keys are never missed,
|
||||
// regardless of whether the screen needs redrawing.
|
||||
SCREENSHOT_ParseInput();
|
||||
#endif
|
||||
|
||||
OnKeyDown(kbd.current);
|
||||
|
||||
// Special handling for MENU key
|
||||
if(kbd.current == KEY_MENU)
|
||||
{
|
||||
kbd.counter = 0;
|
||||
SYSTEM_DelayMs(250);
|
||||
}
|
||||
}
|
||||
else
|
||||
kbd.prev = kbd.current;
|
||||
kbd.current = KEYBOARD_GetKey();
|
||||
|
||||
if (kbd.current == KEY_INVALID)
|
||||
return true;
|
||||
|
||||
// Movement keys: dispatch on every tick while held
|
||||
if (kbd.current == KEY_UP || kbd.current == KEY_DOWN ||
|
||||
kbd.current == KEY_4 || kbd.current == KEY_0)
|
||||
{
|
||||
kbd.counter = 0;
|
||||
OnKeyDown(kbd.current);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Action keys (MENU, EXIT): dispatch only on rising edge
|
||||
if (kbd.current != kbd.prev)
|
||||
{
|
||||
OnKeyDown(kbd.current);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -448,7 +437,6 @@ static bool HandleUserInput()
|
||||
static void Tick()
|
||||
{
|
||||
HandleUserInput();
|
||||
HandleUserInput();
|
||||
}
|
||||
|
||||
// APP_RunBreakout
|
||||
@@ -461,6 +449,9 @@ void APP_RunBreakout(void) {
|
||||
// Init led
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
|
||||
|
||||
// Finish the brightness fade if it is in progress
|
||||
BACKLIGHT_UpdateTickless();
|
||||
|
||||
// Init game
|
||||
UI_DisplayClear();
|
||||
reset();
|
||||
@@ -478,11 +469,6 @@ void APP_RunBreakout(void) {
|
||||
if(swap == 0)
|
||||
{
|
||||
blockAnim = (blockAnim + 1) % 4;
|
||||
|
||||
// For screenshot
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
swap = (swap + 1) % 4;
|
||||
@@ -505,5 +491,12 @@ void APP_RunBreakout(void) {
|
||||
|
||||
ST7565_BlitStatusLine(); // Blank status line
|
||||
ST7565_BlitFullScreen();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
if(isPaused || swap == 0)
|
||||
{
|
||||
SCREENSHOT_Update(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,15 @@ uint8_t initialCROSS_BAND_RX_TX;
|
||||
static void NextFreqChannel(void);
|
||||
static void NextMemChannel(void);
|
||||
|
||||
#if defined(ENABLE_FEAT_F4HWN_RESUME_STATE) || defined(ENABLE_SCAN_RANGES)
|
||||
void CHFRSCANNER_ScanRange(void) {
|
||||
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
|
||||
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
|
||||
if(gScanRangeStart > gScanRangeStop)
|
||||
SWAP(gScanRangeStart, gScanRangeStop);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_direction)
|
||||
{
|
||||
if (storeBackupSettings) {
|
||||
|
||||
@@ -20,6 +20,10 @@ void CHFRSCANNER_Stop(void);
|
||||
void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_direction);
|
||||
void CHFRSCANNER_ContinueScanning(void);
|
||||
|
||||
#if defined(ENABLE_FEAT_F4HWN_RESUME_STATE) || defined(ENABLE_SCAN_RANGES)
|
||||
void CHFRSCANNER_ScanRange(void);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
extern uint32_t lastFoundFrqOrChan;
|
||||
extern uint32_t lastFoundFrqOrChanOld;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "functions.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "ui/inputbox.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
void COMMON_KeypadLockToggle()
|
||||
@@ -29,6 +30,11 @@ void COMMON_SwitchVFOs()
|
||||
#endif
|
||||
gEeprom.TX_VFO ^= 1;
|
||||
|
||||
if (gInputBoxIndex > 0) {
|
||||
gInputBoxIndex = 0;
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
|
||||
if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF)
|
||||
gEeprom.CROSS_BAND_RX_TX = gEeprom.TX_VFO + 1;
|
||||
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
|
||||
@@ -49,6 +55,11 @@ void COMMON_SwitchVFOMode()
|
||||
if (gEeprom.VFO_OPEN)
|
||||
#endif
|
||||
{
|
||||
if (gInputBoxIndex > 0) {
|
||||
gInputBoxIndex = 0;
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
|
||||
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
|
||||
{ // swap to frequency mode
|
||||
gEeprom.ScreenChannel[gEeprom.TX_VFO] = gEeprom.FreqChannel[gEeprom.TX_VFO];
|
||||
|
||||
+19
-13
@@ -51,20 +51,26 @@ static inline void Flashlight_Toggle(){ GPIO_TogglePin(GPIO_PIN_FLASHLIGHT); }
|
||||
|
||||
void ACTION_FlashLight(void)
|
||||
{
|
||||
switch (gFlashLightState) {
|
||||
case FLASHLIGHT_OFF:
|
||||
gFlashLightState++;
|
||||
Flashlight_TurnOn();
|
||||
break;
|
||||
case FLASHLIGHT_ON:
|
||||
case FLASHLIGHT_BLINK:
|
||||
gFlashLightState++;
|
||||
break;
|
||||
case FLASHLIGHT_SOS:
|
||||
default:
|
||||
gFlashLightState = 0;
|
||||
Flashlight_TurnOff();
|
||||
// switch (gFlashLightState) {
|
||||
// case FLASHLIGHT_OFF:
|
||||
// Flashlight_TurnOn();
|
||||
// break;
|
||||
// case FLASHLIGHT_ON:
|
||||
// case FLASHLIGHT_BLINK:
|
||||
// break;
|
||||
// case FLASHLIGHT_SOS:
|
||||
// default:
|
||||
// Flashlight_TurnOff();
|
||||
// }
|
||||
|
||||
if(gFlashLightState == FLASHLIGHT_OFF) {
|
||||
Flashlight_TurnOn();
|
||||
}
|
||||
else if (gFlashLightState == FLASHLIGHT_SOS) {
|
||||
Flashlight_TurnOff();
|
||||
}
|
||||
|
||||
gFlashLightState = (gFlashLightState + 1) % 4;
|
||||
}
|
||||
#else
|
||||
void ACTION_FlashLight(void)
|
||||
|
||||
+43
-14
@@ -129,6 +129,18 @@ void FM_EraseChannels(void)
|
||||
memset(gFM_Channels, 0xFF, sizeof(gFM_Channels));
|
||||
}
|
||||
|
||||
uint16_t FM_WrapFrequency(uint16_t Frequency) {
|
||||
const uint16_t freqLoLimit = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
|
||||
const uint16_t freqHiLimit = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
|
||||
|
||||
if (Frequency < freqLoLimit)
|
||||
return freqHiLimit;
|
||||
else if (Frequency > freqHiLimit)
|
||||
return freqLoLimit;
|
||||
|
||||
return Frequency;
|
||||
}
|
||||
|
||||
void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag)
|
||||
{
|
||||
AUDIO_AudioPathOff();
|
||||
@@ -145,10 +157,7 @@ void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag)
|
||||
|
||||
if (!bFlag) {
|
||||
Frequency += Step;
|
||||
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
|
||||
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
|
||||
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
|
||||
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
|
||||
Frequency = FM_WrapFrequency(Frequency);
|
||||
|
||||
gEeprom.FM_FrequencyPlaying = Frequency;
|
||||
}
|
||||
@@ -248,6 +257,7 @@ static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
|
||||
}
|
||||
|
||||
INPUTBOX_Append(Key);
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_FM;
|
||||
|
||||
@@ -263,6 +273,8 @@ static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
|
||||
uint32_t Frequency;
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 1;
|
||||
|
||||
Frequency = StrToUL(INPUTBOX_GetAscii());
|
||||
|
||||
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band) || BK1080_GetFreqHiLimit(gEeprom.FM_Band) < Frequency) {
|
||||
@@ -285,6 +297,8 @@ static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
|
||||
uint8_t Channel;
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 1;
|
||||
|
||||
Channel = ((gInputBox[0] * 10) + gInputBox[1]) - 1;
|
||||
|
||||
if (State == STATE_MR_MODE) {
|
||||
@@ -327,8 +341,7 @@ static void Key_FUNC(KEY_Code_t Key, uint8_t state)
|
||||
bool autoScan = gWasFKeyPressed || (state == BUTTON_EVENT_HELD);
|
||||
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
HideFKeyIcon();
|
||||
gRequestDisplayScreen = DISPLAY_FM;
|
||||
|
||||
switch (Key) {
|
||||
@@ -395,6 +408,7 @@ static void Key_EXIT(uint8_t state)
|
||||
}
|
||||
else {
|
||||
gInputBox[--gInputBoxIndex] = 10;
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
|
||||
if (gInputBoxIndex) {
|
||||
if (gInputBoxIndex != 1) {
|
||||
@@ -426,14 +440,25 @@ static void Key_EXIT(uint8_t state)
|
||||
|
||||
static void Key_MENU(uint8_t state)
|
||||
{
|
||||
if (state != BUTTON_EVENT_SHORT)
|
||||
if (state == BUTTON_EVENT_HELD) {
|
||||
ACTION_Handle(KEY_MENU, true, true);
|
||||
return;
|
||||
|
||||
}
|
||||
else if (state != BUTTON_EVENT_SHORT) {
|
||||
return;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_FM;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
HideFKeyIcon();
|
||||
|
||||
if (gFM_ScanState == FM_SCAN_OFF) {
|
||||
if (gInputBoxIndex) {
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gEeprom.FM_IsMrMode) {
|
||||
if (gAskToSave) {
|
||||
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
|
||||
@@ -470,6 +495,8 @@ static void Key_MENU(uint8_t state)
|
||||
|
||||
static void Key_UP_DOWN(uint8_t state, int8_t Step)
|
||||
{
|
||||
HideFKeyIcon();
|
||||
|
||||
if (state == BUTTON_EVENT_PRESSED) {
|
||||
if (gInputBoxIndex) {
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
@@ -513,10 +540,7 @@ static void Key_UP_DOWN(uint8_t state, int8_t Step)
|
||||
else {
|
||||
uint16_t Frequency = gEeprom.FM_SelectedFrequency + Step;
|
||||
|
||||
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
|
||||
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
|
||||
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
|
||||
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
|
||||
Frequency = FM_WrapFrequency(Frequency);
|
||||
|
||||
gEeprom.FM_FrequencyPlaying = Frequency;
|
||||
gEeprom.FM_SelectedFrequency = gEeprom.FM_FrequencyPlaying;
|
||||
@@ -557,9 +581,14 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
case KEY_PTT:
|
||||
GENERIC_Key_PTT(bKeyPressed);
|
||||
break;
|
||||
default:
|
||||
if (!bKeyHeld && bKeyPressed)
|
||||
case KEY_SIDE1:
|
||||
case KEY_SIDE2:
|
||||
if (state != BUTTON_EVENT_PRESSED) {
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
HideFKeyIcon();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+79
-109
@@ -51,7 +51,26 @@
|
||||
static VFO_Info_t gVfoBackup;
|
||||
static uint16_t gScreenChannelBackup = 0;
|
||||
static uint16_t gFreqChannelBackup = 0;
|
||||
static bool gHasVfoBackup = false;
|
||||
|
||||
static void VFO_RestoreBackup(void) {
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
||||
static void toggle_chan_scanlist(void)
|
||||
{ // toggle the selected channels scanlist setting
|
||||
@@ -61,10 +80,7 @@ static void toggle_chan_scanlist(void)
|
||||
|
||||
if(!IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
|
||||
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
|
||||
if(gScanRangeStart > gScanRangeStop)
|
||||
SWAP(gScanRangeStart, gScanRangeStop);
|
||||
CHFRSCANNER_ScanRange();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@@ -99,16 +115,14 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
{
|
||||
uint8_t Vfo = gEeprom.TX_VFO;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
if(Key == 2) { // Enable A/B only
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
COMMON_SwitchVFOs();
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
return; // prevent F function if MENU LOCK is true
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true && Key != 2) {
|
||||
HideFKeyIcon();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -126,9 +140,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
|
||||
case KEY_1:
|
||||
if (!IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
HideFKeyIcon();
|
||||
|
||||
#ifdef ENABLE_COPY_CHAN_TO_VFO
|
||||
if (!gEeprom.VFO_OPEN || gCssBackgroundScan) {
|
||||
@@ -192,9 +204,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
break;
|
||||
|
||||
case KEY_2:
|
||||
@@ -202,8 +211,6 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
#endif
|
||||
COMMON_SwitchVFOs();
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
break;
|
||||
|
||||
case KEY_3:
|
||||
@@ -211,19 +218,14 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
#endif
|
||||
COMMON_SwitchVFOMode();
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
|
||||
break;
|
||||
|
||||
case KEY_4:
|
||||
gWasFKeyPressed = false;
|
||||
HideFKeyIcon();
|
||||
|
||||
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
|
||||
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
|
||||
gUpdateStatus = true;
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
|
||||
|
||||
SCANNER_Start(false);
|
||||
gRequestDisplayScreen = DISPLAY_SCANNER;
|
||||
@@ -308,8 +310,9 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case KEY_SIDE1:
|
||||
case KEY_SIDE2:
|
||||
{
|
||||
@@ -327,13 +330,13 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
gUpdateStatus = true;
|
||||
gWasFKeyPressed = false;
|
||||
HideFKeyIcon();
|
||||
|
||||
if (beep)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
@@ -423,8 +426,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
HideFKeyIcon();
|
||||
|
||||
processFKeyFunction(Key, true);
|
||||
}
|
||||
@@ -550,7 +552,13 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
return;
|
||||
}
|
||||
|
||||
gKeyInputCountdown = (gInputBoxIndex == totalDigits) ? (key_input_timeout_500ms / 16) : (key_input_timeout_500ms / 3);
|
||||
gKeyInputCountdown = (gInputBoxIndex >= totalDigits) ? (key_input_timeout_500ms / 16) : (key_input_timeout_500ms / 3);
|
||||
|
||||
if (gInputBoxIndex > totalDigits) {
|
||||
gInputBoxIndex = totalDigits;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char *inputStr = INPUTBOX_GetAscii();
|
||||
uint8_t inputLength = gInputBoxIndex;
|
||||
@@ -619,6 +627,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
}
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
gHasVfoBackup = false;
|
||||
|
||||
uint8_t Channel = (gInputBox[0] * 10) + gInputBox[1];
|
||||
if (Channel >= 1 && Channel <= ARRAY_SIZE(NoaaFrequencyTable)) {
|
||||
@@ -640,8 +649,13 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
return;
|
||||
}
|
||||
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
HideFKeyIcon();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true && Key != 2) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(Key == 8)
|
||||
{
|
||||
@@ -656,11 +670,6 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
#ifdef ENABLE_FEAT_F4HWN_GAME
|
||||
else if(Key == 7)
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
APP_RunBreakout();
|
||||
return;
|
||||
}
|
||||
@@ -678,35 +687,10 @@ static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
if (bKeyHeld) { // exit key held down
|
||||
if (bKeyPressed) {
|
||||
if (gInputBoxIndex > 0 || gDTMF_InputBox_Index > 0 || gDTMF_InputMode)
|
||||
{ // cancel key input mode (channel/frequency entry)
|
||||
// Restore full VFO state on long press EXIT
|
||||
VFO_RestoreBackup();
|
||||
|
||||
// Restore full VFO state on long press EXIT
|
||||
if (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;
|
||||
}
|
||||
|
||||
gDTMF_InputMode = false;
|
||||
gDTMF_InputBox_Index = 0;
|
||||
memset(gDTMF_String, 0, sizeof(gDTMF_String));
|
||||
gInputBoxIndex = 0;
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
}
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -731,23 +715,8 @@ static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
|
||||
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;
|
||||
}
|
||||
if (gInputBoxIndex == 0)
|
||||
VFO_RestoreBackup();
|
||||
|
||||
gKeyInputCountdown = key_input_timeout_500ms;
|
||||
channelMoveSwitch();
|
||||
@@ -839,7 +808,11 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == false) {
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
HideFKeyIcon();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
gFlagRefreshSetting = true;
|
||||
@@ -847,10 +820,6 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = VOICE_ID_MENU;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
gRequestDisplayScreen = DISPLAY_MAIN;
|
||||
@@ -860,13 +829,6 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
return; // prevent F function if MENU LOCK is true
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gCurrentFunction == FUNCTION_TRANSMIT)
|
||||
return;
|
||||
|
||||
@@ -876,6 +838,19 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bKeyHeld && bKeyPressed) { // star key pressed
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; // beep when key is pressed
|
||||
return; // don't use the key till it's released
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
HideFKeyIcon();
|
||||
|
||||
return; // prevent F function if MENU LOCK is true
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bKeyHeld && !gWasFKeyPressed){ // long press
|
||||
if (!bKeyPressed) // released
|
||||
return;
|
||||
@@ -898,12 +873,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bKeyPressed) { // just pressed
|
||||
return;
|
||||
}
|
||||
|
||||
// just released
|
||||
|
||||
if (!gWasFKeyPressed) // pressed without the F-key
|
||||
{
|
||||
@@ -916,7 +885,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
|
||||
#endif
|
||||
)
|
||||
{ // start entering a DTMF string
|
||||
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
|
||||
memcpy(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
|
||||
gDTMF_InputBox_Index = 0;
|
||||
gDTMF_InputMode = true;
|
||||
@@ -958,7 +926,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN // Set Squelch F + UP or Down
|
||||
if(gWasFKeyPressed) {
|
||||
processFKeyFunction(Direction == 1 ? KEY_UP : KEY_DOWN, false);
|
||||
processFKeyFunction(Direction == 1 ? KEY_UP : KEY_DOWN, true);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -971,8 +939,10 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
uint16_t Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO];
|
||||
|
||||
if (bKeyHeld || !bKeyPressed) { // key held or released
|
||||
if (gInputBoxIndex > 0)
|
||||
if (gInputBoxIndex > 0) {
|
||||
gInputBoxIndex = 0;
|
||||
gHasVfoBackup = false;
|
||||
}
|
||||
|
||||
if (!bKeyPressed) {
|
||||
if (!bKeyHeld || IS_FREQ_CHANNEL(Channel))
|
||||
|
||||
+51
-35
@@ -480,6 +480,7 @@ void MENU_AcceptSetting(void)
|
||||
case MENU_SQL:
|
||||
gEeprom.SQUELCH_LEVEL = gSubMenuSelection;
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gRequestSaveSquelch = true;
|
||||
break;
|
||||
|
||||
case MENU_STEP:
|
||||
@@ -1547,12 +1548,14 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
return;
|
||||
}
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_1_CALL ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (m == MENU_MEM_CH ||
|
||||
m == MENU_DEL_CH ||
|
||||
m == MENU_1_CALL ||
|
||||
m == MENU_S_PRI_CH_1 ||
|
||||
m == MENU_S_PRI_CH_2 ||
|
||||
m == MENU_MEM_NAME)
|
||||
{ // enter 4-digit channel number
|
||||
|
||||
if (gInputBoxIndex < 4)
|
||||
@@ -1692,19 +1695,21 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
|
||||
|
||||
if (!gIsInSubMenu)
|
||||
{
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
if (UI_MENU_GetCurrentMenuId() != MENU_SCR)
|
||||
if (m != MENU_SCR)
|
||||
gAnotherVoiceID = MenuList[gMenuCursor].voice_id;
|
||||
#endif
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_UPCODE
|
||||
|| UI_MENU_GetCurrentMenuId() == MENU_DWCODE
|
||||
if (m == MENU_UPCODE
|
||||
|| m == MENU_DWCODE
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
|| UI_MENU_GetCurrentMenuId() == MENU_ANI_ID
|
||||
|| m == MENU_ANI_ID
|
||||
#endif
|
||||
)
|
||||
return;
|
||||
#if 1
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_DEL_CH || UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
|
||||
if (m == MENU_DEL_CH || m == MENU_MEM_NAME)
|
||||
if (!RADIO_CheckValidChannel(gSubMenuSelection, false, 0))
|
||||
return; // invalid channel
|
||||
#endif
|
||||
@@ -1712,7 +1717,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
|
||||
gAskForConfirmation = 0;
|
||||
gIsInSubMenu = true;
|
||||
|
||||
// if (UI_MENU_GetCurrentMenuId() != MENU_D_LIST)
|
||||
// if (m != MENU_D_LIST)
|
||||
{
|
||||
gInputBoxIndex = 0;
|
||||
edit_index = -1;
|
||||
@@ -1763,10 +1768,12 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
|
||||
|
||||
if (gIsInSubMenu)
|
||||
{
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_RESET ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (m == MENU_RESET ||
|
||||
m == MENU_MEM_CH ||
|
||||
m == MENU_DEL_CH ||
|
||||
m == MENU_MEM_NAME)
|
||||
{
|
||||
switch (gAskForConfirmation)
|
||||
{
|
||||
@@ -1779,7 +1786,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
|
||||
|
||||
UI_DisplayMenu();
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_RESET)
|
||||
if (m == MENU_RESET)
|
||||
{
|
||||
#ifdef ENABLE_VOICE
|
||||
AUDIO_SetVoiceID(0, VOICE_ID_CONFIRM);
|
||||
@@ -1853,7 +1860,8 @@ static void MENU_Key_STAR(const bool bKeyPressed, const bool bKeyHeld)
|
||||
if (gRxVfo->Modulation == MODULATION_FM)
|
||||
#endif
|
||||
{
|
||||
if ((UI_MENU_GetCurrentMenuId() == MENU_R_CTCS || UI_MENU_GetCurrentMenuId() == MENU_R_DCS) && gIsInSubMenu)
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
if ((m == MENU_R_CTCS || m == MENU_R_DCS) && gIsInSubMenu)
|
||||
{ // scan CTCSS or DCS to find the tone/code of the incoming signal
|
||||
if (!SCANNER_IsScanning())
|
||||
MENU_StartCssScan();
|
||||
@@ -1925,9 +1933,11 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MENU;
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() != MENU_ABR
|
||||
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MIN
|
||||
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MAX
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (m != MENU_ABR
|
||||
&& m != MENU_ABR_MIN
|
||||
&& m != MENU_ABR_MAX
|
||||
&& gEeprom.BACKLIGHT_TIME == 0) // backlight always off and not in the backlight menu
|
||||
{
|
||||
BACKLIGHT_TurnOff();
|
||||
@@ -1953,8 +1963,10 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
}
|
||||
|
||||
VFO = 0;
|
||||
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
switch (UI_MENU_GetCurrentMenuId())
|
||||
switch (m)
|
||||
{
|
||||
case MENU_DEL_CH:
|
||||
case MENU_1_CALL:
|
||||
@@ -1970,19 +1982,21 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
return;
|
||||
}
|
||||
|
||||
if(UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 || UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2)
|
||||
if(m == MENU_S_PRI_CH_1 || m == MENU_S_PRI_CH_2)
|
||||
{
|
||||
static int16_t last;
|
||||
|
||||
if(Direction > 0 && gSubMenuSelection == MR_CHANNELS_MAX)
|
||||
{
|
||||
gSubMenuSelection = -1;
|
||||
last = -1;
|
||||
}
|
||||
else if(Direction < 0 && gSubMenuSelection == MR_CHANNELS_MAX)
|
||||
{
|
||||
gSubMenuSelection = MR_CHANNELS_MAX;
|
||||
last = MR_CHANNELS_MAX;
|
||||
if(gSubMenuSelection == MR_CHANNELS_MAX) {
|
||||
if(Direction > 0)
|
||||
{
|
||||
gSubMenuSelection = -1;
|
||||
last = -1;
|
||||
}
|
||||
else if(Direction < 0)
|
||||
{
|
||||
gSubMenuSelection = MR_CHANNELS_MAX;
|
||||
last = MR_CHANNELS_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
|
||||
@@ -2067,11 +2081,13 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
|
||||
if (gScreenToDisplay == DISPLAY_MENU)
|
||||
{
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_VOL ||
|
||||
const int m = UI_MENU_GetCurrentMenuId();
|
||||
|
||||
if (m == MENU_VOL ||
|
||||
#ifdef ENABLE_F_CAL_MENU
|
||||
UI_MENU_GetCurrentMenuId() == MENU_F_CALI ||
|
||||
m == MENU_F_CALI ||
|
||||
#endif
|
||||
UI_MENU_GetCurrentMenuId() == MENU_BATCAL)
|
||||
m == MENU_BATCAL)
|
||||
{
|
||||
gMenuCountdown = menu_timeout_long_500ms;
|
||||
}
|
||||
|
||||
+19
-16
@@ -270,16 +270,6 @@ static void GUI_DisplaySmallest(const char *pString, uint8_t x, uint8_t y,
|
||||
|
||||
// Utility functions
|
||||
|
||||
static KEY_Code_t GetKey()
|
||||
{
|
||||
KEY_Code_t btn = KEYBOARD_Poll();
|
||||
if (btn == KEY_INVALID && GPIO_IsPttPressed())
|
||||
{
|
||||
btn = KEY_PTT;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
static int clamp(int v, int min, int max)
|
||||
{
|
||||
return v <= min ? min : (v >= max ? max : v);
|
||||
@@ -787,11 +777,13 @@ static void ToggleBacklight()
|
||||
settings.backlightState = !settings.backlightState;
|
||||
if (settings.backlightState)
|
||||
{
|
||||
BACKLIGHT_TurnOn();
|
||||
// BACKLIGHT_TurnOn();
|
||||
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
BACKLIGHT_TurnOff();
|
||||
// BACKLIGHT_TurnOff();
|
||||
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1515,7 +1507,7 @@ static void Render()
|
||||
static bool HandleUserInput()
|
||||
{
|
||||
kbd.prev = kbd.current;
|
||||
kbd.current = GetKey();
|
||||
kbd.current = KEYBOARD_GetKey();
|
||||
|
||||
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev)
|
||||
{
|
||||
@@ -1665,16 +1657,23 @@ static void UpdateListening()
|
||||
|
||||
static void Tick()
|
||||
{
|
||||
#ifdef ENABLE_AM_FIX
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
// Parse incoming packets on every tick so serial keys are never missed,
|
||||
// regardless of whether the screen needs redrawing.
|
||||
SCREENSHOT_ParseInput();
|
||||
#endif
|
||||
|
||||
if (gNextTimeslice)
|
||||
{
|
||||
gNextTimeslice = false;
|
||||
#ifdef ENABLE_AM_FIX
|
||||
if (settings.modulationType == MODULATION_AM && !lockAGC)
|
||||
{
|
||||
AM_fix_10ms(vfo); // allow AM_Fix to apply its AGC action
|
||||
}
|
||||
}
|
||||
#endif
|
||||
BACKLIGHT_Update();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
if (gNextTimeslice_500ms)
|
||||
@@ -1734,7 +1733,7 @@ static void Tick()
|
||||
Render();
|
||||
// For screenshot
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
SCREENSHOT_Update(false);
|
||||
#endif
|
||||
redrawScreen = false;
|
||||
}
|
||||
@@ -1742,6 +1741,8 @@ static void Tick()
|
||||
|
||||
void APP_RunSpectrum()
|
||||
{
|
||||
settings.backlightState = gEeprom.BACKLIGHT_TIME == 0 ? false : true;
|
||||
|
||||
// TX here coz it always? set to active VFO
|
||||
vfo = gEeprom.TX_VFO;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SPECTRUM
|
||||
@@ -1804,4 +1805,6 @@ void APP_RunSpectrum()
|
||||
{
|
||||
Tick();
|
||||
}
|
||||
|
||||
BACKLIGHT_TurnOn();
|
||||
}
|
||||
+10
-7
@@ -53,12 +53,7 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
|
||||
#endif
|
||||
!gEeprom.BEEP_CONTROL)
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_AIRCOPY
|
||||
if (gScreenToDisplay == DISPLAY_AIRCOPY)
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
if (gCurrentFunction == FUNCTION_RECEIVE)
|
||||
return;
|
||||
|
||||
@@ -182,11 +177,19 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
|
||||
SYSTEM_DelayMs(5);
|
||||
BK4819_WriteRegister(BK4819_REG_71, ToneConfig);
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
const bool isFmRadio = gFmRadioMode;
|
||||
|
||||
if (isFmRadio)
|
||||
SYSTEM_DelayMs(10);
|
||||
#endif
|
||||
|
||||
|
||||
if (gEnableSpeaker)
|
||||
AUDIO_AudioPathOn();
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
if (gFmRadioMode)
|
||||
if (isFmRadio)
|
||||
BK1080_Mute(false);
|
||||
#endif
|
||||
|
||||
|
||||
+67
-32
@@ -31,7 +31,7 @@
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
#define PWM_FREQ 320
|
||||
#define PWM_FREQ 4000
|
||||
#define DUTY_CYCLE_LEVELS 64
|
||||
|
||||
#define DUTY_CYCLE_ON_VALUE GPIO_PIN_MASK(GPIO_PIN_BACKLIGHT)
|
||||
@@ -44,8 +44,14 @@ static uint32_t dutyCycle[DUTY_CYCLE_LEVELS];
|
||||
|
||||
// this is decremented once every 500ms
|
||||
uint16_t gBacklightCountdown_500ms = 0;
|
||||
bool gUpdateBacklight = false;
|
||||
bool backlightOn;
|
||||
|
||||
static uint8_t currentIndex = 0;
|
||||
static int16_t currentBrightness = 0;
|
||||
static int16_t targetBrightness = 0;
|
||||
static int16_t fadeStep = 0;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
const uint8_t value[] = {
|
||||
0, // 0 off
|
||||
@@ -110,6 +116,12 @@ static void BACKLIGHT_Sound(void)
|
||||
gK5startup = false;
|
||||
}
|
||||
|
||||
void BACKLIGHT_UpdateTickless(void) {
|
||||
while(gUpdateBacklight) {
|
||||
BACKLIGHT_Update();
|
||||
SYSTEM_DelayMs(10);
|
||||
}
|
||||
}
|
||||
|
||||
void BACKLIGHT_TurnOn(void)
|
||||
{
|
||||
@@ -134,27 +146,23 @@ void BACKLIGHT_TurnOn(void)
|
||||
|
||||
backlightOn = true;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if(gK5startup == true) {
|
||||
#if defined(ENABLE_FMRADIO) && defined(ENABLE_SPECTRUM)
|
||||
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
|
||||
#else
|
||||
for(uint8_t i = 0; i <= gEeprom.BACKLIGHT_MAX; i++)
|
||||
{
|
||||
BACKLIGHT_SetBrightness(i);
|
||||
SYSTEM_DelayMs(50);
|
||||
}
|
||||
#endif
|
||||
|
||||
BACKLIGHT_Sound();
|
||||
}
|
||||
else
|
||||
{
|
||||
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
|
||||
}
|
||||
#else
|
||||
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if(gK5startup == true)
|
||||
#else
|
||||
static bool startup = true;
|
||||
|
||||
if(startup)
|
||||
#endif
|
||||
{
|
||||
BACKLIGHT_UpdateTickless();
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
BACKLIGHT_Sound();
|
||||
#else
|
||||
startup = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (gEeprom.BACKLIGHT_TIME) {
|
||||
default:
|
||||
@@ -190,18 +198,11 @@ bool BACKLIGHT_IsOn()
|
||||
return backlightOn;
|
||||
}
|
||||
|
||||
static uint8_t currentBrightness = 0;
|
||||
|
||||
void BACKLIGHT_SetBrightness(uint8_t brigtness)
|
||||
static void BACKLIGHT_SetHardwareBrightness(uint8_t brightness)
|
||||
{
|
||||
// printf("BL: %d\n", brigtness);
|
||||
|
||||
if (currentBrightness == brigtness)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == brigtness)
|
||||
if (0 == brightness)
|
||||
{
|
||||
LL_TIM_DisableCounter(TIMx);
|
||||
LL_DMA_DisableChannel(DMA1, DMA_CHANNEL);
|
||||
@@ -210,7 +211,7 @@ void BACKLIGHT_SetBrightness(uint8_t brigtness)
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32_t level = (uint32_t)(value[brigtness]) * DUTY_CYCLE_LEVELS / 255;
|
||||
const uint32_t level = (uint32_t)(brightness) * DUTY_CYCLE_LEVELS / 255;
|
||||
if (level >= DUTY_CYCLE_LEVELS)
|
||||
{
|
||||
LL_TIM_DisableCounter(TIMx);
|
||||
@@ -231,11 +232,45 @@ void BACKLIGHT_SetBrightness(uint8_t brigtness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentBrightness = brigtness;
|
||||
void BACKLIGHT_Update(void)
|
||||
{
|
||||
if (gUpdateBacklight) {
|
||||
currentBrightness += fadeStep;
|
||||
|
||||
if ((fadeStep > 0 && currentBrightness >= targetBrightness) ||
|
||||
(fadeStep < 0 && currentBrightness <= targetBrightness)) {
|
||||
currentBrightness = targetBrightness;
|
||||
gUpdateBacklight = false;
|
||||
}
|
||||
|
||||
BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness);
|
||||
}
|
||||
}
|
||||
|
||||
void BACKLIGHT_SetBrightness(uint8_t targetIndex)
|
||||
{
|
||||
if (currentIndex == targetIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentIndex = targetIndex;
|
||||
targetBrightness = value[targetIndex];
|
||||
|
||||
int16_t diff = targetBrightness - currentBrightness;
|
||||
|
||||
if (diff == 0) {
|
||||
gUpdateBacklight = false;
|
||||
return;
|
||||
}
|
||||
|
||||
fadeStep = diff > 0 ? -(-diff >> 4) : diff >> 4;
|
||||
|
||||
gUpdateBacklight = true;
|
||||
}
|
||||
|
||||
uint8_t BACKLIGHT_GetBrightness(void)
|
||||
{
|
||||
return currentBrightness;
|
||||
return currentIndex;
|
||||
}
|
||||
@@ -40,10 +40,12 @@ typedef enum {
|
||||
#endif
|
||||
|
||||
void BACKLIGHT_InitHardware();
|
||||
void BACKLIGHT_UpdateTickless(void);
|
||||
void BACKLIGHT_TurnOn();
|
||||
void BACKLIGHT_TurnOff();
|
||||
bool BACKLIGHT_IsOn();
|
||||
void BACKLIGHT_SetBrightness(uint8_t brigtness);
|
||||
void BACKLIGHT_Update(void);
|
||||
uint8_t BACKLIGHT_GetBrightness(void);
|
||||
|
||||
#endif
|
||||
@@ -116,6 +116,10 @@ void BK4819_TurnsOffTones_TurnsOnRX(void);
|
||||
#endif
|
||||
void BK4819_ResetFSK(void);
|
||||
void BK4819_Idle(void);
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
void BK4819_EnterBypass(void);
|
||||
void BK4819_EnterRaw(void);
|
||||
#endif
|
||||
void BK4819_ExitBypass(void);
|
||||
void BK4819_PrepareTransmit(void);
|
||||
void BK4819_TxOn_Beep(void);
|
||||
|
||||
+135
-150
@@ -334,45 +334,9 @@ void BK4819_SetAGC(bool enable)
|
||||
|
||||
void BK4819_InitAGC(bool amModulation)
|
||||
{
|
||||
// REG_10, REG_11, REG_12 REG_13, REG_14
|
||||
//
|
||||
// Rx AGC Gain Table[]. (Index Max->Min is 3,2,1,0,-1)
|
||||
//
|
||||
// <15:10> ???
|
||||
//
|
||||
// <9:8> LNA Gain Short
|
||||
// 3 = 0dB <<< 1o11 read from spectrum reference manual
|
||||
// 2 = -24dB -19 -11
|
||||
// 1 = -30dB -24 -16
|
||||
// 0 = -33dB -28 -19
|
||||
//
|
||||
// <7:5> LNA Gain
|
||||
// 7 = 0dB
|
||||
// 6 = -2dB
|
||||
// 5 = -4dB
|
||||
// 4 = -6dB
|
||||
// 3 = -9dB
|
||||
// 2 = -14dB <<<
|
||||
// 1 = -19dB
|
||||
// 0 = -24dB
|
||||
//
|
||||
// <4:3> MIXER Gain
|
||||
// 3 = 0dB <<<
|
||||
// 2 = -3dB
|
||||
// 1 = -6dB
|
||||
// 0 = -8dB
|
||||
//
|
||||
// <2:0> PGA Gain
|
||||
// 7 = 0dB
|
||||
// 6 = -3dB <<<
|
||||
// 5 = -6dB
|
||||
// 4 = -9dB
|
||||
// 3 = -15dB
|
||||
// 2 = -21dB
|
||||
// 1 = -27dB
|
||||
// 0 = -33dB
|
||||
//
|
||||
|
||||
/*
|
||||
// Old strategy
|
||||
BK4819_WriteRegister(BK4819_REG_13, 0x03BE); // 0x03BE / 000000 11 101 11 110 / -7dB
|
||||
BK4819_WriteRegister(BK4819_REG_12, 0x037B); // 0x037B / 000000 11 011 11 011 / -24dB
|
||||
BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 0x027B / 000000 10 011 11 011 / -43dB
|
||||
@@ -387,7 +351,21 @@ void BK4819_InitAGC(bool amModulation)
|
||||
}
|
||||
|
||||
BK4819_WriteRegister(BK4819_REG_7B, 0x8420);
|
||||
*/
|
||||
|
||||
// New strategy
|
||||
// Keep the runtime AGC profile aligned with the stock BK4829 firmware
|
||||
// until modulation-specific AGC changes are proven on hardware.
|
||||
|
||||
(void)amModulation;
|
||||
|
||||
BK4819_WriteRegister(BK4819_REG_10, 0x0318);
|
||||
BK4819_WriteRegister(BK4819_REG_11, 0x033A);
|
||||
BK4819_WriteRegister(BK4819_REG_12, 0x03DB);
|
||||
BK4819_WriteRegister(BK4819_REG_13, 0x03DF);
|
||||
BK4819_WriteRegister(BK4819_REG_14, 0x0210);
|
||||
BK4819_WriteRegister(BK4819_REG_49, 0x2AB2);
|
||||
BK4819_WriteRegister(BK4819_REG_7B, 0x73DC);
|
||||
}
|
||||
|
||||
int8_t BK4819_GetRxGain_dB(void)
|
||||
@@ -625,100 +603,91 @@ void BK4819_EnableVox(uint16_t VoxEnableThreshold, uint16_t VoxDisableThreshold)
|
||||
|
||||
void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const bool weak_no_different)
|
||||
{
|
||||
// REG_43
|
||||
// <15> 0 ???
|
||||
(void)weak_no_different;
|
||||
|
||||
// REG_43 on BK4829, per BK4829 Registers Table.
|
||||
//
|
||||
// <14:12> 4 RF filter bandwidth
|
||||
// 0 = 1.7 kHz
|
||||
// 1 = 2.0 kHz
|
||||
// 2 = 2.5 kHz
|
||||
// 3 = 3.0 kHz
|
||||
// 4 = 3.75 kHz
|
||||
// 5 = 4.0 kHz
|
||||
// 6 = 4.25 kHz
|
||||
// 7 = 4.5 kHz
|
||||
// if <5> == 1, RF filter bandwidth * 2
|
||||
// <14:12> RF filter bandwidth (Apass = 0.1dB)
|
||||
// 000 = 2.0 kHz
|
||||
// 001 = 2.5 kHz
|
||||
// 010 = 3.0 kHz
|
||||
// 011 = 3.5 kHz
|
||||
// 100 = 4.0 kHz
|
||||
// 101 = 4.5 kHz
|
||||
// 110 = 5.0 kHz
|
||||
// 111 = 5.5 kHz
|
||||
// if REG_43<5> == 1, RF filter bandwidth *= 2
|
||||
//
|
||||
// <11:9> 0 RF filter bandwidth when signal is weak
|
||||
// 0 = 1.7 kHz
|
||||
// 1 = 2.0 kHz
|
||||
// 2 = 2.5 kHz
|
||||
// 3 = 3.0 kHz
|
||||
// 4 = 3.75 kHz
|
||||
// 5 = 4.0 kHz
|
||||
// 6 = 4.25 kHz
|
||||
// 7 = 4.5 kHz
|
||||
// if <5> == 1, RF filter bandwidth * 2
|
||||
// <11:9> RF filter bandwidth when signal is weak (Apass = 0.1dB)
|
||||
// 000 = 2.0 kHz
|
||||
// 001 = 2.5 kHz
|
||||
// 010 = 3.0 kHz
|
||||
// 011 = 3.5 kHz
|
||||
// 100 = 4.0 kHz
|
||||
// 101 = 4.5 kHz
|
||||
// 110 = 5.0 kHz
|
||||
// 111 = 5.5 kHz
|
||||
// if REG_43<5> == 1, RF filter bandwidth *= 2
|
||||
//
|
||||
// <8:6> 1 AFTxLPF2 filter Band Width
|
||||
// 1 = 2.5 kHz (for 12.5k channel space)
|
||||
// 2 = 2.75 kHz
|
||||
// 0 = 3.0 kHz (for 25k channel space)
|
||||
// 3 = 3.5 kHz
|
||||
// 4 = 4.5 kHz
|
||||
// 5 = 4.25 kHz
|
||||
// 6 = 4.0 kHz
|
||||
// 7 = 3.75 kHz
|
||||
// <8:6> AF Tx LPF2 filter bandwidth (Apass = 1dB)
|
||||
// 100 = 5.5 kHz
|
||||
// 101 = 5.0 kHz
|
||||
// 110 = 4.5 kHz
|
||||
// 111 = 4.0 kHz
|
||||
// 000 = 3.0 kHz
|
||||
// 001 = 2.5 kHz
|
||||
// 010 = 2.75 kHz
|
||||
// 011 = 3.5 kHz
|
||||
//
|
||||
// <5:4> 0 BW Mode Selection
|
||||
// 0 = 12.5k
|
||||
// 1 = 6.25k
|
||||
// 2 = 25k/20k
|
||||
// <5:4> BW mode selection
|
||||
// 00 = 12.5k
|
||||
// 01 = 6.25k
|
||||
// 10 = 25k/20k
|
||||
//
|
||||
// <3> 1 ???
|
||||
// <2> gain after FM demodulation
|
||||
// 0 = 0 dB
|
||||
// 1 = 6 dB
|
||||
//
|
||||
// <2> 0 Gain after FM Demodulation
|
||||
// 0 = 0dB
|
||||
// 1 = 6dB
|
||||
//
|
||||
// <1:0> 0 ???
|
||||
// <3> and <1:0> remain undocumented here.
|
||||
|
||||
uint16_t val = 0;
|
||||
switch (Bandwidth)
|
||||
{
|
||||
case BK4819_FILTER_BW_WIDE: // 25kHz
|
||||
// if (weak_no_different) {
|
||||
// // make the RX bandwidth the same with weak signals
|
||||
// val = 0x3628; // Old value 0x49a8 < v3.6
|
||||
// } else {
|
||||
// // with weak RX signals the RX bandwidth is reduced
|
||||
// val = 0x3428; // Old value 0x45a8 < v3.6
|
||||
// }
|
||||
// 0x3028 = (0b011 << 12) | (0b000 << 9) | (0b000 << 6) |
|
||||
// (0b10 << 4) | (1 << 3)
|
||||
// = RF 3.5 kHz and weak-RF 2.0 kHz, both doubled because
|
||||
// bit<5> is set in 25k/20k mode => RF 7.0 kHz, weak-RF
|
||||
// 4.0 kHz, AF Tx LPF2 3.0 kHz, FM gain 0 dB.
|
||||
val = 0x3028;
|
||||
break;
|
||||
|
||||
case BK4819_FILTER_BW_NARROW: // 12.5kHz
|
||||
// if (weak_no_different) {
|
||||
// // make the RX bandwidth the same with weak signals
|
||||
// val = 0x3648; // Old value 0x4808 < v3.6
|
||||
// } else {
|
||||
// // with weak RX signals the RX bandwidth is reduced
|
||||
// val = 0x3448; // Old value 0x4408 < v3.6
|
||||
// }
|
||||
// 0x4048 = (0b100 << 12) | (0b000 << 9) | (0b001 << 6) |
|
||||
// (0b00 << 4) | (1 << 3)
|
||||
// = RF 4.0 kHz, weak-RF 2.0 kHz, AF Tx LPF2 2.5 kHz,
|
||||
// 12.5k mode, FM gain 0 dB.
|
||||
val = 0x4048;
|
||||
break;
|
||||
|
||||
case BK4819_FILTER_BW_NARROWER: // 6.25kHz
|
||||
// if (weak_no_different) {
|
||||
// // make the RX bandwidth the same with weak signals
|
||||
// val = 0x1348; // Old value 0x3658 < v3.6
|
||||
// } else {
|
||||
// // with weak RX signals the RX bandwidth is reduced
|
||||
// val = 0x1148; // Old value 0x3658 < v3.6
|
||||
// }
|
||||
// 0x205C = (0b010 << 12) | (0b000 << 9) | (0b001 << 6) |
|
||||
// (0b01 << 4) | (1 << 3) | (1 << 2)
|
||||
// = RF 3.0 kHz, weak-RF 2.0 kHz, AF Tx LPF2 2.5 kHz,
|
||||
// 6.25k mode, FM gain +6 dB.
|
||||
val = 0x205C;
|
||||
break;
|
||||
|
||||
case BK4819_FILTER_BW_AM: // 8.33kHz
|
||||
// if (weak_no_different) {
|
||||
// // make the RX bandwidth the same with weak signals
|
||||
// val = 0x4858;
|
||||
// } else {
|
||||
// // with weak RX signals the RX bandwidth is reduced
|
||||
// val = 0x4458;
|
||||
// }
|
||||
case BK4819_FILTER_BW_AM: // Stock AM preset
|
||||
// 0x345C = (0b011 << 12) | (0b010 << 9) | (0b001 << 6) |
|
||||
// (0b01 << 4) | (1 << 3) | (1 << 2)
|
||||
// = RF 3.5 kHz, weak-RF 3.0 kHz, AF Tx LPF2 2.5 kHz,
|
||||
// 6.25k mode, bit<2> set. The "8.33kHz AM" label used in
|
||||
// the codebase is functional/empirical; it does not come
|
||||
// directly from the BW mode bits of REG_43.
|
||||
val = 0x345C;
|
||||
break;
|
||||
|
||||
default:
|
||||
val = 0x5C;
|
||||
break;
|
||||
@@ -797,21 +766,20 @@ void BK4819_SetupSquelch(
|
||||
// <13:11> 5 Squelch = open Delay Setting
|
||||
// 0 ~ 7
|
||||
//
|
||||
// <10:9> 7 Squelch = close Delay Setting
|
||||
// <10:9> 3 Squelch = close Delay Setting
|
||||
// 0 ~ 3
|
||||
//
|
||||
// <8> 0 ???
|
||||
// <8> 1 ???
|
||||
//
|
||||
// <7:0> 8 Glitch threshold for Squelch = open
|
||||
// 0 ~ 255
|
||||
//
|
||||
BK4819_WriteRegister(BK4819_REG_4E, // 01 101 11 1 00000000
|
||||
|
||||
// original (*)
|
||||
(1u << 14) | // 1 ???
|
||||
(5u << 11) | // *5 squelch = open delay .. 0 ~ 7
|
||||
(6u << 9) | // *3 squelch = close delay .. 0 ~ 3
|
||||
SquelchOpenGlitchThresh); // 0 ~ 255
|
||||
BK4819_WriteRegister(BK4819_REG_4E,
|
||||
(1u << 14) | // 1 ???
|
||||
(5u << 11) | // 5 squelch = open delay .. 0 ~ 7
|
||||
(3u << 9) | // 3 squelch = close delay .. 0 ~ 3
|
||||
(1u << 8) | // 1 ??? (matches stock BK4829)
|
||||
SquelchOpenGlitchThresh); // 0 ~ 255
|
||||
|
||||
|
||||
// REG_4F
|
||||
@@ -1154,45 +1122,62 @@ void BK4819_Idle(void)
|
||||
BK4819_WriteRegister(BK4819_REG_30, 0x0000);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
void BK4819_EnterBypass(void)
|
||||
{
|
||||
// Keep AF output on normal path (REG_47 mode 0x1 is documented on BK4829).
|
||||
BK4819_SetAF(BK4819_AF_FM);
|
||||
|
||||
// Bypass all AF filters (Rx + Tx) as recommended for digital bypass mode.
|
||||
// REG_2B:
|
||||
// bit10: Disable AF Rx HPF300
|
||||
// bit 9: Disable AF Rx LPF3K
|
||||
// bit 8: Disable AF Rx de-emphasis
|
||||
// bit 2: Disable AF Tx HPF300
|
||||
// bit 1: Disable AF Tx LPF1
|
||||
// bit 0: Disable AF Tx pre-emphasis
|
||||
uint16_t reg2b = BK4819_ReadRegister(BK4819_REG_2B);
|
||||
reg2b |= (1u << 10) | (1u << 9) | (1u << 8) | (1u << 2) | (1u << 1) | (1u << 0);
|
||||
BK4819_WriteRegister(BK4819_REG_2B, reg2b);
|
||||
|
||||
// Keep AGC/AFC behavior aligned with FM-like bypass experiments.
|
||||
BK4819_SetRegValue(afcDisableRegSpec, false);
|
||||
}
|
||||
|
||||
void BK4819_EnterRaw(void)
|
||||
{
|
||||
// Keep AF output on a documented mode.
|
||||
BK4819_SetAF(BK4819_AF_FM);
|
||||
|
||||
// RAW profile: bypass RX AF filters only, keep TX filter path unchanged.
|
||||
// REG_2B:
|
||||
// bit10: Disable AF Rx HPF300
|
||||
// bit 9: Disable AF Rx LPF3K
|
||||
// bit 8: Disable AF Rx de-emphasis
|
||||
uint16_t reg2b = BK4819_ReadRegister(BK4819_REG_2B);
|
||||
reg2b |= (1u << 10) | (1u << 9) | (1u << 8);
|
||||
reg2b &= ~((1u << 2) | (1u << 1) | (1u << 0));
|
||||
BK4819_WriteRegister(BK4819_REG_2B, reg2b);
|
||||
|
||||
// RAW profile keeps AFC disabled to preserve discriminator-like behavior.
|
||||
BK4819_SetRegValue(afcDisableRegSpec, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BK4819_ExitBypass(void)
|
||||
{
|
||||
BK4819_SetAF(BK4819_AF_MUTE);
|
||||
|
||||
// REG_7E
|
||||
//
|
||||
// <15> 0 AGC fix mode
|
||||
// 1 = fix
|
||||
// 0 = auto
|
||||
//
|
||||
// <14:12> 3 AGC fix index
|
||||
// 3 ( 3) = max
|
||||
// 2 ( 2)
|
||||
// 1 ( 1)
|
||||
// 0 ( 0)
|
||||
// 7 (-1)
|
||||
// 6 (-2)
|
||||
// 5 (-3)
|
||||
// 4 (-4) = min
|
||||
//
|
||||
// <11:6> 0 ???
|
||||
//
|
||||
// <5:3> 5 DC filter band width for Tx (MIC In)
|
||||
// 0 ~ 7
|
||||
// 0 = bypass DC filter
|
||||
//
|
||||
// <2:0> 6 DC filter band width for Rx (I.F In)
|
||||
// 0 ~ 7
|
||||
// 0 = bypass DC filter
|
||||
//
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
// Restore normal AF filters.
|
||||
uint16_t reg2b = BK4819_ReadRegister(BK4819_REG_2B);
|
||||
reg2b &= ~((1u << 10) | (1u << 9) | (1u << 8) | (1u << 2) | (1u << 1) | (1u << 0));
|
||||
BK4819_WriteRegister(BK4819_REG_2B, reg2b);
|
||||
#endif
|
||||
|
||||
// Keep existing REG_7E logic from your current implementation.
|
||||
uint16_t regVal = BK4819_ReadRegister(BK4819_REG_7E);
|
||||
|
||||
// 0x302E / 0 011 000000 101 110
|
||||
BK4819_WriteRegister(BK4819_REG_7E, (regVal & ~(0b111 << 3))
|
||||
|
||||
| (5u << 3) // 5 DC Filter band width for Tx (MIC In)
|
||||
|
||||
);
|
||||
BK4819_WriteRegister(BK4819_REG_7E, (regVal & ~(0b111 << 3)) | (5u << 3));
|
||||
}
|
||||
|
||||
void BK4819_PrepareTransmit(void)
|
||||
|
||||
+67
-10
@@ -36,30 +36,72 @@ bool gWasFKeyPressed = false;
|
||||
// Must exceed key_repeat_delay_10ms (40) to trigger ProcessKey(key, true, true).
|
||||
#define SERIAL_KEY_LONG_POLLS 45
|
||||
|
||||
// Packet types for serial key injection (K5Viewer → radio)
|
||||
#define SERIAL_KEY_TYPE 0x03
|
||||
#define SERIAL_KEY_TYPE_LONG 0x04
|
||||
|
||||
volatile KEY_Code_t gKeyFromSerial = KEY_INVALID;
|
||||
static uint8_t gSerialKeyHoldCount = 0;
|
||||
static uint8_t gSerialKeyLong = 0; // 0 = short press, 1 = long press
|
||||
|
||||
// Inject a short press from serial (UART or VCP).
|
||||
// Inject a short or long press from serial (UART or VCP).
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
void KEYBOARD_InjectKey(uint8_t keyCode)
|
||||
static inline void KEYBOARD_InjectKey(uint8_t keyCode, bool keyLong)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 0;
|
||||
gSerialKeyLong = keyLong;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject a long press from serial (UART or VCP).
|
||||
// KEY_PTT is explicitly blocked — PTT release cannot be guaranteed over serial.
|
||||
void KEYBOARD_InjectKeyLong(uint8_t keyCode)
|
||||
bool KEYBOARD_ProcessProtocolByte(ParseState_t *state, uint8_t b)
|
||||
{
|
||||
if (keyCode < KEY_INVALID && keyCode != KEY_PTT) {
|
||||
gKeyFromSerial = (KEY_Code_t)keyCode;
|
||||
gSerialKeyHoldCount = 0;
|
||||
gSerialKeyLong = 1;
|
||||
bool connected = false;
|
||||
|
||||
switch (*state)
|
||||
{
|
||||
case STATE_IDLE:
|
||||
if (b == 0x55) *state = STATE_KA_1;
|
||||
else if (b == 0xAA) *state = STATE_KEY_1;
|
||||
break;
|
||||
|
||||
case STATE_KA_1:
|
||||
*state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KA_2:
|
||||
*state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KA_3:
|
||||
if (b == 0x00) connected = true;
|
||||
*state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_1:
|
||||
*state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_2:
|
||||
if (b == SERIAL_KEY_TYPE) *state = STATE_KEY_3;
|
||||
else if (b == SERIAL_KEY_TYPE_LONG) *state = STATE_KEY_3L;
|
||||
else *state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_3:
|
||||
case STATE_KEY_3L:
|
||||
KEYBOARD_InjectKey(b, *state == STATE_KEY_3L);
|
||||
connected = true;
|
||||
*state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
*state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -208,4 +250,19 @@ KEY_Code_t KEYBOARD_Poll(void)
|
||||
GPIO_SetOutputPin(PIN_COLS);
|
||||
|
||||
return Key;
|
||||
}
|
||||
|
||||
KEY_Code_t KEYBOARD_GetKey(void)
|
||||
{
|
||||
KEY_Code_t btn = KEYBOARD_Poll();
|
||||
if (btn == KEY_INVALID && GPIO_IsPttPressed())
|
||||
{
|
||||
btn = KEY_PTT;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
void HideFKeyIcon(void) {
|
||||
gWasFKeyPressed = false;
|
||||
gUpdateStatus = true;
|
||||
}
|
||||
+15
-5
@@ -45,6 +45,17 @@ enum KEY_Code_e {
|
||||
};
|
||||
typedef enum KEY_Code_e KEY_Code_t;
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_KA_1,
|
||||
STATE_KA_2,
|
||||
STATE_KA_3,
|
||||
STATE_KEY_1,
|
||||
STATE_KEY_2,
|
||||
STATE_KEY_3,
|
||||
STATE_KEY_3L,
|
||||
} ParseState_t;
|
||||
|
||||
extern KEY_Code_t gKeyReading0;
|
||||
extern KEY_Code_t gKeyReading1;
|
||||
extern uint16_t gDebounceCounter;
|
||||
@@ -54,13 +65,12 @@ extern bool gWasFKeyPressed;
|
||||
// Serial-injected key (written by UART/VCP parser, consumed by KEYBOARD_Poll).
|
||||
extern volatile KEY_Code_t gKeyFromSerial;
|
||||
|
||||
// Inject a short press received from serial (UART or VCP).
|
||||
void KEYBOARD_InjectKey(uint8_t keyCode);
|
||||
|
||||
// Inject a long press received from serial (UART or VCP).
|
||||
void KEYBOARD_InjectKeyLong(uint8_t keyCode);
|
||||
bool KEYBOARD_ProcessProtocolByte(ParseState_t *state, uint8_t b);
|
||||
#endif
|
||||
|
||||
KEY_Code_t KEYBOARD_Poll(void);
|
||||
KEY_Code_t KEYBOARD_GetKey(void);
|
||||
|
||||
void HideFKeyIcon(void);
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -165,7 +165,7 @@ void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const u
|
||||
{
|
||||
ST7565_BlitScreen(line + 1);
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(true); // Force immediate capture
|
||||
SCREENSHOT_Update(true); // Force immediate capture
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+14
-37
@@ -25,9 +25,6 @@
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
#include "driver/keyboard.h"
|
||||
// Packet types for serial key injection (K5Viewer → radio)
|
||||
#define UART_TYPE_KEY 0x03
|
||||
#define UART_TYPE_KEY_LONG 0x04
|
||||
#endif
|
||||
|
||||
#define USARTx USART1
|
||||
@@ -155,44 +152,24 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
bool UART_IsCableConnected(void) {
|
||||
static uint8_t read_ptr = 0;
|
||||
static ParseState_t state = STATE_IDLE;
|
||||
|
||||
bool connected = false;
|
||||
|
||||
for (size_t i = 0; i < sizeof(UART_DMA_Buffer); i++) {
|
||||
uint8_t b = UART_DMA_Buffer[i];
|
||||
// DMA write position: NbData counts DOWN from 256
|
||||
uint8_t write_ptr = (uint8_t)(sizeof(UART_DMA_Buffer) -
|
||||
LL_DMA_GetDataLength(DMA1, DMA_CHANNEL));
|
||||
|
||||
if (b == 0x55) {
|
||||
// Keepalive byte — viewer is alive
|
||||
UART_DMA_Buffer[i] = 0x00;
|
||||
uint8_t processed = 0;
|
||||
while (read_ptr != write_ptr && processed < sizeof(UART_DMA_Buffer))
|
||||
{
|
||||
uint8_t b = UART_DMA_Buffer[read_ptr++];
|
||||
// read_ptr wraps naturally at 256 since it's uint8_t
|
||||
processed++;
|
||||
|
||||
if(KEYBOARD_ProcessProtocolByte(&state, b))
|
||||
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 connected;
|
||||
|
||||
+7
-64
@@ -20,9 +20,6 @@
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
#include "driver/keyboard.h"
|
||||
// Packet types for serial key injection (K5Viewer → radio)
|
||||
#define VCP_TYPE_KEY 0x03
|
||||
#define VCP_TYPE_KEY_LONG 0x04
|
||||
#endif
|
||||
|
||||
uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE];
|
||||
@@ -63,25 +60,14 @@ bool VCP_ScreenshotPing(void)
|
||||
// KEY_1 → 0x55 → KEY_2 (else IDLE)
|
||||
// KEY_2 → 0x03 → KEY_3 (short press, else check long)
|
||||
// KEY_2 → 0x04 → KEY_3L (long press, else IDLE)
|
||||
// KEY_3 → <b> → InjectKey(b), IDLE
|
||||
// KEY_3L → <b> → InjectKeyLong(b), IDLE
|
||||
// KEY_3 → <b> → KEYBOARD_InjectKey(b, false), IDLE
|
||||
// KEY_3L → <b> → KEYBOARD_InjectKey(b, true), IDLE
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_KA_1,
|
||||
STATE_KA_2,
|
||||
STATE_KA_3,
|
||||
STATE_KEY_1,
|
||||
STATE_KEY_2,
|
||||
STATE_KEY_3,
|
||||
STATE_KEY_3L,
|
||||
} ParseState_t;
|
||||
|
||||
static uint32_t read_ptr = 0;
|
||||
static uint8_t read_ptr = 0;
|
||||
static ParseState_t state = STATE_IDLE;
|
||||
|
||||
bool connected = false;
|
||||
uint32_t write_ptr = VCP_RxBufPointer; // snapshot once — ISR may update concurrently
|
||||
uint8_t write_ptr = VCP_RxBufPointer; // snapshot once — ISR may update concurrently
|
||||
|
||||
// Cap bytes processed per call to VCP_RX_BUF_SIZE.
|
||||
// Prevents unbounded loop if the ISR write pointer laps read_ptr
|
||||
@@ -91,57 +77,14 @@ bool VCP_ScreenshotPing(void)
|
||||
while (read_ptr != write_ptr && processed < VCP_RX_BUF_SIZE)
|
||||
{
|
||||
uint8_t b = VCP_RxBuf[read_ptr];
|
||||
|
||||
read_ptr++;
|
||||
if (read_ptr >= VCP_RX_BUF_SIZE)
|
||||
read_ptr = 0;
|
||||
processed++;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case STATE_IDLE:
|
||||
if (b == 0x55) state = STATE_KA_1;
|
||||
else if (b == 0xAA) state = STATE_KEY_1;
|
||||
break;
|
||||
|
||||
case STATE_KA_1:
|
||||
state = (b == 0xAA) ? STATE_KA_2 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KA_2:
|
||||
state = (b == 0x00) ? STATE_KA_3 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KA_3:
|
||||
if (b == 0x00) connected = true;
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_1:
|
||||
state = (b == 0x55) ? STATE_KEY_2 : STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_2:
|
||||
if (b == VCP_TYPE_KEY) state = STATE_KEY_3;
|
||||
else if (b == VCP_TYPE_KEY_LONG) state = STATE_KEY_3L;
|
||||
else state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_3:
|
||||
KEYBOARD_InjectKey(b);
|
||||
connected = true;
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_KEY_3L:
|
||||
KEYBOARD_InjectKeyLong(b);
|
||||
connected = true;
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
if(KEYBOARD_ProcessProtocolByte(&state, b))
|
||||
connected = true;
|
||||
}
|
||||
|
||||
return connected;
|
||||
|
||||
+5
-8
@@ -163,11 +163,8 @@ int32_t TX_freq_check(const uint32_t Frequency)
|
||||
{ // return '0' if TX frequency is allowed
|
||||
// otherwise return '-1'
|
||||
|
||||
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper)
|
||||
return -1; // not allowed outside this range
|
||||
|
||||
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
|
||||
return -1; // BX chip does not work in this range
|
||||
if (RX_freq_check(Frequency))
|
||||
return -1;
|
||||
|
||||
switch (gSetting_F_LOCK)
|
||||
{
|
||||
@@ -280,10 +277,10 @@ int32_t RX_freq_check(const uint32_t Frequency)
|
||||
// otherwise return '-1'
|
||||
|
||||
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper)
|
||||
return -1;
|
||||
return -1; // not allowed outside this range
|
||||
|
||||
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
|
||||
return -1;
|
||||
return -1; // BX chip does not work in this range
|
||||
|
||||
return 0; // OK frequency
|
||||
return 0; // OK frequency
|
||||
}
|
||||
+25
-64
@@ -277,77 +277,38 @@ void Main(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
if(gEeprom.CURRENT_STATE == 2 || gEeprom.CURRENT_STATE == 5)
|
||||
{
|
||||
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
|
||||
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
|
||||
if(gScanRangeStart > gScanRangeStop)
|
||||
{
|
||||
SWAP(gScanRangeStart, gScanRangeStop);
|
||||
}
|
||||
}
|
||||
switch (gEeprom.CURRENT_STATE) {
|
||||
case 1:
|
||||
gEeprom.SCAN_LIST_DEFAULT = gEeprom.CURRENT_LIST;
|
||||
CHFRSCANNER_Start(true, SCAN_FWD);
|
||||
break;
|
||||
if (gEeprom.CURRENT_STATE == 2 || gEeprom.CURRENT_STATE == 5)
|
||||
CHFRSCANNER_ScanRange();
|
||||
|
||||
case 2:
|
||||
CHFRSCANNER_Start(true, SCAN_FWD);
|
||||
break;
|
||||
switch (gEeprom.CURRENT_STATE) {
|
||||
case 1:
|
||||
gEeprom.SCAN_LIST_DEFAULT = gEeprom.CURRENT_LIST;
|
||||
CHFRSCANNER_Start(true, SCAN_FWD);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
case 3:
|
||||
ACTION_FM();
|
||||
GUI_SelectNextDisplay(gRequestDisplayScreen);
|
||||
break;
|
||||
#endif
|
||||
case 2:
|
||||
CHFRSCANNER_Start(true, SCAN_FWD);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_SPECTRUM
|
||||
case 4:
|
||||
APP_RunSpectrum();
|
||||
break;
|
||||
case 5:
|
||||
APP_RunSpectrum();
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_FMRADIO
|
||||
case 3:
|
||||
ACTION_FM();
|
||||
GUI_SelectNextDisplay(gRequestDisplayScreen);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
// No action for CURRENT_STATE == 0 or other unexpected values
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
#ifdef ENABLE_SPECTRUM
|
||||
case 4:
|
||||
case 5:
|
||||
APP_RunSpectrum();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
if (gEeprom.CURRENT_STATE == 2 || gEeprom.CURRENT_STATE == 5) {
|
||||
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
|
||||
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
|
||||
if (gScanRangeStart > gScanRangeStop) {
|
||||
SWAP(gScanRangeStart, gScanRangeStop);
|
||||
}
|
||||
default:
|
||||
// No action for CURRENT_STATE == 0 or other unexpected values
|
||||
break;
|
||||
}
|
||||
|
||||
if (gEeprom.CURRENT_STATE == 1) {
|
||||
gEeprom.SCAN_LIST_DEFAULT = gEeprom.CURRENT_LIST;
|
||||
}
|
||||
|
||||
if (gEeprom.CURRENT_STATE == 1 || gEeprom.CURRENT_STATE == 2) {
|
||||
CHFRSCANNER_Start(true, SCAN_FWD);
|
||||
}
|
||||
#ifdef ENABLE_FMRADIO
|
||||
else if (gEeprom.CURRENT_STATE == 3) {
|
||||
ACTION_FM();
|
||||
GUI_SelectNextDisplay(gRequestDisplayScreen);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_SPECTRUM
|
||||
else if (gEeprom.CURRENT_STATE == 4 || gEeprom.CURRENT_STATE == 5) {
|
||||
APP_RunSpectrum();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
|
||||
+14
@@ -242,6 +242,7 @@ volatile uint16_t gScanPauseDelayIn_10ms;
|
||||
uint16_t gMenuCountdown;
|
||||
bool gPttWasReleased;
|
||||
bool gPttWasPressed;
|
||||
bool gHasVfoBackup;
|
||||
uint8_t gKeypadLocked;
|
||||
bool gFlagReconfigureVfos;
|
||||
uint8_t gVfoConfigureMode;
|
||||
@@ -249,6 +250,7 @@ bool gFlagResetVfos;
|
||||
bool gRequestSaveVFO;
|
||||
uint16_t gRequestSaveChannel;
|
||||
bool gRequestSaveSettings;
|
||||
bool gRequestSaveSquelch;
|
||||
#ifdef ENABLE_FMRADIO
|
||||
bool gRequestSaveFM;
|
||||
#endif
|
||||
@@ -634,4 +636,16 @@ void MR_PrintCacheStats(void)
|
||||
// cache_hits, cache_misses, MR_GetCacheHitRate());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
bool SCREENSHOT_IsLocked(void)
|
||||
{
|
||||
if (gUART_LockScreenshot > 0) {
|
||||
gUART_LockScreenshot--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -323,6 +323,8 @@ extern volatile bool gTxTimeoutReached;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
extern volatile uint8_t gUART_LockScreenshot; // lock screenshot if Chirp is used
|
||||
extern bool gUSB_ScreenshotEnabled;
|
||||
|
||||
bool SCREENSHOT_IsLocked(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -366,12 +368,14 @@ extern AlarmState_t gAlarmState;
|
||||
extern uint16_t gMenuCountdown;
|
||||
extern bool gPttWasReleased;
|
||||
extern bool gPttWasPressed;
|
||||
extern bool gHasVfoBackup;
|
||||
extern bool gFlagReconfigureVfos;
|
||||
extern uint8_t gVfoConfigureMode;
|
||||
extern bool gFlagResetVfos;
|
||||
extern bool gRequestSaveVFO;
|
||||
extern uint16_t gRequestSaveChannel;
|
||||
extern bool gRequestSaveSettings;
|
||||
extern bool gRequestSaveSquelch;
|
||||
#ifdef ENABLE_FMRADIO
|
||||
extern bool gRequestSaveFM;
|
||||
#endif
|
||||
|
||||
+51
-33
@@ -926,8 +926,8 @@ void RADIO_SetupRegisters(bool switchToForeground)
|
||||
BK4819_EnableDTMF();
|
||||
InterruptMask |= BK4819_REG_3F_DTMF_5TONE_FOUND;
|
||||
|
||||
//RADIO_SetupAGC(gRxVfo->Modulation == MODULATION_AM, false);
|
||||
RADIO_SetupAGC(false, false);
|
||||
RADIO_SetupAGC(gRxVfo->Modulation == MODULATION_AM, false);
|
||||
//RADIO_SetupAGC(false, false);
|
||||
|
||||
// enable/disable BK4819 selected interrupts
|
||||
BK4819_WriteRegister(BK4819_REG_3F, InterruptMask);
|
||||
@@ -1056,6 +1056,31 @@ void RADIO_SetTxParameters(void)
|
||||
|
||||
void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
{
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
// BYP on BK4829 uses full audio bypass profile.
|
||||
if (modulation == MODULATION_BYP) {
|
||||
BK4819_EnterBypass();
|
||||
BK4819_SetRegValue(afDacGainRegSpec, 0xF);
|
||||
BK4819_WriteRegister(BK4819_REG_3D, 0x2AAB);
|
||||
RADIO_SetupAGC(false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// RAW on BK4829 uses RX-only filter bypass profile.
|
||||
if (modulation == MODULATION_RAW) {
|
||||
BK4819_EnterRaw();
|
||||
BK4819_SetRegValue(afDacGainRegSpec, 0xF);
|
||||
BK4819_WriteRegister(BK4819_REG_3D, 0x0000);
|
||||
RADIO_SetupAGC(false, false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
// Ensure we always leave bypass / raw mode before applying normal modulation settings.
|
||||
BK4819_ExitBypass();
|
||||
#endif
|
||||
|
||||
BK4819_AF_Type_t mod;
|
||||
switch(modulation) {
|
||||
default:
|
||||
@@ -1069,14 +1094,6 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
mod = BK4819_AF_BASEBAND2;
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
case MODULATION_BYP:
|
||||
mod = BK4819_AF_UNKNOWN3;
|
||||
break;
|
||||
case MODULATION_RAW:
|
||||
mod = BK4819_AF_BASEBAND1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
BK4819_SetAF(mod);
|
||||
@@ -1111,13 +1128,16 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
BK4819_WriteRegister(0x31,uVar1 | 1);
|
||||
BK4819_WriteRegister(0x42,0x6f5c);
|
||||
BK4819_WriteRegister(0x2a,0x7434);
|
||||
BK4819_WriteRegister(0x2b,0x300);
|
||||
BK4819_WriteRegister(0x2b,0x400);
|
||||
BK4819_WriteRegister(0x2f,0x9990);
|
||||
//BK4819_WriteRegister(0x54, 0x9775);
|
||||
//BK4819_WriteRegister(0x55, 0x32c6);
|
||||
|
||||
BK4819_WriteRegister(0x54, 0x8846);
|
||||
BK4819_WriteRegister(0x55, 0x38C0);
|
||||
//BK4819_WriteRegister(0x54, 0x8846);
|
||||
//BK4819_WriteRegister(0x55, 0x38C0);
|
||||
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x31a9);
|
||||
|
||||
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
|
||||
}
|
||||
@@ -1126,36 +1146,28 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
|
||||
BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
|
||||
|
||||
//RADIO_SetupAGC(modulation == MODULATION_AM, false);
|
||||
RADIO_SetupAGC(false, false);
|
||||
RADIO_SetupAGC(modulation == MODULATION_AM, false);
|
||||
//RADIO_SetupAGC(false, false);
|
||||
}
|
||||
|
||||
void RADIO_SetupAGC(bool listeningAM, bool disable)
|
||||
{
|
||||
static uint8_t lastSettings;
|
||||
static uint8_t lastSettings = 0xFF;
|
||||
uint8_t newSettings = (listeningAM << 1) | disable;
|
||||
if(lastSettings == newSettings)
|
||||
if (lastSettings == newSettings)
|
||||
return;
|
||||
lastSettings = newSettings;
|
||||
|
||||
|
||||
if(!listeningAM) { // if not actively listening AM we don't need any AM specific regulation
|
||||
BK4819_SetAGC(!disable);
|
||||
BK4819_InitAGC(false);
|
||||
}
|
||||
else {
|
||||
#ifdef ENABLE_AM_FIX
|
||||
if(gSetting_AM_fix) { // if AM fix active lock AGC so AM-fix can do it's job
|
||||
BK4819_SetAGC(0);
|
||||
AM_fix_enable(!disable);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
BK4819_SetAGC(!disable);
|
||||
BK4819_InitAGC(true);
|
||||
}
|
||||
if (listeningAM && gSetting_AM_fix) {
|
||||
BK4819_SetAGC(0);
|
||||
AM_fix_enable(!disable);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
BK4819_SetAGC(!disable);
|
||||
BK4819_InitAGC(listeningAM);
|
||||
}
|
||||
|
||||
void RADIO_SetVfoState(VfoState_t State)
|
||||
@@ -1229,6 +1241,12 @@ void RADIO_PrepareTX(void)
|
||||
// over voltage .. this is being a pain
|
||||
State = VFO_STATE_VOLTAGE_HIGH;
|
||||
}
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
else if (gCurrentVfo->Modulation == MODULATION_BYP || gCurrentVfo->Modulation == MODULATION_RAW) {
|
||||
// BYP/RAW are receive-only modes.
|
||||
State = VFO_STATE_TX_DISABLE;
|
||||
}
|
||||
#endif
|
||||
#ifndef ENABLE_TX_WHEN_AM
|
||||
else if (gCurrentVfo->Modulation != MODULATION_FM) {
|
||||
// not allowed to TX if in AM mode
|
||||
|
||||
+54
-48
@@ -21,7 +21,29 @@
|
||||
#include "driver/vcp.h"
|
||||
#include "driver/keyboard.h"
|
||||
|
||||
static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
||||
// SRAM optimization: minimize static allocations
|
||||
// - previousFrame: 1024 bytes (REQUIRED - need to compare for delta)
|
||||
// - No currentFrame or deltaFrame static buffers
|
||||
static uint8_t previousFrame[1024] = {0};
|
||||
static uint8_t forcedBlock = 0;
|
||||
static uint8_t keepAlive = 3;
|
||||
|
||||
void SCREENSHOT_ParseInput(void)
|
||||
{
|
||||
if (SCREENSHOT_IsLocked())
|
||||
return;
|
||||
|
||||
if (UART_IsCableConnected()) {
|
||||
keepAlive = 15;
|
||||
gUSB_ScreenshotEnabled = false;
|
||||
}
|
||||
else if (VCP_ScreenshotPing()) {
|
||||
keepAlive = 15;
|
||||
gUSB_ScreenshotEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void SCREENSHOT_Send(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if (gUSB_ScreenshotEnabled) {
|
||||
cdc_acm_data_send_with_dtr(buf, len);
|
||||
@@ -30,14 +52,19 @@ static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
||||
}
|
||||
}
|
||||
|
||||
// SRAM optimization: minimize static allocations
|
||||
// - previousFrame: 1024 bytes (REQUIRED - need to compare for delta)
|
||||
// - No currentFrame or deltaFrame static buffers
|
||||
static uint8_t previousFrame[1024] = {0};
|
||||
static uint8_t forcedBlock = 0;
|
||||
static uint8_t keepAlive = 10;
|
||||
void SCREENSHOT_Line(uint8_t *src, uint8_t *dest, uint16_t *idx) {
|
||||
for (uint8_t b = 0; b < 8; b++) {
|
||||
for (uint8_t i = 0; i < 128; i += 8) {
|
||||
uint8_t acc = 0;
|
||||
for (uint8_t k = 0; k < 8; k++) {
|
||||
if (src[i + k] & (1 << b)) acc |= (1 << k);
|
||||
}
|
||||
dest[(*idx)++] = gSetting_set_inv ? ~acc : acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getScreenShot(bool force)
|
||||
void SCREENSHOT_Update(bool force)
|
||||
{
|
||||
// Build frame in a temporary stack buffer
|
||||
// This is 1024 bytes but it's temporary and gets freed after the function
|
||||
@@ -45,55 +72,34 @@ void getScreenShot(bool force)
|
||||
uint16_t index = 0;
|
||||
uint8_t acc = 0;
|
||||
uint8_t bitCount = 0;
|
||||
static bool wasConnected = false;
|
||||
|
||||
if (gUART_LockScreenshot > 0) {
|
||||
gUART_LockScreenshot--;
|
||||
if (SCREENSHOT_IsLocked())
|
||||
return;
|
||||
}
|
||||
|
||||
if (UART_IsCableConnected()) {
|
||||
keepAlive = 10;
|
||||
gUSB_ScreenshotEnabled = false;
|
||||
}
|
||||
|
||||
if (VCP_ScreenshotPing()) {
|
||||
keepAlive = 10;
|
||||
gUSB_ScreenshotEnabled = true;
|
||||
}
|
||||
|
||||
if (keepAlive > 0) {
|
||||
if (--keepAlive == 0) return;
|
||||
if (--keepAlive == 0) {
|
||||
// Connection just lost → reset state for next reconnection
|
||||
wasConnected = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Connection is alive — detect reconnection and force full frame
|
||||
if (!wasConnected) {
|
||||
force = true;
|
||||
wasConnected = true;
|
||||
}
|
||||
|
||||
// ==== BUILD FRAME ONCE ====
|
||||
// Status line: 8 bit layers × 128 columns
|
||||
for (uint8_t b = 0; b < 8; b++) {
|
||||
for (uint8_t i = 0; i < 128; i++) {
|
||||
uint8_t bit = (gStatusLine[i] >> b) & 0x01;
|
||||
acc |= (bit << bitCount++);
|
||||
if (bitCount == 8) {
|
||||
frameBuffer[index++] = acc;
|
||||
acc = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
SCREENSHOT_Line(gStatusLine, frameBuffer, &index);
|
||||
|
||||
// Frame buffer: 7 lines × 8 bit layers × 128 columns
|
||||
for (uint8_t l = 0; l < 7; l++) {
|
||||
for (uint8_t b = 0; b < 8; b++) {
|
||||
for (uint8_t i = 0; i < 128; i++) {
|
||||
uint8_t bit = (gFrameBuffer[l][i] >> b) & 0x01;
|
||||
acc |= (bit << bitCount++);
|
||||
if (bitCount == 8) {
|
||||
frameBuffer[index++] = acc;
|
||||
acc = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
SCREENSHOT_Line(gFrameBuffer[l], frameBuffer, &index);
|
||||
}
|
||||
|
||||
if (bitCount > 0)
|
||||
@@ -135,7 +141,7 @@ void getScreenShot(bool force)
|
||||
// New format: sends 0xFF before header
|
||||
// Old format: doesn't exist, so viewers can differentiate
|
||||
uint8_t versionMarker = 0xFF;
|
||||
Screenshot_Send(&versionMarker, 1);
|
||||
SCREENSHOT_Send(&versionMarker, 1);
|
||||
|
||||
// ==== Send header ====
|
||||
uint8_t header[5] = {
|
||||
@@ -144,7 +150,7 @@ void getScreenShot(bool force)
|
||||
(uint8_t)(deltaLen & 0xFF)
|
||||
};
|
||||
|
||||
Screenshot_Send(header, 5);
|
||||
SCREENSHOT_Send(header, 5);
|
||||
|
||||
// ==== SECOND PASS: Send only changed chunks ====
|
||||
uint8_t chunk[9];
|
||||
@@ -157,12 +163,12 @@ void getScreenShot(bool force)
|
||||
chunk[0] = chunkIdx;
|
||||
memcpy(&chunk[1], cur, 8);
|
||||
|
||||
Screenshot_Send(chunk, 9);
|
||||
SCREENSHOT_Send(chunk, 9);
|
||||
|
||||
// Update previousFrame for next comparison
|
||||
memcpy(prev, cur, 8);
|
||||
}
|
||||
|
||||
uint8_t end = 0x0A;
|
||||
Screenshot_Send(&end, 1);
|
||||
SCREENSHOT_Send(&end, 1);
|
||||
}
|
||||
+2
-1
@@ -17,6 +17,7 @@
|
||||
#ifndef SCREENSHOT_H
|
||||
#define SCREENSHOT_H
|
||||
|
||||
void getScreenShot(bool force);
|
||||
void SCREENSHOT_Update(bool force);
|
||||
void SCREENSHOT_ParseInput(void);
|
||||
|
||||
#endif
|
||||
+33
-14
@@ -100,9 +100,21 @@ void SETTINGS_InitEEPROM(void)
|
||||
|
||||
// 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);
|
||||
PY25Q16_ReadBuffer(0x00A0B9, (uint8_t *)buf, 7);
|
||||
|
||||
needsWrite = true;
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
if ((uint8_t)buf[i] != 0xFF) {
|
||||
needsWrite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsWrite) {
|
||||
for (uint8_t i = 0; i < 7; i++)
|
||||
buf[i] = dBmCorrTable[i];
|
||||
PY25Q16_WriteBuffer(0x00A0B9, buf, 7, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,16 +617,20 @@ void SETTINGS_FetchChannelName(char *s, const uint16_t channel)
|
||||
|
||||
void SETTINGS_FactoryReset(bool bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x000000);
|
||||
PY25Q16_SectorErase(0x001000);
|
||||
PY25Q16_SectorErase(0x002000);
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
PY25Q16_SectorErase(0x004000);
|
||||
PY25Q16_SectorErase(0x005000);
|
||||
PY25Q16_SectorErase(0x006000);
|
||||
PY25Q16_SectorErase(0x007000);
|
||||
PY25Q16_SectorErase(0x008000);
|
||||
PY25Q16_SectorErase(0x009000);
|
||||
// PY25Q16_SectorErase(0x000000);
|
||||
// PY25Q16_SectorErase(0x001000);
|
||||
// PY25Q16_SectorErase(0x002000);
|
||||
// PY25Q16_SectorErase(0x003000);
|
||||
// PY25Q16_SectorErase(0x004000);
|
||||
// PY25Q16_SectorErase(0x005000);
|
||||
// PY25Q16_SectorErase(0x006000);
|
||||
// PY25Q16_SectorErase(0x007000);
|
||||
// PY25Q16_SectorErase(0x008000);
|
||||
// PY25Q16_SectorErase(0x009000);
|
||||
|
||||
for (uint32_t addr = 0x000000; addr <= 0x009000; addr += 0x1000) {
|
||||
PY25Q16_SectorErase(addr);
|
||||
}
|
||||
|
||||
// 0d60 - 0e30
|
||||
if (bIsAll)
|
||||
@@ -750,7 +766,10 @@ void SETTINGS_SaveSettings(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
State[0] = gSetting_set_audio;
|
||||
#endif
|
||||
State[1] = gEeprom.SQUELCH_LEVEL;
|
||||
if (gRequestSaveSquelch)
|
||||
{
|
||||
State[1] = gEeprom.SQUELCH_LEVEL;
|
||||
}
|
||||
State[2] = gEeprom.TX_TIMEOUT_TIMER;
|
||||
#ifdef ENABLE_NOAA
|
||||
State[3] = gEeprom.NOAA_AUTO_SCAN;
|
||||
|
||||
@@ -35,6 +35,10 @@ void UI_DisplayFM(void)
|
||||
char *pPrintStr = String;
|
||||
UI_DisplayClear();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
UI_DisplayUnlockKeyboard(5);
|
||||
#endif
|
||||
|
||||
UI_PrintString("FM", 2, 0, 0, 8);
|
||||
|
||||
sprintf(String, "%d%s-%dM",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ui/helper.h"
|
||||
#include "ui/inputbox.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
void UI_GenerateChannelString(char *pString, const uint16_t Channel)
|
||||
@@ -321,6 +322,33 @@ static void sort(int16_t *a, int16_t *b)
|
||||
x += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void UI_DisplayUnlockKeyboard(uint8_t shift) {
|
||||
if (gEeprom.KEY_LOCK && gKeypadLocked > 0)
|
||||
{ // tell user how to unlock the keyboard
|
||||
|
||||
//memcpy(gFrameBuffer[shift] + 2, gFontKeyLock, sizeof(gFontKeyLock));
|
||||
UI_PrintStringSmallBold("UNLOCK KEYBOARD", 12, 0, shift);
|
||||
//memcpy(gFrameBuffer[shift] + 120, gFontKeyLock, sizeof(gFontKeyLock));
|
||||
|
||||
/*
|
||||
for (uint8_t i = 12; i < 116; i++)
|
||||
{
|
||||
gFrameBuffer[shift][i] ^= 0xFF;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmptyName(const char *name, uint8_t len) {
|
||||
if (name[0] == '\0' || name[0] == '\xff')
|
||||
return true;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
if (name[i] != ' ' && name[i] != '\xff' && name[i] != '\0')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void UI_DrawLineBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
|
||||
|
||||
@@ -38,6 +38,8 @@ void UI_DrawPixelBuffer(uint8_t (*buffer)[128], uint8_t x, uint8_t y, bool black
|
||||
void PutPixel(uint8_t x, uint8_t y, bool fill);
|
||||
void PutPixelStatus(uint8_t x, uint8_t y, bool fill);
|
||||
void GUI_DisplaySmallest(const char *pString, uint8_t x, uint8_t y, bool statusbar, bool fill);
|
||||
void UI_DisplayUnlockKeyboard(uint8_t shift);
|
||||
bool IsEmptyName(const char *name, uint8_t len);
|
||||
#endif
|
||||
void UI_DrawLineBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
|
||||
void UI_DrawRectangleBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
|
||||
|
||||
+185
-57
@@ -77,19 +77,13 @@ static void DrawSmallPowerBars(uint8_t *p, unsigned int level)
|
||||
if(level>6)
|
||||
level = 6;
|
||||
|
||||
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);
|
||||
char bar = 0b00111110;
|
||||
|
||||
for(uint8_t i = 0; i <= level; i++) {
|
||||
if(gSetting_set_gui) {
|
||||
bar = (0xff << (6-i)) & 0x7F;
|
||||
}
|
||||
memset(p + 2 + i*3, bar, 2);
|
||||
}
|
||||
}
|
||||
#if defined ENABLE_AUDIO_BAR || defined ENABLE_RSSI_BAR
|
||||
@@ -164,15 +158,17 @@ static void DrawLevelBar(uint8_t xpos, uint8_t line, uint8_t level, uint8_t bars
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
|
||||
// Approximation of a logarithmic scale using integer arithmetic
|
||||
uint8_t log2_approx(unsigned int value) {
|
||||
static uint8_t log2_approx(unsigned int value) {
|
||||
uint8_t log = 0;
|
||||
while (value >>= 1) {
|
||||
log++;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
|
||||
void UI_DisplayAudioBar(void)
|
||||
{
|
||||
@@ -237,6 +233,135 @@ void UI_DisplayAudioBar(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO_SCOPE
|
||||
|
||||
#define SCOPE_SAMPLES 43 // number of columns (43 × 3px = 128px wide)
|
||||
#define SCOPE_NOISE_GATE 50u // minimum range below which the display shows baseline
|
||||
#define SCOPE_FLOOR_RISE 2u // floor rise per frame (+100 units/s at 20ms/frame)
|
||||
#define SCOPE_FLOOR_DROP_SHR 3u // floor drop IIR shift: drop by (floor-min) >> N per frame (~160ms to halve)
|
||||
#define SCOPE_VOLUME_MIN 200u // let's assume that the sound level in silence is 200
|
||||
|
||||
void UI_DisplayAudioScope(void)
|
||||
{
|
||||
static uint16_t g_scope_buf[SCOPE_SAMPLES];
|
||||
static uint8_t g_scope_write = 0;
|
||||
static uint16_t g_scope_floor = SCOPE_VOLUME_MIN; // persistent floor: snaps down fast, rises slowly
|
||||
static uint8_t g_scope_ready = 0; // number of valid samples since TX entry
|
||||
|
||||
// REG_64 (VoiceAmplitudeOut) is only meaningful in TX (mic input).
|
||||
// FM RX audio is frequency-encoded — no register gives the instantaneous waveform.
|
||||
|
||||
// ------------------------------ Sample audio amplitude ------------------------------
|
||||
|
||||
static bool s_was_tx = false;
|
||||
|
||||
if (gCurrentFunction != FUNCTION_TRANSMIT) {
|
||||
s_was_tx = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// This prevents a sudden spike on the bar caused by release the PTT button
|
||||
if (!GPIO_IsPttPressed()
|
||||
#ifdef ENABLE_VOX
|
||||
&& !gEeprom.VOX_SWITCH
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
&& !gSetting_set_ptt_session
|
||||
#endif
|
||||
)
|
||||
return;
|
||||
|
||||
if (!s_was_tx) {
|
||||
// TX entry: full reset so every new transmission starts from a clean state
|
||||
for (uint8_t i = 0; i < SCOPE_SAMPLES; i++) g_scope_buf[i] = SCOPE_VOLUME_MIN;
|
||||
g_scope_write = 0u;
|
||||
g_scope_floor = SCOPE_VOLUME_MIN;
|
||||
s_was_tx = true;
|
||||
}
|
||||
|
||||
// The first 7 bars after turning on the radio
|
||||
// will not display any values: they cause high bars.
|
||||
if (g_scope_ready >= 7)
|
||||
g_scope_buf[g_scope_write] = BK4819_GetVoiceAmplitudeOut();
|
||||
else
|
||||
g_scope_ready++;
|
||||
|
||||
// If the reading is 0, it is definitely an incorrect value
|
||||
// caused by the microphone being muted - set it to 200.
|
||||
if (g_scope_buf[g_scope_write] == 0)
|
||||
g_scope_buf[g_scope_write] = SCOPE_VOLUME_MIN;
|
||||
|
||||
g_scope_write = (g_scope_write + 1u) % SCOPE_SAMPLES;
|
||||
|
||||
// --------------------------------- Refresh display ---------------------------------
|
||||
|
||||
if (gLowBattery && !gLowBatteryConfirmed)
|
||||
return;
|
||||
|
||||
if (gScreenToDisplay != DISPLAY_MAIN
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
|
||||
#endif
|
||||
)
|
||||
return;
|
||||
|
||||
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
|
||||
if (gAlarmState != ALARM_STATE_OFF)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
RxBlinkLed = 0;
|
||||
RxBlinkLedCounter = 0;
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
|
||||
const unsigned int line = isMainOnly() ? 5 : 3;
|
||||
#else
|
||||
const unsigned int line = 3;
|
||||
#endif
|
||||
|
||||
uint8_t *p_line = gFrameBuffer[line];
|
||||
memset(p_line, 0, LCD_WIDTH);
|
||||
|
||||
// Find min and max across current buffer
|
||||
uint16_t min_val = g_scope_buf[0];
|
||||
uint16_t max_val = g_scope_buf[0];
|
||||
for (uint8_t i = 1u; i < SCOPE_SAMPLES; i++) {
|
||||
if (g_scope_buf[i] < min_val) min_val = g_scope_buf[i];
|
||||
if (g_scope_buf[i] > max_val) max_val = g_scope_buf[i];
|
||||
}
|
||||
|
||||
// Floor tracks buffer minimum with asymmetric IIR:
|
||||
// - drops toward min smoothly (SCOPE_FLOOR_DROP_SHR), avoiding instant-snap ghost
|
||||
// - rises slowly (SCOPE_FLOOR_RISE/frame) to handle loud constant voice
|
||||
if (g_scope_floor > min_val)
|
||||
g_scope_floor -= ((g_scope_floor - min_val) >> SCOPE_FLOOR_DROP_SHR) + 1u;
|
||||
else
|
||||
g_scope_floor += SCOPE_FLOOR_RISE;
|
||||
|
||||
const uint16_t range = (max_val > g_scope_floor) ? (max_val - g_scope_floor) : 0u;
|
||||
|
||||
for (uint8_t i = 0u; i < SCOPE_SAMPLES; i++) {
|
||||
const uint8_t idx = (g_scope_write + i) % SCOPE_SAMPLES;
|
||||
uint8_t height = 0u;
|
||||
if (range >= SCOPE_NOISE_GATE) {
|
||||
const uint16_t v = (g_scope_buf[idx] > g_scope_floor) ? (g_scope_buf[idx] - g_scope_floor) : 0u;
|
||||
height = (uint8_t)((uint32_t)v * 7u / range);
|
||||
}
|
||||
// Filled column using bits 6..0 only (bit 7 always off to avoid overlap with text below)
|
||||
// At silence (height 0): single pixel at bit 6 (baseline)
|
||||
const uint8_t mask = (height > 0u) ? (uint8_t)((0x7Fu << (7u - height)) & 0x7Fu) : 0x40u;
|
||||
// 2px column + 1px gap per sample
|
||||
|
||||
uint8_t *p_col = &p_line[i * 3u];
|
||||
p_col[0] = mask;
|
||||
p_col[1] = mask;
|
||||
|
||||
}
|
||||
|
||||
ST7565_BlitLine(line);
|
||||
}
|
||||
#endif // ENABLE_FEAT_F4HWN_AUDIO_SCOPE
|
||||
|
||||
void DisplayRSSIBar(const bool now)
|
||||
{
|
||||
#if defined(ENABLE_RSSI_BAR)
|
||||
@@ -328,22 +453,34 @@ void DisplayRSSIBar(const bool now)
|
||||
#endif
|
||||
+ dBmCorrTable[gRxVfo->Band];
|
||||
|
||||
// S9 = -93 dBm, S0 = -141 dBm (IARU standard)
|
||||
const int16_t s9_dBm = -93;
|
||||
const int16_t s0_dBm = -141;
|
||||
|
||||
// IARU VHF/UHF S-meter: S9 = -93 dBm, 1 S-unit = 6 dB
|
||||
// S(n) threshold = -93 + (n - 9) * 6
|
||||
uint8_t s_level = 0;
|
||||
uint8_t overS9dBm = 0;
|
||||
uint8_t overS9Bars = 0;
|
||||
|
||||
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);
|
||||
// if (rssi_dBm >= -93) s_level = 9; // S9 = -93 dBm
|
||||
// else if (rssi_dBm >= -99) s_level = 8; // S8 = -99 dBm
|
||||
// else if (rssi_dBm >= -105) s_level = 7; // S7 = -105 dBm
|
||||
// else if (rssi_dBm >= -111) s_level = 6; // S6 = -111 dBm
|
||||
// else if (rssi_dBm >= -117) s_level = 5; // S5 = -117 dBm
|
||||
// else if (rssi_dBm >= -123) s_level = 4; // S4 = -123 dBm
|
||||
// else if (rssi_dBm >= -129) s_level = 3; // S3 = -129 dBm
|
||||
// else if (rssi_dBm >= -135) s_level = 2; // S2 = -135 dBm
|
||||
// else if (rssi_dBm >= -141) s_level = 1; // S1 = -141 dBm
|
||||
// else s_level = 0; // S0 (below -141 dBm)
|
||||
|
||||
if (rssi_dBm >= -93)
|
||||
s_level = 9;
|
||||
else if (rssi_dBm < -141)
|
||||
s_level = 0;
|
||||
else
|
||||
s_level = (rssi_dBm + 147) / 6;
|
||||
|
||||
if (s_level == 9) {
|
||||
// Compute over-S9 dB directly
|
||||
overS9dBm = (uint8_t)MIN(rssi_dBm - (-93), 40);
|
||||
overS9Bars = overS9dBm / 10;
|
||||
}
|
||||
#else
|
||||
const int16_t s0_dBm = -gEeprom.S0_LEVEL; // S0 .. base level
|
||||
@@ -551,32 +688,7 @@ void UI_DisplayMain(void)
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (gEeprom.KEY_LOCK && gKeypadLocked > 0)
|
||||
{ // tell user how to unlock the keyboard
|
||||
uint8_t shift = 3;
|
||||
|
||||
/*
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true);
|
||||
SYSTEM_DelayMs(50);
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false);
|
||||
SYSTEM_DelayMs(50);
|
||||
*/
|
||||
|
||||
if(isMainOnly())
|
||||
{
|
||||
shift = 5;
|
||||
}
|
||||
//memcpy(gFrameBuffer[shift] + 2, gFontKeyLock, sizeof(gFontKeyLock));
|
||||
UI_PrintStringSmallBold("UNLOCK KEYBOARD", 12, 0, shift);
|
||||
//memcpy(gFrameBuffer[shift] + 120, gFontKeyLock, sizeof(gFontKeyLock));
|
||||
|
||||
/*
|
||||
for (uint8_t i = 12; i < 116; i++)
|
||||
{
|
||||
gFrameBuffer[shift][i] ^= 0xFF;
|
||||
}
|
||||
*/
|
||||
}
|
||||
UI_DisplayUnlockKeyboard(isMainOnly() ? 5 : 3);
|
||||
#endif
|
||||
|
||||
unsigned int activeTxVFO = gRxVfoIsActive ? gEeprom.RX_VFO : gEeprom.TX_VFO;
|
||||
@@ -976,7 +1088,7 @@ void UI_DisplayMain(void)
|
||||
const char *name = gListName[countList - 1];
|
||||
|
||||
// If name is empty/invalid, display number
|
||||
if (name[0] == '\0' || name[0] == '\xff' || name[0] == ' ') {
|
||||
if (IsEmptyName(name, sizeof(gListName[0]))) {
|
||||
sprintf(String, "%02d", countList);
|
||||
xStart = 117; // 2-digit number aligned right
|
||||
xDisplay = 119;
|
||||
@@ -1007,9 +1119,11 @@ void UI_DisplayMain(void)
|
||||
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 1 : 33, false, true);
|
||||
|
||||
for (uint8_t x = xStart; x < 128; x++) {
|
||||
gFrameBuffer[line][xStart] ^= 0x3E;
|
||||
for (uint8_t x = xStart + 1; x < 127; x++) {
|
||||
gFrameBuffer[line][x] ^= 0x7F;
|
||||
}
|
||||
gFrameBuffer[line][127] ^= 0x3E;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
@@ -1174,9 +1288,15 @@ void UI_DisplayMain(void)
|
||||
Level = 2;
|
||||
}
|
||||
*/
|
||||
Level = gRxVfo->OUTPUT_POWER - 1;
|
||||
|
||||
uint8_t currentPower = gRxVfo->OUTPUT_POWER;
|
||||
|
||||
if(currentPower == OUTPUT_POWER_USER)
|
||||
Level = gSetting_set_pwr;
|
||||
else
|
||||
Level = currentPower - 1;
|
||||
}
|
||||
else
|
||||
else
|
||||
if (mode == VFO_MODE_RX)
|
||||
{ // RX signal level
|
||||
#ifndef ENABLE_RSSI_BAR
|
||||
@@ -1485,6 +1605,14 @@ void UI_DisplayMain(void)
|
||||
|
||||
const bool rx = FUNCTION_IsRx();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO_SCOPE
|
||||
if (gSetting_mic_bar && gCurrentFunction == FUNCTION_TRANSMIT) {
|
||||
// Reserve the line so no other element overwrites it.
|
||||
// Actual drawing is handled exclusively by the app.c timeslice.
|
||||
center_line = CENTER_LINE_AUDIO_SCOPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
if (gSetting_mic_bar && gCurrentFunction == FUNCTION_TRANSMIT) {
|
||||
center_line = CENTER_LINE_AUDIO_BAR;
|
||||
@@ -1520,7 +1648,7 @@ void UI_DisplayMain(void)
|
||||
if (rx || gCurrentFunction == FUNCTION_FOREGROUND || gCurrentFunction == FUNCTION_POWER_SAVE)
|
||||
{
|
||||
#if 1
|
||||
if (gSetting_live_DTMF_decoder && gDTMF_RX_live[0] != 0)
|
||||
if (gSetting_live_DTMF_decoder && gDTMF_RX_live[0] != 0 && gKeypadLocked == 0)
|
||||
{ // show live DTMF decode
|
||||
const unsigned int len = strlen(gDTMF_RX_live);
|
||||
const unsigned int idx = (len > (17 - 5)) ? len - (17 - 5) : 0; // limit to last 'n' chars
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
#ifndef UI_MAIN_H
|
||||
#define UI_MAIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum center_line_t {
|
||||
CENTER_LINE_NONE = 0,
|
||||
CENTER_LINE_IN_USE,
|
||||
CENTER_LINE_AUDIO_BAR,
|
||||
CENTER_LINE_AUDIO_SCOPE,
|
||||
CENTER_LINE_RSSI,
|
||||
CENTER_LINE_AM_FIX_DATA,
|
||||
CENTER_LINE_DTMF_DEC,
|
||||
@@ -37,7 +40,12 @@ typedef enum center_line_t center_line_t;
|
||||
|
||||
extern center_line_t center_line;
|
||||
|
||||
#ifdef ENABLE_AUDIO_BAR
|
||||
void UI_DisplayAudioBar(void);
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO_SCOPE
|
||||
void UI_DisplayAudioScope(void);
|
||||
#endif
|
||||
void UI_MAIN_TimeSlice500ms(void);
|
||||
void UI_DisplayMain(void);
|
||||
|
||||
|
||||
+3
-3
@@ -976,7 +976,7 @@ void UI_DisplayMenu(void)
|
||||
const char *name = gListName[gSubMenuSelection - 1];
|
||||
|
||||
// If first character is empty/invalid, display "N/A"
|
||||
if (name[0] == '\0' || name[0] == '\xff' || name[0] == ' ')
|
||||
if (IsEmptyName(name, sizeof(gListName[0])))
|
||||
sprintf(String, "%02u", gSubMenuSelection);
|
||||
else
|
||||
sprintf(String, "%02u (%.3s)", gSubMenuSelection, name);
|
||||
@@ -989,7 +989,7 @@ void UI_DisplayMenu(void)
|
||||
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] == ' ')
|
||||
if (IsEmptyName(name, sizeof(gListName[0])))
|
||||
sprintf(String, "%02u", gSubMenuSelection);
|
||||
else
|
||||
sprintf(String, "%02u (%.3s)", gSubMenuSelection, name);
|
||||
@@ -1220,7 +1220,7 @@ void UI_DisplayMenu(void)
|
||||
gaugeMax = 63;
|
||||
//#endif
|
||||
}
|
||||
gEeprom.VOLUME_GAIN = gSubMenuSelection;
|
||||
// gEeprom.VOLUME_GAIN = gSubMenuSelection;
|
||||
BK4819_WriteRegister(BK4819_REG_48,
|
||||
(11u << 12) | // ??? .. 0 ~ 15, doesn't seem to make any difference
|
||||
( 0u << 10) | // AF Rx Gain-1
|
||||
|
||||
+21
-30
@@ -114,10 +114,7 @@ void UI_DisplayStatus()
|
||||
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) {
|
||||
if (!IsEmptyName(name, sizeof(gListName[0]))) {
|
||||
sprintf(str, "%.3s%s", name, gEeprom.SCAN_LIST_ENABLED ? "+" : "");
|
||||
end = gEeprom.SCAN_LIST_ENABLED ? 18 : 14;
|
||||
}
|
||||
@@ -176,31 +173,32 @@ void UI_DisplayStatus()
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(line + x + 2, gFontRO, sizeof(gFontRO));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
|
||||
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
|
||||
if(gDualWatchActive)
|
||||
memcpy(line + x + (dw==1?0:2), gFontDWR, sizeof(gFontDWR) - (dw==1?0:5));
|
||||
else
|
||||
memcpy(line + x + 3, gFontHold, sizeof(gFontHold));
|
||||
}
|
||||
else if(dw == 2) { // XB - crossband
|
||||
memcpy(line + x + 2, gFontXB, sizeof(gFontXB));
|
||||
if(!gAirCopyBootMode) {
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == true) {
|
||||
memcpy(line + x + 2, gFontRO, sizeof(gFontRO));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!gAirCopyBootMode)
|
||||
#endif
|
||||
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
|
||||
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
|
||||
if(gDualWatchActive)
|
||||
memcpy(line + x + (dw==1?0:2), gFontDWR, sizeof(gFontDWR) - (dw==1?0:5));
|
||||
else
|
||||
memcpy(line + x + 3, gFontHold, sizeof(gFontHold));
|
||||
}
|
||||
else if(dw == 2) { // XB - crossband
|
||||
memcpy(line + x + 2, gFontXB, sizeof(gFontXB));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(line + x + 2, gFontMO, sizeof(gFontMO));
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
x += sizeof(gFontDWR) + 3;
|
||||
@@ -242,15 +240,8 @@ void UI_DisplayStatus()
|
||||
size = sizeof(gFontKeyLock);
|
||||
}
|
||||
else if (gWasFKeyPressed) {
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if (!gEeprom.MENU_LOCK) {
|
||||
src = gFontF;
|
||||
size = sizeof(gFontF);
|
||||
}
|
||||
#else
|
||||
src = gFontF;
|
||||
size = sizeof(gFontF);
|
||||
#endif
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
else if (gMute) {
|
||||
|
||||
+1
-2
@@ -94,9 +94,8 @@ void GUI_SelectNextDisplay(GUI_DisplayType_t Display)
|
||||
gAskForConfirmation = 0;
|
||||
gAskToSave = false;
|
||||
gAskToDelete = false;
|
||||
gWasFKeyPressed = false;
|
||||
|
||||
gUpdateStatus = true;
|
||||
HideFKeyIcon();
|
||||
}
|
||||
|
||||
gScreenToDisplay = Display;
|
||||
|
||||
+1
-1
@@ -222,7 +222,7 @@ void UI_DisplayWelcome(void)
|
||||
ST7565_BlitFullScreen();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(true);
|
||||
SCREENSHOT_Update(true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -190,8 +190,13 @@ void cdc_acm_data_send_with_dtr(const uint8_t *buf, uint32_t size)
|
||||
{
|
||||
ep_tx_busy_flag = true;
|
||||
usbd_ep_start_write(CDC_IN_EP, buf, size);
|
||||
while (ep_tx_busy_flag)
|
||||
uint32_t timeout = 100000;
|
||||
while (ep_tx_busy_flag && --timeout)
|
||||
;
|
||||
if (!timeout) {
|
||||
ep_tx_busy_flag = false;
|
||||
dtr_enable = 0; // Consider USB disconnected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -60,6 +60,7 @@
|
||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": false,
|
||||
"ENABLE_FEAT_F4HWN_VOL": false,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO": false,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO_SCOPE": false,
|
||||
"ENABLE_FEAT_F4HWN_RESET_VFO": true,
|
||||
"ENABLE_FEAT_F4HWN_PMR": false,
|
||||
"ENABLE_FEAT_F4HWN_GMRS_FRS_MURS": false,
|
||||
@@ -70,7 +71,7 @@
|
||||
"ENABLE_UART_RW_BK_REGS": false,
|
||||
"ENABLE_SWD": false,
|
||||
"VERSION_STRING_1": "v0.22",
|
||||
"VERSION_STRING_2": "v5.2.0"
|
||||
"VERSION_STRING_2": "v5.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -189,6 +190,7 @@
|
||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
||||
"ENABLE_FEAT_F4HWN_VOL": true,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO": true,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO_SCOPE": true,
|
||||
"ENABLE_SWD": true,
|
||||
"EDITION_STRING": "Fusion",
|
||||
"TARGET": "f4hwn.fusion"
|
||||
|
||||
@@ -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 (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 🙏🏻
|
||||
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, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER and Brian WA6JFK for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Reference in new issue
Block a user