![]() |
LambLisp 01 Red Fox Alpha
From AI to Actuator
|
Macros | |
| #define | OTA_NS "ota-p125" |
Functions | |
| Sexpr_t | ota_mop3_request_install (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_request_recover (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_request_console (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_set_network (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| int | ll_ota_boot_factory_raw (void) |
| Sexpr_t | ota_mop3_reboot_to_loader (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_boot_ok (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| int | ll_ota_request_console_raw (void) |
| int | ll_ota_record_death_raw (const char *reason) |
| Sexpr_t | ota_mop3_record_death (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_clear_death (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_mop3_death_record (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | ota_install_mop3 (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
< GENERATED from scm/features/llloader-vocab.scm
LambLisp Boot-Loader Handshake (OTA) builtins.
| Sexpr_t ota_mop3_request_install | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-request-install!) — ask the loader to INSTALL (pending_update=1: fetch + write a new ota_0). Returns #t on success, #f off-device.
| Sexpr_t ota_mop3_request_recover | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-request-recover!) — ask the loader to RECOVER (pending_update=2: re-fetch a known-good image). Returns #t on success, #f off-device.
| Sexpr_t ota_mop3_request_console | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-request-console!) — ask the loader for the CONSOLE fallback (pending_update=3: operator BLE/UART). Returns #t on success, #f off-device.
| Sexpr_t ota_mop3_set_network | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-set-network! ssid pass url) — write the network-rung config keys wifi_ssid / wifi_pass / img_url (all strings) to NVS. Returns #t on success, #f off-device.
| int ll_ota_boot_factory_raw | ( | void | ) |
(ota-reboot-to-loader) — point otadata at the factory llloader partition and esp_restart; never returns on device. Returns #f if there is no factory partition (or off-device). Defined below, beside its siblings; declared here because the mop3 above uses it.
Point the next boot at the FACTORY partition. True on success.
ASKING FOR THE CONSOLE IS NOT ENOUGH ON ITS OWN, AND THIS IS THE HALF THAT IS EASY TO OMIT. pending_update is read by the LOADER – so it is read only if the loader RUNS. On a unit whose otadata selects ota_0, the second-stage bootloader starts ota_0 directly and the factory loader is never entered; the pending request then survives in NVS until (ota-boot-ok!) erases it while marking the application healthy. A reset without this redirect therefore boots the very application that asked to be taken out of service, and the request leaves no trace of having been ignored, because nothing ignored it.
So a handover is TWO writes and a reset, in this order: the pending action, the boot partition, then restart. Verified by omitting the middle one: (ota-request-console!) succeeds, the board resets, and the transcript carries the application's own startup banner and not one loader line.
NO ALLOCATION AND NO VM CALLS, for the same reason as its two siblings: this path runs when the evaluator cannot.
| Sexpr_t ota_mop3_reboot_to_loader | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
ONE COPY OF THE REDIRECT, shared with the watchdog path – see ll_ota_boot_factory_raw(). It reports only success or failure, so the two reasons are distinguished here by asking again rather than by a second implementation.
| Sexpr_t ota_mop3_boot_ok | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-boot-ok!) — confirm THIS image is healthy: cancel the native OTA rollback and clear pending_update + install_tries (the loader's anti-loop counter). The loader's install-retry guard waits for this. Returns #t (vacuously #t off-device).
DO NOT CLEAR THE DEATH COUNT HERE, however natural it looks. This runs EARLY in a boot, to say "this image starts"; the death count exists to say "this image does not keep WORKING". Clearing it here would reset the streak before the failure that increments it, so a unit that dies every cycle would flap between the VM and the loader forever and never reach the latch threshold. Starting is not health. (ota-clear-death!) is the explicit reset, for an application that has evidence it is working.
| int ll_ota_request_console_raw | ( | void | ) |
(ota-record-death! reason) — persist reason and bump the death count; returns the NEW count, or #f if the reason is not a legal symbol (or off-device). Records only: it does not request the console and does not reboot, because what to do after the Nth death is policy and policy belongs in Scheme. Call it through (dead! reason).
Ask the loader for its CONSOLE rung without the evaluator. True on success.
The companion to ll_ota_record_death_raw: dead! in Scheme records, then requests console, then reboots, and the staleness watch must do the same three things in the same order or a wedge stops being equivalent to a declared death. Recording alone leaves the count bumped and nobody told: the count reaches the limit and the unit boots normally, because pending_update was never set.
| int ll_ota_record_death_raw | ( | const char * | reason | ) |
Record a death WITHOUT the evaluator: validate reason, bump the count, persist both. Returns the new count, or -1 if the reason is rejected or this is not an ESP32 build.
THE WATCHDOG PATH CANNOT USE THE MOP3, because the watchdog fires precisely when the evaluator cannot run – and the mop3 takes a Lamb & and logs through it. So the policy lives here, once, and both callers use it: (ota-record-death! reason) for a DECLARED death, and the staleness sampler for a WEDGE. Two copies of "how a death is recorded" would be the hand-maintained-second-copy defect, drifting in the direction that matters most – the wedge path is the one nobody exercises by hand.
NO ALLOCATION AND NO VM CALLS: NVS only. The sampler that calls this is watching the allocator, so allocating here would move the very counter it is reading.
< saturate: a wrap would read as healthy
| Sexpr_t ota_mop3_record_death | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
REFUSED, NOT SUBSTITUTED. A default reason here would be this function's opinion about a failure it knows nothing about, recorded as if the application had said it.
DELEGATES, so a declared death and a wedge cannot diverge – see ll_ota_record_death_raw().
| Sexpr_t ota_mop3_clear_death | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-clear-death!) — erase the death record and reset the death count to zero. Call it when the application has evidence it is WORKING, not merely that it has started. Returns #t.
| Sexpr_t ota_mop3_death_record | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(ota-death-record) — the persisted death record as (reason . count), or #f if this unit has not declared itself dead since the last (ota-boot-ok!). Lets a VM that came back up report why it went down.
| Sexpr_t ota_install_mop3 | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Installer: bind the OTA loader-handshake builtins (ota-request-install! / -recover! / -console!, ota-set-network!, ota-reboot-to-loader, ota-boot-ok!) into env_target.