diff --git a/Makefile b/Makefile index 2e3e003..d5b86ce 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ ENABLE_VOICE := 0 ENABLE_VOX := 1 ENABLE_ALARM := 0 ENABLE_TX1750 := 0 -ENABLE_PWRON_PASSWORD := 0 +ENABLE_PWRON_PASSWORD := 1 ENABLE_DTMF_CALLING := 0 #---- DEBUG ---- @@ -83,9 +83,6 @@ OBJS += external/printf/printf.o # Drivers OBJS += driver/adc.o -ifeq ($(ENABLE_UART),1) - OBJS += driver/aes.o -endif OBJS += driver/backlight.o ifeq ($(ENABLE_FMRADIO),1) OBJS += driver/bk1080.o diff --git a/app/menu.c b/app/menu.c index b54f4cf..42c34f9 100644 --- a/app/menu.c +++ b/app/menu.c @@ -474,6 +474,13 @@ void MENU_AcceptSetting(void) gUpdateStatus = true; break; + #ifdef ENABLE_PWRON_PASSWORD + case MENU_PASSWORD: + gEeprom.POWER_ON_PASSWORD = MIN(gSubMenuSelection, PASSWORD_OFF); + gUpdateStatus = true; + break; + #endif + case MENU_W_N: gTxVfo->CHANNEL_BANDWIDTH = gSubMenuSelection; gRequestSaveChannel = 1; @@ -903,6 +910,12 @@ void MENU_ShowCurrentSetting(void) gSubMenuSelection = gEeprom.RX_OFFSET; break; + #ifdef ENABLE_PWRON_PASSWORD + case MENU_PASSWORD: + gSubMenuSelection = gEeprom.POWER_ON_PASSWORD; + break; + #endif + case MENU_W_N: gSubMenuSelection = gTxVfo->CHANNEL_BANDWIDTH; break; @@ -916,7 +929,8 @@ void MENU_ShowCurrentSetting(void) break; case MENU_MEM_CH: - gSubMenuSelection = RADIO_ValidMemoryChannelsCount(false, 0); + //todo: in vfo mode select last empty channel slot + gSubMenuSelection = gEeprom.MrChannel[gEeprom.TX_VFO]; break; case MENU_MEM_NAME: @@ -1258,6 +1272,17 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) gInputBoxIndex = 0; return; } + #ifdef ENABLE_PWRON_PASSWORD + if (UI_MENU_GetCurrentMenuId() == MENU_PASSWORD) + { + // get 4 digits + if (gInputBoxIndex < 4) { return; } + + uint32_t Password; + Password = StrToUL(INPUTBOX_GetAscii()); + gSubMenuSelection = Password; + } + #endif if (UI_MENU_GetCurrentMenuId() == MENU_MEM_CH || UI_MENU_GetCurrentMenuId() == MENU_DEL_CH || @@ -1650,6 +1675,13 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction) gRequestDisplayScreen = DISPLAY_MENU; return; } + #ifdef ENABLE_PWRON_PASSWORD + if (UI_MENU_GetCurrentMenuId() == MENU_PASSWORD) + { + gSubMenuSelection = PASSWORD_OFF; + gRequestDisplayScreen = DISPLAY_MENU; + } + #endif VFO = 0; diff --git a/app/uart.c b/app/uart.c index ff526e0..60cf0b6 100644 --- a/app/uart.c +++ b/app/uart.c @@ -26,7 +26,6 @@ #include "board.h" #include "bsp/dp32g030/dma.h" #include "bsp/dp32g030/gpio.h" -#include "driver/aes.h" #include "driver/backlight.h" #include "driver/bk4819.h" #include "driver/crc.h" @@ -120,11 +119,6 @@ typedef struct { } Data; } REPLY_0529_t; -typedef struct { - Header_t Header; - uint32_t Response[4]; -} CMD_052D_t; - typedef struct { Header_t Header; struct { @@ -207,25 +201,6 @@ static void SendVersion(void) SendReply(&Reply, sizeof(Reply)); } -static bool IsBadChallenge(const uint32_t *pKey, const uint32_t *pIn, const uint32_t *pResponse) -{ - unsigned int i; - uint32_t IV[4]; - - IV[0] = 0; - IV[1] = 0; - IV[2] = 0; - IV[3] = 0; - - AES_Encrypt(pKey, IV, pIn, IV, true); - - for (i = 0; i < 4; i++) - if (IV[i] != pResponse[i]) - return true; - - return false; -} - static void CMD_0514(const uint8_t *pBuffer) { const CMD_0514_t *pCmd = (const CMD_0514_t *)pBuffer; @@ -346,47 +321,6 @@ static void CMD_0529(void) SendReply(&Reply, sizeof(Reply)); } -static void CMD_052D(const uint8_t *pBuffer) -{ - const CMD_052D_t *pCmd = (const CMD_052D_t *)pBuffer; - REPLY_052D_t Reply; - bool bIsLocked; - - #ifdef ENABLE_FMRADIO - gFmRadioCountdown_500ms = fm_radio_countdown_500ms; - #endif - Reply.Header.ID = 0x052E; - Reply.Header.Size = sizeof(Reply.Data); - - bIsLocked = bHasCustomAesKey; - - if (!bIsLocked) - bIsLocked = IsBadChallenge(gCustomAesKey, gChallenge, pCmd->Response); - - if (!bIsLocked) - { - bIsLocked = IsBadChallenge(gDefaultAesKey, gChallenge, pCmd->Response); - if (bIsLocked) - gTryCount++; - } - - if (gTryCount < 3) - { - if (!bIsLocked) - gTryCount = 0; - } - else - { - gTryCount = 3; - bIsLocked = true; - } - - gIsLocked = bIsLocked; - Reply.Data.bIsLocked = bIsLocked; - - SendReply(&Reply, sizeof(Reply)); -} - static void CMD_052F(const uint8_t *pBuffer) { const CMD_052F_t *pCmd = (const CMD_052F_t *)pBuffer; @@ -544,10 +478,6 @@ void UART_HandleCommand(void) CMD_0529(); break; - case 0x052D: - CMD_052D(UART_Command.Buffer); - break; - case 0x052F: CMD_052F(UART_Command.Buffer); break; diff --git a/board.c b/board.c index af965cd..cc470e6 100644 --- a/board.c +++ b/board.c @@ -45,6 +45,7 @@ #include "sram-overlay.h" #endif #include "ui/menu.h" +#include "ARMCM0.h" static const uint32_t gDefaultFrequencyTable[] = { @@ -579,8 +580,10 @@ void BOARD_EEPROM_Init(void) gEeprom.POWER_ON_DISPLAY_MODE = (Data[7] < 4) ? Data[7] : POWER_ON_DISPLAY_MODE_VOLTAGE; // 0E98..0E9F - EEPROM_ReadBuffer(0x0E98, Data, 8); - memmove(&gEeprom.POWER_ON_PASSWORD, Data, 4); + #ifdef ENABLE_PWRON_PASSWORD + EEPROM_ReadBuffer(0x0E98, Data, 8); + memmove(&gEeprom.POWER_ON_PASSWORD, Data, 4); + #endif // 0EA0..0EA7 EEPROM_ReadBuffer(0x0EA0, Data, 8); @@ -588,6 +591,9 @@ void BOARD_EEPROM_Init(void) gEeprom.VOX_DELAY = (Data[0] < 11) ? Data[0] : 4; #endif gEeprom.RX_AGC = (Data[1] < RX_AGC_LEN) ? Data[1] : RX_AGC_SLOW; + #ifdef ENABLE_PWRON_PASSWORD + gEeprom.PASSWORD_WRONG_ATTEMPTS = (Data[2] > PASSWORD_MAX_RETRIES) ? PASSWORD_MAX_RETRIES : Data[2]; + #endif // 0EA8..0EAF EEPROM_ReadBuffer(0x0EA8, Data, 8); @@ -868,6 +874,9 @@ void BOARD_FactoryReset(bool bIsAll) { RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_FIRST + BAND6_400MHz, 43350000); gEeprom.RX_OFFSET = 0; + gEeprom.POWER_ON_PASSWORD = PASSWORD_OFF; + gEeprom.PASSWORD_WRONG_ATTEMPTS = 0; + SETTINGS_SaveSettings(); // set the first few memory channels for (i = 0; i < ARRAY_SIZE(gDefaultFrequencyTable); i++) { @@ -877,5 +886,7 @@ void BOARD_FactoryReset(bool bIsAll) gRxVfo->Band = FREQUENCY_GetBand(Frequency); SETTINGS_SaveChannel(MR_CHANNEL_FIRST + i, 0, gRxVfo, 2); } + // reboot device + NVIC_SystemReset(); } } diff --git a/docs/UV K5 EEPROM.xlsx b/docs/UV K5 EEPROM.xlsx index c037c5f..3165d61 100644 Binary files a/docs/UV K5 EEPROM.xlsx and b/docs/UV K5 EEPROM.xlsx differ diff --git a/driver/aes.c b/driver/aes.c deleted file mode 100644 index 6a8b5c0..0000000 --- a/driver/aes.c +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright 2023 Dual Tachyon - * https://github.com/DualTachyon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "bsp/dp32g030/aes.h" -#include "driver/aes.h" - -static void AES_Setup_ENC_CBC(bool IsDecrypt, const void *pKey, const void *pIv) -{ - const uint32_t *pK = (const uint32_t *)pKey; - const uint32_t *pI = (const uint32_t *)pIv; - - (void)IsDecrypt; // unused - - AES_CR = (AES_CR & ~AES_CR_EN_MASK) | AES_CR_EN_BITS_DISABLE; - AES_CR = AES_CR_CHMOD_BITS_CBC; - AES_KEYR3 = pK[0]; - AES_KEYR2 = pK[1]; - AES_KEYR1 = pK[2]; - AES_KEYR0 = pK[3]; - AES_IVR3 = pI[0]; - AES_IVR2 = pI[1]; - AES_IVR1 = pI[2]; - AES_IVR0 = pI[3]; - AES_CR = (AES_CR & ~AES_CR_EN_MASK) | AES_CR_EN_BITS_ENABLE; -} - -static void AES_Transform(const void *pIn, void *pOut) -{ - const uint32_t *pI = (const uint32_t *)pIn; - uint32_t *pO = (uint32_t *)pOut; - - AES_DINR = pI[0]; - AES_DINR = pI[1]; - AES_DINR = pI[2]; - AES_DINR = pI[3]; - - while ((AES_SR & AES_SR_CCF_MASK) == AES_SR_CCF_BITS_NOT_COMPLETE) { - } - - pO[0] = AES_DOUTR; - pO[1] = AES_DOUTR; - pO[2] = AES_DOUTR; - pO[3] = AES_DOUTR; - - AES_CR |= AES_CR_CCFC_BITS_SET; -} - -void AES_Encrypt(const void *pKey, const void *pIv, const void *pIn, void *pOut, uint8_t NumBlocks) -{ - const uint8_t *pI = (const uint8_t *)pIn; - uint8_t *pO = (uint8_t *)pOut; - uint8_t i; - - AES_Setup_ENC_CBC(0, pKey, pIv); - for (i = 0; i < NumBlocks; i++) { - AES_Transform(pI + (i * 16), pO + (i * 16)); - } -} - diff --git a/driver/aes.h b/driver/aes.h deleted file mode 100644 index 9aa75e5..0000000 --- a/driver/aes.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2023 Dual Tachyon - * https://github.com/DualTachyon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DRIVER_AES_H -#define DRIVER_AES_H - -#include - -void AES_Encrypt(const void *pKey, const void *pIv, const void *pIn, void *pOut, uint8_t NumBlocks); - -#endif - diff --git a/driver/bk1080.c b/driver/bk1080.c index 584b355..9ae3470 100644 --- a/driver/bk1080.c +++ b/driver/bk1080.c @@ -69,7 +69,8 @@ void BK1080_Init(uint16_t Frequency, bool bDoScan) BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, 0x0201); } - BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, 0x0A5F); + // Europe/USA configuration + BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, (0u << 8) | (0b00 << 6) | (0b01 << 4) | (0b1111 << 0)); BK1080_SetFrequency(Frequency); } else @@ -78,8 +79,7 @@ void BK1080_Init(uint16_t Frequency, bool bDoScan) GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BK1080); } - // Europe/USA configuration - BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, (0u << 8) | (0b00 << 6) | (0b01 << 4) | (0b1111 << 0)); + } uint16_t BK1080_ReadRegister(BK1080_Register_t Register) diff --git a/main.c b/main.c index 200d8c9..4364990 100644 --- a/main.c +++ b/main.c @@ -174,12 +174,14 @@ void Main(void) } #ifdef ENABLE_PWRON_PASSWORD - if (gEeprom.POWER_ON_PASSWORD < 1000000) + if (gEeprom.POWER_ON_PASSWORD < PASSWORD_OFF) { bIsInLockScreen = true; UI_DisplayLock(); bIsInLockScreen = false; } + gEeprom.PASSWORD_WRONG_ATTEMPTS = 0; + gFlagSaveSettings = true; #endif BOOT_ProcessMode(BootMode); diff --git a/misc.h b/misc.h index 08a901e..30a89bd 100644 --- a/misc.h +++ b/misc.h @@ -51,6 +51,13 @@ enum { LAST_CHANNEL }; +#ifdef ENABLE_PWRON_PASSWORD +enum { + PASSWORD_OFF = 10000u +}; +#define PASSWORD_MAX_RETRIES 3 +#endif + enum { FLASHLIGHT_OFF = 0, FLASHLIGHT_ON, diff --git a/settings.c b/settings.c index 92c0c4f..f021131 100644 --- a/settings.c +++ b/settings.c @@ -98,7 +98,7 @@ void SETTINGS_SaveSettings(void) EEPROM_ReadBuffer(0x0E98, State, 8); #ifdef ENABLE_PWRON_PASSWORD memcpy(&State[0], &gEeprom.POWER_ON_PASSWORD, 4); - #endif + #endif memcpy(&State[4], &gEeprom.RX_OFFSET, 4); EEPROM_WriteBuffer(0x0E98, State, true); @@ -107,6 +107,7 @@ void SETTINGS_SaveSettings(void) State[0] = gEeprom.VOX_DELAY; #endif State[1] = gEeprom.RX_AGC; + State[2] = gEeprom.PASSWORD_WRONG_ATTEMPTS; EEPROM_WriteBuffer(0x0EA0, State, true); memset(State, 0xFF, sizeof(State)); diff --git a/settings.h b/settings.h index 2664bd4..d52c601 100644 --- a/settings.h +++ b/settings.h @@ -243,7 +243,10 @@ typedef struct { uint8_t DAC_GAIN; VFO_Info_t VfoInfo[2]; +#ifdef ENABLE_PWRON_PASSWORD uint32_t POWER_ON_PASSWORD; + uint8_t PASSWORD_WRONG_ATTEMPTS; +#endif uint16_t VOX1_THRESHOLD; uint16_t VOX0_THRESHOLD; diff --git a/ui/lock.c b/ui/lock.c index 08183d1..9250388 100644 --- a/ui/lock.c +++ b/ui/lock.c @@ -28,22 +28,28 @@ #include "ui/helper.h" #include "ui/inputbox.h" #include "ui/lock.h" +#include "board.h" -static void Render(void) +static void Render(bool maxAttemptsReached) { unsigned int i; - char String[7]; + char String[5]; memset(gStatusLine, 0, sizeof(gStatusLine)); memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - - strcpy(String, "LOCK"); - UI_PrintString(String, 0, 127, 1, 10); - for (i = 0; i < 6; i++) - String[i] = (gInputBox[i] == 10) ? '-' : '*'; - String[6] = 0; - UI_PrintString(String, 0, 127, 3, 12); - + if (maxAttemptsReached){ + strcpy(String, "OK"); + UI_PrintString(String, 0, 127, 2, 10); + } + else + { + strcpy(String, "LOCK"); + UI_PrintString(String, 0, 127, 1, 10); + for (i = 0; i < 4; i++) + String[i] = (gInputBox[i] == 10) ? '-' : '*'; + String[6] = 0; + UI_PrintString(String, 0, 127, 3, 12); + } ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); } @@ -51,6 +57,7 @@ static void Render(void) void UI_DisplayLock(void) { KEY_Code_t Key; + KEY_Code_t gKeyReadingLocal; BEEP_Type_t Beep; gUpdateDisplay = true; @@ -66,8 +73,13 @@ void UI_DisplayLock(void) gNextTimeslice = false; Key = KEYBOARD_Poll(); - - if (gKeyReading0 == Key) + if (gEeprom.PASSWORD_WRONG_ATTEMPTS >= PASSWORD_MAX_RETRIES) + { + Render(true); + BOARD_FactoryReset(true); + return; + } + if (gKeyReadingLocal == Key) { if (++gDebounceCounter == key_debounce_10ms) { @@ -93,7 +105,7 @@ void UI_DisplayLock(void) case KEY_9: INPUTBOX_Append(Key - KEY_0); - if (gInputBoxIndex < 6) // 6 frequency digits + if (gInputBoxIndex < 4) // 4 frequency digits { Beep = BEEP_1KHZ_60MS_OPTIONAL; } @@ -107,8 +119,15 @@ void UI_DisplayLock(void) if ((gEeprom.POWER_ON_PASSWORD) == Password) { AUDIO_PlayBeep(BEEP_1KHZ_60MS_OPTIONAL); + gEeprom.PASSWORD_WRONG_ATTEMPTS = 0; return; } + else + { + gEeprom.PASSWORD_WRONG_ATTEMPTS++; + } + + SETTINGS_SaveSettings(); memset(gInputBox, 10, sizeof(gInputBox)); @@ -140,19 +159,12 @@ void UI_DisplayLock(void) else { gDebounceCounter = 0; - gKeyReading0 = Key; - } - - if (UART_IsCommandAvailable()) - { - __disable_irq(); - UART_HandleCommand(); - __enable_irq(); + gKeyReadingLocal = Key; } if (gUpdateDisplay) { - Render(); + Render(false); gUpdateDisplay = false; } } diff --git a/ui/menu.c b/ui/menu.c index 50efa64..4a93060 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -109,6 +109,9 @@ const t_menu_item MenuList[] = #endif {"BatVol", VOICE_ID_INVALID, MENU_VOL }, // was "VOL" {"RxMode", VOICE_ID_DUAL_STANDBY, MENU_TDR }, +#ifdef ENABLE_PWRON_PASSWORD + {"Passwd", VOICE_ID_INVALID, MENU_PASSWORD }, // power on password +#endif {"Sql", VOICE_ID_SQUELCH, MENU_SQL }, // hidden menu items from here on // enabled if pressing both the PTT and upper side button at power-on @@ -559,6 +562,28 @@ void UI_DisplayMenu(void) already_printed = true; break; + #ifdef ENABLE_PWRON_PASSWORD + case MENU_PASSWORD: + if (!gIsInSubMenu || gInputBoxIndex == 0) + { + if((unsigned int)gSubMenuSelection >= PASSWORD_OFF) + { + sprintf(String, "OFF"); + } + else + { + sprintf(String, "****"); + } + } + else + { + const char * ascii = INPUTBOX_GetAscii(); + sprintf(String, "%.4s ",ascii); + } + UI_PrintString(String, menu_item_x1, menu_item_x2, 1, 8); + already_printed = true; + break; + #endif case MENU_W_N: strcpy(String, bwNames[gSubMenuSelection]); diff --git a/ui/menu.h b/ui/menu.h index e0dc1cf..ff13387 100644 --- a/ui/menu.h +++ b/ui/menu.h @@ -59,6 +59,9 @@ enum MENU_ABR_MIN, MENU_ABR_MAX, MENU_TDR, +#ifdef ENABLE_PWRON_PASSWORD + MENU_PASSWORD, +#endif MENU_BEEP, #ifdef ENABLE_VOICE MENU_VOICE,