Optimize overlay ABI and reduce flash footprint

This commit is contained in:
Armel FAUVEAU committed 2026-08-30 13:15:16 +02:00
1 parent 8c78d28f0d
commit 88e76b0e9b
14 files changed
+126 -126

No files matched your search

+73 -100
View File
@@ -28,6 +28,7 @@
#include "app/fm.h"
#endif
#include "driver/keyboard.h"
#include "driver/mb_flash.h"
#include "driver/py25q16.h"
#include "driver/st7565.h"
#include "driver/system.h"
@@ -47,22 +48,7 @@
_Static_assert(sizeof(app_header_t) == 64, "app_header_t must be 64 bytes");
/* CRC-32 (zlib) over RAM bytes - matches App/apps/pack_app.py and the firmware's
* mb_ext_image_crc32 (init 0xFFFFFFFF, poly 0xEDB88320, final XOR). */
static uint32_t app_crc32(const uint8_t *p, uint32_t len)
{
uint32_t crc = 0xFFFFFFFFu;
while (len--) {
crc ^= *p++;
for (int k = 0; k < 8; k++)
crc = (crc >> 1) ^ (0xEDB88320u & (0u - (crc & 1u)));
}
return crc ^ 0xFFFFFFFFu;
}
/* ---- ABI wrappers: the few resident calls that are not a direct signature match ---- */
static void app_display_clear(void) { UI_DisplayClear(); }
static void app_status_clear(void) { UI_StatusClear(); }
static uint8_t app_get_key(void) { return (uint8_t)KEYBOARD_GetKey(); }
static int8_t app_nav_dir(uint8_t key)
{
@@ -87,14 +73,6 @@ static void app_play_tone(uint16_t tone, uint16_t ms)
AUDIO_AudioPathOff();
}
static uint32_t app_make_seed(void)
{
/* Reproduces the original Breakout seed source. */
return BK4819_ReadRegister(BK4819_REG_67) & 0x01FF
* gBatteryVoltageAverage
* gEeprom.VfoInfo[0].pRX->Frequency;
}
/* ---- ABI 4: resident triple-VFO engine ---------------------------------
* 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
@@ -519,10 +497,7 @@ static void app_battery_sample(void)
if (app_trivfo_transmitting)
return;
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryVoltageIndex++], &gBatteryCurrent);
if (gBatteryVoltageIndex > 3)
gBatteryVoltageIndex = 0;
BATTERY_GetReadings(false);
BATTERY_Sample(false);
}
/* ---- v2 TX (beacon) ---- */
@@ -569,7 +544,6 @@ static void app_fm_exit(void)
BK4819_PickRXFilterPathBasedOnFrequency(gRxVfo->pRX->Frequency); /* restore RX filter */
}
static void app_fm_set_freq(uint16_t f, uint8_t b) { BK1080_SetFrequency(f, b); }
static uint16_t app_fm_read(uint8_t r) { return BK1080_ReadRegister((BK1080_Register_t)r); }
static uint16_t app_fm_lo(uint8_t b) { return BK1080_GetFreqLoLimit(b); }
static uint16_t app_fm_hi(uint8_t b) { return BK1080_GetFreqHiLimit(b); }
static void app_fm_mute(bool m) { BK1080_Mute(m); }
@@ -628,6 +602,75 @@ uint8_t APP_SlotInfo(uint8_t slot, app_header_t *out_header)
return (h.magic == APP_MAGIC) ? APP_OK : APP_ERR_MAGIC;
}
/* All services are immutable. Keeping the table in flash avoids rebuilding a
* roughly quarter-kilobyte automatic object on every launch and removes that
* object from the launcher's stack frame. */
static const app_api_t app_api = {
.abi_version = APP_ABI_VERSION,
.fb = gFrameBuffer,
.display_clear = UI_DisplayClear,
.status_clear = UI_StatusClear,
.draw_line = UI_DrawLineBuffer,
.draw_rect = UI_DrawRectangleBuffer,
.print_bold = UI_PrintStringSmallBold,
.print_tiny = GUI_DisplaySmallest,
.blit_full = ST7565_BlitFullScreen,
.blit_line = ST7565_BlitLine,
.blit_status = ST7565_BlitStatusLine,
.get_key = app_get_key,
.delay_ms = SYSTEM_DelayMs,
.play_tone = app_play_tone,
.led = app_led,
.print_normal = UI_PrintStringSmallNormal,
.print_inverse = GUI_DisplaySmallestInverse,
.display_freq = UI_DisplayFrequency,
.rssi_dbm = app_rssi_dbm,
.bk_read = app_bk_read,
.bk_write = app_bk_write,
.set_agc = BK4819_SetAGC,
.set_af = app_set_af,
.audio_path = app_audio_path,
.prepare_tone = app_prepare_tone,
.play_tone_raw = app_play_tone_raw,
.tones_off_rx = app_tones_off_rx,
.rx_freq = app_rx_freq,
.cfg_load = app_cfg_load,
.cfg_save = app_cfg_save,
.draw_battery = app_draw_battery,
.battery_sample = app_battery_sample,
.backlight_on = BACKLIGHT_TurnOn,
.backlight_update = BACKLIGHT_Update,
.status_line = gStatusLine,
.tx_state = app_tx_state,
.tx_set_params = app_tx_set_params,
.tx_tone = app_tx_tone,
.tx_mute = app_tx_mute,
.tx_end = app_tx_end,
.tx_freq = app_tx_freq,
.boot_callsign = app_boot_callsign,
.print_string = UI_PrintString,
#ifdef ENABLE_FMRADIO
.fm_enter = app_fm_enter,
.fm_exit = app_fm_exit,
.fm_set_freq = app_fm_set_freq,
.fm_lo = app_fm_lo,
.fm_hi = app_fm_hi,
.fm_mute = app_fm_mute,
.fm_valid = app_fm_valid,
.fm_channels = gFM_Channels,
.fm_state = app_fm_state,
.fm_commit = app_fm_commit,
#endif
.nav_dir = app_nav_dir,
.trivfo_enter = app_trivfo_enter,
.trivfo_leave = app_trivfo_leave,
.trivfo_get = app_trivfo_get,
.trivfo_select = app_trivfo_select,
.trivfo_step = app_trivfo_step,
.trivfo_tick = app_trivfo_tick,
.trivfo_ptt = app_trivfo_ptt,
};
uint8_t APP_LaunchOverlay(uint8_t slot)
{
app_header_t h;
@@ -650,7 +693,7 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
memset(ws, 0, APP_OVERLAY_MAX);
PY25Q16_ReadBuffer(APP_SLOT_BASE(slot) + APP_CODE_OFFSET, ws, h.code_size);
if (app_crc32(ws, h.code_size) != h.code_crc32) {
if (MB_Crc32Bytes(ws, h.code_size) != h.code_crc32) {
PY25Q16_InvalidateCache();
return APP_ERR_CRC;
}
@@ -659,76 +702,6 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
__DSB();
__ISB();
const app_api_t api = {
.abi_version = APP_ABI_VERSION,
.fb = gFrameBuffer,
.display_clear = app_display_clear,
.status_clear = app_status_clear,
.draw_line = UI_DrawLineBuffer,
.draw_rect = UI_DrawRectangleBuffer,
.print_bold = UI_PrintStringSmallBold,
.print_tiny = GUI_DisplaySmallest,
.blit_full = ST7565_BlitFullScreen,
.blit_line = ST7565_BlitLine,
.blit_status = ST7565_BlitStatusLine,
.get_key = app_get_key,
.delay_ms = SYSTEM_DelayMs,
.backlight_tick = BACKLIGHT_UpdateTickless,
.play_tone = app_play_tone,
.led = app_led,
.seed = app_make_seed(),
/* v2 */
.print_normal = UI_PrintStringSmallNormal,
.print_inverse = GUI_DisplaySmallestInverse,
.display_freq = UI_DisplayFrequency,
.rssi_dbm = app_rssi_dbm,
.bk_read = app_bk_read,
.bk_write = app_bk_write,
.set_agc = BK4819_SetAGC,
.set_af = app_set_af,
.audio_path = app_audio_path,
.prepare_tone = app_prepare_tone,
.play_tone_raw = app_play_tone_raw,
.tones_off_rx = app_tones_off_rx,
.rx_freq = app_rx_freq,
.cfg_load = app_cfg_load,
.cfg_save = app_cfg_save,
.draw_battery = app_draw_battery,
.battery_sample = app_battery_sample,
.backlight_on = BACKLIGHT_TurnOn,
.backlight_update = BACKLIGHT_Update,
.status_line = gStatusLine,
.tx_state = app_tx_state,
.tx_set_params = app_tx_set_params,
.tx_tone = app_tx_tone,
.tx_mute = app_tx_mute,
.tx_end = app_tx_end,
.tx_freq = app_tx_freq,
.boot_callsign = app_boot_callsign,
.print_string = UI_PrintString,
#ifdef ENABLE_FMRADIO
.fm_enter = app_fm_enter,
.fm_exit = app_fm_exit,
.fm_set_freq = app_fm_set_freq,
.fm_read = app_fm_read,
.fm_lo = app_fm_lo,
.fm_hi = app_fm_hi,
.fm_mute = app_fm_mute,
.fm_valid = app_fm_valid,
.fm_channels = gFM_Channels,
.fm_state = app_fm_state,
.fm_commit = app_fm_commit,
#endif
.nav_dir = app_nav_dir,
.trivfo_enter = app_trivfo_enter,
.trivfo_leave = app_trivfo_leave,
.trivfo_get = app_trivfo_get,
.trivfo_select = app_trivfo_select,
.trivfo_step = app_trivfo_step,
.trivfo_tick = app_trivfo_tick,
.trivfo_ptt = app_trivfo_ptt,
};
app_run_slot = slot; /* for cfg_load / cfg_save */
app_cfg_len = 0;
#ifdef ENABLE_FMRADIO
@@ -750,7 +723,7 @@ uint8_t APP_LaunchOverlay(uint8_t slot)
RADIO_SetupRegisters(true);
app_entry_t entry = (app_entry_t)(((uint32_t)ws + h.entry_off) | 1u);
entry(&api);
entry(&app_api);
/* A defensive leave also covers an app returning through an error path. */
app_trivfo_leave();