extmod/network_halow: Add the network.HALOW 802.11ah bindings. - #19617
extmod/network_halow: Add the network.HALOW 802.11ah bindings.#19617kwagyeman wants to merge 14 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #19617 +/- ##
==========================================
+ Coverage 98.55% 98.58% +0.03%
==========================================
Files 182 182
Lines 23320 23322 +2
Branches 5 5
==========================================
+ Hits 22984 22993 +9
+ Misses 335 328 -7
Partials 1 1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Some drivers need to register a GPIO interrupt from C rather than through the machine.Pin.irq() Python method -- for example a network driver that wakes on a transceiver's IRQ line. Add mp_hal_pin_interrupt(), matching the stm32 and rp2 ports, plus mp_hal_pin_interrupt_enable() to mask and unmask an already-registered interrupt, which is useful for interrupt coalescing. The registered interrupt is given the lowest priority, as eth.c already does for the Ethernet IRQs: it only schedules work and must not preempt USB or DMA. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Some drivers need to register a GPIO interrupt from C rather than through the machine.Pin.irq() Python method. Factor the IRQ-object allocation out of machine_pin_irq() into a shared helper, then build mp_hal_pin_interrupt() and mp_hal_pin_interrupt_enable() on top of it. The latter masks and unmasks an already-registered interrupt, which is useful for interrupt coalescing. The registered interrupt is given the same low priority this port already uses for the cyw43 host-wake IRQ, since it only schedules work. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Add mp_hal_pin_interrupt_enable() to mask and unmask an already-registered pin interrupt, matching the mimxrt and alif ports. A driver can use it for interrupt coalescing: mask on the edge, unmask once the work is done. It wraps the port's existing extint_enable() / extint_disable(). Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Carries morselib -- the vendor's prebuilt WLAN library -- and the transceiver firmware that the 802.11ah driver is built on. Pinned at release 2.12.3. morselib is distributed as a prebuilt archive under the Morse Micro Binary License; the rest of the SDK is Apache-2.0. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
|
Code size report: |
e651f0f to
fc8e8eb
Compare
The portable core that the network.HALOW binding is built on, sitting between morselib and the MicroPython runtime: - a cooperative scheduler that runs morselib's tasks on their own stacks, pumped from the network poll; - an OSAL providing the RTOS primitives morselib expects -- tasks, mutexes, semaphores, queues and timers -- on top of that scheduler; - a HAL driving the transceiver over SPI, with an optional pin interrupt for low-latency receive; - packet memory and the lwIP interface, allocated from the MicroPython heap so the driver keeps no static pool of its own; - build rules that link the prebuilt morselib archive and the firmware blobs. Scheduler and allocator come with qemu and host unit tests. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
The MicroPython network interface on top of the drivers/halow core: a station-mode network.HALOW class with connect/disconnect, scan, config and status accessors, and an ioctl passthrough for certification tooling, plus the SEC_/TWT_/DUTY_CYCLE_/PM_/STAT_ constants. The constants are fixed to literals and static-asserted against the morselib enums, so a future SDK renumbering fails the build here rather than silently changing what a user's stored value means. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Documents the network.HALOW 802.11ah station interface: its methods, the config and status parameters, the security/power/duty-cycle/TWT constants and the link states, with notes on the ways 802.11ah differs from 2.4GHz Wi-Fi -- no WPA2-PSK, a mandatory country/channel plan, and a transmit-only power-save mode. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Two hardware suites for the network.HALOW interface. network_halow.py needs only the transceiver: it checks the constants, active() cycling, config validation and out-of-range rejection, scan, and that use-after-deinit and config-after-deactivate are refused rather than fatal. network_halow_sta.py needs a HaLow access point and credentials in a halow_config module, and covers association, a socket round trip, and the association-only settings. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Wire the drivers/halow driver into the alif port: include its build rules, tear it down on soft reset, and service it. The transceiver is polled from a dedicated 1ms soft timer -- more often than lwIP's 64ms tick, because morselib always has timers due and this poll is what notices a received frame -- and halow_schedule_poll() raises a PendSV dispatch so a queued transmit does not wait for the next tick. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Wire the drivers/halow driver into the mimxrt port: include its build rules, tear it down on soft reset, and service the transceiver from the network poll each systick, with halow_schedule_poll() raising a PendSV dispatch so a queued transmit does not wait for the next tick. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Wire the drivers/halow driver into the stm32 port: include its build rules, tear it down on soft reset, and service the transceiver from the network poll each systick, with halow_schedule_poll() raising a PendSV dispatch so a queued transmit does not wait for the next tick. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
At the port's 16K MEM_SIZE, sustained TCP exhausts the lwIP heap: it returns ENOMEM and throughput collapses, recovers, and collapses again in a repeating pattern. Raise it to 64K, matching the stm32 port, which holds steady. Measured on an AE3 driving a HaLow uplink: tens of ENOMEM failures per 20-minute soak at 16K, none at 64K. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Enable the Morse Micro MM8108 802.11ah shield on the N6: SPI2 on P0/P1/P2, the shield's control lines on the expansion header, and the pin interrupt for low-latency receive. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
Enable the Morse Micro MM8108 802.11ah shield on the AE3's HP core: SPI0 on P0/P1/P2, with the shield's control lines sharing the JTAG pins on the header. The transceiver is polled -- the IRQ line is mapped but the pin interrupt is left off, as it gives no throughput gain on this port. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
fc8e8eb to
23a14ee
Compare
|
@dpgeorge - I added this to OpenMV's feature list tracker. I understand it will take a while for this to be reviewed and that the review will be lengthy. However, it's now working. Note that the entire PR is AI-generated and verified on real hardware. I drove the AI to max performance and fixed all encountered bugs. Any issues we encountered during bring-up were not overlooked; they were resolved. Original performance when the driver was complete was like < 100KB/s. Scan and association were also problematic along with crashing all over. All that has been fixed and driven to be good. Whatever changes you want to make that are possible given the limitations of the Morse microdriver can be done quickly and reverified thanks to the HIL I set up to test this code. I have a test system for the RT1062, N6, and AE3. You need to buy this to actually test against the shields I sent you. Let me know when I should send you one: https://www.mouser.com/en/ProductDetail/Morse-Micro/MM-HL2-EXT-A-AU?qs=sGAEpiMZZMv0DJfhVcWlK%2FsNvTRZof5PRDeHTp4nalmrn%252B38j3g9qA%3D%3D |
Summary
This PR adds
network.HALOW, a MicroPython network interface for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow) sub-GHz Wi-Fi transceivers, and wires it into the stm32, alif and mimxrt ports.HaLow trades raw throughput for range and power, so the API follows the existing
network.WLAN/cyw43 station model —active(),connect(),isconnected(),ifconfig(),config(),status()— plus the HaLow-specific pieces: regulatorynetwork.country(), S1G channel/bandwidth reporting, OPEN/OWE/SAE (WPA3) security, and TWT-based power save.What's included:
drivers/halow/— the driver core: the SPI/SDIO transport to the transceiver, an lwIP netif, a packet-memory pool, and a small OSAL/scheduler shim so the vendor library runs cooperatively off the MicroPython scheduler + a PendSV dispatch (no vendor RTOS), mirroring how the cyw43 driver is integrated.extmod/network_halow.c— thenetwork.HALOWPython binding.lib/mm-iot-sdk— the Morse Micro MM-IoT-SDK as a submodule, providing the prebuiltmorseliband the transceiver firmware/board-config blobs.mp_hal_pin_interruptC-level IRQ-registration helper), docs, and hardware tests undertests/extmod_hardware/.OPENMV_N6andOPENMV_AE3.The driver is only compiled when a board sets
MICROPY_PY_NETWORK_HALOW=1; it has zero impact on other boards.Testing
Tested on hardware against a HaLow AP — association plus 20-minute TCP/UDP throughput soaks (hundreds of connect/transfer cycles, no leaks or asserts). All three integrated ports (stm32/alif/mimxrt) compile.
Throughput (bench soak means, station→AP, channel 28, 2 MHz bandwidth):
UDP-up is the cleanest capability figure (no retransmit/pacing); ~8 Mbit/s on the N6 is close to the practical ceiling for 2 MHz bandwidth. TCP is lower across the board due to link-level loss/retransmit behaviour.
OPENMV_N6 and OPENMV_AE3 are enabled in this PR. The mimxrt port integration is included and compiles; it's exercised on hardware by an out-of-tree board (the OpenMV RT1060, an i.MX RT1062, numbers above), but no in-tree board enables HaLow on mimxrt yet.
Trade-offs and Alternatives
morselibis a prebuilt binary (Morse Micro Binary Distribution Licence), added via thelib/mm-iot-sdksubmodule — the same model as other vendor Wi-Fi stacks (cyw43, NINA-W10). Building it from source (HALOW_MORSELIB_SOURCE=1) is supported for debugging, but those sources are GPL-3.0 and incompatible with the rest of the firmware, so the prebuilt library is the default.morselibis compiled against newlib, so on-nostdlibports the driver links the target's libc/libm and ships weak newlib syscall stubs to satisfy it (a failing_sbrk, so the C library never touches MicroPython's heap). This is contained entirely within the driver and costs nothing when HaLow is disabled.Generative AI
I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the code and the description above.