Optimize FM and overlay shortcuts

This commit is contained in:
Armel FAUVEAU committed 2026-08-31 02:03:28 +02:00
1 parent 99057f9dd2
commit 62906636ed
8 files changed
+74 -36

No files matched your search

+3 -3
View File
@@ -502,7 +502,7 @@ void ACTION_FoxHunt(void)
APP_RunFoxHunt();
GUI_SelectNextDisplay(DISPLAY_MAIN);
#else
if (APP_LaunchOverlayByName("FoxHunt") != APP_OK)
if (APP_LaunchOverlayShortcut(APP_SHORTCUT_FOXHUNT) != APP_OK)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
#endif
}
@@ -515,7 +515,7 @@ void ACTION_Beacon(void)
APP_RunBeacon();
GUI_SelectNextDisplay(DISPLAY_MAIN);
#else
if (APP_LaunchOverlayByName("Beacon") != APP_OK)
if (APP_LaunchOverlayShortcut(APP_SHORTCUT_BEACON) != APP_OK)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
#endif
}
@@ -526,7 +526,7 @@ void ACTION_Beacon(void)
void ACTION_FM(void)
{
#ifdef ENABLE_FEAT_F4HWN_OVERLAY_APPS
if (APP_LaunchOverlayByName("Broadcast FM") != APP_OK)
if (APP_LaunchOverlayShortcut(APP_SHORTCUT_FM) != APP_OK)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
#else
+31 -1
View File
@@ -52,8 +52,9 @@ const uint8_t BUTTON_EVENT_HELD = BUTTON_STATE_PRESSED | BUTTON_STATE_HELD;
const uint8_t BUTTON_EVENT_SHORT = 0;
const uint8_t BUTTON_EVENT_LONG = BUTTON_STATE_HELD;
#ifndef ENABLE_FEAT_F4HWN_OVERLAY_APPS
static void Key_FUNC(KEY_Code_t Key, uint8_t state);
#endif
bool FM_CheckValidChannel(uint8_t Channel)
{
@@ -94,6 +95,7 @@ int FM_ConfigureChannelState(void)
return 0;
}
#ifndef ENABLE_FEAT_F4HWN_OVERLAY_APPS
void FM_SetFrequency(void)
{
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
@@ -196,6 +198,7 @@ void FM_PlayAndUpdate(void)
BACKLIGHT_TurnOn();
FM_AudioPathOn();
}
#endif
int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit)
{
@@ -240,6 +243,7 @@ int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit)
return 0;
}
#ifndef ENABLE_FEAT_F4HWN_OVERLAY_APPS
static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
{
enum { STATE_FREQ_MODE, STATE_MR_MODE, STATE_SAVE };
@@ -662,5 +666,31 @@ void FM_Start(void)
SETTINGS_WriteCurrentState();
#endif
}
#else
/*
* Broadcast FM is sovereign in Overlay builds: its app owns tuning, scanning,
* audio and persistence through app_api. Keep only the shared channel/state
* loader and FM_CheckFrequencyLock above; these tiny compatibility entry points
* satisfy generic firmware paths which cannot become active because Overlay
* builds never set gFmRadioMode or gFM_ScanState.
*/
void FM_TurnOff(void) {}
void FM_EraseChannels(void) {}
void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag)
{
(void)Frequency;
(void)Step;
(void)bFlag;
}
void FM_PlayAndUpdate(void) {}
void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
(void)Key;
(void)bKeyPressed;
(void)bKeyHeld;
}
void FM_Play(void) {}
void FM_Start(void) {}
#endif
#endif
+15 -23
View File
@@ -671,11 +671,11 @@ 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)
static int8_t app_shortcut_index(uint8_t shortcut)
{
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;
if (shortcut == APP_SHORTCUT_FM) return 0;
if (shortcut == APP_SHORTCUT_FOXHUNT) return 1;
if (shortcut == APP_SHORTCUT_BEACON) return 2;
return -1;
}
@@ -692,11 +692,12 @@ static void app_cache_shortcuts(void)
if (APP_ValidateSlot(slot, &h) != APP_OK || h.link_vma != overlay_vma)
continue;
const int8_t index = app_shortcut_index(h.name);
const uint8_t shortcut = (uint8_t)((h.flags & APP_FLAG_SHORTCUT_MASK) >>
APP_FLAG_SHORTCUT_SHIFT);
const int8_t index = app_shortcut_index(shortcut);
if (index >= 0) {
const uint8_t bit = (uint8_t)(1u << index);
if (!(app_shortcut_mask & bit)) {
app_shortcut_mask |= bit;
if (!(app_shortcut_mask & shortcut)) {
app_shortcut_mask |= shortcut;
app_shortcut_slots[index] = slot;
}
}
@@ -711,27 +712,18 @@ uint8_t APP_OverlayShortcutMask(void)
return app_shortcut_mask;
}
uint8_t APP_LaunchOverlayByName(const char *name)
uint8_t APP_LaunchOverlayShortcut(uint8_t shortcut)
{
const int8_t index = app_shortcut_index(name);
if (index >= 0) {
const int8_t index = app_shortcut_index(shortcut);
if (index < 0)
return APP_ERR_MAGIC;
app_cache_shortcuts();
return (app_shortcut_mask & (1u << index))
return (app_shortcut_mask & shortcut)
? APP_LaunchOverlay(app_shortcut_slots[index])
: APP_ERR_MAGIC;
}
app_header_t h;
for (uint8_t slot = 0; slot < APP_SLOT_COUNT; slot++) {
if (APP_ValidateSlot(slot, &h) == APP_OK &&
strncmp(h.name, name, APP_NAME_LEN) == 0)
return APP_LaunchOverlay(slot);
}
return APP_ERR_MAGIC;
}
uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header)
{
if (slot >= APP_SLOT_COUNT)
+7 -5
View File
@@ -68,12 +68,14 @@
#define APP_HDR_VERSION 1u
#define APP_FLAG_COMMITTED 0x0001u
#define APP_FLAG_SCREEN_SAVER 0x0002u
#define APP_FLAG_SHORTCUT_SHIFT 8u
#define APP_FLAG_SHORTCUT_MASK 0x0700u
#define APP_NAME_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)
#define APP_SHORTCUT_FM 0x01u
#define APP_SHORTCUT_FOXHUNT 0x02u
#define APP_SHORTCUT_BEACON 0x04u
typedef struct __attribute__((packed)) {
uint32_t magic; /* APP_MAGIC */
@@ -108,8 +110,8 @@ uint8_t APP_ValidateSlot(uint8_t slot, app_header_t *out_header);
* Returns when the app exits; the internal flash is never touched. */
uint8_t APP_LaunchOverlay(uint8_t slot);
/* Find the first valid app with this exact header name and launch it. */
uint8_t APP_LaunchOverlayByName(const char *name);
/* Launch the first installed app advertising this shortcut bit. */
uint8_t APP_LaunchOverlayShortcut(uint8_t shortcut);
/* Cached availability of apps exposed as resident quick actions. */
uint8_t APP_OverlayShortcutMask(void);
+2 -1
View File
@@ -29,7 +29,8 @@ trap 'printf "\r ❌ %-13s build failed \n" "$APP_NAME"' ERR
step 1 compile ; "$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf"
step 2 objcopy ; "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin"
step 3 pack ; python3 ../pack_app.py "${APP}.bin" "${OUT}.app" \
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" >/dev/null
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" \
--shortcut beacon >/dev/null
trap - ERR
BYTES=$(wc -c < "${APP}.bin")
+2 -1
View File
@@ -29,7 +29,8 @@ trap 'printf "\r ❌ %-13s build failed \n" "$APP_NAME"' ERR
step 1 compile ; "$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf"
step 2 objcopy ; "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin"
step 3 pack ; python3 ../pack_app.py "${APP}.bin" "${OUT}.app" \
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" --screensaver >/dev/null
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" \
--shortcut fm --screensaver >/dev/null
trap - ERR
BYTES=$(wc -c < "${APP}.bin")
+2 -1
View File
@@ -29,7 +29,8 @@ trap 'printf "\r ❌ %-13s build failed \n" "$APP_NAME"' ERR
step 1 compile ; "$CC" $CFLAGS $LDFLAGS "${APP}_app.c" -lgcc -o "${APP}.elf"
step 2 objcopy ; "$OBJCOPY" -O binary "${APP}.elf" "${APP}.bin"
step 3 pack ; python3 ../pack_app.py "${APP}.bin" "${OUT}.app" \
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" >/dev/null
--name "$APP_NAME" --ver "$APP_VER" --vma "${APP_VMA}" \
--shortcut foxhunt >/dev/null
trap - ERR
BYTES=$(wc -c < "${APP}.bin")
+12 -1
View File
@@ -32,6 +32,13 @@ ABI_VERSION = cdefine("app_api.h", "APP_ABI_VERSION")
OVERLAY_MAX = cdefine("app_overlay.h", "APP_OVERLAY_MAX") # 4 KiB overlay budget
FLAG_COMMITTED = cdefine("app_overlay.h", "APP_FLAG_COMMITTED")
FLAG_SCREEN_SAVER = cdefine("app_overlay.h", "APP_FLAG_SCREEN_SAVER")
FLAG_SHORTCUT_SHIFT = cdefine("app_overlay.h", "APP_FLAG_SHORTCUT_SHIFT")
SHORTCUTS = {
"none": 0,
"fm": cdefine("app_overlay.h", "APP_SHORTCUT_FM"),
"foxhunt": cdefine("app_overlay.h", "APP_SHORTCUT_FOXHUNT"),
"beacon": cdefine("app_overlay.h", "APP_SHORTCUT_BEACON"),
}
def field(s: str, n: int) -> bytes:
b = s.encode("ascii", "strict")[: n - 1]
@@ -48,6 +55,8 @@ def main():
help="RAM VMA the app was linked at (must match the firmware overlay)")
ap.add_argument("--screensaver", action="store_true",
help="allow the resident BLTime screen saver while this app is idle")
ap.add_argument("--shortcut", choices=SHORTCUTS, default="none",
help="resident quick action advertised by this app")
a = ap.parse_args()
code = open(a.infile, "rb").read()
@@ -57,7 +66,9 @@ def main():
sys.exit(f"code {len(code)} B exceeds overlay budget {OVERLAY_MAX} B")
crc = zlib.crc32(code) & 0xFFFFFFFF
flags = FLAG_COMMITTED | (FLAG_SCREEN_SAVER if a.screensaver else 0)
flags = (FLAG_COMMITTED |
(FLAG_SCREEN_SAVER if a.screensaver else 0) |
(SHORTCUTS[a.shortcut] << FLAG_SHORTCUT_SHIFT))
header = struct.pack(
"<4sHHIIHH16s16sI8s",
MAGIC, HDR_VERSION, ABI_VERSION,