Merge pull request #484 from armel/feature_update_v5

Feature update v5
This commit is contained in:
Armel FAUVEAU authored and GitHub committed 2026-08-04 17:45:07 +02:00
commit fe9c4e9432
39 files changed
+2156 -264

No files matched your search

+4
View File
@@ -70,6 +70,7 @@ if(ENABLE_FEAT_F4HWN)
"AUTHOR_STRING_2=\"${AUTHOR_STRING_2}\"" "AUTHOR_STRING_2=\"${AUTHOR_STRING_2}\""
"VERSION_STRING_1=\"${VERSION_STRING_1}\"" "VERSION_STRING_1=\"${VERSION_STRING_1}\""
"VERSION_STRING_2=\"${VERSION_STRING_2}\"" "VERSION_STRING_2=\"${VERSION_STRING_2}\""
"DISPLAY_VERSION_STRING_2=\"${DISPLAY_VERSION_STRING_2}\""
"EDITION_STRING=\"${EDITION_STRING}\"" "EDITION_STRING=\"${EDITION_STRING}\""
ALERT_TOT=10 ALERT_TOT=10
) )
@@ -210,6 +211,9 @@ enable_feature(ENABLE_FEAT_F4HWN_BEAM
enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG
app/rxtx_log.c app/rxtx_log.c
) )
enable_feature(ENABLE_FEAT_F4HWN_FOXHUNT
app/foxhunt.c
)
enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP) enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP)
enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER) enable_feature(ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER)
+17 -2
View File
@@ -48,6 +48,9 @@
#ifdef ENABLE_FEAT_F4HWN_RXTX_LOG #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG
#include "app/rxtx_log.h" #include "app/rxtx_log.h"
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
#include "app/foxhunt.h"
#endif
#if defined(ENABLE_FMRADIO) #if defined(ENABLE_FMRADIO)
static void ACTION_Scan_FM(bool bRestart); static void ACTION_Scan_FM(bool bRestart);
@@ -61,7 +64,7 @@ inline static void ACTION_1750() { ACTION_AlarmOr1750(true); };
inline static void ACTION_ScanRestart() { ACTION_Scan(true); }; inline static void ACTION_ScanRestart() { ACTION_Scan(true); };
void (*action_opt_table[])(void) = { void (*const action_opt_table[])(void) = {
[ACTION_OPT_NONE] = &FUNCTION_NOP, [ACTION_OPT_NONE] = &FUNCTION_NOP,
[ACTION_OPT_POWER] = &ACTION_Power, [ACTION_OPT_POWER] = &ACTION_Power,
[ACTION_OPT_MONITOR] = &ACTION_Monitor, [ACTION_OPT_MONITOR] = &ACTION_Monitor,
@@ -137,6 +140,9 @@ void (*action_opt_table[])(void) = {
#ifdef ENABLE_FEAT_F4HWN_RXTX_LOG #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG
[ACTION_OPT_RXTX_LOG] = &ACTION_RxTxLog, [ACTION_OPT_RXTX_LOG] = &ACTION_RxTxLog,
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
[ACTION_OPT_FOXHUNT] = &ACTION_FoxHunt,
#endif
}; };
static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN); static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN);
@@ -243,7 +249,7 @@ void ACTION_Scan(bool bRestart)
// channel mode. Keep scanning but toggle between scan lists // channel mode. Keep scanning but toggle between scan lists
RADIO_NextValidList(1); RADIO_NextValidList(1);
UI_MAIN_NotifyScanProgressDataChanged(); UI_MAIN_NotifyScanListChanged();
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
SETTINGS_WriteCurrentState(); SETTINGS_WriteCurrentState();
@@ -382,6 +388,9 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_BEAM #ifdef ENABLE_FEAT_F4HWN_BEAM
case ACTION_OPT_BEAM: case ACTION_OPT_BEAM:
#endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
case ACTION_OPT_FOXHUNT:
#endif #endif
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return; return;
@@ -416,6 +425,12 @@ void ACTION_FM(void)
gMonitor = false; gMonitor = false;
if (gScanStateDir != SCAN_OFF) {
// Stop the channel/frequency scan before switching to the FM radio.
gScanKeepResult = false;
CHFRSCANNER_Stop();
}
RADIO_SelectVfos(); RADIO_SelectVfos();
RADIO_SetupRegisters(true); RADIO_SetupRegisters(true);
+3 -2
View File
@@ -90,10 +90,11 @@ DECLARE_AIRCOPY_BANK(1)
static const AIRCOPY_Segment_t AIRCOPY_Segments_Settings[] = { static const AIRCOPY_Segment_t AIRCOPY_Segments_Settings[] = {
{ 0xA000, 0xA170, AIRCOPY_WRITE_BYTES }, { 0xA000, 0xA170, AIRCOPY_WRITE_BYTES },
{ 0x880E, 0x886E, AIRCOPY_WRITE_BYTES }, { 0x880E, 0x886E, AIRCOPY_WRITE_BYTES },
{ 0x9000, 0x90D6, AIRCOPY_WRITE_BYTES }, // VFO area (so scan-range source frequencies are replicated) { 0x9000, 0x90E5, AIRCOPY_WRITE_BYTES }, // VFO area (full 14 VFOs 0x9000..0x90E0) +
// Fox Hunt settings tail 0x90E0..0x90E5
}; };
// total_blocks = ceil(0x170/64) + ceil(0x60/64) + ceil(0xD6/64) = 6 + 2 + 4 = 12 // total_blocks = ceil(0x170/64) + ceil(0x60/64) + ceil(0xE5/64) = 6 + 2 + 4 = 12
static const AIRCOPY_TransferMap_t AIRCOPY_Map_Settings = { static const AIRCOPY_TransferMap_t AIRCOPY_Map_Settings = {
.segments = AIRCOPY_Segments_Settings, .segments = AIRCOPY_Segments_Settings,
.num_segments = 3, .num_segments = 3,
+1 -1
View File
@@ -107,7 +107,7 @@ static KEY_Code_t gScreenSaverWakeKey = KEY_INVALID;
static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld); static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
void (*ProcessKeysFunctions[])(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) = { void (*const ProcessKeysFunctions[])(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) = {
[DISPLAY_MAIN] = &MAIN_ProcessKeys, [DISPLAY_MAIN] = &MAIN_ProcessKeys,
[DISPLAY_MENU] = &MENU_ProcessKeys, [DISPLAY_MENU] = &MENU_ProcessKeys,
[DISPLAY_SCANNER] = &SCANNER_ProcessKeys, [DISPLAY_SCANNER] = &SCANNER_ProcessKeys,
+7
View File
@@ -16,6 +16,10 @@
#include "app/breakout.h" #include "app/breakout.h"
#if defined(ENABLE_UART) || defined(ENABLE_USB)
#include "app/uart.h"
#endif
#ifdef ENABLE_FEAT_F4HWN_K5VIEWER #ifdef ENABLE_FEAT_F4HWN_K5VIEWER
#include "k5viewer.h" #include "k5viewer.h"
#endif #endif
@@ -359,6 +363,9 @@ void APP_RunBreakout(void) {
while(isInitialized) while(isInitialized)
{ {
#if defined(ENABLE_UART) || defined(ENABLE_USB)
UART_ServiceCommands();
#endif
Tick(); Tick();
if(!isPaused) if(!isPaused)
{ {
+6 -2
View File
@@ -771,13 +771,17 @@ void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_directi
#endif #endif
if (IS_MR_CHANNEL(gNextMrChannel)) if (IS_MR_CHANNEL(gNextMrChannel))
{ {
bool scanListChanged = false;
if(!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) { if(!RADIO_CheckValidList(gEeprom.SCAN_LIST_DEFAULT)) {
RADIO_NextValidList(1); RADIO_NextValidList(1);
UI_MAIN_NotifyScanProgressDataChanged(); scanListChanged = true;
} }
if (storeBackupSettings || scanListChanged)
UI_MAIN_NotifyScanListChanged();
// channel mode // channel mode
if (storeBackupSettings) { if (storeBackupSettings) {
initialFrqOrChan = gRxVfo->CHANNEL_SAVE; initialFrqOrChan = gRxVfo->CHANNEL_SAVE;
+1361
View File
File diff suppressed because it is too large. Load diff
+57
View File
@@ -0,0 +1,57 @@
/* Copyright 2026 Armel F4HWN
* https://github.com/armel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_FOXHUNT_H
#define APP_FOXHUNT_H
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
#include "keyboard_state.h"
#include "../bitmaps.h"
#include "../board.h"
#include "py32f0xx.h"
#include "../driver/backlight.h"
#include "../driver/bk4819-regs.h"
#include "../driver/bk4819.h"
#include "../driver/gpio.h"
#include "../driver/keyboard.h"
#include "../driver/py25q16.h"
#include "../driver/st7565.h"
#include "../driver/system.h"
#include "../driver/systick.h"
#include "../external/printf/printf.h"
#include "../font.h"
#include "../helper/battery.h"
#include "../misc.h"
#include "../radio.h"
#include "../settings.h"
#include "../ui/battery.h"
#include "../ui/helper.h"
#include "../ui/ui.h"
#include "../audio.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
// Entry point wired as an assignable side-key action (see action.c).
void ACTION_FoxHunt(void);
// Self-contained modal loop that owns the screen and keypad until EXIT.
void APP_RunFoxHunt(void);
#endif // ENABLE_FEAT_F4HWN_FOXHUNT
#endif // APP_FOXHUNT_H
+16 -4
View File
@@ -105,7 +105,7 @@ static void toggle_chan_scanlist(void)
gTxVfo->SCANLIST_PARTICIPATION = scanlist; gTxVfo->SCANLIST_PARTICIPATION = scanlist;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, true, true); SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
} }
gVfoConfigureMode = VFO_CONFIGURE; gVfoConfigureMode = VFO_CONFIGURE;
@@ -225,6 +225,12 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
case KEY_4: case KEY_4:
HideFKeyIcon(); HideFKeyIcon();
if (gScanStateDir != SCAN_OFF) {
// Stop the channel/frequency scan before saving the RX mode for Close Call.
gScanKeepResult = false;
CHFRSCANNER_Stop();
}
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
@@ -317,7 +323,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
if (gScanStateDir != SCAN_OFF) { if (gScanStateDir != SCAN_OFF) {
RADIO_NextValidList(isKeyUp ? 1 : -1); RADIO_NextValidList(isKeyUp ? 1 : -1);
UI_MAIN_NotifyScanProgressDataChanged(); UI_MAIN_NotifyScanListChanged();
} else { } else {
// Adjust squelch: UP increments, DOWN decrements // Adjust squelch: UP increments, DOWN decrements
if (gSquelchLevelOriginal == 10) if (gSquelchLevelOriginal == 10)
@@ -500,7 +506,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
if (value == 0) if (value == 0)
{ {
gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1; gEeprom.SCAN_LIST_DEFAULT = MR_CHANNELS_LIST + 1;
UI_MAIN_NotifyScanProgressDataChanged(); UI_MAIN_NotifyScanListChanged();
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
SETTINGS_WriteCurrentState(); SETTINGS_WriteCurrentState();
#endif #endif
@@ -519,7 +525,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
RADIO_NextValidList(1); RADIO_NextValidList(1);
} }
UI_MAIN_NotifyScanProgressDataChanged(); UI_MAIN_NotifyScanListChanged();
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
SETTINGS_WriteCurrentState(); SETTINGS_WriteCurrentState();
@@ -918,6 +924,12 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
return; return;
} }
#endif #endif
if (gScanStateDir != SCAN_OFF) {
// Stop the channel/frequency scan before saving the RX mode for the CTCSS/DCS scan.
gScanKeepResult = false;
CHFRSCANNER_Stop();
}
// scan the CTCSS/DCS code // scan the CTCSS/DCS code
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX; gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
+3 -3
View File
@@ -725,7 +725,7 @@ void MENU_AcceptSetting(void)
case MENU_LIST_CH: case MENU_LIST_CH:
gTxVfo->SCANLIST_PARTICIPATION = gSubMenuSelection; gTxVfo->SCANLIST_PARTICIPATION = gSubMenuSelection;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true); SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
gVfoConfigureMode = VFO_CONFIGURE; gVfoConfigureMode = VFO_CONFIGURE;
gFlagResetVfos = true; gFlagResetVfos = true;
return; return;
@@ -752,7 +752,7 @@ void MENU_AcceptSetting(void)
case MENU_COMPAND: case MENU_COMPAND:
gTxVfo->Compander = gSubMenuSelection; gTxVfo->Compander = gSubMenuSelection;
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true, false, true); SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
gVfoConfigureMode = VFO_CONFIGURE; gVfoConfigureMode = VFO_CONFIGURE;
gFlagResetVfos = true; gFlagResetVfos = true;
// gRequestSaveChannel = 1; // gRequestSaveChannel = 1;
@@ -864,7 +864,7 @@ void MENU_AcceptSetting(void)
#endif #endif
case MENU_DEL_CH: case MENU_DEL_CH:
SETTINGS_UpdateChannel(gSubMenuSelection, NULL, false, false, true); SETTINGS_UpdateChannel(gSubMenuSelection, NULL, false);
gVfoConfigureMode = VFO_CONFIGURE_RELOAD; gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true; gFlagResetVfos = true;
return; return;
+33 -15
View File
@@ -136,6 +136,22 @@ static uint16_t gLogCursor;
static uint8_t gLogFilter; static uint8_t gLogFilter;
static uint8_t gLogDetailMode; static uint8_t gLogDetailMode;
bool RXTX_LOG_IsEnabled(void)
{
return gEeprom.KEY_1_SHORT_PRESS_ACTION == ACTION_OPT_RXTX_LOG ||
gEeprom.KEY_1_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG ||
gEeprom.KEY_2_SHORT_PRESS_ACTION == ACTION_OPT_RXTX_LOG ||
gEeprom.KEY_2_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG ||
gEeprom.KEY_M_LONG_PRESS_ACTION == ACTION_OPT_RXTX_LOG;
}
static void RXTX_LOG_ResetActiveSession(void)
{
gSessionActive = false;
gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN;
gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN;
}
static uint8_t RXTX_LOG_Crc8(const void *data, uint16_t size) static uint8_t RXTX_LOG_Crc8(const void *data, uint16_t size)
{ {
const uint8_t *p = (const uint8_t *)data; const uint8_t *p = (const uint8_t *)data;
@@ -755,6 +771,7 @@ uint32_t RXTX_LOG_K5ViewerSignature(void)
{ {
uint32_t hash = 2166136261u; uint32_t hash = 2166136261u;
hash = RXTX_LOG_K5ViewerMix(hash, RXTX_LOG_IsEnabled());
hash = RXTX_LOG_K5ViewerMix(hash, gSessionActive); hash = RXTX_LOG_K5ViewerMix(hash, gSessionActive);
hash = RXTX_LOG_K5ViewerMix(hash, gClearActive); hash = RXTX_LOG_K5ViewerMix(hash, gClearActive);
hash = RXTX_LOG_K5ViewerMix(hash, gLogHasTraffic); hash = RXTX_LOG_K5ViewerMix(hash, gLogHasTraffic);
@@ -863,6 +880,13 @@ void RXTX_LOG_SendK5ViewerPacket(void (*send)(const uint8_t *data, uint16_t size
RXTX_LogK5ViewerRow_t row; RXTX_LogK5ViewerRow_t row;
uint8_t header[4] = {RXTX_LOG_K5VIEWER_VERSION, 0, RXTX_LOG_K5VIEWER_ROW_COUNT, 0}; uint8_t header[4] = {RXTX_LOG_K5VIEWER_VERSION, 0, RXTX_LOG_K5VIEWER_ROW_COUNT, 0};
if (!RXTX_LOG_IsEnabled()) {
header[1] = RXTX_LOG_K5VIEWER_STATUS_DISABLED;
header[2] = 0;
send(header, sizeof(header));
return;
}
if (gSessionActive) if (gSessionActive)
header[1] |= RXTX_LOG_K5VIEWER_STATUS_ACTIVE; header[1] |= RXTX_LOG_K5VIEWER_STATUS_ACTIVE;
if (gLogHasTraffic) if (gLogHasTraffic)
@@ -898,7 +922,7 @@ uint32_t RXTX_LOG_SendK5ViewerHistoryPage(uint32_t beforeSeq, void (*send)(const
static void RXTX_LOG_CaptureSession(uint8_t flags, const VFO_Info_t *vfo) static void RXTX_LOG_CaptureSession(uint8_t flags, const VFO_Info_t *vfo)
{ {
if (gClearActive) if (!RXTX_LOG_IsEnabled() || vfo == NULL || gClearActive)
return; return;
const uint32_t frequency = (flags & RXTX_LOG_FLAG_TX) ? vfo->pTX->Frequency : vfo->pRX->Frequency; const uint32_t frequency = (flags & RXTX_LOG_FLAG_TX) ? vfo->pTX->Frequency : vfo->pRX->Frequency;
@@ -984,15 +1008,13 @@ void RXTX_LOG_Init(void)
// Skip the marker if the log already ends with one (e.g. repeated // Skip the marker if the log already ends with one (e.g. repeated
// reboots with no RX/TX in between) to avoid stacking empty separators. // reboots with no RX/TX in between) to avoid stacking empty separators.
if (!found || (lastEntryFlags & RXTX_LOG_FLAG_SESSION) == 0) if (RXTX_LOG_IsEnabled() &&
(!found || (lastEntryFlags & RXTX_LOG_FLAG_SESSION) == 0))
RXTX_LOG_WriteSessionMarker(); RXTX_LOG_WriteSessionMarker();
} }
void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function) void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function)
{ {
if (vfo == NULL)
return;
uint8_t flags = 0; uint8_t flags = 0;
if (function == FUNCTION_MONITOR) if (function == FUNCTION_MONITOR)
flags |= RXTX_LOG_FLAG_MONITOR; flags |= RXTX_LOG_FLAG_MONITOR;
@@ -1002,9 +1024,6 @@ void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function)
void RXTX_LOG_BeginTx(const VFO_Info_t *vfo) void RXTX_LOG_BeginTx(const VFO_Info_t *vfo)
{ {
if (vfo == NULL)
return;
RXTX_LOG_CaptureSession(RXTX_LOG_FLAG_TX, vfo); RXTX_LOG_CaptureSession(RXTX_LOG_FLAG_TX, vfo);
} }
@@ -1013,10 +1032,8 @@ void RXTX_LOG_EndActive(void)
if (!gSessionActive) if (!gSessionActive)
return; return;
if (gClearActive) { if (!RXTX_LOG_IsEnabled() || gClearActive) {
gSessionActive = false; RXTX_LOG_ResetActiveSession();
gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN;
gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN;
return; return;
} }
@@ -1040,9 +1057,7 @@ void RXTX_LOG_EndActive(void)
gLogHasTraffic = true; gLogHasTraffic = true;
RXTX_LOG_InvalidateViewCache(); RXTX_LOG_InvalidateViewCache();
gSessionActive = false; RXTX_LOG_ResetActiveSession();
gSessionSMeter = RXTX_LOG_SMETER_UNKNOWN;
gSessionBattVolt = RXTX_LOG_BATT_UNKNOWN;
} }
void RXTX_LOG_Tick500ms(void) void RXTX_LOG_Tick500ms(void)
@@ -1056,6 +1071,9 @@ void RXTX_LOG_Tick500ms(void)
void RXTX_LOG_Task10ms(void) void RXTX_LOG_Task10ms(void)
{ {
if (gSessionActive && !RXTX_LOG_IsEnabled())
RXTX_LOG_ResetActiveSession();
if (gClearActive) { if (gClearActive) {
RXTX_LOG_StepClear(); RXTX_LOG_StepClear();
} else if (gViewScanActive) { } else if (gViewScanActive) {
+8 -5
View File
@@ -42,6 +42,8 @@ typedef struct {
#define RXTX_LOG_K5VIEWER_STATUS_ACTIVE (1u << 0) #define RXTX_LOG_K5VIEWER_STATUS_ACTIVE (1u << 0)
#define RXTX_LOG_K5VIEWER_STATUS_HAS_TRAFFIC (1u << 1) #define RXTX_LOG_K5VIEWER_STATUS_HAS_TRAFFIC (1u << 1)
#define RXTX_LOG_K5VIEWER_STATUS_CLEARING (1u << 2) #define RXTX_LOG_K5VIEWER_STATUS_CLEARING (1u << 2)
#define RXTX_LOG_K5VIEWER_STATUS_DISABLED (1u << 3)
#define RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE 4u
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint32_t frequency; uint32_t frequency;
@@ -54,11 +56,11 @@ typedef struct __attribute__((packed)) {
char channelName[RXTX_LOG_K5VIEWER_NAME_LENGTH]; char channelName[RXTX_LOG_K5VIEWER_NAME_LENGTH];
} RXTX_LogK5ViewerRow_t; } RXTX_LogK5ViewerRow_t;
// On-wire packet layout: 4-byte header (version, status, rowCount, // On-wire packet layout: a disabled log sends only the 4-byte status header.
// reserved), one live row, then RXTX_LOG_K5VIEWER_ROW_COUNT row slots, // An enabled log continues with one live row and
// zero-padded past the last valid row. The packet is streamed row by row // RXTX_LOG_K5VIEWER_ROW_COUNT row slots, zero-padded past the last valid row.
// and never built whole in RAM, so only its size is defined here. // The packet is streamed row by row and never built whole in RAM.
#define RXTX_LOG_K5VIEWER_PACKET_SIZE (4u + ((RXTX_LOG_K5VIEWER_ROW_COUNT + 1u) * sizeof(RXTX_LogK5ViewerRow_t))) #define RXTX_LOG_K5VIEWER_PACKET_SIZE (RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE + ((RXTX_LOG_K5VIEWER_ROW_COUNT + 1u) * sizeof(RXTX_LogK5ViewerRow_t)))
#define RXTX_LOG_K5VIEWER_HISTORY_PACKET_SIZE (RXTX_LOG_K5VIEWER_HISTORY_ROW_COUNT * sizeof(RXTX_LogK5ViewerRow_t)) #define RXTX_LOG_K5VIEWER_HISTORY_PACKET_SIZE (RXTX_LOG_K5VIEWER_HISTORY_ROW_COUNT * sizeof(RXTX_LogK5ViewerRow_t))
uint32_t RXTX_LOG_K5ViewerSignature(void); uint32_t RXTX_LOG_K5ViewerSignature(void);
@@ -70,6 +72,7 @@ uint32_t RXTX_LOG_SendK5ViewerHistoryPage(uint32_t beforeSeq, void (*send)(const
#endif #endif
void RXTX_LOG_Init(void); void RXTX_LOG_Init(void);
bool RXTX_LOG_IsEnabled(void);
void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function); void RXTX_LOG_BeginRx(const VFO_Info_t *vfo, FUNCTION_Type_t function);
void RXTX_LOG_BeginTx(const VFO_Info_t *vfo); void RXTX_LOG_BeginTx(const VFO_Info_t *vfo);
void RXTX_LOG_EndActive(void); void RXTX_LOG_EndActive(void);
+9 -2
View File
@@ -18,6 +18,10 @@
#include "audio.h" #include "audio.h"
#include "misc.h" #include "misc.h"
#if defined(ENABLE_UART) || defined(ENABLE_USB)
#include "app/uart.h"
#endif
#ifdef ENABLE_SCAN_RANGES #ifdef ENABLE_SCAN_RANGES
#include "chFrScanner.h" #include "chFrScanner.h"
#endif #endif
@@ -73,7 +77,7 @@ static uint16_t blacklistFreqs[15];
static uint8_t blacklistFreqsIdx; static uint8_t blacklistFreqsIdx;
#endif #endif
const char *bwOptions[] = {"25", "12.5", "6.25"}; const char *const bwOptions[] = {"25", "12.5", "6.25"};
const uint8_t modulationTypeTuneSteps[] = {100, 50, 10}; const uint8_t modulationTypeTuneSteps[] = {100, 50, 10};
const uint8_t modTypeReg47Values[] = {1, 7, 5}; const uint8_t modTypeReg47Values[] = {1, 7, 5};
@@ -176,7 +180,7 @@ char freqInputString[11];
uint8_t menuState = 0; uint8_t menuState = 0;
uint16_t listenT = 0; uint16_t listenT = 0;
RegisterSpec registerSpecs[] = { const RegisterSpec registerSpecs[] = {
{}, {},
{"LNAs", BK4819_REG_13, 8, 0b11, 1}, {"LNAs", BK4819_REG_13, 8, 0b11, 1},
{"LNA", BK4819_REG_13, 5, 0b111, 1}, {"LNA", BK4819_REG_13, 5, 0b111, 1},
@@ -2608,6 +2612,9 @@ void APP_RunSpectrum()
while (isInitialized) while (isInitialized)
{ {
#if defined(ENABLE_UART) || defined(ENABLE_USB)
UART_ServiceCommands();
#endif
Tick(); Tick();
} }
+14 -1
View File
@@ -866,4 +866,17 @@ void UART_HandleCommand(uint32_t Port)
#ifdef ENABLE_FEAT_F4HWN_K5VIEWER #ifdef ENABLE_FEAT_F4HWN_K5VIEWER
gUART_LockK5Viewer = 20; // lock the K5Viewer stream gUART_LockK5Viewer = 20; // lock the K5Viewer stream
#endif #endif
} }
void UART_ServiceCommands(void)
{
#ifdef ENABLE_USB
if (UART_IsCommandAvailable(UART_PORT_VCP))
UART_HandleCommand(UART_PORT_VCP);
#endif
#ifdef ENABLE_UART
if (UART_IsCommandAvailable(UART_PORT_UART))
UART_HandleCommand(UART_PORT_UART);
#endif
}
+1 -1
View File
@@ -32,6 +32,6 @@ enum
bool UART_IsCommandAvailable(uint32_t Port); bool UART_IsCommandAvailable(uint32_t Port);
void UART_HandleCommand(uint32_t Port); void UART_HandleCommand(uint32_t Port);
void UART_ServiceCommands(void);
#endif #endif
+129
View File
@@ -301,6 +301,135 @@ const uint8_t BITMAP_NOAA[12] =
}; };
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
const uint8_t BITMAP_FoxHuntSignal[10] =
{ // point source + the speaker bitmap's two sound waves, oriented horizontally
0b00001000,
0b00011100,
0b00011100,
0b00001000,
0b00000000,
0b00100010,
0b00011100,
0b01000001,
0b00100010,
0b00011100
};
const uint8_t BITMAP_FoxHuntSpeaker[10] =
{ // speaker cone + two sound waves (bit0 = top row)
0b00011100,
0b00011100,
0b00111110,
0b01111111,
0b00000000,
0b00100010,
0b00011100,
0b01000001,
0b00100010,
0b00011100
};
const uint8_t BITMAP_FoxHuntUp[11] =
{ // filled up triangle (getting nearer)
0b00100000,
0b00110000,
0b00111000,
0b00111100,
0b00111110,
0b00111111,
0b00111110,
0b00111100,
0b00111000,
0b00110000,
0b00100000
};
const uint8_t BITMAP_FoxHuntDown[11] =
{ // filled down triangle (getting farther)
0b00000001,
0b00000011,
0b00000111,
0b00001111,
0b00011111,
0b00111111,
0b00011111,
0b00001111,
0b00000111,
0b00000011,
0b00000001
};
const uint8_t BITMAP_FoxHuntFlat[11] =
{ // equals sign (stable)
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010,
0b00010010
};
const uint8_t BITMAP_FoxHuntBars[11] =
{ // ascending bars = S-meter (staircase) gauge mode (bit0 = top row)
0b01000000,
0b01000000,
0b00000000,
0b01110000,
0b01110000,
0b00000000,
0b01111100,
0b01111100,
0b00000000,
0b01111111,
0b01111111
};
const uint8_t BITMAP_FoxHuntGraph[15] =
{ // sine wave = signal-history gauge mode (bit0 = top row)
0b00001000,
0b00000100,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000
};
const uint8_t BITMAP_FoxHuntTx[16] =
{
0b00011100,
0b00100010,
0b01000001,
0b00011100,
0b00100010,
0b00000000,
0b00001000,
0b00011100,
0b00011100,
0b00001000,
0b00000000,
0b00100010,
0b00011100,
0b01000001,
0b00100010,
0b00011100
};
#endif
#ifndef ENABLE_CUSTOM_MENU_LAYOUT #ifndef ENABLE_CUSTOM_MENU_LAYOUT
const uint8_t BITMAP_CurrentIndicator[8] = { const uint8_t BITMAP_CurrentIndicator[8] = {
0xFF, 0xFF,
+11
View File
@@ -45,6 +45,17 @@ extern const uint8_t BITMAP_compand[6];
extern const uint8_t BITMAP_NOAA[12]; extern const uint8_t BITMAP_NOAA[12];
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
extern const uint8_t BITMAP_FoxHuntSignal[10];
extern const uint8_t BITMAP_FoxHuntSpeaker[10];
extern const uint8_t BITMAP_FoxHuntUp[11];
extern const uint8_t BITMAP_FoxHuntDown[11];
extern const uint8_t BITMAP_FoxHuntFlat[11];
extern const uint8_t BITMAP_FoxHuntBars[11];
extern const uint8_t BITMAP_FoxHuntGraph[15];
extern const uint8_t BITMAP_FoxHuntTx[16];
#endif
#ifndef ENABLE_CUSTOM_MENU_LAYOUT #ifndef ENABLE_CUSTOM_MENU_LAYOUT
extern const uint8_t BITMAP_CurrentIndicator[8]; extern const uint8_t BITMAP_CurrentIndicator[8];
#endif #endif
+44 -1
View File
@@ -54,6 +54,17 @@ static int16_t currentBrightness = 0;
static int16_t targetBrightness = 0; static int16_t targetBrightness = 0;
static int16_t fadeStep = 0; static int16_t fadeStep = 0;
static void BACKLIGHT_SetHardwareBrightness(uint8_t brightness);
#ifdef ENABLE_FEAT_F4HWN
// Power-on fade-in tuning.
// STEPS = number of intermediate brightness stops (smoothness).
// STEP_MS = pacing between stops.
// STEPS * STEP_MS ~= total fade duration in ms.
#define BL_STARTUP_FADE_STEPS 40
#define BL_STARTUP_FADE_STEP_MS 12
#endif
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
const uint8_t value[] = { const uint8_t value[] = {
0, // 0 off 0, // 0 off
@@ -130,6 +141,37 @@ void BACKLIGHT_UpdateTickless(void) {
} }
} }
#ifdef ENABLE_FEAT_F4HWN
// Soft, progressive power-on fade-in.
// Ramps from the current brightness (0 at power-on) to targetBrightness using
// a smoothstep (3x^2 - 2x^3) easing curve. Easing gently at both ends reads as
// a smooth, progressive fade instead of the abrupt linear ramp, and stepping
// through many fine stops keeps it fluid even with the 32-level PWM.
static void BACKLIGHT_FadeInStartup(void)
{
const int16_t from = currentBrightness; // 0 at power-on
const int16_t span = targetBrightness - from; // ramp amplitude
if (span <= 0) {
gUpdateBacklight = false;
return;
}
for (uint16_t s = 1; s < BL_STARTUP_FADE_STEPS; s++) {
// x in Q8 (0..256), e = smoothstep(x) in Q16 (0..65536)
uint32_t x = (uint32_t)s * 256 / BL_STARTUP_FADE_STEPS;
uint32_t e = (x * x * (768 - 2 * x)) >> 8;
currentBrightness = from + (int16_t)(((uint32_t)span * e) >> 16);
BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness);
SYSTEM_DelayMs(BL_STARTUP_FADE_STEP_MS);
}
currentBrightness = targetBrightness;
BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness);
gUpdateBacklight = false;
}
#endif
void BACKLIGHT_TurnOn(void) void BACKLIGHT_TurnOn(void)
{ {
#ifdef ENABLE_FEAT_F4HWN_SLEEP #ifdef ENABLE_FEAT_F4HWN_SLEEP
@@ -163,10 +205,11 @@ void BACKLIGHT_TurnOn(void)
if(startup) if(startup)
#endif #endif
{ {
BACKLIGHT_UpdateTickless();
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
BACKLIGHT_FadeInStartup();
BACKLIGHT_Sound(); BACKLIGHT_Sound();
#else #else
BACKLIGHT_UpdateTickless();
startup = false; startup = false;
#endif #endif
} }
+7 -1
View File
@@ -51,7 +51,13 @@ static const AddrMapping_t ADDR_MAPPINGS[] = {
_MK_MAPPING(0x008000, 0x008000, 0x00886E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000) 0x008000 -> 0x00880E _MK_MAPPING(0x008000, 0x008000, 0x00886E), // 1024 MR + 7 VFO Attributes * 2 Bytes (ex 0x002000) 0x008000 -> 0x00880E
// List name * 4 Bytes 0x00880E -> 0x00886E // List name * 4 Bytes 0x00880E -> 0x00886E
_MK_MAPPING(0x009000, 0x009000, 0x0090D6), // 14 VFO * 16 Bytes (ex 0x001000) _MK_MAPPING(0x009000, 0x009000, 0x0090E7), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old
// 0x90D6 bound was 10 B short: it truncated the
// 470 MHz VFO1 record at 0x90D0 -> 0x90DF)
// Fox Hunt settings * 7 Bytes 0x90E0 -> 0x90E7
// (ENABLE_FEAT_F4HWN_FOXHUNT, written directly by
// app/foxhunt.c; concatenated here so aircopy clones
// them together with the VFOs)
_MK_MAPPING(0x00A000, 0x00A000, 0x00A170), // Settings * 16 Bytes (ex 0x004000) 0x00A000 -> 0x00A010 _MK_MAPPING(0x00A000, 0x00A000, 0x00A170), // Settings * 16 Bytes (ex 0x004000) 0x00A000 -> 0x00A010
// Settings * 16 Bytes (ex 0x005000) 0x00A010 -> 0x00A020 // Settings * 16 Bytes (ex 0x005000) 0x00A010 -> 0x00A020
+6 -2
View File
@@ -284,9 +284,13 @@ void PY25Q16_WriteBuffer(uint32_t Address, const void *pBuffer, uint32_t Size, b
if (0 != memcmp(pBuffer, (char *)SectorCache + SecOffset, SecSize)) if (0 != memcmp(pBuffer, (char *)SectorCache + SecOffset, SecSize))
{ {
bool Erase = false; bool Erase = false;
const uint8_t *oldData = SectorCache + SecOffset;
const uint8_t *newData = (const uint8_t *)pBuffer;
for (uint32_t i = 0; i < SecSize; i++) for (uint32_t i = 0; i < SecSize; i++)
{ {
if (0xff != SectorCache[SecOffset + i]) // NOR flash programming can only change bits from 1 to 0.
if ((oldData[i] & newData[i]) != newData[i])
{ {
Erase = true; Erase = true;
break; break;
@@ -491,4 +495,4 @@ void DMA1_Channel4_5_6_7_IRQHandler()
TC_Flag = true; TC_Flag = true;
} }
} }
+1 -1
View File
@@ -260,7 +260,7 @@ void ST7565_FillScreen(uint8_t value)
// D=0, display OFF // D=0, display OFF
#define ST7565_CMD_DISPLAY_ON_OFF 0xAE #define ST7565_CMD_DISPLAY_ON_OFF 0xAE
uint8_t cmds[] = { const uint8_t cmds[] = {
ST7565_CMD_BIAS_SELECT | 0, // Select bias setting: 1/9 ST7565_CMD_BIAS_SELECT | 0, // Select bias setting: 1/9
ST7565_CMD_COM_DIRECTION | (0 << 3), // Set output direction of COM: normal ST7565_CMD_COM_DIRECTION | (0 << 3), // Set output direction of COM: normal
ST7565_CMD_SEG_DIRECTION | 1, // Set scan direction of SEG: reverse ST7565_CMD_SEG_DIRECTION | 1, // Set scan direction of SEG: reverse
+9 -2
View File
@@ -123,6 +123,9 @@ static uint8_t K5VIEWER_StateFlags(void)
#ifdef ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER
static bool K5VIEWER_HasPendingRfLogUpdate(void) static bool K5VIEWER_HasPendingRfLogUpdate(void)
{ {
if (!RXTX_LOG_IsEnabled())
rfLogHistoryBefore = RXTX_LOG_K5VIEWER_HISTORY_START;
if ((gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_RESTART) != 0) { if ((gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_RESTART) != 0) {
gSerialViewerFeatures &= ~SERIAL_VIEWER_FEATURE_RF_LOG_RESTART; gSerialViewerFeatures &= ~SERIAL_VIEWER_FEATURE_RF_LOG_RESTART;
rfLogSent = false; rfLogSent = false;
@@ -157,14 +160,18 @@ static void K5VIEWER_SendRfLog(void)
previousRfLogSignature = RXTX_LOG_K5ViewerSignature(); previousRfLogSignature = RXTX_LOG_K5ViewerSignature();
rfLogSent = true; rfLogSent = true;
K5VIEWER_SendRfLogFrameHeader(K5VIEWER_TYPE_RXTX_LOG, RXTX_LOG_K5VIEWER_PACKET_SIZE); const uint16_t size = RXTX_LOG_IsEnabled()
? RXTX_LOG_K5VIEWER_PACKET_SIZE
: RXTX_LOG_K5VIEWER_STATUS_PACKET_SIZE;
K5VIEWER_SendRfLogFrameHeader(K5VIEWER_TYPE_RXTX_LOG, size);
RXTX_LOG_SendK5ViewerPacket(K5VIEWER_Send); RXTX_LOG_SendK5ViewerPacket(K5VIEWER_Send);
K5VIEWER_SendRfLogFrameEnd(); K5VIEWER_SendRfLogFrameEnd();
} }
static bool K5VIEWER_HasPendingRfLogHistory(void) static bool K5VIEWER_HasPendingRfLogHistory(void)
{ {
return (gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_HISTORY) != 0 && return RXTX_LOG_IsEnabled() &&
(gSerialViewerFeatures & SERIAL_VIEWER_FEATURE_RF_LOG_HISTORY) != 0 &&
rfLogHistoryBefore != 0; rfLogHistoryBefore != 0;
} }
+3
View File
@@ -149,6 +149,9 @@ extern DCS_CodeType_t gCurrentCodeType;
extern VfoState_t VfoState[2]; extern VfoState_t VfoState[2];
// Human-readable label per VfoState_t (defined in ui/main.c), e.g. "TX DISABLE".
extern const char *const VfoStateStr[];
bool RADIO_CheckValidList(uint8_t scanList); bool RADIO_CheckValidList(uint8_t scanList);
void RADIO_NextValidList(int8_t direction); void RADIO_NextValidList(int8_t direction);
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList); bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList);
+21 -47
View File
@@ -1210,7 +1210,7 @@ void SETTINGS_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
PY25Q16_WriteBuffer(OffsetVFO, Buf, 0x10, false); PY25Q16_WriteBuffer(OffsetVFO, Buf, 0x10, false);
SETTINGS_UpdateChannel(Channel, pVFO, true, true, true); SETTINGS_UpdateChannel(Channel, pVFO, true);
if (IS_MR_CHANNEL(Channel)) { if (IS_MR_CHANNEL(Channel)) {
#ifndef ENABLE_KEEP_MEM_NAME #ifndef ENABLE_KEEP_MEM_NAME
@@ -1241,58 +1241,32 @@ void SETTINGS_SaveChannelName(uint16_t channel, const char * name)
PY25Q16_WriteBuffer(0x004000 + offset, buf, 0x10, false); PY25Q16_WriteBuffer(0x004000 + offset, buf, 0x10, false);
} }
void SETTINGS_UpdateChannel(uint16_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)
{ {
#ifdef ENABLE_NOAA #ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(channel)) if (IS_NOAA_CHANNEL(channel))
return;
#endif #endif
{
ChannelAttributes_t state;
ChannelAttributes_t att = {
.band = 0x7,
.compander = 0,
.unused_1 = 0,
.unused_2 = 0,
.exclude = 0,
.scanlist = 0,
}; // default attributes
// 0x0D60 ChannelAttributes_t att = {
PY25Q16_ReadBuffer(0x008000 + (channel * 2), &state, 2); .band = 0x7,
.compander = 0,
.unused_1 = 0,
.unused_2 = 0,
.exclude = 0,
.scanlist = 0,
};
if (keep) { if (keep) {
att.band = pVFO->Band; att.band = pVFO->Band;
att.compander = pVFO->Compander; att.compander = pVFO->Compander;
att.unused_1 = 0; att.scanlist = pVFO->SCANLIST_PARTICIPATION;
att.unused_2 = 0;
att.exclude = 0;
att.scanlist = pVFO->SCANLIST_PARTICIPATION;
if (check && state.__val == att.__val)
return; // no change in the attributes
}
state.__val = att.__val;
#ifndef ENABLE_FEAT_F4HWN
save = true;
#endif
if(save)
{
uint16_t buf[MR_CHANNELS_MAX + 24];
PY25Q16_ReadBuffer(0x008000, buf, sizeof(buf));
buf[channel] = state.__val;
PY25Q16_WriteBuffer(0x008000, buf, sizeof(buf), false);
}
MR_SetChannelAttributes(channel, &att);
if (IS_MR_CHANNEL(channel)) { // it's a memory channel
if (!keep) {
// clear/reset the channel name
SETTINGS_SaveChannelName(channel, "");
}
}
} }
MR_SetChannelAttributes(channel, &att);
if (IS_MR_CHANNEL(channel) && !keep)
SETTINGS_SaveChannelName(channel, "");
} }
void SETTINGS_WriteBuildOptions(void) void SETTINGS_WriteBuildOptions(void)
+4 -1
View File
@@ -132,6 +132,9 @@ enum ACTION_OPT_t {
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_RXTX_LOG #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG
ACTION_OPT_RXTX_LOG, ACTION_OPT_RXTX_LOG,
#endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
ACTION_OPT_FOXHUNT,
#endif #endif
ACTION_OPT_LEN ACTION_OPT_LEN
}; };
@@ -346,7 +349,7 @@ void SETTINGS_SaveSettings(void);
void SETTINGS_SaveChannelName(uint16_t channel, const char * name); 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_SaveChannel(uint16_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode);
void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration); void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration);
void SETTINGS_UpdateChannel(uint16_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);
void SETTINGS_WriteBuildOptions(void); void SETTINGS_WriteBuildOptions(void);
#ifdef ENABLE_FEAT_F4HWN_RESUME_STATE #ifdef ENABLE_FEAT_F4HWN_RESUME_STATE
void SETTINGS_WriteCurrentState(void); void SETTINGS_WriteCurrentState(void);
+78 -17
View File
@@ -68,6 +68,7 @@ center_line_t center_line = CENTER_LINE_NONE;
#ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS #ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS
#define SCAN_PROGRESS_MR_CHANNEL_BYTES ((MR_CHANNELS_MAX + 7u) / 8u) #define SCAN_PROGRESS_MR_CHANNEL_BYTES ((MR_CHANNELS_MAX + 7u) / 8u)
#define SCAN_LIST_NAME_HOLD_500MS (2000u / 500u)
static bool gScanProgressSessionActive; static bool gScanProgressSessionActive;
static bool gScanProgressSessionIsMemory; static bool gScanProgressSessionIsMemory;
@@ -82,6 +83,7 @@ static bool gScanProgressPrevResetVfosFlag;
static bool gScanProgressForceRebuild; static bool gScanProgressForceRebuild;
static uint16_t gScanProgressLastMemoryIndex; static uint16_t gScanProgressLastMemoryIndex;
static uint8_t gScanProgressPriorityState; static uint8_t gScanProgressPriorityState;
static uint8_t gScanListNameCountdown_500ms;
#define SCAN_PROGRESS_PRIORITY_LABEL_MASK 0x03u #define SCAN_PROGRESS_PRIORITY_LABEL_MASK 0x03u
#define SCAN_PROGRESS_PRIORITY_SEEN_SHIFT 2 #define SCAN_PROGRESS_PRIORITY_SEEN_SHIFT 2
#define SCAN_PROGRESS_PRIORITY_SEEN_MASK 0x1cu #define SCAN_PROGRESS_PRIORITY_SEEN_MASK 0x1cu
@@ -90,15 +92,24 @@ static uint8_t gScanProgressPriorityState;
#define SCAN_PROGRESS_PRIORITY_HOLD_FRAMES 6 #define SCAN_PROGRESS_PRIORITY_HOLD_FRAMES 6
#endif #endif
#if defined(ENABLE_FEAT_F4HWN_BEAM) || defined(ENABLE_FEAT_F4HWN_SCAN_PROGRESS)
// Shared center-line renderer: clear the line and print bold text on it.
static void UI_MAIN_DrawCenterBoldLine(const char *text, uint8_t start)
{
#ifdef ENABLE_FEAT_F4HWN
const uint8_t line = isMainOnly() ? 5 : 3;
#else
const uint8_t line = 3;
#endif
memset(gFrameBuffer[line], 0, LCD_WIDTH);
UI_PrintStringSmallBold(text, start, LCD_WIDTH - 1, line);
}
#endif
#ifdef ENABLE_FEAT_F4HWN_BEAM #ifdef ENABLE_FEAT_F4HWN_BEAM
static void UI_MAIN_DrawBeamLine(void) static void UI_MAIN_DrawBeamLine(void)
{ {
const char *text; const char *text;
#ifdef ENABLE_FEAT_F4HWN
const unsigned int line = isMainOnly() ? 5 : 3;
#else
const unsigned int line = 3;
#endif
switch (gBeamStatus) { switch (gBeamStatus) {
case BEAM_STATUS_TX_WAIT: case BEAM_STATUS_TX_WAIT:
@@ -125,12 +136,11 @@ static void UI_MAIN_DrawBeamLine(void)
break; break;
} }
memset(gFrameBuffer[line], 0, LCD_WIDTH); UI_MAIN_DrawCenterBoldLine(text, 2);
UI_PrintStringSmallBold(text, 2, 127, line);
} }
#endif #endif
const char *VfoStateStr[] = { const char *const VfoStateStr[] = {
[VFO_STATE_NORMAL]="", [VFO_STATE_NORMAL]="",
[VFO_STATE_BUSY]="BUSY", [VFO_STATE_BUSY]="BUSY",
[VFO_STATE_BAT_LOW]="BAT LOW", [VFO_STATE_BAT_LOW]="BAT LOW",
@@ -214,6 +224,7 @@ static void ScanProgress_ResetSession(void)
gScanProgressForceRebuild = false; gScanProgressForceRebuild = false;
gScanProgressLastMemoryIndex = 0; gScanProgressLastMemoryIndex = 0;
gScanProgressPriorityState = 0; gScanProgressPriorityState = 0;
gScanListNameCountdown_500ms = 0;
} }
void UI_MAIN_NotifyScanProgressDataChanged(void) void UI_MAIN_NotifyScanProgressDataChanged(void)
@@ -222,6 +233,13 @@ void UI_MAIN_NotifyScanProgressDataChanged(void)
gUpdateStatus = true; gUpdateStatus = true;
} }
void UI_MAIN_NotifyScanListChanged(void)
{
UI_MAIN_NotifyScanProgressDataChanged();
gScanListNameCountdown_500ms = SCAN_LIST_NAME_HOLD_500MS;
gUpdateDisplay = true;
}
static inline void ScanProgress_SetBit(uint8_t *map, uint16_t ch) static inline void ScanProgress_SetBit(uint8_t *map, uint16_t ch)
{ {
map[ch >> 3] |= (uint8_t)(1u << (ch & 7)); map[ch >> 3] |= (uint8_t)(1u << (ch & 7));
@@ -243,6 +261,33 @@ static uint8_t ScanProgress_GetActiveScanList(void)
return scan_list; return scan_list;
} }
static void UI_MAIN_DrawScanListName(void)
{
const uint8_t scan_list = ScanProgress_GetActiveScanList();
char text[16];
// Manual formatting instead of snprintf: much smaller on a divide-less M0 core
strcpy(text, "SCAN LIST ");
char *p = text + 10; // sizeof("SCAN LIST ") - 1
if (scan_list > MR_CHANNELS_LIST) {
*p++ = 'A'; *p++ = 'L'; *p++ = 'L';
} else {
const char *name = gListName[scan_list - 1];
if (IsEmptyName(name, sizeof(gListName[0]))) {
*p++ = (char)('0' + scan_list / 10);
*p++ = (char)('0' + scan_list % 10);
} else {
for (uint8_t i = 0; i < 3 && name[i]; i++)
*p++ = name[i];
}
}
*p = '\0';
UI_MAIN_DrawCenterBoldLine(text, 0);
}
static bool ScanProgress_ChannelBelongsToList(uint16_t channel, const ChannelAttributes_t *att, uint8_t scan_list) static bool ScanProgress_ChannelBelongsToList(uint16_t channel, const ChannelAttributes_t *att, uint8_t scan_list)
{ {
if (!IS_MR_CHANNEL(channel)) if (!IS_MR_CHANNEL(channel))
@@ -490,6 +535,12 @@ static bool UI_DrawScanProgress(void)
return false; return false;
} }
// Right after a scan-list change, briefly show its name instead of the progress bar
if (show_memory && gScanListNameCountdown_500ms > 0) {
UI_MAIN_DrawScanListName();
return true;
}
if (show_memory) { if (show_memory) {
const uint8_t scan_list = ScanProgress_GetActiveScanList(); const uint8_t scan_list = ScanProgress_GetActiveScanList();
const bool reset_vfos_edge = gFlagResetVfos && !gScanProgressPrevResetVfosFlag; const bool reset_vfos_edge = gFlagResetVfos && !gScanProgressPrevResetVfosFlag;
@@ -1167,6 +1218,10 @@ void UI_MAIN_PrintAGC(bool now)
void UI_MAIN_TimeSlice500ms(void) void UI_MAIN_TimeSlice500ms(void)
{ {
if(gScreenToDisplay==DISPLAY_MAIN) { if(gScreenToDisplay==DISPLAY_MAIN) {
#ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS
if (gScanListNameCountdown_500ms > 0 && --gScanListNameCountdown_500ms == 0)
gUpdateDisplay = true;
#endif
#ifdef ENABLE_AGC_SHOW_DATA #ifdef ENABLE_AGC_SHOW_DATA
UI_MAIN_PrintAGC(true); UI_MAIN_PrintAGC(true);
return; return;
@@ -1526,7 +1581,11 @@ void UI_DisplayMain(void)
} }
} }
else { else {
if(RxOnVfofrequency == frequency && !isMainOnly()) { if(RxOnVfofrequency == frequency && !isMainOnly()
#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI)
&& !CHFRSCANNER_HasScanRssiSparkline()
#endif
) {
//UI_PrintStringSmallNormal(">>", 8, 0, line); //UI_PrintStringSmallNormal(">>", 8, 0, line);
//memcpy(p_line0 + 14, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); //memcpy(p_line0 + 14, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
GUI_DisplaySmallest(">>", 8, RxLine == 0 ? 1 : 33, false, true); GUI_DisplaySmallest(">>", 8, RxLine == 0 ? 1 : 33, false, true);
@@ -1538,11 +1597,6 @@ void UI_DisplayMain(void)
#endif #endif
} }
#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI)
if (vfo_num == gEeprom.RX_VFO && gScanStateDir != SCAN_OFF && !FUNCTION_IsRx())
UI_MAIN_DrawScanRssiSparkline(line);
#endif
if((gScanStateDir == SCAN_OFF || vfo_num != gEeprom.RX_VFO) && TX_freq_check(frequency) != 0 && gEeprom.VfoInfo[vfo_num].TX_LOCK == true) if((gScanStateDir == SCAN_OFF || vfo_num != gEeprom.RX_VFO) && TX_freq_check(frequency) != 0 && gEeprom.VfoInfo[vfo_num].TX_LOCK == true)
{ {
if (!FUNCTION_IsRx() || RxOnVfofrequency != frequency) if (!FUNCTION_IsRx() || RxOnVfofrequency != frequency)
@@ -1726,8 +1780,6 @@ void UI_DisplayMain(void)
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS #ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
{
}
} }
#endif #endif
@@ -2055,7 +2107,11 @@ void UI_DisplayMain(void)
#ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS #ifdef ENABLE_FEAT_F4HWN_RESCUE_OPS
const char dir_list[][2] = {"", "+", "-", "D"}; const char dir_list[][2] = {"", "+", "-", "D"};
if(gTxVfo->TX_OFFSET_FREQUENCY_DIRECTION != 0 && gTxVfo->pTX == &gTxVfo->freq_config_RX && !vfoInfo->FrequencyReverse) if(gRemoveOffset &&
vfoInfo == gTxVfo &&
gTxVfo->TX_OFFSET_FREQUENCY_DIRECTION != 0 &&
gTxVfo->pTX == &gTxVfo->freq_config_RX &&
!vfoInfo->FrequencyReverse)
{ {
i = 3; i = 3;
} }
@@ -2198,6 +2254,11 @@ void UI_DisplayMain(void)
#endif #endif
} }
#if defined(ENABLE_FEAT_F4HWN_SCAN_FASTER) && defined(ENABLE_FEAT_F4HWN_SCAN_RSSI)
if (gScanStateDir != SCAN_OFF && !FUNCTION_IsRx())
UI_MAIN_DrawScanRssiSparkline(isMainOnly() ? 0 : (uint8_t)(gEeprom.RX_VFO * 4u));
#endif
#ifdef ENABLE_AGC_SHOW_DATA #ifdef ENABLE_AGC_SHOW_DATA
center_line = CENTER_LINE_IN_USE; center_line = CENTER_LINE_IN_USE;
UI_MAIN_PrintAGC(false); UI_MAIN_PrintAGC(false);
+2
View File
@@ -55,8 +55,10 @@ void UI_DisplayMain(void);
#ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS #ifdef ENABLE_FEAT_F4HWN_SCAN_PROGRESS
void UI_MAIN_NotifyScanProgressDataChanged(void); void UI_MAIN_NotifyScanProgressDataChanged(void);
void UI_MAIN_NotifyScanListChanged(void);
#else #else
static inline void UI_MAIN_NotifyScanProgressDataChanged(void) {} static inline void UI_MAIN_NotifyScanProgressDataChanged(void) {}
static inline void UI_MAIN_NotifyScanListChanged(void) {}
#endif #endif
#ifdef ENABLE_AGC_SHOW_DATA #ifdef ENABLE_AGC_SHOW_DATA
+4 -1
View File
@@ -525,6 +525,9 @@ const t_sidefunction gSubMenu_SIDEFUNCTIONS[] =
#ifdef ENABLE_FEAT_F4HWN_RXTX_LOG #ifdef ENABLE_FEAT_F4HWN_RXTX_LOG
{"RF LOG", ACTION_OPT_RXTX_LOG}, {"RF LOG", ACTION_OPT_RXTX_LOG},
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
{"FOX HUNT\nBEACON", ACTION_OPT_FOXHUNT},
#endif
#endif #endif
}; };
@@ -1187,7 +1190,7 @@ void UI_DisplayMenu(void)
if (page == p++) { if (page == p++) {
// Page 0: firmware identity. // Page 0: firmware identity.
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
sprintf(String, "%s\n%s", AUTHOR_STRING_2, VERSION_STRING_2); sprintf(String, "%s\n%s", AUTHOR_STRING_2, DISPLAY_VERSION_STRING_2);
UI_PrintStringSmallNormal(Edition, menu_item_x1 - 1, menu_item_x2, 6); UI_PrintStringSmallNormal(Edition, menu_item_x1 - 1, menu_item_x2, 6);
#else #else
sprintf(String, "%u.%02uV\n%u%%", sprintf(String, "%u.%02uV\n%u%%",
+1 -1
View File
@@ -48,7 +48,7 @@ bool gAskToSave;
bool gAskToDelete; bool gAskToDelete;
void (*UI_DisplayFunctions[])(void) = { void (*const UI_DisplayFunctions[])(void) = {
[DISPLAY_MAIN] = &UI_DisplayMain, [DISPLAY_MAIN] = &UI_DisplayMain,
[DISPLAY_MENU] = &UI_DisplayMenu, [DISPLAY_MENU] = &UI_DisplayMenu,
[DISPLAY_SCANNER] = &UI_DisplayScanner, [DISPLAY_SCANNER] = &UI_DisplayScanner,
+23 -6
View File
@@ -20,6 +20,7 @@
#include "driver/py25q16.h" #include "driver/py25q16.h"
#include "driver/st7565.h" #include "driver/st7565.h"
#include "external/printf/printf.h" #include "external/printf/printf.h"
#include "font.h"
#include "helper/battery.h" #include "helper/battery.h"
#include "settings.h" #include "settings.h"
#include "misc.h" #include "misc.h"
@@ -312,17 +313,33 @@ void UI_DisplayWelcome(void)
UI_PrintString(WelcomeString1, 0, 127, 2, 10); UI_PrintString(WelcomeString1, 0, 127, 2, 10);
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
UI_PrintStringSmallNormal(Version, 0, 128, 4); const size_t version_width = strlen(DisplayVersion) * (ARRAY_SIZE(gFontSmall[0]) + 1u);
const uint8_t version_x = version_width < LCD_WIDTH
? (uint8_t)((LCD_WIDTH - version_width + 1u) / 2u)
: 0u;
const uint8_t capsule_left = version_x > 2u ? (uint8_t)(version_x - 3u) : 0u;
const size_t capsule_right_candidate = version_x + version_width + 2u;
const uint8_t capsule_right = capsule_right_candidate < LCD_WIDTH
? (uint8_t)capsule_right_candidate
: (LCD_WIDTH - 1u);
UI_DrawLineBuffer(gFrameBuffer, 0, 35, 18, 35, 1); UI_PrintStringSmallNormal(DisplayVersion, version_x, 0, 4);
gFrameBuffer[4][19] ^= 0x7F;
for (uint8_t x = 20; x < 108; x++) if (capsule_left > 0u)
{
UI_DrawLineBuffer(gFrameBuffer, 0, 35, capsule_left - 1u, 35, 1);
}
gFrameBuffer[4][capsule_left] ^= 0x7F;
for (uint8_t x = capsule_left + 1u; x < capsule_right; x++)
{ {
gFrameBuffer[4][x] ^= 0xFF; gFrameBuffer[4][x] ^= 0xFF;
gFrameBuffer[3][x] ^= 0x80; gFrameBuffer[3][x] ^= 0x80;
} }
gFrameBuffer[4][108] ^= 0x7F; gFrameBuffer[4][capsule_right] ^= 0x7F;
UI_DrawLineBuffer(gFrameBuffer, 109, 35, 127, 35, 1); if (capsule_right < LCD_WIDTH - 1u)
{
UI_DrawLineBuffer(gFrameBuffer, capsule_right + 1u, 35, LCD_WIDTH - 1u, 35, 1);
}
/* /*
#ifdef ENABLE_FEAT_F4HWN_MEM #ifdef ENABLE_FEAT_F4HWN_MEM
+6 -5
View File
@@ -6,11 +6,12 @@
#endif #endif
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
const char Version[] = AUTHOR_STRING_2 " " VERSION_STRING_2; const char Version[] = AUTHOR_STRING_2 " " VERSION_STRING_2;
const char Edition[] = EDITION_STRING; const char DisplayVersion[] = AUTHOR_STRING_2 " " DISPLAY_VERSION_STRING_2;
const char BuildDate[] = __DATE__; const char Edition[] = EDITION_STRING;
const char BuildTime[] = __TIME__; const char BuildDate[] = __DATE__;
const char BuildCommit[] = BUILD_COMMIT; const char BuildTime[] = __TIME__;
const char BuildCommit[] = BUILD_COMMIT;
#else #else
const char Version[] = AUTHOR_STRING VER; const char Version[] = AUTHOR_STRING VER;
#endif #endif
+1
View File
@@ -23,6 +23,7 @@ extern const char UART_Version[];
#endif #endif
#ifdef ENABLE_FEAT_F4HWN #ifdef ENABLE_FEAT_F4HWN
extern const char DisplayVersion[];
extern const char Edition[]; extern const char Edition[];
extern const char BuildDate[]; extern const char BuildDate[];
extern const char BuildTime[]; extern const char BuildTime[];
+23
View File
@@ -19,6 +19,8 @@ message("Build type: " ${CMAKE_BUILD_TYPE})
enable_language(C ASM) enable_language(C ASM)
option(DEV "Prepare the rolling Fusion development firmware" OFF)
find_package(Git QUIET) find_package(Git QUIET)
set(BUILD_COMMIT "unknown") set(BUILD_COMMIT "unknown")
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
@@ -71,7 +73,17 @@ else()
set(EXE_NAME "firmware") set(EXE_NAME "firmware")
endif() endif()
if(DEV)
if(NOT "${TARGET}" STREQUAL "f4hwn.fusion")
message(FATAL_ERROR "DEV is only supported for the Fusion target")
endif()
set(DISPLAY_VERSION_STRING_2 "${VERSION_STRING_2} Dev")
else()
set(DISPLAY_VERSION_STRING_2 "${VERSION_STRING_2}")
endif()
message("EXE_NAME = " ${EXE_NAME}) message("EXE_NAME = " ${EXE_NAME})
message("Development build = " ${DEV})
add_executable(${EXE_NAME}) add_executable(${EXE_NAME})
@@ -110,6 +122,17 @@ add_custom_command(
COMMENT "Generating .bin file" COMMENT "Generating .bin file"
) )
if(DEV)
add_custom_command(
TARGET ${EXE_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin"
"${CMAKE_SOURCE_DIR}/archive/f4hwn.fusion.development.bin"
COMMENT "Preparing archive/f4hwn.fusion.development.bin"
)
endif()
# Generate .hex file # Generate .hex file
add_custom_command( add_custom_command(
TARGET ${EXE_NAME} TARGET ${EXE_NAME}
+4 -1
View File
@@ -9,6 +9,7 @@
"toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake", "toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release", "CMAKE_BUILD_TYPE": "Release",
"DEV": false,
"ENABLE_LTO": false, "ENABLE_LTO": false,
"ENABLE_FMRADIO": false, "ENABLE_FMRADIO": false,
"ENABLE_UART": true, "ENABLE_UART": true,
@@ -72,6 +73,7 @@
"ENABLE_FEAT_F4HWN_SCAN_RSSI": false, "ENABLE_FEAT_F4HWN_SCAN_RSSI": false,
"ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": false, "ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": false,
"ENABLE_FEAT_F4HWN_BEAM": false, "ENABLE_FEAT_F4HWN_BEAM": false,
"ENABLE_FEAT_F4HWN_FOXHUNT": false,
"ENABLE_FEAT_F4HWN_RXTX_LOG": false, "ENABLE_FEAT_F4HWN_RXTX_LOG": false,
"ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false,
"ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": false,
@@ -81,7 +83,7 @@
"ENABLE_UART_RW_BK_REGS": false, "ENABLE_UART_RW_BK_REGS": false,
"ENABLE_SWD": false, "ENABLE_SWD": false,
"VERSION_STRING_1": "v0.22", "VERSION_STRING_1": "v0.22",
"VERSION_STRING_2": "v5.7.0" "VERSION_STRING_2": "v5.8.0"
} }
}, },
{ {
@@ -206,6 +208,7 @@
"ENABLE_FEAT_F4HWN_SCAN_RSSI": true, "ENABLE_FEAT_F4HWN_SCAN_RSSI": true,
"ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": true, "ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": true,
"ENABLE_FEAT_F4HWN_BEAM": true, "ENABLE_FEAT_F4HWN_BEAM": true,
"ENABLE_FEAT_F4HWN_FOXHUNT": true,
"ENABLE_FEAT_F4HWN_RXTX_LOG": true, "ENABLE_FEAT_F4HWN_RXTX_LOG": true,
"ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false, "ENABLE_FEAT_F4HWN_RXTX_LOG_WRAP": false,
"ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": true, "ENABLE_FEAT_F4HWN_RXTX_LOG_K5VIEWER": true,
+238 -140
View File
@@ -36,151 +36,238 @@ Anyway, have fun.
> _FR - A propos de CHIRP, comme pour beaucoup d'autres firmwares, vous devez utiliser un pilote dédié. Le driver CHIRP correspondant est désormais fourni avec chaque release de ce dépôt, ce qui permet de récupérer ensemble le firmware et son pilote depuis la page des [Releases](https://github.com/armel/uv-k1-k5v3-firmware-custom/releases)._ > _FR - A propos de CHIRP, comme pour beaucoup d'autres firmwares, vous devez utiliser un pilote dédié. Le driver CHIRP correspondant est désormais fourni avec chaque release de ce dépôt, ce qui permet de récupérer ensemble le firmware et son pilote depuis la page des [Releases](https://github.com/armel/uv-k1-k5v3-firmware-custom/releases)._
> [!CAUTION] > [!CAUTION]
> EN - I recommend to backup your calibration data with [uvtools2](https://armel.github.io/uvtools2/) just after flashing this firmware. It's a good reflex to have. > EN - I recommend backing up your calibration data with [UV Studio](https://armel.github.io/uvstudio/#dump-calib) immediately after flashing this firmware. It is a good habit to adopt.
> >
> _FR - Je recommande de sauvegarder vos données de calibration avec [uvtools2](https://armel.github.io/uvtools2/) juste après avoir flashé ce firmware. C'est un bon réflexe à avoir._ > _FR - Je recommande de sauvegarder vos données de calibration avec [UV Studio](https://armel.github.io/uvstudio/#dump-calib) juste après avoir flashé ce firmware. C'est un bon réflexe à adopter._
# Donations # Donations
Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ and Carlos EA1IJ for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻 Special thanks to Jean-Cyrille F6IWW (3 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW (2 times), Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (4 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF (3 times), Eric KI1C / F4WFS (3 times), Phil G0ELM, Jérôme Lambert, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB (2 times), Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman, Stephen Oliver, Nicolas F4INE, William Bruno, Daniel OK2VLK, Tayler Chew, Peter DL7RFP, Philippe Kopp, Rune LA6YMA, Jeremy Luna, Steef Wagenaar (2 times), Zhuo BG7SGA, Jamie M0JLB, Antoine LIBERT, Vince K0DKR, Julia DF7JA, Ken 2E0UMK, Victor TI2SYS, Tobi DG9LAY, Deaglan K4DFQ, Catherine PALMER, Brian WA6JFK, Stéphane Hintzy, Roger F1HCN, Marcin Kusaj, Flavio Cottarelli, Bob N1MLZ, Carlos EA1IJ, Brian M7YLF, Giuseppe IT9LLH and 邓 月 for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
## Table of Contents ## Table of Contents
* [My Features](#main-features) * [Main features and improvements from F4HWN](#main-features-and-improvements-from-f4hwn)
* [Main Features from Egzumer](#main-features-from-egzumer) * [Main Features from Egzumer](#main-features-from-egzumer)
* [Manual](#manual) * [Manual](#manual)
* [Compiling and Building from Docker](#compiling-and-Building-from-docker) * [Compiling and Building from Docker](#compiling-and-Building-from-docker)
* [Flashing the Firmware with UVTools2](#flashing-the-firmware-with-uvtools2) * [Flashing the Firmware with UV Studio](#flashing-the-firmware-with-uv-studio)
* [Credits](#credits) * [Credits](#credits)
* [Other sources of information](#other-sources-of-information) * [Other sources of information](#other-sources-of-information)
* [License](#license) * [License](#license)
## Main features and improvements from F4HWN: ## Main features and improvements from F4HWN
* Fusion is now the reference edition of the project: ### Fusion edition
* all-in-one firmware for UV-K1 and UV-K5 V3,
* spectrum analyzer made by Fagci, Fusion is the reference edition of the project. It provides an all-in-one firmware for the UV-K1 and UV-K5 V3, including:
* commercial FM radio support,
* Vox and Aircopy support, - Fagci's spectrum analyzer,
* screenshots and K5Viewer support, - broadcast FM radio,
* advanced RX audio profiles and Audio Scope, - VOX and AirCopy,
* first-responder oriented options, - BEAM wireless channel transfer,
* small breakout game, - [UV Studio](https://armel.github.io/uvstudio/) with integrated K5Viewer screen mirroring, screenshots and remote keyboard control,
* improve default power settings level: - advanced RX audio profiles and Audio Scope,
* Low1 to Low5 (<~20mW, ~125mW, ~250mW, ~500mW, ~1W), - first-responder-oriented controls,
* Mid ~2W, - the Breakout game,
* High ~5W, - automatic RX/TX activity logging with RF Log,
* User (see SetPwr), - full Fox Hunt and Morse Beacon support.
* improve S-Meter (IARU Region 1 Technical Recommendation R.1 for VHF/UHF - [read more](https://hamwaves.com/decibel/en/)),
* S-Meter (S0/S9) Level EEPROM settings that were introduced in the Egzumer firmware are now ignored and replaced by hardcoded values to comply with the IARU Recommendation. ### Radio and signal handling
* improve bandscope (Spectrum Analyser):
* add channel name, - Reworked output-power levels:
* add save of some spectrum parameters, - `Low 1`: below approximately 20 mW,
* improve UI: - `Low 2`: approximately 125 mW,
* menu index is always visible, even if a menu is selected, - `Low 3`: approximately 250 mW,
* s-meter new design (Classic or Tiny), - `Low 4`: approximately 500 mW,
* MAIN ONLY screen mode, - `Low 5`: approximately 1 W,
* DUAL and CROSS screen mode, - `Mid`: approximately 2 W,
* RX blink on VFO RX, - `High`: approximately 5 W,
* RX LED blink, - `User`: configurable through `SetPwr`.
* Squelch level and Monitor, - S-meter calibrated according to the [IARU Region 1 recommendation for VHF/UHF](https://hamwaves.com/decibel/en/):
* Step value, - fixed S0 to S9+ values replace the former EEPROM S-meter thresholds,
* CTCSS or DCS value, - Classic and Tiny display styles are available.
* KeyLock message, - Configurable 12.5 kHz or 6.25 kHz narrow-FM bandwidth.
* last RX, - Per-channel TX lock.
* move BatTxt menu from 34/63 to 30/63 (just after BatSave menu 29/63), - Adjustable RX audio volume.
* rename BackLt to BLTime, - Advanced RX audio profiles for FM and AM reception.
* rename BltTRX to BLTxRx, - Regional frequency-lock profiles for amateur bands, PMR446, FRS, GMRS and MURS.
* improve memory channel input, - Support for 1600, 2200 and 3500 mAh battery profiles.
* improve keyboard frequency input,
* add percent and gauge to Air Copy, ### Spectrum analyzer
* improve audio bar,
* add backlight fading, - Channel names displayed in the spectrum view.
* add Audio Scope on TX, - Persistent spectrum settings.
* and more... - Faster and smoother spectrum rendering.
* new menu entries and changes: - Improved behavior when freezing the spectrum or disconnecting USB-C.
* add SetPwr menu to set User power (<20mW, 125mW, 250mW, 500mW, 1W, 2W or 5W), - Spectrum analyzer state can be restored automatically at startup.
* add SetPTT menu to set PTT mode (Classic or OnePush),
* add SetTOT menu to set TOT alert (Off, Sound, Visual, All), ### Scanning
* add SetCtr menu to set contrast (0 to 15),
* add SetInv menu to set screen in invert mode (Off or On), - Support for up to 24 named scan lists.
* add SetEOT menu to set EOT (End Of Transmission) alert (Off, Sound, Visual, All), - Each memory channel can be assigned to:
* add SetMet menu to set s-meter style (Classic or Tiny), - `OFF`,
* add SetLck menu to set what is locked (Keys or Keys + PTT), - one scan list from `01` to `24`,
* add SetGUI menu to set font size on the VFO baseline (Classic or Tiny), - `ALL`.
* add SetRxA menu to select RX audio profiles, - The `ALL` list scans every channel except those assigned to `OFF`.
* add TXLock menu to open TX on channel, - Automatic selection of the next valid list when the requested list is empty.
* add SetTmr menu to set RX and TX timers (Off or On), - Direct scan-list selection while scanning:
* add SetOff menu to set the delay before the transceiver goes into deep sleep (Off or 1 minute to 2 hours), - `00` selects `ALL`,
* add SetNFM menu to set Narrow width (12.5kHz or 6.25kHz), - `01` to `24` select the corresponding list.
* add SetVol menu to adjust RX audio volume, - Long press on `MENU` while scanning to exclude the current memory channel.
* add SetScn menu to set Scan mode - Up to 64 frequency exclusions.
* rename BatVol menu (52/63) to SysInf, which displays the firmware version in addition to the battery status, - Very fast scanning mode, reaching approximately 150 frequencies per second.
* improve PonMsg menu, - Scan progress, RSSI and detected CTCSS/DCS information.
* improve BackLt menu, - Configurable scan resume behavior.
* improve TxTOut menu, - Scan state can be restored automatically at startup.
* improve ScnRev menu (CARRIER from 250ms to 20s, STOP, TIMEOUT from 5s to 2m)
* improve KeyLck menu (OFF, delay from 15s to 10m) ### User interface
* add HAM CA F Lock band (for Canadian zone),
* add PMR 446 F Lock band, - Improved VFO screen with:
* add FRS/GMRS/MURS F Lock band, - Classic and Tiny S-meter styles,
* add SetNav hidden menu to select the navigation layout according to the radio model, - Classic and Tiny frequency-information layouts,
* remove blink and SOS functionality, - `MAIN ONLY`, `DUAL` and `CROSS` display modes,
* remove AM Fix menu (AM Fix is ENABLED by default), - RX activity indication on the active VFO,
* add support of 3500mAh battery, - optional RX LED blinking,
* improve status bar: - squelch, monitor, step and CTCSS/DCS information,
* add SetPtt mode in status bar, - last-RX indication,
* change font and bitmaps, - RX and TX timers.
* move USB icon to left of battery information, - Improved status bar with updated fonts and icons.
* add RX and TX timers, - Menu index remains visible while editing an entry.
* improve channel scanning: - Improved frequency and memory-channel input.
* support up to 24 scan lists, - Improved audio-level display.
* each memory channel can be assigned to `OFF`, to one list (`01` to `24`), or to `ALL`, - AirCopy progress percentage and gauge.
* `ALL` scans every channel except those set to `OFF`, - Smooth backlight fading.
* named scan lists are shown in the UI and status bar when available, - Manual backlight controls for quickly switching between minimum and maximum brightness.
* if the selected scan list is empty or invalid, the firmware automatically jumps to the next valid one, - Configurable contrast and inverted-display mode.
* very fast scan mode (around 150 freq/s), - Configurable navigation layout for the different radio models.
* frequencies exclusions, - Improved power-on message and optional startup logo.
* add resume mode on startup (scan, spectrum analyzer and FM radio), - System-information pages for:
* improve VFO persistence and restore behavior: - firmware version and build information,
* save the Squelch level adjusted with F + UP or F + DOWN, - battery information,
* restore the full VFO state on long press of EXIT, - Flash and SRAM usage,
* new actions: - project and documentation QR codes.
* RX MODE,
* MAIN ONLY, ### Audio and transmission controls
* PTT,
* WIDE NARROW, - Classic and OnePush PTT modes.
* 1750Hz, - Configurable timeout-timer alerts:
* MUTE, - disabled,
* POWER HIGH, - sound,
* REMOVE OFFSET, - visual,
* BEAM, - sound and visual.
* new key combinations: - Configurable end-of-transmission alerts using the same modes.
* add the F + UP or F + DOWN key combination to dynamically change the Squelch level, - Audio Scope during RX and TX.
* add the F + F1 or F + F2 key combination to dynamically change the Step, - Improved Audio Scope behavior with OnePush PTT, DTMF and the 1750 Hz tone.
* add F + 8 to quickly switch backlight between BLMin and BLMax on demand (this bypass BackLt strategy), - Configurable automatic deep-sleep timeout.
* add F + 9 to return to BackLt strategy, - Quick actions for:
* add long press on MENU, in * SCAN mode, to exclude the current memory channel, - RX mode,
* add direct scan list selection while scanning with two digits (`00` = `ALL`, `01` to `24` = scan list). - main-VFO-only display,
* many fix: - PTT,
* squelch, - wide/narrow bandwidth,
* s-meter, - 1750 Hz tone,
* DTMF overlaying, - mute,
* scan range limit, - RX audio profile,
* clean display on startup, - maximum power,
* no more PWM noise, - offset removal.
* K5Viewer/serial key handling,
* spectrum freeze on USB-C unplug, ### Fox Hunt and Beacon
* Audio Scope behavior in OnePush mode and after DTMF/1750,
* and more... - Dedicated Fox Hunt receiver with:
* enabled AIR COPY - calibrated S-meter display,
* disabled ENABLE_DTMF_CALLING, - scrolling signal-history graph,
* disabled SCRAMBLER, - peak, minimum and trend indicators,
* remove 200Tx, 350Tx and 500Tx, - selectable RF attenuation,
* unlock TX on all bands needs only to be repeat 3 times, - silent, Geiger-style and received-audio modes.
* code refactoring and many memory optimization, - Integrated Morse Beacon transmitter with:
* stream the live screen of the Quansheng K5 to K5Viewer and capture screenshots over a USB-to-Serial cable, - `MOE`, `MOI`, `MOS`, `MOH`, `MO5` and `MO` identifiers,
* and more... - optional callsign identification,
- configurable TX and idle periods,
- live TX and idle countdowns,
- persisted Beacon settings,
- interactive control during transmission,
- TX-lock, modulation and battery-safety checks.
- Fox Hunt and Beacon screens are mirrored to UV Studio's integrated K5Viewer.
### RF Log
- Automatic logging of RX and TX activity when RF Log is enabled.
- Logs stored in the radio's external Flash memory.
- Recorded information includes:
- RX or TX direction,
- frequency and channel,
- channel name,
- activity duration,
- S-meter level,
- battery voltage.
- On-radio history with RX/TX filtering and detailed views.
- Live RF Log dashboard and history access through UV Studio.
### Connectivity and data transfer
- Live screen streaming to [UV Studio](https://armel.github.io/uvstudio/) over a USB serial connection.
- Screenshot capture and download.
- Remote keyboard control through the integrated K5Viewer.
- Automatic reconnection after a USB disconnect.
- RF Log monitoring, analytics and CSV export.
- Firmware flashing, calibration backup and restore, and boot-logo management from the same interface.
- BEAM transfer of complete channel settings between compatible radios.
- Improved AirCopy interface and progress reporting.
### Settings and controls
- New or extended menu entries:
- `SetPwr`: configurable User output power,
- `SetPTT`: Classic or OnePush PTT,
- `SetTOT`: timeout-timer alert,
- `SetEOT`: end-of-transmission alert,
- `SetCtr`: display contrast,
- `SetInv`: inverted display,
- `SetLck`: keypad or keypad-and-PTT lock,
- `SetMet`: S-meter style,
- `SetGUI`: VFO information style,
- `SetRxA`: RX audio profile,
- `SetTmr`: RX and TX timers,
- `SetOff`: automatic deep-sleep delay,
- `SetNFM`: narrow-FM bandwidth,
- `SetVol`: RX audio volume,
- `SetScn`: scan mode,
- `SetNav`: radio-specific navigation layout.
- Improved `PonMsg`, `BackLt`, `TxTOut`, `ScnRev` and `KeyLck` menus.
- Full VFO state restoration with a long press on `EXIT`.
- Squelch changes made with `F + UP` or `F + DOWN` are persisted.
### Keyboard shortcuts and assignable actions
- `F + UP` or `F + DOWN`: adjust the squelch level.
- `F + F1` or `F + F2`: adjust the frequency step.
- `F + 8`: temporarily switch the backlight between minimum and maximum brightness.
- `F + 9`: return to the configured backlight strategy.
- Configurable short- and long-press actions include:
- RX mode,
- main-VFO-only display,
- virtual PTT,
- wide/narrow bandwidth,
- 1750 Hz tone,
- mute,
- RX audio profile,
- maximum power,
- offset removal,
- BEAM,
- RF Log,
- Fox Hunt / Beacon.
### Reliability and optimization
- Improved squelch and S-meter behavior.
- Fixed DTMF overlay issues.
- Fixed scan-range limits.
- Cleaner startup display.
- Removed PWM-related audio noise.
- Improved serial and K5Viewer key handling.
- Improved VFO persistence and restoration.
- Extensive code refactoring and memory optimization.
- DTMF calling and the scrambler remain disabled in Fusion.
- Legacy AM Fix code is not used by this firmware.
## Main features from Egzumer: ## Main features from Egzumer:
* many of OneOfEleven mods: * many of OneOfEleven mods:
@@ -284,35 +371,46 @@ Examples:
./compile-with-docker.sh Fusion -DSQL_TONE=600 ./compile-with-docker.sh Fusion -DSQL_TONE=600
``` ```
To prepare the rolling development firmware:
```bash
./compile-with-docker.sh Fusion -DDEV=ON
```
This keeps the regular build output in `build/Fusion` and also updates
`archive/f4hwn.fusion.development.bin`. The development build is identified as
`DEV` in the firmware information screen. Publishing the updated archive file
remains an explicit Git operation.
### Notes ### Notes
- The first run may take a few minutes while Docker builds the base image. - The first run may take a few minutes while Docker builds the base image.
- Each build runs inside Docker, so your host environment remains clean. - Each build runs inside Docker, so your host environment remains clean.
## Flashing the Firmware with UVTools2 ## Flashing the Firmware with UV Studio
You can flash the UV-K5 V3 and UV-K1 directly from your web browser using the cross-platform WebSerial-based [UVTools2](https://armel.github.io/uvtools2/). You can flash the UV-K5 V3 and UV-K1 directly from your web browser using the Web Serial-based [UV Studio](https://armel.github.io/uvstudio/).
It works on Chrome, Chromium and Edge (desktop versions), and does not require installing any driver or software on your computer. UV Studio combines firmware flashing, calibration maintenance, boot-logo management, K5Viewer and RF Log in a single interface. It requires no application installation, server or account. Use a desktop browser with Web Serial support, such as Chrome, Brave, Edge, Opera or Firefox 151+.
## Steps to flash the firmware ## Steps to flash the firmware
- Open UVTools2 in [flash](https://armel.github.io/uvtools2/?mode=flash) mode (or click the Flash Firmware tab). - Open the [Flash Firmware](https://armel.github.io/uvstudio/#flash) view in UV Studio.
- Connect your radio to your computer using a compatible USB programming cable (USB-C or Baofeng/Kenwood like double jack USB cable). - Connect your radio to your computer using a compatible USB programming cable (USB-C or Baofeng/Kenwood like double jack USB cable).
- Make sure your radio is in **DFU mode (flash mode)**. - Make sure your radio is in **DFU mode (flash mode)**.
- Select the firmware .bin file on your computer. - Select an official F4HWN Fusion release from the catalog or load a local `.bin` firmware file.
- Click on `Flash Firmware`, then select the serial port associated with your radio. - Click on `Flash Firmware`, then select the serial port associated with your radio.
- The progress bar will guide you through the flashing steps. - The progress bar will guide you through the flashing steps.
Once finished, your radio restart with the new firmware. Once finished, your radio restarts with the new firmware.
## Steps to dump or restore calibration data ## Steps to dump or restore calibration data
[UVTools2](https://armel.github.io/uvtools2/) can also dump and restore calibration data, which is highly recommended. It’s best to create a dump right after installing F4HWN firmware, and to restore it before installing another firmware (or when returning to the stock firmware, for example). [UV Studio](https://armel.github.io/uvstudio/) can also dump and restore calibration data, which is highly recommended. It is best to create a dump immediately after installing the F4HWN firmware, and to restore it before installing another firmware or returning to the stock firmware.
### Dump ### Dump
- Open UVTools2 in [dump](https://armel.github.io/uvtools2/?mode=dump) mode (or click the Dump Calib tab). - Open the [Dump Calibration](https://armel.github.io/uvstudio/#dump-calib) view in UV Studio.
- Power on your radio in **normal mode**. - Power on your radio in **normal mode**.
- Click `Dump Calibration Data`. - Click `Dump Calibration Data`.
@@ -323,9 +421,9 @@ When the process is complete, click `Download calibration.dat` to save the file
### Restore ### Restore
- Open UVTools2 in [restore](https://armel.github.io/uvtools2/?mode=restore) mode (or click the Restore Calib tab). - Open the [Restore Calibration](https://armel.github.io/uvstudio/#restore-calib) view in UV Studio.
- Power on your radio in **normal mode**. - Power on your radio in **normal mode**.
- Select your calibration.dat file on your computer. - Select your `calibration.dat` file on your computer.
Click `Restore Calibration Data` and wait until the process fully completes. Click `Restore Calibration Data` and wait until the process fully completes.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+1
View File
@@ -8,6 +8,7 @@ set -euo pipefail
# ./compile-with-docker.sh Custom # ./compile-with-docker.sh Custom
# ./compile-with-docker.sh Bandscope -DENABLE_SPECTRUM=ON # ./compile-with-docker.sh Bandscope -DENABLE_SPECTRUM=ON
# ./compile-with-docker.sh Broadcast -DENABLE_FEAT_F4HWN_GAME=ON -DENABLE_NOAA=ON # ./compile-with-docker.sh Broadcast -DENABLE_FEAT_F4HWN_GAME=ON -DENABLE_NOAA=ON
# ./compile-with-docker.sh Fusion -DDEV=ON
# ./compile-with-docker.sh All # ./compile-with-docker.sh All
# Default preset: "Custom" # Default preset: "Custom"
# --------------------------------------------- # ---------------------------------------------