Cellular modem control for CeraLive streaming devices — the standalone home for everything modem, iterated on a bench device before any product integration.
Through v0.2.0 this repository was Phase A: it built, tested, and released on its
own, with zero changes to CeraUI, the device image, or apt-worker. Phase B
adoption — integrating this repository's artifacts into CeraUI, the device image, and the
apt distribution — is authorized starting at the v1.0.0 release tag (see
POLICY.md §4); each downstream integration is still its own explicit,
reviewed change in the receiving repository. Bench devices install the packaged .debs
straight from CI artifacts; nothing is published to apt.ceralive.tv yet.
| Directory | Artifact | What it is |
|---|---|---|
control/ |
@ceralive/modem-control (npm package) |
The TypeScript control library: the frozen v1.1 domain contracts, provider registry and evidence-scored matcher, concrete typed-D-Bus ModemManagerProvider (runtime-discovered generic controls; no CLI subprocess), NetworkManager adapter, desired-state reconciler, injected mutation-admission and exclusive-ownership ports, USB composition-mode model + the evidence-bundle ingestion seam, data-usage sampler plus its setUsagePolicy write surface (control/src/backend/usage/policy-write.ts — a local 0600 policy file, because ModemManager exposes no data-usage API at all), and the read-only SMS port (control/src/ports/sms.ts + control/src/sms/ — LIST/READ plus Added/Deleted observation, never a send or a delete, locked by sms/readonly-gate.test.ts). The USB-hub actuator is port-only here; the bench CLI owns its HIL adapter. Published to the public npm registry under the @ceralive scope as built ESM + .d.ts across seven entry points — see control/README.md. |
cli/ |
modem-control (bench CLI) |
The iteration surface: probe, watch, apply, set-usb-mode, usage, certify, hil-cycle. Compiled for arm64 + amd64 and run against real modems on a bench device to mature the package, capture per-SKU certification bundles, and prove hub VBUS port-cycling (RB-10). |
packaging/ |
ModemManager stack .debs |
Bookworm rebuilds of ModemManager + libmbim + libqmi + libqrtr-glib — packaging only, not a fork. libmbim, libqmi, and libqrtr-glib remain source-unmodified; ModemManager carries one owner-approved, three-patch BELABOX-derived FM350-GL series, hardware-validated on the carrier-mounted USB composition after restoring BELABOX's ATZ0 first-enable override (see POLICY.md and the ADR). Provenance-verified upstream pins; installed on the bench from CI artifacts. |
The control package's existing ./hardware entry point also exposes transport-free
SIM-presence and Huawei/ZTE/UFI response normalization. Device I/O, sessions, retries,
interface binding, caches, and writes remain outside those pure parsers. Its existing
root, ./domain, and ./capabilities surfaces also expose deterministic compatibility
helpers for portable modem identity, display naming, ModemManager enums, USB-network
classification, capability selection, and shadow-result comparison; these helpers perform
no discovery or transport and leave CeraUI integration to a separate cutover.
Sierra groundwork uses exact, evidence-tiered USB model rows for EM74xx, EM75xx, and
EM919x-class application PIDs across Sierra, HP, and Dell branding. These rows provide a
family label only; interface/driver evidence still decides whether a device is MM-managed,
and unknown Sierra PIDs remain unknown. The FCC classifier table separately mirrors the
complete ModemManager 1.24.2 available-tier mapping and does not install or activate links.
RB-18 in docs/BENCH.md records the real identity/composition capture gate;
the 2026-08-25 attempt is a named device-not-present skip with no fabricated bundle.
The same table now also carries exact Telit (1bc7) and u-blox (1546) module rows plus
one NETGEAR (0846) row for the LB1120, which is labelled a router-webui family — a
positive claim whose absence elsewhere means nothing, and which still decides no device
class. NETGEAR's vendor id is deliberately NOT treated as cellular evidence: its USB ID
Repository block is mostly Wi-Fi and Ethernet adapters, so a vendor-keyed rule there would
report a Wi-Fi dongle as an uplink. No Telit, u-blox, or NETGEAR provider exists.
docs/VENDOR-QUIRKS.md is the sourced per-vendor edge-case
reading list behind those rows — every claim carries a pinned citation, no claim sits above
implemented on the five-state support ladder, and nothing in it is on a write path.
docs/COMPAT-MATRIX.md is the one tracked support matrix built on
those rows: 22 hardware rows against 18 operations, from first enumeration through a
sustained bonded uplink, with a hardware-free versus hardware-required split that says which
claims a green CI run establishes and which ones only a bench device can. Every cell is a
member of the same five-state ladder and there is no second status vocabulary, so no
combination is certified and none may be described as supported. Hardware evidence lives
in docs/BENCH.md; the matrix links to it and restates none of it.
The ModemManager operation surface also exposes runtime USB-composition capability. Known
vendors are queried with exact reviewed READ/TEST forms, targets come from the device's own
enumeration only when it includes a return path, and writes retain the shared admission,
journal, rollback, readback, identity, and streaming-interlock fences. Reviewed catalog
descriptors remain the strongest success proof; otherwise a weaker post-switch device READ
must report the target. Both capability-query replies must first report AT success; a failed
current or enumeration reply exposes no targets even if its raw text contains parseable mode
data before ERROR. Band certification remains catalog-gated and unchanged.
ONE unified SemVer tag vX.Y.Z requires the root, control, and CLI package.json
versions to all be X.Y.Z; it publishes @ceralive/modem-control@X.Y.Z to npm and the
.deb artifact set in the same release. This repo deliberately does not use the CeraLive
CalVer scheme. New upstream-source rebuilds use per-source <upstream>-<rev>~ceralive.N
counters; unchanged sources retain their previous version and exact bytes. Legacy published
releases keep their tag-shaped suffixes. Full contract:
docs/VERSIONING.md.
modem-stack/
├── control/ @ceralive/modem-control — TS control library (Bun workspace member)
├── cli/ modem-control bench CLI (Bun workspace member)
├── packaging/ ModemManager-stack .deb rebuilds + provenance/verification CI
├── docs/ BENCH.md runbooks, CATALOG-INGESTION.md, COMPOSITION-EVIDENCE.md,
│ VERSIONING.md, FM350-DECISION.md, ESIM-DECISION.md
│ └── adr/ ADR-FM350-RNDIS-BEARER.md, ADR-STAY-TYPESCRIPT.md
├── AGENTS.md AI routing + repo contract (self-contained; see Rule D)
└── POLICY.md no-fork gate + upstream-contribution-first policy
control/ and cli/ form a single Bun workspace (Bun 1.4.0, strict TypeScript 7.0.2,
Biome via @ceralive/biome-config). packaging/ is built in a bookworm container.
The two AST-backed source-shape guard tests use the test-only TypeScript 6 compiler-API
compatibility package; workspace typechecking and package emit remain TypeScript 7.
That language choice is recorded, not incidental: a Rust migration was assessed and rejected
by the project owner on 2026-08-24, and the same record carries the MIT-licensed
irlserver/modem-metrics idea attribution (concepts adopted, no source code copied). See
docs/adr/ADR-STAY-TYPESCRIPT.md.
bun install # install the workspace (control + cli)
bun test # run the workspace test suite (includes the tarball-shape gate)
bun run lint # Biome check
bun run typecheck # tsc --noEmit (strict, exactOptionalPropertyTypes)
bun run build # build @ceralive/modem-control into control/dist
cd control
bun run verify:tarball # pack + assert the published artifact's shape
bun run verify:consumers # standalone Node 26 + Bun consumers of the packed tarballEvery command runs from the repository root and needs nothing outside this checkout —
the repo is self-contained (see AGENTS.md → Rule D).
AGPL-3.0
control/src/providers/huawei-hilink/ implements two exact firmware profiles: E3372H 22.200.05.00.1080 with password type 3 and E3372H 22.333.01.00.00 with password type 4. Firmware and SesTokInfo evidence select one profile; state-login must confirm its password type before one bounded login attempt, and a mismatch never falls through to another algorithm. Requests are interface-bound and redirect-disabled. Mode and data writes are independently capability-gated, acquire router-session, serialize by physical modem, and require a newly authenticated readback session before applied. Wi-Fi writes are absent. Credentials, derived hashes, cookies, and tokens remain memory-only and never enter errors or contract fixtures. See docs/HUAWEI-HILINK-PROVIDER.md.
control/src/providers/zte-goform/ keeps MF79U base64, MF79U LD-salted-under-LOGIN,
and MF266 LOGIN_MULTI_USER authentication in separate evidence-selected profiles with
one bounded attempt and an in-memory-only stok session. A batched pre-auth probe refuses
known lockout before the credential POST. Unknown ZTE firmware retains read-only telemetry;
no ZTE profile exposes a Wi-Fi write. The executable MF79U one-attempt diagnosis is documented in
docs/MF79U-DIAGNOSIS.md.
control/src/providers/ufi-himi/ is the Qualcomm UFI/HIMI provider: read-only by
construction. The HIMI command vocabulary is a frozen union of seven get* reads plus
login, so a write command cannot be expressed; operations() exposes zero write
descriptors; and the prohibited operations (NV/EFS/identity/calibration writes, firmware
flashing, EDL automation, blind driver/interface retries, DIAG writes, shell transport
fallback) are inert table entries with no implementation anywhere, each answering a typed
refusal before any transport call. 05c6:9024 proves an RNDIS+ADB composition and
05c6:9091 proves nothing at all — only a DIAG interface descriptor does, and even then
production access stays prohibited. The supervised, read-only, bench-only DIAG info probe
is documented in docs/UFI-DIAG-PROBE.md.
That document also carries the read-only descriptor capture:
control/scripts/ufi-himi-capture.sh writes a redacted evidence bundle (full lsusb -v
descriptors, usb-devices, udev properties, per-interface driver bindings, /sys
composition, and — with an ephemeral bench password — the HIMI getproduceinfo /
getsysinfo identity), and control/scripts/ufi-himi-evidence.ts carries the bundle
schema, the per-interface role classifier, and an independent redaction sweep. With no
matching device attached the script answers device-not-present and writes nothing rather
than leaving a partial bundle. The 2026-08-23 hardware drill found the attached 05c6:9091
in a four-interface QMI + ADB-class composition: interface 2 was claimed by qmi_wwan, no
ff/ff/30 DIAG descriptor existed, and the HIMI identity endpoint was unreachable through
the target's wwan1. The redacted bundle remains repo-local and gitignored; the measured
classification is recorded in docs/UFI-DIAG-PROBE.md.
control/src/radio/ carries ModemManager's mode and band answers to a consumer without
editing them. A combination whose preferred mask is 0 reads preferred: 'none' — the
bench Fibocom FM350-GL's actual answer — and survives verbatim into the mode-write
descriptor's allowed values; a mode bit this build cannot name round-trips as
mode-bit-<n> and stays offered rather than being coerced to unsupported; a catalog
member that is not a (uu) pair is retained rather than dropped. Mode and band writes are
readback-gated, and a band write additionally carries mutationImpact: 'disruptive' plus
the per-SKU certification gate from control/src/band/ — whose catalog ships empty, so
band writes are refused on every fleet device today.
On the observation layer, SIM absence is EXPLICIT evidence: absent comes only from
ModemManager's own StateFailedReason: sim-missing, never from a blank Sim object path
(which MM also reports while a modem initializes and while a slot switch is in flight).
Modem.CurrentModes and Modem.SignalQuality are retained as their D-Bus structs, so the
preferred mode and the measurement-recency flag survive normalization.
An observation now also reports who the modem is registered with and to which cell.
operatorName / operatorCode come from Modem3gpp — the registered operator — and never
from Sim.OperatorName, which is the SIM's home operator and differs throughout roaming;
the code stays text because a two- versus three-digit MNC is a different network. An
additive cell block reports cellId and tac, decoded together out of the existing
3gpp-lac-ci source's single five-token value, hex preserved as written. That source is
coarse cell context, not a GNSS fix: it stays outside GNSS_SOURCES, signal_location
stays false, and nothing on the path enables a location source. No EARFCN is claimed
anywhere — ModemManager publishes none generically, only a per-cell earfcn (LTE) and
nrarfcn (5GNR), two keys for two quantities. CellReading gained tac and now reads
ModemManager's real ci key ahead of the older cell-id spelling.
The data-usage sampler reports throughput as rateBytesPerSecond, and omits it rather
than reporting 0 whenever there was no interval to measure. A counter that goes BACKWARDS
— an interface re-created by a replug or a driver reload — yields no rate at all instead of
a clamped zero or a whole-total spike, and the baseline is rebased in the same pass so the
next interval is measured correctly. Rates are never persisted: a same-boot reload resumes
the cumulative baseline but restarts the rate unmeasured. Idea provenance for the
counter-reset rule: irlserver/modem-metrics (MIT), concepts adopted, no code copied — see
docs/adr/ADR-STAY-TYPESCRIPT.md.
control/src/providers/conformance-matrix.test.ts registers all four providers at once and
runs 20 cases — nine fleet profiles (MM-managed Quectel / SIMCom / FM350-on-USB-carrier, both
HiLink firmwares, MF79U, MF266, both UFI USB ids) plus ambiguous-collision, cross-profile
refusal, malformed-response, auth-expired, lockout, unknown-firmware, wrong-interface
and wrong-transport cases — asserting the exact provider, profile, writability and evidence
score each device is entitled to. A tie between two write-capable providers resolves read-only
with both claimants in the evidence ledger and neither credential spent. Companion suites
assert the exact sanitized per-firmware HTTP transcript and a software upper-bound fixture at
16 concurrently attached modems (a fixture result — the hardware-verified fleet size remains
8). See docs/PROVIDER-MATCHING.md.