diff --git a/app/app.c b/app/app.c index 55604fa..c86fdc3 100644 --- a/app/app.c +++ b/app/app.c @@ -1319,7 +1319,7 @@ void APP_CheckKeys(void) { // PTT pressed if (++gPttDebounceCounter >= 3) // 30ms { // start transmitting - boot_counter_10ms = 0; + boot_counter_10ms = 0; // cancel the boot-up screen gPttDebounceCounter = 0; gPttIsPressed = true; APP_ProcessKey(KEY_PTT, true, false); @@ -1333,8 +1333,16 @@ void APP_CheckKeys(void) // scan the hardware keys Key = KEYBOARD_Poll(); - if (Key != KEY_INVALID) - boot_counter_10ms = 0; // cancel boot screen/beeps if any key pressed + if (Key == KEY_INVALID) + { +// gKeyReading0 = KEY_INVALID; +// gKeyReading1 = KEY_INVALID; +// gDebounceCounter = 0; +// gKeyBeingHeld = false; +// return; + } + + boot_counter_10ms = 0; // cancel boot screen/beeps if (gKeyReading0 != Key) { // new key pressed @@ -1549,9 +1557,11 @@ void APP_TimeSlice10ms(void) if (gScanDelay_10ms > 0) { - gScanDelay_10ms--; - APP_CheckKeys(); - return; + if (--gScanDelay_10ms > 0) + { + APP_CheckKeys(); + return; + } } if (gScannerEditState != SCAN_EDIT_STATE_NONE) @@ -1564,36 +1574,33 @@ void APP_TimeSlice10ms(void) { case SCAN_CSS_STATE_OFF: - // must be RF frequency scanning if we're here ? - if (!BK4819_GetFrequencyScanResult(&Result)) break; + // accept only within 1kHz Delta = Result - gScanFrequency; + gScanHitCount = (abs(Delta) < 100) ? gScanHitCount + 1 : 0; + + BK4819_DisableFrequencyScan(); #if 0 gScanFrequency = Result; #else - { + { // round to nearest step multiple const uint32_t step = StepFrequencyTable[gStepSetting]; - gScanFrequency = ((Result + (step / 2)) / step) * step; // round to nearest step multiple -// gScanFrequency = (Result / step) * step; // round down + gScanFrequency = ((Result + (step / 2)) / step) * step; } #endif - Delta = abs(Delta); - - gScanHitCount = (Delta < 100) ? gScanHitCount + 1 : 0; - - BK4819_DisableFrequencyScan(); - if (gScanHitCount < 3) - { + { // keep scanning for an RF carrier BK4819_EnableFrequencyScan(); } else - { + { // RF carrier found .. stop RF scanning BK4819_SetScanFrequency(gScanFrequency); + + // start CTCSS/CTDSS scanning gScanCssResultCode = 0xFF; gScanCssResultType = 0xFF; gScanHitCount = 0; @@ -1602,12 +1609,10 @@ void APP_TimeSlice10ms(void) gScanCssState = SCAN_CSS_STATE_SCANNING; GUI_SelectNextDisplay(DISPLAY_SCANNER); - - gUpdateStatus = true; + gUpdateStatus = true; } - gScanDelay_10ms = scan_delay_10ms; - //gScanDelay_10ms = 1; // 10ms + gScanDelay_10ms = scan_freq_css_delay_10ms; break; case SCAN_CSS_STATE_SCANNING: @@ -1652,10 +1657,10 @@ void APP_TimeSlice10ms(void) } } - if (gScanCssState < SCAN_CSS_STATE_FOUND) - { + if (gScanCssState == SCAN_CSS_STATE_OFF || gScanCssState == SCAN_CSS_STATE_SCANNING) + { // re-start scan BK4819_SetScanFrequency(gScanFrequency); - gScanDelay_10ms = scan_delay_10ms; + gScanDelay_10ms = scan_freq_css_delay_10ms; break; } @@ -1686,22 +1691,22 @@ void APP_TimeSlice10ms(void) void cancelUserInputModes(void) { - gKeyInputCountdown = 0; - - if (gDTMF_InputMode || gDTMF_InputBox_Index > 0 || gInputBoxIndex > 0) + if (gDTMF_InputMode || gDTMF_InputBox_Index > 0) { DTMF_clear_input_box(); - gInputBoxIndex = 0; gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; gRequestDisplayScreen = DISPLAY_MAIN; gUpdateDisplay = true; } - if (gWasFKeyPressed) + if (gWasFKeyPressed || gKeyInputCountdown > 0 || gInputBoxIndex > 0) { - gWasFKeyPressed = false; - gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; - gUpdateStatus = true; + gWasFKeyPressed = false; + gInputBoxIndex = 0; + gKeyInputCountdown = 0; + gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; + gUpdateStatus = true; + gUpdateDisplay = true; } } @@ -1997,7 +2002,6 @@ void APP_TimeSlice500ms(void) if (gDTMF_DecodeRingCountdown_500ms > 0) { // make "ring-ring" sound gDTMF_DecodeRingCountdown_500ms--; - AUDIO_PlayBeep(BEEP_880HZ_200MS); } } @@ -2012,10 +2016,19 @@ void APP_TimeSlice500ms(void) { if (--gDTMF_auto_reset_time_500ms == 0) { - gDTMF_CallState = DTMF_CALL_STATE_NONE; + if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED && gEeprom.DTMF_auto_reset_time >= DTMF_HOLD_MAX) + gDTMF_CallState = DTMF_CALL_STATE_RECEIVED_STAY; // keep message on-screen till a key is pressed + else + gDTMF_CallState = DTMF_CALL_STATE_NONE; gUpdateDisplay = true; } } + +// if (gDTMF_CallState != DTMF_CALL_STATE_RECEIVED_STAY) +// { +// gDTMF_CallState = DTMF_CALL_STATE_NONE; +// gUpdateDisplay = true; +// } } if (gDTMF_IsTx && gDTMF_TxStopCountdown_500ms > 0) @@ -2083,12 +2096,12 @@ void CHANNEL_Next(const bool bFlag, const int8_t scan_direction) bScanKeepFrequency = false; } -static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) +static void APP_ProcessKey(const KEY_Code_t Key, const bool bKeyPressed, const bool bKeyHeld) { bool bFlag = false; - if (Key == KEY_INVALID) - return; +// if (Key == KEY_INVALID) +// return; const bool backlight_was_on = GPIO_CheckBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); @@ -2142,7 +2155,7 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) } else { - if (Key != KEY_PTT) + if (Key != KEY_PTT || gSetting_backlight_on_tx_rx == 1 || gSetting_backlight_on_tx_rx == 3) BACKLIGHT_TurnOn(); if (Key == KEY_EXIT && bKeyHeld) @@ -2155,6 +2168,9 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) gDTMF_RX_live_timeout = 0; gUpdateDisplay = true; } + + // cancel user input + cancelUserInputModes(); } if (gScreenToDisplay == DISPLAY_MENU) // 1of11 @@ -2232,7 +2248,6 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { if (bKeyHeld) bFlag = true; - if (!bKeyPressed) { bFlag = true; @@ -2334,7 +2349,7 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { case DISPLAY_MAIN: MAIN_ProcessKeys(Key, bKeyPressed, bKeyHeld); - bKeyHeld = false; // allow the channel setting to be saved +// bKeyHeld = false; // allow the channel setting to be saved break; #ifdef ENABLE_FMRADIO @@ -2375,9 +2390,6 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) if (!bKeyHeld && bKeyPressed) gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; } - else - if (Key == KEY_EXIT && bKeyHeld) - cancelUserInputModes(); Skip: if (gBeepToPlay != BEEP_NONE) @@ -2399,7 +2411,6 @@ Skip: if (gFlagStopScan) { BK4819_StopScan(); - gFlagStopScan = false; } @@ -2506,6 +2517,8 @@ Skip: if (gFlagStartScan) { + gFlagStartScan = false; + gMonitor = false; #ifdef ENABLE_VOICE @@ -2516,7 +2529,6 @@ Skip: SCANNER_Start(); gRequestDisplayScreen = DISPLAY_SCANNER; - gFlagStartScan = false; } if (gFlagPrepareTX) @@ -2536,6 +2548,7 @@ Skip: #endif GUI_SelectNextDisplay(gRequestDisplayScreen); - gRequestDisplayScreen = DISPLAY_INVALID; + + gUpdateDisplay = true; } diff --git a/app/dtmf.h b/app/dtmf.h index 8fc70a0..d06ba86 100644 --- a/app/dtmf.h +++ b/app/dtmf.h @@ -33,7 +33,8 @@ typedef enum DTMF_State_t DTMF_State_t; enum DTMF_CallState_t { DTMF_CALL_STATE_NONE = 0, DTMF_CALL_STATE_CALL_OUT, - DTMF_CALL_STATE_RECEIVED + DTMF_CALL_STATE_RECEIVED, + DTMF_CALL_STATE_RECEIVED_STAY }; enum DTMF_DecodeResponse_t { @@ -60,6 +61,11 @@ enum DTMF_CallMode_t { DTMF_CALL_MODE_DTMF }; +enum { // seconds + DTMF_HOLD_MIN = 5, + DTMF_HOLD_MAX = 60 +}; + typedef enum DTMF_CallMode_t DTMF_CallMode_t; extern char gDTMF_String[15]; diff --git a/app/generic.c b/app/generic.c index 0bfa0d8..54a43e4 100644 --- a/app/generic.c +++ b/app/generic.c @@ -119,158 +119,154 @@ void GENERIC_Key_PTT(bool bKeyPressed) gInputBoxIndex = 0; if (!bKeyPressed || gSerialConfigCountDown_500ms > 0) - { - //if (gScreenToDisplay == DISPLAY_MAIN) - { - if (gCurrentFunction == FUNCTION_TRANSMIT) + { // PTT released + + if (gCurrentFunction == FUNCTION_TRANSMIT) + { // we are transmitting .. stop + + if (gFlagEndTransmission) { - if (gFlagEndTransmission) - { - FUNCTION_Select(FUNCTION_FOREGROUND); - } - else - { - APP_EndTransmission(); - - if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0) - { - FUNCTION_Select(FUNCTION_FOREGROUND); - } - else - gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10; - } - - gFlagEndTransmission = false; - #ifdef ENABLE_VOX - gVOX_NoiseDetected = false; - #endif + FUNCTION_Select(FUNCTION_FOREGROUND); } + else + { + APP_EndTransmission(); + + if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0) + FUNCTION_Select(FUNCTION_FOREGROUND); + else + gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10; + } + + gFlagEndTransmission = false; + + #ifdef ENABLE_VOX + gVOX_NoiseDetected = false; + #endif RADIO_SetVfoState(VFO_STATE_NORMAL); if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu gRequestDisplayScreen = DISPLAY_MAIN; - - return; } + return; + } + + // PTT pressed + + if (gScanStateDir != SCAN_OFF || // frequency/channel scanning + gScreenToDisplay == DISPLAY_SCANNER || // CTCSS/CDCSS scanning + gCssScanMode != CSS_SCAN_MODE_OFF) // " " + { // we're scanning .. stop + + if (gScreenToDisplay == DISPLAY_SCANNER) + { // CTCSS/CDCSS scanning .. stop + gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX; + gFlagStopScan = true; + gVfoConfigureMode = VFO_CONFIGURE_RELOAD; + gFlagResetVfos = true; + } + else + if (gScanStateDir != SCAN_OFF) + { // frequency/channel scanning . .stop + SCANNER_Stop(); + } + else + if (gCssScanMode != CSS_SCAN_MODE_OFF) + { // CTCSS/CDCSS scanning .. stop + MENU_StopCssScan(); + + #ifdef ENABLE_VOICE + gAnotherVoiceID = VOICE_ID_SCANNING_STOP; + #endif + } + + goto cancel_tx; + } + + #ifdef ENABLE_FMRADIO + if (gFM_ScanState != FM_SCAN_OFF) + { // FM radio is scanning .. stop + FM_PlayAndUpdate(); + #ifdef ENABLE_VOICE + gAnotherVoiceID = VOICE_ID_SCANNING_STOP; + #endif + gRequestDisplayScreen = DISPLAY_FM; + goto cancel_tx; + } + #endif + + #ifdef ENABLE_FMRADIO + if (gScreenToDisplay == DISPLAY_FM) + goto start_tx; // listening to the FM radio .. start TX'ing + #endif + + if (gCurrentFunction == FUNCTION_TRANSMIT && gRTTECountdown == 0) + { // already transmitting gInputBoxIndex = 0; return; } - if (gScanStateDir != SCAN_OFF) - { - SCANNER_Stop(); + if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu + gRequestDisplayScreen = DISPLAY_MAIN; - gPttDebounceCounter = 0; - gPttIsPressed = false; + if (!gDTMF_InputMode && gDTMF_InputBox_Index == 0) + goto start_tx; // wasn't entering a DTMF code .. start TX'ing (maybe) - if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu - gRequestDisplayScreen = DISPLAY_MAIN; + // was entering a DTMF string - return; + if (gDTMF_InputBox_Index > 0 || gDTMF_PreviousIndex > 0) + { // going to transmit a DTMF string + + if (gDTMF_InputBox_Index == 0 && gDTMF_PreviousIndex > 0) + gDTMF_InputBox_Index = gDTMF_PreviousIndex; // use the previous DTMF string + + if (gDTMF_InputBox_Index < sizeof(gDTMF_InputBox)) + gDTMF_InputBox[gDTMF_InputBox_Index] = 0; // NULL term the string + + #if 0 + // append our DTMF ID to the inputted DTMF code - + // IF the user inputted code is exactly 3 digits long + if (gDTMF_InputBox_Index == 3) + gDTMF_CallMode = DTMF_CheckGroupCall(gDTMF_InputBox, 3); + else + gDTMF_CallMode = DTMF_CALL_MODE_DTMF; + #else + // append our DTMF ID to the inputted DTMF code - + // IF the user inputted code is exactly 3 digits long and D-DCD is enabled + if (gDTMF_InputBox_Index == 3 && gTxVfo->DTMF_DECODING_ENABLE > 0) + gDTMF_CallMode = DTMF_CheckGroupCall(gDTMF_InputBox, 3); + else + gDTMF_CallMode = DTMF_CALL_MODE_DTMF; + #endif + + // remember the DTMF string + gDTMF_PreviousIndex = gDTMF_InputBox_Index; + strcpy(gDTMF_String, gDTMF_InputBox); + + gDTMF_ReplyState = DTMF_REPLY_ANI; + gDTMF_State = DTMF_STATE_0; } - #ifdef ENABLE_FMRADIO - if (gFM_ScanState == FM_SCAN_OFF) - #endif + DTMF_clear_input_box(); + +start_tx: + // request start TX + gFlagPrepareTX = true; + goto done; + +cancel_tx: + if (gPttIsPressed) { - if (gCssScanMode == CSS_SCAN_MODE_OFF) - { - #ifdef ENABLE_FMRADIO - if (gScreenToDisplay == DISPLAY_FM) - { - gRequestDisplayScreen = DISPLAY_MAIN; - gInputBoxIndex = 0; - gPttIsPressed = false; - gPttDebounceCounter = 0; - return; - } - #endif - - if (gScreenToDisplay != DISPLAY_SCANNER) - { - if (gCurrentFunction == FUNCTION_TRANSMIT && gRTTECountdown == 0) - { - gInputBoxIndex = 0; - return; - } - - if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu - gRequestDisplayScreen = DISPLAY_MAIN; - - if (!gDTMF_InputMode) - { - gFlagPrepareTX = true; - gInputBoxIndex = 0; - return; - } - - gDTMF_InputMode = false; -// gUpdateDisplay = true; - - if (gDTMF_InputBox_Index > 0 || gDTMF_PreviousIndex > 0) - { - if (gDTMF_InputBox_Index == 0) - gDTMF_InputBox_Index = gDTMF_PreviousIndex; - - if (gDTMF_InputBox_Index < sizeof(gDTMF_InputBox)) - gDTMF_InputBox[gDTMF_InputBox_Index] = 0; - - #if 0 - // append our DTMF ID to the inputted DTMF code - - // IF the user inputted code is exactly 3 digits long - if (gDTMF_InputBox_Index == 3) - gDTMF_CallMode = DTMF_CheckGroupCall(gDTMF_InputBox, 3); - else - #else - // append our DTMF ID to the inputted DTMF code - - // IF the user inputted code is exactly 3 digits long and D-DCD is enabled - if (gDTMF_InputBox_Index == 3 && gTxVfo->DTMF_DECODING_ENABLE > 0) - gDTMF_CallMode = DTMF_CheckGroupCall(gDTMF_InputBox, 3); - else - #endif - gDTMF_CallMode = DTMF_CALL_MODE_DTMF; - - strcpy(gDTMF_String, gDTMF_InputBox); - gDTMF_PreviousIndex = gDTMF_InputBox_Index; - DTMF_clear_input_box(); - - gDTMF_ReplyState = DTMF_REPLY_ANI; - gDTMF_State = DTMF_STATE_0; - - gFlagPrepareTX = true; - } - - return; - } - - gEeprom.CROSS_BAND_RX_TX = gBackupCROSS_BAND_RX_TX; - gFlagStopScan = true; - gVfoConfigureMode = VFO_CONFIGURE_RELOAD; - gFlagResetVfos = true; - - gUpdateStatus = true; - } - else - { - MENU_StopCssScan(); - - if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu - gRequestDisplayScreen = DISPLAY_MENU; - } + gPttIsPressed = false; + gPttWasPressed = true; } - #ifdef ENABLE_FMRADIO - else - { - FM_PlayAndUpdate(); - gRequestDisplayScreen = DISPLAY_FM; - } - #endif - #ifdef ENABLE_VOICE - gAnotherVoiceID = VOICE_ID_SCANNING_STOP; - #endif - - gPttWasPressed = true; +done: + gPttDebounceCounter = 0; + if (gScreenToDisplay != DISPLAY_MENU && gRequestDisplayScreen != DISPLAY_FM) // 1of11 .. don't close the menu + gRequestDisplayScreen = DISPLAY_MAIN; + gUpdateStatus = true; + gUpdateDisplay = true; } diff --git a/app/main.c b/app/main.c index 1a14d3e..6040439 100644 --- a/app/main.c +++ b/app/main.c @@ -195,12 +195,12 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep) gWasFKeyPressed = false; gFlagStartScan = true; gScanSingleFrequency = false; - gBackupCROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; + 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; +// if (beep) +// gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; break; @@ -700,7 +700,7 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld) // scan the CTCSS/DCS code gFlagStartScan = true; gScanSingleFrequency = true; - gBackupCROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; + gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; } @@ -821,31 +821,25 @@ void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) } #endif - if (gDTMF_InputMode && bKeyPressed) + if (gDTMF_InputMode && bKeyPressed && !bKeyHeld) { - if (!bKeyHeld) - { - const char Character = DTMF_GetCharacter(Key); - if (Character != 0xFF) - { // add key to DTMF string - DTMF_Append(Character); - - gKeyInputCountdown = key_input_timeout_500ms; - - gRequestDisplayScreen = DISPLAY_MAIN; - - gPttWasReleased = true; - gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; - return; - } + const char Character = DTMF_GetCharacter(Key); + if (Character != 0xFF) + { // add key to DTMF string + DTMF_Append(Character); + gKeyInputCountdown = key_input_timeout_500ms; + gRequestDisplayScreen = DISPLAY_MAIN; + gPttWasReleased = true; + gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; + return; } } // TODO: ??? - if (Key > KEY_PTT) - { - Key = KEY_SIDE2; // what's this doing ??? - } +// if (Key > KEY_PTT) +// { +// Key = KEY_SIDE2; // what's this doing ??? +// } switch (Key) { diff --git a/app/menu.c b/app/menu.c index 6f259f6..545c696 100644 --- a/app/menu.c +++ b/app/menu.c @@ -314,8 +314,8 @@ int MENU_GetLimits(uint8_t Cursor, int32_t *pMin, int32_t *pMax) break; case MENU_D_HOLD: - *pMin = 5; - *pMax = 60; + *pMin = DTMF_HOLD_MIN; + *pMax = DTMF_HOLD_MAX; break; case MENU_D_PRE: @@ -1079,6 +1079,30 @@ void MENU_ShowCurrentSetting(void) case MENU_D_HOLD: gSubMenuSelection = gEeprom.DTMF_auto_reset_time; + + if (gSubMenuSelection <= DTMF_HOLD_MIN) + gSubMenuSelection = DTMF_HOLD_MIN; + else + if (gSubMenuSelection <= 10) + gSubMenuSelection = 10; + else + if (gSubMenuSelection <= 20) + gSubMenuSelection = 20; + else + if (gSubMenuSelection <= 30) + gSubMenuSelection = 30; + else + if (gSubMenuSelection <= 40) + gSubMenuSelection = 40; + else + if (gSubMenuSelection <= 50) + gSubMenuSelection = 50; + else + if (gSubMenuSelection < DTMF_HOLD_MAX) + gSubMenuSelection = 50; + else + gSubMenuSelection = DTMF_HOLD_MAX; + break; case MENU_D_PRE: diff --git a/app/scanner.c b/app/scanner.c index 07c95fd..b0e1046 100644 --- a/app/scanner.c +++ b/app/scanner.c @@ -95,7 +95,7 @@ static void SCANNER_Key_EXIT(bool bKeyPressed, bool bKeyHeld) case SCAN_EDIT_STATE_NONE: gRequestDisplayScreen = DISPLAY_MAIN; - gEeprom.CROSS_BAND_RX_TX = gBackupCROSS_BAND_RX_TX; + gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX; gUpdateStatus = true; gFlagStopScan = true; gVfoConfigureMode = VFO_CONFIGURE_RELOAD; @@ -166,8 +166,6 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld) { #if 0 - // can't make head nor tail of what's being done here :( - uint32_t Freq250 = FREQUENCY_FloorToStep(gScanFrequency, 250, 0); uint32_t Freq625 = FREQUENCY_FloorToStep(gScanFrequency, 625, 0); @@ -207,6 +205,7 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld) const STEP_Setting_t small_step = STEP_2_5kHz; const STEP_Setting_t big_step = STEP_6_25kHz; #endif + const uint32_t small_step_freq = StepFrequencyTable[small_step]; const uint32_t big_step_freq = StepFrequencyTable[big_step]; @@ -254,12 +253,13 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld) gScannerEditState = SCAN_EDIT_STATE_DONE; } - gScanCssState = SCAN_CSS_STATE_FOUND; - #ifdef ENABLE_VOICE - gAnotherVoiceID = VOICE_ID_MEMORY_CHANNEL; - #endif - gRequestDisplayScreen = DISPLAY_SCANNER; + gScanCssState = SCAN_CSS_STATE_FOUND; + #ifdef ENABLE_VOICE + gAnotherVoiceID = VOICE_ID_MEMORY_CHANNEL; + #endif + + gRequestDisplayScreen = DISPLAY_SCANNER; gUpdateStatus = true; break; @@ -452,7 +452,7 @@ void SCANNER_Start(void) DTMF_clear_RX(); - gScanDelay_10ms = scan_delay_10ms; + gScanDelay_10ms = scan_freq_css_delay_10ms; gScanCssResultCode = 0xFF; gScanCssResultType = 0xFF; gScanHitCount = 0; @@ -467,6 +467,7 @@ void SCANNER_Start(void) g_SquelchLost = false; gScannerEditState = SCAN_EDIT_STATE_NONE; gScanProgressIndicator = 0; +// gFlagStartScan = false; gUpdateStatus = true; } @@ -475,6 +476,9 @@ void SCANNER_Stop(void) { const uint8_t Previous = gRestoreMrChannel; + if (gScanStateDir == SCAN_OFF) + return; // but, but, we weren't ! + gScanStateDir = SCAN_OFF; if (!bScanKeepFrequency) diff --git a/app/spectrum.c b/app/spectrum.c index 9d00b86..1169f96 100644 --- a/app/spectrum.c +++ b/app/spectrum.c @@ -16,40 +16,23 @@ #include "../app/spectrum.h" -struct FrequencyBandInfo { - uint32_t lower; - uint32_t upper; - uint32_t middle; -}; - -const struct FrequencyBandInfo FrequencyBandTable[7] = { - [BAND1_50MHz ] = {.lower = 1600000, .middle = 6500000, .upper = 7600000}, - [BAND2_108MHz] = {.lower = 10800000, .middle = 12200000, .upper = 13599990}, - [BAND3_136MHz] = {.lower = 13600000, .middle = 15000000, .upper = 17399990}, - [BAND4_174MHz] = {.lower = 17400000, .middle = 26000000, .upper = 34999990}, - [BAND5_350MHz] = {.lower = 35000000, .middle = 37000000, .upper = 39999990}, - [BAND6_400MHz] = {.lower = 40000000, .middle = 43500000, .upper = 46999990}, - [BAND7_470MHz] = {.lower = 47000000, .middle = 55000000, .upper = 130000000}, -}; - - #define F_MIN FrequencyBandTable[0].lower #define F_MAX FrequencyBandTable[ARRAY_SIZE(FrequencyBandTable) - 1].upper const uint16_t RSSI_MAX_VALUE = 65535; -static uint16_t R30, R37, R3D, R43, R47, R48, R7E; static uint32_t initialFreq; static char String[32]; bool isInitialized = false; -bool isListening = true; bool monitorMode = false; bool redrawStatus = true; bool redrawScreen = false; bool newScanStart = true; bool preventKeypress = true; -bool audioState = true; + +bool isListening = false; +bool isTransmitting = false; State currentState = SPECTRUM, previousState = SPECTRUM; @@ -62,125 +45,96 @@ const char *modulationTypeOptions[] = {" FM", " AM", "USB"}; const uint8_t modulationTypeTuneSteps[] = {100, 50, 10}; const uint8_t modTypeReg47Values[] = {1, 7, 5}; -SpectrumSettings settings = {stepsCount: STEPS_64, - scanStepIndex: S_STEP_25_0kHz, - frequencyChangeStep: 80000, - scanDelay: 3200, - rssiTriggerLevel: 150, - backlightState: true, - bw: BK4819_FILTER_BW_WIDE, - listenBw: BK4819_FILTER_BW_WIDE, - modulationType: false, - dbMin: -130, - dbMax: -50}; +SpectrumSettings settings = { + .stepsCount = STEPS_64, + .scanStepIndex = S_STEP_25_0kHz, + .frequencyChangeStep = 80000, + .scanDelay = 3200, + .rssiTriggerLevel = 150, + .backlightState = true, + .bw = BK4819_FILTER_BW_WIDE, + .listenBw = BK4819_FILTER_BW_WIDE, + .modulationType = false, +}; uint32_t fMeasure = 0; +uint32_t fTx = 0; uint32_t currentFreq, tempFreq; -uint16_t rssiHistory[128] = {}; +uint16_t rssiHistory[128] = {0}; +bool blacklist[128] = {false}; -uint8_t freqInputIndex = 0; -uint8_t freqInputDotIndex = 0; -KEY_Code_t freqInputArr[10]; -char freqInputString[11] = "----------\0"; // XXXX.XXXXX\0 - -uint8_t menuState = 0; -uint16_t listenT = 0; - -RegisterSpec registerSpecs[] = { +static const RegisterSpec afOutRegSpec = {"AF OUT", 0x47, 8, 0xF, 1}; +static const RegisterSpec afDacGainRegSpec = {"AF DAC G", 0x48, 0, 0xF, 1}; +static const RegisterSpec registerSpecs[] = { {}, {"LNAs", 0x13, 8, 0b11, 1}, {"LNA", 0x13, 5, 0b111, 1}, {"PGA", 0x13, 0, 0b111, 1}, - {"IF", 0x3D, 0, 0xFFFF, 0x2aaa}, - // {"MIX", 0x13, 3, 0b11, 1}, // TODO: hidden + {"MIX", 0x13, 3, 0b11, 1}, + + {"DEV", 0x40, 0, 4095, 1}, + {"CMP", 0x31, 3, 1, 1}, + {"MIC", 0x7D, 0, 0x1F, 1}, }; -uint16_t statuslineUpdateTimer = 0; +static uint16_t registersBackup[128]; +static const uint8_t registersToBackup[] = { + 0x13, 0x30, 0x31, 0x37, 0x3D, 0x40, 0x43, 0x47, 0x48, 0x7D, 0x7E, +}; -static uint8_t DBm2S(int dbm) { - uint8_t i = 0; - dbm *= -1; - for (i = 0; i < ARRAY_SIZE(U8RssiMap); i++) { - if (dbm >= U8RssiMap[i]) { - return i; - } +static MovingAverage mov = {{128}, {}, 255, 128, 0, 0}; +static const uint8_t MOV_N = ARRAY_SIZE(mov.buf); + +const uint8_t FREQ_INPUT_LENGTH = 10; +uint8_t freqInputIndex = 0; +uint8_t freqInputDotIndex = 0; +KEY_Code_t freqInputArr[10]; +char freqInputString[] = "----------"; // XXXX.XXXXX + +uint8_t menuState = 0; + +uint16_t listenT = 0; + +uint16_t batteryUpdateTimer = 0; +bool isMovingInitialized = false; +uint8_t lastStepsCount = 0; + +uint8_t CountBits(uint16_t n) { + uint8_t count = 0; + while (n) { + count++; + n >>= 1; } - return i; + return count; } -static int Rssi2DBm(uint16_t rssi) { return (rssi >> 1) - 160; } +static uint16_t GetRegMask(RegisterSpec s) { + return (1 << CountBits(s.maxValue)) - 1; +} -static uint16_t GetRegMenuValue(uint8_t st) { - RegisterSpec s = registerSpecs[st]; +static uint16_t GetRegValue(RegisterSpec s) { return (BK4819_ReadRegister(s.num) >> s.offset) & s.maxValue; } -static void SetRegMenuValue(uint8_t st, bool add) { - uint16_t v = GetRegMenuValue(st); - RegisterSpec s = registerSpecs[st]; - +static void SetRegValue(RegisterSpec s, uint16_t v) { uint16_t reg = BK4819_ReadRegister(s.num); + reg &= ~(GetRegMask(s) << s.offset); + BK4819_WriteRegister(s.num, reg | (v << s.offset)); +} + +static void UpdateRegMenuValue(RegisterSpec s, bool add) { + uint16_t v = GetRegValue(s); + if (add && v <= s.maxValue - s.inc) { v += s.inc; } else if (!add && v >= 0 + s.inc) { v -= s.inc; } - // TODO: use max value for bits count in max value, or reset by additional - // mask in spec - reg &= ~(s.maxValue << s.offset); - BK4819_WriteRegister(s.num, reg | (v << s.offset)); + + SetRegValue(s, v); redrawScreen = true; } -// GUI functions - -static void PutPixel(uint8_t x, uint8_t y, bool fill) { - if (fill) { - gFrameBuffer[y >> 3][x] |= 1 << (y & 7); - } else { - gFrameBuffer[y >> 3][x] &= ~(1 << (y & 7)); - } -} -static void PutPixelStatus(uint8_t x, uint8_t y, bool fill) { - if (fill) { - gStatusLine[x] |= 1 << y; - } else { - gStatusLine[x] &= ~(1 << y); - } -} - -static void DrawHLine(int sy, int ey, int nx, bool fill) { - for (int i = sy; i <= ey; i++) { - if (i < 56 && nx < 128) { - PutPixel(nx, i, fill); - } - } -} - -static void GUI_DisplaySmallest(const char *pString, uint8_t x, uint8_t y, - bool statusbar, bool fill) { - uint8_t c; - uint8_t pixels; - const uint8_t *p = (const uint8_t *)pString; - - while ((c = *p++) && c != '\0') { - c -= 0x20; - for (int i = 0; i < 3; ++i) { - pixels = gFont3x5[c][i]; - for (int j = 0; j < 6; ++j) { - if (pixels & 1) { - if (statusbar) - PutPixelStatus(x + i, y + j, fill); - else - PutPixel(x + i, y + j, fill); - } - pixels >>= 1; - } - } - x += 4; - } -} - // Utility functions KEY_Code_t GetKey() { @@ -191,12 +145,6 @@ KEY_Code_t GetKey() { return btn; } -static int clamp(int v, int min, int max) { - return v <= min ? min : (v >= max ? max : v); -} - -static uint8_t my_abs(signed v) { return v > 0 ? v : -v; } - void SetState(State state) { previousState = currentState; currentState = state; @@ -206,52 +154,37 @@ void SetState(State state) { // Radio functions -static void ToggleAFBit(bool on) { - uint16_t reg = BK4819_ReadRegister(BK4819_REG_47); - reg &= ~(1 << 8); - if (on) - reg |= on << 8; - BK4819_WriteRegister(BK4819_REG_47, reg); -} - static void BackupRegisters() { - R30 = BK4819_ReadRegister(0x30); - R37 = BK4819_ReadRegister(0x37); - R3D = BK4819_ReadRegister(0x3D); - R43 = BK4819_ReadRegister(0x43); - R47 = BK4819_ReadRegister(0x47); - R48 = BK4819_ReadRegister(0x48); - R7E = BK4819_ReadRegister(0x7E); -} - -static void RestoreRegisters() { - BK4819_WriteRegister(0x30, R30); - BK4819_WriteRegister(0x37, R37); - BK4819_WriteRegister(0x3D, R3D); - BK4819_WriteRegister(0x43, R43); - BK4819_WriteRegister(0x47, R47); - BK4819_WriteRegister(0x48, R48); - BK4819_WriteRegister(0x7E, R7E); -} - -static void SetModulation(ModulationType type) { - RestoreRegisters(); - uint16_t reg = BK4819_ReadRegister(BK4819_REG_47); - reg &= ~(0b111 << 8); - BK4819_WriteRegister(BK4819_REG_47, reg | (modTypeReg47Values[type] << 8)); - if (type == MOD_USB) { - BK4819_WriteRegister(0x3D, 0b0010101101000101); - BK4819_WriteRegister(BK4819_REG_37, 0x160F); - BK4819_WriteRegister(0x48, 0b0000001110101000); + for (int i = 0; i < ARRAY_SIZE(registersToBackup); ++i) { + uint8_t regNum = registersToBackup[i]; + registersBackup[regNum] = BK4819_ReadRegister(regNum); } } -static void ToggleAFDAC(bool on) { - uint32_t Reg = BK4819_ReadRegister(BK4819_REG_30); - Reg &= ~(1 << 9); - if (on) - Reg |= (1 << 9); - BK4819_WriteRegister(BK4819_REG_30, Reg); +static void RestoreRegisters() { + for (int i = 0; i < ARRAY_SIZE(registersToBackup); ++i) { + uint8_t regNum = registersToBackup[i]; + BK4819_WriteRegister(regNum, registersBackup[regNum]); + } +} + +static void SetModulation(ModulationType type) { + // restore only registers, which we affect here fully + BK4819_WriteRegister(0x37, registersBackup[0x37]); + BK4819_WriteRegister(0x3D, registersBackup[0x3D]); + BK4819_WriteRegister(0x48, registersBackup[0x48]); + + SetRegValue(afOutRegSpec, modTypeReg47Values[type]); + + if (type == MOD_USB) { + BK4819_WriteRegister(0x37, 0b0001011000001111); + BK4819_WriteRegister(0x3D, 0b0010101101000101); + BK4819_WriteRegister(0x48, 0b0000001110101000); + } + + if (type == MOD_AM) { + SetRegValue(afDacGainRegSpec, 0xE); + } } static void SetF(uint32_t f) { @@ -264,6 +197,15 @@ static void SetF(uint32_t f) { BK4819_WriteRegister(BK4819_REG_30, reg); } +static void SetTxF(uint32_t f) { + fTx = f; + BK4819_SetFrequency(f); + BK4819_PickRXFilterPathBasedOnFrequency(f); + uint16_t reg = BK4819_ReadRegister(BK4819_REG_30); + BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_WriteRegister(BK4819_REG_30, reg); +} + // Spectrum related bool IsPeakOverLevel() { return peak.rssi >= settings.rssiTriggerLevel; } @@ -273,7 +215,7 @@ static void ResetPeak() { peak.rssi = 0; } -bool IsCenterMode() { return settings.scanStepIndex < S_STEP_2_5kHz; } +bool IsCenterMode() { return settings.scanStepIndex < S_STEP_1_0kHz; } uint8_t GetStepsCount() { return 128 >> settings.stepsCount; } uint16_t GetScanStep() { return scanStepValues[settings.scanStepIndex]; } uint32_t GetBW() { return GetStepsCount() * GetScanStep(); } @@ -282,6 +224,64 @@ uint32_t GetFStart() { } uint32_t GetFEnd() { return currentFreq + GetBW(); } +static void MovingCp(uint16_t *dst, uint16_t *src) { + memcpy(dst, src, GetStepsCount() * sizeof(uint16_t)); +} + +static void ResetMoving() { + for (int i = 0; i < MOV_N; ++i) { + MovingCp(mov.buf[i], rssiHistory); + } +} + +static void MoveHistory() { + const uint8_t XN = GetStepsCount(); + + uint32_t midSum = 0; + + mov.min = RSSI_MAX_VALUE; + mov.max = 0; + + if (lastStepsCount != XN) { + ResetMoving(); + lastStepsCount = XN; + } + for (int i = MOV_N - 1; i > 0; --i) { + MovingCp(mov.buf[i], mov.buf[i - 1]); + } + MovingCp(mov.buf[0], rssiHistory); + + uint8_t skipped = 0; + + for (int x = 0; x < XN; ++x) { + if (blacklist[x]) { + skipped++; + continue; + } + uint32_t sum = 0; + for (int i = 0; i < MOV_N; ++i) { + sum += mov.buf[i][x]; + } + + uint16_t pointV = mov.mean[x] = sum / MOV_N; + + midSum += pointV; + + if (pointV > mov.max) { + mov.max = pointV; + } + + if (pointV < mov.min) { + mov.min = pointV; + } + } + if (skipped == XN) { + return; + } + + mov.mid = midSum / (XN - skipped); +} + static void TuneToPeak() { scanInfo.f = peak.f; scanInfo.rssi = peak.rssi; @@ -289,30 +289,50 @@ static void TuneToPeak() { SetF(scanInfo.f); } -static void DeInitSpectrum() { - SetF(initialFreq); - RestoreRegisters(); - isInitialized = false; +uint8_t GetBWRegValueForScan() { + return scanStepBWRegValues[settings.scanStepIndex == S_STEP_100_0kHz ? 11 + : 0]; } -uint8_t GetBWRegValueForScan() { - return scanStepBWRegValues[settings.scanStepIndex]; +uint8_t GetBWRegValueForListen() { + return listenBWRegValues[settings.listenBw]; +} + +static void ResetRSSI() { + uint32_t Reg = BK4819_ReadRegister(BK4819_REG_30); + Reg &= ~1; + BK4819_WriteRegister(BK4819_REG_30, Reg); + Reg |= 1; + BK4819_WriteRegister(BK4819_REG_30, Reg); } uint16_t GetRssi() { - // SYSTICK_DelayUs(800); - // testing autodelay based on Glitch value - while ((BK4819_ReadRegister(0x63) & 0b11111111) >= 255) { - SYSTICK_DelayUs(100); + if (currentState == SPECTRUM) { + ResetRSSI(); + SYSTICK_DelayUs(3200); } return BK4819_GetRSSI(); } -static void ToggleAudio(bool on) { - if (on == audioState) { - return; +uint32_t GetOffsetedF(uint32_t f) { + switch (gCurrentVfo->FREQUENCY_DEVIATION_SETTING) { + case FREQUENCY_DEVIATION_OFF: + break; + case FREQUENCY_DEVIATION_ADD: + f += gCurrentVfo->FREQUENCY_OF_DEVIATION; + break; + case FREQUENCY_DEVIATION_SUB: + f -= gCurrentVfo->FREQUENCY_OF_DEVIATION; + break; } - audioState = on; + + return Clamp(f, FrequencyBandTable[0].lower, + FrequencyBandTable[ARRAY_SIZE(FrequencyBandTable) - 1].upper); +} + +bool IsTXAllowed() { return gSetting_ALL_TX != 2; } + +static void ToggleAudio(bool on) { if (on) { GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); } else { @@ -320,23 +340,92 @@ static void ToggleAudio(bool on) { } } +static void ToggleTX(bool); +static void ToggleRX(bool); + static void ToggleRX(bool on) { + /* if (isListening == on) { + return; + } */ isListening = on; + if (on) { + ToggleTX(false); + } BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, on); + BK4819_RX_TurnOn(); ToggleAudio(on); - ToggleAFDAC(on); - ToggleAFBit(on); + BK4819_ToggleAFDAC(on); + BK4819_ToggleAFBit(on); if (on) { listenT = 1000; - BK4819_WriteRegister(0x43, listenBWRegValues[settings.listenBw]); + BK4819_WriteRegister(0x43, GetBWRegValueForListen()); } else { BK4819_WriteRegister(0x43, GetBWRegValueForScan()); } } +uint16_t registersVault[128] = {0}; + +static void RegBackupSet(uint8_t num, uint16_t value) { + registersVault[num] = BK4819_ReadRegister(num); + BK4819_WriteRegister(num, value); +} + +static void RegRestore(uint8_t num) { + BK4819_WriteRegister(num, registersVault[num]); +} + +static void ToggleTX(bool on) { + if (isTransmitting == on) { + return; + } + isTransmitting = on; + if (on) { + ToggleRX(false); + } + + BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_RED, on); + + if (on) { + ToggleAudio(false); + + SetTxF(GetOffsetedF(fMeasure)); + + RegBackupSet(BK4819_REG_47, 0x6040); + RegBackupSet(BK4819_REG_7E, 0x302E); + RegBackupSet(BK4819_REG_50, 0x3B20); + RegBackupSet(BK4819_REG_37, 0x1D0F); + RegBackupSet(BK4819_REG_52, 0x028F); + RegBackupSet(BK4819_REG_30, 0x0000); + BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); + RegBackupSet(BK4819_REG_51, 0x0000); + + BK4819_SetupPowerAmplifier(gCurrentVfo->TXP_CalculatedSetting, + gCurrentVfo->pTX->Frequency); + } else { + RADIO_SendEndOfTransmission(); + RADIO_EnableCxCSS(); + + BK4819_SetupPowerAmplifier(0, 0); + + RegRestore(BK4819_REG_51); + BK4819_WriteRegister(BK4819_REG_30, 0); + RegRestore(BK4819_REG_30); + RegRestore(BK4819_REG_52); + RegRestore(BK4819_REG_37); + RegRestore(BK4819_REG_50); + RegRestore(BK4819_REG_7E); + RegRestore(BK4819_REG_47); + + SetF(fMeasure); + } + BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2, !on); + BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1, on); +} + // Scan info static void ResetScanStats() { @@ -357,14 +446,15 @@ static void InitScan() { static void ResetBlacklist() { for (int i = 0; i < 128; ++i) { - if (rssiHistory[i] == RSSI_MAX_VALUE) - rssiHistory[i] = 0; + if (blacklist[i]) + blacklist[i] = false; } } static void RelaunchScan() { InitScan(); ResetPeak(); + lastStepsCount = 0; ToggleRX(false); #ifdef SPECTRUM_AUTOMATIC_SQUELCH settings.rssiTriggerLevel = RSSI_MAX_VALUE; @@ -382,14 +472,12 @@ static void UpdateScanInfo() { if (scanInfo.rssi < scanInfo.rssiMin) { scanInfo.rssiMin = scanInfo.rssi; - settings.dbMin = Rssi2DBm(scanInfo.rssiMin); - redrawStatus = true; } } static void AutoTriggerLevel() { if (settings.rssiTriggerLevel == RSSI_MAX_VALUE) { - settings.rssiTriggerLevel = clamp(scanInfo.rssiMax + 8, 0, RSSI_MAX_VALUE); + settings.rssiTriggerLevel = Clamp(scanInfo.rssiMax + 4, 0, RSSI_MAX_VALUE); } } @@ -416,20 +504,42 @@ static void UpdateRssiTriggerLevel(bool inc) { else settings.rssiTriggerLevel -= 2; redrawScreen = true; - redrawStatus = true; + SYSTEM_DelayMs(10); } -static void UpdateDBMax(bool inc) { - if (inc && settings.dbMax < 10) { - settings.dbMax += 1; - } else if (!inc && settings.dbMax > settings.dbMin) { - settings.dbMax -= 1; - } else { - return; - } - redrawStatus = true; +static void ApplyPreset(FreqPreset p) { + currentFreq = p.fStart; + settings.scanStepIndex = p.stepSizeIndex; + settings.listenBw = p.listenBW; + settings.modulationType = p.modulationType; + settings.stepsCount = p.stepsCountIndex; + SetModulation(settings.modulationType); + RelaunchScan(); + ResetBlacklist(); redrawScreen = true; - SYSTEM_DelayMs(20); +} + +static void SelectNearestPreset(bool inc) { + FreqPreset p; + const uint8_t SZ = ARRAY_SIZE(freqPresets); + if (inc) { + for (int i = 0; i < SZ; ++i) { + p = freqPresets[i]; + if (currentFreq < p.fStart) { + ApplyPreset(p); + return; + } + } + } else { + for (int i = SZ - 1; i >= 0; --i) { + p = freqPresets[i]; + if (currentFreq > p.fEnd) { + ApplyPreset(p); + return; + } + } + } + ApplyPreset(p); } static void UpdateScanStep(bool inc) { @@ -584,7 +694,7 @@ static void UpdateFreqInput(KEY_Code_t key) { } static void Blacklist() { - rssiHistory[peak.i] = RSSI_MAX_VALUE; + blacklist[peak.i] = true; ResetPeak(); ToggleRX(false); newScanStart = true; @@ -592,70 +702,46 @@ static void Blacklist() { // Draw things -// applied x2 to prevent initial rounding -uint8_t Rssi2PX(uint16_t rssi, uint8_t pxMin, uint8_t pxMax) { - const int DB_MIN = settings.dbMin << 1; - const int DB_MAX = settings.dbMax << 1; - const int DB_RANGE = DB_MAX - DB_MIN; - - const uint8_t PX_RANGE = pxMax - pxMin; - - int dbm = clamp(rssi - (160 << 1), DB_MIN, DB_MAX); - - return ((dbm - DB_MIN) * PX_RANGE + DB_RANGE / 2) / DB_RANGE + pxMin; -} - -uint8_t Rssi2Y(uint16_t rssi) { - return DrawingEndY - Rssi2PX(rssi, 0, DrawingEndY); +static uint8_t Rssi2Y(uint16_t rssi) { + return DrawingEndY - ConvertDomain(rssi, mov.min - 2, + mov.max + 30 + (mov.max - mov.min) / 3, 0, + DrawingEndY); } static void DrawSpectrum() { for (uint8_t x = 0; x < 128; ++x) { - uint16_t rssi = rssiHistory[x >> settings.stepsCount]; - if (rssi != RSSI_MAX_VALUE) { - DrawHLine(Rssi2Y(rssi), DrawingEndY, x, true); + uint8_t i = x >> settings.stepsCount; + if (blacklist[i]) { + continue; + } + uint16_t rssi = rssiHistory[i]; + DrawHLine(Rssi2Y(rssi), DrawingEndY, x, true); + } +} + +static void UpdateBatteryInfo() { + for (int i = 0; i < 4; i++) { + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); + } + + uint16_t voltage = Mid(gBatteryVoltages, ARRAY_SIZE(gBatteryVoltages)); + gBatteryDisplayLevel = 0; + + for (int i = ARRAY_SIZE(gBatteryCalibration) - 1; i >= 0; --i) { + if (gBatteryCalibration[i] < voltage) { + gBatteryDisplayLevel = i + 1; + break; } } } static void DrawStatus() { -#ifdef SPECTRUM_EXTRA_VALUES - sprintf(String, "%d/%d P:%d T:%d", settings.dbMin, settings.dbMax, - Rssi2DBm(peak.rssi), Rssi2DBm(settings.rssiTriggerLevel)); -#else - sprintf(String, "%d/%d", settings.dbMin, settings.dbMax); -#endif - GUI_DisplaySmallest(String, 0, 1, true, true); - - for (int i = 0; i < 4; i++) { - BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); - } - - uint16_t Voltage; - uint8_t v = 0; - - Voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] + - gBatteryVoltages[3]) / - 4; - - if (gBatteryCalibration[5] < Voltage) { - v = 5; - } else if (gBatteryCalibration[4] < Voltage) { - v = 5; - } else if (gBatteryCalibration[3] < Voltage) { - v = 4; - } else if (gBatteryCalibration[2] < Voltage) { - v = 3; - } else if (gBatteryCalibration[1] < Voltage) { - v = 2; - } else if (gBatteryCalibration[0] < Voltage) { - v = 1; - } gStatusLine[127] = 0b01111110; for (int i = 126; i >= 116; i--) { gStatusLine[i] = 0b01000010; } + uint8_t v = gBatteryDisplayLevel; v <<= 1; for (int i = 125; i >= 116; i--) { if (126 - i <= v) { @@ -668,38 +754,48 @@ static void DrawStatus() { static void DrawF(uint32_t f) { sprintf(String, "%u.%05u", f / 100000, f % 100000); + + if (currentState == STILL && kbd.current == KEY_PTT) { + if (gBatteryDisplayLevel == 6) { + sprintf(String, "VOLTAGE HIGH"); + } else if (!IsTXAllowed()) { + sprintf(String, "DISABLED"); + } else { + f = GetOffsetedF(f); + sprintf(String, "TX %u.%05u", f / 100000, f % 100000); + } + } UI_PrintStringSmall(String, 8, 127, 0); sprintf(String, "%s", modulationTypeOptions[settings.modulationType]); - GUI_DisplaySmallest(String, 116, 1, false, true); + UI_PrintStringSmallest(String, 116, 1, false, true); sprintf(String, "%s", bwOptions[settings.listenBw]); - GUI_DisplaySmallest(String, 108, 7, false, true); + UI_PrintStringSmallest(String, 108, 7, false, true); } static void DrawNums() { - if (currentState == SPECTRUM) { sprintf(String, "%ux", GetStepsCount()); - GUI_DisplaySmallest(String, 0, 1, false, true); + UI_PrintStringSmallest(String, 0, 1, false, true); sprintf(String, "%u.%02uk", GetScanStep() / 100, GetScanStep() % 100); - GUI_DisplaySmallest(String, 0, 7, false, true); + UI_PrintStringSmallest(String, 0, 7, false, true); } if (IsCenterMode()) { sprintf(String, "%u.%05u \xB1%u.%02uk", currentFreq / 100000, currentFreq % 100000, settings.frequencyChangeStep / 100, settings.frequencyChangeStep % 100); - GUI_DisplaySmallest(String, 36, 49, false, true); + UI_PrintStringSmallest(String, 36, 49, false, true); } else { sprintf(String, "%u.%05u", GetFStart() / 100000, GetFStart() % 100000); - GUI_DisplaySmallest(String, 0, 49, false, true); + UI_PrintStringSmallest(String, 0, 49, false, true); sprintf(String, "\xB1%u.%02uk", settings.frequencyChangeStep / 100, settings.frequencyChangeStep % 100); - GUI_DisplaySmallest(String, 48, 49, false, true); + UI_PrintStringSmallest(String, 48, 49, false, true); sprintf(String, "%u.%05u", GetFEnd() / 100000, GetFEnd() % 100000); - GUI_DisplaySmallest(String, 93, 49, false, true); + UI_PrintStringSmallest(String, 93, 49, false, true); } } @@ -725,7 +821,7 @@ static void DrawTicks() { } // center - if (IsCenterMode()) { + /* if (IsCenterMode()) { gFrameBuffer[5][62] = 0x80; gFrameBuffer[5][63] = 0x80; gFrameBuffer[5][64] = 0xff; @@ -740,25 +836,33 @@ static void DrawTicks() { gFrameBuffer[5][125] = 0x80; gFrameBuffer[5][126] = 0x80; gFrameBuffer[5][127] = 0xff; - } + } */ } static void DrawArrow(uint8_t x) { for (signed i = -2; i <= 2; ++i) { signed v = x + i; + uint8_t a = i > 0 ? i : -i; if (!(v & 128)) { - gFrameBuffer[5][v] |= (0b01111000 << my_abs(i)) & 0b01111000; + gFrameBuffer[5][v] |= (0b01111000 << a) & 0b01111000; } } } +static void DeInitSpectrum() { + SetF(initialFreq); + ToggleRX(false); + RestoreRegisters(); + isInitialized = false; +} + static void OnKeyDown(uint8_t key) { switch (key) { case KEY_3: - UpdateDBMax(true); + SelectNearestPreset(true); break; case KEY_9: - UpdateDBMax(false); + SelectNearestPreset(false); break; case KEY_1: UpdateScanStep(true); @@ -805,6 +909,7 @@ static void OnKeyDown(uint8_t key) { case KEY_PTT: SetState(STILL); TuneToPeak(); + settings.rssiTriggerLevel = 120; break; case KEY_MENU: break; @@ -863,21 +968,19 @@ static void OnKeyDownFreqInput(uint8_t key) { void OnKeyDownStill(KEY_Code_t key) { switch (key) { case KEY_3: - UpdateDBMax(true); break; case KEY_9: - UpdateDBMax(false); break; case KEY_UP: if (menuState) { - SetRegMenuValue(menuState, true); + UpdateRegMenuValue(registerSpecs[menuState], true); break; } UpdateCurrentFreqStill(true); break; case KEY_DOWN: if (menuState) { - SetRegMenuValue(menuState, false); + UpdateRegMenuValue(registerSpecs[menuState], false); break; } UpdateCurrentFreqStill(false); @@ -904,9 +1007,12 @@ void OnKeyDownStill(KEY_Code_t key) { ToggleBacklight(); break; case KEY_PTT: - // TODO: start transmit - /* BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, false); - BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_RED, true); */ + // start transmit + UpdateBatteryInfo(); + if (gBatteryDisplayLevel != 6 && IsTXAllowed()) { + ToggleTX(true); + } + redrawScreen = true; break; case KEY_MENU: if (menuState == ARRAY_SIZE(registerSpecs) - 1) { @@ -917,21 +1023,27 @@ void OnKeyDownStill(KEY_Code_t key) { redrawScreen = true; break; case KEY_EXIT: - if (!menuState) { - SetState(SPECTRUM); - monitorMode = false; - RelaunchScan(); + if (menuState) { + menuState = 0; break; } - menuState = 0; + SetState(SPECTRUM); + monitorMode = false; + RelaunchScan(); break; default: break; } } +static void OnKeysReleased() { + if (isTransmitting) { + ToggleTX(false); + } +} + static void RenderFreqInput() { - UI_PrintString(freqInputString, 2, 127, 0, 8); + UI_PrintString(freqInputString, 2, 127, 0, 8, true); } static void RenderStatus() { @@ -956,39 +1068,51 @@ static void RenderStill() { for (int i = 0; i < 121; i++) { if (i % 10 == 0) { - gFrameBuffer[2][i + METER_PAD_LEFT] = 0b01110000; - } else if (i % 5 == 0) { - gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00110000; + gFrameBuffer[2][i + METER_PAD_LEFT] = 0b11000000; } else { - gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00010000; + gFrameBuffer[2][i + METER_PAD_LEFT] = 0b01000000; } } uint8_t x = Rssi2PX(scanInfo.rssi, 0, 121); for (int i = 0; i < x; ++i) { - if (i % 5) { - gFrameBuffer[2][i + METER_PAD_LEFT] |= 0b00000111; + if (i % 5 && i / 5 < x / 5) { + gFrameBuffer[2][i + METER_PAD_LEFT] |= 0b00011100; } } int dbm = Rssi2DBm(scanInfo.rssi); uint8_t s = DBm2S(dbm); - sprintf(String, "S: %u", s); - GUI_DisplaySmallest(String, 4, 25, false, true); + if (s < 10) { + sprintf(String, "S%u", s); + } else { + sprintf(String, "S9+%u0", s - 9); + } + UI_PrintStringSmallest(String, 4, 10, false, true); sprintf(String, "%d dBm", dbm); - GUI_DisplaySmallest(String, 28, 25, false, true); + UI_PrintStringSmallest(String, 32, 10, false, true); + + if (isTransmitting) { + uint8_t afDB = BK4819_ReadRegister(0x6F) & 0b1111111; + uint8_t afPX = ConvertDomain(afDB, 26, 194, 0, 121); + for (int i = 0; i < afPX; ++i) { + gFrameBuffer[3][i + METER_PAD_LEFT] |= 0b00000011; + } + } if (!monitorMode) { uint8_t x = Rssi2PX(settings.rssiTriggerLevel, 0, 121); - gFrameBuffer[2][METER_PAD_LEFT + x] = 0b11111111; + gFrameBuffer[2][METER_PAD_LEFT + x - 1] |= 0b01000001; + gFrameBuffer[2][METER_PAD_LEFT + x] = 0b01111111; + gFrameBuffer[2][METER_PAD_LEFT + x + 1] |= 0b01000001; } const uint8_t PAD_LEFT = 4; const uint8_t CELL_WIDTH = 30; uint8_t offset = PAD_LEFT; - uint8_t row = 4; + uint8_t row = 3; - for (int i = 0, idx = 1; idx <= 4; ++i, ++idx) { + for (int i = 0, idx = 1; idx <= 7; ++i, ++idx) { if (idx == 5) { row += 2; i = 0; @@ -1000,12 +1124,13 @@ static void RenderStill() { gFrameBuffer[row + 1][j + offset] = 0xFF; } } - sprintf(String, "%s", registerSpecs[idx].name); - GUI_DisplaySmallest(String, offset + 2, row * 8 + 2, false, - menuState != idx); - sprintf(String, "%u", GetRegMenuValue(idx)); - GUI_DisplaySmallest(String, offset + 2, (row + 1) * 8 + 1, false, - menuState != idx); + RegisterSpec s = registerSpecs[idx]; + sprintf(String, "%s", s.name); + UI_PrintStringSmallest(String, offset + 2, row * 8 + 2, false, + menuState != idx); + sprintf(String, "%u", GetRegValue(s)); + UI_PrintStringSmallest(String, offset + 2, (row + 1) * 8 + 1, false, + menuState != idx); } } @@ -1033,15 +1158,16 @@ bool HandleUserInput() { if (kbd.current == KEY_INVALID) { kbd.counter = 0; + OnKeysReleased(); return true; } - if (kbd.current == kbd.prev && kbd.counter <= 16) { + if (kbd.current == kbd.prev && kbd.counter <= 20) { kbd.counter++; - SYSTEM_DelayMs(20); + SYSTEM_DelayMs(10); } - if (kbd.counter == 3 || kbd.counter > 16) { + if (kbd.counter == 4 || kbd.counter > 20) { switch (currentState) { case SPECTRUM: OnKeyDown(kbd.current); @@ -1059,11 +1185,12 @@ bool HandleUserInput() { } static void Scan() { - if (rssiHistory[scanInfo.i] != RSSI_MAX_VALUE) { - SetF(scanInfo.f); - Measure(); - UpdateScanInfo(); + if (blacklist[scanInfo.i]) { + return; } + SetF(scanInfo.f); + Measure(); + UpdateScanInfo(); } static void NextScanStep() { @@ -1080,6 +1207,8 @@ static void UpdateScan() { return; } + MoveHistory(); + redrawScreen = true; preventKeypress = false; @@ -1106,6 +1235,9 @@ static void UpdateStill() { static void UpdateListening() { preventKeypress = false; + if (!isListening) { + ToggleRX(true); + } if (currentState == STILL) { listenT = 0; } @@ -1118,7 +1250,7 @@ static void UpdateListening() { if (currentState == SPECTRUM) { BK4819_WriteRegister(0x43, GetBWRegValueForScan()); Measure(); - BK4819_WriteRegister(0x43, listenBWRegValues[settings.listenBw]); + BK4819_WriteRegister(0x43, GetBWRegValueForListen()); } else { Measure(); } @@ -1135,6 +1267,8 @@ static void UpdateListening() { newScanStart = true; } +static void UpdateTransmitting() {} + static void Tick() { if (!preventKeypress) { HandleUserInput(); @@ -1143,7 +1277,9 @@ static void Tick() { InitScan(); newScanStart = false; } - if (isListening && currentState != FREQ_INPUT) { + if (isTransmitting) { + UpdateTransmitting(); + } else if (isListening && currentState != FREQ_INPUT) { UpdateListening(); } else { if (currentState == SPECTRUM) { @@ -1152,10 +1288,14 @@ static void Tick() { UpdateStill(); } } - if (redrawStatus || ++statuslineUpdateTimer > 4096) { + if (++batteryUpdateTimer > 4096) { + batteryUpdateTimer = 0; + UpdateBatteryInfo(); + redrawStatus = true; + } + if (redrawStatus) { RenderStatus(); redrawStatus = false; - statuslineUpdateTimer = 0; } if (redrawScreen) { Render(); @@ -1163,21 +1303,35 @@ static void Tick() { } } +static void AutomaticPresetChoose(uint32_t f) { + for (int i = 0; i < ARRAY_SIZE(freqPresets); ++i) { + FreqPreset p = freqPresets[i]; + if (f >= p.fStart && f <= freqPresets[i].fEnd) { + ApplyPreset(p); + } + } +} + void APP_RunSpectrum() { - // TX here coz it always? set to active VFO - currentFreq = initialFreq = - gEeprom.VfoInfo[gEeprom.TX_VFO].pRX->Frequency; - BackupRegisters(); + // TX here coz it always? set to active VFO + VFO_Info_t vfo = gEeprom.VfoInfo[gEeprom.TX_CHANNEL]; + initialFreq = vfo.pRX->Frequency; + currentFreq = initialFreq; + settings.scanStepIndex = gStepSettingToIndex[vfo.STEP_SETTING]; + settings.listenBw = vfo.CHANNEL_BANDWIDTH == BANDWIDTH_WIDE + ? BANDWIDTH_WIDE + : BANDWIDTH_NARROW; + settings.modulationType = vfo.IsAM ? MOD_AM : MOD_FM; + + AutomaticPresetChoose(currentFreq); - isListening = true; // to turn off RX later redrawStatus = true; redrawScreen = false; // we will wait until scan done newScanStart = true; ToggleRX(true), ToggleRX(false); // hack to prevent noise when squelch off - SetModulation(settings.modulationType = MOD_FM); - BK4819_SetFilterBandwidth(settings.listenBw = BK4819_FILTER_BW_WIDE, false); + SetModulation(settings.modulationType); RelaunchScan(); diff --git a/app/spectrum.h b/app/spectrum.h index 61ac358..739f4d0 100644 --- a/app/spectrum.h +++ b/app/spectrum.h @@ -31,6 +31,7 @@ #include "../font.h" #include "../frequencies.h" #include "../helper/battery.h" +#include "../helper/measurements.h" #include "../misc.h" #include "../radio.h" #include "../settings.h" @@ -41,17 +42,19 @@ static const uint8_t DrawingEndY = 40; -static const uint8_t U8RssiMap[] = { - 121, 115, 109, 103, 97, 91, 85, 79, 73, 63, -}; - static const uint16_t scanStepValues[] = { 1, 10, 50, 100, 250, 500, 625, 833, 1000, 1250, 2500, 10000, }; -static const uint16_t scanStepBWRegValues[] = { +static const uint8_t gStepSettingToIndex[] = { + [STEP_2_5kHz] = 4, [STEP_5_0kHz] = 5, [STEP_6_25kHz] = 6, + [STEP_10_0kHz] = 8, [STEP_12_5kHz] = 9, [STEP_25_0kHz] = 10, + [STEP_8_33kHz] = 7, +}; + +static const uint16_t scanStepBWRegValues[12] = { // RX RXw TX BW // 0b0 000 000 001 01 1000 // 1 @@ -122,17 +125,16 @@ typedef enum ScanStep { } ScanStep; typedef struct SpectrumSettings { - uint32_t frequencyChangeStep; StepsCount stepsCount; ScanStep scanStepIndex; + uint32_t frequencyChangeStep; uint16_t scanDelay; uint16_t rssiTriggerLevel; + + bool backlightState; BK4819_FilterBandwidth_t bw; BK4819_FilterBandwidth_t listenBw; - int dbMin; - int dbMax; ModulationType modulationType; - bool backlightState; } SpectrumSettings; typedef struct KeyboardState { @@ -150,7 +152,7 @@ typedef struct ScanInfo { } ScanInfo; typedef struct RegisterSpec { - char *name; + const char *name; uint8_t num; uint8_t offset; uint16_t maxValue; @@ -160,10 +162,56 @@ typedef struct RegisterSpec { typedef struct PeakInfo { uint16_t t; uint16_t rssi; - uint32_t f; uint8_t i; + uint32_t f; } PeakInfo; +typedef struct MovingAverage { + uint16_t mean[128]; + uint16_t buf[4][128]; + uint16_t min, mid, max; + uint16_t t; +} MovingAverage; + +typedef struct FreqPreset { + char name[16]; + uint32_t fStart; + uint32_t fEnd; + StepsCount stepsCountIndex; + uint8_t stepSizeIndex; + ModulationType modulationType; + BK4819_FilterBandwidth_t listenBW; +} FreqPreset; + +static const FreqPreset freqPresets[] = { + {"17m", 1806800, 1831800, STEPS_128, S_STEP_1_0kHz, MOD_USB, + BK4819_FILTER_BW_NARROWER}, + {"15m", 2100000, 2145000, STEPS_128, S_STEP_1_0kHz, MOD_USB, + BK4819_FILTER_BW_NARROWER}, + {"12m", 2489000, 2514000, STEPS_128, S_STEP_1_0kHz, MOD_USB, + BK4819_FILTER_BW_NARROWER}, + {"CB", 2697500, 2785500, STEPS_128, S_STEP_5_0kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"10m", 2800000, 2970000, STEPS_128, S_STEP_1_0kHz, MOD_USB, + BK4819_FILTER_BW_NARROWER}, + {"AIR", 11800000, 13500000, STEPS_128, S_STEP_100_0kHz, MOD_AM, + BK4819_FILTER_BW_NARROW}, + {"2m", 14400000, 14600000, STEPS_128, S_STEP_25_0kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"JD1", 15175000, 15400000, STEPS_128, S_STEP_25_0kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"JD2", 15500000, 15600000, STEPS_64, S_STEP_25_0kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"LPD", 43307500, 43477500, STEPS_128, S_STEP_25_0kHz, MOD_FM, + BK4819_FILTER_BW_WIDE}, + {"PMR", 44600625, 44620000, STEPS_16, S_STEP_12_5kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"FRS/GM 462", 46256250, 46272500, STEPS_16, S_STEP_12_5kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, + {"FRS/GM 467", 46756250, 46771250, STEPS_16, S_STEP_12_5kHz, MOD_FM, + BK4819_FILTER_BW_NARROW}, +}; + void APP_RunSpectrum(void); #endif /* ifndef SPECTRUM_H */ diff --git a/board.c b/board.c index a632726..1aea112 100644 --- a/board.c +++ b/board.c @@ -616,24 +616,24 @@ void BOARD_EEPROM_Init(void) #endif gEeprom.ROGER = (Data[1] < 3) ? Data[1] : ROGER_MODE_OFF; gEeprom.REPEATER_TAIL_TONE_ELIMINATION = (Data[2] < 11) ? Data[2] : 0; - gEeprom.TX_VFO = (Data[3] < 2) ? Data[3] : 0; + gEeprom.TX_VFO = (Data[3] < 2) ? Data[3] : 0; // 0ED0..0ED7 EEPROM_ReadBuffer(0x0ED0, Data, 8); - gEeprom.DTMF_SIDE_TONE = (Data[0] < 2) ? Data[0] : true; + gEeprom.DTMF_SIDE_TONE = (Data[0] < 2) ? Data[0] : true; gEeprom.DTMF_SEPARATE_CODE = DTMF_ValidateCodes((char *)(Data + 1), 1) ? Data[1] : '*'; gEeprom.DTMF_GROUP_CALL_CODE = DTMF_ValidateCodes((char *)(Data + 2), 1) ? Data[2] : '#'; - gEeprom.DTMF_DECODE_RESPONSE = (Data[3] < 4) ? Data[3] : 0; - gEeprom.DTMF_auto_reset_time = (Data[4] < 61) ? Data[4] : (Data[4] >= 5) ? Data[4] : 10; - gEeprom.DTMF_PRELOAD_TIME = (Data[5] < 101) ? Data[5] * 10 : 300; - gEeprom.DTMF_FIRST_CODE_PERSIST_TIME = (Data[6] < 101) ? Data[6] * 10 : 100; - gEeprom.DTMF_HASH_CODE_PERSIST_TIME = (Data[7] < 101) ? Data[7] * 10 : 100; + gEeprom.DTMF_DECODE_RESPONSE = (Data[3] < 4) ? Data[3] : DTMF_DEC_RESPONSE_RING; + gEeprom.DTMF_auto_reset_time = (Data[4] <= DTMF_HOLD_MAX) ? Data[4] : (Data[4] >= DTMF_HOLD_MIN) ? Data[4] : DTMF_HOLD_MAX; + gEeprom.DTMF_PRELOAD_TIME = (Data[5] < 101) ? Data[5] * 10 : 200; + gEeprom.DTMF_FIRST_CODE_PERSIST_TIME = (Data[6] < 101) ? Data[6] * 10 : 70; + gEeprom.DTMF_HASH_CODE_PERSIST_TIME = (Data[7] < 101) ? Data[7] * 10 : 70; // 0ED8..0EDF EEPROM_ReadBuffer(0x0ED8, Data, 8); - gEeprom.DTMF_CODE_PERSIST_TIME = (Data[0] < 101) ? Data[0] * 10 : 100; - gEeprom.DTMF_CODE_INTERVAL_TIME = (Data[1] < 101) ? Data[1] * 10 : 100; - gEeprom.PERMIT_REMOTE_KILL = (Data[2] < 2) ? Data[2] : true; + gEeprom.DTMF_CODE_PERSIST_TIME = (Data[0] < 101) ? Data[0] * 10 : 70; + gEeprom.DTMF_CODE_INTERVAL_TIME = (Data[1] < 101) ? Data[1] * 10 : 70; + gEeprom.PERMIT_REMOTE_KILL = (Data[2] < 2) ? Data[2] : false; // 0EE0..0EE7 EEPROM_ReadBuffer(0x0EE0, Data, 8); diff --git a/driver/bk4819.c b/driver/bk4819.c index 0d921d7..4bd0622 100644 --- a/driver/bk4819.c +++ b/driver/bk4819.c @@ -1478,33 +1478,78 @@ uint8_t BK4819_GetAfTxRx(void) bool BK4819_GetFrequencyScanResult(uint32_t *pFrequency) { - const uint16_t High = BK4819_ReadRegister(BK4819_REG_0D); - const bool Finished = (High & 0x8000) == 0; - if (Finished) - { - const uint16_t Low = BK4819_ReadRegister(BK4819_REG_0E); - *pFrequency = (uint32_t)((High & 0x7FF) << 16) | Low; - } - return Finished; + // ********** + // REG_0D read only + // + // <15> frequency scan indicator + // 1 = busy + // 0 = finished + // + // <14:11> ??? + // + // <10:0> frequency scan high 16 bits + // + // ********** + // REG_0E read only + // + // <15:0> frequency scan low 16 bits + // + // ********** + // (REG_0D <10:0> << 16) | (REG_0E <15:0>) .. unit is 10Hz + // + const uint16_t high = BK4819_ReadRegister(BK4819_REG_0D); + const uint16_t low = BK4819_ReadRegister(BK4819_REG_0E); + const bool finished = ((high >> 15) & 1u) == 0; + *pFrequency = ((uint32_t)(high & 0x07FF) << 16) | low; + return finished; } BK4819_CssScanResult_t BK4819_GetCxCSSScanResult(uint32_t *pCdcssFreq, uint16_t *pCtcssFreq) { - uint16_t Low; - uint16_t High = BK4819_ReadRegister(BK4819_REG_69); + // ********** + // REG_68 read only + // + // <15> CTCSS scan indicator + // 1 = busy + // 0 = found + // + // <12:0> CTCSS frequency (Hz) + // div by 20.64888 ... 13M / 26M XTAL + // div by 20.97152 ... 12.8M / 19.2M / 25.6M / 38.4M XTAL + // + // ********** + // REG_69 read only + // + // <15> CDCSS scan indicator + // 1 = busy + // 0 = found + // + // <14> 23 or 24 bit CDCSS Indicator (BK4819v3) + // 1 = 24 bit + // 0 = 23 bit + // + // <11:0> CDCSS High 12 bits + // + // ********** + // REG_6A read only + // + // <11:0> CDCSS Low 12 bits + // + // + const uint16_t High = BK4819_ReadRegister(BK4819_REG_69); + uint16_t Low; - if ((High & 0x8000) == 0) - { + if (((High >> 15) & 1u) == 0) + { // CDCSS Low = BK4819_ReadRegister(BK4819_REG_6A); - *pCdcssFreq = ((High & 0xFFF) << 12) | (Low & 0xFFF); + *pCdcssFreq = ((uint32_t)(High & 0xFFF) << 12) | (Low & 0xFFF); return BK4819_CSS_RESULT_CDCSS; } Low = BK4819_ReadRegister(BK4819_REG_68); - - if ((Low & 0x8000) == 0) - { - *pCtcssFreq = ((Low & 0x1FFF) * 4843) / 10000; + if (((Low >> 15) & 1u) == 0) + { // CTCSS + *pCtcssFreq = ((uint32_t)(Low & 0x1FFF) * 4843) / 10000; return BK4819_CSS_RESULT_CTCSS; } @@ -1513,12 +1558,46 @@ BK4819_CssScanResult_t BK4819_GetCxCSSScanResult(uint32_t *pCdcssFreq, uint16_t void BK4819_DisableFrequencyScan(void) { - BK4819_WriteRegister(BK4819_REG_32, 0x0244); + // REG_32 + // + // <15:14> 0 frequency scan time + // 0 = 0.2 sec + // 1 = 0.4 sec + // 2 = 0.8 sec + // 3 = 1.6 sec + // + // <13:1> ??? + // + // <0> 0 frequency scan enable + // 1 = enable + // 0 = disable + // + BK4819_WriteRegister(BK4819_REG_32, // 0x0244); // 00 0000100100010 0 + ( 0u << 14) | // 0 frequency scan Time + (290u << 1) | // ??? + ( 0u << 0)); // 0 frequency scan enable } void BK4819_EnableFrequencyScan(void) { - BK4819_WriteRegister(BK4819_REG_32, 0x0245); // 00 0000100100010 1 + // REG_32 + // + // <15:14> 0 frequency scan time + // 0 = 0.2 sec + // 1 = 0.4 sec + // 2 = 0.8 sec + // 3 = 1.6 sec + // + // <13:1> ??? + // + // <0> 0 frequency scan enable + // 1 = enable + // 0 = disable + // + BK4819_WriteRegister(BK4819_REG_32, // 0x0245); // 00 0000100100010 1 + ( 0u << 14) | // 0 frequency scan time + (290u << 1) | // ??? + ( 1u << 0)); // 1 frequency scan enable } void BK4819_SetScanFrequency(uint32_t Frequency) @@ -1532,7 +1611,7 @@ void BK4819_SetScanFrequency(uint32_t Frequency) // 0 = Disable // // <14> 0 - // 1 = GPIO0Input for CDCSS + // 1 = GPIO-0 input for CDCSS // 0 = Normal Mode (for BK4819 v3) // // <13> 0 @@ -1547,8 +1626,8 @@ void BK4819_SetScanFrequency(uint32_t Frequency) // 1 = 24bit // 0 = 23bit // - // <10> 0 1050HzDetectionMode - // 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz + // <10> 0 1050Hz detection mode + // 1 = 1050/4 detect enable, CTC1 should be set to 1050/4 Hz // // <9> 0 Auto CDCSS Bw Mode // 1 = Disable diff --git a/driver/keyboard.c b/driver/keyboard.c index 0003a81..62882df 100644 --- a/driver/keyboard.c +++ b/driver/keyboard.c @@ -104,6 +104,8 @@ KEY_Code_t KEYBOARD_Poll(void) for (unsigned int j = 0; j < ARRAY_SIZE(keyboard); j++) { uint16_t reg; + unsigned int i; + unsigned int k; // Set all high GPIOA->DATA |= 1u << GPIOA_PIN_KEYBOARD_4 | @@ -114,11 +116,22 @@ KEY_Code_t KEYBOARD_Poll(void) // Clear the pin we are selecting GPIOA->DATA &= keyboard[j].set_to_zero_mask; - // Wait for the pins to stabilize - SYSTICK_DelayUs(1); + // Read all 4 GPIO pins at once .. with de-noise, max of 8 sample loops + for (i = 0, k = 0, reg = 0; i < 3 && k < 8; i++, k++) + { + uint16_t reg2; - // Read all 4 GPIO pins at once - reg = GPIOA->DATA; + SYSTICK_DelayUs(1); + + reg2 = GPIOA->DATA; + if (reg != reg2) + { // noise + reg = reg2; + i = 0; + } + } + if (i < 3) + break; // noise is too bad for (unsigned int i = 0; i < ARRAY_SIZE(keyboard[j].pins); i++) { diff --git a/driver/systick.c b/driver/systick.c index 9b1cddc..5971d74 100644 --- a/driver/systick.c +++ b/driver/systick.c @@ -29,26 +29,17 @@ void SYSTICK_Init(void) void SYSTICK_DelayUs(uint32_t Delay) { - uint32_t i; - uint32_t Start; - uint32_t Previous; - uint32_t Current; - uint32_t Delta; - - i = 0; - Start = SysTick->LOAD; - Previous = SysTick->VAL; + const uint32_t ticks = Delay * gTickMultiplier; + uint32_t i = 0; + uint32_t Start = SysTick->LOAD; + uint32_t Previous = SysTick->VAL; do { - do { - Current = SysTick->VAL; - } while (Current == Previous); - if (Current < Previous) { - Delta = -Current; - } else { - Delta = Start - Current; - } - i += Delta + Previous; + uint32_t Current; + uint32_t Delta; + while ((Current = SysTick->VAL) == Previous) {} + Delta = (Current < Previous) ? -Current : Start - Current; + i += Delta + Previous; Previous = Current; - } while (i < Delay * gTickMultiplier); + } while (i < ticks); } diff --git a/firmware.bin b/firmware.bin index 607fe74..1be8eb0 100644 Binary files a/firmware.bin and b/firmware.bin differ diff --git a/firmware.packed.bin b/firmware.packed.bin index 0967d1f..4b7e550 100644 Binary files a/firmware.packed.bin and b/firmware.packed.bin differ diff --git a/frequencies.c b/frequencies.c index 6cfb270..d0cd0c1 100644 --- a/frequencies.c +++ b/frequencies.c @@ -101,23 +101,27 @@ uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t T uint32_t FREQUENCY_FloorToStep(uint32_t Upper, uint32_t Step, uint32_t Lower) { - uint32_t Index; - - if (Step == 833) - { - const uint32_t Delta = Upper - Lower; - uint32_t Base = (Delta / 2500) * 2500; - const uint32_t Index = ((Delta - Base) % 2500) / 833; - - if (Index == 2) - Base++; - - return Lower + Base + (Index * 833); - } - - Index = (Upper - Lower) / Step; - - return Lower + (Step * Index); + #if 1 + uint32_t Index; + + if (Step == 833) + { + const uint32_t Delta = Upper - Lower; + uint32_t Base = (Delta / 2500) * 2500; + const uint32_t Index = ((Delta - Base) % 2500) / 833; + + if (Index == 2) + Base++; + + return Lower + Base + (Index * 833); + } + + Index = (Upper - Lower) / Step; + + return Lower + (Step * Index); + #else + return Lower + (((Upper - Lower) / Step) * Step); + #endif } int TX_freq_check(const uint32_t Frequency) diff --git a/functions.c b/functions.c index cd02ab1..49d8cff 100644 --- a/functions.c +++ b/functions.c @@ -116,8 +116,12 @@ void FUNCTION_Select(FUNCTION_Type_t Function) gFM_RestoreCountdown_10ms = fm_restore_countdown_10ms; #endif - if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED) - gDTMF_auto_reset_time_500ms = 1 + (gEeprom.DTMF_auto_reset_time * 2); + if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT || + gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || + gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY) + { + gDTMF_auto_reset_time_500ms = gEeprom.DTMF_auto_reset_time * 2; + } gUpdateStatus = true; return; diff --git a/misc.c b/misc.c index 6a2a121..5e2dbd9 100644 --- a/misc.c +++ b/misc.c @@ -38,7 +38,7 @@ const uint16_t key_repeat_delay_10ms = 400 / 10; // 400ms const uint16_t key_repeat_10ms = 80 / 10; // 80ms .. MUST be less than 'key_repeat_delay' const uint16_t key_debounce_10ms = 20 / 10; // 20ms -const uint8_t scan_delay_10ms = 210 / 10; // 210ms +const uint8_t scan_freq_css_delay_10ms = 210 / 10; // 210ms .. don't reduce this const uint16_t dual_watch_count_after_tx_10ms = 3600 / 10; // 3.6 sec after TX ends const uint16_t dual_watch_count_after_rx_10ms = 1000 / 10; // 1 sec after RX ends ? @@ -224,7 +224,7 @@ bool gKeyBeingHeld; bool gPttIsPressed; uint8_t gPttDebounceCounter; uint8_t gMenuListCount; -uint8_t gBackupCROSS_BAND_RX_TX; +uint8_t gBackup_CROSS_BAND_RX_TX; uint8_t gScanDelay_10ms; #ifdef ENABLE_AIRCOPY uint8_t gAircopySendCountdown; diff --git a/misc.h b/misc.h index 500c454..4b87ce6 100644 --- a/misc.h +++ b/misc.h @@ -113,7 +113,7 @@ extern const uint16_t key_repeat_delay_10ms; extern const uint16_t key_repeat_10ms; extern const uint16_t key_debounce_10ms; -extern const uint8_t scan_delay_10ms; +extern const uint8_t scan_freq_css_delay_10ms; extern const uint16_t battery_save_count_10ms; @@ -296,7 +296,7 @@ extern bool gKeyBeingHeld; extern bool gPttIsPressed; extern uint8_t gPttDebounceCounter; extern uint8_t gMenuListCount; -extern uint8_t gBackupCROSS_BAND_RX_TX; +extern uint8_t gBackup_CROSS_BAND_RX_TX; extern uint8_t gScanDelay_10ms; #ifdef ENABLE_AIRCOPY extern uint8_t gAircopySendCountdown; diff --git a/radio.c b/radio.c index 6ec74e8..745132d 100644 --- a/radio.c +++ b/radio.c @@ -1093,8 +1093,7 @@ void RADIO_SendEndOfTransmission(void) BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE); if (gDTMF_CallState == DTMF_CALL_STATE_NONE && - (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || - gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)) + (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)) { // end-of-tx if (gEeprom.DTMF_SIDE_TONE) { diff --git a/scheduler.c b/scheduler.c index d056fa2..56e5a57 100644 --- a/scheduler.c +++ b/scheduler.c @@ -53,7 +53,8 @@ void SystickHandler(void) gNextTimeslice = true; if ((gGlobalSysTickCounter % 50) == 0) - { + { // 500ms tick + gNextTimeslice_500ms = true; DECREMENT_AND_TRIGGER(gTxTimerCountdown_500ms, gTxTimeoutReached); diff --git a/ui/inputbox.c b/ui/inputbox.c index cd6742c..e352cce 100644 --- a/ui/inputbox.c +++ b/ui/inputbox.c @@ -31,6 +31,5 @@ void INPUTBOX_Append(const KEY_Code_t Digit) if (Digit >= KEY_0 && Digit != KEY_INVALID) gInputBox[gInputBoxIndex++] = (char)(Digit - KEY_0); -// gInputBox[gInputBoxIndex++] = Digit; } diff --git a/ui/main.c b/ui/main.c index 35e74a7..64b5a3d 100644 --- a/ui/main.c +++ b/ui/main.c @@ -377,7 +377,7 @@ void UI_DisplayMain(void) if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT) strcpy(String, (gDTMF_State == DTMF_STATE_CALL_OUT_RSP) ? "CALL OUT(RSP)" : "CALL OUT"); else - if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED) + if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY) sprintf(String, "CALL FRM:%s", (DTMF_FindContact(gDTMF_Caller, Contact)) ? Contact : gDTMF_Caller); else if (gDTMF_IsTx) @@ -396,7 +396,7 @@ void UI_DisplayMain(void) if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT) sprintf(String, ">%s", (DTMF_FindContact(gDTMF_String, Contact)) ? Contact : gDTMF_String); else - if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED) + if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY) sprintf(String, ">%s", (DTMF_FindContact(gDTMF_Callee, Contact)) ? Contact : gDTMF_Callee); else if (gDTMF_IsTx) @@ -735,8 +735,7 @@ void UI_DisplayMain(void) #if defined(ENABLE_AM_FIX) && defined(ENABLE_AM_FIX_SHOW_DATA) if (rx && gEeprom.VfoInfo[gEeprom.RX_VFO].AM_mode && gSetting_AM_fix) { - if (gScreenToDisplay != DISPLAY_MAIN || - gDTMF_CallState != DTMF_CALL_STATE_NONE) + if (gScreenToDisplay != DISPLAY_MAIN || gDTMF_CallState != DTMF_CALL_STATE_NONE) return; center_line = CENTER_LINE_AM_FIX_DATA; @@ -763,8 +762,7 @@ void UI_DisplayMain(void) const unsigned int len = strlen(gDTMF_RX_live); const unsigned int idx = (len > (17 - 5)) ? len - (17 - 5) : 0; // limit to last 'n' chars - if (gScreenToDisplay != DISPLAY_MAIN || - gDTMF_CallState != DTMF_CALL_STATE_NONE) + if (gScreenToDisplay != DISPLAY_MAIN || gDTMF_CallState != DTMF_CALL_STATE_NONE) return; center_line = CENTER_LINE_DTMF_DEC; @@ -779,8 +777,7 @@ void UI_DisplayMain(void) const unsigned int len = gDTMF_RX_index; const unsigned int idx = (len > (17 - 5)) ? len - (17 - 5) : 0; // limit to last 'n' chars - if (gScreenToDisplay != DISPLAY_MAIN || - gDTMF_CallState != DTMF_CALL_STATE_NONE) + if (gScreenToDisplay != DISPLAY_MAIN || gDTMF_CallState != DTMF_CALL_STATE_NONE) return; center_line = CENTER_LINE_DTMF_DEC; @@ -795,8 +792,7 @@ void UI_DisplayMain(void) else if (gChargingWithTypeC) { // charging .. show the battery state - if (gScreenToDisplay != DISPLAY_MAIN || - gDTMF_CallState != DTMF_CALL_STATE_NONE) + if (gScreenToDisplay != DISPLAY_MAIN || gDTMF_CallState != DTMF_CALL_STATE_NONE) return; center_line = CENTER_LINE_CHARGE_DATA; diff --git a/ui/menu.c b/ui/menu.c index 3a5f9a6..706acf8 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -816,7 +816,30 @@ void UI_DisplayMenu(void) break; case MENU_D_HOLD: - sprintf(String, "%ds", gSubMenuSelection); + // only allow 5, 10, 20, 30, 40, 50 or "STAY ON SCREEN" (60) + switch (gSubMenuSelection) + { + case 4: gSubMenuSelection = 60; break; + case 6: gSubMenuSelection = 10; break; + case 9: gSubMenuSelection = 5; break; + case 11: gSubMenuSelection = 20; break; + case 19: gSubMenuSelection = 10; break; + case 21: gSubMenuSelection = 30; break; + case 29: gSubMenuSelection = 20; break; + case 31: gSubMenuSelection = 40; break; + case 39: gSubMenuSelection = 30; break; + case 41: gSubMenuSelection = 50; break; + case 49: gSubMenuSelection = 40; break; + case 51: gSubMenuSelection = 60; break; + case 59: gSubMenuSelection = 50; break; + case 61: gSubMenuSelection = 5; break; + } + + if (gSubMenuSelection < DTMF_HOLD_MAX) + sprintf(String, "%d sec", gSubMenuSelection); + else + strcpy(String, "STAY ON\nSCREEN"); // 60 + break; case MENU_D_PRE: diff --git a/ui/scanner.c b/ui/scanner.c index 74a5e98..bca399b 100644 --- a/ui/scanner.c +++ b/ui/scanner.c @@ -70,7 +70,6 @@ void UI_DisplayScanner(void) else if (gScanCssState == SCAN_CSS_STATE_FOUND) { -// strcpy(String, "SCAN COMPLETE"); strcpy(String, "* repeat M save"); text_centered = true; }