Expand description
The device node: a full umsh-mac/umsh-node stack running on the
device itself, alongside the ULCP session.
The device identity “exists even when no phone is attached” (ULCP spec
§Identities); this module is what makes that true. It is an ordinary
MAC + Host pump with the device’s constraints baked into
DeviceNodePlatform:
- Radio is a
LoraphyRadioover the node’s virtual mux bundle (NODE_CH, mux client B) behind the shared duty-ledger gate: the session and the node share one physical radio throughradio_muxand draw from one combinedPROP_PHY_DUTY_LIMITbudget. A refused transmit is shed via the MAC’s CAD-backoff path rather than killing the pump. - Rng is a ChaCha20 CSPRNG seeded from the board’s hardware TRNG
at boot (
NodeRng): project policy forbids non-crypto RNGs, and under BLE builds the RNG peripheral is not ours to read at runtime. - The counter store is the board’s — the
CSparameter — so TX reservation boundaries for the device identity and per-peer RX replay boundaries survive power cycles, flushed from inside the MAC pump one whole-map record per persist block.
The node always exists: a device identity is generated and
persisted at first boot, so bring-up is unconditional and the only
question is whether the node is transmitting. That is configuration
— the PHY enable state and the forwarding switch — plus the
NODE_ACTIVE gate, which closes while a factory reset is in flight
(the identity has been erased from storage but the running MAC still
holds it until the reboot that completes the wipe).
Beacon requests arrive through BEACON_TRIGGER rather than from any
specific button handler: the trigger is an input, so a button press,
bring-up, and the advertisement-policy timers in advert_loop all
reach the radio by one path.
§Board seam
Embassy task functions cannot be generic, so the spawnable tasks stay
in each firmware as thin shims around the *_loop functions here, and
the board owns the two statics whose types depend on CS: the MAC
cell and its counter store. Everything else — every static whose type
is fixed, and every line of logic — is here once.
Structs§
- Advert
Policy - What the device announces without being asked, mirrored from the device domain’s advertisement-policy properties.
- Device
Node Parts - Everything bring-up produced, for the board to spawn its task shims around. Embassy tasks cannot be generic, so the spawning itself stays board-side.
- Device
Node Platform umsh_mac::Platformbundle for the device node, generic only over the board’s counter store — the one piece of the platform that is genuinely per-board, because it is backed by that board’s flash.- Node
Hooks - Board couplings the node cannot express itself.
- NodeRng
- ChaCha20 CSPRNG adapter implementing the
rand 0.10traits the MAC requires (Platform::Rng: rand::CryptoRng). Seeded once at boot from the board’s hardware TRNG, exactly like the session’sIdentityRng, while that source is still ours to read.
Enums§
- Beacon
Trigger - Why a beacon was requested. Carried through
BEACON_TRIGGERso the send path never assumes a button.
Statics§
- BEACON_
TRIGGER - Beacon requests into the node. On a boot that skipped node bring-up
the queue is never drained and requests are dropped at the
try_sendinrequest_beacon, leaving the slot inert rather than blocking the caller. - DEV_
SYNC - Latest-wins hand-off from the session driver to the sync loop. A
Signalrather than a queue: intermediate table states are irrelevant, only convergence on the newest snapshot matters. On a boot that skipped node bring-up (a crash-report boot) a pending snapshot just sits here unconsumed. - NODE_CH
- The node’s virtual radio bundle (mux client B). Static regardless of whether the node is running: the mux fans RX out to it either way, and a full queue just drops frames per the mux’s per-client policy.
Functions§
- advert_
loop - Emits the device’s unsolicited announcements: one beacon at bring-up
under
PROP_STARTUP_BEACON, then whateverPROP_ADVERT_INTERVALandPROP_BEACON_INTERVALask for. - beacon_
loop - Turns beacon triggers into node sends on the device identity: a signed advertisement either way — unsolicited for the button slot, echoing a nonce for an Advertisement Request.
- bring_
up - Construct the MAC around the device identity and wire up the node. Call at most once. The identity is never absent — boot generates and persists one when the journal is empty — so there is no “unprovisioned” path here.
- dev_
sync_ loop - Reconciles the node’s MAC against each
DevDomainSnapshot: joins newly provisioned channels, removes de-provisioned ones (dropping their replay state), and registers peers. Peer removal is not propagated — MAC registry entries carry no key material, so a stale entry is inert, and the registry is rebuilt from the live table at the next boot. - identity_
blob_ loop - Answers [
IDENT_REQUEST] with the node’s current signed identity. - identity_
profile_ loop - Keeps the Identity Request responder’s profile name synced to the live device name. The responder builds replies synchronously and cannot await, so the current name is pushed in here on each change rather than read at reply time.
- location_
profile_ loop - Keeps the advertised identity’s position synced to what the receiver
has settled on, under
PROP_GNSS_IDENT_UPDATE. - mac_
counters - The most recently published MAC tallies.
- pump_
loop - Drives the device node’s MAC pump. Never returns while healthy; an exit means the MAC hit an unrecoverable radio error, and rebooting through the panic handler beats silently losing the device identity.
- request_
beacon - Fire-and-forget beacon request. A full queue means a beacon (or advertisement) is already pending, so dropping the extra request loses nothing — bursts of Advertisement Requests coalesce here.
- set_
device_ name - Publish the live device name to the node. Call at boot and whenever the session’s device name changes.
- set_
tx_ power_ dbm - Publish the transmit power the board just applied to the radio.
- sign_
identity_ blob - Build and sign this node’s identity blob into
out, returning its length. - tx_
power_ dbm - The applied
PROP_PHY_TX_POWER, orNonebefore the firstEffect::ApplyRadio.
Type Aliases§
- Device
Node - Device
Node Handle - Device
Node Host - Device
Node Mac - Device-node MAC sized to the session’s device-domain tables, which are
the only provisioning source it has: 1 identity (the device identity;
no PFS ephemerals on the device node),
MAX_DEV_PEERSpeers,MAX_CHANNEL_KEYSchannels (a smaller MAC table would refuse channels the property surface accepted), 4 pending ACKs, 4 TX slots (beacons and future acks — no application traffic), 255-byte frames, 32-entry dup cache. The per-channel replay maps are the RAM hot spot (~330 bytes per tracked sender): 4 full-key + 2 hint-only senders per channel keeps the whole table ~2 KiB/channel; extra concurrent senders on one channel fail closed (dropped, never accepted unchecked). - Device
Node MacCell - The
StaticCella board declares for its MAC. Board-side because its type depends onCS, and astaticcannot be generic. - Device
Node Radio - The node’s radio path: its virtual mux bundle behind the shared duty-ledger admission gate.
- Node
Mutex