pub struct Session<A: AesProvider, S: Sha256Provider, const TX: usize = 1> { /* private fields */ }Implementations§
Source§impl<A: AesProvider, S: Sha256Provider, const TX: usize> Session<A, S, TX>
impl<A: AesProvider, S: Sha256Provider, const TX: usize> Session<A, S, TX>
Sourcepub fn new(
config: SessionConfig,
boot_status: Status,
engine: CryptoEngine<A, S>,
) -> Self
pub fn new( config: SessionConfig, boot_status: Status, engine: CryptoEngine<A, S>, ) -> Self
boot_status is the retained hardware reset cause, reported by
the first PROP_LAST_STATUS get of the first session.
Sourcepub fn settings(&self) -> RadioSettings
pub fn settings(&self) -> RadioSettings
The active radio settings.
Sourcepub fn device_name(&self) -> &str
pub fn device_name(&self) -> &str
Current UTF-8 PROP_DEV_NAME value.
Sourcepub fn tx_data(&self) -> &[u8] ⓘ
pub fn tx_data(&self) -> &[u8] ⓘ
Payload of the transmit requested by Effect::StartTransmit.
Sourcepub fn max_tx_power_dbm(&self) -> i8
pub fn max_tx_power_dbm(&self) -> i8
The board’s maximum transmit power, as configured. The concrete
dBm value behind TxPower::Max when a transmit is staged.
Sourcepub fn tx_nocca(&self) -> bool
pub fn tx_nocca(&self) -> bool
Whether the pending transmit requested TX_FLAG_NOCCA — skip the
pre-transmit channel-activity check.
Sourcepub fn has_pending_tx(&self) -> bool
pub fn has_pending_tx(&self) -> bool
Whether a transmit is awaiting Session::on_tx_result.
Sourcepub fn queued_frame_count(&self) -> usize
pub fn queued_frame_count(&self) -> usize
Number of received frames currently waiting for the host.
Sourcepub fn dev_domain_version(&self) -> u32
pub fn dev_domain_version(&self) -> u32
Monotonic generation of the device-domain node tables and the live device key. The firmware caches this and re-syncs the live device node’s MAC whenever it changes (device-node plan increment 3).
Identity provisioning bumps it too, even though a newly
provisioned key only takes effect at the next boot
(live-state-until-reboot, as with CMD_CLEAR): the old key
stops being one the device claims immediately, and the node has
to be told so it can stop originating traffic under it.
Sourcepub fn dev_channel_keys(&self) -> impl Iterator<Item = [u8; 32]> + '_
pub fn dev_channel_keys(&self) -> impl Iterator<Item = [u8; 32]> + '_
The device identity’s provisioned channel keys (raw symmetric keys, not the derived identifiers). The firmware joins each into the device node so it processes multicast on that channel.
Sourcepub fn dev_peers(&self) -> impl Iterator<Item = [u8; 32]> + '_
pub fn dev_peers(&self) -> impl Iterator<Item = [u8; 32]> + '_
The device identity’s provisioned peer public keys. The firmware registers each with the device node’s MAC.
Sourcepub fn repeater_enabled(&self) -> bool
pub fn repeater_enabled(&self) -> bool
PROP_MAC_REPEATER_ENABLED: whether the device node should
autonomously forward overheard routable frames and advertise
NodeRole::Repeater. Part of the device domain, so it changes
Session::dev_domain_version and the firmware reconciles it
against the live MAC on the next sync.
Sourcepub fn repeater_regions(&self) -> &[u8] ⓘ
pub fn repeater_regions(&self) -> &[u8] ⓘ
PROP_MAC_REPEATER_REGIONS: the flood-forwarding region filter,
in wire order — concatenated 2-octet codes, empty for no
restriction. This is also exactly the Supported Regions identity
option payload, so a caller advertising the device’s regions can
forward these bytes unchanged.
Sourcepub fn repeater_default_region(&self) -> Option<[u8; 2]>
pub fn repeater_default_region(&self) -> Option<[u8; 2]>
PROP_MAC_REPEATER_DEFAULT_REGION: the code inserted into an
untagged flood packet, or None to never tag.
Sourcepub fn repeater_min_rssi(&self) -> Option<i16>
pub fn repeater_min_rssi(&self) -> Option<i16>
PROP_MAC_REPEATER_MIN_RSSI: minimum received RSSI in dBm for
flood forwarding, or None for no threshold.
Sourcepub fn repeater_min_snr(&self) -> Option<i8>
pub fn repeater_min_snr(&self) -> Option<i8>
PROP_MAC_REPEATER_MIN_SNR: minimum received SNR in whole dB for
flood forwarding, or None for no threshold.
Sourcepub fn dev_key(&self) -> Option<&[u8; 32]>
pub fn dev_key(&self) -> Option<&[u8; 32]>
The live PROP_DEV_KEY value. None once a factory reset
(CMD_CLEAR + CMD_RST) completes — the firmware uses this
edge to make a running device node dormant.
Sourcepub fn reset(&mut self, reason: Status, emit: &mut impl FnMut(&[u8])) -> Effect
pub fn reset(&mut self, reason: Status, emit: &mut impl FnMut(&[u8])) -> Effect
Reset all protocol state to post-reset values, announce the reset with the given reason, and return the radio effect applying the post-reset radio configuration.
Used for CMD_RST (with [Status::RESET_SOFTWARE]). With a
saved snapshot the post-reset value of every saved device-domain
property is its saved value — including the PHY enable state; the
documented defaults apply only when nothing is saved. The host
domain always returns to its documented defaults: it is never
saved. Queue contents and replay baselines are discarded either
way.
Sourcepub fn attach(&mut self, link_secure: bool)
pub fn attach(&mut self, link_secure: bool)
A host attached. Resets session state only (spec §Attach): the
device and host domains — PHY configuration and enable state,
device name, duty accounting, provisioning, and the inbound
queue — are untouched, and nothing is emitted; the attach itself
produces no notification. Accepted frames are delivered live
from here on; queued frames wait for CMD_QUEUE_DRAIN.
link_secure states whether this transport meets its security
binding for key provisioning (spec §Provisioning Security):
physical possession for serial transports, an encrypted bonded
LESC link for BLE. Key-bearing writes are refused while false.
Sourcepub fn detach(&mut self)
pub fn detach(&mut self)
The host detached. Session state is discarded; the device and
host domains keep operating detached: accepted frames are queued
instead of delivered (delegated acknowledgement arrives with
CAP_HOST_AUTO_ACK).
Sourcepub fn handle_frame(
&mut self,
bytes: &[u8],
now_ms: u64,
emit: &mut impl FnMut(&[u8]),
) -> Option<Effect>
pub fn handle_frame( &mut self, bytes: &[u8], now_ms: u64, emit: &mut impl FnMut(&[u8]), ) -> Option<Effect>
Handle one decoded ULCP frame from the host.
Sourcepub fn on_radio_rx(
&mut self,
data: &[u8],
rssi_dbm: i16,
snr_cb: i16,
lqi: Option<NonZeroU8>,
now_ms: u64,
emit: &mut impl FnMut(&[u8]),
) -> Option<Effect>
pub fn on_radio_rx( &mut self, data: &[u8], rssi_dbm: i16, snr_cb: i16, lqi: Option<NonZeroU8>, now_ms: u64, emit: &mut impl FnMut(&[u8]), ) -> Option<Effect>
Report a frame received on air at now_ms. While a host is
attached, accepted frames are emitted live as CMD_STR_RECV
(promiscuous mode bypasses filtering for live delivery only);
while detached, accepted frames are placed in the inbound queue,
authenticated duplicates coalesce, and a qualifying frame may
produce a delegated-acknowledgement transmit effect. Ignored
while the PHY is disabled or the frame exceeds the MTU (an
unstorable frame is never acknowledged).
Sourcepub fn on_tx_result(
&mut self,
outcome: TxOutcome,
now_ms: u64,
emit: &mut impl FnMut(&[u8]),
) -> Option<Effect>
pub fn on_tx_result( &mut self, outcome: TxOutcome, now_ms: u64, emit: &mut impl FnMut(&[u8]), ) -> Option<Effect>
Report completion of the transmit started by
Effect::StartTransmit.
Sourcepub fn respond_rssi(
&mut self,
tid: u8,
rssi: Result<i16, ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_rssi( &mut self, tid: u8, rssi: Result<i16, ()>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred PROP_PHY_RSSI read requested via
Effect::SampleRssi. rssi is the sampled value in dBm, or Err if
the radio read failed. Quote the same tid the effect carried.
Sourcepub fn respond_identity_blob(
&mut self,
tid: u8,
blob: Result<&[u8], ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_identity_blob( &mut self, tid: u8, blob: Result<&[u8], ()>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred PROP_IDENT read requested via
Effect::SignIdentity. blob is the complete signed
node-identity payload — the canonical unsigned encoding followed
by its 64-octet detached signature — or Err if it could not be
produced. Quote the same tid the effect carried.
Sourcepub fn ident_role(&self) -> Option<u8>
pub fn ident_role(&self) -> Option<u8>
PROP_IDENT_ROLE: the advertised ROLE byte, or None to let
the device derive it from its live forwarding state.
Sourcepub fn ident_mobile(&self) -> bool
pub fn ident_mobile(&self) -> bool
PROP_IDENT_MOBILE: whether the device identity advertises the
MOB capability bit.
Sourcepub fn dev_discoverable(&self) -> bool
pub fn dev_discoverable(&self) -> bool
PROP_DEV_DISCOVERABLE: whether the device identity answers
Identity Requests.
Sourcepub fn advert_interval_s(&self) -> u32
pub fn advert_interval_s(&self) -> u32
PROP_ADVERT_INTERVAL: seconds between unsolicited advertisements,
0 for none.
Sourcepub fn beacon_interval_s(&self) -> u32
pub fn beacon_interval_s(&self) -> u32
PROP_BEACON_INTERVAL: seconds between unsolicited beacons, 0 for
none.
Sourcepub fn startup_beacon(&self) -> bool
pub fn startup_beacon(&self) -> bool
PROP_STARTUP_BEACON: whether one beacon goes out at bring-up.
Sourcepub fn tz_offset_min(&self) -> i16
pub fn tz_offset_min(&self) -> i16
PROP_TZ_OFFSET: minutes east of UTC.
Sourcepub fn gnss_enabled(&self) -> bool
pub fn gnss_enabled(&self) -> bool
PROP_GNSS_ENABLED: whether the receiver should be powered.
Always false on a board without CAP_GNSS, so a platform can act
on it without first asking whether it has a receiver.
Sourcepub fn gnss_ident_update(&self) -> bool
pub fn gnss_ident_update(&self) -> bool
PROP_GNSS_IDENT_UPDATE: whether fixes refresh the advertised
node identity’s location.
Sourcepub fn gnss_ident_precision(&self) -> u8
pub fn gnss_ident_precision(&self) -> u8
PROP_GNSS_IDENT_PRECISION: the precision the advertised location
is clamped to.
Sourcepub fn gnss_time_trust(&self) -> bool
pub fn gnss_time_trust(&self) -> bool
PROP_GNSS_TIME_TRUST: whether receiver-derived time may set the
wall clock.
Sourcepub fn alert(&self) -> AlertState
pub fn alert(&self) -> AlertState
PROP_ALERT: what the device is currently doing to draw
attention to itself.
Sourcepub fn alert_deadline_ms(&self) -> Option<u64>
pub fn alert_deadline_ms(&self) -> Option<u64>
When the running alert gives itself up, as a monotonic
millisecond deadline on the caller’s clock, or None when no
alert is running.
The driver arms a timer on this and calls Session::poll_alert
when it fires. Enforcing the bound centrally is what keeps the
spec’s “a device MUST bound how long it will remain in
ALERT_LOCATE” from being a promise each board has to remember
to keep.
Sourcepub fn poll_alert(
&mut self,
now_ms: u64,
emit: &mut impl FnMut(&[u8]),
) -> Option<Effect>
pub fn poll_alert( &mut self, now_ms: u64, emit: &mut impl FnMut(&[u8]), ) -> Option<Effect>
Expire a running alert whose deadline has passed, returning the effect that stops the board’s indication.
Safe to call at any time: it does nothing until the deadline is actually reached, so a driver that polls it on every loop iteration behaves identically to one that arms a precise timer.
Sourcepub fn cancel_alert(&mut self, emit: &mut impl FnMut(&[u8])) -> Option<Effect>
pub fn cancel_alert(&mut self, emit: &mut impl FnMut(&[u8])) -> Option<Effect>
Cancel a running alert from the device itself — the button press of whoever found the radio.
Returns the effect that stops the indication, or None when no
alert was running (so a board can use the return to decide
whether the press was consumed).
Sourcepub fn toggle_gnss(&mut self, emit: &mut impl FnMut(&[u8])) -> Option<bool>
pub fn toggle_gnss(&mut self, emit: &mut impl FnMut(&[u8])) -> Option<bool>
Flip PROP_GNSS_ENABLED from the device itself — a button on a
board that offers the receiver as a user-facing switch.
Returns the new state, or None on a device without CAP_GNSS
(so a board can report a press unconditionally). No effect is
returned: the switch reaches the platform through the
device-domain mirror, the same path a host write, a boot restore
and a CMD_RST all take.
The transition is announced like any the host did not command.
PROP_GNSS_ENABLED is not otherwise an asynchronous property —
nothing else moves it behind the host’s back — but a switch the
operator can reach is exactly a thing that does.
Sourcepub fn publish_battery(
&mut self,
sample: BatteryStatus,
emit: &mut impl FnMut(&[u8]),
) -> bool
pub fn publish_battery( &mut self, sample: BatteryStatus, emit: &mut impl FnMut(&[u8]), ) -> bool
Publish an unsolicited PROP_BATTERY snapshot (spec
§PROP_BATTERY, Asynchronous Updates: Yes).
The platform decides when a measurement is worth announcing —
it owns the sampling cadence and the charge-state edges, and it
is the only layer that sees every sample. This publishes what it
hands over, so the session keeps its rule that it never caches a
reading: nothing here can answer a later CMD_PROP_GET.
Returns whether a frame was emitted. Nothing is published while
no host is attached (there is nobody to notify), and a snapshot
populating a field the configured BatteryFields never claimed
is dropped rather than sent — an unsolicited notification has no
transaction to fail. A snapshot that merely omits an advertised
field is published as-is: absence is how the device says the value
is not knowable right now.
Sourcepub fn respond_battery(
&mut self,
tid: u8,
sample: Result<BatteryStatus, ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_battery( &mut self, tid: u8, sample: Result<BatteryStatus, ()>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred PROP_BATTERY read requested via
Effect::SampleBattery. sample is the platform’s snapshot, or
Err if the measurement failed. Quote the same tid the effect
carried.
A snapshot populating a field the configured BatteryFields
never claimed is refused as STATUS_FAILURE; one that omits an
advertised field is answered as-is, since a field the platform
cannot currently substantiate is reported by its absence.
Sourcepub fn respond_illuminance(
&mut self,
tid: u8,
millilux: Option<u32>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_illuminance( &mut self, tid: u8, millilux: Option<u32>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred PROP_ILLUMINANCE read requested via
Effect::SampleIlluminance. millilux is the measurement, or
None when the sensor could not be read. Quote the same tid the
effect carried.
A failed read is the empty value rather than an error status: the
property is a measurement, and “no reading right now” is the same
answer PROP_TIME gives for a clock that has never been set.
Sourcepub fn respond_time(
&mut self,
tid: u8,
epoch: Option<u32>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_time( &mut self, tid: u8, epoch: Option<u32>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred PROP_TIME read requested via
Effect::ReadTime. epoch is the platform’s wall clock in Unix
seconds, or None when the device does not know what time it is.
Quote the same tid the effect carried.
Not knowing is a legitimate answer, not a failure: it is reported as the empty value, which is precisely what tells a host — and a device’s own display — that there is no clock to show.
Sourcepub fn publish_time(
&mut self,
epoch: Option<u32>,
emit: &mut impl FnMut(&[u8]),
) -> bool
pub fn publish_time( &mut self, epoch: Option<u32>, emit: &mut impl FnMut(&[u8]), ) -> bool
Publish an unsolicited PROP_TIME (spec §PROP_TIME,
Asynchronous Updates: Yes).
The platform decides what is worth announcing — it owns the clock and is the only layer that sees every source that touches it. A clock going from unknown to known is the announcement that matters most; a fresh fix agreeing with the clock to the second is not.
Returns whether a frame was emitted; nothing is published while no host is attached.
Sourcepub fn respond_gnss(
&mut self,
tid: u8,
key: u32,
sample: Result<GnssSnapshot, ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_gnss( &mut self, tid: u8, key: u32, sample: Result<GnssSnapshot, ()>, emit: &mut impl FnMut(&[u8]), )
Complete a deferred positioning read requested via
Effect::SampleGnss. sample is the receiver’s current view, or
Err if it could not be obtained. Quote the same tid and key
the effect carried.
A receiver that is off or still searching is not a failure — it
reports [GnssSnapshot::SEARCHING], which answers zero for the
facts it is sure of and empty for the position it does not have.
Sourcepub fn publish_gnss(
&mut self,
key: u32,
snapshot: &GnssSnapshot,
emit: &mut impl FnMut(&[u8]),
) -> bool
pub fn publish_gnss( &mut self, key: u32, snapshot: &GnssSnapshot, emit: &mut impl FnMut(&[u8]), ) -> bool
Publish one positioning property as an unsolicited CMD_PROP_IS
(spec §PROP_GNSS_LOCATION / §PROP_GNSS_FIX, Asynchronous Updates:
Yes).
The platform decides the cadence, as it does for PROP_BATTERY:
it sees every sentence the receiver produces and is the only layer
that can tell a meaningful change from a jittering last digit.
Returns whether a frame was emitted. key must be a positioning
property; anything else, and any publication while no host is
attached, is dropped.
Sourcepub fn drain_step(&mut self, now_ms: u64, emit: &mut impl FnMut(&[u8])) -> bool
pub fn drain_step(&mut self, now_ms: u64, emit: &mut impl FnMut(&[u8])) -> bool
Advance the drain started by Effect::DrainQueue one step,
emitting either the next covered frame (oldest first, as
CMD_STR_RECV with buffered metadata) or, once the covered set
is exhausted, the completion status. Returns true while
another call is needed; flush the transport between calls.
Sourcepub fn encode_snapshot(&self, out: &mut [u8]) -> Option<usize>
pub fn encode_snapshot(&self, out: &mut [u8]) -> Option<usize>
Encode the current device and host domains as a snapshot for
Effect::SaveSnapshot. out must hold SNAPSHOT_MAX
bytes.
Sourcepub fn restore_at_boot(&mut self, bytes: &[u8]) -> Result<Effect, SnapshotError>
pub fn restore_at_boot(&mut self, bytes: &[u8]) -> Result<Effect, SnapshotError>
Restore a stored snapshot at boot, before any host command is processed. On success the saved configuration is applied — the returned effect re-enables the PHY if it was enabled when saved, and detached operation (filtering, queueing, delegation) begins immediately.
The payload is decoded and validated into a candidate state
first and committed in one step, so a malformed option arriving
late in the decode cannot leave the device half-configured. On
rejection nothing is modified and the caller should offer the
next-older committed generation; see [Session::note_snapshot_ rejected] for what the device reports when none decodes.
Sourcepub fn note_snapshot_rejected(&mut self)
pub fn note_snapshot_rejected(&mut self)
Record that a stored generation was rejected at boot.
Called once per rejected generation. If a later, older generation
restores, PROP_SAVED reports SavedStatus::Fallback — the
device is working but running on stale configuration, which is
both more actionable and more urgent than “something was wrong”.
If none restores it reports SavedStatus::Unreadable, which a
host can tell apart from “nothing saved”.
Sourcepub fn saved_status(&self) -> SavedStatus
pub fn saved_status(&self) -> SavedStatus
What PROP_SAVED reports (spec §Saved State).
Sourcepub fn respond_save(
&mut self,
tid: u8,
result: Result<(), ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_save( &mut self, tid: u8, result: Result<(), ()>, emit: &mut impl FnMut(&[u8]), )
Complete the durable write requested via
Effect::SaveSnapshot, quoting the same tid. On Ok the
captured state becomes the post-reset baseline; on Err the
previous snapshot (if any) must have been left intact by the
caller and remains in effect.
Sourcepub fn note_snapshot_saved(&mut self)
pub fn note_snapshot_saved(&mut self)
Note that the live state was persisted without a host having asked — a device-initiated save, such as a switch the operator flipped at the board.
Required after any such write. The session answers CMD_RST and
CMD_RESTORE from its own copy of the snapshot rather than by
re-reading flash, so a save it was not told about would leave the
device restoring the values it had at boot and silently undoing
what the operator did.
Sourcepub fn respond_clear(
&mut self,
tid: u8,
result: Result<(), ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_clear( &mut self, tid: u8, result: Result<(), ()>, emit: &mut impl FnMut(&[u8]), )
Complete the durable erase requested via Effect::ClearSaved,
quoting the same tid. Live state is unaffected either way: the
live device identity in particular remains in effect until the
CMD_RST that completes a factory reset.
Sourcepub fn identity_request(&self) -> Option<IdentitySource>
pub fn identity_request(&self) -> Option<IdentitySource>
The staged PROP_DEV_PRIVATE_KEY provisioning awaiting
Effect::ProvisionIdentity execution.
Sourcepub fn respond_identity(
&mut self,
tid: u8,
result: Result<[u8; 32], ()>,
emit: &mut impl FnMut(&[u8]),
)
pub fn respond_identity( &mut self, tid: u8, result: Result<[u8; 32], ()>, emit: &mut impl FnMut(&[u8]), )
Complete the device-identity provisioning requested via
Effect::ProvisionIdentity, quoting the same tid. result
carries the new identity’s public key once the keypair is
durably stored — success is announced as CMD_PROP_IS for
PROP_DEV_KEY and the private key is never emitted (spec
§PROP_DEV_PRIVATE_KEY). On Ok the new identity is adopted even
if the transaction was abandoned by a detach: the durable write
already happened, and flash is the source of truth.
Sourcepub fn set_boot_identity(&mut self, public_key: [u8; 32])
pub fn set_boot_identity(&mut self, public_key: [u8; 32])
Install the independently persisted device identity’s public
key at boot, before any host command: the post-reset value of
PROP_DEV_KEY is the persisted identity, snapshot or not.