![]() |
LambLisp 01 Red Fox Alpha
From AI to Actuator
|
Macros | |
| #define | LL_SONAR_NO_DEVICE_GUARD 0 |
| #define | SONAR_REQUIRE_DEVICE() |
Functions | |
| void IRAM_ATTR | sonar_echo_isr (void *arg) |
| Sexpr_t | Sonar_mop3_begin (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_start (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_result (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_ping (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_poke (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_us_to_distance (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_set_timeout_us (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_set_min_interval_us (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_set_rest_after_echo_us (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_mop3_defaults (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | Sonar_install_mop3 (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
Variables | |
| Sonar * | sonar = 0 |
Copyright 2026 by Frobenius Norm LLC 2026-04-23 00:00:00.
< esp_timer_get_time(): the IRAM-resident clock the ISR needs
LambLisp Ultrasonic Sonar (HC-SR04) builtins.
| #define LL_SONAR_NO_DEVICE_GUARD 0 |
Return #f from a sonar procedure when the device is absent or not yet begun. #f is already these procedures' "no reading", so a caller that handles a timeout handles a missing sensor.
| #define SONAR_REQUIRE_DEVICE | ( | ) |
| void IRAM_ATTR sonar_echo_isr | ( | void * | arg | ) |
FALLING-edge ISR: ECHO pin went LOW – echo received (or timeout on sensor side).
esp_timer_get_time() AND NOT micros(), AND THE FUNCTION BEING IRAM_ATTR IS WHY THAT MATTERS RATHER THAN WHY IT DOES NOT. An ISR marked IRAM_ATTR is placed in IRAM so it can run while the flash cache is disabled – but the marking covers THIS function only, not what it calls. Arduino's micros() lives in FLASH on this core (esp32-hal-misc.c; measured at 0x40170ba4 against esp_timer_get_time at 0x4008393c), so calling it from here jumped out of IRAM the moment a flash operation had the cache off, and the core panicked:
Guru Meditation Error: Core 1 panic'ed (Cache error). Cache disabled but cached memory region accessed
The backtrace comes out CORRUPTED, so the panic names neither this file nor the sonar – the only clue is the GPIO number sitting in A2/A4. Reproduced by (sd-mount) with a floating echo pin: esp_vfs_fat_sdmmc_mount disables the cache and the floating input supplies the edge. Any flash write will do it – LittleFS, NVS, OTA – so this is not SD-specific, and a board that has never mounted a filesystem can carry the fault indefinitely without showing it.
micros() is itself just (unsigned long) esp_timer_get_time(), so this is the same number with the same 32-bit wrap, and result()'s arithmetic is unchanged.
THE GENERAL FORM, worth carrying to any other ISR here: IRAM_ATTR places THIS function in IRAM and says nothing about its callees. An ISR is only as interrupt-safe as the deepest thing it calls.
< IRAM-safe; micros() is not
| Sexpr_t Sonar_mop3_begin | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Initialize the Sonar singleton with trigger and echo pin numbers.
| Sexpr_t Sonar_mop3_start | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Start a ping. On ESP32: non-blocking. On other platforms: blocks on pulseIn.
| Sexpr_t Sonar_mop3_result | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Returns: #f – echo not yet received (still within timeout window) 0 – timed out, no echo; caller should re-arm with Sonar.start integer – elapsed microseconds; caller should convert and re-arm
| Sexpr_t Sonar_mop3_ping | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Blocking ping: fire trigger, wait for echo, return elapsed microseconds or #f on timeout.
| Sexpr_t Sonar_mop3_poke | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Blocking ping converted to distance in meters; returns #f on timeout.
| Sexpr_t Sonar_mop3_us_to_distance | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Convert elapsed microseconds to distance in meters; optional Celsius temperature arg.
| Sexpr_t Sonar_mop3_set_timeout_us | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(Sonar.timeout-us! <us>) – set the no-echo timeout at runtime; returns the effective (clamped-to-range-floor) value so the caller can confirm it.
| Sexpr_t Sonar_mop3_set_min_interval_us | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(Sonar.min-interval-us! <us>) – set the HC-SR04 inter-ping settle gap at runtime; returns the effective value. Larger = steadier readings, lower max ping rate.
| Sexpr_t Sonar_mop3_set_rest_after_echo_us | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(Sonar.rest-after-echo-us! <us>) – set the required REST measured from the ECHO (or from a declared timeout) to the next SEND; returns the effective value. 0 DISABLES it, leaving min-interval-us! the only gate. The default is NOT 0 – this gate is on; the value is SONAR_REST_AFTER_ECHO_DEFAULT_US. Never shortens min-interval-us!: both gates must pass, so this can only make the driver wait longer.
| Sexpr_t Sonar_mop3_defaults | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(Sonar.defaults!) – restore every runtime tunable to its compiled default. Returns the three effective values as (timeout-us min-interval-us rest-after-echo-us), so a caller can assert the reset rather than trusting it.
| Sexpr_t Sonar_install_mop3 | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Install all Sonar symbols in base environment.
| Sonar* sonar = 0 |
Sonar singleton.