![]() |
LambLisp 01 Red Fox Alpha
From AI to Actuator
|
Enumerations | |
| enum | LL_WifiPref { LL_WIFI_PREF_ABSENT = 0 , LL_WIFI_PREF_OFF , LL_WIFI_PREF_ON } |
Functions | |
| Sexpr_t | WiFi_mop3_begin (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_disconnect (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_reconnect (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_config (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_setDNS (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_waitForConnectResult (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_isConnected (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_setAutoReconnect (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_SSID (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_BSSID (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_RSSI (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_scanChannel (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_localIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_subnetMask (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_gatewayIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_broadcastIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_networkID (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_dnsIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_subnetCIDR (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_psk (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_macAddress (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_encryptionType (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_status (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_mode (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_getHostname (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_setHostname (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_setSleep (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_channel (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_scanNetworks (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_hostByName (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPConfig (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPdisconnect (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPgetStationNum (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPBroadcastIP (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPSSID (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPmacAddress (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPgetHostname (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| Sexpr_t | WiFi_mop3_softAPsetHostname (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
| void | ll_wifi_boot_reserve () |
| Sexpr_t | WiFi_install_mop3 (Lamb &lamb, Sexpr_t sexpr, Sexpr_t env_exec) |
Variables | |
| WiFiClass * | LL_WiFi = &WiFi |
LambLisp WiFi builtins.
| enum LL_WifiPref |
WILL THIS BOARD ACTUALLY RAISE A RADIO? Answered HERE, in the installer, because the reservation is made here and a speculative reservation is not free.
WHY THIS IS NOT "PARSING SCHEME IN C++": it is not evaluating anything. setup.scm reads Settings.scm and then Settings-local.scm (which OVERRIDES it – setup.scm:120-129) long after this point, and (setting 'wifi 0) is a plain assq over the result. All we need is the value of one key, and LittleFS is already mounted (ll_heap_note("after LittleFS.begin") precedes the installer loop), so we read the file and look for it.
IT FAILS TOWARD TODAY'S BEHAVIOUR. Cannot open the file, cannot find the key, cannot parse the value -> return false -> NO reservation -> the radio allocates exactly as it did before this proposal existed. A wrong answer costs ordering quality; it can never cost correctness. That matters because the cost of guessing WRONG is measured and asymmetric: on Freenove-ESP32-WROVER, reserving 48 KB for a radio that never starts pushed the NCG exec pool's 32 KB claim into a 14,324-byte largest block, it failed, and the board ran NCG 0 BC 191 – it gave up native code entirely to hold memory for a radio it does not use.
KEEP IN STEP WITH scm/core/WiFi.scm:19, which is the other half of this decision: (when (positive? (setting 'wifi 0)) (WiFi.begin ...)) If that guard changes, this must change with it. Two readers of one key is a drift risk, and the mitigation is that this one fails safe while that one is authoritative.
TRI-STATE, BECAUSE "NO KEY" AND "KEY SAYS 0" ARE DIFFERENT FACTS. Collapsing them into one bool is what made the boot message assert a conclusion about the BOARD ("this board does not auto-connect at boot") when what had actually happened was that the settings could not be read. A correct configuration and an unreadable one printed the same sentence, so the operator's next move was to check the hardware rather than the file.
| Sexpr_t WiFi_mop3_begin | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Connect to an access point with SSID and optional password; returns wl_status_t.
HAND THE RESERVATION BACK IMMEDIATELY BEFORE THE RADIO CLAIMS, so the stack lands in the hole taken at install time rather than in whatever the .scm load chain has left. Same shape as EyeCam's camera hole. Nothing allocates internal DRAM between here and begin().
| Sexpr_t WiFi_mop3_disconnect | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Disconnect from WiFi; optional args wifioff and eraseap.
| Sexpr_t WiFi_mop3_reconnect | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Reconnect to the last access point; returns #t on success.
| Sexpr_t WiFi_mop3_config | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set static IP configuration; all args are IP strings or #f for INADDR_ANY.
| Sexpr_t WiFi_mop3_setDNS | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Reconfigure DNS servers without changing IP/GW/subnet.
| Sexpr_t WiFi_mop3_waitForConnectResult | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Block until connected or timeout (default 60000 ms); returns wl_status_t integer.
| Sexpr_t WiFi_mop3_isConnected | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
NOT STARTED IS NOT CONNECTED. A predicate named isConnected must answer the question, never abort the VM – returning #f here is both correct and what any caller expects.
| Sexpr_t WiFi_mop3_setAutoReconnect | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Enable or disable automatic reconnection; optional arg defaults to #t (enable).
| Sexpr_t WiFi_mop3_SSID | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(WiFi.SSID) -> the CONNECTED access point's SSID. (WiFi.SSID i) -> the SSID of scan result i, after (WiFi.scanNetworks).
THE INDEX FORM WAS MISSING AND THE ARGUMENT WAS SILENTLY IGNORED, which made WiFi.scanNetworks useless: it returns a COUNT, and nothing could read the results behind it. (WiFi.SSID 0) returned the connected SSID – an empty string when not associated – so a scan reported "2 networks" and then two blanks, which reads as a broken radio rather than a missing accessor. The question it answers: "which networks can this board actually see" is the first question about a board that will not associate, and the runtime could not answer it. Arduino has had the overload all along; this just stops throwing it away.
| Sexpr_t WiFi_mop3_BSSID | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the BSSID (AP MAC address) as a colon-separated hex string.
| Sexpr_t WiFi_mop3_RSSI | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(WiFi.RSSI) -> the connected AP's signal in dBm; (WiFi.RSSI i) -> scan result i. Same missing-overload story as WiFi.SSID above.
| Sexpr_t WiFi_mop3_scanChannel | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
(WiFi.channel i) -> the channel of scan result i. NEW. Channel is how you tell a 2.4 GHz AP (1-14) from a 5 GHz one (36+) – and an ESP32-S3 is 2.4 GHz ONLY, so an SSID on channel 36 is one this part can never join no matter how strong it is. Worth having when a board "cannot see" a network everything else can.
| Sexpr_t WiFi_mop3_localIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the local IP address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_subnetMask | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the subnet mask as a dotted-decimal string.
| Sexpr_t WiFi_mop3_gatewayIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the gateway IP address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_broadcastIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the broadcast IP address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_networkID | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the network base address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_dnsIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the DNS server IP string; optional arg n selects primary (0) or secondary (1).
| Sexpr_t WiFi_mop3_subnetCIDR | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the subnet prefix length as an integer (CIDR notation).
| Sexpr_t WiFi_mop3_psk | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the WPA/WPA2 pre-shared key as a string.
| Sexpr_t WiFi_mop3_macAddress | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the station MAC address as a colon-separated hex string.
| Sexpr_t WiFi_mop3_encryptionType | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the encryption type of the connected network as an integer.
| Sexpr_t WiFi_mop3_status | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return a list (status-int status-string) describing the current WiFi connection state.
status() reads the same NetworkInterface state isConnected() does, so it is the direct equivalent and gets the same guard. WL_NO_SHIELD is the honest answer for "no interface".
< "%s" even though every msg
< above is a literal with no % in it: this overload is PRINTF, so the safety is a property of the TABLE rather than of the call, and the next case added would not announce the difference.
| Sexpr_t WiFi_mop3_mode | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set WiFi mode: 0=NULL 1=STA 2=AP 3=APSTA; returns #t on success.
| Sexpr_t WiFi_mop3_getHostname | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the mDNS hostname as a string.
| Sexpr_t WiFi_mop3_setHostname | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set the mDNS hostname; returns #t on success.
| Sexpr_t WiFi_mop3_setSleep | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set power-save sleep mode: #t/#f or integer 0=none 1=modem 2=light.
| Sexpr_t WiFi_mop3_channel | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the current WiFi channel number.
| Sexpr_t WiFi_mop3_scanNetworks | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Scan for nearby networks and return the count found.
| Sexpr_t WiFi_mop3_hostByName | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Resolve a hostname to an IP string; returns #f on failure.
< printf overload – the
< literal format keeps data out of it.
| Sexpr_t WiFi_mop3_softAP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Start a soft access point with SSID and optional password/channel/hidden/max-conn.
| Sexpr_t WiFi_mop3_softAPConfig | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set soft-AP IP configuration; ip, gateway, subnet are dotted-decimal strings.
| Sexpr_t WiFi_mop3_softAPdisconnect | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Shut down the soft-AP; optional arg wifioff also disables the radio.
| Sexpr_t WiFi_mop3_softAPgetStationNum | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the number of stations currently connected to the soft-AP.
| Sexpr_t WiFi_mop3_softAPIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the soft-AP IP address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_softAPBroadcastIP | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the soft-AP broadcast IP address as a dotted-decimal string.
| Sexpr_t WiFi_mop3_softAPSSID | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the soft-AP SSID as a string.
| Sexpr_t WiFi_mop3_softAPmacAddress | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the soft-AP MAC address as a colon-separated hex string.
| Sexpr_t WiFi_mop3_softAPgetHostname | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Return the soft-AP mDNS hostname as a string.
| Sexpr_t WiFi_mop3_softAPsetHostname | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
Set the soft-AP mDNS hostname; returns #t on success.
| void ll_wifi_boot_reserve | ( | ) |
Reserve the radio's fast RAM at boot, BEFORE the VM claims internal DRAM.
ORDER IS THE WHOLE POINT OF THIS FUNCTION EXISTING SEPARATELY. The radio needs one CONTIGUOUS block, and the reservation has to be made while a block that size still exists. Taking it at installer time is too late: the VM's internal-DRAM residents are claimed when the interpreter is constructed, which is before any installer runs, so by then the largest free block has already been reduced and the reserve is refused – measured on a classic ESP32 as wifi reserve 49152 FAILED with 34,804 bytes largest, against 110,580 before construction.
The refusal is a DEGRADATION, not an error: the consumer then allocates unordered and the radio works. That is why the old ordering survived – nothing fails loudly, and the one line scrolls past in a boot log.
RELEASED TWO WAYS, unchanged: to WiFi.begin() if the radio starts, and by the unclaimed sweep after setup.scm if it does not. A reserve that could not be met is not held at all.
Take the radio's boot-time fast-RAM reservation. Called from Lamb::setup() BEFORE the VM claims its internal-DRAM residents, so the reserve is made while a contiguous block that size still exists. No-op where there is no radio or the part is not an ESP32.
| Sexpr_t WiFi_install_mop3 | ( | Lamb & | lamb, |
| Sexpr_t | sexpr, | ||
| Sexpr_t | env_exec ) |
CLAIM THE RADIO'S FAST RAM HERE, NOT WHERE WiFi.scm HAPPENS TO RUN. Measured on esp32-s3-eye: the when form in WiFi.scm costs 48,752 bytes and takes the largest contiguous block from 69,620 to 31,732 – mid-way through the .scm chain, after every earlier claimant has already budgeted against a number that is about to be wrong. Reserving at install time means the claim lands while the pool is whole, and the barrier after the installer loop reports a remainder a later claimant can actually trust. RELEASED THREE WAYS: to WiFi.begin() if the radio starts, by the unclaimed sweep after setup.scm if it does not, and not at all if the reserve could not be met (best-effort).
SAY WHAT WAS READ, NOT WHAT IT MEANS. "no key found" is a failure to read the settings; "(wifi . 0)" is an instruction someone wrote. Printing one sentence for both is the defect – it sends whoever is holding a correctly-configured board off to test the hardware. The radio reserve is taken at BOOT, before the VM claims internal DRAM. See ll_wifi_boot_reserve() and its call site in Lamb::setup().
| WiFiClass* LL_WiFi = &WiFi |
POINT THIS AT THE ARDUINO GLOBAL. It was declared and NEVER ASSIGNED anywhere in the repo – so it was a NULL pointer, and every one of the ~40 LL_WiFi-> call sites below dereferenced null. It did not look like that from the crash: Guru Meditation Error: Core 1 panic'ed (LoadProhibited), EXCVADDR 0x00000008 NetworkInterface::getStatusBits() NetworkInterface.cpp:231 WiFiSTAClass::isConnected() WiFiSTA.cpp:222 which reads as an Arduino 3.x defect – a "null netif in the new NetworkInterface layer" – and was first diagnosed that way. It is ours. STAClass STA is a MEMBER of WiFiSTAClass, so with this == nullptr the call reaches _interface_event_group at offset 8 of a null object: that IS the 0x00000008 in the report. getStatusBits() already null-checks its event group, so a real object cannot panic there. WHY IT SURVIVED ARDUINO 2.0.17: isConnected() there read a global and touched no member, so calling it through a null this was undefined but harmless in practice. Arduino 3.x moved status behind a member, and the latent null became a reboot. So this is a migration TRIGGER, not a migration regression – the defect predates it. Constant-initialised: &WiFi is a link-time address, so this does not depend on WiFi's constructor having run (no static-init-order hazard); the calls all happen after setup(). Fixing it HERE fixes all ~40 sites at once, which per-site readiness guards would not.