mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
Decouple FoxHunt and Beacon actions
This commit is contained in:
1 parent
4c3847ef34
commit
0850420fdf
18 files changed
+258
-147
No files matched your search
+5
-3
@@ -234,9 +234,11 @@ 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
|
enable_feature(ENABLE_FEAT_F4HWN_FOXHUNT)
|
||||||
app/foxhunt.c
|
enable_feature(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
)
|
if(ENABLE_FEAT_F4HWN_FOXHUNT OR ENABLE_FEAT_F4HWN_BEACON)
|
||||||
|
target_sources(App INTERFACE app/foxhunt.c)
|
||||||
|
endif()
|
||||||
enable_feature(ENABLE_FEAT_F4HWN_ACTION_PICKER)
|
enable_feature(ENABLE_FEAT_F4HWN_ACTION_PICKER)
|
||||||
|
|
||||||
if(ENABLE_FEAT_F4HWN_ACTION_PICKER AND NOT ENABLE_FEAT_F4HWN)
|
if(ENABLE_FEAT_F4HWN_ACTION_PICKER AND NOT ENABLE_FEAT_F4HWN)
|
||||||
|
|||||||
+59
-4
@@ -51,7 +51,7 @@
|
|||||||
#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
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
#include "app/foxhunt.h"
|
#include "app/foxhunt.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_FEAT_F4HWN_ACTION_PICKER
|
#ifdef ENABLE_FEAT_F4HWN_ACTION_PICKER
|
||||||
@@ -119,9 +119,12 @@ void (*const action_opt_table[ACTION_OPT_LEN])(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
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
[ACTION_OPT_FOXHUNT] = &ACTION_FoxHunt,
|
[ACTION_OPT_FOXHUNT] = &ACTION_FoxHunt,
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
|
[ACTION_OPT_BEACON] = &ACTION_Beacon,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN);
|
static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN);
|
||||||
@@ -130,10 +133,33 @@ static_assert(ACTION_OPT_BEAM == 19);
|
|||||||
static_assert(ACTION_OPT_POWER_HIGH == 20);
|
static_assert(ACTION_OPT_POWER_HIGH == 20);
|
||||||
static_assert(ACTION_OPT_REMOVE_OFFSET == 21);
|
static_assert(ACTION_OPT_REMOVE_OFFSET == 21);
|
||||||
static_assert(ACTION_OPT_FOXHUNT == 22);
|
static_assert(ACTION_OPT_FOXHUNT == 22);
|
||||||
|
static_assert(ACTION_OPT_BEACON == 23);
|
||||||
|
|
||||||
bool ACTION_IsAvailable(uint8_t action)
|
bool ACTION_IsAvailable(uint8_t action)
|
||||||
{
|
{
|
||||||
return action < ACTION_OPT_LEN && action_opt_table[action] != NULL;
|
if (action >= ACTION_OPT_LEN || action_opt_table[action] == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_APPS
|
||||||
|
switch (action) {
|
||||||
|
#ifdef ENABLE_FMRADIO
|
||||||
|
case ACTION_OPT_FM:
|
||||||
|
return (APP_OverlayShortcutMask() & APP_SHORTCUT_FM) != 0;
|
||||||
|
#endif
|
||||||
|
#ifndef ENABLE_FEAT_F4HWN_FOXHUNT
|
||||||
|
case ACTION_OPT_FOXHUNT:
|
||||||
|
return (APP_OverlayShortcutMask() & APP_SHORTCUT_FOXHUNT) != 0;
|
||||||
|
#endif
|
||||||
|
#ifndef ENABLE_FEAT_F4HWN_BEACON
|
||||||
|
case ACTION_OPT_BEACON:
|
||||||
|
return (APP_OverlayShortcutMask() & APP_SHORTCUT_BEACON) != 0;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACTION_Power(void)
|
void ACTION_Power(void)
|
||||||
@@ -315,8 +341,11 @@ inline static bool ACTION_IsBlockedInFM(uint8_t action)
|
|||||||
#ifdef ENABLE_FEAT_F4HWN_BEAM
|
#ifdef ENABLE_FEAT_F4HWN_BEAM
|
||||||
case ACTION_OPT_BEAM:
|
case ACTION_OPT_BEAM:
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
case ACTION_OPT_FOXHUNT:
|
case ACTION_OPT_FOXHUNT:
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
|
case ACTION_OPT_BEACON:
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -466,6 +495,32 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
|||||||
ACTION_Execute(func);
|
ACTION_Execute(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
|
void ACTION_FoxHunt(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
||||||
|
APP_RunFoxHunt();
|
||||||
|
GUI_SelectNextDisplay(DISPLAY_MAIN);
|
||||||
|
#else
|
||||||
|
if (APP_LaunchOverlayByName("FoxHunt") != APP_OK)
|
||||||
|
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
|
void ACTION_Beacon(void)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_BEACON
|
||||||
|
APP_RunBeacon();
|
||||||
|
GUI_SelectNextDisplay(DISPLAY_MAIN);
|
||||||
|
#else
|
||||||
|
if (APP_LaunchOverlayByName("Beacon") != APP_OK)
|
||||||
|
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_FMRADIO
|
#ifdef ENABLE_FMRADIO
|
||||||
void ACTION_FM(void)
|
void ACTION_FM(void)
|
||||||
|
|||||||
+1
-1
@@ -1985,7 +1985,7 @@ void APP_TimeSlice500ms(void)
|
|||||||
|
|
||||||
if ((gBatteryCheckCounter & 1) == 0)
|
if ((gBatteryCheckCounter & 1) == 0)
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT)
|
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
BATTERY_Sample(true);
|
BATTERY_Sample(true);
|
||||||
#else
|
#else
|
||||||
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent);
|
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent);
|
||||||
|
|||||||
+100
-122
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "app/foxhunt.h"
|
#include "app/foxhunt.h"
|
||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
|
|
||||||
#if defined(ENABLE_UART) || defined(ENABLE_USB)
|
#if defined(ENABLE_UART) || defined(ENABLE_USB)
|
||||||
#include "app/uart.h"
|
#include "app/uart.h"
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
#define FOXHUNT_AUDIO_BEEP 1
|
#define FOXHUNT_AUDIO_BEEP 1
|
||||||
#define FOXHUNT_AUDIO_STATION 2
|
#define FOXHUNT_AUDIO_STATION 2
|
||||||
|
|
||||||
// --- Beacon (fox) sub-mode ---------------------------------------------------
|
// --- Beacon (fox) app --------------------------------------------------------
|
||||||
// Turns the radio into the hidden transmitter: each cycle keys up on the TX VFO and
|
// Turns the radio into the hidden transmitter: each cycle keys up on the TX VFO and
|
||||||
// repeats the CW fox identifier (MOE..MO5, or "<call> MOE") in Morse for the TX window,
|
// repeats the CW fox identifier (MOE..MO5, or "<call> MOE") in Morse for the TX window,
|
||||||
// then stays silent for the (adjustable) idle gap. The carrier stays up during the
|
// then stays silent for the (adjustable) idle gap. The carrier stays up during the
|
||||||
@@ -201,8 +201,7 @@ static const uint8_t FOXHUNT_MORSE_DIGIT[10] = {
|
|||||||
// Trailing character of each fox id: MOE / MOI / MOS / MOH / MO5 (index = FOXHUNT_FOX_*).
|
// Trailing character of each fox id: MOE / MOI / MOS / MOH / MO5 (index = FOXHUNT_FOX_*).
|
||||||
static const char FOXHUNT_FOX_TAIL[5] = {'E', 'I', 'S', 'H', '5'};
|
static const char FOXHUNT_FOX_TAIL[5] = {'E', 'I', 'S', 'H', '5'};
|
||||||
|
|
||||||
// Beacon sub-mode state.
|
// Beacon state.
|
||||||
static bool foxBeacon; // false = hunt (RX), true = beacon (TX)
|
|
||||||
static bool beaconPhaseTx; // true = transmit this tick, false = idle gap
|
static bool beaconPhaseTx; // true = transmit this tick, false = idle gap
|
||||||
static uint8_t beaconIdle; // configured silence between IDs (s)
|
static uint8_t beaconIdle; // configured silence between IDs (s)
|
||||||
static uint8_t beaconIdleLeft; // seconds left in the current silence
|
static uint8_t beaconIdleLeft; // seconds left in the current silence
|
||||||
@@ -782,11 +781,6 @@ static void FOXHUNT_HandleKeys(void)
|
|||||||
minDbm = curDbm;
|
minDbm = curDbm;
|
||||||
trendRef = curDbm;
|
trendRef = curDbm;
|
||||||
break;
|
break;
|
||||||
case KEY_SIDE1:
|
|
||||||
case KEY_SIDE2:
|
|
||||||
// Same shortcut that opened Fox Hunt now toggles to the beacon.
|
|
||||||
FOXHUNT_EnterBeacon();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -794,22 +788,18 @@ static void FOXHUNT_HandleKeys(void)
|
|||||||
gWasFKeyPressed = false; // any non-F key consumes (or cancels) the reverse arm
|
gWasFKeyPressed = false; // any non-F key consumes (or cancels) the reverse arm
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Re)enter the hunt (RX) sub-mode: fixed front-end gain, attenuator and audio mode
|
// Enter Fox Hunt with fixed front-end gain, the persisted attenuator/audio mode,
|
||||||
// re-applied, peak/trend reset. Called at start-up and when leaving the beacon. The
|
// and freshly rebased level tracking.
|
||||||
// audio mode is a hunt setting, so it is (re)applied here, not forced off — it must
|
|
||||||
// survive a trip through the beacon.
|
|
||||||
static void FOXHUNT_EnterHunt(void)
|
static void FOXHUNT_EnterHunt(void)
|
||||||
{
|
{
|
||||||
foxBeacon = false;
|
|
||||||
|
|
||||||
BK4819_SetAGC(false);
|
BK4819_SetAGC(false);
|
||||||
FOXHUNT_ApplyAtt();
|
FOXHUNT_ApplyAtt();
|
||||||
FOXHUNT_SetAudio(); // (re)apply the current audio mode: off / beep / station
|
FOXHUNT_SetAudio(); // (re)apply the current audio mode: off / beep / station
|
||||||
|
|
||||||
// Let the RSSI settle to the gain just applied, then reset the peak/min hold, trend
|
// Let the RSSI settle to the gain just applied, then reset the peak/min hold, trend
|
||||||
// reference and signal history onto a fresh reading (also re-primes the sparkline on
|
// reference and signal history onto a fresh reading. Same settle as
|
||||||
// return from the beacon). Same settle as FOXHUNT_AttCycle: without it a restored
|
// FOXHUNT_AttCycle: without it a restored
|
||||||
// BYP/BYP+ step at start-up or on beacon return would rebase onto the old-gain reading.
|
// BYP/BYP+ step at start-up would rebase onto the old-gain reading.
|
||||||
// SetAudio already waits when audio is on, but not in the default audio-off case.
|
// SetAudio already waits when audio is on, but not in the default audio-off case.
|
||||||
SYSTEM_DelayMs(FOXHUNT_ATT_SETTLE_MS);
|
SYSTEM_DelayMs(FOXHUNT_ATT_SETTLE_MS);
|
||||||
FOXHUNT_RebaseMeasurements();
|
FOXHUNT_RebaseMeasurements();
|
||||||
@@ -836,9 +826,8 @@ static VfoState_t FOXHUNT_TxState(void)
|
|||||||
|
|
||||||
// Refuse feedback shown when a burst is barred: reuse the beacon screen layout and
|
// Refuse feedback shown when a burst is barred: reuse the beacon screen layout and
|
||||||
// the radio's own state label (VfoStateStr, e.g. "TX DISABLE" / "BAT LOW" / "VOLT
|
// the radio's own state label (VfoStateStr, e.g. "TX DISABLE" / "BAT LOW" / "VOLT
|
||||||
// HIGH"), same font as the main screen, for a beat; the caller then falls back to
|
// HIGH"), same font as the main screen, for a beat; the caller then waits through
|
||||||
// the hunt. The RX front-end and audio path are left untouched so the hunt keeps
|
// a fresh idle gap before checking again.
|
||||||
// reading cleanly.
|
|
||||||
static void FOXHUNT_TxDeniedNotice(VfoState_t state)
|
static void FOXHUNT_TxDeniedNotice(VfoState_t state)
|
||||||
{
|
{
|
||||||
// Frame (clear + BEACON tag + battery + barred TX frequency).
|
// Frame (clear + BEACON tag + battery + barred TX frequency).
|
||||||
@@ -855,12 +844,10 @@ static void FOXHUNT_TxDeniedNotice(VfoState_t state)
|
|||||||
FOXHUNT_TickDelay();
|
FOXHUNT_TickDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter the beacon (fox) sub-mode. The TX gates are enforced per burst in
|
// Enter the Beacon app. TX gates are enforced before each burst.
|
||||||
// FOXHUNT_BeaconTick (which runs immediately), so entry just arms the state.
|
|
||||||
static void FOXHUNT_EnterBeacon(void)
|
static void FOXHUNT_EnterBeacon(void)
|
||||||
{
|
{
|
||||||
foxBeacon = true;
|
AUDIO_AudioPathOff();
|
||||||
AUDIO_AudioPathOff(); // no RX audio while beaconing; foxAudioMode kept for the hunt
|
|
||||||
gCurrentVfo = gTxVfo; // the VFO RADIO_SetTxParameters keys up
|
gCurrentVfo = gTxVfo; // the VFO RADIO_SetTxParameters keys up
|
||||||
beaconPhaseTx = true;
|
beaconPhaseTx = true;
|
||||||
}
|
}
|
||||||
@@ -879,8 +866,8 @@ static void FOXHUNT_DrawTxSeconds(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sleep in short slices while watching the keypad, so a burst stays interactive and the
|
// Sleep in short slices while watching the keypad, so a burst stays interactive and the
|
||||||
// TX-window countdown (beaconTxMsLeft) drains in real time. EXIT leaves Fox Hunt and a
|
// TX-window countdown (beaconTxMsLeft) drains in real time. EXIT leaves Beacon. The
|
||||||
// side key aborts back to the hunt (both return true). The 1/2/3 keys edit the beacon
|
// 1/2/3 keys edit the beacon
|
||||||
// settings live, exactly as in the idle phase: the TX window (1) and idle gap (2) take
|
// settings live, exactly as in the idle phase: the TX window (1) and idle gap (2) take
|
||||||
// effect at the upcoming window / gap, and a FOX change (3) at the next repeat (the
|
// effect at the upcoming window / gap, and a FOX change (3) at the next repeat (the
|
||||||
// message is rebuilt there, never under the running loop).
|
// message is rebuilt there, never under the running loop).
|
||||||
@@ -926,17 +913,12 @@ static bool FOXHUNT_TxDelay(uint16_t ms)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (kbd.current == KEY_EXIT) {
|
if (kbd.current == KEY_EXIT) {
|
||||||
foxRunning = false; // abort the burst and leave Fox Hunt
|
foxRunning = false; // abort the burst and leave Beacon
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (kbd.current == KEY_SIDE1 || kbd.current == KEY_SIDE2) {
|
|
||||||
foxBeacon = false; // abort the burst and switch back to hunt
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (kbd.current == KEY_MENU) {
|
if (kbd.current == KEY_MENU) {
|
||||||
// Cut the transmission short but stay in Beacon: aborting the burst without
|
// Cut the transmission short but stay in Beacon: the loop drops straight
|
||||||
// clearing foxBeacon/foxRunning drops the loop straight into a fresh idle
|
// into a fresh idle gap of the configured IDLE length.
|
||||||
// gap of the configured IDLE length.
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (kbd.current == KEY_F) { // arm / disarm the reverse step
|
if (kbd.current == KEY_F) { // arm / disarm the reverse step
|
||||||
@@ -1051,8 +1033,8 @@ static void FOXHUNT_BeaconTransmit(void)
|
|||||||
stop = FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 7);
|
stop = FOXHUNT_TxDelay(FOXHUNT_MORSE_UNIT_MS * 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key down: mute, drop the PA and restore RX for the silent gap. If the burst
|
// Key down: mute, drop the PA and restore RX for the silent gap. If EXIT
|
||||||
// was interrupted, FOXHUNT_TxDelay already set the target mode (quit or hunt).
|
// interrupted the burst, FOXHUNT_TxDelay has already stopped the app.
|
||||||
BK4819_EnterTxMute();
|
BK4819_EnterTxMute();
|
||||||
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
|
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
|
||||||
RADIO_SetupRegisters(true);
|
RADIO_SetupRegisters(true);
|
||||||
@@ -1208,11 +1190,7 @@ static void FOXHUNT_BeaconKeys(void)
|
|||||||
|
|
||||||
switch (kbd.current) {
|
switch (kbd.current) {
|
||||||
case KEY_EXIT:
|
case KEY_EXIT:
|
||||||
foxRunning = false; // leave Fox Hunt entirely
|
foxRunning = false;
|
||||||
break;
|
|
||||||
case KEY_SIDE1:
|
|
||||||
case KEY_SIDE2:
|
|
||||||
foxBeacon = false; // toggle back to the hunt
|
|
||||||
break;
|
break;
|
||||||
case KEY_MENU:
|
case KEY_MENU:
|
||||||
// Restart a full idle interval now (the TX-phase M drops here too).
|
// Restart a full idle interval now (the TX-phase M drops here too).
|
||||||
@@ -1237,28 +1215,26 @@ static void FOXHUNT_BeaconTick(void)
|
|||||||
// LOCK / TX LOCK and modulation are fixed for the session, but the battery
|
// LOCK / TX LOCK and modulation are fixed for the session, but the battery
|
||||||
// is re-sampled over the idle gaps (FOXHUNT_IdleHousekeeping), so a beacon
|
// is re-sampled over the idle gaps (FOXHUNT_IdleHousekeeping), so a beacon
|
||||||
// left running stops keying up once the pack falls low or over-voltage
|
// left running stops keying up once the pack falls low or over-voltage
|
||||||
// instead of transmitting blind. Refuse, notify, and drop back to hunt.
|
// instead of transmitting blind. Refuse, notify, then retry after an idle gap.
|
||||||
VfoState_t state = FOXHUNT_TxState();
|
VfoState_t state = FOXHUNT_TxState();
|
||||||
if (state != VFO_STATE_NORMAL) {
|
if (state != VFO_STATE_NORMAL) {
|
||||||
FOXHUNT_TxDeniedNotice(state);
|
FOXHUNT_TxDeniedNotice(state);
|
||||||
foxBeacon = false;
|
|
||||||
beaconPhaseTx = false;
|
beaconPhaseTx = false;
|
||||||
FOXHUNT_EnterHunt();
|
beaconIdleLeft = beaconIdle;
|
||||||
|
beaconIdleTick = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The burst repeats the ID for the whole TX window, redrawing the screen
|
// The burst repeats the ID for the whole TX window, redrawing the screen
|
||||||
// itself each repeat (remaining-window countdown); it may clear foxBeacon
|
// itself each repeat (remaining-window countdown); EXIT may clear
|
||||||
// (side-key abort) or foxRunning (EXIT).
|
// foxRunning and abort it.
|
||||||
FOXHUNT_BeaconTransmit();
|
FOXHUNT_BeaconTransmit();
|
||||||
|
|
||||||
beaconPhaseTx = false;
|
beaconPhaseTx = false;
|
||||||
beaconIdleLeft = beaconIdle;
|
beaconIdleLeft = beaconIdle;
|
||||||
beaconIdleTick = 0;
|
beaconIdleTick = 0;
|
||||||
|
|
||||||
if (foxRunning && !foxBeacon) // side-key switched to hunt
|
return;
|
||||||
FOXHUNT_EnterHunt();
|
|
||||||
return; // EXIT (quit) falls through
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Idle (silent) phase: responsive, editable countdown.
|
// Idle (silent) phase: responsive, editable countdown.
|
||||||
@@ -1267,12 +1243,8 @@ static void FOXHUNT_BeaconTick(void)
|
|||||||
#endif
|
#endif
|
||||||
FOXHUNT_BeaconKeys();
|
FOXHUNT_BeaconKeys();
|
||||||
|
|
||||||
if (!foxRunning) // EXIT: leave Fox Hunt
|
if (!foxRunning)
|
||||||
return;
|
return;
|
||||||
if (!foxBeacon) { // side-key: back to the hunt
|
|
||||||
FOXHUNT_EnterHunt();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FOXHUNT_BeaconDraw(false, beaconIdleLeft);
|
FOXHUNT_BeaconDraw(false, beaconIdleLeft);
|
||||||
FOXHUNT_BlitScreen();
|
FOXHUNT_BlitScreen();
|
||||||
@@ -1340,7 +1312,7 @@ static void FOXHUNT_LoadConfig(void)
|
|||||||
|
|
||||||
// Write the settings to flash, but only when they changed since the last write.
|
// Write the settings to flash, but only when they changed since the last write.
|
||||||
// Called on the 500 ms tick (so any change persists within ~0.5 s and survives a
|
// Called on the 500 ms tick (so any change persists within ~0.5 s and survives a
|
||||||
// power-off, not just a clean EXIT) and once more on leaving Fox Hunt. The RAM
|
// power-off, not just a clean EXIT) and once more on leaving either app. The RAM
|
||||||
// compare avoids re-reading the 4 KB sector on every quiet tick.
|
// compare avoids re-reading the 4 KB sector on every quiet tick.
|
||||||
static void FOXHUNT_SaveConfig(void)
|
static void FOXHUNT_SaveConfig(void)
|
||||||
{
|
{
|
||||||
@@ -1354,83 +1326,90 @@ static void FOXHUNT_SaveConfig(void)
|
|||||||
memcpy(foxCfgSaved, cfg, sizeof(cfg));
|
memcpy(foxCfgSaved, cfg, sizeof(cfg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void APP_RunFoxHunt(void)
|
static void FOXHUNT_Begin(void)
|
||||||
{
|
{
|
||||||
// Finish any pending backlight fade, then start with the screen on and a full
|
|
||||||
// BLTime window (BACKLIGHT_TurnOn also re-arms the sleep countdown).
|
|
||||||
BACKLIGHT_UpdateTickless();
|
BACKLIGHT_UpdateTickless();
|
||||||
BACKLIGHT_TurnOn();
|
BACKLIGHT_TurnOn();
|
||||||
|
|
||||||
// Hunt on the user-selected VFO: dual-watch / cross-band may have left the
|
// Both apps operate on the user-selected VFO. Dual watch may have left the
|
||||||
// radio listening on the other VFO, so force RX on the selected one and retune.
|
// receiver on the other one, so establish a deterministic starting point.
|
||||||
gEeprom.RX_VFO = gEeprom.TX_VFO;
|
gEeprom.RX_VFO = gEeprom.TX_VFO;
|
||||||
gRxVfo = gTxVfo;
|
gRxVfo = gTxVfo;
|
||||||
gCurrentVfo = gTxVfo;
|
gCurrentVfo = gTxVfo;
|
||||||
RADIO_SetupRegisters(true);
|
RADIO_SetupRegisters(true);
|
||||||
|
|
||||||
// Beacon defaults (LoadConfig may override fox / tx / idle below).
|
// Initialise the complete legacy seven-byte configuration before loading it.
|
||||||
beaconIdle = FOXHUNT_BEACON_IDLE_DEF;
|
// Keeping the layout unchanged preserves existing FieldOps settings and lets
|
||||||
beaconTx = FOXHUNT_BEACON_TX_DEF;
|
// either independently compiled app update its fields without a migration.
|
||||||
foxFox = FOXHUNT_FOX_CALL; // identified beacon by default (legal on ham)
|
|
||||||
beaconPhaseTx = false;
|
|
||||||
|
|
||||||
// Read the callsign from the boot message (line 1), sanitised to what Morse can
|
|
||||||
// send; empty/erased leaves foxCall empty (the CALL id then falls back to bare MOE).
|
|
||||||
{
|
|
||||||
char call[FOXHUNT_CALLSIGN_MAX + 1];
|
|
||||||
uint8_t n = 0;
|
|
||||||
PY25Q16_ReadBuffer(FOXHUNT_CALLSIGN_ADDR, call, FOXHUNT_CALLSIGN_MAX);
|
|
||||||
call[FOXHUNT_CALLSIGN_MAX] = '\0';
|
|
||||||
for (uint8_t i = 0; i < FOXHUNT_CALLSIGN_MAX; i++) {
|
|
||||||
char c = call[i];
|
|
||||||
if (c == '\0' || (uint8_t)c == 0xFF)
|
|
||||||
break;
|
|
||||||
if (c >= 'a' && c <= 'z')
|
|
||||||
c -= 32;
|
|
||||||
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '/')
|
|
||||||
foxCall[n++] = c;
|
|
||||||
}
|
|
||||||
foxCall[n] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start in the hunt (RX) sub-mode, S-meter staircase gauge by default, then restore
|
|
||||||
// any persisted settings (attenuator, gauge, audio, beacon idle / fox / tx).
|
|
||||||
attStep = 0;
|
attStep = 0;
|
||||||
foxGraphMode = FOXHUNT_GRAPH_BAR;
|
foxGraphMode = FOXHUNT_GRAPH_BAR;
|
||||||
foxAudioMode = FOXHUNT_AUDIO_OFF;
|
foxAudioMode = FOXHUNT_AUDIO_OFF;
|
||||||
FOXHUNT_LoadConfig(); // may override att / gauge / audio / idle / fox / tx
|
beaconIdle = FOXHUNT_BEACON_IDLE_DEF;
|
||||||
FOXHUNT_EnterHunt(); // applies the restored attStep and audio mode
|
beaconTx = FOXHUNT_BEACON_TX_DEF;
|
||||||
// beaconMsg is (re)built by FOXHUNT_BeaconTransmit before every burst, and nothing
|
foxFox = FOXHUNT_FOX_CALL;
|
||||||
// reads it before the first burst, so no need to assemble it here.
|
beaconPhaseTx = false;
|
||||||
|
FOXHUNT_LoadConfig();
|
||||||
|
|
||||||
// Prime the key state with whatever is held right now, so the side key that
|
// Ignore the key that launched the modal app until it has been released.
|
||||||
// launched Fox Hunt (still down on a long-press assignment) is not taken for
|
|
||||||
// a fresh press and does not immediately toggle to the beacon.
|
|
||||||
kbd.prev = kbd.current = KEYBOARD_GetKey();
|
kbd.prev = kbd.current = KEYBOARD_GetKey();
|
||||||
gWasFKeyPressed = false; // start with the reverse-step arm cleared
|
gWasFKeyPressed = false;
|
||||||
|
|
||||||
// Always enter unlocked: the keypad lock is a transient safety toggle, not a
|
|
||||||
// persisted setting, so a previous session must not leave the pad locked.
|
|
||||||
foxLocked = false;
|
foxLocked = false;
|
||||||
fHoldMs = 0;
|
fHoldMs = 0;
|
||||||
fLongDone = false;
|
fLongDone = false;
|
||||||
|
|
||||||
foxRunning = true;
|
foxRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FOXHUNT_LoadCallsign(void)
|
||||||
|
{
|
||||||
|
char call[FOXHUNT_CALLSIGN_MAX + 1];
|
||||||
|
uint8_t n = 0;
|
||||||
|
|
||||||
|
// Read the callsign from the boot message (line 1), sanitised to what Morse can
|
||||||
|
// send; empty/erased leaves foxCall empty (the CALL id then falls back to bare MOE).
|
||||||
|
PY25Q16_ReadBuffer(FOXHUNT_CALLSIGN_ADDR, call, FOXHUNT_CALLSIGN_MAX);
|
||||||
|
call[FOXHUNT_CALLSIGN_MAX] = '\0';
|
||||||
|
for (uint8_t i = 0; i < FOXHUNT_CALLSIGN_MAX; i++) {
|
||||||
|
char c = call[i];
|
||||||
|
if (c == '\0' || (uint8_t)c == 0xFF)
|
||||||
|
break;
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
c -= 32;
|
||||||
|
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '/')
|
||||||
|
foxCall[n++] = c;
|
||||||
|
}
|
||||||
|
foxCall[n] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FOXHUNT_End(void)
|
||||||
|
{
|
||||||
|
FOXHUNT_SaveConfig();
|
||||||
|
gWasFKeyPressed = false;
|
||||||
|
AUDIO_AudioPathOff();
|
||||||
|
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
|
||||||
|
RADIO_SelectVfos();
|
||||||
|
RADIO_SetupRegisters(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both entry points stay in this translation unit so their small modal services
|
||||||
|
* can be shared when both features are enabled. The action table references only
|
||||||
|
* the enabled entry point(s); --gc-sections then drops the complete unused RX or
|
||||||
|
* Beacon call graph, including its private constants and bitmaps. */
|
||||||
|
void APP_RunFoxHunt(void)
|
||||||
|
{
|
||||||
|
FOXHUNT_Begin();
|
||||||
|
|
||||||
|
FOXHUNT_EnterHunt();
|
||||||
while (foxRunning) {
|
while (foxRunning) {
|
||||||
#if defined(ENABLE_UART) || defined(ENABLE_USB)
|
#if defined(ENABLE_UART) || defined(ENABLE_USB)
|
||||||
UART_ServiceCommands();
|
UART_ServiceCommands();
|
||||||
#endif
|
#endif
|
||||||
if (foxBeacon) {
|
|
||||||
FOXHUNT_BeaconTick();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_K5VIEWER
|
#ifdef ENABLE_FEAT_F4HWN_K5VIEWER
|
||||||
// Keep the K5Viewer link alive and pick up any remote key.
|
// Keep the K5Viewer link alive and pick up any remote key.
|
||||||
K5VIEWER_ParseInput();
|
K5VIEWER_ParseInput();
|
||||||
#endif
|
#endif
|
||||||
FOXHUNT_HandleKeys();
|
FOXHUNT_HandleKeys();
|
||||||
if (foxBeacon) // just switched to beacon: skip the RX work this tick
|
if (!foxRunning)
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
curDbm = FOXHUNT_ReadDbm();
|
curDbm = FOXHUNT_ReadDbm();
|
||||||
if (curDbm > peakDbm)
|
if (curDbm > peakDbm)
|
||||||
@@ -1468,24 +1447,23 @@ void APP_RunFoxHunt(void)
|
|||||||
FOXHUNT_TickDelay(); // tick delay + smooth backlight fade
|
FOXHUNT_TickDelay(); // tick delay + smooth backlight fade
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist the session's settings on the way out (EXIT clears foxRunning) so
|
FOXHUNT_End();
|
||||||
// they survive a later power cycle.
|
|
||||||
FOXHUNT_SaveConfig();
|
|
||||||
|
|
||||||
gWasFKeyPressed = false; // don't leak a pending reverse-step arm to the main screen
|
|
||||||
|
|
||||||
// Mute any pending tone, drop the PA (safety), then restore the normal VFO
|
|
||||||
// selection and RX config.
|
|
||||||
AUDIO_AudioPathOff();
|
|
||||||
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
|
|
||||||
RADIO_SelectVfos();
|
|
||||||
RADIO_SetupRegisters(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACTION_FoxHunt(void)
|
void APP_RunBeacon(void)
|
||||||
{
|
{
|
||||||
APP_RunFoxHunt();
|
FOXHUNT_Begin();
|
||||||
GUI_SelectNextDisplay(DISPLAY_MAIN);
|
FOXHUNT_LoadCallsign();
|
||||||
|
FOXHUNT_EnterBeacon();
|
||||||
|
|
||||||
|
while (foxRunning) {
|
||||||
|
#if defined(ENABLE_UART) || defined(ENABLE_USB)
|
||||||
|
UART_ServiceCommands();
|
||||||
|
#endif
|
||||||
|
FOXHUNT_BeaconTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
FOXHUNT_End();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ENABLE_FEAT_F4HWN_FOXHUNT
|
#endif // ENABLE_FEAT_F4HWN_FOXHUNT || ENABLE_FEAT_F4HWN_BEACON
|
||||||
+12
-3
@@ -17,7 +17,7 @@
|
|||||||
#ifndef APP_FOXHUNT_H
|
#ifndef APP_FOXHUNT_H
|
||||||
#define APP_FOXHUNT_H
|
#define APP_FOXHUNT_H
|
||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
|
|
||||||
#include "keyboard_state.h"
|
#include "keyboard_state.h"
|
||||||
|
|
||||||
@@ -46,12 +46,21 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Entry point wired as an assignable side-key action (see action.c).
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
|
// Assignable resident/overlay launchers (see action.c).
|
||||||
void ACTION_FoxHunt(void);
|
void ACTION_FoxHunt(void);
|
||||||
|
void ACTION_Beacon(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
||||||
// Self-contained modal loop that owns the screen and keypad until EXIT.
|
// Self-contained modal loop that owns the screen and keypad until EXIT.
|
||||||
void APP_RunFoxHunt(void);
|
void APP_RunFoxHunt(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_FEAT_F4HWN_BEACON
|
||||||
|
void APP_RunBeacon(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // ENABLE_FEAT_F4HWN_FOXHUNT
|
|
||||||
#endif // APP_FOXHUNT_H
|
#endif // APP_FOXHUNT_H
|
||||||
@@ -633,8 +633,60 @@ uint8_t APP_ValidateSlot(uint8_t slot, app_header_t *out_header)
|
|||||||
return APP_OK;
|
return APP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool app_shortcuts_cached;
|
||||||
|
static uint8_t app_shortcut_mask;
|
||||||
|
static uint8_t app_shortcut_slots[3];
|
||||||
|
|
||||||
|
static int8_t app_shortcut_index(const char *name)
|
||||||
|
{
|
||||||
|
if (strncmp(name, "Broadcast FM", APP_NAME_LEN) == 0) return 0;
|
||||||
|
if (strncmp(name, "FoxHunt", APP_NAME_LEN) == 0) return 1;
|
||||||
|
if (strncmp(name, "Beacon", APP_NAME_LEN) == 0) return 2;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cache_shortcuts(void)
|
||||||
|
{
|
||||||
|
if (app_shortcuts_cached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
app_shortcut_mask = 0;
|
||||||
|
const uint32_t overlay_vma = (uint32_t)PY25Q16_OverlayBuffer();
|
||||||
|
|
||||||
|
for (uint8_t slot = 0; slot < APP_SLOT_COUNT; slot++) {
|
||||||
|
app_header_t h;
|
||||||
|
if (APP_ValidateSlot(slot, &h) != APP_OK || h.link_vma != overlay_vma)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int8_t index = app_shortcut_index(h.name);
|
||||||
|
if (index >= 0) {
|
||||||
|
const uint8_t bit = (uint8_t)(1u << index);
|
||||||
|
if (!(app_shortcut_mask & bit)) {
|
||||||
|
app_shortcut_mask |= bit;
|
||||||
|
app_shortcut_slots[index] = slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app_shortcuts_cached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t APP_OverlayShortcutMask(void)
|
||||||
|
{
|
||||||
|
app_cache_shortcuts();
|
||||||
|
return app_shortcut_mask;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t APP_LaunchOverlayByName(const char *name)
|
uint8_t APP_LaunchOverlayByName(const char *name)
|
||||||
{
|
{
|
||||||
|
const int8_t index = app_shortcut_index(name);
|
||||||
|
if (index >= 0) {
|
||||||
|
app_cache_shortcuts();
|
||||||
|
return (app_shortcut_mask & (1u << index))
|
||||||
|
? APP_LaunchOverlay(app_shortcut_slots[index])
|
||||||
|
: APP_ERR_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
app_header_t h;
|
app_header_t h;
|
||||||
|
|
||||||
for (uint8_t slot = 0; slot < APP_SLOT_COUNT; slot++) {
|
for (uint8_t slot = 0; slot < APP_SLOT_COUNT; slot++) {
|
||||||
@@ -840,6 +892,7 @@ uint8_t APP_SlotErase(uint8_t slot)
|
|||||||
for (uint32_t off = 0; off < APP_SLOT_STRIDE; off += APP_SECTOR_SIZE)
|
for (uint32_t off = 0; off < APP_SLOT_STRIDE; off += APP_SECTOR_SIZE)
|
||||||
PY25Q16_SectorErase(base + off);
|
PY25Q16_SectorErase(base + off);
|
||||||
PY25Q16_InvalidateCache();
|
PY25Q16_InvalidateCache();
|
||||||
|
app_shortcuts_cached = false;
|
||||||
return APP_OK;
|
return APP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,6 +904,7 @@ uint8_t APP_SlotWrite(uint8_t slot, uint32_t offset, const uint8_t *data, uint32
|
|||||||
return APP_ERR_SIZE;
|
return APP_ERR_SIZE;
|
||||||
PY25Q16_WriteBuffer(APP_SLOT_BASE(slot) + offset, data, len, false);
|
PY25Q16_WriteBuffer(APP_SLOT_BASE(slot) + offset, data, len, false);
|
||||||
PY25Q16_InvalidateCache();
|
PY25Q16_InvalidateCache();
|
||||||
|
app_shortcuts_cached = false;
|
||||||
return APP_OK;
|
return APP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,10 @@
|
|||||||
#define APP_NAME_LEN 16
|
#define APP_NAME_LEN 16
|
||||||
#define APP_VERSION_LEN 16
|
#define APP_VERSION_LEN 16
|
||||||
|
|
||||||
|
#define APP_SHORTCUT_FM (1u << 0)
|
||||||
|
#define APP_SHORTCUT_FOXHUNT (1u << 1)
|
||||||
|
#define APP_SHORTCUT_BEACON (1u << 2)
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint32_t magic; /* APP_MAGIC */
|
uint32_t magic; /* APP_MAGIC */
|
||||||
uint16_t hdr_version; /* APP_HDR_VERSION */
|
uint16_t hdr_version; /* APP_HDR_VERSION */
|
||||||
@@ -106,6 +110,9 @@ uint8_t APP_LaunchOverlay(uint8_t slot);
|
|||||||
/* Find the first valid app with this exact header name and launch it. */
|
/* Find the first valid app with this exact header name and launch it. */
|
||||||
uint8_t APP_LaunchOverlayByName(const char *name);
|
uint8_t APP_LaunchOverlayByName(const char *name);
|
||||||
|
|
||||||
|
/* Cached availability of apps exposed as resident quick actions. */
|
||||||
|
uint8_t APP_OverlayShortcutMask(void);
|
||||||
|
|
||||||
/* Host-tool slot management (external flash only, never brick-critical). */
|
/* Host-tool slot management (external flash only, never brick-critical). */
|
||||||
uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header);
|
uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header);
|
||||||
uint8_t APP_SlotErase(uint8_t slot);
|
uint8_t APP_SlotErase(uint8_t slot);
|
||||||
|
|||||||
+1
-1
@@ -301,7 +301,7 @@ const uint8_t BITMAP_NOAA[12] =
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_FEAT_F4HWN_FOXHUNT
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
const uint8_t BITMAP_FoxHuntSignal[10] =
|
const uint8_t BITMAP_FoxHuntSignal[10] =
|
||||||
{ // point source + the speaker bitmap's two sound waves, oriented horizontally
|
{ // point source + the speaker bitmap's two sound waves, oriented horizontally
|
||||||
0b00001000,
|
0b00001000,
|
||||||
|
|||||||
+1
-1
@@ -45,7 +45,7 @@ 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
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
extern const uint8_t BITMAP_FoxHuntSignal[10];
|
extern const uint8_t BITMAP_FoxHuntSignal[10];
|
||||||
extern const uint8_t BITMAP_FoxHuntSpeaker[10];
|
extern const uint8_t BITMAP_FoxHuntSpeaker[10];
|
||||||
extern const uint8_t BITMAP_FoxHuntUp[11];
|
extern const uint8_t BITMAP_FoxHuntUp[11];
|
||||||
|
|||||||
@@ -54,10 +54,9 @@ static const AddrMapping_t ADDR_MAPPINGS[] = {
|
|||||||
_MK_MAPPING(0x009000, 0x009000, 0x0090E7), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old
|
_MK_MAPPING(0x009000, 0x009000, 0x0090E7), // 14 VFO * 16 Bytes = 0x9000 -> 0x90E0 (the old
|
||||||
// 0x90D6 bound was 10 B short: it truncated the
|
// 0x90D6 bound was 10 B short: it truncated the
|
||||||
// 470 MHz VFO1 record at 0x90D0 -> 0x90DF)
|
// 470 MHz VFO1 record at 0x90D0 -> 0x90DF)
|
||||||
// Fox Hunt settings * 7 Bytes 0x90E0 -> 0x90E7
|
// Fox Hunt / Beacon settings * 7 Bytes 0x90E0 -> 0x90E7
|
||||||
// (ENABLE_FEAT_F4HWN_FOXHUNT, written directly by
|
// (written directly by app/foxhunt.c; concatenated
|
||||||
// app/foxhunt.c; concatenated here so aircopy clones
|
// here so aircopy clones them with the VFOs)
|
||||||
// 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
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ unsigned int BATTERY_VoltsToPercent(const unsigned int voltage_10mV)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT)
|
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
void BATTERY_Sample(const bool bDisplayBatteryLevel)
|
void BATTERY_Sample(const bool bDisplayBatteryLevel)
|
||||||
{
|
{
|
||||||
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent);
|
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
unsigned int BATTERY_VoltsToPercent(unsigned int voltage_10mV);
|
unsigned int BATTERY_VoltsToPercent(unsigned int voltage_10mV);
|
||||||
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT)
|
#if defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS) || defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON)
|
||||||
void BATTERY_Sample(bool bDisplayBatteryLevel);
|
void BATTERY_Sample(bool bDisplayBatteryLevel);
|
||||||
#endif
|
#endif
|
||||||
void BATTERY_GetReadings(bool bDisplayBatteryLevel);
|
void BATTERY_GetReadings(bool bDisplayBatteryLevel);
|
||||||
|
|||||||
+2
-1
@@ -126,8 +126,9 @@ enum ACTION_OPT_t {
|
|||||||
ACTION_OPT_POWER_HIGH = 20,
|
ACTION_OPT_POWER_HIGH = 20,
|
||||||
ACTION_OPT_REMOVE_OFFSET = 21,
|
ACTION_OPT_REMOVE_OFFSET = 21,
|
||||||
ACTION_OPT_FOXHUNT = 22,
|
ACTION_OPT_FOXHUNT = 22,
|
||||||
|
ACTION_OPT_BEACON = 23,
|
||||||
|
|
||||||
ACTION_OPT_LEN = 23
|
ACTION_OPT_LEN = 24
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_VOICE
|
#ifdef ENABLE_VOICE
|
||||||
|
|||||||
+2
-1
@@ -495,7 +495,8 @@ const t_sidefunction gSubMenu_SIDEFUNCTIONS[] =
|
|||||||
{"BEAM", ACTION_OPT_BEAM},
|
{"BEAM", ACTION_OPT_BEAM},
|
||||||
{"POWER\nHIGH", ACTION_OPT_POWER_HIGH},
|
{"POWER\nHIGH", ACTION_OPT_POWER_HIGH},
|
||||||
{"REMOVE\nOFFSET", ACTION_OPT_REMOVE_OFFSET},
|
{"REMOVE\nOFFSET", ACTION_OPT_REMOVE_OFFSET},
|
||||||
{"FOX HUNT\nBEACON", ACTION_OPT_FOXHUNT},
|
{"FOX HUNT", ACTION_OPT_FOXHUNT},
|
||||||
|
{"BEACON", ACTION_OPT_BEACON},
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t gSubMenu_SIDEFUNCTIONS_size = ARRAY_SIZE(gSubMenu_SIDEFUNCTIONS);
|
const uint8_t gSubMenu_SIDEFUNCTIONS_size = ARRAY_SIZE(gSubMenu_SIDEFUNCTIONS);
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ static void convertTime(uint8_t *line, uint8_t type)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
void UI_DrawStatusBattery(uint8_t *line, char *str)
|
void UI_DrawStatusBattery(uint8_t *line, char *str)
|
||||||
#else
|
#else
|
||||||
static __attribute__((always_inline)) inline void UI_DrawStatusBattery(uint8_t *line, char *str)
|
static __attribute__((always_inline)) inline void UI_DrawStatusBattery(uint8_t *line, char *str)
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
#if defined(ENABLE_FEAT_F4HWN_FOXHUNT) || defined(ENABLE_FEAT_F4HWN_BEACON) || defined(ENABLE_FEAT_F4HWN_OVERLAY_APPS)
|
||||||
void UI_DrawStatusBattery(uint8_t *line, char *str);
|
void UI_DrawStatusBattery(uint8_t *line, char *str);
|
||||||
#endif
|
#endif
|
||||||
void UI_DisplayStatus();
|
void UI_DisplayStatus();
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
"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_FOXHUNT": false,
|
||||||
|
"ENABLE_FEAT_F4HWN_BEACON": false,
|
||||||
"ENABLE_FEAT_F4HWN_ACTION_PICKER": false,
|
"ENABLE_FEAT_F4HWN_ACTION_PICKER": 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,
|
||||||
@@ -132,6 +133,7 @@
|
|||||||
"ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": true,
|
"ENABLE_FEAT_F4HWN_SCAN_SUBAUDIBLE": true,
|
||||||
"ENABLE_FEAT_F4HWN_BEAM": false,
|
"ENABLE_FEAT_F4HWN_BEAM": false,
|
||||||
"ENABLE_FEAT_F4HWN_FOXHUNT": false,
|
"ENABLE_FEAT_F4HWN_FOXHUNT": false,
|
||||||
|
"ENABLE_FEAT_F4HWN_BEACON": false,
|
||||||
"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,
|
||||||
@@ -155,6 +157,7 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
||||||
"ENABLE_FEAT_F4HWN_FOXHUNT": true,
|
"ENABLE_FEAT_F4HWN_FOXHUNT": true,
|
||||||
|
"ENABLE_FEAT_F4HWN_BEACON": true,
|
||||||
"EDITION_STRING": "FieldOps",
|
"EDITION_STRING": "FieldOps",
|
||||||
"TARGET": "f4hwn.fieldops"
|
"TARGET": "f4hwn.fieldops"
|
||||||
}
|
}
|
||||||
@@ -175,6 +178,7 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
"ENABLE_FEAT_F4HWN_RESCUE_OPS": true,
|
||||||
"ENABLE_FEAT_F4HWN_FOXHUNT": false,
|
"ENABLE_FEAT_F4HWN_FOXHUNT": false,
|
||||||
|
"ENABLE_FEAT_F4HWN_BEACON": false,
|
||||||
"ENABLE_AIRCOPY": true,
|
"ENABLE_AIRCOPY": true,
|
||||||
"ENABLE_FEAT_F4HWN_BEAM": true,
|
"ENABLE_FEAT_F4HWN_BEAM": true,
|
||||||
"ENABLE_FEAT_F4HWN_GAME": false,
|
"ENABLE_FEAT_F4HWN_GAME": false,
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ Specialized presets extend Fusion for specific uses:
|
|||||||
- selectable RF attenuation,
|
- selectable RF attenuation,
|
||||||
- silent, Geiger-style and received-audio modes,
|
- silent, Geiger-style and received-audio modes,
|
||||||
- long-press `F` keypad lock (attenuation stays adjustable with the arrow keys).
|
- long-press `F` keypad lock (attenuation stays adjustable with the arrow keys).
|
||||||
- Integrated Morse Beacon transmitter with:
|
- Independent Morse Beacon transmitter with:
|
||||||
- `MOE`, `MOI`, `MOS`, `MOH`, `MO5` and `MO` identifiers,
|
- `MOE`, `MOI`, `MOS`, `MOH`, `MO5` and `MO` identifiers,
|
||||||
- optional callsign identification,
|
- optional callsign identification,
|
||||||
- configurable TX and idle periods,
|
- configurable TX and idle periods,
|
||||||
@@ -264,7 +264,8 @@ Specialized presets extend Fusion for specific uses:
|
|||||||
- offset removal,
|
- offset removal,
|
||||||
- BEAM,
|
- BEAM,
|
||||||
- RF Log,
|
- RF Log,
|
||||||
- Fox Hunt / Beacon.
|
- Fox Hunt,
|
||||||
|
- Beacon.
|
||||||
|
|
||||||
### Reliability and optimization
|
### Reliability and optimization
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user