Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Run tests

on: [push, pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
host:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install packages
run: source tools/ci.sh && ci_tests_setup
- name: Run tests
run: source tools/ci.sh && ci_tests_run

qemu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install packages
run: source tools/ci.sh && ci_tests_qemu_setup
- name: Run tests
run: source tools/ci.sh && ci_tests_qemu_run
30 changes: 30 additions & 0 deletions .github/workflows/tests_clang.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Run tests with clang

on: [push, pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
host:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install packages
run: source tools/ci.sh && ci_tests_clang_setup
- name: Run tests
run: source tools/ci.sh && ci_tests_clang_run

qemu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install packages
run: source tools/ci.sh && ci_tests_qemu_clang_setup
- name: Run tests
run: source tools/ci.sh && ci_tests_qemu_clang_run
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/mm-iot-sdk"]
path = lib/mm-iot-sdk
url = https://github.com/MorseMicro/mm-iot-sdk.git
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
Morse Micro 802.11ah HaLow driver
=================================

This is a driver for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow) transceivers.
A portable driver for the Morse Micro MM6108/MM8108 802.11ah (Wi-Fi HaLow)
transceivers: host-agnostic C that an embedding environment integrates by
providing a small configuration header. It presents a compact station model --
a state object holding the lwIP interfaces, a link status that folds the WLAN
and TCP/IP state together, and a poll function the host drives.

The vendor stack (`morselib`) and the transceiver firmware/board-configuration
blobs come from the Morse Micro
[MM-IoT-SDK](https://github.com/MorseMicro/mm-iot-sdk), included here as the
`lib/mm-iot-sdk` submodule. `morselib` is a prebuilt library under the Morse
Micro Binary Distribution Licence; the driver runs it cooperatively off the
host's scheduler through a small OSAL shim -- no vendor RTOS.

## Layout

- `src/` -- the driver:
- `mm_halow_config.h` -- the host integration contract. The embedder
provides `mm_halow_configport.h` (or the file named by
`MM_HALOW_CONFIG_FILE`) supplying atomic sections, a millisecond tick,
pin accessors, and the `mm_halow_port_*` functions (SPI transport, private
heap backing, hardware RNG, fallback MAC, optional edge IRQ).
- `mm_halow_ctrl.c` -- driver core: init/deinit, connect/scan/status, the
morselib event plumbing.
- `mm_halow_lwip.c` -- the lwIP netif.
- `mm_halow_hal.c` -- morselib's `mmhal` interface, mapped onto the
`mm_halow_port_*` hooks (SD-over-SPI framing, reset/wake sequencing,
firmware/BCF blob serving).
- `mm_halow_osal.c` / `mm_halow_sched.c` -- morselib's `mmosal` interface: a
private heap (morselib allocates from interrupt context, where a host GC
must not run) and a cooperative scheduler with a wall-clock budget.
- `mm_halow_pktmem.c` -- the packet-memory pool.
- `mmport.h` -- morselib's port header (name fixed by the SDK).
- `mm_halow.mk` -- build fragment for make-based embedders: prebuilt morselib
linkage (grouped with the target multilib's libc/libm) and the firmware/BCF
blob embedding.
- `tests/host` -- allocator tests, compiled natively from the real sources
(`make`, `make asan`).
- `tests/qemu` -- scheduler tests on a Cortex-M55 under QEMU (`make`), since
the context switch is naked asm that cannot run on the host.

## Integrating

1. Add `src/` to the include path along with
`lib/mm-iot-sdk/framework/morselib/include`, and compile `src/*.c`.
2. Provide `mm_halow_configport.h`; `src/mm_halow_config.h` documents every
hook and fails the build naming whatever is missing.
3. Link the prebuilt `morselib` and the transceiver firmware blob --
`mm_halow.mk` does both for make-based builds. morselib is built against
newlib and pulls in a few C library functions (`sscanf`, `qsort`, `setjmp`,
...) that in turn reference newlib's syscall back-end (`_sbrk`, `_write`,
...). The host must provide that back-end; MicroPython's ports already do.
morselib never calls these at run time, so the back-end only needs to
satisfy the link -- and `_sbrk` in particular should fail rather than hand
out memory, since the driver runs entirely from its own heap. (If the host
links `-nostdlib`, also group libc/libm with morselib, as the fragment
does.)
4. Drive `mm_halow_poll()` from the host's deferred-work mechanism and call
`mm_halow_schedule_poll()` when the transceiver's IRQ line asserts (or poll
by level; the driver checks the line each pass).

The MicroPython `network.HALOW` binding is the reference embedding.
1 change: 1 addition & 0 deletions lib/mm-iot-sdk
Submodule mm-iot-sdk added at 88606f
89 changes: 89 additions & 0 deletions mm_halow.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Build fragment for embedding builds (make-based): links the prebuilt
# morselib and the transceiver firmware/BCF blobs. The including build must
# provide TOP, BUILD, CC, CFLAGS, OBJCOPY and collect LIBS/OBJ/CFLAGS.

MM_HALOW_DIR ?= lib/mm-halow-driver
MM_HALOW_TOP ?= $(TOP)/$(MM_HALOW_DIR)
MM_HALOW_MMIOT_DIR = $(MM_HALOW_TOP)/lib/mm-iot-sdk/framework
MM_HALOW_MORSELIB_DIR = $(MM_HALOW_MMIOT_DIR)/morselib

# morselib is distributed as a prebuilt library under the Morse Micro Binary
# Distribution Licence. Building it from source instead is useful for
# debugging, but those sources are GPL-3.0, which is not compatible with the
# rest of this firmware, so the prebuilt library is the default.
MM_HALOW_MORSELIB_CORE ?= arm-cortex-m33f

# The MM-IoT-SDK (prebuilt morselib + the transceiver firmware blobs) is a
# submodule of this driver, i.e. a submodule of a submodule of the embedding
# project. A recursive checkout populates it, but the embedder's flat "fetch
# my submodules" step is usually not recursive (MicroPython's `make submodules`
# is not), which leaves the SDK empty -- and both its source files (compiled
# below) and its firmware blobs then fail with "No such file". Fetch it here
# at parse time, before anything reads from it, guarded so it is a no-op once
# the SDK is present.
ifeq ($(wildcard $(MM_HALOW_MORSELIB_DIR)/lib/$(MM_HALOW_MORSELIB_CORE)/libmorse.a),)
$(info Fetching the mm-iot-sdk nested submodule...)
$(shell cd $(MM_HALOW_TOP) && git submodule update --init lib/mm-iot-sdk >&2)
endif
ifeq ($(MM_HALOW_MORSELIB_SOURCE),1)
INC += $(addprefix -I$(MM_HALOW_MORSELIB_DIR)/,src src/internal src/emmet src/umac/rc/mmrc_osal mmrc/src/core)
SRC_THIRDPARTY_C += $(patsubst $(TOP)/%,%,\
$(shell find $(MM_HALOW_MORSELIB_DIR)/src $(MM_HALOW_MORSELIB_DIR)/mmrc/src -name '*.c'))
CFLAGS_THIRDPARTY += -DLOOKAROUND_FAIL_MAX=50 -Wno-c++-compat
else
# morselib is prebuilt against newlib, but the ports link with -nostdlib, so the
# C library functions it calls (sscanf, qsort, setjmp, _ctype_, ...) are not
# otherwise pulled in. Resolve libc/libm for the target multilib the same way
# the ports resolve libgcc, and group them with the archive so the linker settles
# the references between morselib and libc regardless of order. These are lazily
# expanded: CFLAGS only carries the -mcpu flags that select the multilib once the
# including port has finished adding them, after this file is included.
MM_HALOW_LIBC = $(shell $(CC) $(CFLAGS) -print-file-name=libc.a)
MM_HALOW_LIBM = $(shell $(CC) $(CFLAGS) -print-file-name=libm.a)
LIBS += -Wl,--start-group $(MM_HALOW_MORSELIB_DIR)/lib/$(MM_HALOW_MORSELIB_CORE)/libmorse.a $(MM_HALOW_LIBC) $(MM_HALOW_LIBM) -Wl,--end-group
endif

# objcopy derives a blob's symbol names from its path, mangling everything that
# is not alphanumeric into an underscore.
mm_halow_blob_sym = _binary_$(subst .,_,$(subst -,_,$(subst /,_,$(1))))_$(2)

# Output format for the blobs. Overridable, as the only thing tying the driver
# to a particular architecture is the prebuilt morselib.
MM_HALOW_BFDNAME ?= elf32-littlearm
MM_HALOW_BFDARCH ?= arm

# The transceiver firmware, and optionally a board configuration file holding
# calibration data, are linked in as binary blobs. A board picks its BCF by
# name with MM_HALOW_BCF; the SDK keeps them per chip under morsefirmware.
MM_HALOW_CHIPSET ?= mm8108
MM_HALOW_BCF ?= mf15457
MM_HALOW_FW_MBIN ?= $(MM_HALOW_MMIOT_DIR)/morsefirmware/mm8108b2-rl.mbin
ifneq ($(MM_HALOW_BCF),)
MM_HALOW_BCF_MBIN ?= $(MM_HALOW_MMIOT_DIR)/morsefirmware/$(MM_HALOW_CHIPSET)/bcfs/bcf_$(MM_HALOW_BCF).mbin
endif
MM_HALOW_FW_OBJ = $(BUILD)/$(MM_HALOW_DIR)/mm_halow_firmware.o

$(MM_HALOW_FW_OBJ): $(MM_HALOW_FW_MBIN)
$(ECHO) "GEN $@"
$(Q)$(MKDIR) -p $(dir $@)
$(Q)$(OBJCOPY) -I binary -O $(MM_HALOW_BFDNAME) -B $(MM_HALOW_BFDARCH) $< $@ \
--redefine-sym $(call mm_halow_blob_sym,$<,start)=mm_halow_firmware_start \
--redefine-sym $(call mm_halow_blob_sym,$<,end)=mm_halow_firmware_end \
--rename-section .data=.rodata.mm_halow_firmware,contents,alloc,load,readonly,data \
--set-section-alignment .data=4

ifneq ($(MM_HALOW_BCF_MBIN),)
CFLAGS += -DMM_HALOW_BCF=1
MM_HALOW_BCF_OBJ = $(BUILD)/$(MM_HALOW_DIR)/mm_halow_bcf.o

$(MM_HALOW_BCF_OBJ): $(MM_HALOW_BCF_MBIN)
$(ECHO) "GEN $@"
$(Q)$(MKDIR) -p $(dir $@)
$(Q)$(OBJCOPY) -I binary -O $(MM_HALOW_BFDNAME) -B $(MM_HALOW_BFDARCH) $< $@ \
--redefine-sym $(call mm_halow_blob_sym,$<,start)=mm_halow_bcf_start \
--redefine-sym $(call mm_halow_blob_sym,$<,end)=mm_halow_bcf_end \
--rename-section .data=.rodata.mm_halow_bcf,contents,alloc,load,readonly,data \
--set-section-alignment .data=4
endif

OBJ += $(MM_HALOW_FW_OBJ) $(MM_HALOW_BCF_OBJ)
Loading
Loading