0
mirror of https://github.com/OneOfEleven/uv-k5-firmware-custom.git synced 2025-06-19 22:58:04 +03:00

Fix serial comms mishap, fix dual-watch not starting at power-on

This commit is contained in:
OneOfEleven
2023-10-11 16:02:45 +01:00
parent 5942582da4
commit 46a082ef05
23 changed files with 612 additions and 506 deletions

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
#define INCLUDE_AES
#include <string.h>
#if !defined(ENABLE_OVERLAY)
@ -43,65 +45,70 @@
#define DMA_INDEX(x, y) (((x) + (y)) % sizeof(UART_DMA_Buffer))
#define EEPROM_SIZE 0x2000u // 8192 .. BL24C64 I2C eeprom chip
// ****************************************************
typedef struct {
uint16_t ID;
uint16_t Size;
} Header_t;
} __attribute__((packed)) Header_t;
typedef struct {
uint8_t Padding[2];
uint8_t pad[2];
uint16_t ID;
} Footer_t;
} __attribute__((packed)) Footer_t;
typedef struct {
Header_t Header;
uint32_t Timestamp;
} CMD_0514_t;
uint32_t time_stamp;
} __attribute__((packed)) cmd_0514_t;
// version
typedef struct {
Header_t Header;
struct {
char Version[16];
bool g_has_custom_aes_key;
bool g_is_in_lock_screen;
uint8_t Padding[2];
uint8_t has_custom_aes_key;
uint8_t password_locked;
uint8_t pad[2];
uint32_t Challenge[4];
} Data;
} REPLY_0514_t;
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_0514_t;
typedef struct {
Header_t Header;
uint16_t Offset;
uint8_t Size;
uint8_t Padding;
uint32_t Timestamp;
} CMD_051B_t;
uint8_t pad;
uint32_t time_stamp;
} __attribute__((packed)) cmd_051B_t;
typedef struct {
Header_t Header;
struct {
uint16_t Offset;
uint8_t Size;
uint8_t Padding;
uint8_t pad;
uint8_t Data[128];
} Data;
} REPLY_051B_t;
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_051B_t;
typedef struct {
Header_t Header;
uint16_t Offset;
uint8_t Size;
bool bAllowPassword;
uint32_t Timestamp;
uint8_t Data[0];
} CMD_051D_t;
uint8_t allow_password;
uint32_t time_stamp;
// uint8_t Data[0]; // new compiler strict warning settings doesn't allow zero-length arrays
} __attribute__((packed)) cmd_051D_t;
typedef struct {
Header_t Header;
struct {
uint16_t Offset;
} Data;
} REPLY_051D_t;
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_051D_t;
typedef struct {
Header_t Header;
@ -109,39 +116,34 @@ typedef struct {
uint16_t RSSI;
uint8_t ExNoiseIndicator;
uint8_t GlitchIndicator;
} Data;
} REPLY_0527_t;
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_0527_t;
typedef struct {
Header_t Header;
struct {
uint16_t Voltage;
uint16_t Current;
} Data;
} REPLY_0529_t;
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_0529_t;
typedef struct {
Header_t Header;
uint32_t Response[4];
} CMD_052D_t;
} __attribute__((packed)) cmd_052D_t;
typedef struct {
Header_t Header;
struct {
bool bIsLocked;
uint8_t Padding[3];
} Data;
} REPLY_052D_t;
uint8_t locked;
uint8_t pad[3];
} __attribute__((packed)) Data;
} __attribute__((packed)) reply_052D_t;
typedef struct {
Header_t Header;
uint32_t Timestamp;
} CMD_052F_t;
static const uint8_t Obfuscation[16] =
{
0x16, 0x6C, 0x14, 0xE6, 0x2E, 0x91, 0x0D, 0x40, 0x21, 0x35, 0xD5, 0x40, 0x13, 0x03, 0xE9, 0x80
};
uint32_t time_stamp;
} __attribute__((packed)) cmd_052F_t;
static union
{
@ -149,73 +151,81 @@ static union
struct
{
Header_t Header;
uint8_t Data[252];
};
} UART_Command;
uint8_t Data[252];
} __attribute__((packed));
} __attribute__((packed)) UART_Command;
static uint32_t Timestamp;
static uint16_t g_uart_write_index;
static bool bIsEncrypted = true;
static const uint8_t Obfuscation[16] = {
0x16, 0x6C, 0x14, 0xE6, 0x2E, 0x91, 0x0D, 0x40, 0x21, 0x35, 0xD5, 0x40, 0x13, 0x03, 0xE9, 0x80
};
static void SendReply(void *pReply, uint16_t Size)
uint32_t time_stamp = 0;
uint16_t write_index = 0;
bool is_encrypted = true;
#ifdef INCLUDE_AES
uint8_t is_locked = (uint8_t)true;
uint8_t try_count = 0;
#endif
// ****************************************************
static void SendReply(void *preply, uint16_t Size)
{
Header_t Header;
Footer_t Footer;
if (bIsEncrypted)
if (is_encrypted)
{
uint8_t *pBytes = (uint8_t *)pReply;
uint8_t *pBytes = (uint8_t *)preply;
unsigned int i;
for (i = 0; i < Size; i++)
pBytes[i] ^= Obfuscation[i % 16];
}
Header.ID = 0xCDAB;
Header.ID = 0xCDAB;
Header.Size = Size;
UART_Send(&Header, sizeof(Header));
UART_Send(pReply, Size);
UART_Send(preply, Size);
if (bIsEncrypted)
if (is_encrypted)
{
Footer.Padding[0] = Obfuscation[(Size + 0) % 16] ^ 0xFF;
Footer.Padding[1] = Obfuscation[(Size + 1) % 16] ^ 0xFF;
Footer.pad[0] = Obfuscation[(Size + 0) % 16] ^ 0xFF;
Footer.pad[1] = Obfuscation[(Size + 1) % 16] ^ 0xFF;
}
else
{
Footer.Padding[0] = 0xFF;
Footer.Padding[1] = 0xFF;
Footer.pad[0] = 0xFF;
Footer.pad[1] = 0xFF;
}
Footer.ID = 0xBADC;
UART_Send(&Footer, sizeof(Footer));
}
static void SendVersion(void)
{
REPLY_0514_t Reply;
reply_0514_t reply;
Reply.Header.ID = 0x0515;
Reply.Header.Size = sizeof(Reply.Data);
strcpy(Reply.Data.Version, Version);
Reply.Data.g_has_custom_aes_key = g_has_custom_aes_key;
Reply.Data.g_is_in_lock_screen = g_is_in_lock_screen;
Reply.Data.Challenge[0] = g_challenge[0];
Reply.Data.Challenge[1] = g_challenge[1];
Reply.Data.Challenge[2] = g_challenge[2];
Reply.Data.Challenge[3] = g_challenge[3];
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x0515;
reply.Header.Size = sizeof(reply.Data);
strcpy(reply.Data.Version, Version);
reply.Data.has_custom_aes_key = g_has_custom_aes_key;
reply.Data.password_locked = g_password_locked;
reply.Data.Challenge[0] = g_challenge[0];
reply.Data.Challenge[1] = g_challenge[1];
reply.Data.Challenge[2] = g_challenge[2];
reply.Data.Challenge[3] = g_challenge[3];
SendReply(&Reply, sizeof(Reply));
SendReply(&reply, sizeof(reply));
}
#ifdef INCLUDE_AES
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;
uint32_t IV[4] = {0, 0, 0, 0};
AES_Encrypt(pKey, IV, pIn, IV, true);
@ -226,174 +236,216 @@ static bool IsBadChallenge(const uint32_t *pKey, const uint32_t *pIn, const uint
return false;
}
static void CMD_0514(const uint8_t *pBuffer)
#endif
// version
static void cmd_0514(const uint8_t *pBuffer)
{
const CMD_0514_t *pCmd = (const CMD_0514_t *)pBuffer;
const cmd_0514_t *pCmd = (const cmd_0514_t *)pBuffer;
Timestamp = pCmd->Timestamp;
#ifdef ENABLE_FMRADIO
g_fm_radio_count_down_500ms = fm_radio_countdown_500ms;
#endif
time_stamp = pCmd->time_stamp;
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
// turn the LCD backlight off
// GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT);
// show message
g_request_display_screen = DISPLAY_MAIN;
g_update_display = true;
g_update_display = true;
SendVersion();
}
static void CMD_051B(const uint8_t *pBuffer)
// read eeprom
static void cmd_051B(const uint8_t *pBuffer)
{
const CMD_051B_t *pCmd = (const CMD_051B_t *)pBuffer;
REPLY_051B_t Reply;
bool bLocked = false;
const cmd_051B_t *pCmd = (const cmd_051B_t *)pBuffer;
unsigned int addr = pCmd->Offset;
unsigned int size = pCmd->Size;
// bool locked = false;
reply_051B_t reply;
if (pCmd->Timestamp != Timestamp)
return;
// if (pCmd->time_stamp != time_stamp)
// return;
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
#ifdef ENABLE_FMRADIO
g_fm_radio_count_down_500ms = fm_radio_countdown_500ms;
#endif
if (addr >= EEPROM_SIZE)
return;
memset(&Reply, 0, sizeof(Reply));
Reply.Header.ID = 0x051C;
Reply.Header.Size = pCmd->Size + 4;
Reply.Data.Offset = pCmd->Offset;
Reply.Data.Size = pCmd->Size;
if (size > sizeof(reply.Data.Data))
size = sizeof(reply.Data.Data);
if (size > (EEPROM_SIZE - addr))
size = EEPROM_SIZE - addr;
if (g_has_custom_aes_key)
bLocked = g_is_locked;
if (size == 0)
return;
if (!bLocked)
EEPROM_ReadBuffer(pCmd->Offset, Reply.Data.Data, pCmd->Size);
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x051C;
reply.Header.Size = size + 4;
reply.Data.Offset = addr;
reply.Data.Size = size;
SendReply(&Reply, pCmd->Size + 8);
// if (g_has_custom_aes_key)
// locked = is_locked;
// if (!locked)
EEPROM_ReadBuffer(addr, reply.Data.Data, size);
SendReply(&reply, size + 8);
}
static void CMD_051D(const uint8_t *pBuffer)
// write eeprom
static void cmd_051D(const uint8_t *pBuffer)
{
const CMD_051D_t *pCmd = (const CMD_051D_t *)pBuffer;
REPLY_051D_t Reply;
bool bReloadEeprom;
bool bIsLocked;
const unsigned int write_size = 8;
const cmd_051D_t *pCmd = (const cmd_051D_t *)pBuffer;
unsigned int addr = pCmd->Offset;
unsigned int size = pCmd->Size;
#ifdef INCLUDE_AES
bool reload_eeprom = false;
bool locked = g_has_custom_aes_key ? is_locked : g_has_custom_aes_key;
#endif
reply_051D_t reply;
if (pCmd->Timestamp != Timestamp)
return;
// if (pCmd->time_stamp != time_stamp)
// return;
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
bReloadEeprom = false;
#ifdef ENABLE_FMRADIO
g_fm_radio_count_down_500ms = fm_radio_countdown_500ms;
#endif
if (addr >= EEPROM_SIZE)
return;
Reply.Header.ID = 0x051E;
Reply.Header.Size = sizeof(Reply.Data);
Reply.Data.Offset = pCmd->Offset;
if (size > sizeof(reply.Data))
size = sizeof(reply.Data);
if (size > (EEPROM_SIZE - addr))
size = EEPROM_SIZE - addr;
bIsLocked = g_has_custom_aes_key ? g_is_locked : g_has_custom_aes_key;
if (size == 0)
return;
if (!bIsLocked)
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x051E;
reply.Header.Size = size;
reply.Data.Offset = addr;
#ifdef INCLUDE_AES
if (!locked)
#endif
{
const uint8_t *data = (uint8_t *)&pCmd + sizeof(cmd_051D_t); // point to the RX'ed data to write to eeprom
unsigned int i;
for (i = 0; i < (pCmd->Size / 8); i++)
for (i = 0; i < (size / write_size); i++)
{
const uint16_t Offset = pCmd->Offset + (i * 8U);
const uint16_t Offset = addr + (i * write_size);
if (Offset >= 0x0F30 && Offset < 0x0F40)
if (!g_is_locked)
bReloadEeprom = true;
if ((Offset + write_size) > EEPROM_SIZE)
break;
if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !g_is_in_lock_screen || pCmd->bAllowPassword)
EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U]);
#ifdef INCLUDE_AES
if (Offset >= 0x0F30 && Offset < 0x0F40) // AES key
if (!is_locked)
reload_eeprom = true;
#endif
#ifdef ENABLE_PWRON_PASSWORD
if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !g_password_locked || pCmd->bAllowPassword)
EEPROM_WriteBuffer(Offset, &pCmd->Data[i * write_size]);
#else
EEPROM_WriteBuffer(Offset, &data[i * write_size]);
#endif
}
if (bReloadEeprom)
BOARD_EEPROM_Init();
#ifdef INCLUDE_AES
if (reload_eeprom)
BOARD_EEPROM_load();
#endif
}
SendReply(&Reply, sizeof(Reply));
SendReply(&reply, sizeof(reply));
}
static void CMD_0527(void)
// read RSSI
static void cmd_0527(void)
{
REPLY_0527_t Reply;
reply_0527_t reply;
Reply.Header.ID = 0x0528;
Reply.Header.Size = sizeof(Reply.Data);
Reply.Data.RSSI = BK4819_ReadRegister(BK4819_REG_67) & 0x01FF;
Reply.Data.ExNoiseIndicator = BK4819_ReadRegister(BK4819_REG_65) & 0x007F;
Reply.Data.GlitchIndicator = BK4819_ReadRegister(BK4819_REG_63);
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x0528;
reply.Header.Size = sizeof(reply.Data);
reply.Data.RSSI = BK4819_ReadRegister(BK4819_REG_67) & 0x01FF;
reply.Data.ExNoiseIndicator = BK4819_ReadRegister(BK4819_REG_65) & 0x007F;
reply.Data.GlitchIndicator = BK4819_ReadRegister(BK4819_REG_63);
SendReply(&Reply, sizeof(Reply));
SendReply(&reply, sizeof(reply));
}
static void CMD_0529(void)
// read ADC
static void cmd_0529(void)
{
REPLY_0529_t Reply;
Reply.Header.ID = 0x52A;
Reply.Header.Size = sizeof(Reply.Data);
uint16_t voltage;
uint16_t current;
reply_0529_t reply;
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x52A;
reply.Header.Size = sizeof(reply.Data);
// Original doesn't actually send current!
BOARD_ADC_GetBatteryInfo(&Reply.Data.Voltage, &Reply.Data.Current);
SendReply(&Reply, sizeof(Reply));
BOARD_ADC_GetBatteryInfo(&voltage, &current);
reply.Data.Voltage = voltage;
reply.Data.Current = current;
SendReply(&reply, sizeof(reply));
}
static void CMD_052D(const uint8_t *pBuffer)
#ifdef INCLUDE_AES
static void cmd_052D(const uint8_t *pBuffer)
{
const CMD_052D_t *pCmd = (const CMD_052D_t *)pBuffer;
REPLY_052D_t Reply;
bool bIsLocked;
cmd_052D_t *pCmd = (cmd_052D_t *)pBuffer;
bool locked = g_has_custom_aes_key;
uint32_t response[4];
reply_052D_t reply;
#ifdef ENABLE_FMRADIO
g_fm_radio_count_down_500ms = fm_radio_countdown_500ms;
#endif
Reply.Header.ID = 0x052E;
Reply.Header.Size = sizeof(Reply.Data);
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
bIsLocked = g_has_custom_aes_key;
if (!bIsLocked)
bIsLocked = IsBadChallenge(g_custom_aes_key, g_challenge, pCmd->Response);
if (!bIsLocked)
if (!locked)
{
bIsLocked = IsBadChallenge(g_default_aes_key, g_challenge, pCmd->Response);
if (bIsLocked)
g_try_count++;
memmove((void *)&response, &pCmd->Response, sizeof(response)); // overcome strict compiler warning settings
locked = IsBadChallenge(g_custom_aes_key, g_challenge, response);
}
if (g_try_count < 3)
if (!locked)
{
if (!bIsLocked)
g_try_count = 0;
memmove((void *)&response, &pCmd->Response, sizeof(response)); // overcome strict compiler warning settings
locked = IsBadChallenge(g_default_aes_key, g_challenge, response);
if (locked)
try_count++;
}
if (try_count < 3)
{
if (!locked)
try_count = 0;
}
else
{
g_try_count = 3;
bIsLocked = true;
try_count = 3;
locked = true;
}
g_is_locked = bIsLocked;
Reply.Data.bIsLocked = bIsLocked;
SendReply(&Reply, sizeof(Reply));
is_locked = locked;
memset(&reply, 0, sizeof(reply));
reply.Header.ID = 0x052E;
reply.Header.Size = sizeof(reply.Data);
reply.Data.locked = is_locked;
SendReply(&reply, sizeof(reply));
}
static void CMD_052F(const uint8_t *pBuffer)
#endif
static void cmd_052F(const uint8_t *pBuffer)
{
const CMD_052F_t *pCmd = (const CMD_052F_t *)pBuffer;
const cmd_052F_t *pCmd = (const cmd_052F_t *)pBuffer;
g_eeprom.dual_watch = DUAL_WATCH_OFF;
g_eeprom.cross_vfo_rx_tx = CROSS_BAND_OFF;
@ -406,6 +458,8 @@ static void CMD_052F(const uint8_t *pBuffer)
g_eeprom.vfo_info[0].dtmf_ptt_id_tx_mode = PTT_ID_OFF;
g_eeprom.vfo_info[0].dtmf_decoding_enable = false;
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
#ifdef ENABLE_NOAA
g_is_noaa_mode = false;
#endif
@ -413,12 +467,7 @@ static void CMD_052F(const uint8_t *pBuffer)
if (g_current_function == FUNCTION_POWER_SAVE)
FUNCTION_Select(FUNCTION_FOREGROUND);
g_serial_config_count_down_500ms = serial_config_count_down_500ms;
Timestamp = pCmd->Timestamp;
// turn the LCD backlight off
// GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT);
time_stamp = pCmd->time_stamp;
// show message
g_request_display_screen = DISPLAY_MAIN;
@ -438,35 +487,35 @@ bool UART_IsCommandAvailable(void)
while (1)
{
if (g_uart_write_index == DmaLength)
if (write_index == DmaLength)
return false;
while (g_uart_write_index != DmaLength && UART_DMA_Buffer[g_uart_write_index] != 0xABU)
g_uart_write_index = DMA_INDEX(g_uart_write_index, 1);
while (write_index != DmaLength && UART_DMA_Buffer[write_index] != 0xABU)
write_index = DMA_INDEX(write_index, 1);
if (g_uart_write_index == DmaLength)
if (write_index == DmaLength)
return false;
if (g_uart_write_index < DmaLength)
CommandLength = DmaLength - g_uart_write_index;
if (write_index < DmaLength)
CommandLength = DmaLength - write_index;
else
CommandLength = (DmaLength + sizeof(UART_DMA_Buffer)) - g_uart_write_index;
CommandLength = (DmaLength + sizeof(UART_DMA_Buffer)) - write_index;
if (CommandLength < 8)
return 0;
if (UART_DMA_Buffer[DMA_INDEX(g_uart_write_index, 1)] == 0xCD)
if (UART_DMA_Buffer[DMA_INDEX(write_index, 1)] == 0xCD)
break;
g_uart_write_index = DMA_INDEX(g_uart_write_index, 1);
write_index = DMA_INDEX(write_index, 1);
}
Index = DMA_INDEX(g_uart_write_index, 2);
Index = DMA_INDEX(write_index, 2);
Size = (UART_DMA_Buffer[DMA_INDEX(Index, 1)] << 8) | UART_DMA_Buffer[Index];
if ((Size + 8u) > sizeof(UART_DMA_Buffer))
{
g_uart_write_index = DmaLength;
write_index = DmaLength;
return false;
}
@ -478,7 +527,7 @@ bool UART_IsCommandAvailable(void)
if (UART_DMA_Buffer[TailIndex] != 0xDC || UART_DMA_Buffer[DMA_INDEX(TailIndex, 1)] != 0xBA)
{
g_uart_write_index = DmaLength;
write_index = DmaLength;
return false;
}
@ -492,29 +541,29 @@ bool UART_IsCommandAvailable(void)
memmove(UART_Command.Buffer, UART_DMA_Buffer + Index, TailIndex - Index);
TailIndex = DMA_INDEX(TailIndex, 2);
if (TailIndex < g_uart_write_index)
if (TailIndex < write_index)
{
memset(UART_DMA_Buffer + g_uart_write_index, 0, sizeof(UART_DMA_Buffer) - g_uart_write_index);
memset(UART_DMA_Buffer + write_index, 0, sizeof(UART_DMA_Buffer) - write_index);
memset(UART_DMA_Buffer, 0, TailIndex);
}
else
memset(UART_DMA_Buffer + g_uart_write_index, 0, TailIndex - g_uart_write_index);
memset(UART_DMA_Buffer + write_index, 0, TailIndex - write_index);
g_uart_write_index = TailIndex;
write_index = TailIndex;
if (UART_Command.Header.ID == 0x0514)
bIsEncrypted = false;
is_encrypted = false;
if (UART_Command.Header.ID == 0x6902)
bIsEncrypted = true;
is_encrypted = true;
if (bIsEncrypted)
if (is_encrypted)
{
unsigned int i;
for (i = 0; i < (Size + 2u); i++)
UART_Command.Buffer[i] ^= Obfuscation[i % 16];
}
CRC = UART_Command.Buffer[Size] | (UART_Command.Buffer[Size + 1] << 8);
return (CRC_Calculate(UART_Command.Buffer, Size) != CRC) ? false : true;
@ -524,41 +573,43 @@ void UART_HandleCommand(void)
{
switch (UART_Command.Header.ID)
{
case 0x0514:
CMD_0514(UART_Command.Buffer);
case 0x0514: // version
cmd_0514(UART_Command.Buffer);
break;
case 0x051B:
CMD_051B(UART_Command.Buffer);
case 0x051B: // read eeprom
cmd_051B(UART_Command.Buffer);
break;
case 0x051D:
CMD_051D(UART_Command.Buffer);
case 0x051D: // write eeprom
cmd_051D(UART_Command.Buffer);
break;
case 0x051F: // Not implementing non-authentic command
break;
case 0x0521: // Not implementing non-authentic command
break;
case 0x0527:
CMD_0527();
case 0x0527: // read RSSI
cmd_0527();
break;
case 0x0529:
CMD_0529();
case 0x0529: // read ADC
cmd_0529();
break;
case 0x052D:
CMD_052D(UART_Command.Buffer);
#ifdef INCLUDE_AES
case 0x052D: //
cmd_052D(UART_Command.Buffer);
break;
case 0x052F:
CMD_052F(UART_Command.Buffer);
#endif
case 0x052F: //
cmd_052F(UART_Command.Buffer);
break;
case 0x05DD:
case 0x05DD: // reboot
#if defined(ENABLE_OVERLAY)
overlay_FLASH_RebootToBootloader();
#else