Skip to main content

ThreadDriver

Struct ThreadDriver 

Source
pub struct ThreadDriver<'d, T>
where T: Mode,
{ /* private fields */ }
Expand description

This struct provides a safe wrapper over the ESP IDF Thread C driver.

The driver works on Layer 2 (Data Link) in the OSI model, in that it provides facilities for sending and receiving ethernet packets over the Thread radio.

For most use cases, utilizing EspThread - which provides a networking (IP) layer as well - should be preferred. Using ThreadDriver directly is beneficial only when one would like to utilize a custom, non-STD network stack like smoltcp.

The driver can work in two modes:

  • RCP (Radio Co-Processor) mode: The driver operates as a co-processor to the host, which is expected to be another chip connected to ours via SPI or UART. This is of course only supported with MCUs that do have a Thread radio, like esp32c2 and esp32c6
  • Host mode: The driver operates as a host, and if the chip does not have a Thread radio it has to be connected via SPI or USB to a chip which runs the Thread stack in RCP mode

Implementations§

Source§

impl<T> ThreadDriver<'_, T>
where T: Mode,

Source

pub fn srp_conf<F, R>(&self, f: F) -> Result<R, EspError>
where F: FnOnce(&SrpConf<'_>, SrpState, bool) -> Result<R, EspError>,

Return the current SRP client configuration and SRP client host state to the provided closure.

Arguments:

  • f: A closure that takes the SRP configuration and SRP host state as arguments.
Source

pub fn srp_is_empty(&self) -> Result<bool, EspError>

Return true if there is neither host, nor any service currently registered with the SRP client.

Source

pub fn srp_set_conf(&self, conf: &SrpConf<'_>) -> Result<(), EspError>

Set the SRP client configuration.

Arguments:

  • conf: The SRP configuration.

Returns:

  • Ok(()) if the configuration was set successfully.
  • Err(OtError) if the configuration could not be set. One reason why the configuration setting might fail is if the configuration had already been set and then not removed with srp_remove_all.
Source

pub fn srp_running(&self) -> Result<bool, EspError>

Return true if the SRP client is running, false otherwise.

Source

pub fn srp_autostart_enabled(&self) -> Result<bool, EspError>

Return true if the SRP client is in auto-start mode, false otherwise.

Source

pub fn srp_autostart(&self) -> Result<(), EspError>

Auto-starts the SRP client.

Source

pub fn srp_start(&self, server_addr: SocketAddrV6) -> Result<(), EspError>

Start the SRP client for the given SRP server address.

Arguments:

  • server_addr: The SRP server address.
Source

pub fn srp_stop(&self) -> Result<(), EspError>

Stop the SRP client.

Source

pub fn srp_server_addr(&self) -> Result<Option<SocketAddrV6>, EspError>

Return the SRP server address, if the SRP client is running and had connected to a server.

Source

pub fn srp_services<F>(&self, f: F) -> Result<(), EspError>
where F: FnMut(Option<(&OutSrpService<'_>, SrpState, SrpServiceSlot)>),

Iterate over the SRP services registered with the SRP client.

Arguments:

  • f: A closure that receives a tuple of the next SRP service, SRP service state, and SRP service ID. If there are no more SRP services, the closure will receive None.
Source

pub fn srp_add_service<'a, SI, TI>( &self, service: &'a SrpService<'a, SI, TI>, ) -> Result<SrpServiceSlot, EspError>
where SI: Iterator<Item = &'a str> + Clone + 'a, TI: Iterator<Item = (&'a str, &'a [u8])> + Clone + 'a,

Add an SRP service to the SRP client.

Arguments:

  • service: The SRP service to add.

Returns:

  • The SRP service slot, if the service was added successfully.
  • Err(OtError) if the service could not be added. One reason why the service addition might fail is if there are no more slots available for services. This can happen even if all services had been removed, as the slots are not freed until the SRP client propagates the removal info to the SRP server.
Source

pub fn srp_remove_service( &self, slot: SrpServiceSlot, immediate: bool, ) -> Result<(), EspError>

Remove an SRP service from the SRP client.

Arguments:

  • slot: The SRP service to remove.
  • immediate: If true, the service will be removed immediately, otherwise, the service will be removed gracefully by propagating the removal info to the SRP server.
Source

pub fn srp_remove_all(&self, immediate: bool) -> Result<(), EspError>

Remove the SRP hostname and all SRP services from the SRP client.

Arguments:

  • immediate: If true, the hostname and services will be removed immediately, otherwise, the hostname and services will be removed gracefully by propagating the removal info to the SRP server.
Source§

impl<'d> ThreadDriver<'d, Host>

Source

pub fn new_spi<S: Spi + 'd>( spi: S, mosi: impl InputPin + 'd, miso: impl OutputPin + 'd, sclk: impl InputPin + OutputPin + 'd, cs: Option<impl InputPin + OutputPin + 'd>, intr: Option<impl InputPin + OutputPin + 'd>, config: &Config, sysloop: EspSystemEventLoop, nvs: EspDefaultNvsPartition, mounted_event_fs: Arc<MountedEventfs>, ) -> Result<Self, EspError>

Create a new Thread Host driver instance utilizing an SPI connection to another MCU running the Thread stack in RCP mode.

Source

pub fn new_uart<U: Uart + 'd>( uart: U, tx: impl OutputPin + 'd, rx: impl InputPin + 'd, config: &Config, sysloop: EspSystemEventLoop, nvs: EspDefaultNvsPartition, mounted_event_fs: Arc<MountedEventfs>, ) -> Result<Self, EspError>

Create a new Thread Host driver instance utilizing a UART connection to another MCU running the Thread stack in RCP mode.

Source

pub fn enable_ipv6(&self, enable: bool) -> Result<(), EspError>

Enable or disable the network interface of the Thread driver

Source

pub fn enable_thread(&self, enable: bool) -> Result<(), EspError>

Enable or disable Thread

When enabling, this should be called after the network interface is enabled

Source

pub fn role(&self) -> Result<Role, EspError>

Retrieve the current role of the device in the Thread network

Source

pub fn init_cli(&mut self) -> Result<(), EspError>

Initialize the Thread command-line interface (CLI) for debugging purposes.

NOTE: This function can only be called once.

Source

pub fn tod(&self, buf: &mut [u8]) -> Result<usize, EspError>

Retrieve the active TOD (Thread Operational Dataset) in the user-supplied buffer

Return the size of the TOD data written to the buffer

The TOD is in Thread TLV format.

Source

pub fn pending_tod(&self, buf: &mut [u8]) -> Result<usize, EspError>

Retrieve the pending TOD (Thread Operational Dataset) in the user-supplied buffer

Return the size of the TOD data written to the buffer

The TOD is in Thread TLV format.

Source

pub fn set_tod(&self, tod: &[u8]) -> Result<(), EspError>

Set the active TOD (Thread Operational Dataset) to the provided data

The TOD data should be in Thread TLV format.

Source

pub fn set_pending_tod(&self, tod: &[u8]) -> Result<(), EspError>

Set the pending TOD (Thread Operational Dataset) to the provided data

The TOD data should be in Thread TLV format.

Source

pub fn set_tod_hexstr(&self, tod: &str) -> Result<(), EspError>

Set the active TOD (Thread Operational Dataset) to the provided data

The TOD data should be in Thread TLV format.

Source

pub fn set_pending_tod_hexstr(&self, tod: &str) -> Result<(), EspError>

Set the pending TOD (Thread Operational Dataset) to the provided data

The TOD data should be in Thread TLV format.

Source

pub fn set_tod_from_cfg(&self) -> Result<(), EspError>

Set the active TOD (Thread Operational Dataset) according to the CONFIG_OPENTHREAD_ TOD-related parameters compiled into the app during build (via sdkconfig*)

Source

pub fn scan<F: FnMut(Option<ActiveScanResult<'_>>) + Send + 'static>( &self, callback: F, ) -> Result<(), EspError>

Perform an active scan for Thread networks

The callback will be called for each found network At the end of the scan, the callback will be called with None

Source

pub fn is_scan_in_progress(&self) -> Result<bool, EspError>

Check if an active scan is in progress

Source

pub fn energy_scan<F: FnMut(Option<EnergyScanResult<'_>>) + Send + 'static>( &self, callback: F, ) -> Result<(), EspError>

Perform an energy scan for Thread networks

The callback will be called for each found network At the end of the scan, the callback will be called with None

Source

pub fn is_energy_scan_in_progress(&self) -> Result<bool, EspError>

Check if an energy scan is in progress

Source

pub fn tx(&self, packet: &[u8]) -> Result<(), EspError>

Send an Ipv6 raw packet over Thread

Source

pub fn set_rx_callback<R>(&self, callback: Option<R>) -> Result<(), EspError>
where R: FnMut(Ipv6Incoming<'_>) + Send + 'static,

Set a callback function for receiving Ipv6 raw packets from Thread

Source

pub fn set_nonstatic_rx_callback<R>( &self, callback: Option<R>, ) -> Result<(), EspError>
where R: FnMut(Ipv6Incoming<'_>) + Send + 'd,

Set a callback function for receiving Ipv6 raw packets from Thread

§Safety

This method - in contrast to method set_rx_callback - allows the user to pass non-static callback/closure. This enables users to borrow

  • in the closure - variables that live on the stack - or more generally - in the same scope where the service is created.

HOWEVER: care should be taken NOT to call core::mem::forget() on the service, as that would immediately lead to an UB (crash). Also note that forgetting the service might happen with Rc and Arc when circular references are introduced: https://github.com/rust-lang/rust/issues/24456

The reason is that the closure is actually sent to a hidden ESP IDF thread. This means that if the service is forgotten, Rust is free to e.g. unwind the stack and the closure now owned by this other thread will end up with references to variables that no longer exist.

The destructor of the service takes care - prior to the service being dropped and e.g. the stack being unwind - to remove the closure from the hidden thread and destroy it. Unfortunately, when the service is forgotten, the un-subscription does not happen and invalid references are left dangling.

This “local borrowing” will only be possible to express in a safe way once/if !Leak types are introduced to Rust (i.e. the impossibility to “forget” a type and thus not call its destructor).

Source§

impl<T> ThreadDriver<'_, T>
where T: Mode,

Source

pub fn start(&mut self) -> Result<(), EspError>

Start the Thread driver

If the driver is already started, an error is returned.

Source

pub fn stop(&mut self) -> Result<(), EspError>

Stop the Thread driver

If the driver is not started, an error is returned.

Source

pub fn is_started(&self) -> Result<bool, EspError>

Check if the Thread driver is started

Trait Implementations§

Source§

impl<T> Drop for ThreadDriver<'_, T>
where T: Mode,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<T> Send for ThreadDriver<'_, T>
where T: Mode,

Source§

impl<T> Sync for ThreadDriver<'_, T>
where T: Mode,

Auto Trait Implementations§

§

impl<'d, T> !Freeze for ThreadDriver<'d, T>

§

impl<'d, T> !RefUnwindSafe for ThreadDriver<'d, T>

§

impl<'d, T> !UnwindSafe for ThreadDriver<'d, T>

§

impl<'d, T> Unpin for ThreadDriver<'d, T>
where T: Unpin,

§

impl<'d, T> UnsafeUnpin for ThreadDriver<'d, T>
where T: UnsafeUnpin,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = !

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.