use core::future::pending;
use futures_util::{
future::{select, Either},
pin_mut,
};
use crate::{
error::{
ClaimFault::{self},
SendPgnError,
},
infra::codec::traits::PgnData,
protocol::{
management::{
address_claiming::{engine::AddressClaimEngine, AddressClaimStrategy},
iso_name::IsoName,
},
transport::{
can_frame::CanFrame,
fast_packet::builder::FastPacketBuilder,
traits::{can_bus::CanBus, korri_timer::KorriTimer, pgn_sender::PgnSender},
FAST_PACKET_INTER_FRAME_DELAY_MS,
},
},
};
#[cfg(any(feature = "embassy", feature = "tokio"))]
use crate::protocol::management::address_claiming::engine::ClaimOutput;
pub struct AddressManager<'a, C: CanBus, T: KorriTimer> {
can_bus: C,
timer: T,
engine: AddressClaimEngine<'a>,
}
impl<'a, C: CanBus, T: KorriTimer> AddressManager<'a, C, T>
where
C::Error: core::fmt::Debug,
{
pub fn new(
can_bus: C,
timer: T,
name: IsoName,
strategy: AddressClaimStrategy<'a>,
) -> Result<Self, ClaimFault> {
let engine = AddressClaimEngine::new(name, strategy)?;
Ok(Self {
can_bus,
timer,
engine,
})
}
pub fn claimed_address(&self) -> Option<u8> {
self.engine.claimed_address()
}
#[cfg(any(feature = "embassy", feature = "tokio"))]
pub(crate) fn poll(&mut self, rx: Option<&CanFrame>) -> ClaimOutput {
self.engine.poll(self.timer.now_ms(), rx)
}
#[cfg(any(feature = "embassy", feature = "tokio"))]
pub(crate) fn tx_sent(&mut self) -> ClaimOutput {
self.engine.tx_sent(self.timer.now_ms())
}
#[cfg(any(feature = "embassy", feature = "tokio"))]
pub(crate) async fn emit_claim(&mut self, frame: &CanFrame) -> Result<(), C::Error> {
self.can_bus.send(frame).await
}
pub async fn recv_until(
&mut self,
wake_at_ms: Option<u64>,
) -> Result<Option<CanFrame>, C::Error> {
let Self { can_bus, timer, .. } = self;
let remaining_ms =
wake_at_ms.map(|at| at.saturating_sub(timer.now_ms()).min(u32::MAX as u64) as u32);
let recv = can_bus.recv();
pin_mut!(recv);
let deadline = async {
match remaining_ms {
Some(delay_ms) => timer.delay_ms(delay_ms).await,
None => pending::<()>().await,
}
};
pin_mut!(deadline);
match select(recv, deadline).await {
Either::Left((frame, _)) => frame.map(Some),
Either::Right((_, _)) => Ok(None),
}
}
pub async fn send_pgn<P: PgnData>(
&mut self,
pgn_data: &P,
pgn: u32,
destination: Option<u8>,
) -> Result<(), SendPgnError<C::Error>> {
let Some(source_addr) = self.claimed_address() else {
return Err(SendPgnError::NotClaimed);
};
self.can_bus
.send_pgn(pgn_data, pgn, source_addr, destination, &mut self.timer)
.await
}
pub async fn send_payload(
&mut self,
pgn: u32,
priority: u8,
destination: Option<u8>,
payload: &[u8],
) -> Result<(), SendPgnError<C::Error>> {
let Some(source_addr) = self.claimed_address() else {
return Err(SendPgnError::NotClaimed);
};
let builder =
FastPacketBuilder::new(pgn, source_addr, destination, payload).with_priority(priority);
let mut is_first = true;
for frame in builder.build() {
let frame = frame.map_err(SendPgnError::Build)?;
if !is_first && payload.len() > 8 {
self.timer.delay_ms(FAST_PACKET_INTER_FRAME_DELAY_MS).await;
}
self.can_bus
.send(&frame)
.await
.map_err(SendPgnError::Send)?;
is_first = false;
}
Ok(())
}
}