Make Triple VFO and Beam overlay services optional

This commit is contained in:
Armel FAUVEAU committed 2026-09-02 20:22:00 +02:00
1 parent 9019d0df1a
commit e7db0bc1dc
8 files changed
+46 -9

No files matched your search

+6
View File
@@ -201,9 +201,15 @@ enable_feature(ENABLE_FEAT_F4HWN_OVERLAY_APPS
apps/app_overlay.c apps/app_overlay.c
apps/app_menu.c apps/app_menu.c
) )
enable_feature(ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO)
enable_feature(ENABLE_FEAT_F4HWN_OVERLAY_BEAM)
if(ENABLE_FEAT_F4HWN_OVERLAY_APPS AND NOT ENABLE_FEAT_F4HWN_MULTIBOOT_OVERLAY) if(ENABLE_FEAT_F4HWN_OVERLAY_APPS AND NOT ENABLE_FEAT_F4HWN_MULTIBOOT_OVERLAY)
message(FATAL_ERROR "ENABLE_FEAT_F4HWN_OVERLAY_APPS requires ENABLE_FEAT_F4HWN_MULTIBOOT_OVERLAY (the 4 KiB overlay workspace).") message(FATAL_ERROR "ENABLE_FEAT_F4HWN_OVERLAY_APPS requires ENABLE_FEAT_F4HWN_MULTIBOOT_OVERLAY (the 4 KiB overlay workspace).")
endif() endif()
if((ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO OR ENABLE_FEAT_F4HWN_OVERLAY_BEAM) AND
NOT ENABLE_FEAT_F4HWN_OVERLAY_APPS)
message(FATAL_ERROR "Overlay Triple VFO/Beam services require ENABLE_FEAT_F4HWN_OVERLAY_APPS.")
endif()
enable_feature(ENABLE_FEAT_F4HWN_K5VIEWER enable_feature(ENABLE_FEAT_F4HWN_K5VIEWER
k5viewer.c k5viewer.c
) )
+2 -2
View File
@@ -255,7 +255,7 @@ typedef struct app_api {
* Returns 0 for any other key. Keep get_key() raw for spatial controls. */ * Returns 0 for any other key. Keep get_key() raw for spatial controls. */
int8_t (*nav_dir)(uint8_t key); int8_t (*nav_dir)(uint8_t key);
/* ---- triple VFO (API level 1 baseline) ---- /* ---- triple VFO (optional resident capability APP_CAP_TRIVFO) ----
* A and B are the live Main Display VFOs. C is a resident temporary VFO * A and B are the live Main Display VFOs. C is a resident temporary VFO
* loaded from c_channel (or the first valid memory after B when invalid). * loaded from c_channel (or the first valid memory after B when invalid).
* tick is called every 20 ms by the app and returns APP_TRIVFO_* state. */ * tick is called every 20 ms by the app and returns APP_TRIVFO_* state. */
@@ -267,7 +267,7 @@ typedef struct app_api {
uint8_t (*trivfo_tick)(void); uint8_t (*trivfo_tick)(void);
uint8_t (*trivfo_ptt)(bool pressed); /* physical PTT edge; resident applies SetPTT */ uint8_t (*trivfo_ptt)(bool pressed); /* physical PTT edge; resident applies SetPTT */
/* ---- BEAM channel transfer (API level 1 baseline) ---- */ /* ---- BEAM channel transfer (optional resident capability APP_CAP_BEAM) ---- */
void (*beam_prepare)(void); /* tune the fixed narrow-band FSK channel */ void (*beam_prepare)(void); /* tune the fixed narrow-band FSK channel */
void (*beam_leave)(void); /* defensively stop FSK before app return */ void (*beam_leave)(void); /* defensively stop FSK before app return */
void (*beam_get)(app_beam_channel_t *channel); /* export selected VFO */ void (*beam_get)(app_beam_channel_t *channel); /* export selected VFO */
+30 -5
View File
@@ -54,11 +54,18 @@
_Static_assert(sizeof(app_header_t) == 64, "app_header_t must be 64 bytes"); _Static_assert(sizeof(app_header_t) == 64, "app_header_t must be 64 bytes");
_Static_assert(sizeof(app_api_t) <= UINT16_MAX, "app_api_t size field overflow"); _Static_assert(sizeof(app_api_t) <= UINT16_MAX, "app_api_t size field overflow");
enum {
APP_AVAILABLE_CAPS = 0u
#ifdef ENABLE_FMRADIO #ifdef ENABLE_FMRADIO
#define APP_AVAILABLE_CAPS APP_CAP_FM | APP_CAP_FM
#else
#define APP_AVAILABLE_CAPS 0u
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
| APP_CAP_TRIVFO
#endif
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_BEAM
| APP_CAP_BEAM
#endif
};
/* ---- ABI wrappers: the few resident calls that are not a direct signature match ---- */ /* ---- ABI wrappers: the few resident calls that are not a direct signature match ---- */
static bool app_allow_screen_saver; static bool app_allow_screen_saver;
@@ -137,7 +144,8 @@ static void app_play_tone(uint16_t tone, uint16_t ms)
AUDIO_AudioPathOff(); AUDIO_AudioPathOff();
} }
/* ---- API level 1: resident triple-VFO engine ---------------------------- #ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
/* ---- optional resident triple-VFO engine --------------------------------
* The overlay owns the UI and key timing, while this resident engine owns all * The overlay owns the UI and key timing, while this resident engine owns all
* radio details. Keeping VFO_Info_t and BK4819 sequencing on this side makes * radio details. Keeping VFO_Info_t and BK4819 sequencing on this side makes
* the app independent of feature-dependent firmware layouts. */ * the app independent of feature-dependent firmware layouts. */
@@ -532,8 +540,10 @@ static uint8_t app_trivfo_ptt(bool pressed)
app_trivfo_tx_ticks = 0; app_trivfo_tx_ticks = 0;
return 0; return 0;
} }
#endif
/* ---- API level 1: BEAM radio/channel bridge ------------------------------- #ifdef ENABLE_FEAT_F4HWN_OVERLAY_BEAM
/* ---- optional BEAM radio/channel bridge -----------------------------------
* The modal app owns the packet format, CRC, UI and state machine. Resident * The modal app owns the packet format, CRC, UI and state machine. Resident
* code only translates the stable ABI channel structure and performs the FSK * code only translates the stable ABI channel structure and performs the FSK
* operations which depend on VFO_Info_t and the BK4819 driver. */ * operations which depend on VFO_Info_t and the BK4819 driver. */
@@ -757,6 +767,7 @@ static void app_beam_draw(const char *status)
memset(gFrameBuffer[line], 0, LCD_WIDTH); memset(gFrameBuffer[line], 0, LCD_WIDTH);
UI_PrintStringSmallBold(status, 2, LCD_WIDTH - 1u, line); UI_PrintStringSmallBold(status, 2, LCD_WIDTH - 1u, line);
} }
#endif
/* ---- radio wrappers ---- */ /* ---- radio wrappers ---- */
static int16_t app_rssi_dbm(void) { return BK4819_GetRSSI_dBm() + dBmCorrTable[gRxVfo->Band]; } static int16_t app_rssi_dbm(void) { return BK4819_GetRSSI_dBm() + dBmCorrTable[gRxVfo->Band]; }
@@ -803,8 +814,10 @@ static void app_battery_sample(void)
/* The resident scheduler deliberately skips ADC battery updates while the /* The resident scheduler deliberately skips ADC battery updates while the
* PA is keyed. Do the same for Triple VFO: sampling the loaded voltage as * PA is keyed. Do the same for Triple VFO: sampling the loaded voltage as
* capacity made an 80% pack appear to fall immediately to about 16%. */ * capacity made an 80% pack appear to fall immediately to about 16%. */
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
if (app_trivfo_transmitting) if (app_trivfo_transmitting)
return; return;
#endif
BATTERY_Sample(false); BATTERY_Sample(false);
} }
@@ -1039,6 +1052,7 @@ static const app_api_t app_api = {
.fm_commit = app_fm_commit, .fm_commit = app_fm_commit,
#endif #endif
.nav_dir = app_nav_dir, .nav_dir = app_nav_dir,
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
.trivfo_enter = app_trivfo_enter, .trivfo_enter = app_trivfo_enter,
.trivfo_leave = app_trivfo_leave, .trivfo_leave = app_trivfo_leave,
.trivfo_get = app_trivfo_get, .trivfo_get = app_trivfo_get,
@@ -1046,6 +1060,8 @@ static const app_api_t app_api = {
.trivfo_step = app_trivfo_step, .trivfo_step = app_trivfo_step,
.trivfo_tick = app_trivfo_tick, .trivfo_tick = app_trivfo_tick,
.trivfo_ptt = app_trivfo_ptt, .trivfo_ptt = app_trivfo_ptt,
#endif
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_BEAM
.beam_prepare = app_beam_prepare, .beam_prepare = app_beam_prepare,
.beam_leave = app_beam_leave, .beam_leave = app_beam_leave,
.beam_get = app_beam_get, .beam_get = app_beam_get,
@@ -1054,6 +1070,7 @@ static const app_api_t app_api = {
.beam_rx = app_beam_rx, .beam_rx = app_beam_rx,
.beam_rx_poll = app_beam_rx_poll, .beam_rx_poll = app_beam_rx_poll,
.beam_draw = app_beam_draw, .beam_draw = app_beam_draw,
#endif
}; };
uint8_t APP_LaunchOverlay(uint8_t slot) uint8_t APP_LaunchOverlay(uint8_t slot)
@@ -1092,7 +1109,9 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
#ifdef ENABLE_FMRADIO #ifdef ENABLE_FMRADIO
app_fm_dirty = false; app_fm_dirty = false;
#endif #endif
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_BEAM
app_beam_dirty = false; app_beam_dirty = false;
#endif
app_allow_screen_saver = (h.flags & APP_FLAG_SCREEN_SAVER) != 0; app_allow_screen_saver = (h.flags & APP_FLAG_SCREEN_SAVER) != 0;
app_screen_saver_wake = false; app_screen_saver_wake = false;
@@ -1129,7 +1148,9 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
app_screen_saver_wake = false; app_screen_saver_wake = false;
/* A defensive leave also covers an app returning through an error path. */ /* A defensive leave also covers an app returning through an error path. */
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
app_trivfo_leave(); app_trivfo_leave();
#endif
/* Restore the resident RX/dual-watch tuning the app ran on top of. */ /* Restore the resident RX/dual-watch tuning the app ran on top of. */
gEeprom.RX_VFO = saved_rx_vfo; gEeprom.RX_VFO = saved_rx_vfo;
@@ -1139,8 +1160,11 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
/* The overlay held app code, not a valid config sector. */ /* The overlay held app code, not a valid config sector. */
PY25Q16_InvalidateCache(); PY25Q16_InvalidateCache();
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_BEAM
app_beam_commit(); app_beam_commit();
#endif
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO
if (app_trivfo_ab_dirty) { if (app_trivfo_ab_dirty) {
SETTINGS_SaveVfoIndices(); SETTINGS_SaveVfoIndices();
app_trivfo_ab_dirty = false; app_trivfo_ab_dirty = false;
@@ -1152,6 +1176,7 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
&gEeprom.VfoInfo[i], 1); &gEeprom.VfoInfo[i], 1);
} }
app_trivfo_freq_dirty = 0; app_trivfo_freq_dirty = 0;
#endif
/* Commit any deferred config the app staged (RMW keeps the slot header). */ /* Commit any deferred config the app staged (RMW keeps the slot header). */
if (app_cfg_len) { if (app_cfg_len) {
+2
View File
@@ -81,6 +81,8 @@
/* Optional resident facilities an app may require. Requirements live in the /* Optional resident facilities an app may require. Requirements live in the
* previously reserved header bytes, so app_header_t remains 64 bytes. */ * previously reserved header bytes, so app_header_t remains 64 bytes. */
#define APP_CAP_FM 0x00000001u #define APP_CAP_FM 0x00000001u
#define APP_CAP_TRIVFO 0x00000002u
#define APP_CAP_BEAM 0x00000004u
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint32_t magic; /* APP_MAGIC */ uint32_t magic; /* APP_MAGIC */
+1 -1
View File
@@ -26,7 +26,7 @@ step 1 compile ; "$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf"
step 2 objcopy ; "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin" step 2 objcopy ; "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin"
step 3 pack ; python3 ../pack_app.py "${APP}.bin" "${OUT}.app" \ step 3 pack ; python3 ../pack_app.py "${APP}.bin" "${OUT}.app" \
--name "$APP_NAME" --ver "$APP_VER" --api-min "$APP_API_MIN" --vma "${APP_VMA}" \ --name "$APP_NAME" --ver "$APP_VER" --api-min "$APP_API_MIN" --vma "${APP_VMA}" \
--shortcut beam >/dev/null --shortcut beam --require beam >/dev/null
trap - ERR trap - ERR
BYTES=$(wc -c < "${APP}.bin") BYTES=$(wc -c < "${APP}.bin")
+2
View File
@@ -44,6 +44,8 @@ SHORTCUTS = {
} }
CAPABILITIES = { CAPABILITIES = {
"fm": cdefine("app_overlay.h", "APP_CAP_FM"), "fm": cdefine("app_overlay.h", "APP_CAP_FM"),
"trivfo": cdefine("app_overlay.h", "APP_CAP_TRIVFO"),
"beam": cdefine("app_overlay.h", "APP_CAP_BEAM"),
} }
def field(s: str, n: int) -> bytes: def field(s: str, n: int) -> bytes:
+1 -1
View File
@@ -14,7 +14,7 @@ LDFLAGS="-nostdlib -nostartfiles -T app.ld -Wl,--defsym,APP_VMA=${APP_VMA} -Wl,-
rm -f ./*.app ./*.elf ./*.bin rm -f ./*.app ./*.elf ./*.bin
"$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf" "$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf"
"$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin" "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin"
python3 ../pack_app.py "${APP}.bin" "${OUT}.app" --name "$APP_NAME" --ver "$APP_VER" --api-min "$APP_API_MIN" --vma "${APP_VMA}" --screensaver >/dev/null python3 ../pack_app.py "${APP}.bin" "${OUT}.app" --name "$APP_NAME" --ver "$APP_VER" --api-min "$APP_API_MIN" --vma "${APP_VMA}" --require trivfo --screensaver >/dev/null
BYTES=$(wc -c < "${APP}.bin") BYTES=$(wc -c < "${APP}.bin")
test "$BYTES" -le 4096 test "$BYTES" -le 4096
printf ' ✅ %-13s %4d B (%d%% of 4 KiB) -> %s.app\n' \ printf ' ✅ %-13s %4d B (%d%% of 4 KiB) -> %s.app\n' \
+2
View File
@@ -183,6 +183,8 @@
"ENABLE_FEAT_F4HWN_BEAM": false, "ENABLE_FEAT_F4HWN_BEAM": false,
"ENABLE_FEAT_F4HWN_GAME": false, "ENABLE_FEAT_F4HWN_GAME": false,
"ENABLE_FEAT_F4HWN_OVERLAY_APPS": true, "ENABLE_FEAT_F4HWN_OVERLAY_APPS": true,
"ENABLE_FEAT_F4HWN_OVERLAY_TRIVFO": false,
"ENABLE_FEAT_F4HWN_OVERLAY_BEAM": true,
"EDITION_STRING": "Labs", "EDITION_STRING": "Labs",
"TARGET": "f4hwn.labs" "TARGET": "f4hwn.labs"
} }