diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index b3230d9e..ceceed22 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -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) diff --git a/App/app/action.c b/App/app/action.c index 299b40c3..643ad6f7 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -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 diff --git a/App/app/aircopy.c b/App/app/aircopy.c index 01bb6700..5cbfe838 100644 --- a/App/app/aircopy.c +++ b/App/app/aircopy.c @@ -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 #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 \ No newline at end of file diff --git a/App/app/aircopy.h b/App/app/aircopy.h index 3ad79b68..9aba37bb 100644 --- a/App/app/aircopy.h +++ b/App/app/aircopy.h @@ -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 diff --git a/App/app/chFrScanner.c b/App/app/chFrScanner.c index d17ad0c6..ff2a1d2c 100644 --- a/App/app/chFrScanner.c +++ b/App/app/chFrScanner.c @@ -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; } diff --git a/App/app/common.c b/App/app/common.c index 8bc2168c..d647efef 100644 --- a/App/app/common.c +++ b/App/app/common.c @@ -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 diff --git a/App/app/main.c b/App/app/main.c index 10fe3aa8..10518970 100644 --- a/App/app/main.c +++ b/App/app/main.c @@ -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; diff --git a/App/app/menu.c b/App/app/menu.c index 439e21b8..0d44d668 100644 --- a/App/app/menu.c +++ b/App/app/menu.c @@ -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) diff --git a/App/app/spectrum.c b/App/app/spectrum.c index cfd7b245..284ed42b 100644 --- a/App/app/spectrum.c +++ b/App/app/spectrum.c @@ -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 diff --git a/App/bitmaps.c b/App/bitmaps.c index 0889687d..05a11422 100644 --- a/App/bitmaps.c +++ b/App/bitmaps.c @@ -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, diff --git a/App/bitmaps.h b/App/bitmaps.h index 2b468ff6..be10a970 100644 --- a/App/bitmaps.h +++ b/App/bitmaps.h @@ -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]; diff --git a/App/driver/backlight.c b/App/driver/backlight.c index 61d627c3..ce3f20c2 100644 --- a/App/driver/backlight.c +++ b/App/driver/backlight.c @@ -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) diff --git a/App/driver/eeprom_compat.c b/App/driver/eeprom_compat.c index f93e6474..b61aadb3 100644 --- a/App/driver/eeprom_compat.c +++ b/App/driver/eeprom_compat.c @@ -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); diff --git a/App/frequencies.h b/App/frequencies.h index 2e49ea1b..a21a6727 100644 --- a/App/frequencies.h +++ b/App/frequencies.h @@ -20,6 +20,7 @@ #include #define _1GHz_in_KHz 100000000 +#define DEFAULT_FREQ 43450000 // Use for Reset and Aircopy typedef struct { const uint32_t lower; diff --git a/App/helper/boot.c b/App/helper/boot.c index db296e46..cb50aa20 100644 --- a/App/helper/boot.c +++ b/App/helper/boot.c @@ -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; diff --git a/App/main.c b/App/main.c index f7a63a02..c3153b37 100644 --- a/App/main.c +++ b/App/main.c @@ -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); diff --git a/App/misc.c b/App/misc.c index 49759b92..b969b08d 100644 --- a/App/misc.c +++ b/App/misc.c @@ -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; diff --git a/App/misc.h b/App/misc.h index 73aba42e..606e1016 100644 --- a/App/misc.h +++ b/App/misc.h @@ -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 diff --git a/App/radio.c b/App/radio.c index 6de30167..cb8f1835 100644 --- a/App/radio.c +++ b/App/radio.c @@ -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)) { diff --git a/App/radio.h b/App/radio.h index 19f5b8bf..00088428 100644 --- a/App/radio.h +++ b/App/radio.h @@ -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); diff --git a/App/screenshot.c b/App/screenshot.c index 38640cf3..bad36206 100644 --- a/App/screenshot.c +++ b/App/screenshot.c @@ -18,16 +18,20 @@ #include "driver/st7565.h" #include "screenshot.h" #include "misc.h" +#include -// 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 = ¤tFrame[block * 8]; - uint8_t *prev = &previousFrame[block * 8]; + for (uint8_t chunk = 0; chunk < 128; chunk++) { + uint8_t *cur = &frameBuffer[chunk * 8]; + uint8_t *prev = &previousFrame[chunk * 8]; bool changed = memcmp(cur, prev, 8) != 0; - bool isForced = (block == forcedBlock); + bool isForced = (chunk == forcedBlock); bool fullUpdate = force; if (changed || isForced || fullUpdate) { - deltaFrame[deltaLen++] = block; - memcpy(&deltaFrame[deltaLen], cur, 8); - deltaLen += 8; - memcpy(prev, cur, 8); // Update stored frame + changedChunks[changedCount++] = chunk; + deltaLen += 9; } } forcedBlock = (forcedBlock + 1) % 128; if (deltaLen == 0) - return; // No update needed + return; - // ==== Send frame ==== + // ==== Send version marker (for backward compatibility detection) ==== + // New format: sends 0xFF before header + // Old format: doesn't exist, so viewers can differentiate + uint8_t versionMarker = 0xFF; + 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); } \ No newline at end of file diff --git a/App/settings.c b/App/settings.c index 0ed81e1a..e23377a4 100644 --- a/App/settings.c +++ b/App/settings.c @@ -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 diff --git a/App/settings.h b/App/settings.h index 35639b58..022691c6 100644 --- a/App/settings.h +++ b/App/settings.h @@ -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); diff --git a/App/ui/aircopy.c b/App/ui/aircopy.c index 80472f81..1eb3eece 100644 --- a/App/ui/aircopy.c +++ b/App/ui/aircopy.c @@ -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 \ No newline at end of file diff --git a/App/ui/fmradio.c b/App/ui/fmradio.c index 8c5dbb5c..fc1e3096 100644 --- a/App/ui/fmradio.c +++ b/App/ui/fmradio.c @@ -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"; diff --git a/App/ui/helper.c b/App/ui/helper.c index cf63819a..f2ef032b 100644 --- a/App/ui/helper.c +++ b/App/ui/helper.c @@ -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); diff --git a/App/ui/helper.h b/App/ui/helper.h index 2dea9ea4..47114a2f 100644 --- a/App/ui/helper.h +++ b/App/ui/helper.h @@ -20,11 +20,13 @@ #include #include -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); diff --git a/App/ui/main.c b/App/ui/main.c index 26496b52..bf62ffeb 100644 --- a/App/ui/main.c +++ b/App/ui/main.c @@ -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 { diff --git a/App/ui/menu.c b/App/ui/menu.c index 46e57e3d..de69fec8 100644 --- a/App/ui/menu.c +++ b/App/ui/menu.c @@ -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) diff --git a/App/ui/menu.h b/App/ui/menu.h index f8bfb1a1..6128c954 100644 --- a/App/ui/menu.h +++ b/App/ui/menu.h @@ -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 diff --git a/App/ui/status.c b/App/ui/status.c index bd723c6a..f8e7f9be 100644 --- a/App/ui/status.c +++ b/App/ui/status.c @@ -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 diff --git a/App/ui/welcome.c b/App/ui/welcome.c index d47fd7cf..757d8f31 100644 --- a/App/ui/welcome.c +++ b/App/ui/welcome.c @@ -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, diff --git a/CMakePresets.json b/CMakePresets.json index 77f8bd5c..25da12c5 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -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" } }, {