pub struct MobileUlcpSession { /* private fields */ }Expand description
Stateful mobile host session for the ULCP.
This is the protocol boundary: it consumes complete reassembled ULCP frames and owns TIDs, response matching, capability-driven synchronization, host ownership, and claim/save choreography. Platform code owns only the transport lifecycle, byte shuttling, and timers.
Implementations§
Source§impl MobileUlcpSession
impl MobileUlcpSession
Sourcepub fn administrative() -> Arc<Self>
pub fn administrative() -> Arc<Self>
A session for a radio this phone administers but does not claim.
Self::claim is refused; everything else behaves identically.
Sourcepub fn attach_mode(&self) -> UlcpAttachMode
pub fn attach_mode(&self) -> UlcpAttachMode
Which relationship this session represents.
Sourcepub fn begin(
&self,
selected_host_key: Option<Vec<u8>>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn begin( &self, selected_host_key: Option<Vec<u8>>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Begin post-attach synchronization for a new transport generation.
Sourcepub fn claim(
&self,
host_key: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn claim( &self, host_key: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Replace an unclaimed or other-host configuration with this phone’s key.
Sourcepub fn factory_reset(&self) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn factory_reset(&self) -> Result<UlcpSessionUpdateRecord, MobileError>
Erase ALL mutable state on the radio (saved provisioning, device
identity, BLE bonds, pairing PIN, every persisted journal) and
reboot it. The radio does not reply — the reset drops the link —
so this is fire-and-forget: send the frame, then treat the ensuing
disconnect as completion. Permitted from any stage so a misbehaving
radio can always be wiped; unlike claim/configure it makes no
stage or ownership demands.
Sourcepub fn set_alert(
&self,
state: UlcpAlertState,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn set_alert( &self, state: UlcpAlertState, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Start or stop the radio’s locate alert (PROP_ALERT) so a
misplaced radio can be found.
Not part of configure_device, and never saved: this is live
behavior rather than configuration, and it deliberately survives
the phone walking out of BLE range — which is precisely when a
search needs it. What ends it is this call, a button press at the
radio, or the radio’s own deadline; the latter two arrive as an
unsolicited PROP_ALERT carried on the session snapshot.
Re-sending Locate while an alert is running restarts that
deadline, which is how a longer search keeps the alert alive.
Sourcepub fn set_time(
&self,
epoch_seconds: Option<u32>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn set_time( &self, epoch_seconds: Option<u32>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Set — or clear — the device’s wall clock (PROP_TIME).
Live state rather than configuration, and never saved: an epoch
written to flash would come back arbitrarily wrong, since nothing
bounds how long a device spends powered off. So this is not part
of Self::configure_device, which carries the time zone —
where the device is meant to be is worth persisting even when what
time it is is not.
None clears the clock back to unknown, which is what a device
reports before its first fix. On a device whose receiver is
trusted for time, a fix will overwrite whatever is set here.
The device answers with the epoch it now holds; that answer, not the value written, is what the session snapshot reports.
Sourcepub fn configure(
&self,
settings: UlcpRadioSettingsRecord,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn configure( &self, settings: UlcpRadioSettingsRecord, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Apply, verify, and persist a complete radio-settings snapshot.
Sourcepub fn configure_device(
&self,
configuration: UlcpDeviceConfigRecord,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn configure_device( &self, configuration: UlcpDeviceConfigRecord, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Apply, verify, and persist a complete configuration of the device’s own domain: its radio, the role it advertises, and whether and how it forwards for the mesh on its own.
This is what commissioning writes. It touches nothing in the host domain — no host key, no filters, no queues — so it is equally valid from an administrative session on someone else’s radio and from a tethered session on this phone’s own.
Sourcepub fn configure_positioning(
&self,
gnss: Option<UlcpGnssSettingsRecord>,
tz_offset_min: Option<i16>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn configure_positioning( &self, gnss: Option<UlcpGnssSettingsRecord>, tz_offset_min: Option<i16>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Apply and persist the time zone and the positioning policy, and nothing else.
Self::configure_device can write these too, as part of a whole
device domain — that is what commissioning does. This exists for
the case commissioning does not cover: a phone changing the
positioning settings of the radio it is tethered to, which has
no reason to restate that radio’s role, discoverability, or
forwarding policy in order to switch a receiver on.
Each argument must be present exactly when the device advertises
the matching capability, and the four positioning properties
travel together for the reason UlcpGnssSettingsRecord gives.
The write is echo-verified property by property and closed with a
save, like any other configuration pass.
Sourcepub fn configure_advertising(
&self,
advert: Option<UlcpAdvertSettingsRecord>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn configure_advertising( &self, advert: Option<UlcpAdvertSettingsRecord>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Apply and persist the advertisement policy, and nothing else.
The tethered-radio counterpart of Self::configure_positioning:
a phone changing how often its own radio announces itself has no
reason to restate that radio’s role, forwarding policy, or
receiver settings to do it.
Sourcepub fn refresh(&self) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn refresh(&self) -> Result<UlcpSessionUpdateRecord, MobileError>
Re-read every capability-gated property represented by the mobile snapshot. The existing snapshot remains usable while the bounded refresh is in flight; authoritative provisioning is published when the full capability-gated read completes.
Sourcepub fn refresh_positioning(
&self,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn refresh_positioning( &self, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Sample where the device is, and how well it knows.
The device announces a fix indicator and nothing else about a position — a receiver reports about a fix a second and ordinary noise moves the reading, so announcing any of this would keep the radio transmitting for a host that may not be looking. A host that is looking asks, at whatever rate it can use the answer.
Deliberately narrower than refresh: the five
positioning properties and nothing else, so a screen watching a
position does not re-read the PHY triple every time it looks.
Sourcepub fn insert_device_channel_key(
&self,
channel_key: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn insert_device_channel_key( &self, channel_key: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Store one channel key on the radio’s device identity
(PROP_DEV_CHANNEL_KEYS), then persist with a chained CMD_SAVE when
the device can.
This is the device’s own channel membership, independent of the phone’s: it is what the device uses for its own advertisements, blind-unicast addressing, and repeater filtering, and it survives host replacement.
Requires an attached, otherwise-idle session on a device advertising
CAP_DEV_IDENTITY, and the device additionally requires an encrypted
link before it will accept key material. Failures surface as
operation_error with the device’s status name — NOMEM when the list
is full (capacity ulcp_max_dev_channels), ALREADY when the key is
already stored, which callers should treat as success.
Sourcepub fn remove_device_channel_key(
&self,
channel_key: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn remove_device_channel_key( &self, channel_key: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Remove one channel key from the radio’s device identity
(PROP_DEV_CHANNEL_KEYS), then persist with a chained CMD_SAVE when
the device can.
The remove selector is the key itself, so only a channel the caller
still holds the key for can be removed this way. Same preconditions as
Self::insert_device_channel_key; ITEM_NOT_FOUND surfaces as
operation_error and callers should treat it as success.
Sourcepub fn reconcile_host_channel_keys(
&self,
keys: Vec<Vec<u8>>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn reconcile_host_channel_keys( &self, keys: Vec<Vec<u8>>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Make the radio’s host channel-key table (PROP_HOST_CHANNEL_KEYS)
match the phone identity’s joined channels.
The radio needs these keys to recognize multicast and blind-unicast traffic addressed to channels this phone has joined, and to queue it while the phone is away. That is bookkeeping between the app and its own radio, not a user-facing setting: callers reconcile on attach and after every join or leave, and never surface it.
The host domain is volatile — the device does not persist it — so no
CMD_SAVE is chained and reconciling on attach is what makes it stick.
Requires an attached, idle session on a device advertising
CAP_HOST_KEYS; otherwise the table is not this session’s to manage
and the call reports that the capability is missing.
Returns without any frames when the device already holds exactly the requested set.
Sourcepub fn insert_device_peer(
&self,
public_key: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn insert_device_peer( &self, public_key: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Store one peer public key on the radio’s device identity
(PROP_DEV_PEERS), then persist with a chained CMD_SAVE when the
device can.
Requires an attached, otherwise-idle session on a device advertising
CAP_DEV_IDENTITY. Failures surface as operation_error with the
device’s status name — NOMEM when the list is full (capacity
ulcp_max_dev_peers), ALREADY when the key is already stored,
which callers should treat as success.
Sourcepub fn remove_device_peer(
&self,
public_key: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn remove_device_peer( &self, public_key: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Remove one peer public key from the radio’s device identity
(PROP_DEV_PEERS), then persist with a chained CMD_SAVE when the
device can.
Same preconditions as Self::insert_device_peer. ITEM_NOT_FOUND
surfaces as operation_error and callers should treat it as success —
the key is not on the device either way.
Sourcepub fn transmit_raw(
&self,
data: Vec<u8>,
nocca: bool,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn transmit_raw( &self, data: Vec<u8>, nocca: bool, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Queue one complete raw UMSH frame on STR_PHY_RAW.
The platform adapter supplies only opaque bytes from MobileMeshSession;
Rust owns the ULCP command, stream identifier, metadata, TID, and
confirmation matching. nocca sets TX_FLAG_NOCCA so the device
transmits without its pre-transmit channel-activity check — used for
immediate MAC acks (see [MobileMeshOutboundFrameRecord::nocca]).
Sourcepub fn consume(
&self,
frame: Vec<u8>,
) -> Result<UlcpSessionUpdateRecord, MobileError>
pub fn consume( &self, frame: Vec<u8>, ) -> Result<UlcpSessionUpdateRecord, MobileError>
Consume one complete ULCP frame and advance the session reducer.
Sourcepub fn reset(&self) -> UlcpSessionUpdateRecord
pub fn reset(&self) -> UlcpSessionUpdateRecord
Invalidate all outstanding transactions for a disconnected transport.
Sourcepub fn abandon_raw_transmits(
&self,
transaction_ids: Vec<u8>,
) -> UlcpSessionUpdateRecord
pub fn abandon_raw_transmits( &self, transaction_ids: Vec<u8>, ) -> UlcpSessionUpdateRecord
Abandon raw transactions whose GATT writes were rejected locally. Their late correlated responses are ignored once; the attachment and all non-raw session state remain intact.