mirror of
https://github.com/OneOfEleven/uv-k5-firmware-custom.git
synced 2025-04-28 14:21:25 +03:00
484 lines
11 KiB
C
484 lines
11 KiB
C
/* 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 <string.h>
|
|
|
|
#include "app/aircopy.h"
|
|
#include "audio.h"
|
|
#include "driver/bk4819.h"
|
|
#include "driver/crc.h"
|
|
#include "driver/eeprom.h"
|
|
#include "driver/system.h"
|
|
#include "frequencies.h"
|
|
#include "misc.h"
|
|
#include "radio.h"
|
|
#include "settings.h"
|
|
#include "ui/helper.h"
|
|
#include "ui/inputbox.h"
|
|
#include "ui/ui.h"
|
|
|
|
#define AIRCOPY_MAGIC_START 0xABCD
|
|
#define AIRCOPY_MAGIC_END 0xDCBA
|
|
|
|
#define AIRCOPY_LAST_EEPROM_ADDR 0x1E00
|
|
|
|
const uint8_t g_aircopy_block_max = 120;
|
|
uint8_t g_aircopy_block_number;
|
|
uint8_t g_aircopy_rx_errors;
|
|
aircopy_state_t g_aircopy_state;
|
|
|
|
uint8_t aircopy_send_count_down_10ms;
|
|
|
|
uint16_t g_fsk_buffer[36];
|
|
unsigned int g_fsk_write_index;
|
|
uint16_t g_fsk_tx_timeout_10ms;
|
|
|
|
void AIRCOPY_start_FSK_tx(const uint8_t request_packet)
|
|
{
|
|
unsigned int i;
|
|
const uint16_t eeprom_addr = (uint16_t)g_aircopy_block_number * 64;
|
|
|
|
// will be used to ask the TX/ing radio to resend a missing/corrupted packet
|
|
(void)request_packet;
|
|
|
|
// *********
|
|
|
|
// packet start
|
|
g_fsk_buffer[0] = AIRCOPY_MAGIC_START;
|
|
|
|
// eeprom address
|
|
g_fsk_buffer[1] = eeprom_addr;
|
|
|
|
// data
|
|
EEPROM_ReadBuffer(eeprom_addr, &g_fsk_buffer[2], 64);
|
|
|
|
// data CRC
|
|
g_fsk_buffer[34] = CRC_Calculate(&g_fsk_buffer[1], 2 + 64);
|
|
|
|
// packet end
|
|
g_fsk_buffer[35] = AIRCOPY_MAGIC_END;
|
|
|
|
// *********
|
|
|
|
{ // scramble the packet
|
|
//for (i = 0; i < 34; i++)
|
|
//g_fsk_buffer[1 + i] ^= Obfuscation[i % ARRAY_SIZE(Obfuscation)];
|
|
|
|
uint8_t *p = (uint8_t *)&g_fsk_buffer[1];
|
|
for (i = 0; i < (34 * 2); i++)
|
|
*p++ ^= obfuscate_array[i % ARRAY_SIZE(obfuscate_array)];
|
|
}
|
|
|
|
// TX the packet
|
|
RADIO_SetTxParameters();
|
|
BK4819_SetupPowerAmplifier(0, g_current_vfo->p_tx->frequency); // VERY low TX power
|
|
|
|
// turn the RED LED on
|
|
BK4819_set_GPIO_pin(BK4819_GPIO1_PIN29_RED, true);
|
|
|
|
// start sending the packet
|
|
|
|
// let the TX stabilize
|
|
SYSTEM_DelayMs(10);
|
|
|
|
BK4819_WriteRegister(BK4819_REG_3F, BK4819_REG_3F_FSK_TX_FINISHED);
|
|
|
|
BK4819_WriteRegister(BK4819_REG_59, 0x8068);
|
|
BK4819_WriteRegister(BK4819_REG_59, 0x0068);
|
|
|
|
// load the packet
|
|
for (i = 0; i < 36; i++)
|
|
BK4819_WriteRegister(BK4819_REG_5F, g_fsk_buffer[i]);
|
|
|
|
// SYSTEM_DelayMs(20);
|
|
|
|
BK4819_WriteRegister(BK4819_REG_59, 0x2868);
|
|
|
|
g_fsk_tx_timeout_10ms = 1000 / 10; // 1 second timeout
|
|
}
|
|
|
|
void AIRCOPY_stop_FSK_tx(void)
|
|
{
|
|
if (g_aircopy_state != AIRCOPY_TX && g_fsk_tx_timeout_10ms == 0)
|
|
return;
|
|
|
|
g_fsk_tx_timeout_10ms = 0;
|
|
|
|
BK4819_WriteRegister(BK4819_REG_02, 0); // disable all interrupts
|
|
|
|
// SYSTEM_DelayMs(20);
|
|
|
|
BK4819_ResetFSK();
|
|
|
|
// disable the TX
|
|
BK4819_SetupPowerAmplifier(0, 0);
|
|
BK4819_set_GPIO_pin(BK4819_GPIO5_PIN1, false);
|
|
|
|
// turn the RED LED off
|
|
BK4819_set_GPIO_pin(BK4819_GPIO1_PIN29_RED, false);
|
|
|
|
if (++g_aircopy_block_number >= g_aircopy_block_max)
|
|
{ // transfer is complete
|
|
g_aircopy_state = AIRCOPY_TX_COMPLETE;
|
|
}
|
|
else
|
|
{
|
|
// TX pause/gap time till we start the next packet
|
|
#if 0
|
|
aircopy_send_count_down_10ms = 300 / 10; // 300ms
|
|
#else
|
|
aircopy_send_count_down_10ms = 10 / 10; // 10ms
|
|
#endif
|
|
}
|
|
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
}
|
|
|
|
void AIRCOPY_process_FSK_tx_10ms(void)
|
|
{
|
|
if (g_aircopy_state != AIRCOPY_TX)
|
|
return;
|
|
|
|
if (g_fsk_tx_timeout_10ms == 0)
|
|
{ // not currently TX'ing
|
|
if (g_aircopy_block_number < g_aircopy_block_max)
|
|
{ // not yet finished the complete transfer
|
|
if (aircopy_send_count_down_10ms > 0)
|
|
{ // waiting till it's time to TX next packet
|
|
if (--aircopy_send_count_down_10ms == 0)
|
|
{ // start next packet
|
|
AIRCOPY_start_FSK_tx(0xff);
|
|
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (--g_fsk_tx_timeout_10ms > 0)
|
|
{ // still TX'ing
|
|
if ((BK4819_ReadRegister(BK4819_REG_0C) & (1u << 0)) == 0)
|
|
return; /// TX not yet finished
|
|
}
|
|
|
|
AIRCOPY_stop_FSK_tx();
|
|
}
|
|
|
|
void AIRCOPY_process_FSK_rx_10ms(const uint16_t interrupt_status_bits)
|
|
{
|
|
unsigned int i;
|
|
uint16_t Status;
|
|
|
|
if (g_aircopy_state != AIRCOPY_RX)
|
|
return;
|
|
|
|
if (interrupt_status_bits & BK4819_REG_02_FSK_RX_SYNC)
|
|
{
|
|
// turn the green LED on
|
|
// BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, true);
|
|
}
|
|
|
|
if (interrupt_status_bits & BK4819_REG_02_FSK_RX_FINISHED)
|
|
{
|
|
// turn the green LED off
|
|
// BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, false);
|
|
}
|
|
|
|
if (interrupt_status_bits & BK4819_REG_02_FSK_FIFO_ALMOST_FULL)
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
g_fsk_buffer[g_fsk_write_index++] = BK4819_ReadRegister(BK4819_REG_5F);
|
|
|
|
if (g_fsk_write_index < ARRAY_SIZE(g_fsk_buffer))
|
|
{
|
|
// turn the green LED on
|
|
BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, true);
|
|
return;
|
|
}
|
|
|
|
// turn the green LED off
|
|
BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, false);
|
|
|
|
g_fsk_write_index = 0;
|
|
g_update_display = true;
|
|
|
|
Status = BK4819_ReadRegister(BK4819_REG_0B);
|
|
|
|
BK4819_PrepareFSKReceive();
|
|
|
|
// Doc says bit 4 should be 1 = CRC OK, 0 = CRC FAIL, but original firmware checks for FAIL
|
|
|
|
if ((Status & (1u << 4)) == 0 &&
|
|
g_fsk_buffer[0] == AIRCOPY_MAGIC_START &&
|
|
g_fsk_buffer[35] == AIRCOPY_MAGIC_END)
|
|
{
|
|
unsigned int i;
|
|
uint16_t CRC;
|
|
|
|
{ // unscramble the packet
|
|
uint8_t *p = (uint8_t *)&g_fsk_buffer[1];
|
|
for (i = 0; i < (34 * 2); i++)
|
|
*p++ ^= obfuscate_array[i % ARRAY_SIZE(obfuscate_array)];
|
|
}
|
|
|
|
CRC = CRC_Calculate(&g_fsk_buffer[1], 2 + 64);
|
|
|
|
if (g_fsk_buffer[34] == CRC)
|
|
{ // CRC is valid
|
|
uint16_t eeprom_addr = g_fsk_buffer[1];
|
|
|
|
if (eeprom_addr == 0)
|
|
{ // start again
|
|
g_aircopy_block_number = 0;
|
|
g_aircopy_rx_errors = 0;
|
|
}
|
|
|
|
if ((eeprom_addr + 64) <= AIRCOPY_LAST_EEPROM_ADDR)
|
|
{ // eeprom block is valid .. write it directly to eeprom
|
|
|
|
uint16_t *pData = &g_fsk_buffer[2];
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (eeprom_addr == 0x0E98)
|
|
{ // power-on password .. wipe it
|
|
#ifndef ENABLE_PWRON_PASSWORD
|
|
pData[0] = 0xffff;
|
|
pData[1] = 0xffff;
|
|
#endif
|
|
}
|
|
else
|
|
if (eeprom_addr == 0x0F30)
|
|
{ // AES key .. wipe it
|
|
#ifdef ENABLE_RESET_AES_KEY
|
|
pData[0] = 0xffff;
|
|
pData[1] = 0xffff;
|
|
pData[2] = 0xffff;
|
|
pData[3] = 0xffff;
|
|
#endif
|
|
}
|
|
|
|
EEPROM_WriteBuffer(eeprom_addr, pData); // 8 bytes at a time
|
|
pData += 4;
|
|
eeprom_addr += 8;
|
|
}
|
|
|
|
g_aircopy_block_number = eeprom_addr / 64;
|
|
|
|
if (eeprom_addr >= AIRCOPY_LAST_EEPROM_ADDR)
|
|
{ // reached end of eeprom config area
|
|
g_aircopy_state = AIRCOPY_RX_COMPLETE;
|
|
|
|
// turn the green LED off
|
|
BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, false);
|
|
|
|
g_update_display = true;
|
|
}
|
|
|
|
memset(g_fsk_buffer, 0, sizeof(g_fsk_buffer));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_aircopy_rx_errors++;
|
|
}
|
|
}
|
|
|
|
static void AIRCOPY_Key_DIGITS(key_code_t Key, bool key_pressed, bool key_held)
|
|
{
|
|
if (g_aircopy_state == AIRCOPY_RX || g_aircopy_state == AIRCOPY_TX)
|
|
return;
|
|
|
|
if (g_aircopy_state != AIRCOPY_READY)
|
|
{
|
|
AIRCOPY_stop_FSK_tx();
|
|
|
|
g_aircopy_state = AIRCOPY_READY;
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
}
|
|
|
|
if (!key_held && key_pressed)
|
|
{
|
|
uint32_t Frequency;
|
|
unsigned int i;
|
|
|
|
INPUTBOX_Append(Key);
|
|
|
|
g_request_display_screen = DISPLAY_AIRCOPY;
|
|
|
|
if (g_input_box_index < 6)
|
|
{
|
|
#ifdef ENABLE_VOICE
|
|
g_another_voice_id = (voice_id_t)Key;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
g_input_box_index = 0;
|
|
|
|
NUMBER_Get(g_input_box, &Frequency);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(FREQ_BAND_TABLE); i++)
|
|
{
|
|
if (Frequency >= FREQ_BAND_TABLE[i].lower && Frequency < FREQ_BAND_TABLE[i].upper)
|
|
{
|
|
#ifdef ENABLE_VOICE
|
|
g_another_voice_id = (voice_id_t)Key;
|
|
#endif
|
|
|
|
g_rx_vfo->band = i;
|
|
|
|
// round the frequency to nearest step size
|
|
Frequency = ((Frequency + (g_rx_vfo->step_freq / 2)) / g_rx_vfo->step_freq) * g_rx_vfo->step_freq;
|
|
|
|
g_aircopy_freq = Frequency;
|
|
#ifdef ENABLE_AIRCOPY_FREQ
|
|
SETTINGS_SaveSettings(); // remeber the frequency for the next time
|
|
#endif
|
|
|
|
g_rx_vfo->freq_config_rx.frequency = Frequency;
|
|
g_rx_vfo->freq_config_tx.frequency = Frequency;
|
|
RADIO_ConfigureSquelchAndOutputPower(g_rx_vfo);
|
|
|
|
g_current_vfo = g_rx_vfo;
|
|
|
|
RADIO_SetupRegisters(true);
|
|
BK4819_SetupAircopy();
|
|
BK4819_ResetFSK();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
g_request_display_screen = DISPLAY_AIRCOPY;
|
|
}
|
|
}
|
|
|
|
static void AIRCOPY_Key_EXIT(bool key_pressed, bool key_held)
|
|
{
|
|
if (!key_pressed)
|
|
return;
|
|
|
|
if (g_aircopy_state != AIRCOPY_READY)
|
|
{
|
|
if (!key_held)
|
|
{
|
|
// turn the green LED off
|
|
BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, false);
|
|
|
|
AIRCOPY_stop_FSK_tx();
|
|
g_input_box_index = 0;
|
|
g_aircopy_state = AIRCOPY_READY;
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
}
|
|
}
|
|
else
|
|
if (key_held)
|
|
{
|
|
if (g_input_box_index > 0)
|
|
{ // cancel the frequency input
|
|
g_input_box_index = 0;
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
}
|
|
}
|
|
else
|
|
if (g_input_box_index > 0)
|
|
{ // entering a new frequency to use
|
|
g_input_box[--g_input_box_index] = 10;
|
|
GUI_DisplayScreen();
|
|
}
|
|
else
|
|
{ // enter RX mode
|
|
|
|
// turn the green LED off
|
|
BK4819_set_GPIO_pin(BK4819_GPIO0_PIN28_GREEN, false);
|
|
|
|
g_input_box_index = 0;
|
|
|
|
g_aircopy_state = AIRCOPY_RX;
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
|
|
g_fsk_write_index = 0;
|
|
g_aircopy_block_number = 0;
|
|
g_aircopy_rx_errors = 0;
|
|
memset(g_fsk_buffer, 0, sizeof(g_fsk_buffer));
|
|
|
|
BK4819_PrepareFSKReceive();
|
|
}
|
|
}
|
|
|
|
static void AIRCOPY_Key_MENU(bool key_pressed, bool key_held)
|
|
{
|
|
(void)key_held;
|
|
|
|
if (g_aircopy_state == AIRCOPY_RX || g_aircopy_state == AIRCOPY_TX)
|
|
return; // busy
|
|
|
|
if (key_pressed && !key_held)
|
|
{ // key released
|
|
|
|
// enter TX mode
|
|
g_input_box_index = 0;
|
|
|
|
g_aircopy_state = AIRCOPY_TX;
|
|
g_update_display = true;
|
|
GUI_DisplayScreen();
|
|
|
|
g_input_box_index = 0;
|
|
|
|
g_fsk_write_index = 0;
|
|
g_aircopy_block_number = 0;
|
|
g_aircopy_rx_errors = 0;
|
|
|
|
g_fsk_tx_timeout_10ms = 0;
|
|
aircopy_send_count_down_10ms = 30 / 10; // 30ms
|
|
}
|
|
}
|
|
|
|
void AIRCOPY_ProcessKey(key_code_t Key, bool key_pressed, bool key_held)
|
|
{
|
|
switch (Key)
|
|
{
|
|
case KEY_0:
|
|
case KEY_1:
|
|
case KEY_2:
|
|
case KEY_3:
|
|
case KEY_4:
|
|
case KEY_5:
|
|
case KEY_6:
|
|
case KEY_7:
|
|
case KEY_8:
|
|
case KEY_9:
|
|
AIRCOPY_Key_DIGITS(Key, key_pressed, key_held);
|
|
break;
|
|
case KEY_MENU:
|
|
AIRCOPY_Key_MENU(key_pressed, key_held);
|
|
break;
|
|
case KEY_EXIT:
|
|
AIRCOPY_Key_EXIT(key_pressed, key_held);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|