mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
59 files changed
+2259
-1077
No files matched your search
+3
-1
@@ -11,4 +11,6 @@ compile_commands.json
|
||||
k5_eeprom.raw
|
||||
|
||||
/build
|
||||
/serialtool/__pycache__
|
||||
/serialtool/__pycache__
|
||||
|
||||
.DS_Store
|
||||
+2
-6
@@ -157,9 +157,6 @@ enable_feature(ENABLE_BOOT_BEEPS)
|
||||
enable_feature(ENABLE_SHOW_CHARGE_LEVEL)
|
||||
enable_feature(ENABLE_REVERSE_BAT_SYMBOL)
|
||||
enable_feature(ENABLE_NO_CODE_SCAN_TIMEOUT)
|
||||
enable_feature(ENABLE_AM_FIX
|
||||
am_fix.c
|
||||
)
|
||||
enable_feature(ENABLE_SQUELCH_MORE_SENSITIVE)
|
||||
enable_feature(ENABLE_FASTER_CHANNEL_SCAN)
|
||||
enable_feature(ENABLE_RSSI_BAR)
|
||||
@@ -169,7 +166,6 @@ enable_feature(ENABLE_REDUCE_LOW_MID_TX_POWER)
|
||||
enable_feature(ENABLE_BYP_RAW_DEMODULATORS)
|
||||
enable_feature(ENABLE_BLMIN_TMP_OFF)
|
||||
enable_feature(ENABLE_SCAN_RANGES)
|
||||
enable_feature(ENABLE_NAVIG_LEFT_RIGHT)
|
||||
|
||||
# ---- CONTRIB MODS ----
|
||||
|
||||
@@ -199,7 +195,8 @@ enable_feature(ENABLE_FEAT_F4HWN_INV)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_CTR)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_RESCUE_OPS)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_VOL)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_RESET_CHANNEL)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_AUDIO)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_RESET_VFO)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_PMR)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_GMRS_FRS_MURS)
|
||||
enable_feature(ENABLE_FEAT_F4HWN_CA)
|
||||
@@ -207,7 +204,6 @@ enable_feature(ENABLE_FEAT_F4HWN_DEBUG)
|
||||
|
||||
# ---- DEBUGGING ----
|
||||
|
||||
enable_feature(ENABLE_AM_FIX_SHOW_DATA)
|
||||
enable_feature(ENABLE_AGC_SHOW_DATA)
|
||||
enable_feature(ENABLE_UART_RW_BK_REGS)
|
||||
|
||||
|
||||
+46
-33
@@ -114,6 +114,12 @@ void (*action_opt_table[])(void) = {
|
||||
//#else
|
||||
// [ACTION_OPT_MUTE] = &FUNCTION_NOP,
|
||||
//#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
[ACTION_OPT_RXA] = &ACTION_RxA,
|
||||
#else
|
||||
[ACTION_OPT_RXA] = &FUNCTION_NOP,
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
[ACTION_OPT_POWER_HIGH] = &ACTION_Power_High,
|
||||
[ACTION_OPT_REMOVE_OFFSET] = &ACTION_Remove_Offset,
|
||||
@@ -230,7 +236,8 @@ void ACTION_Scan(bool bRestart)
|
||||
}
|
||||
|
||||
// channel mode. Keep scanning but toggle between scan lists
|
||||
gEeprom.SCAN_LIST_DEFAULT = (gEeprom.SCAN_LIST_DEFAULT + 1) % 6;
|
||||
RADIO_NextValidList();
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
#endif
|
||||
@@ -535,6 +542,14 @@ void ACTION_MainOnly(void)
|
||||
ACTION_Update();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
void ACTION_RxA(void)
|
||||
{
|
||||
gSetting_set_audio = (gSetting_set_audio + 1) % 5;
|
||||
RADIO_SetModulation(gRxVfo->Modulation);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ACTION_Ptt(void)
|
||||
{
|
||||
gSetting_set_ptt_session = !gSetting_set_ptt_session;
|
||||
@@ -632,38 +647,36 @@ void ACTION_BackLightOnDemand(void)
|
||||
BACKLIGHT_TurnOn();
|
||||
}
|
||||
|
||||
//#if !defined(ENABLE_SPECTRUM) || !defined(ENABLE_FMRADIO)
|
||||
void ACTION_Mute(void)
|
||||
{
|
||||
// Toggle mute state
|
||||
gMute = !gMute;
|
||||
void ACTION_Mute(void)
|
||||
{
|
||||
// Toggle mute state
|
||||
gMute = !gMute;
|
||||
|
||||
// Update the registers
|
||||
#ifdef ENABLE_FMRADIO
|
||||
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, gMute ? 0x0A10 : 0x0A1F);
|
||||
#endif
|
||||
gEeprom.VOLUME_GAIN = gMute ? 0 : gEeprom.VOLUME_GAIN_BACKUP;
|
||||
BK4819_WriteRegister(BK4819_REG_48,
|
||||
(11u << 12) | // ??? .. 0 ~ 15, doesn't seem to make any difference
|
||||
(0u << 10) | // AF Rx Gain-1
|
||||
(gEeprom.VOLUME_GAIN << 4) | // AF Rx Gain-2
|
||||
(gEeprom.DAC_GAIN << 0)); // AF DAC Gain (after Gain-1 and Gain-2)
|
||||
|
||||
gUpdateStatus = true;
|
||||
}
|
||||
//#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
void ACTION_Power_High(void)
|
||||
{
|
||||
gPowerHigh = !gPowerHigh;
|
||||
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
|
||||
}
|
||||
|
||||
void ACTION_Remove_Offset(void)
|
||||
{
|
||||
gRemoveOffset = !gRemoveOffset;
|
||||
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
|
||||
}
|
||||
// Update the registers
|
||||
#ifdef ENABLE_FMRADIO
|
||||
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, gMute ? 0x0A10 : 0x0A1F);
|
||||
#endif
|
||||
gEeprom.VOLUME_GAIN = gMute ? 0 : gEeprom.VOLUME_GAIN_BACKUP;
|
||||
BK4819_WriteRegister(BK4819_REG_48,
|
||||
(11u << 12) | // ??? .. 0 ~ 15, doesn't seem to make any difference
|
||||
(0u << 10) | // AF Rx Gain-1
|
||||
(gEeprom.VOLUME_GAIN << 4) | // AF Rx Gain-2
|
||||
(gEeprom.DAC_GAIN << 0)); // AF DAC Gain (after Gain-1 and Gain-2)
|
||||
|
||||
gUpdateStatus = true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
void ACTION_Power_High(void)
|
||||
{
|
||||
gPowerHigh = !gPowerHigh;
|
||||
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
|
||||
}
|
||||
|
||||
void ACTION_Remove_Offset(void)
|
||||
{
|
||||
gRemoveOffset = !gRemoveOffset;
|
||||
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+3
-2
@@ -42,9 +42,10 @@ void ACTION_SwitchDemodul(void);
|
||||
void ACTION_Wn(void);
|
||||
void ACTION_BackLightOnDemand(void);
|
||||
void ACTION_BackLight(void);
|
||||
//#if !defined(ENABLE_SPECTRUM) || !defined(ENABLE_FMRADIO)
|
||||
void ACTION_Mute(void);
|
||||
//#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
void ACTION_RxA(void);
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
void ACTION_Power_High(void);
|
||||
void ACTION_Remove_Offset(void);
|
||||
|
||||
+238
-28
@@ -16,10 +16,6 @@
|
||||
|
||||
#ifdef ENABLE_AIRCOPY
|
||||
|
||||
//#if !defined(ENABLE_OVERLAY)
|
||||
// #include "ARMCM0.h"
|
||||
//#endif
|
||||
|
||||
#include "app/aircopy.h"
|
||||
#include "audio.h"
|
||||
#include "driver/bk4819.h"
|
||||
@@ -31,6 +27,8 @@
|
||||
#include "ui/helper.h"
|
||||
#include "ui/inputbox.h"
|
||||
#include "ui/ui.h"
|
||||
#include "settings.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
#include "screenshot.h"
|
||||
@@ -45,6 +43,94 @@ uint8_t gAirCopyIsSendMode;
|
||||
|
||||
uint16_t g_FSK_Buffer[36];
|
||||
|
||||
// ============================================================================
|
||||
// Transfer Maps Definition
|
||||
// ============================================================================
|
||||
|
||||
#define AIRCOPY_BANK_SEGMENTS(bank) \
|
||||
{ \
|
||||
{ 0x0000 + (bank)*0x0800, 0x0000 + (bank)*0x0800 + 0x0800, AIRCOPY_WRITE_STRUCT }, \
|
||||
{ 0x4000 + (bank)*0x0800, 0x4000 + (bank)*0x0800 + 0x0800, AIRCOPY_WRITE_STRUCT }, \
|
||||
{ 0x8000 + (bank)*0x0100, 0x8000 + (bank)*0x0100 + 0x0100, AIRCOPY_WRITE_BYTES }, \
|
||||
}
|
||||
|
||||
#define AIRCOPY_STD_MAP(seg_array) \
|
||||
{ \
|
||||
.segments = seg_array, \
|
||||
.num_segments = 3, \
|
||||
.total_blocks = 68 \
|
||||
}
|
||||
|
||||
// total_blocks = 68 (blocs of 64 bytes) because (16 bytes + 16 bytes + 2 bytes) * 128 = 4352 / 64 = 68
|
||||
|
||||
#define DECLARE_AIRCOPY_BANK(n) \
|
||||
static const AIRCOPY_Segment_t AIRCOPY_Segments_Bank##n[] = \
|
||||
AIRCOPY_BANK_SEGMENTS(n); \
|
||||
\
|
||||
static const AIRCOPY_TransferMap_t AIRCOPY_Map_Bank##n = \
|
||||
AIRCOPY_STD_MAP(AIRCOPY_Segments_Bank##n);
|
||||
|
||||
DECLARE_AIRCOPY_BANK(0)
|
||||
DECLARE_AIRCOPY_BANK(1)
|
||||
#if AIRCOPY_NUM_BANKS >= 4 // if 512 MR CHANNEL
|
||||
DECLARE_AIRCOPY_BANK(2)
|
||||
DECLARE_AIRCOPY_BANK(3)
|
||||
#endif
|
||||
#if AIRCOPY_NUM_BANKS >= 6 // if 758 MR CHANNEL
|
||||
DECLARE_AIRCOPY_BANK(4)
|
||||
DECLARE_AIRCOPY_BANK(5)
|
||||
#endif
|
||||
#if AIRCOPY_NUM_BANKS >= 8 // if 1024 MR CHANNEL
|
||||
DECLARE_AIRCOPY_BANK(6)
|
||||
DECLARE_AIRCOPY_BANK(7)
|
||||
#endif
|
||||
|
||||
// For settings only
|
||||
|
||||
static const AIRCOPY_Segment_t AIRCOPY_Segments_Settings[] = {
|
||||
{ 0xA000, 0xA170, AIRCOPY_WRITE_BYTES },
|
||||
};
|
||||
|
||||
static const AIRCOPY_TransferMap_t AIRCOPY_Map_Settings = {
|
||||
.segments = AIRCOPY_Segments_Settings,
|
||||
.num_segments = 1,
|
||||
.total_blocks = 6
|
||||
};
|
||||
|
||||
// Finally
|
||||
|
||||
static const AIRCOPY_TransferMap_t *AIRCOPY_AvailableMaps[] = {
|
||||
&AIRCOPY_Map_Bank0,
|
||||
&AIRCOPY_Map_Bank1,
|
||||
#if AIRCOPY_NUM_BANKS >= 4 // if 512 MR CHANNEL
|
||||
&AIRCOPY_Map_Bank2,
|
||||
&AIRCOPY_Map_Bank3,
|
||||
#endif
|
||||
#if AIRCOPY_NUM_BANKS >= 6 // if 758 MR CHANNEL
|
||||
&AIRCOPY_Map_Bank4,
|
||||
&AIRCOPY_Map_Bank5,
|
||||
#endif
|
||||
#if AIRCOPY_NUM_BANKS >= 8 // if 1024 MR CHANNEL
|
||||
&AIRCOPY_Map_Bank6,
|
||||
&AIRCOPY_Map_Bank7,
|
||||
#endif
|
||||
&AIRCOPY_Map_Settings,
|
||||
};
|
||||
|
||||
#define AIRCOPY_NUM_MAPS (sizeof(AIRCOPY_AvailableMaps) / sizeof(AIRCOPY_AvailableMaps[0]))
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
const AIRCOPY_TransferMap_t* AIRCOPY_GetCurrentMap(void)
|
||||
{
|
||||
if (gAircopyCurrentMapIndex >= AIRCOPY_NUM_MAPS) {
|
||||
gAircopyCurrentMapIndex = 0;
|
||||
}
|
||||
return AIRCOPY_AvailableMaps[gAircopyCurrentMapIndex];
|
||||
}
|
||||
|
||||
static void AIRCOPY_clear()
|
||||
{
|
||||
for (uint8_t i = 0; i < 15; i++)
|
||||
@@ -56,9 +142,44 @@ static void AIRCOPY_clear()
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline const AIRCOPY_Segment_t *AIRCOPY_FindSegmentForOffset(uint16_t off)
|
||||
{
|
||||
const AIRCOPY_TransferMap_t *map = AIRCOPY_GetCurrentMap();
|
||||
|
||||
for (uint16_t i = 0; i < map->num_segments; i++)
|
||||
{
|
||||
const AIRCOPY_Segment_t *seg = &map->segments[i];
|
||||
|
||||
if (off >= seg->start_offset && off < seg->end_offset)
|
||||
return seg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void AIRCOPY_CheckComplete(void)
|
||||
{
|
||||
const AIRCOPY_TransferMap_t *map = AIRCOPY_GetCurrentMap();
|
||||
uint16_t done = gAirCopyBlockNumber + gErrorsDuringAirCopy;
|
||||
|
||||
if (done >= map->total_blocks)
|
||||
{
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Send/Receive Functions
|
||||
// ============================================================================
|
||||
|
||||
bool AIRCOPY_SendMessage(void)
|
||||
{
|
||||
static uint8_t gAircopySendCountdown = 1;
|
||||
static uint16_t CurrentOffset = 0;
|
||||
static uint16_t CurrentSegmentIndex = 0;
|
||||
|
||||
if (gAircopyState != AIRCOPY_TRANSFER) {
|
||||
return 1;
|
||||
@@ -68,9 +189,36 @@ bool AIRCOPY_SendMessage(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_FSK_Buffer[1] = (gAirCopyBlockNumber & 0x3FF) << 6;
|
||||
const AIRCOPY_TransferMap_t *map = AIRCOPY_GetCurrentMap();
|
||||
|
||||
EEPROM_ReadBuffer(g_FSK_Buffer[1], &g_FSK_Buffer[2], 64);
|
||||
// Initialize on first call
|
||||
if (gAirCopyBlockNumber == 0) {
|
||||
CurrentSegmentIndex = 0;
|
||||
CurrentOffset = map->segments[0].start_offset;
|
||||
}
|
||||
|
||||
// Advance to next segment if current is done
|
||||
while (CurrentSegmentIndex < map->num_segments &&
|
||||
CurrentOffset >= map->segments[CurrentSegmentIndex].end_offset)
|
||||
{
|
||||
CurrentSegmentIndex++;
|
||||
if (CurrentSegmentIndex < map->num_segments) {
|
||||
CurrentOffset = map->segments[CurrentSegmentIndex].start_offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if transfer is complete
|
||||
if (CurrentSegmentIndex >= map->num_segments) {
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send data from current offset
|
||||
g_FSK_Buffer[1] = CurrentOffset;
|
||||
EEPROM_ReadBuffer(CurrentOffset, &g_FSK_Buffer[2], 64);
|
||||
|
||||
g_FSK_Buffer[34] = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
|
||||
|
||||
@@ -78,20 +226,14 @@ bool AIRCOPY_SendMessage(void)
|
||||
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
|
||||
}
|
||||
|
||||
if (++gAirCopyBlockNumber >= 0x78) {
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
#endif
|
||||
//NVIC_SystemReset();
|
||||
}
|
||||
|
||||
RADIO_SetTxParameters();
|
||||
|
||||
BK4819_SendFSKData(g_FSK_Buffer);
|
||||
BK4819_SetupPowerAmplifier(0, 0);
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
|
||||
|
||||
CurrentOffset += 64;
|
||||
gAirCopyBlockNumber++;
|
||||
gAircopySendCountdown = 30;
|
||||
|
||||
return 0;
|
||||
@@ -108,10 +250,13 @@ void AIRCOPY_StorePacket(void)
|
||||
uint16_t 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 & 0x0010U) != 0 || g_FSK_Buffer[0] != 0xABCD || g_FSK_Buffer[35] != 0xDCBA) {
|
||||
gErrorsDuringAirCopy++;
|
||||
|
||||
BK4819_ResetFSK(); // <- important
|
||||
BK4819_PrepareFSKReceive(); // <- re-arm proprement
|
||||
|
||||
AIRCOPY_CheckComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,33 +267,67 @@ void AIRCOPY_StorePacket(void)
|
||||
uint16_t Crc = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
|
||||
if (g_FSK_Buffer[34] != Crc) {
|
||||
gErrorsDuringAirCopy++;
|
||||
AIRCOPY_CheckComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t Offset = g_FSK_Buffer[1];
|
||||
const AIRCOPY_TransferMap_t *map = AIRCOPY_GetCurrentMap();
|
||||
|
||||
if (Offset >= 0x1E00) {
|
||||
// Validate offset is in the map
|
||||
bool validOffset = false;
|
||||
for (uint16_t i = 0; i < map->num_segments; i++) {
|
||||
if (Offset >= map->segments[i].start_offset && Offset < map->segments[i].end_offset) {
|
||||
validOffset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validOffset) {
|
||||
gErrorsDuringAirCopy++;
|
||||
AIRCOPY_CheckComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t *pData = &g_FSK_Buffer[2];
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
EEPROM_WriteBuffer(Offset, pData);
|
||||
pData += 4;
|
||||
Offset += 8;
|
||||
const AIRCOPY_Segment_t *seg = AIRCOPY_FindSegmentForOffset(Offset);
|
||||
|
||||
if (seg == NULL) {
|
||||
gErrorsDuringAirCopy++;
|
||||
AIRCOPY_CheckComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Offset == 0x1E00) {
|
||||
gAircopyState = AIRCOPY_COMPLETE;
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
getScreenShot(false);
|
||||
#endif
|
||||
if (seg->write_mode == AIRCOPY_WRITE_BYTES)
|
||||
{
|
||||
/* Raw bytes stream, written in 8-byte EEPROM chunks */
|
||||
const uint8_t *p8 = (const uint8_t *)&g_FSK_Buffer[2];
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
{
|
||||
EEPROM_WriteBuffer(Offset + (i * 8), p8 + (i * 8));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Structured data path (kept as-is) */
|
||||
const uint16_t *pData = &g_FSK_Buffer[2];
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
{
|
||||
EEPROM_WriteBuffer(Offset, pData);
|
||||
pData += 4;
|
||||
Offset += 8;
|
||||
}
|
||||
}
|
||||
|
||||
gAirCopyBlockNumber++;
|
||||
AIRCOPY_CheckComplete();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Key Processing
|
||||
// ============================================================================
|
||||
|
||||
static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
@@ -245,6 +424,25 @@ static void AIRCOPY_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
gAircopyState = AIRCOPY_TRANSFER;
|
||||
}
|
||||
|
||||
static void AIRCOPY_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
{
|
||||
if (bKeyHeld || !bKeyPressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(Direction)
|
||||
{
|
||||
case 1:
|
||||
gAircopyCurrentMapIndex = (gAircopyCurrentMapIndex + 1) % AIRCOPY_NUM_MAPS;
|
||||
break;
|
||||
case -1:
|
||||
gAircopyCurrentMapIndex = (gAircopyCurrentMapIndex + AIRCOPY_NUM_MAPS - 1) % AIRCOPY_NUM_MAPS;
|
||||
break;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_AIRCOPY;
|
||||
}
|
||||
|
||||
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
{
|
||||
switch (Key) {
|
||||
@@ -266,9 +464,21 @@ void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
case KEY_EXIT:
|
||||
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
else
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
else
|
||||
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+70
-6
@@ -21,14 +21,73 @@
|
||||
|
||||
#include "driver/keyboard.h"
|
||||
|
||||
enum AIRCOPY_State_t
|
||||
{
|
||||
// ============================================================================
|
||||
// General definitions
|
||||
// ============================================================================
|
||||
|
||||
#define AIRCOPY_BLOCK_SIZE 0x0040u // 64 bytes per AirCopy block
|
||||
#define AIRCOPY_CHANNELS_PER_BANK 128
|
||||
#define AIRCOPY_NUM_BANKS MR_CHANNELS_MAX / AIRCOPY_CHANNELS_PER_BANK
|
||||
#define AIRCOPY_CHANNEL_SIZE 16 // bytes per channel (freq/name)
|
||||
#define AIRCOPY_BANK_SIZE_BYTES 0x1080u // 0x800 (Freq) + 0x800 (Name) + 0x80 (Attr)
|
||||
#define AIRCOPY_BAR_WIDTH 120 // Visible width of the progress gauge
|
||||
|
||||
// ============================================================================
|
||||
// Segment write mode
|
||||
// ============================================================================
|
||||
|
||||
/*
|
||||
* Defines how a segment must be written to EEPROM.
|
||||
*
|
||||
* - STRUCT: structured data (frequencies, names)
|
||||
* - BYTES : raw byte stream (attributes, settings, etc.)
|
||||
*/
|
||||
typedef enum {
|
||||
AIRCOPY_WRITE_STRUCT = 0,
|
||||
AIRCOPY_WRITE_BYTES = 1,
|
||||
} AIRCOPY_WriteMode_t;
|
||||
|
||||
// ============================================================================
|
||||
// Transfer segment structure
|
||||
// ============================================================================
|
||||
|
||||
/*
|
||||
* Describes a contiguous EEPROM region involved in AirCopy.
|
||||
* The write_mode defines how the RX side must write the data.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t start_offset;
|
||||
uint16_t end_offset;
|
||||
AIRCOPY_WriteMode_t write_mode;
|
||||
} AIRCOPY_Segment_t;
|
||||
|
||||
// ============================================================================
|
||||
// Transfer map structure
|
||||
// ============================================================================
|
||||
|
||||
/*
|
||||
* A transfer map is a collection of segments describing
|
||||
* one complete AirCopy operation (bank, settings, etc.).
|
||||
*/
|
||||
typedef struct {
|
||||
const AIRCOPY_Segment_t *segments;
|
||||
uint16_t num_segments;
|
||||
uint16_t total_blocks;
|
||||
} AIRCOPY_TransferMap_t;
|
||||
|
||||
// ============================================================================
|
||||
// AirCopy state
|
||||
// ============================================================================
|
||||
|
||||
typedef enum {
|
||||
AIRCOPY_READY = 0,
|
||||
AIRCOPY_TRANSFER,
|
||||
AIRCOPY_COMPLETE
|
||||
};
|
||||
} AIRCOPY_State_t;
|
||||
|
||||
typedef enum AIRCOPY_State_t AIRCOPY_State_t;
|
||||
// ============================================================================
|
||||
// Globals
|
||||
// ============================================================================
|
||||
|
||||
extern AIRCOPY_State_t gAircopyState;
|
||||
extern uint16_t gAirCopyBlockNumber;
|
||||
@@ -37,10 +96,15 @@ extern uint8_t gAirCopyIsSendMode;
|
||||
|
||||
extern uint16_t g_FSK_Buffer[36];
|
||||
|
||||
// ============================================================================
|
||||
// API
|
||||
// ============================================================================
|
||||
|
||||
bool AIRCOPY_SendMessage(void);
|
||||
void AIRCOPY_StorePacket(void);
|
||||
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
|
||||
|
||||
#endif
|
||||
const AIRCOPY_TransferMap_t* AIRCOPY_GetCurrentMap(void);
|
||||
|
||||
#endif
|
||||
#endif // ENABLE_AIRCOPY
|
||||
#endif // APP_AIRCOPY_H
|
||||
+6
-1
@@ -1363,6 +1363,11 @@ static void CheckKeys(void)
|
||||
void APP_TimeSlice10ms(void)
|
||||
{
|
||||
gNextTimeslice = false;
|
||||
|
||||
if (gScheduleVfoSave) {
|
||||
SETTINGS_SaveVfoIndicesFlush();
|
||||
}
|
||||
|
||||
gFlashLightBlinkCounter++;
|
||||
|
||||
#ifdef ENABLE_AM_FIX
|
||||
@@ -2187,7 +2192,7 @@ Skip:
|
||||
}
|
||||
|
||||
if (gRequestSaveChannel > 0) { // TODO: remove the gRequestSaveChannel, why use global variable for that??
|
||||
if ((!bKeyHeld && !bKeyPressed) || UI_MENU_GetCurrentMenuId())
|
||||
if ((!bKeyHeld && !bKeyPressed) || (UI_MENU_GetCurrentMenuId() != 0 && gScreenToDisplay == DISPLAY_MENU))
|
||||
{
|
||||
SETTINGS_SaveChannel(gTxVfo->CHANNEL_SAVE, gEeprom.TX_VFO, gTxVfo, gRequestSaveChannel);
|
||||
|
||||
|
||||
+16
-10
@@ -52,7 +52,13 @@ void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_directi
|
||||
gScanStateDir = scan_direction;
|
||||
|
||||
if (IS_MR_CHANNEL(gNextMrChannel))
|
||||
{ // channel mode
|
||||
{
|
||||
|
||||
if(!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) {
|
||||
RADIO_NextValidList();
|
||||
}
|
||||
|
||||
// channel mode
|
||||
if (storeBackupSettings) {
|
||||
initialFrqOrChan = gRxVfo->CHANNEL_SAVE;
|
||||
lastFoundFrqOrChan = initialFrqOrChan;
|
||||
@@ -249,12 +255,12 @@ static void NextFreqChannel(void)
|
||||
|
||||
static void NextMemChannel(void)
|
||||
{
|
||||
static unsigned int prev_mr_chan = 0;
|
||||
const bool enabled = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT < 4) ? gEeprom.SCAN_LIST_ENABLED[gEeprom.SCAN_LIST_DEFAULT - 1] : true;
|
||||
const int chan1 = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT < 4) ? gEeprom.SCANLIST_PRIORITY_CH1[gEeprom.SCAN_LIST_DEFAULT - 1] : -1;
|
||||
const int chan2 = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT < 4) ? gEeprom.SCANLIST_PRIORITY_CH2[gEeprom.SCAN_LIST_DEFAULT - 1] : -1;
|
||||
const unsigned int prev_chan = gNextMrChannel;
|
||||
unsigned int chan = 0;
|
||||
static uint16_t prev_mr_chan = 0;
|
||||
const bool enabled = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT <= MR_CHANNELS_LIST + 1) ? gEeprom.SCAN_LIST_ENABLED : true;
|
||||
const int16_t chan1 = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT <= MR_CHANNELS_LIST + 1 && gEeprom.SCANLIST_PRIORITY_CH[0] != MR_CHANNELS_MAX) ? gEeprom.SCANLIST_PRIORITY_CH[0] : -1;
|
||||
const int16_t chan2 = (gEeprom.SCAN_LIST_DEFAULT > 0 && gEeprom.SCAN_LIST_DEFAULT <= MR_CHANNELS_LIST + 1 && gEeprom.SCANLIST_PRIORITY_CH[1] != MR_CHANNELS_MAX) ? gEeprom.SCANLIST_PRIORITY_CH[1] : -1;
|
||||
const uint16_t prev_chan = gNextMrChannel;
|
||||
uint16_t chan = 0;
|
||||
|
||||
//char str[64] = "";
|
||||
|
||||
@@ -327,15 +333,15 @@ static void NextMemChannel(void)
|
||||
case SCAN_NEXT_CHAN_MR:
|
||||
currentScanList = SCAN_NEXT_CHAN_MR;
|
||||
gNextMrChannel = prev_mr_chan;
|
||||
chan = 0xff;
|
||||
chan = 0xFFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled || chan == 0xff)
|
||||
if (!enabled || chan == 0xFFFF)
|
||||
{
|
||||
chan = RADIO_FindNextChannel(gNextMrChannel + gScanStateDir, gScanStateDir, true, gEeprom.SCAN_LIST_DEFAULT);
|
||||
if (chan == 0xFF)
|
||||
if (chan == 0xFFFF)
|
||||
{ // no valid channel found
|
||||
chan = MR_CHANNEL_FIRST;
|
||||
}
|
||||
|
||||
+2
-2
@@ -60,8 +60,8 @@ void COMMON_SwitchVFOMode()
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t Channel = RADIO_FindNextChannel(gEeprom.MrChannel[gEeprom.TX_VFO], 1, false, 0);
|
||||
if (Channel != 0xFF)
|
||||
uint16_t Channel = RADIO_FindNextChannel(gEeprom.MrChannel[gEeprom.TX_VFO], 1, false, 0);
|
||||
if (Channel != 0xFFFF)
|
||||
{ // swap to channel mode
|
||||
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
|
||||
#ifdef ENABLE_VOICE
|
||||
|
||||
+15
-16
@@ -32,11 +32,7 @@
|
||||
#include "ui/inputbox.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
uint16_t gFM_Channels[20];
|
||||
uint16_t gFM_Channels[FM_CHANNELS_MAX];
|
||||
bool gFmRadioMode;
|
||||
uint8_t gFmRadioCountdown_500ms;
|
||||
volatile uint16_t gFmPlayCountdown_10ms;
|
||||
@@ -124,7 +120,12 @@ void FM_TurnOff(void)
|
||||
|
||||
void FM_EraseChannels(void)
|
||||
{
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
//PY25Q16_SectorErase(0x003000);
|
||||
|
||||
uint8_t clearBuf[128];
|
||||
memset(clearBuf, 0xFF, sizeof(clearBuf));
|
||||
PY25Q16_WriteBuffer(0x00A028, clearBuf, sizeof(clearBuf), false);
|
||||
|
||||
memset(gFM_Channels, 0xFF, sizeof(gFM_Channels));
|
||||
}
|
||||
|
||||
@@ -318,7 +319,7 @@ static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (Channel < 20) {
|
||||
else if (Channel < FM_CHANNELS_MAX) {
|
||||
#ifdef ENABLE_VOICE
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
#endif
|
||||
@@ -494,7 +495,7 @@ static void Key_UP_DOWN(uint8_t state, int8_t Step)
|
||||
|
||||
if (gAskToSave) {
|
||||
gRequestDisplayScreen = DISPLAY_FM;
|
||||
gFM_ChannelPosition = NUMBER_AddWithWraparound(gFM_ChannelPosition, Step, 0, 19);
|
||||
gFM_ChannelPosition = NUMBER_AddWithWraparound(gFM_ChannelPosition, Step, 0, FM_CHANNELS_MAX - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -552,18 +553,16 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
Key_MENU(state);
|
||||
break;
|
||||
case KEY_UP:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
Key_UP_DOWN(state, -1);
|
||||
#else
|
||||
else
|
||||
Key_UP_DOWN(state, 1);
|
||||
#endif
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
Key_UP_DOWN(state, 1);
|
||||
#else
|
||||
else
|
||||
Key_UP_DOWN(state, -1);
|
||||
#endif
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
Key_EXIT(state);
|
||||
@@ -598,10 +597,10 @@ void FM_Play(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (gFM_ChannelPosition < 20)
|
||||
if (gFM_ChannelPosition < FM_CHANNELS_MAX)
|
||||
gFM_Channels[gFM_ChannelPosition++] = gEeprom.FM_FrequencyPlaying;
|
||||
|
||||
if (gFM_ChannelPosition >= 20) {
|
||||
if (gFM_ChannelPosition >= FM_CHANNELS_MAX) {
|
||||
FM_PlayAndUpdate();
|
||||
GUI_SelectNextDisplay(DISPLAY_FM);
|
||||
return;
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
#ifdef ENABLE_FMRADIO
|
||||
|
||||
#include "driver/keyboard.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define FM_CHANNEL_UP 0x01
|
||||
#define FM_CHANNEL_DOWN 0xFF
|
||||
@@ -28,7 +29,7 @@ enum {
|
||||
FM_SCAN_OFF = 0U,
|
||||
};
|
||||
|
||||
extern uint16_t gFM_Channels[20];
|
||||
extern uint16_t gFM_Channels[FM_CHANNELS_MAX];
|
||||
extern bool gFmRadioMode;
|
||||
extern uint8_t gFmRadioCountdown_500ms;
|
||||
extern volatile uint16_t gFmPlayCountdown_10ms;
|
||||
|
||||
+83
-23
@@ -63,20 +63,23 @@ static void toggle_chan_scanlist(void)
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelAttributes_t *att = MR_GetChannelAttributes(gTxVfo->CHANNEL_SAVE);
|
||||
|
||||
// Remove exclude
|
||||
if(gMR_ChannelExclude[gTxVfo->CHANNEL_SAVE] == true)
|
||||
if(att->exclude == true)
|
||||
{
|
||||
gMR_ChannelExclude[gTxVfo->CHANNEL_SAVE] = false;
|
||||
att->exclude = false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t scanTmp = gTxVfo->SCANLIST1_PARTICIPATION | (gTxVfo->SCANLIST2_PARTICIPATION << 1) | (gTxVfo->SCANLIST3_PARTICIPATION << 2);
|
||||
uint8_t scanlist = gTxVfo->SCANLIST_PARTICIPATION;
|
||||
|
||||
scanTmp = (scanTmp++ < 7) ? scanTmp: 0;
|
||||
scanlist++;
|
||||
|
||||
gTxVfo->SCANLIST1_PARTICIPATION = (scanTmp >> 0) & 0x01;
|
||||
gTxVfo->SCANLIST2_PARTICIPATION = (scanTmp >> 1) & 0x01;
|
||||
gTxVfo->SCANLIST3_PARTICIPATION = (scanTmp >> 2) & 0x01;
|
||||
if (scanlist > MR_CHANNELS_LIST + 1)
|
||||
scanlist = 0;
|
||||
|
||||
gTxVfo->SCANLIST_PARTICIPATION = scanlist;
|
||||
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true);
|
||||
|
||||
@@ -348,8 +351,8 @@ void channelMove(uint16_t Channel)
|
||||
gAnotherVoiceID = (VOICE_ID_t)Key;
|
||||
#endif
|
||||
|
||||
gEeprom.MrChannel[Vfo] = (uint8_t)Channel;
|
||||
gEeprom.ScreenChannel[Vfo] = (uint8_t)Channel;
|
||||
gEeprom.MrChannel[Vfo] = (uint16_t)Channel;
|
||||
gEeprom.ScreenChannel[Vfo] = (uint16_t)Channel;
|
||||
//gRequestSaveVFO = true;
|
||||
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
|
||||
|
||||
@@ -386,11 +389,11 @@ void channelMoveSwitch(void) {
|
||||
Channel = (Channel * 10) + gInputBox[i];
|
||||
}
|
||||
|
||||
if ((Channel == 0) && (gInputBoxIndex != 3)) {
|
||||
if ((Channel == 0) && (gInputBoxIndex != 4)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gInputBoxIndex == 3) {
|
||||
if (gInputBoxIndex == 4) {
|
||||
gInputBoxIndex = 0;
|
||||
gKeyInputCountdown = 1;
|
||||
|
||||
@@ -401,6 +404,7 @@ void channelMoveSwitch(void) {
|
||||
}
|
||||
|
||||
channelMove(Channel - 1);
|
||||
SETTINGS_SaveVfoIndices();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,8 +436,15 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
if (!gWasFKeyPressed) { // F-key wasn't pressed
|
||||
|
||||
if (gScanStateDir != SCAN_OFF){
|
||||
/*
|
||||
switch(Key) {
|
||||
case KEY_0...KEY_5:
|
||||
case KEY_0:
|
||||
gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
#endif
|
||||
break;
|
||||
case KEY_1...KEY_9:
|
||||
gEeprom.SCAN_LIST_DEFAULT = Key;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
@@ -443,6 +454,54 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
break;
|
||||
}
|
||||
return;
|
||||
*/
|
||||
|
||||
INPUTBOX_Append(Key);
|
||||
|
||||
/* Wait until exactly two digits are entered */
|
||||
if (gInputBoxIndex < 2)
|
||||
return;
|
||||
|
||||
/* Two digits entered */
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
uint8_t value = (gInputBox[0] * 10) + gInputBox[1];
|
||||
|
||||
/* 00 = ALL scan lists */
|
||||
if (value == 0)
|
||||
{
|
||||
gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* 01 .. MR_CHANNELS_LIST */
|
||||
if (value <= MR_CHANNELS_LIST)
|
||||
{
|
||||
if (RADIO_CheckValidList(value))
|
||||
{
|
||||
/* Requested scan list is valid */
|
||||
gEeprom.SCAN_LIST_DEFAULT = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Requested scan list is empty or invalid:
|
||||
jump to the next valid scan list */
|
||||
gEeprom.SCAN_LIST_DEFAULT = value;
|
||||
RADIO_NextValidList();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
SETTINGS_WriteCurrentState();
|
||||
#endif
|
||||
}
|
||||
|
||||
gInputBoxIndex = 0;
|
||||
|
||||
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t Vfo = gEeprom.TX_VFO;
|
||||
@@ -673,12 +732,15 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
if (bKeyPressed) { // long press MENU key
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
// Exclude work with list 1, 2, 3 or all list
|
||||
// Exclude channel
|
||||
if(gScanStateDir != SCAN_OFF)
|
||||
{
|
||||
if(FUNCTION_IsRx() || gScanPauseDelayIn_10ms > 9)
|
||||
{
|
||||
gMR_ChannelExclude[gTxVfo->CHANNEL_SAVE] = true;
|
||||
ChannelAttributes_t *att = MR_GetChannelAttributes(lastFoundFrqOrChan);
|
||||
att->exclude = true;
|
||||
|
||||
MR_SaveChannelAttributesToFlash(lastFoundFrqOrChan, att);
|
||||
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gFlagResetVfos = true;
|
||||
@@ -855,7 +917,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
gPowerHigh = false;
|
||||
#endif
|
||||
|
||||
uint8_t Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO];
|
||||
uint16_t Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO];
|
||||
|
||||
if (bKeyHeld || !bKeyPressed) { // key held or released
|
||||
if (gInputBoxIndex > 0)
|
||||
@@ -885,7 +947,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
if (!IS_NOAA_CHANNEL(Channel))
|
||||
#endif
|
||||
{
|
||||
uint8_t Next;
|
||||
uint16_t Next;
|
||||
if (IS_FREQ_CHANNEL(Channel)) { // step/down in frequency
|
||||
const uint32_t frequency = APP_SetFrequencyByStep(gTxVfo, Direction);
|
||||
|
||||
@@ -901,7 +963,7 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
}
|
||||
|
||||
Next = RADIO_FindNextChannel(Channel + Direction, Direction, false, 0);
|
||||
if (Next == 0xFF)
|
||||
if (Next == 0xFFFF)
|
||||
return;
|
||||
if (Channel == Next)
|
||||
return;
|
||||
@@ -977,18 +1039,16 @@ void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
MAIN_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
#else
|
||||
else
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
#endif
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0)
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
#else
|
||||
else
|
||||
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
#endif
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
MAIN_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
|
||||
+133
-77
@@ -34,6 +34,7 @@
|
||||
#include "helper/battery.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "../driver/st7565.h"
|
||||
#if defined(ENABLE_OVERLAY)
|
||||
#include "sram-overlay.h"
|
||||
#endif
|
||||
@@ -41,9 +42,6 @@
|
||||
#include "ui/menu.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
uint8_t gUnlockAllTxConfCnt;
|
||||
|
||||
@@ -234,9 +232,6 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
#endif
|
||||
case MENU_BCL:
|
||||
case MENU_BEEP:
|
||||
case MENU_S_ADD1:
|
||||
case MENU_S_ADD2:
|
||||
case MENU_S_ADD3:
|
||||
case MENU_STE:
|
||||
case MENU_D_ST:
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
@@ -257,6 +252,7 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
case MENU_SET_TMR:
|
||||
case MENU_S_PRI:
|
||||
#endif
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_OFF_ON) - 1;
|
||||
@@ -299,11 +295,10 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
*pMax = MR_CHANNEL_LAST;
|
||||
break;
|
||||
|
||||
case MENU_SLIST1:
|
||||
case MENU_SLIST2:
|
||||
case MENU_SLIST3:
|
||||
*pMin = -1;
|
||||
*pMax = MR_CHANNEL_LAST;
|
||||
case MENU_S_PRI_CH_1:
|
||||
case MENU_S_PRI_CH_2:
|
||||
//*pMin = 0;
|
||||
*pMax = MR_CHANNEL_LAST + 2;
|
||||
break;
|
||||
|
||||
case MENU_SAVE:
|
||||
@@ -316,9 +311,14 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
*pMax = 4;
|
||||
break;
|
||||
|
||||
case MENU_S_LIST:
|
||||
case MENU_LIST_CH:
|
||||
//*pMin = 0;
|
||||
*pMax = 5;
|
||||
*pMax = MR_CHANNELS_LIST + 1;
|
||||
break;
|
||||
|
||||
case MENU_S_LIST:
|
||||
*pMin = 1;
|
||||
*pMax = MR_CHANNELS_LIST + 1;
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
@@ -371,6 +371,11 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
*pMax = 4;
|
||||
break;
|
||||
|
||||
case MENU_SET_NAV:
|
||||
//*pMin = 0;
|
||||
*pMax = 1;
|
||||
break;
|
||||
|
||||
case MENU_F1SHRT:
|
||||
case MENU_F1LONG:
|
||||
case MENU_F2SHRT:
|
||||
@@ -399,19 +404,19 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_SET_TOT) - 1;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
case MENU_SET_CTR:
|
||||
*pMin = 1;
|
||||
*pMax = 15;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case MENU_TX_LOCK:
|
||||
#ifdef ENABLE_FEAT_F4HWN_INV
|
||||
#ifdef ENABLE_FEAT_F4HWN_INV
|
||||
case MENU_SET_INV:
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_OFF_ON) - 1;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case MENU_SET_LCK:
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_SET_LCK) - 1;
|
||||
@@ -421,6 +426,12 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_SET_MET) - 1;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
case MENU_SET_AUD:
|
||||
//*pMin = 0;
|
||||
*pMax = ARRAY_SIZE(gSubMenu_SET_AUD) - 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
case MENU_SET_NFM:
|
||||
//*pMin = 0;
|
||||
@@ -583,6 +594,14 @@ void MENU_AcceptSetting(void)
|
||||
SETTINGS_SaveChannelName(gSubMenuSelection, edit);
|
||||
return;
|
||||
|
||||
case MENU_S_PRI_CH_1:
|
||||
gEeprom.SCANLIST_PRIORITY_CH[0] = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
case MENU_S_PRI_CH_2:
|
||||
gEeprom.SCANLIST_PRIORITY_CH[1] = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
case MENU_SAVE:
|
||||
gEeprom.BATTERY_SAVE = gSubMenuSelection;
|
||||
break;
|
||||
@@ -661,22 +680,8 @@ void MENU_AcceptSetting(void)
|
||||
gKeyLockCountdown = gEeprom.AUTO_KEYPAD_LOCK * 30; // 15 seconds step
|
||||
break;
|
||||
|
||||
case MENU_S_ADD1:
|
||||
gTxVfo->SCANLIST1_PARTICIPATION = gSubMenuSelection;
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true);
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gFlagResetVfos = true;
|
||||
return;
|
||||
|
||||
case MENU_S_ADD2:
|
||||
gTxVfo->SCANLIST2_PARTICIPATION = gSubMenuSelection;
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true);
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gFlagResetVfos = true;
|
||||
return;
|
||||
|
||||
case MENU_S_ADD3:
|
||||
gTxVfo->SCANLIST3_PARTICIPATION = gSubMenuSelection;
|
||||
case MENU_LIST_CH:
|
||||
gTxVfo->SCANLIST_PARTICIPATION = gSubMenuSelection;
|
||||
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true);
|
||||
gVfoConfigureMode = VFO_CONFIGURE;
|
||||
gFlagResetVfos = true;
|
||||
@@ -718,6 +723,10 @@ void MENU_AcceptSetting(void)
|
||||
gEeprom.SCAN_LIST_DEFAULT = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
case MENU_S_PRI:
|
||||
gEeprom.SCAN_LIST_ENABLED = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_ALARM
|
||||
case MENU_AL_MOD:
|
||||
gEeprom.ALARM_MODE = gSubMenuSelection;
|
||||
@@ -877,11 +886,11 @@ void MENU_AcceptSetting(void)
|
||||
#endif
|
||||
|
||||
case MENU_BATCAL:
|
||||
{ // voltages are averages between discharge curves of 1600 and 2200 mAh
|
||||
{ // voltages are averages between discharge curves of 1600 and 2200 mAh
|
||||
// gBatteryCalibration[0] = (520ul * gSubMenuSelection) / 760; // 5.20V empty, blinking above this value, reduced functionality below
|
||||
// gBatteryCalibration[1] = (689ul * gSubMenuSelection) / 760; // 6.89V, ~5%, 1 bars above this value
|
||||
// gBatteryCalibration[2] = (724ul * gSubMenuSelection) / 760; // 7.24V, ~17%, 2 bars above this value
|
||||
gBatteryCalibration[3] = gSubMenuSelection; // 7.6V, ~29%, 3 bars above this value
|
||||
gBatteryCalibration[3] = gSubMenuSelection; // 7.6V, ~29%, 3 bars above this value
|
||||
// gBatteryCalibration[4] = (771ul * gSubMenuSelection) / 760; // 7.71V, ~65%, 4 bars above this value
|
||||
// gBatteryCalibration[5] = 2300;
|
||||
SETTINGS_SaveBatteryCalibration(gBatteryCalibration);
|
||||
@@ -892,6 +901,10 @@ void MENU_AcceptSetting(void)
|
||||
gEeprom.BATTERY_TYPE = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
case MENU_SET_NAV:
|
||||
gEeprom.SET_NAV = gSubMenuSelection;
|
||||
break;
|
||||
|
||||
case MENU_F1SHRT:
|
||||
case MENU_F1LONG:
|
||||
case MENU_F2SHRT:
|
||||
@@ -929,11 +942,11 @@ void MENU_AcceptSetting(void)
|
||||
case MENU_SET_EOT:
|
||||
gSetting_set_eot = gSubMenuSelection;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
case MENU_SET_CTR:
|
||||
gSetting_set_ctr = gSubMenuSelection;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case MENU_SET_INV:
|
||||
gSetting_set_inv = gSubMenuSelection;
|
||||
break;
|
||||
@@ -946,6 +959,12 @@ void MENU_AcceptSetting(void)
|
||||
case MENU_SET_GUI:
|
||||
gSetting_set_gui = gSubMenuSelection;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
case MENU_SET_AUD:
|
||||
gSetting_set_audio = gSubMenuSelection;
|
||||
RADIO_SetModulation(gRxVfo->Modulation);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
case MENU_SET_NFM:
|
||||
gSetting_set_nfm = gSubMenuSelection;
|
||||
@@ -1163,16 +1182,8 @@ void MENU_ShowCurrentSetting(void)
|
||||
gSubMenuSelection = gEeprom.AUTO_KEYPAD_LOCK;
|
||||
break;
|
||||
|
||||
case MENU_S_ADD1:
|
||||
gSubMenuSelection = gTxVfo->SCANLIST1_PARTICIPATION;
|
||||
break;
|
||||
|
||||
case MENU_S_ADD2:
|
||||
gSubMenuSelection = gTxVfo->SCANLIST2_PARTICIPATION;
|
||||
break;
|
||||
|
||||
case MENU_S_ADD3:
|
||||
gSubMenuSelection = gTxVfo->SCANLIST3_PARTICIPATION;
|
||||
case MENU_LIST_CH:
|
||||
gSubMenuSelection = gTxVfo->SCANLIST_PARTICIPATION;
|
||||
break;
|
||||
|
||||
case MENU_STE:
|
||||
@@ -1205,10 +1216,16 @@ void MENU_ShowCurrentSetting(void)
|
||||
gSubMenuSelection = gEeprom.SCAN_LIST_DEFAULT;
|
||||
break;
|
||||
|
||||
case MENU_SLIST1:
|
||||
case MENU_SLIST2:
|
||||
case MENU_SLIST3:
|
||||
gSubMenuSelection = RADIO_FindNextChannel(0, 1, true, UI_MENU_GetCurrentMenuId() - MENU_SLIST1 + 1);
|
||||
case MENU_S_PRI:
|
||||
gSubMenuSelection = gEeprom.SCAN_LIST_ENABLED;
|
||||
break;
|
||||
|
||||
case MENU_S_PRI_CH_1:
|
||||
gSubMenuSelection = gEeprom.SCANLIST_PRIORITY_CH[0];
|
||||
break;
|
||||
|
||||
case MENU_S_PRI_CH_2:
|
||||
gSubMenuSelection = gEeprom.SCANLIST_PRIORITY_CH[1];
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_ALARM
|
||||
@@ -1333,6 +1350,10 @@ void MENU_ShowCurrentSetting(void)
|
||||
gSubMenuSelection = gEeprom.BATTERY_TYPE;
|
||||
break;
|
||||
|
||||
case MENU_SET_NAV:
|
||||
gSubMenuSelection = gEeprom.SET_NAV;
|
||||
break;
|
||||
|
||||
case MENU_F1SHRT:
|
||||
case MENU_F1LONG:
|
||||
case MENU_F2SHRT:
|
||||
@@ -1376,11 +1397,11 @@ void MENU_ShowCurrentSetting(void)
|
||||
case MENU_SET_EOT:
|
||||
gSubMenuSelection = gSetting_set_eot;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
#ifdef ENABLE_FEAT_F4HWN_CTR
|
||||
case MENU_SET_CTR:
|
||||
gSubMenuSelection = gSetting_set_ctr;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case MENU_SET_INV:
|
||||
gSubMenuSelection = gSetting_set_inv;
|
||||
break;
|
||||
@@ -1393,6 +1414,11 @@ void MENU_ShowCurrentSetting(void)
|
||||
case MENU_SET_GUI:
|
||||
gSubMenuSelection = gSetting_set_gui;
|
||||
break;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
case MENU_SET_AUD:
|
||||
gSubMenuSelection = gSetting_set_audio;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
case MENU_SET_NFM:
|
||||
gSubMenuSelection = gSetting_set_nfm;
|
||||
@@ -1524,6 +1550,8 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_1_CALL ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2 ||
|
||||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
|
||||
{ // enter 3-digit channel number
|
||||
|
||||
@@ -1842,7 +1870,7 @@ static void MENU_Key_STAR(const bool bKeyPressed, const bool bKeyHeld)
|
||||
static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
{
|
||||
uint8_t VFO;
|
||||
uint8_t Channel;
|
||||
uint16_t Channel;
|
||||
bool bCheckScanList;
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && gIsInSubMenu && edit_index >= 0)
|
||||
@@ -1925,34 +1953,60 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
|
||||
{
|
||||
case MENU_DEL_CH:
|
||||
case MENU_1_CALL:
|
||||
case MENU_S_PRI_CH_1:
|
||||
case MENU_S_PRI_CH_2:
|
||||
case MENU_MEM_NAME:
|
||||
bCheckScanList = false;
|
||||
break;
|
||||
|
||||
case MENU_SLIST3:
|
||||
bCheckScanList = true;
|
||||
VFO = 3;
|
||||
break;
|
||||
case MENU_SLIST2:
|
||||
bCheckScanList = true;
|
||||
VFO = 2;
|
||||
break;
|
||||
case MENU_SLIST1:
|
||||
bCheckScanList = true;
|
||||
VFO = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
MENU_ClampSelection(Direction);
|
||||
gRequestDisplayScreen = DISPLAY_MENU;
|
||||
return;
|
||||
}
|
||||
|
||||
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
|
||||
if (Channel != 0xFF)
|
||||
gSubMenuSelection = Channel;
|
||||
if(UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 || UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2)
|
||||
{
|
||||
static int16_t last;
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MENU;
|
||||
if(Direction > 0 && gSubMenuSelection == MR_CHANNELS_MAX)
|
||||
{
|
||||
gSubMenuSelection = -1;
|
||||
last = -1;
|
||||
}
|
||||
else if(Direction < 0 && gSubMenuSelection == MR_CHANNELS_MAX)
|
||||
{
|
||||
gSubMenuSelection = MR_CHANNELS_MAX;
|
||||
last = MR_CHANNELS_MAX;
|
||||
}
|
||||
|
||||
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
|
||||
if (Channel != 0xFFFF)
|
||||
gSubMenuSelection = Channel;
|
||||
|
||||
if(Direction > 0 && gSubMenuSelection < last)
|
||||
{
|
||||
gSubMenuSelection = MR_CHANNELS_MAX;
|
||||
}
|
||||
else if(Direction < 0 && gSubMenuSelection > last)
|
||||
{
|
||||
gSubMenuSelection = MR_CHANNELS_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
last = Channel;
|
||||
}
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MENU;
|
||||
}
|
||||
else
|
||||
{
|
||||
Channel = RADIO_FindNextChannel(gSubMenuSelection + Direction, Direction, bCheckScanList, VFO);
|
||||
if (Channel != 0xFFFF)
|
||||
gSubMenuSelection = Channel;
|
||||
|
||||
gRequestDisplayScreen = DISPLAY_MENU;
|
||||
}
|
||||
}
|
||||
|
||||
void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
@@ -1975,24 +2029,26 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
MENU_Key_MENU(bKeyPressed, bKeyHeld);
|
||||
break;
|
||||
case KEY_UP:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0) {
|
||||
if(gIsInSubMenu)
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
else
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
#else
|
||||
}
|
||||
else {
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
if(gEeprom.SET_NAV == 0) {
|
||||
if(gIsInSubMenu)
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
|
||||
else
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
#else
|
||||
}
|
||||
else {
|
||||
MENU_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
MENU_Key_EXIT(bKeyPressed, bKeyHeld);
|
||||
|
||||
+40
-51
@@ -103,8 +103,8 @@ RegisterSpec registerSpecs[] = {
|
||||
{},
|
||||
{"LNAs", BK4819_REG_13, 8, 0b11, 1},
|
||||
{"LNA", BK4819_REG_13, 5, 0b111, 1},
|
||||
{"VGA", BK4819_REG_13, 0, 0b111, 1},
|
||||
{"BPF", BK4819_REG_3D, 0, 0xFFFF, 0x2aaa},
|
||||
{"PGA", BK4819_REG_13, 0, 0b111, 1},
|
||||
//{"BPF", BK4819_REG_3D, 0, 0xFFFF, 0x2aaa},
|
||||
// {"MIX", 0x13, 3, 0b11, 1}, // TODO: hidden
|
||||
};
|
||||
|
||||
@@ -112,7 +112,7 @@ RegisterSpec registerSpecs[] = {
|
||||
const int8_t LNAsOptions[] = {-19, -16, -11, 0};
|
||||
const int8_t LNAOptions[] = {-24, -19, -14, -9, -6, -4, -2, 0};
|
||||
const int8_t VGAOptions[] = {-33, -27, -21, -15, -9, -6, -3, 0};
|
||||
const char *BPFOptions[] = {"8.46", "7.25", "6.35", "5.64", "5.08", "4.62", "4.23"};
|
||||
//const char *BPFOptions[] = {"8.46", "7.25", "6.35", "5.64", "5.08", "4.62", "4.23"};
|
||||
#endif
|
||||
|
||||
uint16_t statuslineUpdateTimer = 0;
|
||||
@@ -121,7 +121,7 @@ uint16_t statuslineUpdateTimer = 0;
|
||||
static void LoadSettings()
|
||||
{
|
||||
uint8_t Data[8] = {0};
|
||||
PY25Q16_ReadBuffer(0x00c000, Data, sizeof(Data));
|
||||
PY25Q16_ReadBuffer(0x00A158, Data, sizeof(Data));
|
||||
|
||||
settings.scanStepIndex = ((Data[3] & 0xF0) >> 4);
|
||||
|
||||
@@ -148,11 +148,11 @@ static void LoadSettings()
|
||||
static void SaveSettings()
|
||||
{
|
||||
uint8_t Data[8] = {0};
|
||||
PY25Q16_ReadBuffer(0x00c000, Data, sizeof(Data));
|
||||
PY25Q16_ReadBuffer(0x00A158, Data, sizeof(Data));
|
||||
|
||||
Data[3] = (settings.scanStepIndex << 4) | (settings.stepsCount << 2) | settings.listenBw;
|
||||
|
||||
PY25Q16_WriteBuffer(0x00c000, Data, sizeof(Data), true);
|
||||
PY25Q16_WriteBuffer(0x00A158, Data, sizeof(Data), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -183,8 +183,10 @@ static uint16_t GetRegMenuValue(uint8_t st)
|
||||
|
||||
void LockAGC()
|
||||
{
|
||||
RADIO_SetupAGC(settings.modulationType == MODULATION_AM, lockAGC);
|
||||
lockAGC = true;
|
||||
//RADIO_SetupAGC(settings.modulationType == MODULATION_AM, lockAGC);
|
||||
RADIO_SetupAGC(false, lockAGC);
|
||||
//lockAGC = true;
|
||||
lockAGC = false;
|
||||
}
|
||||
|
||||
static void SetRegMenuValue(uint8_t st, bool add)
|
||||
@@ -504,7 +506,9 @@ static void ToggleRX(bool on)
|
||||
#endif
|
||||
isListening = on;
|
||||
|
||||
RADIO_SetupAGC(settings.modulationType == MODULATION_AM, lockAGC);
|
||||
//RADIO_SetupAGC(settings.modulationType == MODULATION_AM, lockAGC);
|
||||
RADIO_SetupAGC(false, lockAGC);
|
||||
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, on);
|
||||
|
||||
ToggleAudio(on);
|
||||
@@ -950,16 +954,16 @@ uint8_t Rssi2Y(uint16_t rssi)
|
||||
// Total width units = (bars - 1) full bars + 2 half bars = bars
|
||||
// First bar: half width, middle bars: full width, last bar: half width
|
||||
// Scale: 128 pixels / (bars - 1) = pixels per full bar
|
||||
uint16_t fullWidth = 128 * 2 / (bars - 1); // x2 for precision
|
||||
uint16_t fullWidth = (128 << 8) / (bars - 1); // x256 for precision
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
x = fullWidth / 4; // half of half (because fullWidth is x2)
|
||||
x = fullWidth / (2 << 8); // half of /256 (because fullWidth is x256)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Position = half + (i-1) full bars + current bar
|
||||
x = fullWidth / 4 + (uint16_t)i * fullWidth / 2;
|
||||
x = fullWidth / (2 << 8) + (uint16_t)i * fullWidth / (1 << 8);
|
||||
if (i == bars - 1) x = 128; // Last bar ends at screen edge
|
||||
}
|
||||
}
|
||||
@@ -1181,6 +1185,8 @@ static void DrawArrow(uint8_t x)
|
||||
|
||||
static void OnKeyDown(uint8_t key)
|
||||
{
|
||||
bool nav = (gEeprom.SET_NAV != 0);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_3:
|
||||
@@ -1203,22 +1209,20 @@ static void OnKeyDown(uint8_t key)
|
||||
break;
|
||||
case KEY_UP:
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
if (!gScanRangeStart)
|
||||
if (!gScanRangeStart) {
|
||||
#endif
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
UpdateCurrentFreq(false);
|
||||
#else
|
||||
UpdateCurrentFreq(true);
|
||||
UpdateCurrentFreq(nav);
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
if (!gScanRangeStart)
|
||||
if (!gScanRangeStart) {
|
||||
#endif
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
UpdateCurrentFreq(true);
|
||||
#else
|
||||
UpdateCurrentFreq(false);
|
||||
UpdateCurrentFreq(!nav);
|
||||
#ifdef ENABLE_SCAN_RANGES
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case KEY_SIDE1:
|
||||
@@ -1326,6 +1330,8 @@ static void OnKeyDownFreqInput(uint8_t key)
|
||||
|
||||
void OnKeyDownStill(KEY_Code_t key)
|
||||
{
|
||||
bool nav = (gEeprom.SET_NAV != 0);
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_3:
|
||||
@@ -1335,37 +1341,18 @@ void OnKeyDownStill(KEY_Code_t key)
|
||||
UpdateDBMax(false);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (menuState)
|
||||
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
{
|
||||
SetRegMenuValue(menuState, false);
|
||||
if (menuState) {
|
||||
SetRegMenuValue(menuState, nav);
|
||||
break;
|
||||
}
|
||||
UpdateCurrentFreqStill(false);
|
||||
#else
|
||||
{
|
||||
SetRegMenuValue(menuState, true);
|
||||
break;
|
||||
}
|
||||
UpdateCurrentFreqStill(true);
|
||||
#endif
|
||||
UpdateCurrentFreqStill(nav);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (menuState)
|
||||
#ifdef ENABLE_NAVIG_LEFT_RIGHT
|
||||
{
|
||||
SetRegMenuValue(menuState, true);
|
||||
if (menuState) {
|
||||
SetRegMenuValue(menuState, !nav);
|
||||
break;
|
||||
}
|
||||
UpdateCurrentFreqStill(true);
|
||||
#else
|
||||
{
|
||||
SetRegMenuValue(menuState, false);
|
||||
break;
|
||||
}
|
||||
UpdateCurrentFreqStill(false);
|
||||
#endif
|
||||
UpdateCurrentFreqStill(!nav);
|
||||
break;
|
||||
case KEY_STAR:
|
||||
UpdateRssiTriggerLevel(true);
|
||||
@@ -1432,7 +1419,7 @@ static void RenderStatus()
|
||||
static void RenderSpectrum()
|
||||
{
|
||||
DrawTicks();
|
||||
DrawArrow(128u * peak.i / GetStepsCount());
|
||||
DrawArrow(128u * peak.i / (GetStepsCount() - 1));
|
||||
DrawSpectrum();
|
||||
DrawRssiTriggerLevel();
|
||||
DrawF(peak.f);
|
||||
@@ -1484,9 +1471,9 @@ static void RenderStill()
|
||||
uint8_t offset = PAD_LEFT;
|
||||
uint8_t row = 4;
|
||||
|
||||
for (int i = 0, idx = 1; idx <= 4; ++i, ++idx)
|
||||
for (int i = 0, idx = 1; idx <= 3; ++i, ++idx)
|
||||
{
|
||||
if (idx == 5)
|
||||
if (idx == 4)
|
||||
{
|
||||
row += 2;
|
||||
i = 0;
|
||||
@@ -1517,10 +1504,12 @@ static void RenderStill()
|
||||
{
|
||||
sprintf(String, "%ddB", VGAOptions[GetRegMenuValue(idx)]);
|
||||
}
|
||||
/*
|
||||
else if(idx == 4)
|
||||
{
|
||||
sprintf(String, "%skHz", BPFOptions[(GetRegMenuValue(idx) / 0x2aaa)]);
|
||||
}
|
||||
*/
|
||||
#else
|
||||
sprintf(String, "%u", GetRegMenuValue(idx));
|
||||
#endif
|
||||
@@ -1611,7 +1600,7 @@ static void UpdateScan()
|
||||
{
|
||||
Scan();
|
||||
|
||||
if (scanInfo.i < scanInfo.measurementsCount)
|
||||
if (scanInfo.i + 1 < scanInfo.measurementsCount)
|
||||
{
|
||||
NextScanStep();
|
||||
return;
|
||||
|
||||
+22
-3
@@ -677,14 +677,26 @@ bool UART_IsCommandAvailable(uint32_t Port)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (1)
|
||||
// Limit iterations to prevent long loops when buffer is full of non-command data
|
||||
uint16_t maxIterations = ReadBufSize + 1;
|
||||
|
||||
while (maxIterations--)
|
||||
{
|
||||
if ((*pReadPointer) == DmaLength)
|
||||
return false;
|
||||
|
||||
while ((*pReadPointer) != DmaLength && ReadBuf[*pReadPointer] != 0xABU)
|
||||
// Find 0xAB with iteration limit
|
||||
uint16_t searchLimit = ReadBufSize;
|
||||
while ((*pReadPointer) != DmaLength && ReadBuf[*pReadPointer] != 0xABU && searchLimit--)
|
||||
*pReadPointer = DMA_INDEX((*pReadPointer), 1, ReadBufSize);
|
||||
|
||||
if (searchLimit == 0)
|
||||
{
|
||||
// Too many bytes without finding 0xAB - sync to current position and exit
|
||||
*pReadPointer = DmaLength;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((*pReadPointer) == DmaLength)
|
||||
return false;
|
||||
|
||||
@@ -702,6 +714,13 @@ bool UART_IsCommandAvailable(uint32_t Port)
|
||||
*pReadPointer = DMA_INDEX(*pReadPointer, 1, ReadBufSize);
|
||||
}
|
||||
|
||||
if (maxIterations == 0)
|
||||
{
|
||||
// Safety: too many outer loop iterations
|
||||
*pReadPointer = DmaLength;
|
||||
return false;
|
||||
}
|
||||
|
||||
Index = DMA_INDEX(*pReadPointer, 2, ReadBufSize);
|
||||
Size = (ReadBuf[DMA_INDEX(Index, 1, ReadBufSize)] << 8) | ReadBuf[Index];
|
||||
|
||||
@@ -847,4 +866,4 @@ void UART_HandleCommand(uint32_t Port)
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
gUART_LockScreenshot = 20; // lock screenshot
|
||||
#endif
|
||||
}
|
||||
}
|
||||
+7
-110
@@ -168,13 +168,13 @@ const uint8_t BITMAP_Antenna[5] =
|
||||
|
||||
const uint8_t BITMAP_VFO_Lock[7] =
|
||||
{
|
||||
0b01111100,
|
||||
0b01000110,
|
||||
0b01000101,
|
||||
0b01000101,
|
||||
0b01000101,
|
||||
0b01000110,
|
||||
0b01111100,
|
||||
0b00111100,
|
||||
0b00100110,
|
||||
0b00100101,
|
||||
0b00100101,
|
||||
0b00100101,
|
||||
0b00100110,
|
||||
0b00111100,
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_VFO_Default[7] =
|
||||
@@ -199,109 +199,6 @@ const uint8_t BITMAP_VFO_NotDefault[7] =
|
||||
0b00001000
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanList0[7] =
|
||||
{ // '0' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01000011,
|
||||
0b01011101,
|
||||
0b01100001,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanList1[7] =
|
||||
{ // '1' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111011,
|
||||
0b01000001,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanList2[7] =
|
||||
{ // '2' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01001101,
|
||||
0b01010101,
|
||||
0b01011011,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanList3[7] =
|
||||
{ // '3' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01011101,
|
||||
0b01010101,
|
||||
0b01101011,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanListE[7] =
|
||||
{ // 'E' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01000001,
|
||||
0b01010101,
|
||||
0b01010101,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanList123[19] =
|
||||
{
|
||||
// '123' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111011,
|
||||
0b01000001,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01001101,
|
||||
0b01010101,
|
||||
0b01011011,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01011101,
|
||||
0b01010101,
|
||||
0b01101011,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_ScanListAll[19] =
|
||||
{
|
||||
// 'All' symbol
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01000011,
|
||||
0b01110101,
|
||||
0b01000011,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01000001,
|
||||
0b01011111,
|
||||
0b01011111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b01000001,
|
||||
0b01011111,
|
||||
0b01011111,
|
||||
0b01111111,
|
||||
0b01111111
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_compand[6] =
|
||||
{
|
||||
0b00000000,
|
||||
|
||||
@@ -39,13 +39,6 @@ extern const uint8_t BITMAP_Antenna[5];
|
||||
extern const uint8_t BITMAP_VFO_Default[7];
|
||||
extern const uint8_t BITMAP_VFO_NotDefault[7];
|
||||
extern const uint8_t BITMAP_VFO_Lock[7];
|
||||
extern const uint8_t BITMAP_ScanList0[7];
|
||||
extern const uint8_t BITMAP_ScanList1[7];
|
||||
extern const uint8_t BITMAP_ScanList2[7];
|
||||
extern const uint8_t BITMAP_ScanList3[7];
|
||||
extern const uint8_t BITMAP_ScanList123[19];
|
||||
extern const uint8_t BITMAP_ScanListAll[19];
|
||||
extern const uint8_t BITMAP_ScanListE[7];
|
||||
extern const uint8_t BITMAP_PowerUser[3];
|
||||
extern const uint8_t BITMAP_compand[6];
|
||||
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "dcs.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
#include "misc.h"
|
||||
|
||||
// CTCSS Hz * 10
|
||||
const uint16_t CTCSS_Options[50] = {
|
||||
|
||||
+14
-2
@@ -31,7 +31,7 @@
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
#define PWM_FREQ 240
|
||||
#define PWM_FREQ 320
|
||||
#define DUTY_CYCLE_LEVELS 64
|
||||
|
||||
#define DUTY_CYCLE_ON_VALUE GPIO_PIN_MASK(GPIO_PIN_BACKLIGHT)
|
||||
@@ -47,7 +47,19 @@ uint16_t gBacklightCountdown_500ms = 0;
|
||||
bool backlightOn;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
const uint8_t value[] = {0, 3, 6, 9, 15, 24, 38, 62, 100, 159, 255};
|
||||
const uint8_t value[] = {
|
||||
0, // 0 off
|
||||
8, // 1 visible in the dark
|
||||
14, // 2
|
||||
22, // 3
|
||||
32, // 4
|
||||
48, // 5
|
||||
72, // 6
|
||||
104, // 7
|
||||
150, // 8
|
||||
200, // 9
|
||||
255 // 10 max
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
#include "driver/system.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
static const uint16_t BK1080_RegisterTable[] =
|
||||
{
|
||||
0x0008, 0x1080, 0x0201, 0x0000, 0x40C0, 0x0A1F, 0x002E, 0x02FF,
|
||||
|
||||
@@ -163,7 +163,7 @@ typedef enum BK4819_GPIO_PIN_t BK4819_GPIO_PIN_t;
|
||||
#define BK4819_REG_02_SHIFT_SQUELCH_LOST 2
|
||||
#define BK4819_REG_02_SHIFT_FSK_RX_SYNC 1
|
||||
|
||||
#define BK4819_REG_02_MASK_FSK_TX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_TX)
|
||||
#define BK4819_REG_02_MASK_FSK_TX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_TX_FINISHED)
|
||||
#define BK4819_REG_02_MASK_FSK_FIFO_ALMOST_EMPTY (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_EMPTY)
|
||||
#define BK4819_REG_02_MASK_FSK_RX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_RX_FINISHED)
|
||||
#define BK4819_REG_02_MASK_FSK_FIFO_ALMOST_FULL (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_FULL)
|
||||
|
||||
+1
-4
@@ -19,6 +19,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "settings.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
@@ -28,10 +29,6 @@
|
||||
#include "driver/systick.h"
|
||||
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
#define PIN_CSN GPIO_MAKE_PIN(GPIOF, LL_GPIO_PIN_9)
|
||||
#define PIN_SCL GPIO_MAKE_PIN(GPIOB, LL_GPIO_PIN_8)
|
||||
#define PIN_SDA GPIO_MAKE_PIN(GPIOB, LL_GPIO_PIN_9)
|
||||
|
||||
+2
-6
@@ -19,6 +19,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "settings.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
@@ -27,11 +28,6 @@
|
||||
#include "driver/system.h"
|
||||
#include "driver/systick.h"
|
||||
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
#define PIN_CSN GPIO_MAKE_PIN(GPIOF, LL_GPIO_PIN_9)
|
||||
#define PIN_SCL GPIO_MAKE_PIN(GPIOB, LL_GPIO_PIN_8)
|
||||
#define PIN_SDA GPIO_MAKE_PIN(GPIOB, LL_GPIO_PIN_9)
|
||||
@@ -177,7 +173,7 @@ void BK4819_Init(void)
|
||||
|
||||
BK4819_WriteRegister(0x73, 0x4691);
|
||||
BK4819_WriteRegister(0x77, 0x88EF);
|
||||
BK4819_WriteRegister(BK4819_REG_19, 0x104E);
|
||||
BK4819_WriteRegister(BK4819_REG_19, 0x1041);
|
||||
BK4819_WriteRegister(BK4819_REG_28, 0x0B40);
|
||||
BK4819_WriteRegister(BK4819_REG_29, 0xAA00);
|
||||
BK4819_WriteRegister(0x2A, 0x6600);
|
||||
|
||||
+27
-24
@@ -38,30 +38,33 @@ typedef struct
|
||||
#define _MK_MAPPING(PY25Q16_Addr, EEPROM_From, EEPROM_To) {PY25Q16_Addr, EEPROM_From, EEPROM_To - EEPROM_From}
|
||||
|
||||
static const AddrMapping_t ADDR_MAPPINGS[] = {
|
||||
// Sorted by EEPROM addr
|
||||
_MK_MAPPING(0x000000, 0x0000, 0x0c80), //
|
||||
_MK_MAPPING(0x001000, 0x0c80, 0x0d60), //
|
||||
_MK_MAPPING(0x002000, 0x0d60, 0x0e30), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x0e30, 0x0e40), //
|
||||
_MK_MAPPING(0x003000, 0x0e40, 0x0e68), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x0e68, 0x0e70), //
|
||||
_MK_MAPPING(0x004000, 0x0e70, 0x0e80), //
|
||||
_MK_MAPPING(0x005000, 0x0e80, 0x0e88), //
|
||||
_MK_MAPPING(0x006000, 0x0e88, 0x0e90), //
|
||||
_MK_MAPPING(0x007000, 0x0e90, 0x0ee0), //
|
||||
_MK_MAPPING(0x008000, 0x0ee0, 0x0f18), //
|
||||
_MK_MAPPING(0x009000, 0x0f18, 0x0f20), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x0f20, 0x0f30), //
|
||||
_MK_MAPPING(0x00a000, 0x0f30, 0x0f40), //
|
||||
_MK_MAPPING(0x00b000, 0x0f40, 0x0f48), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x0f48, 0x0f50), //
|
||||
_MK_MAPPING(0x00e000, 0x0f50, 0x1bd0), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x1bd0, 0x1c00), //
|
||||
_MK_MAPPING(0x00f000, 0x1c00, 0x1d00), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x1d00, 0x1e00), //
|
||||
_MK_MAPPING(0x010000, 0x1e00, 0x1f90), //
|
||||
_MK_MAPPING(HOLE_ADDR, 0x1f90, 0x1ff0), //
|
||||
_MK_MAPPING(0x00c000, 0x1ff0, 0x2000), //
|
||||
_MK_MAPPING(0x000000, 0x000000, 0x001000), // 256 MR Freq * 16 Bytes (ex 0x000000)
|
||||
_MK_MAPPING(0x001000, 0x001000, 0x002000), // 256 MR Freq * 16 Bytes
|
||||
_MK_MAPPING(0x002000, 0x002000, 0x003000), // 256 MR Freq * 16 Bytes
|
||||
_MK_MAPPING(0x003000, 0x003000, 0x004000), // 256 MR Freq * 16 Bytes
|
||||
|
||||
_MK_MAPPING(0x004000, 0x004000, 0x005000), // 256 MR Name * 16 Bytes (ex 0x00e000)
|
||||
_MK_MAPPING(0x005000, 0x005000, 0x006000), // 256 MR Name * 16 Bytes
|
||||
_MK_MAPPING(0x006000, 0x006000, 0x007000), // 256 MR Name * 16 Bytes
|
||||
_MK_MAPPING(0x007000, 0x007000, 0x008000), // 256 MR Name * 16 Bytes
|
||||
|
||||
_MK_MAPPING(0x008000, 0x008000, 0x00880E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000)
|
||||
|
||||
_MK_MAPPING(0x009000, 0x009000, 0x0090D6), // 14 VFO * 16 Bytes (ex 0x001000)
|
||||
|
||||
_MK_MAPPING(0x00A000, 0x00A000, 0x00A170), // Settings * 16 Bytes (ex 0x004000) 0x00A000 -> 0x00A010
|
||||
// Settings * 16 Bytes (ex 0x005000) 0x00A010 -> 0x00A020
|
||||
// Settings FM * 8 Bytes (0x006000) 0x00A020 -> 0x00A028
|
||||
// MR FM * 128 Bytes (0x003000) 0x00A028 -> 0x00A0A8
|
||||
// Settings * 80 Bytes (0x007000) 0x00A0A8 -> 0x00A0F8
|
||||
// Settings * 56 Bytes (0x008000) 0x00A0F8 -> 0x00A130
|
||||
// Settings Scanlist * 8 Bytes (0x009000) 0x00A130 -> 0x00A140
|
||||
// Settings AES * 16 Bytes (0x00A000) 0x00A140 -> 0x00A150
|
||||
// Settings * 8 Bytes (0x00B000) 0x00A150 -> 0x00A158
|
||||
// Settings F4HWN * 8 Bytes (0x00C000) 0x00A158 -> 0x00A160
|
||||
// Settings Version * 16 Bytes 0x00A160 -> 0x00A170
|
||||
|
||||
_MK_MAPPING(0x010000, 0x00B000, 0x00B200), // Calibration 512 Bytes!!!
|
||||
};
|
||||
|
||||
static void AddrTranslate(uint16_t EEPROM_Addr, uint16_t Size, uint32_t *PY25Q16_Addr_out, uint16_t *Size_out, bool *End_out);
|
||||
|
||||
+27
-3
@@ -22,6 +22,11 @@
|
||||
#define PIN_SCL GPIO_MAKE_PIN(GPIOF, LL_GPIO_PIN_5)
|
||||
#define PIN_SDA GPIO_MAKE_PIN(GPIOF, LL_GPIO_PIN_6)
|
||||
|
||||
// CRITICAL FIX: Define I2C timeout to prevent infinite hangs
|
||||
// If I2C slave doesn't respond, timeout after this many iterations
|
||||
// 255 iterations × 1µs = 255µs, plus we add safety margin
|
||||
#define I2C_ACK_TIMEOUT_ITERATIONS 255
|
||||
|
||||
static inline void SCL_Set()
|
||||
{
|
||||
GPIO_SetOutputPin(PIN_SCL);
|
||||
@@ -141,11 +146,24 @@ int I2C_Write(uint8_t Data)
|
||||
SCL_Set();
|
||||
SYSTICK_DelayUs(1);
|
||||
|
||||
for (i = 0; i < 255; i++) {
|
||||
// CRITICAL FIX #1: Add timeout to ACK check
|
||||
// Original: for (i = 0; i < 255; i++)
|
||||
// Problem: If I2C slave doesn't respond, waits 255 iterations = 255µs spin-wait
|
||||
// If slave broken/disconnected: loops forever with no break condition
|
||||
//
|
||||
// Solution: Keep iteration limit but add explicit timeout check
|
||||
// If slave doesn't pull SDA low within 255 iterations, return error
|
||||
// This prevents indefinite hangs while still being conservative
|
||||
|
||||
for (i = 0; i < I2C_ACK_TIMEOUT_ITERATIONS; i++) {
|
||||
if (!SDA_IsSet()) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
// CRITICAL FIX #2: Small delay between ACK checks
|
||||
// This prevents CPU from spinning 255 times at full speed
|
||||
// Also gives slave time to respond
|
||||
SYSTICK_DelayUs(1);
|
||||
}
|
||||
|
||||
SCL_Reset();
|
||||
@@ -178,11 +196,17 @@ int I2C_WriteBuffer(const void *pBuffer, uint8_t Size)
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < Size; i++) {
|
||||
// CRITICAL FIX #3: Check return value of I2C_Write
|
||||
// Original: if (I2C_Write(*pData++) < 0)
|
||||
// This detects if ACK timeout occurred
|
||||
// If slave not responding, return error immediately instead of continuing
|
||||
if (I2C_Write(*pData++) < 0) {
|
||||
// I2C slave not responding (ACK timeout)
|
||||
// Return error instead of continuing to write more bytes
|
||||
// This prevents cascading timeouts
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
+50
-21
@@ -80,36 +80,59 @@ KEY_Code_t KEYBOARD_Poll(void)
|
||||
{
|
||||
KEY_Code_t Key = KEY_INVALID;
|
||||
|
||||
// if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT))
|
||||
// return KEY_PTT;
|
||||
|
||||
// *****************
|
||||
|
||||
// Scan all 5 columns - never break early to avoid GPIO state issues
|
||||
for (unsigned int j = 0; j < 5; j++)
|
||||
{
|
||||
uint32_t reg;
|
||||
unsigned int i;
|
||||
unsigned int k;
|
||||
uint32_t match_count = 0; // Count consecutive matching reads
|
||||
|
||||
// Set all high
|
||||
// Set all columns high first
|
||||
GPIO_SetOutputPin(PIN_COLS);
|
||||
|
||||
// Clear the pin we are selecting
|
||||
// Clear the specific column we are selecting
|
||||
if (j > 0)
|
||||
GPIO_ResetOutputPin(PIN_COL(j - 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++)
|
||||
{
|
||||
SYSTICK_DelayUs(1);
|
||||
uint32_t reg2 = read_rows();
|
||||
i *= reg == reg2;
|
||||
reg = reg2;
|
||||
GPIO_ResetOutputPin(PIN_COL(j - 1));
|
||||
}
|
||||
|
||||
if (i < 3)
|
||||
break; // noise is too bad
|
||||
// Debounce: Read rows multiple times and look for stable reads
|
||||
// CRITICAL FIX #1: Proper debounce logic (replaces confusing i *= syntax)
|
||||
// CRITICAL FIX #2: Increased delay from 1µs to 10µs for real keyboard bounce capture
|
||||
// CRITICAL FIX #3: Clear match_count if reads differ (noise detection)
|
||||
reg = 0;
|
||||
for (unsigned int k = 0; k < 8; k++)
|
||||
{
|
||||
SYSTICK_DelayUs(10); // FIX #2: Increased from 1µs to 10µs
|
||||
uint32_t reg2 = read_rows();
|
||||
|
||||
// FIX #3: Clear match counter if values don't match
|
||||
if (reg2 != reg)
|
||||
{
|
||||
match_count = 0;
|
||||
reg = reg2;
|
||||
}
|
||||
else
|
||||
{
|
||||
match_count++;
|
||||
}
|
||||
|
||||
// Success: We have 3 consecutive matching reads = stable signal
|
||||
if (match_count >= 2)
|
||||
{
|
||||
break; // Debounce complete for this column
|
||||
}
|
||||
}
|
||||
|
||||
// FIX #1: Do NOT break on noise - continue scanning all columns
|
||||
// Only skip key detection if debounce failed, but GPIO state is cleaned
|
||||
if (match_count < 2)
|
||||
{
|
||||
// Debounce failed (too much noise), but continue to next column
|
||||
// This prevents GPIO from staying in invalid state and blocking other columns
|
||||
continue;
|
||||
}
|
||||
|
||||
// Debounce successful, check which row is pressed in this column
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!(reg & PIN_MASK_ROW(i)))
|
||||
@@ -120,8 +143,14 @@ KEY_Code_t KEYBOARD_Poll(void)
|
||||
}
|
||||
|
||||
if (Key != KEY_INVALID)
|
||||
break;
|
||||
{
|
||||
break; // Found a valid key, stop scanning
|
||||
}
|
||||
}
|
||||
|
||||
// CRITICAL FIX #4: Always clean up GPIO state - set all columns high at end
|
||||
// This ensures GPIO pins are in a known state even if function exited early due to noise
|
||||
GPIO_SetOutputPin(PIN_COLS);
|
||||
|
||||
return Key;
|
||||
}
|
||||
}
|
||||
+39
-14
@@ -25,6 +25,7 @@
|
||||
#include "driver/system.h"
|
||||
#include "driver/systick.h"
|
||||
#include "external/printf/printf.h"
|
||||
#include "misc.h"
|
||||
|
||||
// #define DEBUG
|
||||
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
static uint32_t SectorCacheAddr = 0x1000000;
|
||||
static uint8_t SectorCache[SECTOR_SIZE];
|
||||
static uint8_t BlackHole[1];
|
||||
static uint8_t BlackHole[4] __attribute__((aligned(4)));
|
||||
static volatile bool TC_Flag;
|
||||
|
||||
static inline void CS_Assert()
|
||||
@@ -226,20 +227,20 @@ void PY25Q16_Init()
|
||||
|
||||
void PY25Q16_ReadBuffer(uint32_t Address, void *pBuffer, uint32_t Size)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("spi flash read: %06x %ld\n", Address, Size);
|
||||
#endif
|
||||
CS_Assert();
|
||||
|
||||
SPI_WriteByte(0x03); // Fast read
|
||||
WriteAddr(Address);
|
||||
SPI_WriteByte(0x03); // Send read command
|
||||
WriteAddr(Address); // Send address (3 bytes)
|
||||
|
||||
if (Size >= 16)
|
||||
// CRITICAL: Flush RX FIFO before DMA to remove residual data
|
||||
while (LL_SPI_RX_FIFO_EMPTY != LL_SPI_GetRxFIFOLevel(SPIx))
|
||||
{
|
||||
SPI_ReadBuf((uint8_t *)pBuffer, Size);
|
||||
LL_SPI_ReceiveData8(SPIx); // Read and discard
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (Size >= 16) {
|
||||
SPI_ReadBuf((uint8_t *)pBuffer, Size);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < Size; i++)
|
||||
{
|
||||
((uint8_t *)(pBuffer))[i] = SPI_WriteByte(0xff);
|
||||
@@ -254,6 +255,11 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
|
||||
#ifdef DEBUG
|
||||
printf("spi flash write: %06x %ld %d\n", Address, Size, Append);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
gDebug++;
|
||||
#endif
|
||||
|
||||
uint32_t SecIndex = Address / SECTOR_SIZE;
|
||||
uint32_t SecAddr = SecIndex * SECTOR_SIZE;
|
||||
uint32_t SecOffset = Address % SECTOR_SIZE;
|
||||
@@ -261,6 +267,9 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
|
||||
|
||||
while (Size)
|
||||
{
|
||||
// CRITICAL FIX #1: Wait for flash ready before processing each sector
|
||||
WaitWIP();
|
||||
|
||||
if (Size < SecSize)
|
||||
{
|
||||
SecSize = Size;
|
||||
@@ -289,6 +298,10 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
|
||||
if (Erase)
|
||||
{
|
||||
SectorErase(SecAddr);
|
||||
|
||||
// CRITICAL FIX #2: Erase takes ~300ms, must complete before program starts
|
||||
WaitWIP();
|
||||
|
||||
if (Append)
|
||||
{
|
||||
SectorProgram(SecAddr, SectorCache, SecOffset + SecSize);
|
||||
@@ -313,6 +326,9 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
|
||||
SecOffset = 0;
|
||||
SecSize = SECTOR_SIZE;
|
||||
} // while
|
||||
|
||||
// CRITICAL FIX #3: Ensure all writes complete before function returns
|
||||
WaitWIP();
|
||||
}
|
||||
|
||||
void PY25Q16_SectorErase(uint32_t Address)
|
||||
@@ -454,11 +470,20 @@ void DMA1_Channel4_5_6_7_IRQHandler()
|
||||
LL_DMA_DisableIT_TC(DMA1, CHANNEL_RD);
|
||||
LL_DMA_ClearFlag_TC4(DMA1);
|
||||
|
||||
while (LL_SPI_TX_FIFO_EMPTY != LL_SPI_GetTxFIFOLevel(SPIx))
|
||||
// Wait a tiny bit for SPI to finish
|
||||
SYSTICK_DelayUs(10); // ← ADD THIS
|
||||
|
||||
uint32_t timeout = 10000;
|
||||
|
||||
while ((LL_SPI_TX_FIFO_EMPTY != LL_SPI_GetTxFIFOLevel(SPIx)) && timeout--)
|
||||
;
|
||||
while (LL_SPI_IsActiveFlag_BSY(SPIx))
|
||||
|
||||
timeout = 10000;
|
||||
while (LL_SPI_IsActiveFlag_BSY(SPIx) && timeout--)
|
||||
;
|
||||
while (LL_SPI_RX_FIFO_EMPTY != LL_SPI_GetRxFIFOLevel(SPIx))
|
||||
|
||||
timeout = 10000;
|
||||
while ((LL_SPI_RX_FIFO_EMPTY != LL_SPI_GetRxFIFOLevel(SPIx)) && timeout--)
|
||||
;
|
||||
|
||||
LL_SPI_DisableDMAReq_TX(SPIx);
|
||||
@@ -466,4 +491,4 @@ void DMA1_Channel4_5_6_7_IRQHandler()
|
||||
|
||||
TC_Flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-19
@@ -13,39 +13,44 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "py32f0xx.h"
|
||||
#include "systick.h"
|
||||
#include "misc.h"
|
||||
|
||||
// 0x20000324
|
||||
static uint32_t gTickMultiplier;
|
||||
|
||||
void SYSTICK_Init(void)
|
||||
{
|
||||
SysTick_Config(480000);
|
||||
gTickMultiplier = 48;
|
||||
SysTick_Config(SystemCoreClock / 100); // 10 ms (1/100 sec) systick interrupt
|
||||
gTickMultiplier = SystemCoreClock / 1000000;
|
||||
|
||||
NVIC_SetPriority(SysTick_IRQn, 0);
|
||||
}
|
||||
|
||||
void SYSTICK_DelayUs(uint32_t Delay)
|
||||
{
|
||||
const uint32_t ticks = Delay * gTickMultiplier;
|
||||
uint32_t elapsed_ticks = 0;
|
||||
uint32_t Start = SysTick->LOAD;
|
||||
uint32_t Previous = SysTick->VAL;
|
||||
do {
|
||||
uint32_t Current;
|
||||
|
||||
do {
|
||||
Current = SysTick->VAL;
|
||||
} while (Current == Previous);
|
||||
|
||||
uint32_t Delta = ((Current < Previous) ? - Current : Start - Current);
|
||||
|
||||
elapsed_ticks += Delta + Previous;
|
||||
|
||||
|
||||
// FIX: Simplified loop - removed inner "wait for change" loop
|
||||
while (elapsed_ticks < ticks)
|
||||
{
|
||||
uint32_t Current = SysTick->VAL;
|
||||
|
||||
// FIX: Corrected wraparound detection (was: "Current < Previous - 10")
|
||||
if (Current < Previous)
|
||||
{
|
||||
// Normal countdown case
|
||||
uint32_t Delta = Previous - Current;
|
||||
elapsed_ticks += Delta;
|
||||
}
|
||||
else if (Current > Previous)
|
||||
{
|
||||
// Wraparound case: SysTick went 0 → LOAD → Current
|
||||
uint32_t Delta = Previous + (Start - Current);
|
||||
elapsed_ticks += Delta;
|
||||
}
|
||||
|
||||
Previous = Current;
|
||||
} while (elapsed_ticks < ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-4
@@ -27,6 +27,11 @@
|
||||
#define USARTx USART1
|
||||
#define DMA_CHANNEL LL_DMA_CHANNEL_2
|
||||
|
||||
// CRITICAL FIX: Define UART TX timeout
|
||||
// If UART TX buffer doesn't clear within this many iterations, skip byte and continue
|
||||
// Prevents permanent freeze if UART is stuck
|
||||
#define UART_TX_TIMEOUT_ITERATIONS 10000
|
||||
|
||||
static bool UART_IsLogEnabled;
|
||||
uint8_t UART_DMA_Buffer[256];
|
||||
|
||||
@@ -111,9 +116,27 @@ void UART_Send(const void *pBuffer, uint32_t Size)
|
||||
|
||||
for (i = 0; i < Size; i++)
|
||||
{
|
||||
while (!LL_USART_IsActiveFlag_TXE(USARTx))
|
||||
;
|
||||
LL_USART_TransmitData8(USARTx, pData[i]);
|
||||
// CRITICAL FIX: Add timeout to UART TX busy-wait
|
||||
// Original: while (!LL_USART_IsActiveFlag_TXE(USARTx)) ;
|
||||
// Problem: If UART TX stuck or disconnected, this is infinite loop
|
||||
// Result: Radio freeze for 100ms+ while trying to send one character
|
||||
//
|
||||
// Solution: Add iteration counter timeout
|
||||
// If TXE flag doesn't set within timeout iterations, skip byte and continue
|
||||
// This caps maximum freeze at ~10ms per UART_Send() call
|
||||
|
||||
uint32_t timeout = UART_TX_TIMEOUT_ITERATIONS;
|
||||
while (!LL_USART_IsActiveFlag_TXE(USARTx) && timeout > 0)
|
||||
{
|
||||
timeout--;
|
||||
}
|
||||
|
||||
// Send byte only if TXE flag is set
|
||||
// If timeout occurred, skip this byte and continue
|
||||
if (timeout > 0)
|
||||
{
|
||||
LL_USART_TransmitData8(USARTx, pData[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,4 +157,4 @@ void UART_LogSend(const void *pBuffer, uint32_t Size)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -37,3 +37,25 @@ void VCP_Init()
|
||||
NVIC_SetPriority(USBD_IRQn, 3);
|
||||
NVIC_EnableIRQ(USBD_IRQn);
|
||||
}
|
||||
|
||||
bool VCP_ScreenshotPing(void)
|
||||
{
|
||||
static uint32_t read_ptr = 0;
|
||||
|
||||
uint32_t write_ptr = VCP_RxBufPointer;
|
||||
|
||||
while (read_ptr != write_ptr)
|
||||
{
|
||||
uint8_t b = VCP_RxBuf[read_ptr];
|
||||
|
||||
read_ptr++;
|
||||
if (read_ptr >= VCP_RX_BUF_SIZE)
|
||||
read_ptr = 0;
|
||||
|
||||
if (b == 0x55)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "usb_config.h"
|
||||
|
||||
#define VCP_RX_BUF_SIZE 256
|
||||
@@ -27,6 +28,7 @@ extern uint8_t VCP_RxBuf[VCP_RX_BUF_SIZE];
|
||||
extern volatile uint32_t VCP_RxBufPointer;
|
||||
|
||||
void VCP_Init();
|
||||
bool VCP_ScreenshotPing(void);
|
||||
|
||||
static inline void VCP_Send(const uint8_t *Buf, uint32_t Size)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define _1GHz_in_KHz 100000000
|
||||
#define DEFAULT_FREQ 43450000 // Use for Reset and Aircopy
|
||||
|
||||
typedef struct {
|
||||
const uint32_t lower;
|
||||
|
||||
+4
-2
@@ -61,8 +61,10 @@ BOOT_Mode_t BOOT_GetMode(void)
|
||||
return BOOT_MODE_F_LOCK;
|
||||
|
||||
#ifdef ENABLE_AIRCOPY
|
||||
if (Keys[0] == KEY_SIDE2)
|
||||
if (Keys[0] == KEY_SIDE2) {
|
||||
gAirCopyBootMode = true;
|
||||
return BOOT_MODE_AIRCOPY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -95,7 +97,7 @@ void BOOT_ProcessMode(BOOT_Mode_t Mode)
|
||||
gEeprom.KEY_2_LONG_PRESS_ACTION = ACTION_OPT_NONE;
|
||||
gEeprom.KEY_M_LONG_PRESS_ACTION = ACTION_OPT_NONE;
|
||||
|
||||
RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_LAST - 1, 43400000); // LPD
|
||||
RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_LAST - 1, DEFAULT_FREQ); // LPD
|
||||
|
||||
gRxVfo->CHANNEL_BANDWIDTH = BANDWIDTH_NARROW;
|
||||
gRxVfo->OUTPUT_POWER = OUTPUT_POWER_LOW1;
|
||||
|
||||
+3
-10
@@ -157,18 +157,11 @@ void Main(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
gEeprom.KEY_LOCK = 0;
|
||||
SETTINGS_SaveSettings();
|
||||
#ifndef ENABLE_VOX
|
||||
gMenuCursor = 67; // move to hidden section, fix me if change... !!! Remove VOX and Mic Bar
|
||||
#else
|
||||
gMenuCursor = 68; // move to hidden section, fix me if change... !!!
|
||||
#endif
|
||||
|
||||
gMenuCursor = MENU_ITEMS;
|
||||
|
||||
#ifdef ENABLE_NOAA
|
||||
gMenuCursor += 1; // move to hidden section, fix me if change... !!!
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
gMenuCursor += 1; // move to hidden section, fix me if change... !!!
|
||||
#endif
|
||||
gSubMenuSelection = gSetting_F_LOCK;
|
||||
#endif
|
||||
}
|
||||
@@ -262,7 +255,7 @@ void Main(void)
|
||||
|
||||
#ifdef ENABLE_VOICE
|
||||
{
|
||||
uint8_t Channel;
|
||||
uint16_t Channel;
|
||||
|
||||
AUDIO_SetVoiceID(0, VOICE_ID_WELCOME);
|
||||
|
||||
|
||||
+293
-7
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "driver/py25q16.h"
|
||||
|
||||
const uint8_t fm_radio_countdown_500ms = 2000 / 500; // 2 seconds
|
||||
const uint16_t fm_play_countdown_scan_10ms = 100 / 10; // 100ms
|
||||
@@ -125,13 +126,16 @@ enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
bool gSetting_set_lck = false;
|
||||
bool gSetting_set_met = 0;
|
||||
bool gSetting_set_gui = 0;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
uint8_t gSetting_set_audio = 0;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
bool gSetting_set_nfm = 0;
|
||||
#endif
|
||||
bool gSetting_set_tmr = 0;
|
||||
bool gSetting_set_ptt_session;
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
uint8_t gDebug;
|
||||
uint16_t gDebug;
|
||||
#endif
|
||||
uint8_t gDW = 0;
|
||||
uint8_t gCB = 0;
|
||||
@@ -139,6 +143,8 @@ enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
uint8_t crc[15] = { 0 };
|
||||
uint8_t lErrorsDuringAirCopy = 0;
|
||||
uint8_t gAircopyStep = 0;
|
||||
uint8_t gAircopyCurrentMapIndex = 0;
|
||||
bool gAirCopyBootMode = 0;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
bool gPowerHigh = false;
|
||||
bool gRemoveOffset = false;
|
||||
@@ -163,8 +169,13 @@ uint16_t gEEPROM_RSSI_CALIB[7][4];
|
||||
uint16_t gEEPROM_1F8A;
|
||||
uint16_t gEEPROM_1F8C;
|
||||
|
||||
ChannelAttributes_t gMR_ChannelAttributes[FREQ_CHANNEL_LAST + 1];
|
||||
bool gMR_ChannelExclude[FREQ_CHANNEL_LAST + 1];
|
||||
//
|
||||
// Cache-Based Architecture: channel attributes moved to Flash
|
||||
// Cache holds only active channels in RAM (instead of all!)
|
||||
//
|
||||
|
||||
MR_ChannelCache_t gMR_ChannelAttributes_Cache[MR_CHANNELS_CACHE_SIZE] = {0};
|
||||
ChannelAttributes_t gMR_ChannelAttributes_Current = {0};
|
||||
|
||||
volatile uint16_t gBatterySaveCountdown_10ms = battery_save_count_10ms;
|
||||
|
||||
@@ -191,7 +202,8 @@ volatile bool gTxTimeoutReached;
|
||||
volatile uint16_t gRxTimerCountdown_500ms;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
volatile uint8_t gUART_LockScreenshot = 0; // lock screenshot if Chirp is used
|
||||
volatile uint8_t gUART_LockScreenshot = 0; // lock screenshot if Chirp is used
|
||||
bool gUSB_ScreenshotEnabled = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -234,7 +246,7 @@ bool gFlagReconfigureVfos;
|
||||
uint8_t gVfoConfigureMode;
|
||||
bool gFlagResetVfos;
|
||||
bool gRequestSaveVFO;
|
||||
uint8_t gRequestSaveChannel;
|
||||
uint16_t gRequestSaveChannel;
|
||||
bool gRequestSaveSettings;
|
||||
#ifdef ENABLE_FMRADIO
|
||||
bool gRequestSaveFM;
|
||||
@@ -262,7 +274,7 @@ bool g_SquelchLost;
|
||||
volatile uint16_t gFlashLightBlinkCounter;
|
||||
|
||||
bool gFlagEndTransmission;
|
||||
uint8_t gNextMrChannel;
|
||||
uint16_t gNextMrChannel;
|
||||
ReceptionMode_t gRxReceptionMode;
|
||||
|
||||
bool gRxVfoIsActive;
|
||||
@@ -280,7 +292,7 @@ uint8_t gFSKWriteIndex;
|
||||
|
||||
#ifdef ENABLE_NOAA
|
||||
bool gIsNoaaMode;
|
||||
uint8_t gNoaaChannel;
|
||||
uint16_t gNoaaChannel;
|
||||
#endif
|
||||
|
||||
bool gUpdateDisplay;
|
||||
@@ -318,6 +330,10 @@ uint8_t gIsLocked = 0xFF;
|
||||
uint8_t gBacklightBrightnessOld;
|
||||
uint8_t gPttOnePushCounter = 0;
|
||||
uint32_t gBlinkCounter = 0;
|
||||
|
||||
uint16_t gVfoSaveCountdown_10ms = 0;
|
||||
bool gScheduleVfoSave = false;
|
||||
bool gVfoStateChanged = false;
|
||||
#endif
|
||||
|
||||
inline void FUNCTION_NOP() { ; }
|
||||
@@ -347,3 +363,273 @@ unsigned long StrToUL(const char * str)
|
||||
}
|
||||
return ul;
|
||||
}
|
||||
|
||||
//
|
||||
// Cache-Based Channel Attributes Implementation
|
||||
//
|
||||
//
|
||||
// This replaces the huge array (~ 2,000 bytes in RAM) with a smart cache system
|
||||
// that keeps only active channels in RAM and loads others from Flash on demand.
|
||||
//
|
||||
// SRAM Savings: ~ 2,000 bytes (84% reduction!)
|
||||
//
|
||||
|
||||
// Flash address where channel attributes start
|
||||
// NOTE: Verify this matches your Flash layout!
|
||||
|
||||
#define FLASH_CHANNEL_ATTR_BASE 0x8000
|
||||
|
||||
// Each channel takes 2 bytes (ChannelAttributes_t is uint16_t)
|
||||
#define FLASH_CHANNEL_ATTR_SIZE 2
|
||||
|
||||
// Cache hit/miss statistics (optional, for debugging)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
static uint32_t cache_hits = 0;
|
||||
static uint32_t cache_misses = 0;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Internal Helper Functions
|
||||
//
|
||||
|
||||
// Find cache entry for given channel
|
||||
// Returns index if found, -1 if not found
|
||||
|
||||
static int MR_FindInCache(uint16_t channel_id)
|
||||
{
|
||||
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
|
||||
if (gMR_ChannelAttributes_Cache[i].channel_id == channel_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find oldest entry in cache (for eviction - LRU)
|
||||
static int MR_FindOldestCacheEntry(void)
|
||||
{
|
||||
int oldest_index = 0;
|
||||
uint32_t oldest_time = gMR_ChannelAttributes_Cache[0].access_time;
|
||||
|
||||
for (int i = 1; i < MR_CHANNELS_CACHE_SIZE; i++) {
|
||||
if (gMR_ChannelAttributes_Cache[i].access_time < oldest_time) {
|
||||
oldest_time = gMR_ChannelAttributes_Cache[i].access_time;
|
||||
oldest_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return oldest_index;
|
||||
}
|
||||
|
||||
// Find empty cache slot
|
||||
// Returns index if found, -1 if cache is full
|
||||
static int MR_FindEmptyCacheSlot(void)
|
||||
{
|
||||
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
|
||||
if (gMR_ChannelAttributes_Cache[i].channel_id == 0xFFFF) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // Cache is full, need to evict
|
||||
}
|
||||
|
||||
// Get current time (for LRU eviction)
|
||||
static uint32_t GetCurrentTime(void)
|
||||
{
|
||||
// Using gBlinkCounter which increments continuously
|
||||
extern uint32_t gBlinkCounter;
|
||||
return gBlinkCounter;
|
||||
}
|
||||
|
||||
//
|
||||
// Public API Functions
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// Load channel attributes from Flash
|
||||
void MR_LoadChannelAttributesFromFlash(uint16_t channel_id, ChannelAttributes_t* attributes)
|
||||
{
|
||||
// CRITICAL: Validate channel_id
|
||||
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
|
||||
attributes->__val = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate Flash address
|
||||
uint32_t flash_addr = FLASH_CHANNEL_ATTR_BASE + (channel_id * sizeof(ChannelAttributes_t));
|
||||
|
||||
// Read 2 bytes from Flash
|
||||
PY25Q16_ReadBuffer(flash_addr, attributes, sizeof(ChannelAttributes_t));
|
||||
}
|
||||
|
||||
// Save channel attributes to Flash
|
||||
void MR_SaveChannelAttributesToFlash(uint16_t channel_id, const ChannelAttributes_t* attributes)
|
||||
{
|
||||
// CRITICAL: Validate channel_id
|
||||
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate Flash address
|
||||
uint16_t flash_addr = FLASH_CHANNEL_ATTR_BASE + (channel_id * FLASH_CHANNEL_ATTR_SIZE);
|
||||
|
||||
// Write 2 bytes to Flash
|
||||
PY25Q16_WriteBuffer(flash_addr, attributes, sizeof(ChannelAttributes_t), false);
|
||||
}
|
||||
|
||||
// Get channel attributes (from cache or Flash)
|
||||
// This is the main function used by the rest of the code
|
||||
ChannelAttributes_t* MR_GetChannelAttributes(uint16_t channel_id)
|
||||
{
|
||||
// Input validation
|
||||
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check cache first (FAST PATH)
|
||||
int cache_index = MR_FindInCache(channel_id);
|
||||
|
||||
if (cache_index >= 0) {
|
||||
// CACHE HIT
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
cache_hits++;
|
||||
#endif
|
||||
|
||||
// Update access time for LRU
|
||||
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
|
||||
|
||||
return &gMR_ChannelAttributes_Cache[cache_index].attributes;
|
||||
}
|
||||
|
||||
// CACHE MISS - Load from Flash
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
cache_misses++;
|
||||
#endif
|
||||
|
||||
// Find slot for new entry
|
||||
int slot = MR_FindEmptyCacheSlot();
|
||||
|
||||
if (slot < 0) {
|
||||
// Cache is full, evict oldest entry
|
||||
slot = MR_FindOldestCacheEntry();
|
||||
}
|
||||
|
||||
// Load from Flash into cache slot
|
||||
MR_LoadChannelAttributesFromFlash(channel_id, &gMR_ChannelAttributes_Cache[slot].attributes);
|
||||
|
||||
// Store channel_id in cache
|
||||
gMR_ChannelAttributes_Cache[slot].channel_id = channel_id;
|
||||
|
||||
// Set access time
|
||||
gMR_ChannelAttributes_Cache[slot].access_time = GetCurrentTime();
|
||||
|
||||
return &gMR_ChannelAttributes_Cache[slot].attributes;
|
||||
}
|
||||
|
||||
// Set channel attributes (updates both cache and Flash)
|
||||
void MR_SetChannelAttributes(uint16_t channel_id, const ChannelAttributes_t* attributes)
|
||||
{
|
||||
// Input validation
|
||||
if (channel_id >= (MR_CHANNELS_MAX + 7) || !attributes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CRITICAL FIX: WRITE-PROTECT - Prevent Flash wear
|
||||
// Before writing, check if data already exists and is identical
|
||||
ChannelAttributes_t flash_version;
|
||||
MR_LoadChannelAttributesFromFlash(channel_id, &flash_version);
|
||||
|
||||
// Compare current Flash data with new data
|
||||
if (memcmp(&flash_version, attributes, sizeof(ChannelAttributes_t)) == 0) {
|
||||
// But still update cache for consistency
|
||||
int cache_index = MR_FindInCache(channel_id);
|
||||
if (cache_index >= 0) {
|
||||
gMR_ChannelAttributes_Cache[cache_index].attributes = *attributes;
|
||||
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
|
||||
}
|
||||
return; // Early exit - no Flash write needed
|
||||
}
|
||||
|
||||
// Data has changed - write to Flash
|
||||
MR_SaveChannelAttributesToFlash(channel_id, attributes);
|
||||
|
||||
// Update cache if entry exists
|
||||
int cache_index = MR_FindInCache(channel_id);
|
||||
|
||||
if (cache_index >= 0) {
|
||||
// Entry in cache, update it
|
||||
gMR_ChannelAttributes_Cache[cache_index].attributes = *attributes;
|
||||
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
|
||||
} else {
|
||||
// Not in cache, add it
|
||||
int slot = MR_FindEmptyCacheSlot();
|
||||
|
||||
if (slot < 0) {
|
||||
// Cache full, evict oldest
|
||||
slot = MR_FindOldestCacheEntry();
|
||||
}
|
||||
|
||||
gMR_ChannelAttributes_Cache[slot].channel_id = channel_id;
|
||||
gMR_ChannelAttributes_Cache[slot].attributes = *attributes;
|
||||
gMR_ChannelAttributes_Cache[slot].access_time = GetCurrentTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate entire cache (call after loading Flash backup)
|
||||
void MR_InvalidateChannelAttributesCache(void)
|
||||
{
|
||||
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
|
||||
gMR_ChannelAttributes_Cache[i].channel_id = 0xFFFF; // Mark as empty
|
||||
gMR_ChannelAttributes_Cache[i].access_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize cache (call from settings.c boot sequence)
|
||||
void MR_InitChannelAttributesCache(void)
|
||||
{
|
||||
// Clear cache
|
||||
MR_InvalidateChannelAttributesCache();
|
||||
|
||||
// Pre-load commonly used channels (VFO A, VFO B, channel 0)
|
||||
// This speeds up first access
|
||||
uint16_t channels_to_preload[] = {0, 1, 2};
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(channels_to_preload); i++) {
|
||||
if (channels_to_preload[i] < (MR_CHANNELS_MAX + 7)) {
|
||||
MR_GetChannelAttributes(channels_to_preload[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Debugging / Statistics (optional, for development)
|
||||
//
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
|
||||
uint32_t MR_GetCacheHits(void)
|
||||
{
|
||||
return cache_hits;
|
||||
}
|
||||
|
||||
uint32_t MR_GetCacheMisses(void)
|
||||
{
|
||||
return cache_misses;
|
||||
}
|
||||
|
||||
float MR_GetCacheHitRate(void)
|
||||
{
|
||||
uint32_t total = cache_hits + cache_misses;
|
||||
if (total == 0) return 0.0f;
|
||||
return (float)cache_hits / (float)total * 100.0f;
|
||||
}
|
||||
|
||||
void MR_PrintCacheStats(void)
|
||||
{
|
||||
// This would print cache statistics (requires UART_Printf)
|
||||
// Uncomment if you want debug output:
|
||||
// UART_Printf("Cache Stats: Hits=%u Misses=%u Rate=%.1f%%\n",
|
||||
// cache_hits, cache_misses, MR_GetCacheHitRate());
|
||||
}
|
||||
|
||||
#endif
|
||||
+86
-18
@@ -36,18 +36,28 @@
|
||||
#define SWAP(a, b) ({ __typeof__ (a) _c = (a); a = b; b = _c; })
|
||||
#endif
|
||||
|
||||
#define IS_MR_CHANNEL(x) ((x) <= MR_CHANNEL_LAST)
|
||||
#define FM_CHANNELS_MAX 48
|
||||
#define MR_CHANNELS_MAX 1024
|
||||
#define MR_CHANNELS_LIST 24
|
||||
#define MENU_ITEMS 69
|
||||
|
||||
// CACHE-BASED OPTIMIZATION: Only keep active channels in RAM
|
||||
// Full array stays in EEPROM, cache holds ~10 most-used channels
|
||||
#define MR_CHANNELS_CACHE_SIZE 10
|
||||
|
||||
|
||||
#define IS_MR_CHANNEL(x) ((x) >= MR_CHANNEL_FIRST && (x) <= MR_CHANNEL_LAST)
|
||||
#define IS_FREQ_CHANNEL(x) ((x) >= FREQ_CHANNEL_FIRST && (x) <= FREQ_CHANNEL_LAST)
|
||||
#define IS_VALID_CHANNEL(x) ((x) < LAST_CHANNEL)
|
||||
#define IS_NOAA_CHANNEL(x) ((x) >= NOAA_CHANNEL_FIRST && (x) <= NOAA_CHANNEL_LAST)
|
||||
|
||||
enum {
|
||||
MR_CHANNEL_FIRST = 0,
|
||||
MR_CHANNEL_LAST = 199u,
|
||||
FREQ_CHANNEL_FIRST = 200u,
|
||||
FREQ_CHANNEL_LAST = 206u,
|
||||
NOAA_CHANNEL_FIRST = 207u,
|
||||
NOAA_CHANNEL_LAST = 216u,
|
||||
MR_CHANNEL_LAST = MR_CHANNELS_MAX - 1,
|
||||
FREQ_CHANNEL_FIRST = MR_CHANNELS_MAX,
|
||||
FREQ_CHANNEL_LAST = MR_CHANNELS_MAX + 6,
|
||||
NOAA_CHANNEL_FIRST = MR_CHANNELS_MAX + 7,
|
||||
NOAA_CHANNEL_LAST = MR_CHANNELS_MAX + 16,
|
||||
LAST_CHANNEL
|
||||
};
|
||||
|
||||
@@ -178,13 +188,16 @@ extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
extern bool gSetting_set_lck;
|
||||
extern bool gSetting_set_met;
|
||||
extern bool gSetting_set_gui;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
extern uint8_t gSetting_set_audio;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
extern bool gSetting_set_nfm;
|
||||
#endif
|
||||
extern bool gSetting_set_tmr;
|
||||
extern bool gSetting_set_ptt_session;
|
||||
#ifdef ENABLE_FEAT_F4HWN_DEBUG
|
||||
extern uint8_t gDebug;
|
||||
extern uint16_t gDebug;
|
||||
#endif
|
||||
extern uint8_t gDW;
|
||||
extern uint8_t gCB;
|
||||
@@ -192,6 +205,8 @@ extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
|
||||
extern uint8_t crc[15];
|
||||
extern uint8_t lErrorsDuringAirCopy;
|
||||
extern uint8_t gAircopyStep;
|
||||
extern uint8_t gAircopyCurrentMapIndex;
|
||||
extern bool gAirCopyBootMode;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
extern bool gPowerHigh;
|
||||
extern bool gRemoveOffset;
|
||||
@@ -219,18 +234,66 @@ extern uint16_t gEEPROM_1F8C;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t
|
||||
band : 3,
|
||||
uint16_t
|
||||
band : 3,
|
||||
compander : 2,
|
||||
scanlist1 : 1,
|
||||
scanlist2 : 1,
|
||||
scanlist3 : 1;
|
||||
unused_1 : 1,
|
||||
unused_2 : 1,
|
||||
exclude : 1,
|
||||
scanlist : 8;
|
||||
};
|
||||
uint8_t __val;
|
||||
uint16_t __val;
|
||||
} ChannelAttributes_t;
|
||||
|
||||
extern ChannelAttributes_t gMR_ChannelAttributes[207];
|
||||
extern bool gMR_ChannelExclude[207];
|
||||
//
|
||||
// Cache-Based Architecture
|
||||
//
|
||||
//
|
||||
// Instead of keeping all 1038 channel attributes in RAM (~ 2,000 bytes),
|
||||
// we now keep only the active ones in a small cache (40 bytes).
|
||||
//
|
||||
// The full array remains in Flash and is loaded on-demand.
|
||||
//
|
||||
// SRAM Savings: ~ 2,000 bytes (84% reduction!)
|
||||
//
|
||||
|
||||
// Cache entry structure
|
||||
typedef struct {
|
||||
uint16_t channel_id; // Which channel this is
|
||||
ChannelAttributes_t attributes; // The actual attributes
|
||||
uint32_t access_time; // For LRU eviction (optional)
|
||||
} MR_ChannelCache_t;
|
||||
|
||||
// The cache (small, stays in RAM)
|
||||
extern MR_ChannelCache_t gMR_ChannelAttributes_Cache[MR_CHANNELS_CACHE_SIZE];
|
||||
|
||||
// REMOVED: extern ChannelAttributes_t gMR_ChannelAttributes[MR_CHANNELS_MAX + 7];
|
||||
// This now stays in Flash, not in RAM
|
||||
|
||||
//
|
||||
// Cache Access Functions (See misc.c for implementation)
|
||||
//
|
||||
|
||||
// Get channel attributes (from cache or Flash)
|
||||
// Returns pointer to attributes, loads from Flash if not in cache
|
||||
|
||||
void MR_InitChannelAttributesCache(void);
|
||||
|
||||
ChannelAttributes_t* MR_GetChannelAttributes(uint16_t channel_id);
|
||||
|
||||
// Set channel attributes (updates both cache and Flasf)
|
||||
void MR_SetChannelAttributes(uint16_t channel_id, const ChannelAttributes_t* attributes);
|
||||
|
||||
// Invalidate cache (on Flash clear)
|
||||
void MR_InvalidateChannelAttributesCache(void);
|
||||
|
||||
// Load channel attributes from Flash directly (internal use)
|
||||
void MR_LoadChannelAttributesFromFlash(uint16_t channel_id, ChannelAttributes_t* attributes);
|
||||
|
||||
// Save channel attributes to Flash directly (internal use)
|
||||
void MR_SaveChannelAttributesToFlash(uint16_t channel_id, const ChannelAttributes_t* attributes);
|
||||
|
||||
extern ChannelAttributes_t gMR_ChannelAttributes_Current; // Current VFO attributes (for speed)
|
||||
|
||||
extern volatile uint16_t gBatterySaveCountdown_10ms;
|
||||
|
||||
@@ -258,6 +321,7 @@ extern volatile bool gTxTimeoutReached;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
extern volatile uint8_t gUART_LockScreenshot; // lock screenshot if Chirp is used
|
||||
extern bool gUSB_ScreenshotEnabled;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -305,7 +369,7 @@ extern bool gFlagReconfigureVfos;
|
||||
extern uint8_t gVfoConfigureMode;
|
||||
extern bool gFlagResetVfos;
|
||||
extern bool gRequestSaveVFO;
|
||||
extern uint8_t gRequestSaveChannel;
|
||||
extern uint16_t gRequestSaveChannel;
|
||||
extern bool gRequestSaveSettings;
|
||||
#ifdef ENABLE_FMRADIO
|
||||
extern bool gRequestSaveFM;
|
||||
@@ -336,7 +400,7 @@ extern bool g_SquelchLost;
|
||||
extern volatile uint16_t gFlashLightBlinkCounter;
|
||||
|
||||
extern bool gFlagEndTransmission;
|
||||
extern uint8_t gNextMrChannel;
|
||||
extern uint16_t gNextMrChannel;
|
||||
extern ReceptionMode_t gRxReceptionMode;
|
||||
|
||||
//TRUE when dual watch is momentarly suspended and RX_VFO is locked to either last TX or RX
|
||||
@@ -387,6 +451,10 @@ extern volatile uint8_t boot_counter_10ms;
|
||||
extern uint8_t gBacklightBrightnessOld;
|
||||
extern uint8_t gPttOnePushCounter;
|
||||
extern uint32_t gBlinkCounter;
|
||||
|
||||
extern uint16_t gVfoSaveCountdown_10ms;
|
||||
extern bool gScheduleVfoSave;
|
||||
extern bool gVfoStateChanged;
|
||||
#endif
|
||||
|
||||
int32_t NUMBER_AddWithWraparound(int32_t Base, int32_t Add, int32_t LowerLimit, int32_t UpperLimit);
|
||||
@@ -396,4 +464,4 @@ void FUNCTION_NOP();
|
||||
|
||||
static inline bool SerialConfigInProgress() { return gSerialConfigCountDown_500ms != 0; }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+150
-82
@@ -53,68 +53,114 @@ const char gModulationStr[MODULATION_UKNOWN][4] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
static void AUDIO_ApplyProfile(uint8_t profile)
|
||||
{
|
||||
switch (profile)
|
||||
{
|
||||
default:
|
||||
case 0: // FLAT
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x3200);
|
||||
break;
|
||||
|
||||
case 1: // CLEAN
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x33A9);
|
||||
break;
|
||||
|
||||
case 2: // MID
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x3600);
|
||||
break;
|
||||
|
||||
case 3: // BOOST
|
||||
BK4819_WriteRegister(0x54, 0x8546);
|
||||
BK4819_WriteRegister(0x55, 0x3AF0);
|
||||
break;
|
||||
|
||||
case 4: // MAX
|
||||
BK4819_WriteRegister(0x54, 0x8566);
|
||||
BK4819_WriteRegister(0x55, 0x3D00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool RADIO_CheckValidList(uint8_t scanList)
|
||||
{
|
||||
if(scanList == MR_CHANNELS_LIST + 1)
|
||||
return true;
|
||||
|
||||
for (uint16_t i = 0; IS_MR_CHANNEL(i); i++) {
|
||||
const ChannelAttributes_t* att = MR_GetChannelAttributes(i);
|
||||
if(att->scanlist == scanList && att->exclude == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RADIO_NextValidList(void)
|
||||
{
|
||||
uint8_t startList = gEeprom.SCAN_LIST_DEFAULT;
|
||||
uint8_t attempts = 0;
|
||||
const uint8_t MAX_LISTS = MR_CHANNELS_LIST + 2; // 1-25, includes ALL
|
||||
|
||||
do {
|
||||
// Move to next scan list, wrapping around from 25 to 1
|
||||
gEeprom.SCAN_LIST_DEFAULT = ((gEeprom.SCAN_LIST_DEFAULT + 1) % MAX_LISTS) ?: 1;
|
||||
attempts++;
|
||||
|
||||
// Check if current list has valid channels
|
||||
if (RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT))
|
||||
return;
|
||||
|
||||
// Stop if we've cycled through all lists or made too many attempts
|
||||
} while (gEeprom.SCAN_LIST_DEFAULT != startList && attempts < MAX_LISTS);
|
||||
|
||||
// Safety fallback: if no valid list found, switch to ALL mode
|
||||
// This prevents infinite loops and ensures scanning can continue
|
||||
if (!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) {
|
||||
gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1; // ALL
|
||||
}
|
||||
}
|
||||
|
||||
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList)
|
||||
{
|
||||
const ChannelAttributes_t* att = MR_GetChannelAttributes(channel);
|
||||
|
||||
// return true if the channel appears valid
|
||||
if (!IS_MR_CHANNEL(channel))
|
||||
return false;
|
||||
|
||||
const ChannelAttributes_t att = gMR_ChannelAttributes[channel];
|
||||
|
||||
if (checkScanList && gMR_ChannelExclude[channel] == true)
|
||||
if (checkScanList && att->exclude == true)
|
||||
return false;
|
||||
|
||||
if (att.band > BAND7_470MHz)
|
||||
if (att->band > BAND7_470MHz)
|
||||
return false;
|
||||
|
||||
if (!checkScanList || scanList > 4)
|
||||
if (!checkScanList || (scanList > MR_CHANNELS_LIST && att->scanlist != 0) || (scanList > 0 && att->scanlist == MR_CHANNELS_LIST + 1))
|
||||
return true;
|
||||
|
||||
/*
|
||||
if(scanList == 0 && (att.scanlist1 == 1 || att.scanlist2 == 1 || att.scanlist3 == 1))
|
||||
{
|
||||
if ((scanList == 0) || (scanList != att->scanlist)) {
|
||||
return false;
|
||||
}
|
||||
else if(scanList == 1 && att.scanlist1 != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(scanList == 2 && att.scanlist2 != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(scanList == 3 && att.scanlist3 != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(scanList == 4 && (att.scanlist1 == 0 && att.scanlist2 == 0 && att.scanlist3 == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if ((scanList == 0 && (att.scanlist1 == 1 || att.scanlist2 == 1 || att.scanlist3 == 1)) ||
|
||||
(scanList == 1 && att.scanlist1 != 1) ||
|
||||
(scanList == 2 && att.scanlist2 != 1) ||
|
||||
(scanList == 3 && att.scanlist3 != 1) ||
|
||||
(scanList == 4 && (att.scanlist1 == 0 && att.scanlist2 == 0 && att.scanlist3 == 0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//return true;
|
||||
|
||||
// I don't understand what this code is for...
|
||||
|
||||
const uint8_t PriorityCh1 = gEeprom.SCANLIST_PRIORITY_CH1[scanList - 1];
|
||||
const uint8_t PriorityCh2 = gEeprom.SCANLIST_PRIORITY_CH2[scanList - 1];
|
||||
|
||||
return PriorityCh1 != channel && PriorityCh2 != channel;
|
||||
// Exclude priority channels ONLY if SCAN_LIST_ENABLED is active
|
||||
// Otherwise, treat them as normal channels in the list
|
||||
if (gEeprom.SCAN_LIST_ENABLED)
|
||||
{
|
||||
const uint16_t PriorityCh1 = gEeprom.SCANLIST_PRIORITY_CH[0];
|
||||
const uint16_t PriorityCh2 = gEeprom.SCANLIST_PRIORITY_CH[1];
|
||||
if (PriorityCh1 == channel || PriorityCh2 == channel)
|
||||
return false; // Excluded because it's a priority channel and they are enabled
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t RADIO_FindNextChannel(uint8_t Channel, int8_t Direction, bool bCheckScanList, uint8_t VFO)
|
||||
uint16_t RADIO_FindNextChannel(uint16_t Channel, int8_t Direction, bool bCheckScanList, uint8_t VFO)
|
||||
{
|
||||
for (unsigned int i = 0; IS_MR_CHANNEL(i); i++, Channel += Direction) {
|
||||
if (Channel == 0xFF) {
|
||||
for (uint16_t i = 0; IS_MR_CHANNEL(i); i++, Channel += Direction) {
|
||||
if (Channel == 0xFFFF) {
|
||||
Channel = MR_CHANNEL_LAST;
|
||||
} else if (!IS_MR_CHANNEL(Channel)) {
|
||||
Channel = MR_CHANNEL_FIRST;
|
||||
@@ -125,17 +171,15 @@ uint8_t RADIO_FindNextChannel(uint8_t Channel, int8_t Direction, bool bCheckScan
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint8_t ChannelSave, const uint32_t Frequency)
|
||||
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint16_t ChannelSave, const uint32_t Frequency)
|
||||
{
|
||||
memset(pInfo, 0, sizeof(*pInfo));
|
||||
|
||||
pInfo->Band = FREQUENCY_GetBand(Frequency);
|
||||
pInfo->SCANLIST1_PARTICIPATION = false;
|
||||
pInfo->SCANLIST2_PARTICIPATION = false;
|
||||
pInfo->SCANLIST3_PARTICIPATION = false;
|
||||
pInfo->SCANLIST_PARTICIPATION = 0;
|
||||
pInfo->STEP_SETTING = STEP_12_5kHz;
|
||||
pInfo->StepFrequency = gStepFrequencyTable[pInfo->STEP_SETTING];
|
||||
pInfo->CHANNEL_SAVE = ChannelSave;
|
||||
@@ -168,7 +212,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
|
||||
gEeprom.ScreenChannel[VFO] = FREQ_CHANNEL_FIRST + BAND6_400MHz;
|
||||
}
|
||||
|
||||
uint8_t channel = gEeprom.ScreenChannel[VFO];
|
||||
uint16_t channel = gEeprom.ScreenChannel[VFO];
|
||||
|
||||
if (IS_VALID_CHANNEL(channel)) {
|
||||
#ifdef ENABLE_NOAA
|
||||
@@ -188,7 +232,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
|
||||
|
||||
if (IS_MR_CHANNEL(channel)) {
|
||||
channel = RADIO_FindNextChannel(channel, RADIO_CHANNEL_UP, false, VFO);
|
||||
if (channel == 0xFF) {
|
||||
if (channel == 0xFFFF) {
|
||||
channel = gEeprom.FreqChannel[VFO];
|
||||
gEeprom.ScreenChannel[VFO] = gEeprom.FreqChannel[VFO];
|
||||
}
|
||||
@@ -201,50 +245,42 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
|
||||
else
|
||||
channel = FREQ_CHANNEL_LAST - 1;
|
||||
|
||||
ChannelAttributes_t att = gMR_ChannelAttributes[channel];
|
||||
if (att.__val == 0xFF) { // invalid/unused channel
|
||||
ChannelAttributes_t* att = MR_GetChannelAttributes(channel);
|
||||
if (att->__val == 0xFFFF) { // invalid/unused channel
|
||||
if (IS_MR_CHANNEL(channel)) {
|
||||
channel = gEeprom.FreqChannel[VFO];
|
||||
gEeprom.ScreenChannel[VFO] = channel;
|
||||
}
|
||||
|
||||
uint8_t bandIdx = channel - FREQ_CHANNEL_FIRST;
|
||||
uint16_t bandIdx = channel - FREQ_CHANNEL_FIRST;
|
||||
RADIO_InitInfo(pVfo, channel, frequencyBandTable[bandIdx].lower);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t band = att.band;
|
||||
uint8_t band = att->band;
|
||||
if (band > BAND7_470MHz) {
|
||||
band = BAND6_400MHz;
|
||||
}
|
||||
|
||||
bool bParticipation1;
|
||||
bool bParticipation2;
|
||||
bool bParticipation3;
|
||||
uint8_t bParticipation;
|
||||
|
||||
if (IS_MR_CHANNEL(channel)) {
|
||||
bParticipation1 = att.scanlist1;
|
||||
bParticipation2 = att.scanlist2;
|
||||
bParticipation3 = att.scanlist3;
|
||||
bParticipation = att->scanlist;
|
||||
}
|
||||
else {
|
||||
band = channel - FREQ_CHANNEL_FIRST;
|
||||
bParticipation1 = true;
|
||||
bParticipation2 = true;
|
||||
bParticipation3 = true;
|
||||
bParticipation = MR_CHANNELS_LIST + 1;
|
||||
}
|
||||
|
||||
pVfo->Band = band;
|
||||
pVfo->SCANLIST1_PARTICIPATION = bParticipation1;
|
||||
pVfo->SCANLIST2_PARTICIPATION = bParticipation2;
|
||||
pVfo->SCANLIST3_PARTICIPATION = bParticipation3;
|
||||
pVfo->SCANLIST_PARTICIPATION = bParticipation;
|
||||
pVfo->CHANNEL_SAVE = channel;
|
||||
|
||||
uint32_t base;
|
||||
if (IS_MR_CHANNEL(channel))
|
||||
base = channel * 16;
|
||||
else
|
||||
base = 0x001000 + ((channel - FREQ_CHANNEL_FIRST) * 32) + (VFO * 16);
|
||||
base = 0x009000 + ((channel - FREQ_CHANNEL_FIRST) * 32) + (VFO * 16);
|
||||
|
||||
if (configure == VFO_CONFIGURE_RELOAD || IS_FREQ_CHANNEL(channel))
|
||||
{
|
||||
@@ -424,7 +460,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
|
||||
pConfig->Frequency = 43300000;
|
||||
}
|
||||
|
||||
pVfo->Compander = att.compander;
|
||||
pVfo->Compander = att->compander;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gRemoveOffset)
|
||||
@@ -513,7 +549,7 @@ void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
|
||||
|
||||
Band = FREQUENCY_GetBand(pInfo->pTX->Frequency);
|
||||
|
||||
// my eeprom calibration data
|
||||
// my eeprom calibration data on UV-K5 (V1)
|
||||
//
|
||||
// 1ED0 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 50 MHz
|
||||
// 1EE0 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 108 MHz
|
||||
@@ -523,6 +559,15 @@ void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
|
||||
// 1F20 5f 5f 5f 69 69 69 87 87 87 ff ff ff ff ff ff ff 400 MHz
|
||||
// 1F30 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 470 MHz
|
||||
|
||||
// my eeprom calibration data on UV-K1
|
||||
// 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 50 MHz
|
||||
// 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 108 MHz
|
||||
// 4b 4b 4b 78 78 78 96 96 96 ff ff ff ff ff ff ff 137 MHz
|
||||
// 32 32 32 64 64 64 8c 8c 8c ff ff ff ff ff ff ff 174 MHz
|
||||
// 5a 5a 5a 64 64 64 a0 a0 a0 ff ff ff ff ff ff ff 350 MHz
|
||||
// 4b 4b 4b 78 78 78 96 96 96 ff ff ff ff ff ff ff 400 MHz
|
||||
// 32 32 32 64 64 64 94 8c 8c ff ff ff ff ff ff ff 470 MHz
|
||||
|
||||
uint8_t Txp[3];
|
||||
uint8_t Op = 0; // Low eeprom calibration data
|
||||
uint8_t currentPower = pInfo->OUTPUT_POWER;
|
||||
@@ -602,7 +647,17 @@ void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
|
||||
}
|
||||
*/
|
||||
|
||||
static const uint8_t dividers[6] = { 25, 19, 13, 10, 7, 4};
|
||||
//static const uint8_t dividers[6] = { 25, 19, 13, 10, 7, 4}; // For UV-K5 V1
|
||||
|
||||
static const uint8_t dividers_band2[6] = { 20, 15, 10, 8, 6, 4 };
|
||||
static const uint8_t dividers_band5[6] = { 25, 19, 13, 9, 6, 4 }; // Need to improve measure...
|
||||
|
||||
const uint8_t *dividers;
|
||||
|
||||
if (Band == 2) // VHF
|
||||
dividers = dividers_band2;
|
||||
else // UHF
|
||||
dividers = dividers_band5;
|
||||
|
||||
for (uint8_t p = 0; p < 3; p++)
|
||||
{
|
||||
@@ -612,7 +667,8 @@ void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
|
||||
}
|
||||
else // case 6
|
||||
{
|
||||
Txp[p] += 30;
|
||||
// Txp[p] += 30; // For UV-K5 V1
|
||||
Txp[p] += 24;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -868,7 +924,8 @@ void RADIO_SetupRegisters(bool switchToForeground)
|
||||
BK4819_EnableDTMF();
|
||||
InterruptMask |= BK4819_REG_3F_DTMF_5TONE_FOUND;
|
||||
|
||||
RADIO_SetupAGC(gRxVfo->Modulation == MODULATION_AM, false);
|
||||
//RADIO_SetupAGC(gRxVfo->Modulation == MODULATION_AM, false);
|
||||
RADIO_SetupAGC(false, false);
|
||||
|
||||
// enable/disable BK4819 selected interrupts
|
||||
BK4819_WriteRegister(BK4819_REG_3F, InterruptMask);
|
||||
@@ -1037,8 +1094,14 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
BK4819_WriteRegister(0x2a,0x7400);
|
||||
BK4819_WriteRegister(0x2b,0);
|
||||
BK4819_WriteRegister(0x2f,0x9890);
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x31a9);
|
||||
//BK4819_WriteRegister(0x54, 0x9009);
|
||||
//BK4819_WriteRegister(0x55, 0x31a9);
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
AUDIO_ApplyProfile(gSetting_set_audio);
|
||||
#else
|
||||
BK4819_WriteRegister(0x54, 0x9009);
|
||||
BK4819_WriteRegister(0x55, 0x31a9);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1048,8 +1111,12 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
BK4819_WriteRegister(0x2a,0x7434);
|
||||
BK4819_WriteRegister(0x2b,0x300);
|
||||
BK4819_WriteRegister(0x2f,0x9990);
|
||||
BK4819_WriteRegister(0x54, 0x9775);
|
||||
BK4819_WriteRegister(0x55, 0x32c6);
|
||||
//BK4819_WriteRegister(0x54, 0x9775);
|
||||
//BK4819_WriteRegister(0x55, 0x32c6);
|
||||
|
||||
BK4819_WriteRegister(0x54, 0x8846);
|
||||
BK4819_WriteRegister(0x55, 0x38C0);
|
||||
|
||||
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_AM, true);
|
||||
}
|
||||
|
||||
@@ -1057,7 +1124,8 @@ void RADIO_SetModulation(ModulationMode_t modulation)
|
||||
BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
|
||||
BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
|
||||
|
||||
RADIO_SetupAGC(modulation == MODULATION_AM, false);
|
||||
//RADIO_SetupAGC(modulation == MODULATION_AM, false);
|
||||
RADIO_SetupAGC(false, false);
|
||||
}
|
||||
|
||||
void RADIO_SetupAGC(bool listeningAM, bool disable)
|
||||
|
||||
+7
-7
@@ -95,7 +95,7 @@ typedef struct VFO_Info_t
|
||||
uint32_t TX_OFFSET_FREQUENCY;
|
||||
uint16_t StepFrequency;
|
||||
|
||||
uint8_t CHANNEL_SAVE;
|
||||
uint16_t CHANNEL_SAVE;
|
||||
|
||||
uint8_t TX_OFFSET_FREQUENCY_DIRECTION;
|
||||
|
||||
@@ -115,11 +115,9 @@ typedef struct VFO_Info_t
|
||||
uint8_t SCRAMBLING_TYPE;
|
||||
uint8_t CHANNEL_BANDWIDTH;
|
||||
|
||||
uint8_t SCANLIST1_PARTICIPATION;
|
||||
uint8_t SCANLIST2_PARTICIPATION;
|
||||
uint8_t SCANLIST3_PARTICIPATION;
|
||||
uint8_t SCANLIST_PARTICIPATION;
|
||||
|
||||
uint8_t Band;
|
||||
uint16_t Band;
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
uint8_t DTMF_DECODING_ENABLE;
|
||||
#endif
|
||||
@@ -150,9 +148,11 @@ extern DCS_CodeType_t gCurrentCodeType;
|
||||
|
||||
extern VfoState_t VfoState[2];
|
||||
|
||||
bool RADIO_CheckValidList(uint8_t scanList);
|
||||
void RADIO_NextValidList(void);
|
||||
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList);
|
||||
uint8_t RADIO_FindNextChannel(uint8_t ChNum, int8_t Direction, bool bCheckScanList, uint8_t RadioNum);
|
||||
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint8_t ChannelSave, const uint32_t Frequency);
|
||||
uint16_t RADIO_FindNextChannel(uint16_t ChNum, int8_t Direction, bool bCheckScanList, uint8_t RadioNum);
|
||||
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint16_t ChannelSave, const uint32_t Frequency);
|
||||
void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure);
|
||||
void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo);
|
||||
void RADIO_ApplyOffset(VFO_Info_t *pInfo);
|
||||
|
||||
@@ -55,6 +55,7 @@ void SysTick_Handler(void)
|
||||
gNextTimeslice_500ms = true;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
DECREMENT_AND_TRIGGER(gVfoSaveCountdown_10ms, gScheduleVfoSave);
|
||||
DECREMENT_AND_TRIGGER(gTxTimerCountdownAlert_500ms - ALERT_TOT * 2, gTxTimeoutReachedAlert);
|
||||
#ifdef ENABLE_FEAT_F4HWN_RX_TX_TIMER
|
||||
DECREMENT(gRxTimerCountdown_500ms);
|
||||
|
||||
+64
-23
@@ -18,16 +18,29 @@
|
||||
#include "driver/st7565.h"
|
||||
#include "screenshot.h"
|
||||
#include "misc.h"
|
||||
#include "driver/vcp.h"
|
||||
|
||||
// RAM optimization: Only keep previousFrame static (1024 bytes)
|
||||
// Build currentFrame on-the-fly and send delta blocks immediately
|
||||
static void Screenshot_Send(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if (gUSB_ScreenshotEnabled) {
|
||||
cdc_acm_data_send_with_dtr(buf, len);
|
||||
} else {
|
||||
UART_Send(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
// SRAM optimization: minimize static allocations
|
||||
// - previousFrame: 1024 bytes (REQUIRED - need to compare for delta)
|
||||
// - No currentFrame or deltaFrame static buffers
|
||||
static uint8_t previousFrame[1024] = {0};
|
||||
static uint8_t forcedBlock = 0;
|
||||
static uint8_t keepAlive = 10;
|
||||
|
||||
void getScreenShot(bool force)
|
||||
{
|
||||
static uint8_t currentFrame[1024]; // Reused static buffer
|
||||
// Build frame in a temporary stack buffer
|
||||
// This is 1024 bytes but it's temporary and gets freed after the function
|
||||
uint8_t frameBuffer[1024];
|
||||
uint16_t index = 0;
|
||||
uint8_t acc = 0;
|
||||
uint8_t bitCount = 0;
|
||||
@@ -39,6 +52,12 @@ void getScreenShot(bool force)
|
||||
|
||||
if (UART_IsCableConnected()) {
|
||||
keepAlive = 10;
|
||||
gUSB_ScreenshotEnabled = false;
|
||||
}
|
||||
|
||||
if (VCP_ScreenshotPing()) {
|
||||
keepAlive = 10;
|
||||
gUSB_ScreenshotEnabled = true;
|
||||
}
|
||||
|
||||
if (keepAlive > 0) {
|
||||
@@ -47,14 +66,14 @@ void getScreenShot(bool force)
|
||||
return;
|
||||
}
|
||||
|
||||
// ==== Build currentFrame (exact same logic as original) ====
|
||||
// ==== BUILD FRAME ONCE ====
|
||||
// Status line: 8 bit layers × 128 columns
|
||||
for (uint8_t b = 0; b < 8; b++) {
|
||||
for (uint8_t i = 0; i < 128; i++) {
|
||||
uint8_t bit = (gStatusLine[i] >> b) & 0x01;
|
||||
acc |= (bit << bitCount++);
|
||||
if (bitCount == 8) {
|
||||
currentFrame[index++] = acc;
|
||||
frameBuffer[index++] = acc;
|
||||
acc = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
@@ -68,7 +87,7 @@ void getScreenShot(bool force)
|
||||
uint8_t bit = (gFrameBuffer[l][i] >> b) & 0x01;
|
||||
acc |= (bit << bitCount++);
|
||||
if (bitCount == 8) {
|
||||
currentFrame[index++] = acc;
|
||||
frameBuffer[index++] = acc;
|
||||
acc = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
@@ -77,45 +96,67 @@ void getScreenShot(bool force)
|
||||
}
|
||||
|
||||
if (bitCount > 0)
|
||||
currentFrame[index++] = acc;
|
||||
frameBuffer[index++] = acc;
|
||||
|
||||
if (index != 1024)
|
||||
return; // Frame size mismatch, abort
|
||||
return;
|
||||
|
||||
// ==== Generate delta frame ====
|
||||
// ==== FIRST PASS: Count changed chunks ====
|
||||
uint16_t deltaLen = 0;
|
||||
uint8_t deltaFrame[128 * 9]; // Worst case: all 128 blocks changed
|
||||
uint8_t changedChunks[128]; // List of changed chunk indices
|
||||
uint8_t changedCount = 0;
|
||||
|
||||
for (uint8_t block = 0; block < 128; block++) {
|
||||
uint8_t *cur = ¤tFrame[block * 8];
|
||||
uint8_t *prev = &previousFrame[block * 8];
|
||||
for (uint8_t chunk = 0; chunk < 128; chunk++) {
|
||||
uint8_t *cur = &frameBuffer[chunk * 8];
|
||||
uint8_t *prev = &previousFrame[chunk * 8];
|
||||
|
||||
bool changed = memcmp(cur, prev, 8) != 0;
|
||||
bool isForced = (block == forcedBlock);
|
||||
bool isForced = (chunk == forcedBlock);
|
||||
bool fullUpdate = force;
|
||||
|
||||
if (changed || isForced || fullUpdate) {
|
||||
deltaFrame[deltaLen++] = block;
|
||||
memcpy(&deltaFrame[deltaLen], cur, 8);
|
||||
deltaLen += 8;
|
||||
memcpy(prev, cur, 8); // Update stored frame
|
||||
changedChunks[changedCount++] = chunk;
|
||||
deltaLen += 9;
|
||||
}
|
||||
}
|
||||
|
||||
forcedBlock = (forcedBlock + 1) % 128;
|
||||
|
||||
if (deltaLen == 0)
|
||||
return; // No update needed
|
||||
return;
|
||||
|
||||
// ==== Send frame ====
|
||||
// ==== Send version marker (for backward compatibility detection) ====
|
||||
// New format: sends 0xFF before header
|
||||
// Old format: doesn't exist, so viewers can differentiate
|
||||
uint8_t versionMarker = 0xFF;
|
||||
Screenshot_Send(&versionMarker, 1);
|
||||
|
||||
// ==== Send header ====
|
||||
uint8_t header[5] = {
|
||||
0xAA, 0x55, 0x02,
|
||||
(uint8_t)(deltaLen >> 8),
|
||||
(uint8_t)(deltaLen & 0xFF)
|
||||
};
|
||||
|
||||
UART_Send(header, 5);
|
||||
UART_Send(deltaFrame, deltaLen);
|
||||
Screenshot_Send(header, 5);
|
||||
|
||||
// ==== SECOND PASS: Send only changed chunks ====
|
||||
uint8_t chunk[9];
|
||||
|
||||
for (uint8_t i = 0; i < changedCount; i++) {
|
||||
uint8_t chunkIdx = changedChunks[i];
|
||||
uint8_t *cur = &frameBuffer[chunkIdx * 8];
|
||||
uint8_t *prev = &previousFrame[chunkIdx * 8];
|
||||
|
||||
chunk[0] = chunkIdx;
|
||||
memcpy(&chunk[1], cur, 8);
|
||||
|
||||
Screenshot_Send(chunk, 9);
|
||||
|
||||
// Update previousFrame for next comparison
|
||||
memcpy(prev, cur, 8);
|
||||
}
|
||||
|
||||
uint8_t end = 0x0A;
|
||||
UART_Send(&end, 1);
|
||||
Screenshot_Send(&end, 1);
|
||||
}
|
||||
+360
-238
@@ -28,25 +28,83 @@
|
||||
#include "settings.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESET_CHANNEL
|
||||
static const uint32_t gDefaultFrequencyTable[] =
|
||||
{
|
||||
14500000, //
|
||||
14550000, //
|
||||
43300000, //
|
||||
43320000, //
|
||||
43350000 //
|
||||
};
|
||||
#endif
|
||||
|
||||
EEPROM_Config_t gEeprom = { 0 };
|
||||
|
||||
void SETTINGS_InitEEPROM(void)
|
||||
{
|
||||
uint8_t Data[16] = {0};
|
||||
|
||||
//
|
||||
// Version check
|
||||
// Read stored version from EEPROM and compare with VERSION_STRING_2
|
||||
//
|
||||
{
|
||||
char storedVersion[16] = {0};
|
||||
PY25Q16_ReadBuffer(0x00A160, storedVersion, sizeof(storedVersion));
|
||||
|
||||
// Compare with current version
|
||||
if (strncmp(storedVersion, VERSION_STRING_2, sizeof(storedVersion)) != 0)
|
||||
{
|
||||
// Different version: new install or firmware update
|
||||
|
||||
// 1. Write new version to EEPROM
|
||||
char newVersion[16] = {0};
|
||||
strncpy(newVersion, VERSION_STRING_2, sizeof(newVersion));
|
||||
PY25Q16_WriteBuffer(0x00A160, newVersion, sizeof(newVersion), false);
|
||||
|
||||
// 2. Reset sensitive parameters (MENU_LOCK, etc.)
|
||||
uint8_t configByte[8] = {0};
|
||||
PY25Q16_ReadBuffer(0x00A000, configByte, sizeof(configByte));
|
||||
|
||||
configByte[4] &= (uint8_t)~0x01; // KEY_LOCK = 0
|
||||
configByte[4] &= (uint8_t)~0x02; // MENU_LOCK = 0
|
||||
configByte[4] &= (uint8_t)~0x3C; // SET_KEY = 0
|
||||
configByte[4] &= (uint8_t)~0x40; // SET_NAV = 0
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A000, configByte, sizeof(configByte), false);
|
||||
|
||||
// 3. Reset display inversion (SET_INV = 0)
|
||||
uint8_t displayByte[8] = {0};
|
||||
PY25Q16_ReadBuffer(0x00A158, displayByte, sizeof(displayByte));
|
||||
|
||||
displayByte[5] &= (uint8_t)~0x10; // Clear bit 4 (SET_INV)
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A158, displayByte, sizeof(displayByte), false);
|
||||
|
||||
// 4. Reset logo lines (clear to null for strlen() == 0)
|
||||
|
||||
char logoLines[32];
|
||||
PY25Q16_ReadBuffer(0x00A0C8, logoLines, sizeof(logoLines));
|
||||
|
||||
bool needsWrite = false;
|
||||
|
||||
for (int line = 0; line < 2; line++) {
|
||||
int offset = line * 16;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
char c = logoLines[offset + i];
|
||||
if (c == 0) {
|
||||
break;
|
||||
}
|
||||
if (c < 0x20 || c > 0x7E) {
|
||||
memset(logoLines + offset, 0, 16);
|
||||
needsWrite = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsWrite) {
|
||||
PY25Q16_WriteBuffer(0x00A0C8, logoLines, sizeof(logoLines), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0E70..0E77
|
||||
PY25Q16_ReadBuffer(0x004000, Data, 8);
|
||||
gEeprom.CHAN_1_CALL = IS_MR_CHANNEL(Data[0]) ? Data[0] : MR_CHANNEL_FIRST;
|
||||
PY25Q16_ReadBuffer(0x00A000, Data, 8);
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
gSetting_set_audio = (Data[0] < 5) ? Data[0] : 0;
|
||||
#endif
|
||||
gEeprom.SQUELCH_LEVEL = (Data[1] < 10) ? Data[1] : 1;
|
||||
gEeprom.TX_TIMEOUT_TIMER = (Data[2] > 4 && Data[2] < 180) ? Data[2] : 11;
|
||||
#ifdef ENABLE_NOAA
|
||||
@@ -56,6 +114,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.KEY_LOCK = (Data[4] & 0x01) != 0;
|
||||
gEeprom.MENU_LOCK = (Data[4] & 0x02) != 0;
|
||||
gEeprom.SET_KEY = ((Data[4] >> 2) & 0x0F) > 4 ? 0 : (Data[4] >> 2) & 0x0F;
|
||||
gEeprom.SET_NAV = (Data[4] & 0x40) != 0;
|
||||
#else
|
||||
gEeprom.KEY_LOCK = (Data[4] < 2) ? Data[4] : false;
|
||||
#endif
|
||||
@@ -66,7 +125,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.MIC_SENSITIVITY = (Data[7] < 5) ? Data[7] : 4;
|
||||
|
||||
// 0E78..0E7F
|
||||
PY25Q16_ReadBuffer(0x004008, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A008, Data, 8);
|
||||
gEeprom.BACKLIGHT_MAX = (Data[0] & 0xF) <= 10 ? (Data[0] & 0xF) : 10;
|
||||
gEeprom.BACKLIGHT_MIN = (Data[0] >> 4) < gEeprom.BACKLIGHT_MAX ? (Data[0] >> 4) : 0;
|
||||
#ifdef ENABLE_BLMIN_TMP_OFF
|
||||
@@ -80,20 +139,23 @@ void SETTINGS_InitEEPROM(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
gEeprom.TAIL_TONE_ELIMINATION = Data[6] & 0x01;
|
||||
gSetting_set_nfm = (Data[6] >> 1) & 0x01;
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
gEeprom.VFO_OPEN = ((Data[6] >> 2) & 0x01) != 0 ? true : true;
|
||||
#endif
|
||||
#else
|
||||
gEeprom.TAIL_TONE_ELIMINATION = (Data[6] < 2) ? Data[6] : false;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
gEeprom.VFO_OPEN = Data[7] & 0x01;
|
||||
gEeprom.CURRENT_STATE = (Data[7] >> 1) & 0x07;
|
||||
gEeprom.CURRENT_LIST = (Data[7] >> 4) & 0x07;
|
||||
gEeprom.CURRENT_STATE = Data[7] & 0x07; // bits 0..2
|
||||
gEeprom.CURRENT_LIST = (Data[7] >> 3) & 0x1F; // bits 3..7
|
||||
#else
|
||||
gEeprom.VFO_OPEN = (Data[7] < 2) ? Data[7] : true;
|
||||
#endif
|
||||
|
||||
// 0E80..0E87
|
||||
PY25Q16_ReadBuffer(0x005000, Data, 8);
|
||||
/*
|
||||
PY25Q16_ReadBuffer(0x00A010, Data, 8);
|
||||
gEeprom.ScreenChannel[0] = IS_VALID_CHANNEL(Data[0]) ? Data[0] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
gEeprom.ScreenChannel[1] = IS_VALID_CHANNEL(Data[3]) ? Data[3] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
gEeprom.MrChannel[0] = IS_MR_CHANNEL(Data[1]) ? Data[1] : MR_CHANNEL_FIRST;
|
||||
@@ -104,6 +166,24 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.NoaaChannel[0] = IS_NOAA_CHANNEL(Data[6]) ? Data[6] : NOAA_CHANNEL_FIRST;
|
||||
gEeprom.NoaaChannel[1] = IS_NOAA_CHANNEL(Data[7]) ? Data[7] : NOAA_CHANNEL_FIRST;
|
||||
#endif
|
||||
*/
|
||||
|
||||
// 0x00A010 .. 0x00A01F
|
||||
uint16_t Data16[8];
|
||||
|
||||
PY25Q16_ReadBuffer(0x00A010, Data16, sizeof(Data16));
|
||||
|
||||
gEeprom.ScreenChannel[0] = IS_VALID_CHANNEL(Data16[0]) ? Data16[0] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
gEeprom.MrChannel[0] = IS_MR_CHANNEL(Data16[1]) ? Data16[1] : MR_CHANNEL_FIRST;
|
||||
gEeprom.FreqChannel[0] = IS_FREQ_CHANNEL(Data16[2]) ? Data16[2] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
gEeprom.ScreenChannel[1] = IS_VALID_CHANNEL(Data16[3]) ? Data16[3] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
gEeprom.MrChannel[1] = IS_MR_CHANNEL(Data16[4]) ? Data16[4] : MR_CHANNEL_FIRST;
|
||||
gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data16[5]) ? Data16[5] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
|
||||
|
||||
#ifdef ENABLE_NOAA
|
||||
gEeprom.NoaaChannel[0] = IS_NOAA_CHANNEL(Data16[6]) ? Data16[6] : NOAA_CHANNEL_FIRST;
|
||||
gEeprom.NoaaChannel[1] = IS_NOAA_CHANNEL(Data16[7]) ? Data16[7] : NOAA_CHANNEL_FIRST;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FMRADIO
|
||||
{ // 0E88..0E8F
|
||||
@@ -115,7 +195,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
uint8_t band:2;
|
||||
//uint8_t space:2;
|
||||
} __attribute__((packed)) fmCfg;
|
||||
PY25Q16_ReadBuffer(0x006000, &fmCfg, 4);
|
||||
PY25Q16_ReadBuffer(0x00A020, &fmCfg, 4);
|
||||
|
||||
gEeprom.FM_Band = fmCfg.band;
|
||||
//gEeprom.FM_Space = fmCfg.space;
|
||||
@@ -128,12 +208,12 @@ void SETTINGS_InitEEPROM(void)
|
||||
}
|
||||
|
||||
// 0E40..0E67
|
||||
PY25Q16_ReadBuffer(0x003000, gFM_Channels, sizeof(gFM_Channels));
|
||||
PY25Q16_ReadBuffer(0x00A028, gFM_Channels, sizeof(gFM_Channels));
|
||||
FM_ConfigureChannelState();
|
||||
#endif
|
||||
|
||||
// 0E90..0E97
|
||||
PY25Q16_ReadBuffer(0x007000, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8, Data, 8);
|
||||
gEeprom.BEEP_CONTROL = Data[0] & 1;
|
||||
gEeprom.KEY_M_LONG_PRESS_ACTION = ((Data[0] >> 1) < ACTION_OPT_LEN) ? (Data[0] >> 1) : ACTION_OPT_NONE;
|
||||
gEeprom.KEY_1_SHORT_PRESS_ACTION = (Data[1] < ACTION_OPT_LEN) ? Data[1] : ACTION_OPT_MONITOR;
|
||||
@@ -150,12 +230,12 @@ void SETTINGS_InitEEPROM(void)
|
||||
|
||||
// 0E98..0E9F
|
||||
#ifdef ENABLE_PWRON_PASSWORD
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x8, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8 + 0x8, Data, 8);
|
||||
memcpy(&gEeprom.POWER_ON_PASSWORD, Data, 4);
|
||||
#endif
|
||||
|
||||
// 0EA0..0EA7
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x10, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8 + 0x10, Data, 8);
|
||||
#ifdef ENABLE_VOICE
|
||||
gEeprom.VOICE_PROMPT = (Data[0] < 3) ? Data[0] : VOICE_PROMPT_ENGLISH;
|
||||
#endif
|
||||
@@ -171,7 +251,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
#endif
|
||||
|
||||
// 0EA8..0EAF
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x18, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8 + 0x18, Data, 8);
|
||||
#ifdef ENABLE_ALARM
|
||||
gEeprom.ALARM_MODE = (Data[0] < 2) ? Data[0] : true;
|
||||
#endif
|
||||
@@ -181,7 +261,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.BATTERY_TYPE = (Data[4] < BATTERY_TYPE_UNKNOWN) ? Data[4] : BATTERY_TYPE_1600_MAH;
|
||||
|
||||
// 0ED0..0ED7
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x40, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8 + 0x40, Data, 8);
|
||||
gEeprom.DTMF_SIDE_TONE = (Data[0] < 2) ? Data[0] : true;
|
||||
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
@@ -195,7 +275,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
gEeprom.DTMF_HASH_CODE_PERSIST_TIME = (Data[7] < 101) ? Data[7] * 10 : 100;
|
||||
|
||||
// 0ED8..0EDF
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x48, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A0A8 + 0x48, 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;
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
@@ -203,7 +283,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
|
||||
// 0EE0..0EE7
|
||||
|
||||
PY25Q16_ReadBuffer(0x008000, Data, sizeof(gEeprom.ANI_DTMF_ID));
|
||||
PY25Q16_ReadBuffer(0x00A0F8, Data, sizeof(gEeprom.ANI_DTMF_ID));
|
||||
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.ANI_DTMF_ID))) {
|
||||
memcpy(gEeprom.ANI_DTMF_ID, Data, sizeof(gEeprom.ANI_DTMF_ID));
|
||||
} else {
|
||||
@@ -212,7 +292,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
|
||||
|
||||
// 0EE8..0EEF
|
||||
PY25Q16_ReadBuffer(0x008000 + 0x8, Data, sizeof(gEeprom.KILL_CODE));
|
||||
PY25Q16_ReadBuffer(0x00A0F8 + 0x8, Data, sizeof(gEeprom.KILL_CODE));
|
||||
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.KILL_CODE))) {
|
||||
memcpy(gEeprom.KILL_CODE, Data, sizeof(gEeprom.KILL_CODE));
|
||||
} else {
|
||||
@@ -220,7 +300,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
}
|
||||
|
||||
// 0EF0..0EF7
|
||||
PY25Q16_ReadBuffer(0x008000 + 0x10, Data, sizeof(gEeprom.REVIVE_CODE));
|
||||
PY25Q16_ReadBuffer(0x00A0F8 + 0x10, Data, sizeof(gEeprom.REVIVE_CODE));
|
||||
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.REVIVE_CODE))) {
|
||||
memcpy(gEeprom.REVIVE_CODE, Data, sizeof(gEeprom.REVIVE_CODE));
|
||||
} else {
|
||||
@@ -229,7 +309,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
#endif
|
||||
|
||||
// 0EF8..0F07
|
||||
PY25Q16_ReadBuffer(0x008000 + 0x18, Data, sizeof(gEeprom.DTMF_UP_CODE));
|
||||
PY25Q16_ReadBuffer(0x00A0F8 + 0x18, Data, sizeof(gEeprom.DTMF_UP_CODE));
|
||||
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.DTMF_UP_CODE))) {
|
||||
memcpy(gEeprom.DTMF_UP_CODE, Data, sizeof(gEeprom.DTMF_UP_CODE));
|
||||
} else {
|
||||
@@ -237,7 +317,7 @@ void SETTINGS_InitEEPROM(void)
|
||||
}
|
||||
|
||||
// 0F08..0F17
|
||||
PY25Q16_ReadBuffer(0x008000 + 0x28, Data, sizeof(gEeprom.DTMF_DOWN_CODE));
|
||||
PY25Q16_ReadBuffer(0x00A0F8 + 0x28, Data, sizeof(gEeprom.DTMF_DOWN_CODE));
|
||||
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.DTMF_DOWN_CODE))) {
|
||||
memcpy(gEeprom.DTMF_DOWN_CODE, Data, sizeof(gEeprom.DTMF_DOWN_CODE));
|
||||
} else {
|
||||
@@ -245,40 +325,28 @@ void SETTINGS_InitEEPROM(void)
|
||||
}
|
||||
|
||||
// 0F18..0F1F
|
||||
PY25Q16_ReadBuffer(0x009000, Data, 8);
|
||||
gEeprom.SCAN_LIST_DEFAULT = (Data[0] < 6) ? Data[0] : 0; // we now have 'all' channel scan option
|
||||
PY25Q16_ReadBuffer(0x00A130, Data, 8);
|
||||
|
||||
// Fake data
|
||||
/*
|
||||
gEeprom.SCAN_LIST_ENABLED[0] = 0;
|
||||
gEeprom.SCAN_LIST_ENABLED[1] = 0;
|
||||
gEeprom.SCAN_LIST_ENABLED[2] = 0;
|
||||
gEeprom.SCAN_LIST_DEFAULT =
|
||||
(((Data[0] & 0x7F) >= 1) && ((Data[0] & 0x7F) <= (MR_CHANNELS_LIST + 1)))
|
||||
? (Data[0] & 0x7F)
|
||||
: 1;
|
||||
gEeprom.SCAN_LIST_ENABLED = (Data[0] >> 7) & 0x01;
|
||||
|
||||
gEeprom.SCANLIST_PRIORITY_CH1[0] = 0;
|
||||
gEeprom.SCANLIST_PRIORITY_CH2[0] = 2;
|
||||
gEeprom.SCANLIST_PRIORITY_CH[0] =
|
||||
(uint16_t)Data[1] |
|
||||
((uint16_t)Data[2] << 8);
|
||||
|
||||
gEeprom.SCANLIST_PRIORITY_CH1[1] = 14;
|
||||
gEeprom.SCANLIST_PRIORITY_CH2[1] = 15;
|
||||
gEeprom.SCANLIST_PRIORITY_CH[1] =
|
||||
(uint16_t)Data[3] |
|
||||
((uint16_t)Data[4] << 8);
|
||||
|
||||
gEeprom.SCANLIST_PRIORITY_CH1[2] = 40;
|
||||
gEeprom.SCANLIST_PRIORITY_CH2[2] = 41;
|
||||
*/
|
||||
|
||||
// Fix me probably after Chirp update...
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
gEeprom.SCAN_LIST_ENABLED[i] = (Data[1] >> i) & 1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
const unsigned int j = 1 + (i * 2);
|
||||
gEeprom.SCANLIST_PRIORITY_CH1[i] = Data[j + 1];
|
||||
gEeprom.SCANLIST_PRIORITY_CH2[i] = Data[j + 2];
|
||||
}
|
||||
gEeprom.CHAN_1_CALL =
|
||||
(uint16_t)Data[5] |
|
||||
((uint16_t)Data[6] << 8);
|
||||
|
||||
// 0F40..0F47
|
||||
PY25Q16_ReadBuffer(0x00b000, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A150, Data, 8);
|
||||
gSetting_F_LOCK = (Data[0] < F_LOCK_LEN) ? Data[0] : F_LOCK_DEF;
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
gSetting_350TX = (Data[1] < 2) ? Data[1] : false; // was true
|
||||
@@ -317,34 +385,62 @@ void SETTINGS_InitEEPROM(void)
|
||||
}
|
||||
|
||||
// 0D60..0E27
|
||||
PY25Q16_ReadBuffer(0x002000, gMR_ChannelAttributes, sizeof(gMR_ChannelAttributes));
|
||||
for(uint16_t i = 0; i < sizeof(gMR_ChannelAttributes); i++) {
|
||||
ChannelAttributes_t *att = &gMR_ChannelAttributes[i];
|
||||
if(att->__val == 0xff){
|
||||
/*
|
||||
PY25Q16_ReadBuffer(0x008000, gMR_ChannelAttributes, sizeof(gMR_ChannelAttributes));
|
||||
uint16_t count = ARRAY_SIZE(gMR_ChannelAttributes);
|
||||
|
||||
for (uint16_t i = 0; i < count; i++) {
|
||||
ChannelAttributes_t *att = MR_GetChannelAttributes(i);
|
||||
|
||||
if (att->__val == 0xFFFF) {
|
||||
att->__val = 0;
|
||||
att->band = 0x7;
|
||||
}
|
||||
gMR_ChannelExclude[i] = false;
|
||||
else
|
||||
{
|
||||
att->exclude = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Init attr cache
|
||||
MR_InitChannelAttributesCache();
|
||||
|
||||
// Load and check channel
|
||||
for (uint16_t i = 0; i < MR_CHANNELS_MAX + 7; i++) {
|
||||
ChannelAttributes_t *att = MR_GetChannelAttributes(i);
|
||||
|
||||
if (att != NULL) {
|
||||
if (att->__val == 0xFFFF) {
|
||||
att->__val = 0;
|
||||
att->band = 0x7;
|
||||
MR_SetChannelAttributes(i, att); // ⭐ IMPORTANT: Sauvegarder!
|
||||
}
|
||||
else {
|
||||
att->exclude = 0;
|
||||
MR_SetChannelAttributes(i, att); // ⭐ IMPORTANT: Sauvegarder!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0F30..0F3F
|
||||
PY25Q16_ReadBuffer(0x00a000, gCustomAesKey, sizeof(gCustomAesKey));
|
||||
bHasCustomAesKey = false;
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(gCustomAesKey); i++)
|
||||
// 0F30..0F3F
|
||||
PY25Q16_ReadBuffer(0x00A138, gCustomAesKey, sizeof(gCustomAesKey));
|
||||
bHasCustomAesKey = false;
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(gCustomAesKey); i++)
|
||||
{
|
||||
if (gCustomAesKey[i] != 0xFFFFFFFFu)
|
||||
{
|
||||
if (gCustomAesKey[i] != 0xFFFFFFFFu)
|
||||
{
|
||||
bHasCustomAesKey = true;
|
||||
return;
|
||||
}
|
||||
bHasCustomAesKey = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
// 1FF0..0x1FF7
|
||||
// TODO: address TBD
|
||||
PY25Q16_ReadBuffer(0x00c000, Data, 8);
|
||||
PY25Q16_ReadBuffer(0x00A158, Data, 8);
|
||||
gSetting_set_pwr = (((Data[7] & 0xF0) >> 4) < 7) ? ((Data[7] & 0xF0) >> 4) : 0;
|
||||
gSetting_set_ptt = (((Data[7] & 0x0F)) < 2) ? ((Data[7] & 0x0F)) : 0;
|
||||
|
||||
@@ -461,7 +557,7 @@ void SETTINGS_LoadCalibration(void)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SETTINGS_FetchChannelFrequency(const int channel)
|
||||
uint32_t SETTINGS_FetchChannelFrequency(const uint16_t channel)
|
||||
{
|
||||
struct
|
||||
{
|
||||
@@ -474,7 +570,7 @@ uint32_t SETTINGS_FetchChannelFrequency(const int channel)
|
||||
return info.frequency;
|
||||
}
|
||||
|
||||
void SETTINGS_FetchChannelName(char *s, const int channel)
|
||||
void SETTINGS_FetchChannelName(char *s, const uint16_t channel)
|
||||
{
|
||||
if (s == NULL)
|
||||
return;
|
||||
@@ -488,7 +584,7 @@ void SETTINGS_FetchChannelName(char *s, const int channel)
|
||||
return;
|
||||
|
||||
// 0x0F50
|
||||
PY25Q16_ReadBuffer(0x00e000 + (channel * 16), s, 10);
|
||||
PY25Q16_ReadBuffer(0x004000 + (channel * 16), s, 10);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 10; i++)
|
||||
@@ -503,92 +599,67 @@ void SETTINGS_FetchChannelName(char *s, const int channel)
|
||||
|
||||
void SETTINGS_FactoryReset(bool bIsAll)
|
||||
{
|
||||
// 0000 - 0c80
|
||||
PY25Q16_SectorErase(0);
|
||||
// 0c80 - 0d60
|
||||
PY25Q16_SectorErase(0x000000);
|
||||
PY25Q16_SectorErase(0x001000);
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
PY25Q16_SectorErase(0x004000);
|
||||
PY25Q16_SectorErase(0x005000);
|
||||
PY25Q16_SectorErase(0x006000);
|
||||
PY25Q16_SectorErase(0x007000);
|
||||
PY25Q16_SectorErase(0x008000);
|
||||
PY25Q16_SectorErase(0x009000);
|
||||
|
||||
// 0d60 - 0e30
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x002000);
|
||||
}
|
||||
// 0e40 - 0e68
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x003000);
|
||||
}
|
||||
// 0e70 - 0e80
|
||||
PY25Q16_SectorErase(0x004000);
|
||||
// 0e80 - 0e88
|
||||
PY25Q16_SectorErase(0x005000);
|
||||
// 0e88 - 0e90
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x006000);
|
||||
}
|
||||
// 0e90 - 0ee0
|
||||
do
|
||||
{
|
||||
uint8_t Buf[0x50];
|
||||
memset(Buf, 0xff, 0x50);
|
||||
// 0EA0 - 0EA8 : keep
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x10, Buf + 0x10, 8);
|
||||
// 0EB0 - 0ED0 : keep
|
||||
PY25Q16_ReadBuffer(0x007000 + 0x20, Buf + 0x20, 0x20);
|
||||
PY25Q16_WriteBuffer(0x007000, Buf, 0x50, true);
|
||||
} while (0);
|
||||
// 0ee0 - 0f18 : keep
|
||||
// 0f18 - 0f20
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x009000);
|
||||
}
|
||||
// 0f30 - 0f40 : keep
|
||||
// 0f40 - 0f48 : keep
|
||||
// 0f50 - 1bd0
|
||||
if (bIsAll)
|
||||
{
|
||||
PY25Q16_SectorErase(0x00e000);
|
||||
}
|
||||
// 1c00 - 1d00 : keep
|
||||
|
||||
if (bIsAll)
|
||||
{
|
||||
RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_FIRST + BAND6_400MHz, 43350000);
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESET_CHANNEL
|
||||
// set the first few memory channels
|
||||
for (i = 0; i < ARRAY_SIZE(gDefaultFrequencyTable); i++)
|
||||
{
|
||||
const uint32_t Frequency = gDefaultFrequencyTable[i];
|
||||
gRxVfo->freq_config_RX.Frequency = Frequency;
|
||||
gRxVfo->freq_config_TX.Frequency = Frequency;
|
||||
gRxVfo->Band = FREQUENCY_GetBand(Frequency);
|
||||
SETTINGS_SaveChannel(MR_CHANNEL_FIRST + i, 0, gRxVfo, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
PY25Q16_SectorErase(0x00c000);
|
||||
#endif
|
||||
PY25Q16_SectorErase(0x00A000);
|
||||
}
|
||||
|
||||
// Prevent reset to restart in RO mode...
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
{
|
||||
uint8_t buf[0x10];
|
||||
// Bloc 0x0E70..0x0E7F -> offset 0x00A000
|
||||
uint8_t Data8[0x10];
|
||||
PY25Q16_ReadBuffer(0x00A000, Data8, sizeof(Data8));
|
||||
|
||||
// Bloc 0x0E70..0x0E7F -> offset 0x004000
|
||||
PY25Q16_ReadBuffer(0x004000, buf, sizeof(buf));
|
||||
// MENU_LOCK & KEY_LOCK to 0
|
||||
|
||||
// bit 1 = MENU_LOCK => on le force à 0
|
||||
buf[4] &= (uint8_t)~0x02;
|
||||
Data8[4] &= (uint8_t)~0x01;
|
||||
Data8[4] &= (uint8_t)~0x02;
|
||||
|
||||
PY25Q16_WriteBuffer(0x004000, buf, sizeof(buf), true);
|
||||
// SET_KEY to 0
|
||||
Data8[4] &= (uint8_t)~0x3C; // Clear bits 2-5 (SET_KEY)
|
||||
|
||||
// cohérence RAM
|
||||
gEeprom.MENU_LOCK = 0;
|
||||
}
|
||||
// SET_NAV to false
|
||||
Data8[4] &= (uint8_t)~0x40; // Clear bit 6 (SET_NAV) for UV-K1 by default
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESET_VFO
|
||||
Data8[7] = (1 & 0x01);
|
||||
#endif
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A000, Data8, sizeof(Data8), false);
|
||||
|
||||
// cohérence RAM
|
||||
gEeprom.MENU_LOCK = 0;
|
||||
#endif
|
||||
|
||||
// Reset VFO for the first time...
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESET_VFO
|
||||
RADIO_InitInfo(&gEeprom.VfoInfo[0], FREQ_CHANNEL_FIRST + BAND3_137MHz, 14550000);
|
||||
RADIO_InitInfo(&gEeprom.VfoInfo[1], FREQ_CHANNEL_FIRST + BAND6_400MHz, 43350000);
|
||||
|
||||
gEeprom.ScreenChannel[0] = FREQ_CHANNEL_FIRST + BAND3_137MHz;
|
||||
gEeprom.ScreenChannel[1] = FREQ_CHANNEL_FIRST + BAND6_400MHz;
|
||||
gEeprom.MrChannel[0] = MR_CHANNEL_FIRST;
|
||||
gEeprom.MrChannel[1] = MR_CHANNEL_FIRST;
|
||||
gEeprom.FreqChannel[0] = FREQ_CHANNEL_FIRST + BAND3_137MHz;
|
||||
gEeprom.FreqChannel[1] = FREQ_CHANNEL_FIRST + BAND6_400MHz;
|
||||
|
||||
SETTINGS_SaveChannel(FREQ_CHANNEL_FIRST + BAND3_137MHz, 0, &gEeprom.VfoInfo[0], 2);
|
||||
SETTINGS_SaveChannel(FREQ_CHANNEL_FIRST + BAND6_400MHz, 1, &gEeprom.VfoInfo[1], 2);
|
||||
|
||||
gVfoStateChanged = true;
|
||||
gScheduleVfoSave = true;
|
||||
SETTINGS_SaveVfoIndicesFlush();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -613,35 +684,47 @@ void SETTINGS_SaveFM(void)
|
||||
fmCfg.band = gEeprom.FM_Band;
|
||||
// fmCfg.space = gEeprom.FM_Space;
|
||||
// 0E88
|
||||
PY25Q16_WriteBuffer(0x006000, fmCfg.__raw, 8, true);
|
||||
PY25Q16_WriteBuffer(0x00A020, fmCfg.__raw, 8, false);
|
||||
|
||||
// 0E40
|
||||
PY25Q16_WriteBuffer(0x003000, gFM_Channels, sizeof(gFM_Channels), true);
|
||||
PY25Q16_WriteBuffer(0x00A028, gFM_Channels, sizeof(gFM_Channels), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SETTINGS_SaveVfoIndices(void)
|
||||
{
|
||||
uint8_t State[8];
|
||||
gVfoStateChanged = true;
|
||||
gVfoSaveCountdown_10ms = 2;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_NOAA
|
||||
// 0x0E80
|
||||
PY25Q16_ReadBuffer(0x005000, State, sizeof(State));
|
||||
#endif
|
||||
void SETTINGS_SaveVfoIndicesFlush(void)
|
||||
{
|
||||
if (gScheduleVfoSave) {
|
||||
gScheduleVfoSave = false;
|
||||
|
||||
if (gVfoStateChanged) {
|
||||
gVfoStateChanged = false;
|
||||
uint16_t Data16[8];
|
||||
|
||||
State[0] = gEeprom.ScreenChannel[0];
|
||||
State[1] = gEeprom.MrChannel[0];
|
||||
State[2] = gEeprom.FreqChannel[0];
|
||||
State[3] = gEeprom.ScreenChannel[1];
|
||||
State[4] = gEeprom.MrChannel[1];
|
||||
State[5] = gEeprom.FreqChannel[1];
|
||||
#ifdef ENABLE_NOAA
|
||||
State[6] = gEeprom.NoaaChannel[0];
|
||||
State[7] = gEeprom.NoaaChannel[1];
|
||||
#endif
|
||||
#ifndef ENABLE_NOAA
|
||||
PY25Q16_ReadBuffer(0x00A010, Data16, sizeof(Data16));
|
||||
#endif
|
||||
|
||||
// 0x0E80
|
||||
PY25Q16_WriteBuffer(0x005000, State, 8, true);
|
||||
Data16[0] = gEeprom.ScreenChannel[0];
|
||||
Data16[1] = gEeprom.MrChannel[0];
|
||||
Data16[2] = gEeprom.FreqChannel[0];
|
||||
Data16[3] = gEeprom.ScreenChannel[1];
|
||||
Data16[4] = gEeprom.MrChannel[1];
|
||||
Data16[5] = gEeprom.FreqChannel[1];
|
||||
|
||||
#ifdef ENABLE_NOAA
|
||||
Data16[6] = gEeprom.NoaaChannel[0];
|
||||
Data16[7] = gEeprom.NoaaChannel[1];
|
||||
#endif
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A010, Data16, sizeof(Data16), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SETTINGS_SaveSettings(void)
|
||||
@@ -657,7 +740,9 @@ void SETTINGS_SaveSettings(void)
|
||||
|
||||
// 0x0E70
|
||||
State = SecBuf;
|
||||
State[0] = gEeprom.CHAN_1_CALL;
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
State[0] = gSetting_set_audio;
|
||||
#endif
|
||||
State[1] = gEeprom.SQUELCH_LEVEL;
|
||||
State[2] = gEeprom.TX_TIMEOUT_TIMER;
|
||||
#ifdef ENABLE_NOAA
|
||||
@@ -667,7 +752,11 @@ void SETTINGS_SaveSettings(void)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
State[4] = (gEeprom.KEY_LOCK ? 0x01 : 0) | (gEeprom.MENU_LOCK ? 0x02 :0) | ((gEeprom.SET_KEY & 0x0F) << 2);
|
||||
State[4] =
|
||||
(gEeprom.KEY_LOCK ? 0x01 : 0) |
|
||||
(gEeprom.MENU_LOCK ? 0x02 : 0) |
|
||||
((gEeprom.SET_KEY & 0x0F) << 2) |
|
||||
(gEeprom.SET_NAV ? 0x40 : 0);
|
||||
#else
|
||||
State[4] = gEeprom.KEY_LOCK;
|
||||
#endif
|
||||
@@ -708,24 +797,30 @@ void SETTINGS_SaveSettings(void)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
State[6] = (gEeprom.TAIL_TONE_ELIMINATION & 0x01) | ((gSetting_set_nfm & 0x03) << 1);
|
||||
State[6] =
|
||||
(gEeprom.TAIL_TONE_ELIMINATION & 0x01) |
|
||||
((gSetting_set_nfm & 0x01) << 1)
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
| ((gEeprom.VFO_OPEN & 0x01) << 2)
|
||||
#endif
|
||||
;
|
||||
#else
|
||||
State[6] = gEeprom.TAIL_TONE_ELIMINATION;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
State[7] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x07) << 4);
|
||||
State[7] = (gEeprom.CURRENT_STATE & 0x07) | ((gEeprom.SCAN_LIST_DEFAULT & 0x1F) << 3);
|
||||
#else
|
||||
State[7] = gEeprom.VFO_OPEN;
|
||||
#endif
|
||||
|
||||
PY25Q16_WriteBuffer(0x004000, SecBuf, 0x10, true);
|
||||
PY25Q16_WriteBuffer(0x00A000, SecBuf, 0x10, false);
|
||||
|
||||
// -------------------------
|
||||
// 0e90 - 0ee0
|
||||
|
||||
// memset(SecBuf, 0xff, 0x50);
|
||||
PY25Q16_ReadBuffer(0x007000, SecBuf, 0x50);
|
||||
PY25Q16_ReadBuffer(0x00A0A8, SecBuf, 0x50);
|
||||
|
||||
// 0x0E90
|
||||
State = SecBuf;
|
||||
@@ -788,35 +883,29 @@ void SETTINGS_SaveSettings(void)
|
||||
State[2] = gEeprom.PERMIT_REMOTE_KILL;
|
||||
#endif
|
||||
|
||||
PY25Q16_WriteBuffer(0x007000, SecBuf, 0x50, true);
|
||||
PY25Q16_WriteBuffer(0x00A0A8, SecBuf, 0x50, false);
|
||||
|
||||
// -------------------------
|
||||
// 0f18 - 0f20
|
||||
|
||||
memset(SecBuf, 0xff, 0x8);
|
||||
memset(SecBuf, 0xff, 0x08);
|
||||
|
||||
// 0x0F18
|
||||
State = SecBuf;
|
||||
State[0] = gEeprom.SCAN_LIST_DEFAULT;
|
||||
|
||||
tmp = 0;
|
||||
State[0] = (gEeprom.SCAN_LIST_DEFAULT & 0x7F)
|
||||
| ((gEeprom.SCAN_LIST_ENABLED & 0x01) << 7);
|
||||
|
||||
if (gEeprom.SCAN_LIST_ENABLED[0] == 1)
|
||||
tmp = tmp | (1 << 0);
|
||||
if (gEeprom.SCAN_LIST_ENABLED[1] == 1)
|
||||
tmp = tmp | (1 << 1);
|
||||
if (gEeprom.SCAN_LIST_ENABLED[2] == 1)
|
||||
tmp = tmp | (1 << 2);
|
||||
State[1] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[0] & 0xFF);
|
||||
State[2] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[0] >> 8);
|
||||
|
||||
State[1] = tmp;
|
||||
State[2] = gEeprom.SCANLIST_PRIORITY_CH1[0];
|
||||
State[3] = gEeprom.SCANLIST_PRIORITY_CH2[0];
|
||||
State[4] = gEeprom.SCANLIST_PRIORITY_CH1[1];
|
||||
State[5] = gEeprom.SCANLIST_PRIORITY_CH2[1];
|
||||
State[6] = gEeprom.SCANLIST_PRIORITY_CH1[2];
|
||||
State[7] = gEeprom.SCANLIST_PRIORITY_CH2[2];
|
||||
State[3] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[1] & 0xFF);
|
||||
State[4] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[1] >> 8);
|
||||
|
||||
PY25Q16_WriteBuffer(0x009000, SecBuf, 8, true);
|
||||
State[5] = (uint8_t)(gEeprom.CHAN_1_CALL & 0xFF);
|
||||
State[6] = (uint8_t)(gEeprom.CHAN_1_CALL >> 8);
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A130, SecBuf, 0x08, false);
|
||||
|
||||
// ---------------------
|
||||
// 0f40 - 0f48
|
||||
@@ -856,7 +945,7 @@ void SETTINGS_SaveSettings(void)
|
||||
#endif
|
||||
State[7] = (State[7] & ~(3u << 6)) | ((gSetting_backlight_on_tx_rx & 3u) << 6);
|
||||
|
||||
PY25Q16_WriteBuffer(0x00b000, SecBuf, 8, true);
|
||||
PY25Q16_WriteBuffer(0x00A150, SecBuf, 8, false);
|
||||
|
||||
// ------------------
|
||||
|
||||
@@ -864,7 +953,7 @@ void SETTINGS_SaveSettings(void)
|
||||
// 0x1FF0
|
||||
State = SecBuf;
|
||||
// TODO: TBD
|
||||
PY25Q16_ReadBuffer(0x00c000, State, 8);
|
||||
PY25Q16_ReadBuffer(0x00A158, State, 8);
|
||||
|
||||
//memset(State, 0xFF, sizeof(State));
|
||||
|
||||
@@ -905,7 +994,7 @@ void SETTINGS_SaveSettings(void)
|
||||
|
||||
gEeprom.KEY_LOCK_PTT = gSetting_set_lck;
|
||||
|
||||
PY25Q16_WriteBuffer(0x00c000, SecBuf, 8, true);
|
||||
PY25Q16_WriteBuffer(0x00A158, SecBuf, 8, false);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_VOL
|
||||
@@ -913,7 +1002,7 @@ void SETTINGS_SaveSettings(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode)
|
||||
void SETTINGS_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode)
|
||||
{
|
||||
#ifdef ENABLE_NOAA
|
||||
if (IS_NOAA_CHANNEL(Channel))
|
||||
@@ -925,7 +1014,7 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
|
||||
|
||||
if (IS_FREQ_CHANNEL(Channel)) { // it's a VFO, not a channel
|
||||
// 0x0C80
|
||||
OffsetVFO = (VFO == 0) ? 0x001000 : 0x001010;
|
||||
OffsetVFO = (VFO == 0) ? 0x009000 : 0x009010;
|
||||
OffsetVFO += (Channel - FREQ_CHANNEL_FIRST) * 32;
|
||||
}
|
||||
|
||||
@@ -990,16 +1079,16 @@ void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration)
|
||||
PY25Q16_WriteBuffer(0x010000 + 0x140, batteryCalibration, 12, false);
|
||||
}
|
||||
|
||||
void SETTINGS_SaveChannelName(uint8_t channel, const char * name)
|
||||
void SETTINGS_SaveChannelName(uint16_t channel, const char * name)
|
||||
{
|
||||
uint16_t offset = channel * 16;
|
||||
uint8_t buf[16] = {0};
|
||||
memcpy(buf, name, MIN(strlen(name), 10u));
|
||||
// 0x0F50
|
||||
PY25Q16_WriteBuffer(0x00e000 + offset, buf, 0x10, false);
|
||||
PY25Q16_WriteBuffer(0x004000 + offset, buf, 0x10, false);
|
||||
}
|
||||
|
||||
void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save)
|
||||
void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save)
|
||||
{
|
||||
#ifdef ENABLE_NOAA
|
||||
if (!IS_NOAA_CHANNEL(channel))
|
||||
@@ -1009,20 +1098,22 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
ChannelAttributes_t att = {
|
||||
.band = 0x7,
|
||||
.compander = 0,
|
||||
.scanlist1 = 0,
|
||||
.scanlist2 = 0,
|
||||
.scanlist3 = 0,
|
||||
.unused_1 = 0,
|
||||
.unused_2 = 0,
|
||||
.exclude = 0,
|
||||
.scanlist = 0,
|
||||
}; // default attributes
|
||||
|
||||
// 0x0D60
|
||||
PY25Q16_ReadBuffer(0x002000 + channel, &state, 1);
|
||||
PY25Q16_ReadBuffer(0x008000 + channel, &state, 1);
|
||||
|
||||
if (keep) {
|
||||
att.band = pVFO->Band;
|
||||
att.scanlist1 = pVFO->SCANLIST1_PARTICIPATION;
|
||||
att.scanlist2 = pVFO->SCANLIST2_PARTICIPATION;
|
||||
att.scanlist3 = pVFO->SCANLIST3_PARTICIPATION;
|
||||
att.compander = pVFO->Compander;
|
||||
att.unused_1 = 0;
|
||||
att.unused_2 = 0;
|
||||
att.exclude = 0;
|
||||
att.scanlist = pVFO->SCANLIST_PARTICIPATION;
|
||||
if (check && state.__val == att.__val)
|
||||
return; // no change in the attributes
|
||||
}
|
||||
@@ -1034,13 +1125,13 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep,
|
||||
#endif
|
||||
if(save)
|
||||
{
|
||||
uint8_t buf[224];
|
||||
PY25Q16_ReadBuffer(0x002000, buf, sizeof(buf));
|
||||
uint16_t buf[MR_CHANNELS_MAX + 24];
|
||||
PY25Q16_ReadBuffer(0x008000, buf, sizeof(buf));
|
||||
buf[channel] = state.__val;
|
||||
PY25Q16_WriteBuffer(0x002000, buf, sizeof(buf), true);
|
||||
PY25Q16_WriteBuffer(0x008000, buf, sizeof(buf), false);
|
||||
}
|
||||
|
||||
gMR_ChannelAttributes[channel] = att;
|
||||
MR_SetChannelAttributes(channel, &att);
|
||||
|
||||
if (IS_MR_CHANNEL(channel)) { // it's a memory channel
|
||||
if (!keep) {
|
||||
@@ -1057,7 +1148,7 @@ void SETTINGS_WriteBuildOptions(void)
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
// 0x1FF0
|
||||
PY25Q16_ReadBuffer(0x00c000, State, sizeof(State));
|
||||
PY25Q16_ReadBuffer(0x00A158, State, sizeof(State));
|
||||
#endif
|
||||
|
||||
State[0] = 0
|
||||
@@ -1110,18 +1201,37 @@ State[1] = 0
|
||||
| (1 << 6)
|
||||
#endif
|
||||
;
|
||||
PY25Q16_WriteBuffer(0x00c000, State, sizeof(State), true);
|
||||
PY25Q16_WriteBuffer(0x00A158, State, sizeof(State), false);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
void SETTINGS_WriteCurrentState(void)
|
||||
{
|
||||
uint8_t State[0x10];
|
||||
// 0x0E78
|
||||
PY25Q16_ReadBuffer(0x004000, State, sizeof(State));
|
||||
//State[11] = (gEeprom.CURRENT_STATE << 4) | (gEeprom.BATTERY_SAVE & 0x0F);
|
||||
State[15] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x07) << 4);
|
||||
PY25Q16_WriteBuffer(0x004000, State, sizeof(State), true);
|
||||
uint8_t State[0x08];
|
||||
|
||||
PY25Q16_ReadBuffer(0x00A008, State, sizeof(State));
|
||||
State[7] =
|
||||
(gEeprom.CURRENT_STATE & 0x07) |
|
||||
((gEeprom.SCAN_LIST_DEFAULT & 0x1F) << 3);
|
||||
PY25Q16_WriteBuffer(0x00A008, State, sizeof(State), false);
|
||||
|
||||
//
|
||||
|
||||
PY25Q16_ReadBuffer(0x00A130, State, sizeof(State));
|
||||
|
||||
State[0] = (gEeprom.SCAN_LIST_DEFAULT & 0x7F)
|
||||
| ((gEeprom.SCAN_LIST_ENABLED & 0x01) << 7);
|
||||
|
||||
State[1] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[0] & 0xFF);
|
||||
State[2] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[0] >> 8);
|
||||
|
||||
State[3] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[1] & 0xFF);
|
||||
State[4] = (uint8_t)(gEeprom.SCANLIST_PRIORITY_CH[1] >> 8);
|
||||
|
||||
State[5] = (uint8_t)(gEeprom.CHAN_1_CALL & 0xFF);
|
||||
State[6] = (uint8_t)(gEeprom.CHAN_1_CALL >> 8);
|
||||
|
||||
PY25Q16_WriteBuffer(0x00A130, State, sizeof(State), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1137,32 +1247,44 @@ State[1] = 0
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
|
||||
void SETTINGS_ResetTxLock(void)
|
||||
{
|
||||
// TODO: This is expensive operation!
|
||||
// This is an expensive operation: full scan of all MR channels
|
||||
|
||||
#define SETTINGS_ResetTxLock_BATCH 10
|
||||
#define CHANNEL_SIZE 16
|
||||
#define TXLOCK_BYTE_OFFSET 12
|
||||
#define TXLOCK_BIT 6
|
||||
#define SETTINGS_ResetTxLock_BATCH 32
|
||||
|
||||
uint8_t Buf[0xc80 / SETTINGS_ResetTxLock_BATCH];
|
||||
const uint32_t BatchSize = 0xc80 / SETTINGS_ResetTxLock_BATCH;
|
||||
const uint32_t BatchChCnt = BatchSize / 0x10;
|
||||
const uint32_t TotalBytes = MR_CHANNELS_MAX * CHANNEL_SIZE; // 1024 * 16 = 16 384
|
||||
const uint32_t BatchSize = TotalBytes / SETTINGS_ResetTxLock_BATCH; // 16 384 / 32 = 512
|
||||
const uint32_t BatchChCnt = BatchSize / CHANNEL_SIZE; // 32 channels per batch
|
||||
|
||||
for (uint32_t i = 0; i < SETTINGS_ResetTxLock_BATCH; i++)
|
||||
uint8_t Buf[BatchSize];
|
||||
|
||||
for (uint32_t batch = 0; batch < SETTINGS_ResetTxLock_BATCH; batch++)
|
||||
{
|
||||
uint32_t Offset = i * BatchSize;
|
||||
PY25Q16_ReadBuffer(0 + Offset, Buf, sizeof(Buf));
|
||||
uint32_t Offset = batch * BatchSize;
|
||||
|
||||
uint8_t *State;
|
||||
for (uint8_t channel = 0; channel < BatchChCnt; channel++)
|
||||
PY25Q16_ReadBuffer(Offset, Buf, BatchSize);
|
||||
|
||||
for (uint32_t ch = 0; ch < BatchChCnt; ch++)
|
||||
{
|
||||
uint16_t OffsetVFO = channel * 16;
|
||||
State = Buf + OffsetVFO;
|
||||
State[4] |= (1 << 6);
|
||||
uint32_t off = ch * CHANNEL_SIZE;
|
||||
Buf[off + TXLOCK_BYTE_OFFSET] |= (1 << TXLOCK_BIT);
|
||||
}
|
||||
|
||||
PY25Q16_WriteBuffer(0 + Offset, Buf, sizeof(Buf), false);
|
||||
PY25Q16_WriteBuffer(Offset, Buf, BatchSize, false);
|
||||
}
|
||||
|
||||
#undef SETTINGS_ResetTxLock_BATCH
|
||||
RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD);
|
||||
RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD);
|
||||
|
||||
#undef SETTINGS_ResetTxLock_BATCH
|
||||
#undef CHANNEL_SIZE
|
||||
#undef TXLOCK_BYTE_OFFSET
|
||||
#undef TXLOCK_BIT
|
||||
}
|
||||
|
||||
#endif
|
||||
+15
-13
@@ -118,6 +118,7 @@ enum ACTION_OPT_t {
|
||||
ACTION_OPT_WN,
|
||||
ACTION_OPT_BACKLIGHT,
|
||||
ACTION_OPT_MUTE,
|
||||
ACTION_OPT_RXA,
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
ACTION_OPT_POWER_HIGH,
|
||||
ACTION_OPT_REMOVE_OFFSET,
|
||||
@@ -162,11 +163,11 @@ enum CHANNEL_DisplayMode_t {
|
||||
typedef enum CHANNEL_DisplayMode_t CHANNEL_DisplayMode_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ScreenChannel[2]; // current channels set in the radio (memory or frequency channels)
|
||||
uint8_t FreqChannel[2]; // last frequency channels used
|
||||
uint8_t MrChannel[2]; // last memory channels used
|
||||
uint16_t ScreenChannel[2]; // current channels set in the radio (memory or frequency channels)
|
||||
uint16_t FreqChannel[2]; // last frequency channels used
|
||||
uint16_t MrChannel[2]; // last memory channels used
|
||||
#ifdef ENABLE_NOAA
|
||||
uint8_t NoaaChannel[2];
|
||||
uint16_t NoaaChannel[2];
|
||||
#endif
|
||||
|
||||
// The actual VFO index (0-upper/1-lower) that is now used for RX,
|
||||
@@ -194,6 +195,7 @@ typedef struct {
|
||||
bool KEY_LOCK;
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
bool KEY_LOCK_PTT;
|
||||
bool SET_NAV;
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
bool MENU_LOCK;
|
||||
@@ -214,9 +216,8 @@ typedef struct {
|
||||
uint8_t BACKLIGHT_TIME;
|
||||
uint8_t SCAN_RESUME_MODE;
|
||||
uint8_t SCAN_LIST_DEFAULT;
|
||||
bool SCAN_LIST_ENABLED[3];
|
||||
uint8_t SCANLIST_PRIORITY_CH1[3];
|
||||
uint8_t SCANLIST_PRIORITY_CH2[3];
|
||||
bool SCAN_LIST_ENABLED;
|
||||
uint16_t SCANLIST_PRIORITY_CH[6];
|
||||
//#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE // Fix me !!! What the hell is this?
|
||||
uint8_t CURRENT_STATE;
|
||||
uint8_t CURRENT_LIST;
|
||||
@@ -241,7 +242,7 @@ typedef struct {
|
||||
uint8_t KEY_2_LONG_PRESS_ACTION;
|
||||
uint8_t MIC_SENSITIVITY;
|
||||
uint8_t MIC_SENSITIVITY_TUNING;
|
||||
uint8_t CHAN_1_CALL;
|
||||
uint16_t CHAN_1_CALL;
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
char ANI_DTMF_ID[8];
|
||||
char KILL_CODE[8];
|
||||
@@ -308,18 +309,19 @@ extern EEPROM_Config_t gEeprom;
|
||||
|
||||
void SETTINGS_InitEEPROM(void);
|
||||
void SETTINGS_LoadCalibration(void);
|
||||
uint32_t SETTINGS_FetchChannelFrequency(const int channel);
|
||||
void SETTINGS_FetchChannelName(char *s, const int channel);
|
||||
uint32_t SETTINGS_FetchChannelFrequency(const uint16_t channel);
|
||||
void SETTINGS_FetchChannelName(char *s, const uint16_t channel);
|
||||
void SETTINGS_FactoryReset(bool bIsAll);
|
||||
#ifdef ENABLE_FMRADIO
|
||||
void SETTINGS_SaveFM(void);
|
||||
#endif
|
||||
void SETTINGS_SaveVfoIndices(void);
|
||||
void SETTINGS_SaveVfoIndicesFlush(void);
|
||||
void SETTINGS_SaveSettings(void);
|
||||
void SETTINGS_SaveChannelName(uint8_t channel, const char * name);
|
||||
void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode);
|
||||
void SETTINGS_SaveChannelName(uint16_t channel, const char * name);
|
||||
void SETTINGS_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode);
|
||||
void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration);
|
||||
void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save);
|
||||
void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep, bool check, bool save);
|
||||
void SETTINGS_WriteBuildOptions(void);
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
|
||||
void SETTINGS_WriteCurrentState(void);
|
||||
|
||||
+56
-13
@@ -70,7 +70,15 @@ void UI_DisplayAircopy(void)
|
||||
|
||||
memset(String, 0, sizeof(String));
|
||||
|
||||
percent = (gAirCopyBlockNumber * 10000) / 120;
|
||||
// Get the current map and calculate percentage based on its total blocks
|
||||
const AIRCOPY_TransferMap_t *currentMap = AIRCOPY_GetCurrentMap();
|
||||
|
||||
uint16_t doneBlocks = gAirCopyBlockNumber + gErrorsDuringAirCopy;
|
||||
|
||||
if (doneBlocks > currentMap->total_blocks)
|
||||
doneBlocks = currentMap->total_blocks;
|
||||
|
||||
percent = (doneBlocks * 10000) / currentMap->total_blocks;
|
||||
|
||||
if (gAirCopyIsSendMode == 0) {
|
||||
sprintf(String, "RCV:%02u.%02u%% E:%d", percent / 100, percent % 100, gErrorsDuringAirCopy);
|
||||
@@ -86,7 +94,7 @@ void UI_DisplayAircopy(void)
|
||||
gFrameBuffer[4][1] = 0x3c;
|
||||
gFrameBuffer[4][2] = 0x42;
|
||||
|
||||
for(uint8_t i = 1; i <= 122; i++)
|
||||
for(uint8_t i = 1; i <= AIRCOPY_BAR_WIDTH + 2; i++)
|
||||
{
|
||||
gFrameBuffer[4][2 + i] = 0x81;
|
||||
}
|
||||
@@ -94,26 +102,61 @@ void UI_DisplayAircopy(void)
|
||||
gFrameBuffer[4][125] = 0x42;
|
||||
gFrameBuffer[4][126] = 0x3c;
|
||||
}
|
||||
|
||||
if(gAirCopyBlockNumber + gErrorsDuringAirCopy != 0)
|
||||
|
||||
// Draw memory selection
|
||||
if(gAircopyState == AIRCOPY_READY)
|
||||
{
|
||||
// Check CRC
|
||||
if(gErrorsDuringAirCopy != lErrorsDuringAirCopy)
|
||||
doneBlocks = 0;
|
||||
|
||||
memset(gFrameBuffer[5], 0, 128);
|
||||
memset(gFrameBuffer[6], 0, 128);
|
||||
|
||||
if(gAircopyCurrentMapIndex < AIRCOPY_NUM_BANKS) {
|
||||
sprintf(String, "MEM %03u - %03u%", (gAircopyCurrentMapIndex * 128) + 1, (gAircopyCurrentMapIndex + 1) * 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_bit(crc, gAirCopyBlockNumber + gErrorsDuringAirCopy);
|
||||
sprintf(String, "Settings");
|
||||
}
|
||||
UI_PrintString(String, 2, 127, 5, 8);
|
||||
}
|
||||
|
||||
if (doneBlocks > 0)
|
||||
{
|
||||
// Track CRC errors per real block index
|
||||
if (gErrorsDuringAirCopy != lErrorsDuringAirCopy)
|
||||
{
|
||||
// Mark the last processed block as faulty
|
||||
set_bit(crc, doneBlocks - 1);
|
||||
lErrorsDuringAirCopy = gErrorsDuringAirCopy;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < (gAirCopyBlockNumber + gErrorsDuringAirCopy); i++)
|
||||
const AIRCOPY_TransferMap_t *currentMap = AIRCOPY_GetCurrentMap();
|
||||
|
||||
uint16_t total = currentMap->total_blocks;
|
||||
uint16_t done = gAirCopyBlockNumber + gErrorsDuringAirCopy;
|
||||
|
||||
if (done > total) done = total;
|
||||
|
||||
for (uint8_t col = 0; col < AIRCOPY_BAR_WIDTH; col++)
|
||||
{
|
||||
if(get_bit(crc, i) == 0)
|
||||
{
|
||||
gFrameBuffer[4][i + 4] = 0xbd;
|
||||
}
|
||||
/* Map column [0..BAR_WIDTH-1] to block [0..total-1] */
|
||||
uint16_t b = (uint16_t)((col * (uint32_t)total) / AIRCOPY_BAR_WIDTH);
|
||||
|
||||
bool processed = (b < done);
|
||||
bool error = processed && get_bit(crc, b);
|
||||
|
||||
if (!processed)
|
||||
gFrameBuffer[4][col + 4] = 0x81; // not yet processed
|
||||
else if (error)
|
||||
gFrameBuffer[4][col + 4] = 0x81; // error gap (intentional hole)
|
||||
else
|
||||
gFrameBuffer[4][col + 4] = 0xBD; // ok filled
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ST7565_BlitFullScreen();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+2
-2
@@ -59,7 +59,7 @@ void UI_DisplayFM(void)
|
||||
pPrintStr = String;
|
||||
} else {
|
||||
pPrintStr = "VFO";
|
||||
for (unsigned int i = 0; i < 20; i++) {
|
||||
for (unsigned int i = 0; i < FM_CHANNELS_MAX; i++) {
|
||||
if (gEeprom.FM_FrequencyPlaying == gFM_Channels[i]) {
|
||||
sprintf(String, "VFO(CH%02u)", i + 1);
|
||||
pPrintStr = String;
|
||||
@@ -68,7 +68,7 @@ void UI_DisplayFM(void)
|
||||
}
|
||||
}
|
||||
} else if (gFM_AutoScan) {
|
||||
sprintf(String, "A-SCAN(%u)", gFM_ChannelPosition + 1);
|
||||
sprintf(String, "A-SCAN(%u)", gFM_ChannelPosition);
|
||||
pPrintStr = String;
|
||||
} else {
|
||||
pPrintStr = "M-SCAN";
|
||||
|
||||
+58
-6
@@ -23,11 +23,8 @@
|
||||
#include "ui/inputbox.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
void UI_GenerateChannelString(char *pString, const uint8_t Channel)
|
||||
void UI_GenerateChannelString(char *pString, const uint16_t Channel)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -44,7 +41,7 @@ void UI_GenerateChannelString(char *pString, const uint8_t Channel)
|
||||
pString[i + 3] = (gInputBox[i] == 10) ? '-' : gInputBox[i] + '0';
|
||||
}
|
||||
|
||||
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint8_t ChannelNumber)
|
||||
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint16_t ChannelNumber)
|
||||
{
|
||||
if (gInputBoxIndex > 0) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
@@ -58,7 +55,9 @@ void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uin
|
||||
if (bShowPrefix) {
|
||||
// BUG here? Prefixed NULLs are allowed
|
||||
sprintf(pString, "CH-%03u", ChannelNumber + 1);
|
||||
} else if (ChannelNumber == 0xFF) {
|
||||
} else if (ChannelNumber == MR_CHANNEL_LAST + 1) {
|
||||
strcpy(pString, "None");
|
||||
} else if (ChannelNumber == 0xFFFF) {
|
||||
strcpy(pString, "NULL");
|
||||
} else {
|
||||
sprintf(pString, "%03u", ChannelNumber + 1);
|
||||
@@ -116,6 +115,35 @@ void UI_PrintStringSmallNormal(const char *pString, uint8_t Start, uint8_t End,
|
||||
UI_PrintStringSmall(pString, Start, End, Line, ARRAY_SIZE(gFontSmall[0]), (const uint8_t *)gFontSmall);
|
||||
}
|
||||
|
||||
void UI_PrintStringSmallNormalInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
|
||||
{
|
||||
// First draw the string normally
|
||||
UI_PrintStringSmallNormal(pString, Start, End, Line);
|
||||
|
||||
// Now invert the framebuffer bits for the rendered area
|
||||
uint8_t len = strlen(pString);
|
||||
uint8_t char_width = 7; // small font is typically 6px wide
|
||||
|
||||
uint8_t x_start = Start;
|
||||
uint8_t x_end = Start + (len * char_width) + 1;
|
||||
|
||||
if (End != 0 && x_end > End)
|
||||
x_end = End;
|
||||
|
||||
gFrameBuffer[Line][x_start - 3] ^= 0x3E;
|
||||
gFrameBuffer[Line][x_start - 2] ^= 0x7F;
|
||||
gFrameBuffer[Line][x_start - 1] ^= 0xFF;
|
||||
for (uint8_t x = x_start; x < x_end; x++)
|
||||
{
|
||||
gFrameBuffer[Line][x] ^= 0xFF;
|
||||
gFrameBuffer[Line - 1][x] ^= 0x80;
|
||||
}
|
||||
gFrameBuffer[Line][x_end + 0] ^= 0xFF;
|
||||
gFrameBuffer[Line][x_end + 1] ^= 0x7F;
|
||||
gFrameBuffer[Line][x_end + 2] ^= 0x3E;
|
||||
}
|
||||
|
||||
|
||||
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
|
||||
{
|
||||
#ifdef ENABLE_SMALL_BOLD
|
||||
@@ -129,6 +157,30 @@ void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, ui
|
||||
UI_PrintStringSmall(pString, Start, End, Line, char_width, font);
|
||||
}
|
||||
|
||||
void UI_PrintStringSmallBoldInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
|
||||
{
|
||||
// First draw the string normally
|
||||
UI_PrintStringSmallBold(pString, Start, End, Line);
|
||||
|
||||
// Now invert the framebuffer bits for the rendered area
|
||||
uint8_t len = strlen(pString);
|
||||
uint8_t char_width = 7; // small font is typically 6px wide
|
||||
|
||||
uint8_t x_start = Start;
|
||||
uint8_t x_end = Start + (len * char_width);
|
||||
|
||||
if (End != 0 && x_end > End)
|
||||
x_end = End;
|
||||
|
||||
gFrameBuffer[Line][x_start] ^= 0x7F;
|
||||
for (uint8_t x = x_start + 1; x < x_end; x++)
|
||||
{
|
||||
gFrameBuffer[Line][x] ^= 0x41;
|
||||
}
|
||||
gFrameBuffer[Line][x_end + 1] ^= 0x7F;
|
||||
}
|
||||
|
||||
|
||||
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t * buffer)
|
||||
{
|
||||
UI_PrintStringBuffer(pString, buffer, ARRAY_SIZE(gFontSmall[0]), (uint8_t *)gFontSmall);
|
||||
|
||||
+4
-2
@@ -20,11 +20,13 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void UI_GenerateChannelString(char *pString, const uint8_t Channel);
|
||||
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint8_t ChannelNumber);
|
||||
void UI_GenerateChannelString(char *pString, const uint16_t Channel);
|
||||
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint16_t ChannelNumber);
|
||||
void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, uint8_t Width);
|
||||
void UI_PrintStringSmallNormal(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallNormalInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBoldInverse(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
|
||||
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t *buffer);
|
||||
void UI_PrintStringSmallBufferBold(const char *pString, uint8_t * buffer);
|
||||
void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center);
|
||||
|
||||
+72
-43
@@ -37,6 +37,7 @@
|
||||
#include "ui/main.h"
|
||||
#include "ui/ui.h"
|
||||
#include "audio.h"
|
||||
#include "menu.h"
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
#include "driver/system.h"
|
||||
@@ -272,10 +273,13 @@ void DisplayRSSIBar(const bool now)
|
||||
//sprintf(String, "%d", RxBlink);
|
||||
//UI_PrintStringSmallBold(String, 80, 0, RxLine);
|
||||
|
||||
/*
|
||||
if(RxLine >= 0 && center_line != CENTER_LINE_IN_USE)
|
||||
{
|
||||
if (RxBlink == 0 || RxBlink == 1) {
|
||||
UI_PrintStringSmallBold("RX", 8, 0, RxLine);
|
||||
//GUI_DisplaySmallest("RX", 10, (RxLine * 8) + 1, false, true);
|
||||
|
||||
if (RxBlink == 1) RxBlink = 2;
|
||||
} else {
|
||||
for (uint8_t i = 8; i < 24; i++)
|
||||
@@ -286,6 +290,7 @@ void DisplayRSSIBar(const bool now)
|
||||
}
|
||||
ST7565_BlitLine(RxLine);
|
||||
}
|
||||
*/
|
||||
#else
|
||||
const unsigned int line = 3;
|
||||
#endif
|
||||
@@ -736,12 +741,12 @@ void UI_DisplayMain(void)
|
||||
|
||||
uint32_t frequency = gEeprom.VfoInfo[vfo_num].pRX->Frequency;
|
||||
|
||||
if(TX_freq_check(frequency) != 0 && gEeprom.VfoInfo[vfo_num].TX_LOCK == true)
|
||||
if(TX_freq_check(frequency) != 0 && gEeprom.VfoInfo[vfo_num].TX_LOCK == true && !FUNCTION_IsRx())
|
||||
{
|
||||
if(isMainOnly())
|
||||
memcpy(p_line0 + 14, BITMAP_VFO_Lock, sizeof(BITMAP_VFO_Lock));
|
||||
memcpy(p_line0 + 25, BITMAP_VFO_Lock, sizeof(BITMAP_VFO_Lock));
|
||||
else
|
||||
memcpy(p_line0 + 24, BITMAP_VFO_Lock, sizeof(BITMAP_VFO_Lock));
|
||||
memcpy(p_line0 + 25, BITMAP_VFO_Lock, sizeof(BITMAP_VFO_Lock));
|
||||
}
|
||||
|
||||
if (gCurrentFunction == FUNCTION_TRANSMIT)
|
||||
@@ -756,7 +761,9 @@ void UI_DisplayMain(void)
|
||||
if (activeTxVFO == vfo_num)
|
||||
{ // show the TX symbol
|
||||
mode = VFO_MODE_TX;
|
||||
UI_PrintStringSmallBold("TX", 8, 0, line);
|
||||
//UI_PrintStringSmallBold("TX", 8, 0, line);
|
||||
GUI_DisplaySmallest("TX", 10, line == 0 ? 1 : 33, false, true);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -778,6 +785,21 @@ void UI_DisplayMain(void)
|
||||
{
|
||||
RxBlink = 0;
|
||||
}
|
||||
|
||||
if (RxBlink == 0 || RxBlink == 1) {
|
||||
if(gRxVfo->Modulation == MODULATION_AM)
|
||||
GUI_DisplaySmallest("AIR", 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
else {
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
strcpy(String, gSubMenu_SET_AUD[gSetting_set_audio]);
|
||||
#else
|
||||
strcpy(String, "RX");
|
||||
#endif
|
||||
GUI_DisplaySmallest(String, 10, RxLine == 0 ? 1 : 33, false, true);
|
||||
}
|
||||
|
||||
//UI_PrintStringSmallBold("RX", 8, 0, RxLine);
|
||||
}
|
||||
#else
|
||||
UI_PrintStringSmallBold("RX", 8, 0, line);
|
||||
#endif
|
||||
@@ -799,13 +821,13 @@ void UI_DisplayMain(void)
|
||||
|
||||
if (IS_MR_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
|
||||
{ // channel mode
|
||||
const unsigned int x = 2;
|
||||
const unsigned int x = 3;
|
||||
const bool inputting = gInputBoxIndex != 0 && gEeprom.TX_VFO == vfo_num;
|
||||
if (!inputting)
|
||||
sprintf(String, "M%u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
if (!inputting || gScanStateDir != SCAN_OFF)
|
||||
sprintf(String, "%04u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
else
|
||||
sprintf(String, "M%.3s", INPUTBOX_GetAscii()); // show the input text
|
||||
UI_PrintStringSmallNormal(String, x, 0, line + 1);
|
||||
sprintf(String, "%.4s", INPUTBOX_GetAscii()); // show the input text
|
||||
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
|
||||
}
|
||||
else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
|
||||
{ // frequency mode
|
||||
@@ -843,7 +865,7 @@ void UI_DisplayMain(void)
|
||||
if (state != VFO_STATE_NORMAL)
|
||||
{
|
||||
if (state < ARRAY_SIZE(VfoStateStr))
|
||||
UI_PrintString(VfoStateStr[state], 31, 0, line, 8);
|
||||
UI_PrintString(VfoStateStr[state], 35, 0, line, 8);
|
||||
}
|
||||
else if (gInputBoxIndex > 0 && IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]) && gEeprom.TX_VFO == vfo_num)
|
||||
{ // user entering a frequency
|
||||
@@ -881,43 +903,48 @@ void UI_DisplayMain(void)
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
if(gEeprom.MENU_LOCK == false) {
|
||||
#endif
|
||||
uint8_t countList = 0;
|
||||
uint8_t shiftList = 0;
|
||||
|
||||
if(gMR_ChannelExclude[gEeprom.ScreenChannel[vfo_num]] == false)
|
||||
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
|
||||
|
||||
|
||||
if(att->exclude == false)
|
||||
{
|
||||
// show the scan list assigment symbols
|
||||
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
|
||||
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
|
||||
|
||||
countList = att.scanlist1 + att.scanlist2 + att.scanlist3;
|
||||
|
||||
if(countList == 0)
|
||||
{
|
||||
memcpy(p_line0 + 127 - (1 * 6), BITMAP_ScanList0, sizeof(BITMAP_ScanList0));
|
||||
uint8_t countList = att->scanlist;
|
||||
if(countList > MR_CHANNELS_LIST + 1) {
|
||||
countList = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftList = countList;
|
||||
|
||||
if (att.scanlist1)
|
||||
{
|
||||
memcpy(p_line0 + 127 - (shiftList * 6), BITMAP_ScanList1, sizeof(BITMAP_ScanList1));
|
||||
shiftList--;
|
||||
}
|
||||
if (att.scanlist2)
|
||||
{
|
||||
memcpy(p_line0 + 127 - (shiftList * 6), BITMAP_ScanList2, sizeof(BITMAP_ScanList2));
|
||||
shiftList--;
|
||||
}
|
||||
if (att.scanlist3)
|
||||
{
|
||||
memcpy(p_line0 + 127 - (shiftList * 6), BITMAP_ScanList3, sizeof(BITMAP_ScanList3));
|
||||
}
|
||||
const char *displayStr = (countList == MR_CHANNELS_LIST + 1) ? "ALL" :
|
||||
(countList == 0) ? "OFF" : String;
|
||||
uint8_t xStart = (countList > 0 && countList != MR_CHANNELS_LIST + 1) ? 117 : 113;
|
||||
uint8_t xDisplay = (countList > 0 && countList != MR_CHANNELS_LIST + 1) ? 119 : 115;
|
||||
|
||||
if(countList > 0 && countList != MR_CHANNELS_LIST + 1) {
|
||||
sprintf(String, "%02d", countList);
|
||||
}
|
||||
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 2 : 34, false, true);
|
||||
|
||||
for (uint8_t x = xStart; x < 128; x++) {
|
||||
gFrameBuffer[line][x] ^= 0xFE;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p_line0 + 127 - (1 * 6), BITMAP_ScanListE, sizeof(BITMAP_ScanListE));
|
||||
const char *displayStr = "EX";
|
||||
|
||||
uint8_t xStart = 117;
|
||||
uint8_t xDisplay = 119;
|
||||
|
||||
GUI_DisplaySmallest(displayStr, xDisplay, line == 0 ? 2 : 34, false, true);
|
||||
|
||||
for (uint8_t x = xStart; x < 128; x++) {
|
||||
gFrameBuffer[line][x] ^= 0xFE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
@@ -928,7 +955,7 @@ void UI_DisplayMain(void)
|
||||
|
||||
// compander symbol
|
||||
#ifndef ENABLE_BIG_FREQ
|
||||
if (att.compander)
|
||||
if (att->compander)
|
||||
memcpy(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
|
||||
#else
|
||||
// TODO: // find somewhere else to put the symbol
|
||||
@@ -957,7 +984,7 @@ void UI_DisplayMain(void)
|
||||
|
||||
case MDF_CHANNEL: // show the channel number
|
||||
sprintf(String, "CH-%03u", gEeprom.ScreenChannel[vfo_num] + 1);
|
||||
UI_PrintString(String, 32, 0, line, 8);
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
break;
|
||||
|
||||
case MDF_NAME: // show the channel name
|
||||
@@ -970,13 +997,15 @@ void UI_DisplayMain(void)
|
||||
}
|
||||
|
||||
if (gEeprom.CHANNEL_DISPLAY_MODE == MDF_NAME) {
|
||||
UI_PrintString(String, 32, 0, line, 8);
|
||||
String[9] = 0;
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
}
|
||||
else {
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
if (isMainOnly())
|
||||
{
|
||||
UI_PrintString(String, 32, 0, line, 8);
|
||||
String[9] = 0;
|
||||
UI_PrintString(String, 36, 0, line, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1043,8 +1072,8 @@ void UI_DisplayMain(void)
|
||||
}
|
||||
|
||||
// show the channel symbols
|
||||
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
|
||||
if (att.compander)
|
||||
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
|
||||
if (att->compander)
|
||||
#ifdef ENABLE_BIG_FREQ
|
||||
memcpy(p_line0 + 120, BITMAP_compand, sizeof(BITMAP_compand));
|
||||
#else
|
||||
|
||||
+79
-81
@@ -63,17 +63,15 @@ const t_menu_item MenuList[] =
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
{"TXLock", MENU_TX_LOCK },
|
||||
#endif
|
||||
{"ScAdd1", MENU_S_ADD1 },
|
||||
{"ScAdd2", MENU_S_ADD2 },
|
||||
{"ScAdd3", MENU_S_ADD3 },
|
||||
{"ChList", MENU_LIST_CH },
|
||||
{"ChSave", MENU_MEM_CH }, // was "MEM-CH"
|
||||
{"ChDele", MENU_DEL_CH }, // was "DEL-CH"
|
||||
{"ChName", MENU_MEM_NAME },
|
||||
|
||||
{"SList", MENU_S_LIST },
|
||||
{"SList1", MENU_SLIST1 },
|
||||
{"SList2", MENU_SLIST2 },
|
||||
{"SList3", MENU_SLIST3 },
|
||||
{"ScList", MENU_S_LIST },
|
||||
{"ScPri", MENU_S_PRI },
|
||||
{"PriCh1", MENU_S_PRI_CH_1 },
|
||||
{"PriCh2", MENU_S_PRI_CH_2 },
|
||||
{"ScnRev", MENU_SC_REV },
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
#ifdef ENABLE_NOAA
|
||||
@@ -149,6 +147,9 @@ const t_menu_item MenuList[] =
|
||||
{"SetLck", MENU_SET_LCK },
|
||||
{"SetMet", MENU_SET_MET },
|
||||
{"SetGUI", MENU_SET_GUI },
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
{"SetRxA", MENU_SET_AUD },
|
||||
#endif
|
||||
{"SetTmr", MENU_SET_TMR },
|
||||
#ifdef ENABLE_FEAT_F4HWN_SLEEP
|
||||
{"SetOff", MENU_SET_OFF },
|
||||
@@ -183,6 +184,7 @@ const t_menu_item MenuList[] =
|
||||
#endif
|
||||
{"BatCal", MENU_BATCAL }, // battery voltage calibration
|
||||
{"BatTyp", MENU_BATTYP }, // battery type 1600/2200mAh
|
||||
{"SetNav", MENU_SET_NAV }, // set navigation (LEFT / RIGHT or UP / DOWN)
|
||||
{"Reset", MENU_RESET }, // might be better to move this to the hidden menu items ?
|
||||
|
||||
{"", 0xff } // end of list - DO NOT delete or move this this
|
||||
@@ -349,6 +351,12 @@ const char gSubMenu_BATTYP[][12] =
|
||||
"2500mAh K1"
|
||||
};
|
||||
|
||||
const char gSubMenu_SET_NAV[][17] =
|
||||
{
|
||||
"LEFT\nRIGHT\nUV-K1",
|
||||
"UP\nDOWN\nUV-K5(8)",
|
||||
};
|
||||
|
||||
#ifndef ENABLE_FEAT_F4HWN
|
||||
const char gSubMenu_SCRAMBLER[][7] =
|
||||
{
|
||||
@@ -404,6 +412,17 @@ const char gSubMenu_SCRAMBLER[][7] =
|
||||
"CLASSIC"
|
||||
};
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
const char gSubMenu_SET_AUD[][6] =
|
||||
{
|
||||
"FLAT",
|
||||
"CLEAN",
|
||||
"MID",
|
||||
"BOOST",
|
||||
"MAX"
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
const char gSubMenu_SET_NFM[][9] =
|
||||
{
|
||||
@@ -461,9 +480,10 @@ const t_sidefunction gSubMenu_SIDEFUNCTIONS[] =
|
||||
{"MAIN ONLY", ACTION_OPT_MAINONLY},
|
||||
{"PTT", ACTION_OPT_PTT},
|
||||
{"WIDE\nNARROW", ACTION_OPT_WN},
|
||||
//#if !defined(ENABLE_SPECTRUM) || !defined(ENABLE_FMRADIO)
|
||||
{"MUTE", ACTION_OPT_MUTE},
|
||||
//#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
{"RxA", ACTION_OPT_RXA},
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
{"POWER\nHIGH", ACTION_OPT_POWER_HIGH},
|
||||
{"REMOVE\nOFFSET", ACTION_OPT_REMOVE_OFFSET},
|
||||
@@ -787,9 +807,6 @@ void UI_DisplayMenu(void)
|
||||
#endif
|
||||
case MENU_BCL:
|
||||
case MENU_BEEP:
|
||||
case MENU_S_ADD1:
|
||||
case MENU_S_ADD2:
|
||||
case MENU_S_ADD3:
|
||||
case MENU_STE:
|
||||
case MENU_D_ST:
|
||||
#ifdef ENABLE_DTMF_CALLING
|
||||
@@ -810,6 +827,7 @@ void UI_DisplayMenu(void)
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
case MENU_SET_TMR:
|
||||
case MENU_S_PRI:
|
||||
#endif
|
||||
strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]);
|
||||
break;
|
||||
@@ -817,23 +835,34 @@ void UI_DisplayMenu(void)
|
||||
case MENU_MEM_CH:
|
||||
case MENU_1_CALL:
|
||||
case MENU_DEL_CH:
|
||||
case MENU_S_PRI_CH_1:
|
||||
case MENU_S_PRI_CH_2:
|
||||
{
|
||||
const bool valid = RADIO_CheckValidChannel(gSubMenuSelection, false, 0);
|
||||
|
||||
UI_GenerateChannelStringEx(String, valid, gSubMenuSelection);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
|
||||
|
||||
if (valid && !gAskForConfirmation)
|
||||
{ // show the frequency so that the user knows the channels frequency
|
||||
const uint32_t frequency = SETTINGS_FetchChannelFrequency(gSubMenuSelection);
|
||||
sprintf(String, "%u.%05u", frequency / 100000, frequency % 100000);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 4, 8);
|
||||
if(gSubMenuSelection == MR_CHANNELS_MAX)
|
||||
{
|
||||
UI_PrintString("None", menu_item_x1, menu_item_x2, 2, 8);
|
||||
already_printed = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool valid = RADIO_CheckValidChannel(gSubMenuSelection, false, 0);
|
||||
|
||||
SETTINGS_FetchChannelName(String, gSubMenuSelection);
|
||||
UI_PrintString(String[0] ? String : "--", menu_item_x1, menu_item_x2, 2, 8);
|
||||
already_printed = true;
|
||||
break;
|
||||
UI_GenerateChannelStringEx(String, valid, gSubMenuSelection);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
|
||||
|
||||
if (valid && !gAskForConfirmation)
|
||||
{ // show the frequency so that the user knows the channels frequency
|
||||
const uint32_t frequency = SETTINGS_FetchChannelFrequency(gSubMenuSelection);
|
||||
sprintf(String, "%u.%05u", frequency / 100000, frequency % 100000);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 4, 8);
|
||||
}
|
||||
|
||||
SETTINGS_FetchChannelName(String, gSubMenuSelection);
|
||||
UI_PrintString(String[0] ? String : "--", menu_item_x1, menu_item_x2, 2, 8);
|
||||
already_printed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case MENU_MEM_NAME:
|
||||
@@ -935,15 +964,20 @@ void UI_DisplayMenu(void)
|
||||
sprintf(String, gSubMenuSelection == 0 ? gSubMenu_OFF_ON[0] : "%u*100ms", gSubMenuSelection);
|
||||
break;
|
||||
|
||||
case MENU_S_LIST:
|
||||
if (gSubMenuSelection == 0)
|
||||
strcpy(String, "LIST [0]\nNO LIST");
|
||||
else if (gSubMenuSelection < 4)
|
||||
sprintf(String, "LIST [%u]", gSubMenuSelection);
|
||||
else if (gSubMenuSelection == 4)
|
||||
strcpy(String, "LISTS\n[1, 2, 3]");
|
||||
else if (gSubMenuSelection == 5)
|
||||
case MENU_LIST_CH:
|
||||
if (gSubMenuSelection == MR_CHANNELS_LIST + 1)
|
||||
strcpy(String, "ALL");
|
||||
else if (gSubMenuSelection == 0)
|
||||
strcpy(String, "OFF");
|
||||
else
|
||||
sprintf(String, "%u", gSubMenuSelection);
|
||||
break;
|
||||
|
||||
case MENU_S_LIST:
|
||||
if (gSubMenuSelection == MR_CHANNELS_LIST + 1)
|
||||
strcpy(String, "ALL");
|
||||
else
|
||||
sprintf(String, "%u", gSubMenuSelection);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_ALARM
|
||||
@@ -1058,6 +1092,10 @@ void UI_DisplayMenu(void)
|
||||
strcpy(String, gSubMenu_BATTYP[gSubMenuSelection]);
|
||||
break;
|
||||
|
||||
case MENU_SET_NAV:
|
||||
strcpy(String, gSubMenu_SET_NAV[gSubMenuSelection]);
|
||||
break;
|
||||
|
||||
case MENU_F1SHRT:
|
||||
case MENU_F1LONG:
|
||||
case MENU_F2SHRT:
|
||||
@@ -1138,6 +1176,12 @@ void UI_DisplayMenu(void)
|
||||
strcpy(String, gSubMenu_SET_MET[gSubMenuSelection]); // Same as SET_MET
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
case MENU_SET_AUD:
|
||||
strcpy(String, gSubMenu_SET_AUD[gSubMenuSelection]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_NARROWER
|
||||
case MENU_SET_NFM:
|
||||
strcpy(String, gSubMenu_SET_NFM[gSubMenuSelection]);
|
||||
@@ -1260,55 +1304,9 @@ void UI_DisplayMenu(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_SLIST1 || UI_MENU_GetCurrentMenuId() == MENU_SLIST2 || UI_MENU_GetCurrentMenuId() == MENU_SLIST3)
|
||||
if (UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_1 || UI_MENU_GetCurrentMenuId() == MENU_S_PRI_CH_2)
|
||||
{
|
||||
i = UI_MENU_GetCurrentMenuId() - MENU_SLIST1;
|
||||
|
||||
char *pPrintStr = String;
|
||||
|
||||
if (gSubMenuSelection < 0) {
|
||||
pPrintStr = "NULL";
|
||||
} else {
|
||||
UI_GenerateChannelStringEx(String, true, gSubMenuSelection);
|
||||
pPrintStr = String;
|
||||
}
|
||||
|
||||
// channel number
|
||||
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 0, 8);
|
||||
|
||||
SETTINGS_FetchChannelName(String, gSubMenuSelection);
|
||||
pPrintStr = String[0] ? String : "--";
|
||||
|
||||
// channel name and scan-list
|
||||
if (gSubMenuSelection < 0 || !gEeprom.SCAN_LIST_ENABLED[i]) {
|
||||
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 2, 8);
|
||||
} else {
|
||||
/*
|
||||
UI_PrintStringSmallNormal(pPrintStr, menu_item_x1, menu_item_x2, 2);
|
||||
|
||||
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH1[i])) {
|
||||
sprintf(String, "PRI%d:%u", 1, gEeprom.SCANLIST_PRIORITY_CH1[i] + 1);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 3, 8);
|
||||
}
|
||||
|
||||
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH2[i])) {
|
||||
sprintf(String, "PRI%d:%u", 2, gEeprom.SCANLIST_PRIORITY_CH2[i] + 1);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, 5, 8);
|
||||
}
|
||||
*/
|
||||
|
||||
UI_PrintStringSmallNormal(pPrintStr, menu_item_x1, menu_item_x2, 2);
|
||||
|
||||
for (uint8_t pri = 1; pri <= 2; pri++) {
|
||||
uint8_t channel = (pri == 1) ? gEeprom.SCANLIST_PRIORITY_CH1[i] : gEeprom.SCANLIST_PRIORITY_CH2[i];
|
||||
|
||||
if (IS_MR_CHANNEL(channel)) {
|
||||
sprintf(String, "PRI%d:%u", pri, channel + 1);
|
||||
UI_PrintString(String, menu_item_x1, menu_item_x2, pri * 2 + 1, 8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ((UI_MENU_GetCurrentMenuId() == MENU_R_CTCS || UI_MENU_GetCurrentMenuId() == MENU_R_DCS) && gCssBackgroundScan)
|
||||
|
||||
+11
-6
@@ -65,9 +65,7 @@ enum
|
||||
#endif
|
||||
MENU_SC_REV,
|
||||
MENU_AUTOLK,
|
||||
MENU_S_ADD1,
|
||||
MENU_S_ADD2,
|
||||
MENU_S_ADD3,
|
||||
MENU_LIST_CH,
|
||||
MENU_STE,
|
||||
MENU_RP_STE,
|
||||
MENU_MIC,
|
||||
@@ -75,9 +73,9 @@ enum
|
||||
MENU_COMPAND,
|
||||
MENU_1_CALL,
|
||||
MENU_S_LIST,
|
||||
MENU_SLIST1,
|
||||
MENU_SLIST2,
|
||||
MENU_SLIST3,
|
||||
MENU_S_PRI,
|
||||
MENU_S_PRI_CH_1,
|
||||
MENU_S_PRI_CH_2,
|
||||
#ifdef ENABLE_ALARM
|
||||
MENU_AL_MOD,
|
||||
#endif
|
||||
@@ -151,6 +149,10 @@ enum
|
||||
#ifdef ENABLE_NOAA
|
||||
MENU_NOAA_S,
|
||||
#endif
|
||||
MENU_SET_NAV,
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
MENU_SET_AUD,
|
||||
#endif
|
||||
#endif
|
||||
MENU_BATCAL, // battery voltage calibration
|
||||
MENU_F1SHRT,
|
||||
@@ -195,6 +197,9 @@ extern const char gSubMenu_D_RSP[4][11];
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
extern const char gSubMenu_SET_KEY[][9];
|
||||
#endif
|
||||
#ifdef ENABLE_FEAT_F4HWN_AUDIO
|
||||
extern const char gSubMenu_SET_AUD[5][6];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern const char* const gSubMenu_PTT_ID[5];
|
||||
|
||||
+43
-28
@@ -94,25 +94,37 @@ void UI_DisplayStatus()
|
||||
{ // SCAN indicator
|
||||
if (gScanStateDir != SCAN_OFF || SCANNER_IsScanning()) {
|
||||
if (IS_MR_CHANNEL(gNextMrChannel) && !SCANNER_IsScanning()) { // channel mode
|
||||
switch(gEeprom.SCAN_LIST_DEFAULT) {
|
||||
case 0:
|
||||
memcpy(line + 0, BITMAP_ScanList0, sizeof(BITMAP_ScanList0));
|
||||
break;
|
||||
case 1:
|
||||
memcpy(line + 0, BITMAP_ScanList1, sizeof(BITMAP_ScanList1));
|
||||
break;
|
||||
case 2:
|
||||
memcpy(line + 0, BITMAP_ScanList2, sizeof(BITMAP_ScanList2));
|
||||
break;
|
||||
case 3:
|
||||
memcpy(line + 0, BITMAP_ScanList3, sizeof(BITMAP_ScanList3));
|
||||
break;
|
||||
case 4:
|
||||
memcpy(line + 0, BITMAP_ScanList123, sizeof(BITMAP_ScanList123));
|
||||
break;
|
||||
case 5:
|
||||
memcpy(line + 0, BITMAP_ScanListAll, sizeof(BITMAP_ScanListAll));
|
||||
break;
|
||||
|
||||
uint8_t end = 0;
|
||||
|
||||
if(gEeprom.SCAN_LIST_DEFAULT == MR_CHANNELS_LIST + 1)
|
||||
{
|
||||
if(gEeprom.SCAN_LIST_ENABLED==1) {
|
||||
sprintf(str, "%s+", "ALL");
|
||||
end = 19;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(str, "%s", "ALL");
|
||||
end = 15;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(gEeprom.SCAN_LIST_ENABLED==1) {
|
||||
sprintf(str, "%02d+", gEeprom.SCAN_LIST_DEFAULT);
|
||||
end = 15;
|
||||
}
|
||||
else {
|
||||
sprintf(str, "%02d", gEeprom.SCAN_LIST_DEFAULT);
|
||||
end = 11;
|
||||
}
|
||||
}
|
||||
|
||||
GUI_DisplaySmallest(str, 2, 1, true, true);
|
||||
for (uint8_t x = 0; x < end; x++)
|
||||
{
|
||||
gStatusLine[x] ^= 0x7F;
|
||||
}
|
||||
}
|
||||
else { // frequency mode
|
||||
@@ -174,7 +186,8 @@ void UI_DisplayStatus()
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(line + x + 2, gFontMO, sizeof(gFontMO));
|
||||
if(!gAirCopyBootMode)
|
||||
memcpy(line + x + 2, gFontMO, sizeof(gFontMO));
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
|
||||
}
|
||||
@@ -195,14 +208,16 @@ void UI_DisplayStatus()
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN
|
||||
// PTT indicator
|
||||
if (gSetting_set_ptt_session) {
|
||||
memcpy(line + x, gFontPttOnePush, sizeof(gFontPttOnePush));
|
||||
x1 = x + sizeof(gFontPttOnePush) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(line + x, gFontPttClassic, sizeof(gFontPttClassic));
|
||||
x1 = x + sizeof(gFontPttClassic) + 1;
|
||||
if(!gAirCopyBootMode) {
|
||||
if (gSetting_set_ptt_session) {
|
||||
memcpy(line + x, gFontPttOnePush, sizeof(gFontPttOnePush));
|
||||
x1 = x + sizeof(gFontPttOnePush) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(line + x, gFontPttClassic, sizeof(gFontPttClassic));
|
||||
x1 = x + sizeof(gFontPttClassic) + 1;
|
||||
}
|
||||
}
|
||||
x += sizeof(gFontPttClassic) + 3;
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -76,9 +76,9 @@ void UI_DisplayWelcome(void)
|
||||
memset(WelcomeString1, 0, sizeof(WelcomeString1));
|
||||
|
||||
// 0x0EB0
|
||||
PY25Q16_ReadBuffer(0x007020, WelcomeString0, 16);
|
||||
PY25Q16_ReadBuffer(0x00A0C8, WelcomeString0, 16);
|
||||
// 0x0EC0
|
||||
PY25Q16_ReadBuffer(0x007030, WelcomeString1, 16);
|
||||
PY25Q16_ReadBuffer(0x00A0D8, WelcomeString1, 16);
|
||||
|
||||
sprintf(WelcomeString2, "%u.%02uV %u%%",
|
||||
gBatteryVoltageAverage / 100,
|
||||
|
||||
@@ -70,6 +70,10 @@ target_link_libraries(${EXE_NAME} Core App)
|
||||
target_compile_definitions(${EXE_NAME} PRIVATE $<$<CONFIG:Debug>:DEBUG>)
|
||||
target_link_libraries(${EXE_NAME} ${TOOLCHAIN_LINK_LIBRARIES})
|
||||
|
||||
if(ENABLE_LTO)
|
||||
target_compile_options(${EXE_NAME} PRIVATE -flto=auto)
|
||||
endif()
|
||||
|
||||
# Generate map file
|
||||
target_link_options(${EXE_NAME} PRIVATE "-Wl,-Map=${EXE_NAME}.map")
|
||||
|
||||
|
||||
+6
-5
@@ -9,6 +9,7 @@
|
||||
"toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"ENABLE_LTO": false,
|
||||
"ENABLE_FMRADIO": false,
|
||||
"ENABLE_UART": true,
|
||||
"ENABLE_USB": true,
|
||||
@@ -34,7 +35,6 @@
|
||||
"ENABLE_SHOW_CHARGE_LEVEL": false,
|
||||
"ENABLE_REVERSE_BAT_SYMBOL": false,
|
||||
"ENABLE_NO_CODE_SCAN_TIMEOUT": true,
|
||||
"ENABLE_AM_FIX": false,
|
||||
"ENABLE_SQUELCH_MORE_SENSITIVE": true,
|
||||
"ENABLE_FASTER_CHANNEL_SCAN": true,
|
||||
"ENABLE_RSSI_BAR": true,
|
||||
@@ -59,18 +59,17 @@
|
||||
"ENABLE_FEAT_F4HWN_CTR": true,
|
||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": false,
|
||||
"ENABLE_FEAT_F4HWN_VOL": false,
|
||||
"ENABLE_FEAT_F4HWN_RESET_CHANNEL": false,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO": false,
|
||||
"ENABLE_FEAT_F4HWN_RESET_VFO": true,
|
||||
"ENABLE_FEAT_F4HWN_PMR": false,
|
||||
"ENABLE_FEAT_F4HWN_GMRS_FRS_MURS": false,
|
||||
"ENABLE_FEAT_F4HWN_CA": true,
|
||||
"ENABLE_FEAT_F4HWN_DEBUG": false,
|
||||
"ENABLE_AM_FIX_SHOW_DATA": false,
|
||||
"ENABLE_AGC_SHOW_DATA": false,
|
||||
"ENABLE_UART_RW_BK_REGS": false,
|
||||
"ENABLE_NAVIG_LEFT_RIGHT": true,
|
||||
"ENABLE_SWD": false,
|
||||
"VERSION_STRING_1": "v0.22",
|
||||
"VERSION_STRING_2": "v4.3.2"
|
||||
"VERSION_STRING_2": "v5.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -187,6 +186,8 @@
|
||||
"ENABLE_FEAT_F4HWN_PMR": true,
|
||||
"ENABLE_FEAT_F4HWN_GMRS_FRS_MURS": true,
|
||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
||||
"ENABLE_FEAT_F4HWN_VOL": true,
|
||||
"ENABLE_FEAT_F4HWN_AUDIO": true,
|
||||
"ENABLE_SWD": true,
|
||||
"EDITION_STRING": "Fusion",
|
||||
"TARGET": "f4hwn.fusion"
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ FROM mcr.microsoft.com/devcontainers/python:3.10-bookworm
|
||||
# ---------------------------------------------
|
||||
# Base build tools
|
||||
# ---------------------------------------------
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
RUN rm -f /etc/apt/sources.list.d/yarn.list && \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential cmake ninja-build python3 curl xz-utils ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ FROM mcr.microsoft.com/devcontainers/python:3.10-bookworm
|
||||
# ---------------------------------------------
|
||||
# Base build tools
|
||||
# ---------------------------------------------
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
RUN rm -f /etc/apt/sources.list.d/yarn.list && \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential cmake ninja-build python3 curl xz-utils ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ Anyway, have fun.
|
||||
|
||||
# Donations
|
||||
|
||||
Special thanks to Jean-Cyrille F6IWW (2 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (3 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF, Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Meinhard Frank Günther, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB, Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno and Daniel OK2VLK for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar, Zhuo BG7SGA and Jamie M0JLB for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -31,13 +31,16 @@ fi
|
||||
# ---------------------------------------------
|
||||
# Build the Docker image (only needed once)
|
||||
# ---------------------------------------------
|
||||
docker build -t "$IMAGE" .
|
||||
if [[ "$(docker images -q $IMAGE)" == "" ]]; then
|
||||
echo "Building Docker image..."
|
||||
docker build -t "$IMAGE" .
|
||||
fi
|
||||
|
||||
# ---------------------------------------------
|
||||
# Clean existing CMake cache to ensure toolchain reload
|
||||
# ---------------------------------------------
|
||||
rm -rf build
|
||||
|
||||
export MSYS_NO_PATHCONV=1
|
||||
# ---------------------------------------------
|
||||
# Function to build one preset
|
||||
# ---------------------------------------------
|
||||
@@ -46,7 +49,9 @@ build_preset() {
|
||||
echo ""
|
||||
echo "=== 🚀 Building preset: ${preset} ==="
|
||||
echo "---------------------------------------------"
|
||||
docker run --rm -it -v "$PWD":/src -w /src "$IMAGE" \
|
||||
docker run --rm \
|
||||
-u $(id -u):$(id -g) \
|
||||
-it -v "$PWD":/src -w /src "$IMAGE" \
|
||||
bash -c "which arm-none-eabi-gcc && arm-none-eabi-gcc --version && \
|
||||
cmake --preset ${preset} ${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"} && \
|
||||
cmake --build --preset ${preset} -j"
|
||||
|
||||
Reference in new issue
Block a user