Increase FM broadcast channels, memory channels and scan lists

- Increase FM broadcast memory channels from 20 to 48
- Increase memory channels from 200 to 768
- Increase scan lists from 3 to 10
- Update internal limits, mappings and related logic accordingly
- Minor cleanups and adjustments related to these changes
This commit is contained in:
Armel FAUVEAU committed 2026-01-12 00:46:52 +01:00
1 parent 8bb2915446
commit e5ca2265e4
33 files changed
+1018 -794

No files matched your search

+1 -1
View File
@@ -199,7 +199,7 @@ 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_RESET_VFO)
enable_feature(ENABLE_FEAT_F4HWN_PMR)
enable_feature(ENABLE_FEAT_F4HWN_GMRS_FRS_MURS)
enable_feature(ENABLE_FEAT_F4HWN_CA)
+2 -1
View File
@@ -230,7 +230,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;
gEeprom.SCAN_LIST_DEFAULT = ((gEeprom.SCAN_LIST_DEFAULT + 1) % (MR_CHANNELS_LIST + 2)) ?: 1;
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
SETTINGS_WriteCurrentState();
#endif
+235 -37
View File
@@ -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,7 @@
#include "ui/helper.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
#include <stddef.h>
#ifdef ENABLE_FEAT_F4HWN_SCREENSHOT
#include "screenshot.h"
@@ -45,14 +42,92 @@ uint8_t gAirCopyIsSendMode;
uint16_t g_FSK_Buffer[36];
static uint16_t AIRCOPY_BlockToOffset(const uint16_t block)
{
if (block < AIRCOPY_MAIN_BLOCKS) {
return (uint16_t)(block * AIRCOPY_BLOCK_SIZE);
}
// ============================================================================
// Transfer Maps Definition
// ============================================================================
const uint16_t extraBlock = (uint16_t)(block - AIRCOPY_MAIN_BLOCKS);
return (uint16_t)(AIRCOPY_EXTRA_START + (extraBlock * AIRCOPY_BLOCK_SIZE));
#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, 0xA160, 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()
@@ -66,9 +141,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;
@@ -78,9 +188,36 @@ bool AIRCOPY_SendMessage(void)
return 1;
}
g_FSK_Buffer[1] = AIRCOPY_BlockToOffset(gAirCopyBlockNumber);
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);
@@ -88,20 +225,14 @@ bool AIRCOPY_SendMessage(void)
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
}
if (++gAirCopyBlockNumber >= AIRCOPY_TOTAL_BLOCKS) {
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;
@@ -118,10 +249,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;
}
@@ -132,36 +266,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();
const bool in_main = (Offset < AIRCOPY_MAIN_END);
const bool in_extra = (Offset >= AIRCOPY_EXTRA_START && Offset < AIRCOPY_EXTRA_END);
// 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 (!in_main && !in_extra) {
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 == AIRCOPY_EXTRA_END) {
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) {
@@ -258,6 +423,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) {
@@ -279,9 +463,23 @@ void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
case KEY_EXIT:
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
break;
case KEY_UP:
#ifdef ENABLE_NAVIG_LEFT_RIGHT
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
#else
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
#endif
break;
case KEY_DOWN:
#ifdef ENABLE_NAVIG_LEFT_RIGHT
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
#else
AIRCOPY_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
#endif
break;
default:
break;
}
}
#endif
#endif
+69 -15
View File
@@ -21,24 +21,73 @@
#include "driver/keyboard.h"
// Extended AirCopy: after 0x0000..0x1E00, also send 0x2000..0x2080 (2 blocks)
#define AIRCOPY_MAIN_END 0x1E00u
#define AIRCOPY_EXTRA_START 0x2000u
#define AIRCOPY_EXTRA_END 0x2080u
#define AIRCOPY_BLOCK_SIZE 0x0040u // 64 bytes
#define AIRCOPY_MAIN_BLOCKS (AIRCOPY_MAIN_END / AIRCOPY_BLOCK_SIZE) // 0x78
#define AIRCOPY_EXTRA_BLOCKS ((AIRCOPY_EXTRA_END - AIRCOPY_EXTRA_START) / AIRCOPY_BLOCK_SIZE) // 2
#define AIRCOPY_TOTAL_BLOCKS (AIRCOPY_MAIN_BLOCKS + AIRCOPY_EXTRA_BLOCKS)
#define AIRCOPY_BAR_WIDTH 120 // Visible width of the progress gauge for UI
// ============================================================================
// General definitions
// ============================================================================
enum AIRCOPY_State_t
{
#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;
@@ -47,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
+9 -9
View File
@@ -249,12 +249,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[0] : 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 +327,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
View File
@@ -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
+23 -15
View File
@@ -63,20 +63,21 @@ static void toggle_chan_scanlist(void)
return;
}
ChannelAttributes_t *att = &gMR_ChannelAttributes[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;
if (scanlist > MR_CHANNELS_LIST + 1)
scanlist = 0;
gTxVfo->SCANLIST1_PARTICIPATION = (scanTmp >> 0) & 0x01;
gTxVfo->SCANLIST2_PARTICIPATION = (scanTmp >> 1) & 0x01;
gTxVfo->SCANLIST3_PARTICIPATION = (scanTmp >> 2) & 0x01;
gTxVfo->SCANLIST_PARTICIPATION = scanlist;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true);
@@ -348,8 +349,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;
@@ -433,7 +434,13 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
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();
@@ -673,12 +680,13 @@ 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 = &gMR_ChannelAttributes[lastFoundFrqOrChan];
att->exclude = true;
gVfoConfigureMode = VFO_CONFIGURE;
gFlagResetVfos = true;
@@ -855,7 +863,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 +893,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 +909,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;
+87 -60
View File
@@ -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
@@ -234,9 +235,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 +255,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 +298,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 +314,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
@@ -583,6 +586,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 +672,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 +715,10 @@ void MENU_AcceptSetting(void)
gEeprom.SCAN_LIST_DEFAULT = gSubMenuSelection;
break;
case MENU_S_PRI:
gEeprom.SCAN_LIST_ENABLED[0] = gSubMenuSelection;
break;
#ifdef ENABLE_ALARM
case MENU_AL_MOD:
gEeprom.ALARM_MODE = gSubMenuSelection;
@@ -877,11 +878,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);
@@ -1163,16 +1164,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 +1198,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[0];
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
@@ -1524,6 +1523,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 +1843,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 +1926,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)
+3 -3
View File
@@ -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
-103
View File
@@ -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,
-7
View File
@@ -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];
+1 -1
View File
@@ -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)
+26 -23
View File
@@ -38,29 +38,32 @@ 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, 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(0x003000, 0x2000, 0x2080), //
_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, 0x00A160), // 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
_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);
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+6 -5
View File
@@ -131,7 +131,7 @@ enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
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 +139,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;
@@ -164,7 +166,6 @@ uint16_t gEEPROM_1F8A;
uint16_t gEEPROM_1F8C;
ChannelAttributes_t gMR_ChannelAttributes[FREQ_CHANNEL_LAST + 1];
bool gMR_ChannelExclude[FREQ_CHANNEL_LAST + 1];
volatile uint16_t gBatterySaveCountdown_10ms = battery_save_count_10ms;
@@ -234,7 +235,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 +263,7 @@ bool g_SquelchLost;
volatile uint16_t gFlashLightBlinkCounter;
bool gFlagEndTransmission;
uint8_t gNextMrChannel;
uint16_t gNextMrChannel;
ReceptionMode_t gRxReceptionMode;
bool gRxVfoIsActive;
@@ -280,7 +281,7 @@ uint8_t gFSKWriteIndex;
#ifdef ENABLE_NOAA
bool gIsNoaaMode;
uint8_t gNoaaChannel;
uint16_t gNoaaChannel;
#endif
bool gUpdateDisplay;
+24 -18
View File
@@ -36,20 +36,24 @@
#define SWAP(a, b) ({ __typeof__ (a) _c = (a); a = b; b = _c; })
#endif
#define FM_CHANNELS_MAX 64
#define FM_CHANNELS_MAX 48
#define MR_CHANNELS_MAX 768
#define MR_CHANNELS_LIST 9
#define MENU_ITEMS 67
#define IS_MR_CHANNEL(x) ((x) <= MR_CHANNEL_LAST)
#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
};
@@ -186,7 +190,7 @@ extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
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;
@@ -194,6 +198,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;
@@ -221,18 +227,18 @@ 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];
extern ChannelAttributes_t gMR_ChannelAttributes[MR_CHANNELS_MAX + 7];
extern volatile uint16_t gBatterySaveCountdown_10ms;
@@ -307,7 +313,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;
@@ -338,7 +344,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
+21 -57
View File
@@ -61,43 +61,17 @@ bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanL
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)
return false;
if (!checkScanList || scanList > 4)
//if (!checkScanList || scanList > 4)
if (!checkScanList || scanList > MR_CHANNELS_LIST)
return true;
/*
if(scanList == 0 && (att.scanlist1 == 1 || att.scanlist2 == 1 || att.scanlist3 == 1))
{
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))) {
if ((scanList == 0) || (scanList != att.scanlist)) {
return false;
}
@@ -105,16 +79,16 @@ bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanL
// 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];
const uint16_t PriorityCh1 = gEeprom.SCANLIST_PRIORITY_CH[0];
const uint16_t PriorityCh2 = gEeprom.SCANLIST_PRIORITY_CH[1];
return PriorityCh1 != channel && PriorityCh2 != channel;
}
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 +99,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 +140,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 +160,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];
}
@@ -202,13 +174,13 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
channel = FREQ_CHANNEL_LAST - 1;
ChannelAttributes_t att = gMR_ChannelAttributes[channel];
if (att.__val == 0xFF) { // invalid/unused 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;
}
@@ -218,33 +190,25 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
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))
{
+5 -7
View File
@@ -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
@@ -151,8 +149,8 @@ extern DCS_CodeType_t gCurrentCodeType;
extern VfoState_t VfoState[2];
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);
+47 -21
View File
@@ -18,16 +18,20 @@
#include "driver/st7565.h"
#include "screenshot.h"
#include "misc.h"
#include <string.h>
// RAM optimization: Only keep previousFrame static (1024 bytes)
// Build currentFrame on-the-fly and send delta blocks immediately
// 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;
@@ -47,14 +51,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 +72,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,37 +81,42 @@ 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 = &currentFrame[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;
UART_Send(&versionMarker, 1);
// ==== Send header ====
uint8_t header[5] = {
0xAA, 0x55, 0x02,
(uint8_t)(deltaLen >> 8),
@@ -115,7 +124,24 @@ void getScreenShot(bool force)
};
UART_Send(header, 5);
UART_Send(deltaFrame, deltaLen);
// ==== 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);
UART_Send(chunk, 9);
// Update previousFrame for next comparison
memcpy(prev, cur, 8);
}
uint8_t end = 0x0A;
UART_Send(&end, 1);
}
+194 -200
View File
@@ -28,23 +28,13 @@
#include "settings.h"
#include "ui/menu.h"
#ifdef ENABLE_FEAT_F4HWN_RESET_CHANNEL
static const uint32_t gDefaultFrequencyTable[] =
{
14550000, //
43350000, //
44608125, //
12150000, //
};
#endif
EEPROM_Config_t gEeprom = { 0 };
void SETTINGS_InitEEPROM(void)
{
uint8_t Data[16] = {0};
// 0E70..0E77
PY25Q16_ReadBuffer(0x004000, Data, 8);
PY25Q16_ReadBuffer(0x00A000, Data, 8);
gEeprom.CHAN_1_CALL = IS_MR_CHANNEL(Data[0]) ? Data[0] : MR_CHANNEL_FIRST;
gEeprom.SQUELCH_LEVEL = (Data[1] < 10) ? Data[1] : 1;
gEeprom.TX_TIMEOUT_TIMER = (Data[2] > 4 && Data[2] < 180) ? Data[2] : 11;
@@ -65,7 +55,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
@@ -86,13 +76,14 @@ void SETTINGS_InitEEPROM(void)
#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_LIST = (Data[7] >> 4) & 0x0F;
#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;
@@ -103,6 +94,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
@@ -114,7 +123,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;
@@ -127,12 +136,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;
@@ -149,12 +158,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
@@ -170,7 +179,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
@@ -180,7 +189,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
@@ -194,7 +203,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
@@ -202,7 +211,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 {
@@ -211,7 +220,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 {
@@ -219,7 +228,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 {
@@ -228,7 +237,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 {
@@ -236,7 +245,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 {
@@ -244,8 +253,8 @@ 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);
gEeprom.SCAN_LIST_DEFAULT = (Data[0] <= (MR_CHANNELS_LIST + 1)) ? Data[0] : 0; // we now have 'all' channel scan option
// Fake data
/*
@@ -253,14 +262,14 @@ void SETTINGS_InitEEPROM(void)
gEeprom.SCAN_LIST_ENABLED[1] = 0;
gEeprom.SCAN_LIST_ENABLED[2] = 0;
gEeprom.SCANLIST_PRIORITY_CH1[0] = 0;
gEeprom.SCANLIST_PRIORITY_CH2[0] = 2;
gEeprom.SCANLIST_PRIORITY_CH[0] = 0;
gEeprom.SCANLIST_PRIORITY_CH[1] = 2;
gEeprom.SCANLIST_PRIORITY_CH1[1] = 14;
gEeprom.SCANLIST_PRIORITY_CH2[1] = 15;
gEeprom.SCANLIST_PRIORITY_CH[2] = 14;
gEeprom.SCANLIST_PRIORITY_CH[3] = 15;
gEeprom.SCANLIST_PRIORITY_CH1[2] = 40;
gEeprom.SCANLIST_PRIORITY_CH2[2] = 41;
gEeprom.SCANLIST_PRIORITY_CH[4] = 40;
gEeprom.SCANLIST_PRIORITY_CH[5] = 41;
*/
// Fix me probably after Chirp update...
@@ -269,15 +278,15 @@ void SETTINGS_InitEEPROM(void)
gEeprom.SCAN_LIST_ENABLED[i] = (Data[1] >> i) & 1;
}
for (unsigned int i = 0; i < 3; i++)
for (uint8_t i = 0; i < 6; 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.SCANLIST_PRIORITY_CH[i] =
(uint16_t)Data[2 + (i * 2)] |
((uint16_t)Data[2 + (i * 2) + 1] << 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
@@ -316,34 +325,40 @@ void SETTINGS_InitEEPROM(void)
}
// 0D60..0E27
PY25Q16_ReadBuffer(0x002000, gMR_ChannelAttributes, sizeof(gMR_ChannelAttributes));
for(uint16_t i = 0; i < sizeof(gMR_ChannelAttributes); i++) {
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 = &gMR_ChannelAttributes[i];
if(att->__val == 0xff){
if (att->__val == 0xFFFF) {
att->__val = 0;
att->band = 0x7;
}
gMR_ChannelExclude[i] = false;
else
{
att->exclude = 0;
}
}
// 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;
@@ -460,7 +475,7 @@ void SETTINGS_LoadCalibration(void)
}
}
uint32_t SETTINGS_FetchChannelFrequency(const int channel)
uint32_t SETTINGS_FetchChannelFrequency(const uint16_t channel)
{
struct
{
@@ -473,7 +488,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;
@@ -487,7 +502,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++)
@@ -502,92 +517,57 @@ 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 (uint8_t 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;
#ifdef ENABLE_FEAT_F4HWN_RESET_VFO
Data8[7] = (1 & 0x01);
#endif
PY25Q16_WriteBuffer(0x004000, buf, sizeof(buf), true);
PY25Q16_WriteBuffer(0x00A000, Data8, sizeof(Data8), false);
// cohérence RAM
gEeprom.MENU_LOCK = 0;
}
// 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_SaveVfoIndices();
SETTINGS_SaveChannel(FREQ_CHANNEL_FIRST + BAND3_137MHz, 0, &gEeprom.VfoInfo[0], 2);
SETTINGS_SaveChannel(FREQ_CHANNEL_FIRST + BAND6_400MHz, 1, &gEeprom.VfoInfo[1], 2);
#endif
}
@@ -612,37 +592,37 @@ 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];
uint16_t Data16[8];
#ifndef ENABLE_NOAA
// 0x0E80
PY25Q16_ReadBuffer(0x005000, State, sizeof(State));
PY25Q16_ReadBuffer(0x00A010, Data16, sizeof(Data16));
#endif
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
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];
// 0x0E80
PY25Q16_WriteBuffer(0x005000, State, 8, true);
#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)
{
uint8_t *State;
@@ -713,18 +693,18 @@ void SETTINGS_SaveSettings(void)
#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.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x0F) << 4);
#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;
@@ -787,12 +767,12 @@ 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, 0x10);
// 0x0F18
State = SecBuf;
@@ -808,14 +788,16 @@ void SETTINGS_SaveSettings(void)
tmp = tmp | (1 << 2);
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];
for (uint8_t i = 0; i < 6; i++)
{
uint16_t v = gEeprom.SCANLIST_PRIORITY_CH[i];
PY25Q16_WriteBuffer(0x009000, SecBuf, 8, true);
State[2 + (i * 2) + 0] = (uint8_t)(v & 0xFF);
State[2 + (i * 2) + 1] = (uint8_t)(v >> 8);
}
PY25Q16_WriteBuffer(0x00A130, SecBuf, 0x10, false);
// ---------------------
// 0f40 - 0f48
@@ -855,7 +837,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);
// ------------------
@@ -863,7 +845,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));
@@ -904,7 +886,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
@@ -912,7 +894,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))
@@ -924,7 +906,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;
}
@@ -989,16 +971,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))
@@ -1008,20 +990,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
}
@@ -1033,10 +1017,10 @@ 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;
@@ -1056,7 +1040,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
@@ -1109,7 +1093,7 @@ 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
@@ -1117,10 +1101,11 @@ State[1] = 0
{
uint8_t State[0x10];
// 0x0E78
PY25Q16_ReadBuffer(0x004000, State, sizeof(State));
PY25Q16_ReadBuffer(0x00A000, 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);
//State[15] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x07) << 4);
State[15] = (gEeprom.VFO_OPEN & 0x01) | ((gEeprom.CURRENT_STATE & 0x07) << 1) | ((gEeprom.SCAN_LIST_DEFAULT & 0x0F) << 4);
PY25Q16_WriteBuffer(0x00A000, State, sizeof(State), false);
}
#endif
@@ -1136,32 +1121,41 @@ 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 4
#define TXLOCK_BIT 6
#define SETTINGS_ResetTxLock_BATCH 16
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; // 512 * 16 = 8192
const uint32_t BatchSize = TotalBytes / SETTINGS_ResetTxLock_BATCH; // 8192 / 16 = 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
#undef SETTINGS_ResetTxLock_BATCH
#undef CHANNEL_SIZE
#undef TXLOCK_BYTE_OFFSET
#undef TXLOCK_BIT
}
#endif
+10 -11
View File
@@ -162,11 +162,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,
@@ -215,8 +215,7 @@ typedef struct {
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];
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;
@@ -308,18 +307,18 @@ 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_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);
+44 -34
View File
@@ -70,7 +70,15 @@ void UI_DisplayAircopy(void)
memset(String, 0, sizeof(String));
percent = (gAirCopyBlockNumber * 10000) / AIRCOPY_TOTAL_BLOCKS;
// 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);
@@ -94,8 +102,24 @@ void UI_DisplayAircopy(void)
gFrameBuffer[4][125] = 0x42;
gFrameBuffer[4][126] = 0x3c;
}
// Draw memory selection
if(gAircopyState == AIRCOPY_READY)
{
doneBlocks = 0;
uint16_t doneBlocks = gAirCopyBlockNumber + gErrorsDuringAirCopy;
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
{
sprintf(String, "Settings");
}
UI_PrintString(String, 2, 127, 5, 8);
}
if (doneBlocks > 0)
{
@@ -107,46 +131,32 @@ void UI_DisplayAircopy(void)
lErrorsDuringAirCopy = gErrorsDuringAirCopy;
}
// Project real blocks onto a fixed-width progress bar
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++)
{
// Determine the range of blocks represented by this column
uint16_t block_start = (col * AIRCOPY_TOTAL_BLOCKS) / AIRCOPY_BAR_WIDTH;
uint16_t block_end = ((col + 1) * AIRCOPY_TOTAL_BLOCKS) / AIRCOPY_BAR_WIDTH;
/* Map column [0..BAR_WIDTH-1] to block [0..total-1] */
uint16_t b = (uint16_t)((col * (uint32_t)total) / AIRCOPY_BAR_WIDTH);
bool has_data = false;
bool has_error = false;
bool processed = (b < done);
bool error = processed && get_bit(crc, b);
// Scan the block range mapped to this column
for (uint16_t b = block_start; b < block_end; b++)
{
if (b < doneBlocks)
has_data = true;
if (get_bit(crc, b))
has_error = true;
}
// Render the column
if (has_error)
{
// Error blocks are rendered as empty gaps
gFrameBuffer[4][col + 4] = 0x81; // error
}
else if (has_data)
{
// Successfully transferred blocks
gFrameBuffer[4][col + 4] = 0xbd; // full block
}
if (!processed)
gFrameBuffer[4][col + 4] = 0x81; // not yet processed
else if (error)
gFrameBuffer[4][col + 4] = 0x81; // error gap (intentional hole)
else
{
// Not yet transferred
gFrameBuffer[4][col + 4] = 0x81; // empty
}
gFrameBuffer[4][col + 4] = 0xBD; // ok filled
}
}
ST7565_BlitFullScreen();
}
#endif
#endif
+1 -1
View File
@@ -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 -3
View File
@@ -27,7 +27,7 @@
#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 +44,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 +58,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 +118,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 +160,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
View File
@@ -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);
+48 -33
View File
@@ -272,10 +272,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 +289,7 @@ void DisplayRSSIBar(const bool now)
}
ST7565_BlitLine(RxLine);
}
*/
#else
const unsigned int line = 3;
#endif
@@ -778,6 +782,10 @@ void UI_DisplayMain(void)
{
RxBlink = 0;
}
if (RxBlink == 0 || RxBlink == 1) {
UI_PrintStringSmallBold("RX", 8, 0, RxLine);
}
#else
UI_PrintStringSmallBold("RX", 8, 0, line);
#endif
@@ -799,13 +807,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);
sprintf(String, "M%03u", gEeprom.ScreenChannel[vfo_num] + 1);
else
sprintf(String, "M%.3s", INPUTBOX_GetAscii()); // show the input text
UI_PrintStringSmallNormal(String, x, 0, line + 1);
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
}
else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
{ // frequency mode
@@ -843,7 +851,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 +889,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 = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if(att.exclude == false)
{
// show the scan list assigment symbols
const ChannelAttributes_t att = gMR_ChannelAttributes[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
@@ -957,7 +970,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 +983,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
{
+36 -78
View File
@@ -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
@@ -787,9 +785,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 +805,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 +813,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 +942,12 @@ void UI_DisplayMenu(void)
sprintf(String, gSubMenuSelection == 0 ? gSubMenu_OFF_ON[0] : "%u*100ms", gSubMenuSelection);
break;
case MENU_LIST_CH:
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)
if (gSubMenuSelection == MR_CHANNELS_LIST + 1)
strcpy(String, "ALL");
else
sprintf(String, "%u", gSubMenuSelection);
break;
#ifdef ENABLE_ALARM
@@ -1260,55 +1264,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)
+4 -6
View File
@@ -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
+46 -25
View File
@@ -94,26 +94,44 @@ void UI_DisplayStatus()
{ // SCAN indicator
if (gScanStateDir != SCAN_OFF || SCANNER_IsScanning()) {
if (IS_MR_CHANNEL(gNextMrChannel) && !SCANNER_IsScanning()) { // channel mode
if(gEeprom.SCAN_LIST_DEFAULT == MR_CHANNELS_LIST + 1)
{
sprintf(str, "%s", "ALL");
GUI_DisplaySmallest(str, 2, 1, true, true);
for (uint8_t x = 0; x < 15; x++)
{
gStatusLine[x] ^= 0x7F;
}
}
else
{
uint8_t end = 0;
if(gEeprom.SCAN_LIST_ENABLED[0]==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;
}
}
/*
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:
case MR_CHANNELS_LIST + 1:
memcpy(line + 0, BITMAP_ScanListAll, sizeof(BITMAP_ScanListAll));
break;
default:
sprintf(str, "%02d", gEeprom.SCAN_LIST_DEFAULT);
UI_PrintStringSmallBufferNormal(str, line + 0);
}
*/
}
else { // frequency mode
memcpy(line + x + 1, gFontS, sizeof(gFontS));
@@ -174,7 +192,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 +214,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
View File
@@ -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,
+2 -2
View File
@@ -59,7 +59,7 @@
"ENABLE_FEAT_F4HWN_CTR": true,
"ENABLE_FEAT_F4HWN_RESCUE_OPS": false,
"ENABLE_FEAT_F4HWN_VOL": false,
"ENABLE_FEAT_F4HWN_RESET_CHANNEL": true,
"ENABLE_FEAT_F4HWN_RESET_VFO": true,
"ENABLE_FEAT_F4HWN_PMR": false,
"ENABLE_FEAT_F4HWN_GMRS_FRS_MURS": false,
"ENABLE_FEAT_F4HWN_CA": true,
@@ -70,7 +70,7 @@
"ENABLE_NAVIG_LEFT_RIGHT": true,
"ENABLE_SWD": false,
"VERSION_STRING_1": "v0.22",
"VERSION_STRING_2": "v4.3.3"
"VERSION_STRING_2": "v5.0.0"
}
},
{