esp_idf_svc::netif

Struct EspNetifDriver

Source
pub struct EspNetifDriver<'d, T>
where T: BorrowMut<EspNetif>,
{ /* private fields */ }

Implementations§

Source§

impl<T> EspNetifDriver<'static, T>
where T: BorrowMut<EspNetif>,

Source

pub fn new<P, F>(netif: T, post_attach_cfg: P, tx: F) -> Result<Self, EspError>
where P: FnMut(&mut EspNetif) -> Result<(), EspError> + Send + 'static, F: FnMut(&[u8]) -> Result<(), EspError> + Send + 'static,

Create a new netif driver around the provided EspNetif instance.

The driver transport is represented by:

  • The tx callback that the driver would call when it wants to ingest a packet into the underlying transport
  • EsNetifDriver::rx, which should be called by the transport when a new packet has arrived that has to be ingested in the driver

The transport can be anything, but with - say - PPP netif - it would typically be UART, and the tx callback implementation is simply expected to write the PPP packet into UART.

Arguments:

  • netif is the EspNetif instance that the driver will manage
  • got_ip_event_id and lost_ip_event_id are the event IDs that the driver will listen to so that it can connect/disconnect the netif upon receival / loss of IP
  • post_attach_cfg is a netif-specific configuration that will be executed after the netif is attached. For example, for a PPP netif, the post attach configuration might want to invoke EspNetif::set_ppp_conf.
  • tx is the callback that the driver will call when it wants to ingest a packet into the underlying transport

Example:

let (uart_rx, uart_tx) = uart.into_split();

let mut driver = EspNetifDriver::new(
    EspNetif::new(NetifStack::Ppp)?,
    |netif| netif.set_ppp_conf(&PppConfiguration {
        phase_events_enabled: false,
        ..Default::default()
    }),
    move |data| uart_tx.write_all(data),
)?;

loop {
    let mut buffer = [0; 128];
    let len = uart_rx.read(&mut buffer)?;
    driver.rx(&buffer[..len])?;
}
Source§

impl<'d, T> EspNetifDriver<'d, T>
where T: BorrowMut<EspNetif>,

Source

pub fn new_nonstatic<P, F>( netif: T, post_attach_cfg: P, tx: F, ) -> Result<Self, EspError>
where P: FnMut(&mut EspNetif) -> Result<(), EspError> + Send + 'd, F: FnMut(&[u8]) -> Result<(), EspError> + Send + 'd,

Create a new netif driver around the provided EspNetif instance.

The driver transport is represented by:

  • The tx callback that the driver would call when it wants to ingest a packet into the underlying transport
  • EsNetifDriver::rx, which should be called by the transport when a new packet has arrived that has to be ingested in the driver

The transport can be anything, but with - say - PPP netif - it would typically be UART, and the tx callback implementation is simply expected to write the PPP packet into UART.

Arguments:

  • netif is the EspNetif instance that the driver will manage
  • got_ip_event_id and lost_ip_event_id are the event IDs that the driver will listen to so that it can connect/disconnect the netif upon receival / loss of IP
  • post_attach_cfg is a netif-specific configuration that will be executed after the netif is attached. For example, for a PPP netif, the post attach configuration might want to invoke EspNetif::set_ppp_conf.
  • tx is the callback that the driver will call when it wants to ingest a packet into the underlying transport

Example:

let (uart_rx, uart_tx) = uart.into_split();

let mut driver = EspNetifDriver::new(
    EspNetif::new(NetifStack::Ppp)?,
    |netif| netif.set_ppp_conf(&PppConfiguration {
        phase_events_enabled: false,
        ..Default::default()
    }),
    move |data| uart_tx.write_all(data),
)?;

loop {
    let mut buffer = [0; 128];
    let len = uart_rx.read(&mut buffer)?;
    driver.rx(&buffer[..len])?;
}
§Safety

This method - in contrast to method new - allows the user to pass non-static callbacks/closures. 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

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

Ingest a packet into the driver

The packet can arrive from anywhere, but with say - a PPP netif - it would be a PPP packet arriving typically from UART, by reading from it.

Source

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

Start the driver

Source

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

Stop the driver

Source

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

Check if the driver is started

Source

pub fn netif(&self) -> &EspNetif

Get a reference to the underlying EspNetif instance

Source

pub fn netif_mut(&mut self) -> &mut EspNetif

Get a mutable reference to the underlying EspNetif instance

Trait Implementations§

Source§

impl<T> Drop for EspNetifDriver<'_, T>
where T: BorrowMut<EspNetif>,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<'d, T> Freeze for EspNetifDriver<'d, T>

§

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

§

impl<'d, T> !Send for EspNetifDriver<'d, T>

§

impl<'d, T> !Sync for EspNetifDriver<'d, T>

§

impl<'d, T> Unpin for EspNetifDriver<'d, T>

§

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

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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.