Improve SRAM and Flash write cycles

This commit is contained in:
Armel FAUVEAU committed 2026-01-22 02:48:19 +01:00
1 parent b9ce4934d8
commit 6b94ae4ed3
11 files changed
+436 -52

No files matched your search

+6 -1
View File
@@ -1363,6 +1363,11 @@ static void CheckKeys(void)
void APP_TimeSlice10ms(void)
{
gNextTimeslice = false;
if (gScheduleVfoSave) {
SETTINGS_SaveVfoIndicesFlush();
}
gFlashLightBlinkCounter++;
#ifdef ENABLE_AM_FIX
@@ -2187,7 +2192,7 @@ Skip:
}
if (gRequestSaveChannel > 0) { // TODO: remove the gRequestSaveChannel, why use global variable for that??
if ((!bKeyHeld && !bKeyPressed) || UI_MENU_GetCurrentMenuId())
if ((!bKeyHeld && !bKeyPressed) || (UI_MENU_GetCurrentMenuId() != 0 && gScreenToDisplay == DISPLAY_MENU))
{
SETTINGS_SaveChannel(gTxVfo->CHANNEL_SAVE, gEeprom.TX_VFO, gTxVfo, gRequestSaveChannel);
+4 -4
View File
@@ -63,7 +63,7 @@ static void toggle_chan_scanlist(void)
return;
}
ChannelAttributes_t *att = &gMR_ChannelAttributes[gTxVfo->CHANNEL_SAVE];
ChannelAttributes_t *att = MR_GetChannelAttributes(gTxVfo->CHANNEL_SAVE);
// Remove exclude
if(att->exclude == true)
@@ -389,11 +389,11 @@ void channelMoveSwitch(void) {
Channel = (Channel * 10) + gInputBox[i];
}
if ((Channel == 0) && (gInputBoxIndex != 3)) {
if ((Channel == 0) && (gInputBoxIndex != 4)) {
return;
}
if (gInputBoxIndex == 3) {
if (gInputBoxIndex == 4) {
gInputBoxIndex = 0;
gKeyInputCountdown = 1;
@@ -747,7 +747,7 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
if(FUNCTION_IsRx() || gScanPauseDelayIn_10ms > 9)
{
ChannelAttributes_t *att = &gMR_ChannelAttributes[lastFoundFrqOrChan];
ChannelAttributes_t *att = MR_GetChannelAttributes(lastFoundFrqOrChan);
att->exclude = true;
gVfoConfigureMode = VFO_CONFIGURE;
+6
View File
@@ -25,6 +25,7 @@
#include "driver/system.h"
#include "driver/systick.h"
#include "external/printf/printf.h"
#include "misc.h"
// #define DEBUG
@@ -254,6 +255,11 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
#ifdef DEBUG
printf("spi flash write: %06x %ld %d\n", Address, Size, Append);
#endif
#ifdef ENABLE_FEAT_F4HWN_DEBUG
gDebug++;
#endif
uint32_t SecIndex = Address / SECTOR_SIZE;
uint32_t SecAddr = SecIndex * SECTOR_SIZE;
uint32_t SecOffset = Address % SECTOR_SIZE;
+282 -1
View File
@@ -18,6 +18,7 @@
#include "misc.h"
#include "settings.h"
#include "driver/py25q16.h"
const uint8_t fm_radio_countdown_500ms = 2000 / 500; // 2 seconds
const uint16_t fm_play_countdown_scan_10ms = 100 / 10; // 100ms
@@ -165,7 +166,13 @@ uint16_t gEEPROM_RSSI_CALIB[7][4];
uint16_t gEEPROM_1F8A;
uint16_t gEEPROM_1F8C;
ChannelAttributes_t gMR_ChannelAttributes[FREQ_CHANNEL_LAST + 1];
//
// Cache-Based Architecture: channel attributes moved to Flash
// Cache holds only active channels in RAM (instead of all!)
//
MR_ChannelCache_t gMR_ChannelAttributes_Cache[MR_CHANNELS_CACHE_SIZE] = {0};
ChannelAttributes_t gMR_ChannelAttributes_Current = {0};
volatile uint16_t gBatterySaveCountdown_10ms = battery_save_count_10ms;
@@ -319,6 +326,10 @@ uint8_t gIsLocked = 0xFF;
uint8_t gBacklightBrightnessOld;
uint8_t gPttOnePushCounter = 0;
uint32_t gBlinkCounter = 0;
uint16_t gVfoSaveCountdown_10ms = 0;
bool gScheduleVfoSave = false;
bool gVfoStateChanged = false;
#endif
inline void FUNCTION_NOP() { ; }
@@ -348,3 +359,273 @@ unsigned long StrToUL(const char * str)
}
return ul;
}
//
// Cache-Based Channel Attributes Implementation
//
//
// This replaces the huge array (~ 2,000 bytes in RAM) with a smart cache system
// that keeps only active channels in RAM and loads others from Flash on demand.
//
// SRAM Savings: ~ 2,000 bytes (84% reduction!)
//
// Flash address where channel attributes start
// NOTE: Verify this matches your Flash layout!
#define FLASH_CHANNEL_ATTR_BASE 0x8000
// Each channel takes 2 bytes (ChannelAttributes_t is uint16_t)
#define FLASH_CHANNEL_ATTR_SIZE 2
// Cache hit/miss statistics (optional, for debugging)
#ifdef ENABLE_FEAT_F4HWN_DEBUG
static uint32_t cache_hits = 0;
static uint32_t cache_misses = 0;
#endif
//
// Internal Helper Functions
//
// Find cache entry for given channel
// Returns index if found, -1 if not found
static int MR_FindInCache(uint16_t channel_id)
{
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
if (gMR_ChannelAttributes_Cache[i].channel_id == channel_id) {
return i;
}
}
return -1;
}
// Find oldest entry in cache (for eviction - LRU)
static int MR_FindOldestCacheEntry(void)
{
int oldest_index = 0;
uint32_t oldest_time = gMR_ChannelAttributes_Cache[0].access_time;
for (int i = 1; i < MR_CHANNELS_CACHE_SIZE; i++) {
if (gMR_ChannelAttributes_Cache[i].access_time < oldest_time) {
oldest_time = gMR_ChannelAttributes_Cache[i].access_time;
oldest_index = i;
}
}
return oldest_index;
}
// Find empty cache slot
// Returns index if found, -1 if cache is full
static int MR_FindEmptyCacheSlot(void)
{
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
if (gMR_ChannelAttributes_Cache[i].channel_id == 0xFFFF) {
return i;
}
}
return -1; // Cache is full, need to evict
}
// Get current time (for LRU eviction)
static uint32_t GetCurrentTime(void)
{
// Using gBlinkCounter which increments continuously
extern uint32_t gBlinkCounter;
return gBlinkCounter;
}
//
// Public API Functions
// ════════════════════════════════════════════════════════════════════════════
// Load channel attributes from Flash
void MR_LoadChannelAttributesFromFlash(uint16_t channel_id, ChannelAttributes_t* attributes)
{
// CRITICAL: Validate channel_id
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
attributes->__val = 0;
return;
}
// Calculate Flash address
uint32_t flash_addr = FLASH_CHANNEL_ATTR_BASE + (channel_id * sizeof(ChannelAttributes_t));
// Read 2 bytes from Flash
PY25Q16_ReadBuffer(flash_addr, attributes, sizeof(ChannelAttributes_t));
}
// Save channel attributes to Flash
void MR_SaveChannelAttributesToFlash(uint16_t channel_id, const ChannelAttributes_t* attributes)
{
// CRITICAL: Validate channel_id
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
return;
}
// Calculate Flash address
uint16_t flash_addr = FLASH_CHANNEL_ATTR_BASE + (channel_id * FLASH_CHANNEL_ATTR_SIZE);
// Write 2 bytes to Flash
PY25Q16_WriteBuffer(flash_addr, attributes, sizeof(ChannelAttributes_t), false);
}
// Get channel attributes (from cache or Flash)
// This is the main function used by the rest of the code
ChannelAttributes_t* MR_GetChannelAttributes(uint16_t channel_id)
{
// Input validation
if (channel_id >= (MR_CHANNELS_MAX + 7)) {
return NULL;
}
// Check cache first (FAST PATH)
int cache_index = MR_FindInCache(channel_id);
if (cache_index >= 0) {
// CACHE HIT
#ifdef ENABLE_FEAT_F4HWN_DEBUG
cache_hits++;
#endif
// Update access time for LRU
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
return &gMR_ChannelAttributes_Cache[cache_index].attributes;
}
// CACHE MISS - Load from Flash
#ifdef ENABLE_FEAT_F4HWN_DEBUG
cache_misses++;
#endif
// Find slot for new entry
int slot = MR_FindEmptyCacheSlot();
if (slot < 0) {
// Cache is full, evict oldest entry
slot = MR_FindOldestCacheEntry();
}
// Load from Flash into cache slot
MR_LoadChannelAttributesFromFlash(channel_id, &gMR_ChannelAttributes_Cache[slot].attributes);
// Store channel_id in cache
gMR_ChannelAttributes_Cache[slot].channel_id = channel_id;
// Set access time
gMR_ChannelAttributes_Cache[slot].access_time = GetCurrentTime();
return &gMR_ChannelAttributes_Cache[slot].attributes;
}
// Set channel attributes (updates both cache and Flash)
void MR_SetChannelAttributes(uint16_t channel_id, const ChannelAttributes_t* attributes)
{
// Input validation
if (channel_id >= (MR_CHANNELS_MAX + 7) || !attributes) {
return;
}
// CRITICAL FIX: WRITE-PROTECT - Prevent Flash wear
// Before writing, check if data already exists and is identical
ChannelAttributes_t flash_version;
MR_LoadChannelAttributesFromFlash(channel_id, &flash_version);
// Compare current Flash data with new data
if (memcmp(&flash_version, attributes, sizeof(ChannelAttributes_t)) == 0) {
// But still update cache for consistency
int cache_index = MR_FindInCache(channel_id);
if (cache_index >= 0) {
gMR_ChannelAttributes_Cache[cache_index].attributes = *attributes;
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
}
return; // Early exit - no Flash write needed
}
// Data has changed - write to Flash
MR_SaveChannelAttributesToFlash(channel_id, attributes);
// Update cache if entry exists
int cache_index = MR_FindInCache(channel_id);
if (cache_index >= 0) {
// Entry in cache, update it
gMR_ChannelAttributes_Cache[cache_index].attributes = *attributes;
gMR_ChannelAttributes_Cache[cache_index].access_time = GetCurrentTime();
} else {
// Not in cache, add it
int slot = MR_FindEmptyCacheSlot();
if (slot < 0) {
// Cache full, evict oldest
slot = MR_FindOldestCacheEntry();
}
gMR_ChannelAttributes_Cache[slot].channel_id = channel_id;
gMR_ChannelAttributes_Cache[slot].attributes = *attributes;
gMR_ChannelAttributes_Cache[slot].access_time = GetCurrentTime();
}
}
// Invalidate entire cache (call after loading Flash backup)
void MR_InvalidateChannelAttributesCache(void)
{
for (int i = 0; i < MR_CHANNELS_CACHE_SIZE; i++) {
gMR_ChannelAttributes_Cache[i].channel_id = 0xFFFF; // Mark as empty
gMR_ChannelAttributes_Cache[i].access_time = 0;
}
}
// Initialize cache (call from settings.c boot sequence)
void MR_InitChannelAttributesCache(void)
{
// Clear cache
MR_InvalidateChannelAttributesCache();
// Pre-load commonly used channels (VFO A, VFO B, channel 0)
// This speeds up first access
uint16_t channels_to_preload[] = {0, 1, 2};
for (int i = 0; i < ARRAY_SIZE(channels_to_preload); i++) {
if (channels_to_preload[i] < (MR_CHANNELS_MAX + 7)) {
MR_GetChannelAttributes(channels_to_preload[i]);
}
}
}
//
// Debugging / Statistics (optional, for development)
//
#ifdef ENABLE_FEAT_F4HWN_DEBUG
uint32_t MR_GetCacheHits(void)
{
return cache_hits;
}
uint32_t MR_GetCacheMisses(void)
{
return cache_misses;
}
float MR_GetCacheHitRate(void)
{
uint32_t total = cache_hits + cache_misses;
if (total == 0) return 0.0f;
return (float)cache_hits / (float)total * 100.0f;
}
void MR_PrintCacheStats(void)
{
// This would print cache statistics (requires UART_Printf)
// Uncomment if you want debug output:
// UART_Printf("Cache Stats: Hits=%u Misses=%u Rate=%.1f%%\n",
// cache_hits, cache_misses, MR_GetCacheHitRate());
}
#endif
+59 -3
View File
@@ -37,10 +37,14 @@
#endif
#define FM_CHANNELS_MAX 48
#define MR_CHANNELS_MAX 768
#define MR_CHANNELS_MAX 1024
#define MR_CHANNELS_LIST 24
#define MENU_ITEMS 68
// CACHE-BASED OPTIMIZATION: Only keep active channels in RAM
// Full array stays in EEPROM, cache holds ~10 most-used channels
#define MR_CHANNELS_CACHE_SIZE 10
#define IS_MR_CHANNEL(x) ((x) >= MR_CHANNEL_FIRST && (x) <= MR_CHANNEL_LAST)
#define IS_FREQ_CHANNEL(x) ((x) >= FREQ_CHANNEL_FIRST && (x) <= FREQ_CHANNEL_LAST)
@@ -238,7 +242,55 @@ typedef union {
uint16_t __val;
} ChannelAttributes_t;
extern ChannelAttributes_t gMR_ChannelAttributes[MR_CHANNELS_MAX + 7];
//
// Cache-Based Architecture
//
//
// Instead of keeping all 1038 channel attributes in RAM (~ 2,000 bytes),
// we now keep only the active ones in a small cache (40 bytes).
//
// The full array remains in Flash and is loaded on-demand.
//
// SRAM Savings: ~ 2,000 bytes (84% reduction!)
//
// Cache entry structure
typedef struct {
uint16_t channel_id; // Which channel this is
ChannelAttributes_t attributes; // The actual attributes
uint32_t access_time; // For LRU eviction (optional)
} MR_ChannelCache_t;
// The cache (small, stays in RAM)
extern MR_ChannelCache_t gMR_ChannelAttributes_Cache[MR_CHANNELS_CACHE_SIZE];
// REMOVED: extern ChannelAttributes_t gMR_ChannelAttributes[MR_CHANNELS_MAX + 7];
// This now stays in Flash, not in RAM
//
// Cache Access Functions (See misc.c for implementation)
//
// Get channel attributes (from cache or Flash)
// Returns pointer to attributes, loads from Flash if not in cache
void MR_InitChannelAttributesCache(void);
ChannelAttributes_t* MR_GetChannelAttributes(uint16_t channel_id);
// Set channel attributes (updates both cache and Flasf)
void MR_SetChannelAttributes(uint16_t channel_id, const ChannelAttributes_t* attributes);
// Invalidate cache (on Flash clear)
void MR_InvalidateChannelAttributesCache(void);
// Load channel attributes from Flash directly (internal use)
void MR_LoadChannelAttributesFromFlash(uint16_t channel_id, ChannelAttributes_t* attributes);
// Save channel attributes to Flash directly (internal use)
void MR_SaveChannelAttributesToFlash(uint16_t channel_id, const ChannelAttributes_t* attributes);
extern ChannelAttributes_t gMR_ChannelAttributes_Current; // Current VFO attributes (for speed)
extern volatile uint16_t gBatterySaveCountdown_10ms;
@@ -395,6 +447,10 @@ extern volatile uint8_t boot_counter_10ms;
extern uint8_t gBacklightBrightnessOld;
extern uint8_t gPttOnePushCounter;
extern uint32_t gBlinkCounter;
extern uint16_t gVfoSaveCountdown_10ms;
extern bool gScheduleVfoSave;
extern bool gVfoStateChanged;
#endif
int32_t NUMBER_AddWithWraparound(int32_t Base, int32_t Add, int32_t LowerLimit, int32_t UpperLimit);
@@ -404,4 +460,4 @@ void FUNCTION_NOP();
static inline bool SerialConfigInProgress() { return gSerialConfigCountDown_500ms != 0; }
#endif
#endif
+12 -12
View File
@@ -56,8 +56,8 @@ const char gModulationStr[MODULATION_UKNOWN][4] = {
bool RADIO_CheckValidList(uint8_t scanList)
{
for (uint16_t i = 0; IS_MR_CHANNEL(i); i++) {
const ChannelAttributes_t att = gMR_ChannelAttributes[i];
if(att.scanlist == scanList && att.exclude == false)
const ChannelAttributes_t* att = MR_GetChannelAttributes(i);
if(att->scanlist == scanList && att->exclude == false)
{
return true;
}
@@ -67,18 +67,18 @@ bool RADIO_CheckValidList(uint8_t scanList)
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList)
{
const ChannelAttributes_t att = gMR_ChannelAttributes[channel];
const ChannelAttributes_t* att = MR_GetChannelAttributes(channel);
// return true if the channel appears valid
if (!IS_MR_CHANNEL(channel))
return false;
if (checkScanList && att.exclude == true)
if (checkScanList && att->exclude == true)
return false;
if (att.band > BAND7_470MHz)
if (att->band > BAND7_470MHz)
return false;
if (!checkScanList || (scanList > MR_CHANNELS_LIST && att.scanlist != 0))
if (!checkScanList || (scanList > MR_CHANNELS_LIST && att->scanlist != 0))
return true;
if ((scanList == 0) || (scanList != att.scanlist)) {
if ((scanList == 0) || (scanList != att->scanlist)) {
return false;
}
@@ -183,8 +183,8 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
else
channel = FREQ_CHANNEL_LAST - 1;
ChannelAttributes_t att = gMR_ChannelAttributes[channel];
if (att.__val == 0xFFFF) { // invalid/unused channel
ChannelAttributes_t* att = MR_GetChannelAttributes(channel);
if (att->__val == 0xFFFF) { // invalid/unused channel
if (IS_MR_CHANNEL(channel)) {
channel = gEeprom.FreqChannel[VFO];
gEeprom.ScreenChannel[VFO] = channel;
@@ -195,7 +195,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
return;
}
uint8_t band = att.band;
uint8_t band = att->band;
if (band > BAND7_470MHz) {
band = BAND6_400MHz;
}
@@ -203,7 +203,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
uint8_t bParticipation;
if (IS_MR_CHANNEL(channel)) {
bParticipation = att.scanlist;
bParticipation = att->scanlist;
}
else {
band = channel - FREQ_CHANNEL_FIRST;
@@ -398,7 +398,7 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
pConfig->Frequency = 43300000;
}
pVfo->Compander = att.compander;
pVfo->Compander = att->compander;
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
if(gRemoveOffset)
+1
View File
@@ -55,6 +55,7 @@ void SysTick_Handler(void)
gNextTimeslice_500ms = true;
#ifdef ENABLE_FEAT_F4HWN
DECREMENT_AND_TRIGGER(gVfoSaveCountdown_10ms, gScheduleVfoSave);
DECREMENT_AND_TRIGGER(gTxTimerCountdownAlert_500ms - ALERT_TOT * 2, gTxTimeoutReachedAlert);
#ifdef ENABLE_FEAT_F4HWN_RX_TX_TIMER
DECREMENT(gRxTimerCountdown_500ms);
+55 -21
View File
@@ -312,11 +312,12 @@ gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data16[5]) ? Data16[5] : (FREQ_CHANNE
}
// 0D60..0E27
/*
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];
ChannelAttributes_t *att = MR_GetChannelAttributes(i);
if (att->__val == 0xFFFF) {
att->__val = 0;
@@ -327,6 +328,27 @@ gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data16[5]) ? Data16[5] : (FREQ_CHANNE
att->exclude = 0;
}
}
*/
// Init attr cache
MR_InitChannelAttributesCache();
// Load and check channel
for (uint16_t i = 0; i < MR_CHANNELS_MAX + 7; i++) {
ChannelAttributes_t *att = MR_GetChannelAttributes(i);
if (att != NULL) {
if (att->__val == 0xFFFF) {
att->__val = 0;
att->band = 0x7;
MR_SetChannelAttributes(i, att); // ⭐ IMPORTANT: Sauvegarder!
}
else {
att->exclude = 0;
MR_SetChannelAttributes(i, att); // ⭐ IMPORTANT: Sauvegarder!
}
}
}
// 0F30..0F3F
PY25Q16_ReadBuffer(0x00A138, gCustomAesKey, sizeof(gCustomAesKey));
@@ -588,27 +610,39 @@ void SETTINGS_SaveFM(void)
void SETTINGS_SaveVfoIndices(void)
{
uint16_t Data16[8];
#ifndef ENABLE_NOAA
PY25Q16_ReadBuffer(0x00A010, Data16, sizeof(Data16));
#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];
#ifdef ENABLE_NOAA
Data16[6] = gEeprom.NoaaChannel[0];
Data16[7] = gEeprom.NoaaChannel[1];
#endif
PY25Q16_WriteBuffer(0x00A010, Data16, sizeof(Data16), false);
gVfoStateChanged = true;
gVfoSaveCountdown_10ms = 2;
}
void SETTINGS_SaveVfoIndicesFlush(void)
{
if (gScheduleVfoSave) {
gScheduleVfoSave = false;
if (gVfoStateChanged) {
gVfoStateChanged = false;
uint16_t Data16[8];
#ifndef ENABLE_NOAA
PY25Q16_ReadBuffer(0x00A010, Data16, sizeof(Data16));
#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];
#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)
{
@@ -1011,7 +1045,7 @@ void SETTINGS_UpdateChannel(uint16_t channel, const VFO_Info_t *pVFO, bool keep,
PY25Q16_WriteBuffer(0x008000, buf, sizeof(buf), false);
}
gMR_ChannelAttributes[channel] = att;
MR_SetChannelAttributes(channel, &att);
if (IS_MR_CHANNEL(channel)) { // it's a memory channel
if (!keep) {
+1
View File
@@ -315,6 +315,7 @@ void SETTINGS_FactoryReset(bool bIsAll);
void SETTINGS_SaveFM(void);
#endif
void SETTINGS_SaveVfoIndices(void);
void SETTINGS_SaveVfoIndicesFlush(void);
void SETTINGS_SaveSettings(void);
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);
+9 -9
View File
@@ -810,9 +810,9 @@ void UI_DisplayMain(void)
const unsigned int x = 3;
const bool inputting = gInputBoxIndex != 0 && gEeprom.TX_VFO == vfo_num;
if (!inputting || gScanStateDir != SCAN_OFF)
sprintf(String, "M%03u", gEeprom.ScreenChannel[vfo_num] + 1);
sprintf(String, "%04u", gEeprom.ScreenChannel[vfo_num] + 1);
else
sprintf(String, "M%.3s", INPUTBOX_GetAscii()); // show the input text
sprintf(String, "%.4s", INPUTBOX_GetAscii()); // show the input text
UI_PrintStringSmallNormalInverse(String, x, 0, line + 1);
}
else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
@@ -890,15 +890,15 @@ void UI_DisplayMain(void)
if(gEeprom.MENU_LOCK == false) {
#endif
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
if(att.exclude == false)
if(att->exclude == false)
{
// show the scan list assigment symbols
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
uint8_t countList = att.scanlist;
uint8_t countList = att->scanlist;
if(countList > MR_CHANNELS_LIST + 1) {
countList = 0;
}
@@ -941,7 +941,7 @@ void UI_DisplayMain(void)
// compander symbol
#ifndef ENABLE_BIG_FREQ
if (att.compander)
if (att->compander)
memcpy(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
#else
// TODO: // find somewhere else to put the symbol
@@ -1058,8 +1058,8 @@ void UI_DisplayMain(void)
}
// show the channel symbols
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if (att.compander)
const ChannelAttributes_t* att = MR_GetChannelAttributes(gEeprom.ScreenChannel[vfo_num]);
if (att->compander)
#ifdef ENABLE_BIG_FREQ
memcpy(p_line0 + 120, BITMAP_compand, sizeof(BITMAP_compand));
#else
+1 -1
View File
@@ -67,7 +67,7 @@
"ENABLE_UART_RW_BK_REGS": false,
"ENABLE_SWD": false,
"VERSION_STRING_1": "v0.22",
"VERSION_STRING_2": "v5.0.0"
"VERSION_STRING_2": "v5.0.1"
}
},
{