korri-n2k 0.7.1

no_std-first NMEA 2000 protocol stack for embedded and Linux systems
Documentation
//! Network discovery service: send an ISO Request (PGN 59904) and collect
//! Address Claim responses (PGN 60928) to identify neighbouring nodes.
use crate::error::ClaimError;
use crate::error::ClaimError::SendError;
use crate::protocol::management::iso_name::IsoName;
use crate::protocol::management::network_discovering::engine::AddressRequester;
use crate::protocol::transport::can_frame::CanFrame;
use crate::protocol::transport::traits::{can_bus::CanBus, korri_timer::KorriTimer};
use futures_util::future::{select, Either};
use futures_util::pin_mut;
/// The I/O-free discovery engine, same contract as the claim engine.
pub mod engine;

/// Broadcast a request and gather responses to enumerate devices.
/// `source_address` must be an address the node holds; see
/// [`engine::AddressRequester::new`].
pub async fn request_network_discovery<C: CanBus, T: KorriTimer>(
    can_bus: &mut C,
    timer: &mut T,
    source_address: u8,
    discovered_devices: &mut [(u8, IsoName)],
) -> Result<usize, ClaimError<C::Error>>
where
    C::Error: core::fmt::Debug,
{
    let mut network_discover = AddressRequester::new(source_address, discovered_devices);
    let mut rx: Option<CanFrame> = None;

    loop {
        let now_ms = timer.now_ms();
        match network_discover.poll(now_ms, rx.as_ref()) {
            Ok(request_action) => match request_action {
                engine::RequestAction::Send(frame) => {
                    can_bus.send(&frame).await.map_err(SendError)?;
                    network_discover.tx_sent(timer.now_ms());
                    rx = None;
                }
                engine::RequestAction::Wait(delay) => {
                    let timer = timer.delay_ms(delay);
                    pin_mut!(timer);
                    let recv = can_bus.recv();
                    pin_mut!(recv);
                    match select(timer.as_mut(), recv).await {
                        Either::Left(_) => rx = None,
                        Either::Right((f, _)) => {
                            rx = Some(f.map_err(ClaimError::ReceiveError)?);
                        }
                    };
                }
                engine::RequestAction::Done(device_count) => return Ok(device_count),
            },
            Err(e) => {
                return Err(ClaimError::Fault(e));
            }
        };
    }
}