pub struct UlcpDevice<L> { /* private fields */ }Expand description
Companion radio attached over a frame link, usable as a
[umsh_hal::Radio].
Implementations§
Source§impl<L> UlcpDevice<L>where
L: FrameLink,
impl<L> UlcpDevice<L>where
L: FrameLink,
Sourcepub fn attach_mode(&self) -> AttachMode
pub fn attach_mode(&self) -> AttachMode
Which relationship this handle has with the device.
Sourcepub async fn new(link: L, config: UlcpDeviceConfig) -> Result<Self, UlcpError>
pub async fn new(link: L, config: UlcpDeviceConfig) -> Result<Self, UlcpError>
Attach to a device: reset it, verify the protocol version, apply the RF configuration, and enable the PHY.
This is the minimal-protocol attach: CMD_RST discards a
full-protocol device’s session-independent state visibility (and
with a saved snapshot the post-reset values come from the
snapshot, not the documented defaults). A host cooperating with
an autonomously operating device should use
Self::attach_existing instead.
Sourcepub async fn attach_existing(
link: L,
config: UlcpDeviceConfig,
) -> Result<Self, UlcpError>
pub async fn attach_existing( link: L, config: UlcpDeviceConfig, ) -> Result<Self, UlcpError>
Attach to an already-operating device as its tethered host: the one host whose traffic it filters, queues and acknowledges.
This is the full-protocol attach (spec §Attach, Detach, and
Synchronization): attach implies no known state, so the host
synchronizes by fetching. Only the identity handshake runs here
— retained PROP_LAST_STATUS (the reset cause, preserved for
Self::boot_status and Self::sync), the protocol version
check, PROP_DEV_VERSION, and PROP_PHY_MTU. The PHY keeps
whatever configuration and enable state it had; queued frames
and provisioning are untouched. Follow with Self::sync,
Self::provision, and drain the queue when ready.
Use Self::attach_administrative to configure a device you do
not intend to tether to — one phone administering ten repeaters
must not write PROP_HOST_KEY on any of them.
Sourcepub async fn attach_administrative(
link: L,
config: UlcpDeviceConfig,
) -> Result<Self, UlcpError>
pub async fn attach_administrative( link: L, config: UlcpDeviceConfig, ) -> Result<Self, UlcpError>
Attach to an already-operating device to administer it: configure its own identity, radio, and behavior without becoming its host.
Commissioning and tethering are different relationships and this
is the difference made mechanical. The handle refuses every
host-domain write — PROP_HOST_KEY, the host key tables, the
filter table, the delegation policy, and Self::provision —
with UlcpError::AdministrativeAttach. Everything
else, including the device identity and the saved snapshot, works
normally.
A device may be administered by many hosts over its lifetime and tethered to at most one at a time; nothing about administering it disturbs whichever host it is currently serving.
Sourcepub fn into_link(self) -> L
pub fn into_link(self) -> L
Give up this handle and recover the transport underneath it.
The link stays open, so the device sees no detach and keeps its
session-scoped state: this releases the host’s bookkeeping, not
the connection. Re-attaching the returned link produces a fresh
handle, which is how a long-lived interactive host changes
AttachMode — administrative for inspection, tethered for the
one command that establishes a host domain — without making the
user wait through a BLE reconnect.
Sourcepub fn set_frame_trace(&mut self, trace: Option<FrameTrace>)
pub fn set_frame_trace(&mut self, trace: Option<FrameTrace>)
Install (or clear) a per-frame trace sink. Every frame sent and
every frame received is reported as a one-line summary (see
describe_frame), so a failure can be placed at the host API,
framing, session, storage, or radio boundary.
Sourcepub fn dev_version(&self) -> &str
pub fn dev_version(&self) -> &str
The device’s firmware version string (PROP_DEV_VERSION).
Sourcepub async fn device_name(&mut self) -> Result<String, UlcpError>
pub async fn device_name(&mut self) -> Result<String, UlcpError>
Fetch the device’s human-readable PROP_DEV_NAME.
Sourcepub async fn set_device_name(&mut self, name: &str) -> Result<(), UlcpError>
pub async fn set_device_name(&mut self, name: &str) -> Result<(), UlcpError>
Set the device’s human-readable PROP_DEV_NAME.
Sourcepub async fn battery_status(
&mut self,
) -> Result<Option<BatteryStatus>, UlcpError>
pub async fn battery_status( &mut self, ) -> Result<Option<BatteryStatus>, UlcpError>
Fetch a live battery status snapshot (PROP_BATTERY).
Ok(None) means the device does not advertise CAP_BATTERY (not
battery powered). Ok(Some(status)) with every field None means
battery powered with unsupported reporting. A measurement the device
cannot currently obtain surfaces as a command failure, never as
None — battery is live telemetry, so this is deliberately not
part of UlcpDevice::sync.
Sourcepub async fn illuminance(&mut self) -> Result<Option<u32>, UlcpError>
pub async fn illuminance(&mut self) -> Result<Option<u32>, UlcpError>
Fetch a live ambient illuminance reading in millilux
(PROP_ILLUMINANCE).
Ok(None) means either that the device does not advertise
CAP_ILLUMINANCE — no light sensor is fitted — or that a device
which does could not read the sensor just now. Both are “there is
no reading”, which is what a caller acts on; neither is an error.
Live telemetry, so deliberately not part of UlcpDevice::sync.
Sourcepub async fn alert(&mut self) -> Result<Option<AlertState>, UlcpError>
pub async fn alert(&mut self) -> Result<Option<AlertState>, UlcpError>
Read the device’s locate-alert state (PROP_ALERT).
Ok(None) means the device does not advertise CAP_ALERT — it has
no way to make itself conspicuous.
Sourcepub async fn set_alert(
&mut self,
state: AlertState,
) -> Result<AlertState, UlcpError>
pub async fn set_alert( &mut self, state: AlertState, ) -> Result<AlertState, UlcpError>
Start or stop the device’s locate alert (PROP_ALERT).
Setting [AlertState::Locate] while an alert is already running
restarts the device’s deadline rather than failing, so a host that
wants an alert to outlast the board’s own bound re-sends this.
Returns the authoritative state the device reported.
The alert also ends when someone cancels it at the device or the
deadline expires; both arrive as an unsolicited PROP_ALERT
update rather than as a response to this call.
A device without CAP_ALERT answers STATUS_PROP_NOT_FOUND.
Sourcepub fn boot_status(&self) -> Status
pub fn boot_status(&self) -> Status
Reset cause reported by the device immediately after transport attach.
Sourcepub async fn repeater_policy(
&mut self,
) -> Result<Option<RepeaterPolicy>, UlcpError>
pub async fn repeater_policy( &mut self, ) -> Result<Option<RepeaterPolicy>, UlcpError>
Read the device’s full repeater forwarding policy.
Ok(None) means the device does not advertise CAP_REPEATER.
Sourcepub async fn set_repeater_regions(
&mut self,
regions: &[RegionCode],
) -> Result<Vec<RegionCode>, UlcpError>
pub async fn set_repeater_regions( &mut self, regions: &[RegionCode], ) -> Result<Vec<RegionCode>, UlcpError>
Set which region-tagged floods the device forwards
(PROP_MAC_REPEATER_REGIONS). An empty list clears the filter,
which imposes no regional restriction rather than blocking every
flood.
Returns the list the device actually stored. A device with less capacity than the caller offered keeps a prefix, so a shorter return is a truncation, not an error.
Sourcepub async fn set_repeater_default_region(
&mut self,
region: Option<RegionCode>,
) -> Result<Option<RegionCode>, UlcpError>
pub async fn set_repeater_default_region( &mut self, region: Option<RegionCode>, ) -> Result<Option<RegionCode>, UlcpError>
Set the region code inserted into untagged floods before
forwarding (PROP_MAC_REPEATER_DEFAULT_REGION). None forwards
untagged.
Deliberately not cross-checked against
set_repeater_regions: the two are
written in either order.
Sourcepub async fn set_repeater_min_rssi(
&mut self,
min_rssi: Option<i16>,
) -> Result<Option<i16>, UlcpError>
pub async fn set_repeater_min_rssi( &mut self, min_rssi: Option<i16>, ) -> Result<Option<i16>, UlcpError>
Set the RSSI floor for forwarding in dBm
(PROP_MAC_REPEATER_MIN_RSSI). None accepts any.
Sourcepub async fn set_repeater_min_snr(
&mut self,
min_snr: Option<i8>,
) -> Result<Option<i8>, UlcpError>
pub async fn set_repeater_min_snr( &mut self, min_snr: Option<i8>, ) -> Result<Option<i8>, UlcpError>
Set the SNR floor for forwarding in dB
(PROP_MAC_REPEATER_MIN_SNR). None accepts any.
Sourcepub async fn time(&mut self) -> Result<Option<DeviceTime>, UlcpError>
pub async fn time(&mut self) -> Result<Option<DeviceTime>, UlcpError>
Read the device’s wall clock and time zone (PROP_TIME,
PROP_TZ_OFFSET).
Ok(None) means the device does not advertise CAP_TIME.
Ok(Some(time)) with time.epoch == None means it has one and
does not know what time it is — the state in which a device with a
screen must show no clock at all.
Sourcepub async fn set_time(
&mut self,
epoch: Option<u32>,
) -> Result<Option<u32>, UlcpError>
pub async fn set_time( &mut self, epoch: Option<u32>, ) -> Result<Option<u32>, UlcpError>
Set the device’s wall clock (PROP_TIME). None returns it to not
knowing what time it is.
A manual set outranks every receiver-derived one, including while
PROP_GNSS_TIME_TRUST is clear.
Sourcepub async fn set_tz_offset(&mut self, minutes: i16) -> Result<i16, UlcpError>
pub async fn set_tz_offset(&mut self, minutes: i16) -> Result<i16, UlcpError>
Set the device’s local time-zone offset in minutes east of UTC
(PROP_TZ_OFFSET).
Sourcepub async fn gnss_status(&mut self) -> Result<Option<GnssStatus>, UlcpError>
pub async fn gnss_status(&mut self) -> Result<Option<GnssStatus>, UlcpError>
Read everything the device reports about positioning
(PROP_GNSS_*).
Ok(None) means the device does not advertise CAP_GNSS. The fix
is live telemetry, so a disabled or searching receiver reports
[GnssSnapshot::SEARCHING] rather than an error.
Sourcepub async fn advert_policy(&mut self) -> Result<Option<AdvertPolicy>, UlcpError>
pub async fn advert_policy(&mut self) -> Result<Option<AdvertPolicy>, UlcpError>
Read the device’s advertisement policy, or None on a device
without CAP_ADVERT.
Sourcepub async fn set_advert_interval(
&mut self,
seconds: u32,
) -> Result<u32, UlcpError>
pub async fn set_advert_interval( &mut self, seconds: u32, ) -> Result<u32, UlcpError>
Set the seconds between signed identity advertisements, 0 for none
(PROP_ADVERT_INTERVAL).
Sourcepub async fn set_beacon_interval(
&mut self,
seconds: u32,
) -> Result<u32, UlcpError>
pub async fn set_beacon_interval( &mut self, seconds: u32, ) -> Result<u32, UlcpError>
Set the seconds between empty beacons, 0 for none
(PROP_BEACON_INTERVAL).
Sourcepub async fn set_startup_beacon(
&mut self,
enabled: bool,
) -> Result<bool, UlcpError>
pub async fn set_startup_beacon( &mut self, enabled: bool, ) -> Result<bool, UlcpError>
Set whether one beacon goes out at bring-up (PROP_STARTUP_BEACON).
Sourcepub async fn set_gnss_enabled(
&mut self,
enabled: bool,
) -> Result<bool, UlcpError>
pub async fn set_gnss_enabled( &mut self, enabled: bool, ) -> Result<bool, UlcpError>
Power the GNSS receiver on or off (PROP_GNSS_ENABLED).
Sourcepub async fn set_gnss_ident_update(
&mut self,
enabled: bool,
) -> Result<bool, UlcpError>
pub async fn set_gnss_ident_update( &mut self, enabled: bool, ) -> Result<bool, UlcpError>
Set whether fixes refresh the advertised node identity’s location
(PROP_GNSS_IDENT_UPDATE).
Sourcepub async fn set_gnss_ident_precision(
&mut self,
precision: u8,
) -> Result<u8, UlcpError>
pub async fn set_gnss_ident_precision( &mut self, precision: u8, ) -> Result<u8, UlcpError>
Set the precision the advertised location is clamped to, in
location bytes (PROP_GNSS_IDENT_PRECISION).
Sourcepub async fn set_gnss_time_trust(
&mut self,
trust: bool,
) -> Result<bool, UlcpError>
pub async fn set_gnss_time_trust( &mut self, trust: bool, ) -> Result<bool, UlcpError>
Set whether receiver-derived time may set the wall clock
(PROP_GNSS_TIME_TRUST).
Clearing it leaves a manually-set clock proof against a jammed or spoofed sky; position reporting is unaffected.
Sourcepub async fn get_prop(&mut self, key: u32) -> Result<Vec<u8>, UlcpError>
pub async fn get_prop(&mut self, key: u32) -> Result<Vec<u8>, UlcpError>
Fetch a property’s raw value via CMD_PROP_GET.
Sourcepub async fn set_prop(
&mut self,
key: u32,
value: &[u8],
) -> Result<Vec<u8>, UlcpError>
pub async fn set_prop( &mut self, key: u32, value: &[u8], ) -> Result<Vec<u8>, UlcpError>
Set a property via CMD_PROP_SET, returning the authoritative
value echoed by the device.
Sourcepub async fn insert_prop_item(
&mut self,
key: u32,
item: &[u8],
) -> Result<Vec<u8>, UlcpError>
pub async fn insert_prop_item( &mut self, key: u32, item: &[u8], ) -> Result<Vec<u8>, UlcpError>
Insert one item into a multi-value property via
CMD_PROP_INSERT, returning the inserted item’s digest form
from the correlated CMD_PROP_INSERTED.
item is in the property’s item form with no length prefix.
A duplicate fails with STATUS_ALREADY unless the property
defines replacement semantics (PROP_HOST_PEER_KEYS).
Sourcepub async fn remove_prop_item(
&mut self,
key: u32,
selector: &[u8],
) -> Result<Vec<u8>, UlcpError>
pub async fn remove_prop_item( &mut self, key: u32, selector: &[u8], ) -> Result<Vec<u8>, UlcpError>
Remove one item from a multi-value property via
CMD_PROP_REMOVE, returning the removed item’s digest form from
the correlated CMD_PROP_REMOVED.
selector is the property’s documented remove selector. A
missing item fails with STATUS_ITEM_NOT_FOUND.
Sourcepub async fn queue_drain(&mut self) -> Result<(), UlcpError>
pub async fn queue_drain(&mut self) -> Result<(), UlcpError>
Drain the device’s inbound queue (CMD_QUEUE_DRAIN).
Buffered frames are delivered as ordinary CMD_STR_RECV and land
in the receive queue for [Radio::poll_receive]; this future
resolves on the correlated completion status.
Sourcepub async fn queue_drain_with(
&mut self,
on_frame: impl FnMut(&[u8], &[u8]),
) -> Result<(), UlcpError>
pub async fn queue_drain_with( &mut self, on_frame: impl FnMut(&[u8], &[u8]), ) -> Result<(), UlcpError>
As Self::queue_drain, invoking on_frame with each frame
(data, trailing metadata bytes) delivered before completion —
buffered and interleaved live frames alike. The callback sees
every such frame: an device queue larger than this driver’s
bounded receive buffer drains losslessly through it. Frames are
additionally queued for [Radio::poll_receive], where the
bounded buffer’s oldest-dropped policy still applies.
Sourcepub async fn save(&mut self) -> Result<(), UlcpError>
pub async fn save(&mut self) -> Result<(), UlcpError>
Save the device’s device and host domains to non-volatile storage
(CMD_SAVE; requires CAP_SAVE).
Sourcepub async fn clear(&mut self) -> Result<(), UlcpError>
pub async fn clear(&mut self) -> Result<(), UlcpError>
Erase the device’s saved snapshot and other persisted provisioning
(CMD_CLEAR; base protocol, BLE bonds and pairing PIN exempt).
Sourcepub async fn reset(&mut self) -> Result<Status, UlcpError>
pub async fn reset(&mut self) -> Result<Status, UlcpError>
Reset the device (CMD_RST) and wait for the reset notification,
returning the announced reset status. The device comes up as from
a power cycle — restoring its saved snapshot when one exists,
factory configuration otherwise. All session-scoped state and
cached views are gone; follow with Self::sync.
Sourcepub async fn factory_reset(&mut self) -> Result<(), UlcpError>
pub async fn factory_reset(&mut self) -> Result<(), UlcpError>
Factory-reset the device (CMD_FACTORY_RESET): erase ALL mutable
state — saved provisioning, the device identity, BLE bonds, and the
pairing PIN — and reboot to a blank factory state. Unlike
Self::reset this sends no expectation of a reply and does not
wait: the device wipes storage and reboots without responding, which
drops the transport link. Treat the ensuing disconnect as
completion; a caller that needs the radio again must re-open the
transport and re-pair, since the bond it used is now gone.
Sourcepub async fn restore(&mut self) -> Result<RestoreCompletion, UlcpError>
pub async fn restore(&mut self) -> Result<RestoreCompletion, UlcpError>
Revert the device to its saved snapshot (CMD_RESTORE; requires
CAP_SAVE), accepting both spec-permitted completion forms.
Sourcepub async fn set_ble_pairing_pin(
&mut self,
pin: Option<u32>,
) -> Result<(), UlcpError>
pub async fn set_ble_pairing_pin( &mut self, pin: Option<u32>, ) -> Result<(), UlcpError>
Set or clear the device’s persisted, write-only BLE pairing PIN.
This property is the protocol’s sole status-only property write: the
value is never echoed. None clears the configured passkey.
Sourcepub async fn capabilities(&mut self) -> Result<Vec<u32>, UlcpError>
pub async fn capabilities(&mut self) -> Result<Vec<u32>, UlcpError>
Fetch and decode PROP_CAPS.
Sourcepub async fn sync(
&mut self,
expected_host_key: Option<&[u8; 32]>,
) -> Result<DeviceSync, UlcpError>
pub async fn sync( &mut self, expected_host_key: Option<&[u8; 32]>, ) -> Result<DeviceSync, UlcpError>
Run the spec’s post-attach synchronization procedure: fetch the
retained PROP_LAST_STATUS (detecting a reset since the last
contact), the capability list, the configured host identity —
yielding an ownership verdict against expected_host_key — and
the state each advertised capability grants, all in digest form.
The host must decide ownership before treating queued data as
its own: HostOwnership::OtherHost means the queue and
provisioning belong to another identity.
Sourcepub async fn provision(
&mut self,
desired: &HostProvisioning,
) -> Result<ProvisionReport, UlcpError>
pub async fn provision( &mut self, desired: &HostProvisioning, ) -> Result<ProvisionReport, UlcpError>
Establish desired as the device’s complete host domain,
writing every part of it unconditionally.
This does not compare and patch, and that is deliberate. Key
tables read back in lossy form only: the device reports channel
identifiers and peer public keys, never key material. An
administrator can replace a peer’s K_enc/K_mic without
changing anything observable, so no comparison over the readable
surface can detect it — and a digest over the secret state would
mean deriving a readable value from key material, which is worse
than the problem. The host asserts what it wants; it does not
reason about what the device already holds.
Removals still come from comparison, and that is not a
contradiction: membership is readable even though key material
is not. So this reads the digest lists, removes what desired
omits, and writes everything desired contains regardless of
what came back.
The host domain is volatile across power cycles, so the usual case is a device that has just rebooted and holds nothing. When it has not rebooted the rewrite is redundant — that is the point. Correctness must not depend on detecting which case this is, because reboot detection would also have to cover partial provisioning, another administrator having intervened, and future device behavior changes.
Each individual write is transactional on the device (spec §Mutation Atomicity); the sequence is not (see the ULCP transition plan, decision 7). An interrupted call leaves a mixture, which the next call repairs by rewriting everything.
Provisioning is per item rather than per table wherever the table can grow: a whole peer table stops fitting in a frame at the fifth entry.
Sourcepub async fn ensure_device_identity(&mut self) -> Result<[u8; 32], UlcpError>
pub async fn ensure_device_identity(&mut self) -> Result<[u8; 32], UlcpError>
The device’s device identity public key, generating one on-device
if none is configured (CAP_DEV_IDENTITY; generation requires
the transport’s provisioning-security binding).
On-device generation is the spec-recommended form: the private key never exists anywhere but the radio, and only the resulting public key crosses the link.
Sourcepub fn pop_prop_event(&mut self) -> Option<PropEvent>
pub fn pop_prop_event(&mut self) -> Option<PropEvent>
Take the oldest retained unsolicited property notification.
Events accumulate while other calls read from the link (bounded
at [PROP_EVENT_DEPTH], oldest dropped first).
Sourcepub async fn transmit_raw_with_meta(
&mut self,
data: &[u8],
metadata: &[u8],
) -> Result<(), TxError<UlcpError>>
pub async fn transmit_raw_with_meta( &mut self, data: &[u8], metadata: &[u8], ) -> Result<(), TxError<UlcpError>>
Transmit a frame with a caller-supplied STR_PHY_RAW metadata
block, byte for byte.
[Radio::transmit] composes the metadata from [TxOptions],
which is what a MAC wants. A bridge does not: it relays frames
whose transmit parameters were decided elsewhere, and must be
able to put exactly those bytes on the wire — including fields
[TxOptions] has no vocabulary for, such as a power override.
The channel-access retry budget comes from the metadata itself:
with TX_FLAG_NOCCA clear the device performs CCA and a busy
channel fails immediately with [TxError::CadTimeout], leaving
the retry policy to the caller.
Sourcepub fn poll_receive_raw(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<RawRxFrame, UlcpError>>
pub fn poll_receive_raw( &mut self, cx: &mut Context<'_>, ) -> Poll<Result<RawRxFrame, UlcpError>>
Poll for one inbound frame, preserving its metadata bytes.
[Radio::poll_receive] decodes the metadata into [RxInfo],
which cannot represent it faithfully: the “unsupported” sentinels
collapse to zero and the buffered-frame extension is discarded
entirely. A bridge relays the metadata rather than interpreting
it, so it needs the bytes.
Sourcepub async fn receive_raw(&mut self) -> Result<RawRxFrame, UlcpError>
pub async fn receive_raw(&mut self) -> Result<RawRxFrame, UlcpError>
Await one inbound frame with its metadata bytes intact.
Cancel-safe: the frame is only removed from the inbound queue once this future is ready to return it.
Source§impl UlcpDevice<SerialFrameLink<SerialStream>>
impl UlcpDevice<SerialFrameLink<SerialStream>>
Sourcepub async fn open_serial(
path: impl AsRef<str>,
baud_rate: u32,
config: UlcpDeviceConfig,
) -> Result<Self, UlcpError>
pub async fn open_serial( path: impl AsRef<str>, baud_rate: u32, config: UlcpDeviceConfig, ) -> Result<Self, UlcpError>
Attach to a device on a serial port.
Source§impl UlcpDevice<BleFrameLink>
impl UlcpDevice<BleFrameLink>
Sourcepub async fn open_ble(
selector: Option<&str>,
config: UlcpDeviceConfig,
) -> Result<Self, UlcpError>
pub async fn open_ble( selector: Option<&str>, config: UlcpDeviceConfig, ) -> Result<Self, UlcpError>
Discover, connect, attach, and initialize a BLE companion radio.
Sourcepub async fn open_ble_with_link_config(
selector: Option<&str>,
config: UlcpDeviceConfig,
link_config: BleFrameLinkConfig,
) -> Result<Self, UlcpError>
pub async fn open_ble_with_link_config( selector: Option<&str>, config: UlcpDeviceConfig, link_config: BleFrameLinkConfig, ) -> Result<Self, UlcpError>
As Self::open_ble, with an explicit GATT link configuration.
Trait Implementations§
Source§impl<L> Radio for UlcpDevice<L>where
L: FrameLink,
impl<L> Radio for UlcpDevice<L>where
L: FrameLink,
Source§async fn transmit(
&mut self,
data: &[u8],
options: TxOptions,
) -> Result<(), TxError<Self::Error>>
async fn transmit( &mut self, data: &[u8], options: TxOptions, ) -> Result<(), TxError<Self::Error>>
Transmit one frame and await the device’s confirmation.
A confirmed transmit blocks the caller for up to
response_timeout + 2 × t_frame_ms while the frame goes out on air. This
is inherent to the half-duplex [Radio::transmit] contract and a real
radio behaves the same way. Frames the device receives during this window
are not lost — they are queued (see wait_response
→ ingest) and surface on the next
poll_receive. MAC-layer timers (ACK timeouts,
retransmit deadlines) cannot advance while this future is pending, but
they are only delayed, not missed: the coordinator re-evaluates every
deadline against the current clock as soon as transmit returns, so a
deadline that came due mid-transmit fires immediately afterward.
type Error = UlcpError
Source§fn poll_receive(
&mut self,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<Result<RxInfo, Self::Error>>
fn poll_receive( &mut self, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<RxInfo, Self::Error>>
buf. Read more