Edge Mesh is a throwaway proof-of-concept / learning experiment built on top of the Greengrass reference implementation. It is not a supported or maintained deliverable and may be removed. The reference implementation itself is long-lived; Edge Mesh is not.
Hardware & RF
Every mesh radio is an ath9k_htc USB dongle, because a hard driver interop wall means mixed radios (Intel or Broadcom) silently won't carry the mesh. On the Pis the dongle is plug-and-play; on the CompuLab core the ath9k_htc and batman-adv kernel modules must be cross-built against the exact running kernel and side-loaded. Every node must share identical RF constants (SSID, channel 1, fixed BSSID) or it forms its own isolated cell. Before this: skim the Overview.
This page is for electrical and firmware engineers. It covers the physical nodes, the radio decision that makes the mesh work for us, the RF constants every node must share, and the kernel-module constraints that make the CompuLab core the hard part of the build.
The lessons here were won the hard way; the authoritative deep-dive with the exact commands lives in tools/mesh/COMPULAB-IMX8.md.
The hardware
| Node | Hardware | OS | Mesh radio |
|---|---|---|---|
| Core | CompuLab IOT-GATE-iMX8 (i.MX 8M Mini) | Debian Bookworm, aarch64 | ath9k_htc USB dongle (onboard Intel wlan0 stays on corp WiFi) |
| Mesh-node | Raspberry Pi 4 | Raspberry Pi OS (Trixie) | ath9k_htc USB dongle (onboard Broadcom wlan0 stays free for management) |
The mesh radio on every node is an ath9k_htc USB WiFi dongle, an Atheros AR9271, e.g. the Alfa AWUS036NHA or a TP-Link TL-WN722N v1 only (v2/v3 are Realtek and will not work). It typically enumerates as wlan1. The onboard radio is deliberately left off the mesh and stays available for management WiFi.
The ath9k_htc dongle decision
The decision to standardize on ath9k_htc dongles was not a preference. It was forced by a hard interop wall (below) and two radio traps.
The Intel radio trap (core)
The IOT-GATE-iMX8's onboard wlan0 is an Intel WiFi card (iwlwifi). Intel's iwlwifi advertises IBSS in iw phy but its IBSS is non-functional for broadcast/multicast:
- Nodes join the cell and see each other at layer 2 (beacons cross;
station dumpshows the peer). - But batman OGMs (broadcast data frames) never cross in either direction, so
batctl nstays empty forever.
No software toggle fixes this, and the card has no 802.11s "mesh point" mode either, so there is no fallback. iw phy advertising * IBSS is necessary but not sufficient: only running batman and checking batctl n proves a radio works.
The interop wall: brcmfmac ↔ ath9k_htc
Even with an Atheros dongle on the core and the Pi's onboard Broadcom (brcmfmac) radio on the mesh, the mesh silently fails:
An
ath9k_htcdongle and a Pi'sbrcmfmacradio do not carry IBSS broadcast/multicast data between each other. Beacons cross (L2 association looks healthy), but batman OGM / broadcast data frames never do, in either direction. It is a driver interop wall, not a tunable knob.
Two ath9k_htc radios mesh instantly. The fix was therefore homogeneous hardware: make every mesh radio an ath9k_htc dongle. On the Pis the dongle is plug-and-play (Raspberry Pi OS ships ath9k_htc + htc_9271.fw); on the CompuLab core the driver must be cross-built (below).
The interop wall was not fixed by forcing DSSS basic rates (brcmfmac is FullMAC and ignores iw … basic-rates), by TX-power or regulatory tweaks (country 00 already allows 20 dBm IBSS on ch 1), or by swapping dongles (a second AR9271 failed identically). The routing algorithm is BATMAN_IV on both.
The verified cell configuration is OFDM basic-rates 6,12,24 + HT20, wired through mesh-defaults.conf (MESH_BASIC_RATES="6,12,24") and the HT20 token in the IBSS service template.
The RF constants (every node shares these)
Every node must use identical values or it forms its own isolated cell and sees no one. These constants live in tools/mesh/mesh-defaults.conf.
| Item | Value |
|---|---|
| Mesh cell (SSID) | edge-mesh |
| Frequency / channel | 2412 MHz (channel 1) |
| BSSID (fixed) | 02:12:ED:6E:00:01 |
| Mode | IBSS ad-hoc (802.11s "mesh point" as fallback only) |
| Cell rates | OFDM 6,12,24 + HT20 |
| Subnet | 10.88.0.0/24 |
| Core (reserved) | 10.88.0.1 |
mesh-node-N | 10.88.0.(N+2) (node-0 → .2, … node-4 → .6) |
The mesh IP auto-derives from the hostname, so getting the hostname exact at imaging time (mesh-node-N) is what pins each node's address.
Kernel-module constraints (the CompuLab core)
On the Pi, both ath9k_htc and batman-adv ship ready to load. On the CompuLab core, neither does, and they cannot be installed the easy way:
- Debian dropped
batman-adv-dkms(no DKMS shortcut). - CompuLab ships the kernel as flat files under
/bootwith no matchinglinux-headersand no apt repo. - You cannot swap in a stock Debian arm64 kernel: the i.MX 8M Mini WiFi/DT support is vendor-specific.
- The AR9271 driver was compiled out (
# CONFIG_ATH9K_HTC is not set), so plugging in the dongle enumerates on USB but nowlan1appears, nothing bound.
So both modules must be cross-built against the exact running kernel and side-loaded:
Key constraints the builder handles:
CONFIG_MODVERSIONS=y: symbol CRCs are enforced, so a random out-of-tree build will not load. You must build the full kernel from the exact source + config so the CRCs line up. (CONFIG_MODULE_SIGis not set, so unsigned modules load, no signing key needed.)- Version-string exactness: the module's
vermagicmust matchuname -rexactly, so the builder pinsLOCALVERSIONand disables git auto-versioning to avoid the "exceeds 64 characters" doubling trap. - Kernel-agnostic interop: batman-adv interoperates as long as the compatibility version (15) and routing algorithm (
BATMAN_IV) match. The Pis run batman-adv2024.2, the iMX8 build is2023.3, but both are compat 15, so they mesh fine. - The
ath9k_htcbuild also needs the firmware on the device (firmware-ath9k-htc, provideshtc_9271.fw): the radio will not come up without it.
Where the code lives
tools/mesh/COMPULAB-IMX8.md: the authoritative core how-to, covering the radio trap, the cross-build, and thebrcmfmac↔ath9k_htcwall.tools/mesh/build-imx8-module.sh/build-batman-imx8.sh: the cross-build helpers.tools/mesh/mesh-defaults.conf: the shared RF constants (SSID, channel, BSSID, basic-rates).tools/mesh/mesh-wlan-ibss.service.tmpl/mesh-wlan-mp.service.tmpl: the L1 radio units (IBSS and 802.11s fallback).tools/mesh/runbooks/kernel-module-crossbuild.md: step-by-step cross-build + side-load + verify.tools/mesh/README.md: Pi dongle requirements and the plug-and-play path on Raspberry Pi OS.