use core::fmt::Debug;
use core::future::pending;
use futures_util::{future::select, future::Either, pin_mut};
use std::sync::Arc;
use tokio::sync::mpsc::error::TrySendError;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use crate::error::{ClaimFault, SendPgnError};
use crate::infra::codec::traits::PgnData;
use crate::protocol::management::address_claiming::engine::ClaimStatus;
use crate::protocol::management::address_supervisor::{
handle_command, AddressHandleError, AddressSupervisorRunError, ClaimedAddress,
SupervisorCommand,
};
use crate::protocol::management::{address_manager::AddressManager, iso_name::IsoName};
use crate::protocol::transport::can_frame::CanFrame;
use crate::protocol::transport::fast_packet::MAX_FAST_PACKET_PAYLOAD;
use crate::protocol::transport::traits::can_bus::CanBus;
use crate::protocol::transport::traits::korri_timer::KorriTimer;
pub struct AddressService<'a, C: CanBus, T: KorriTimer>
where
C::Error: Debug,
{
manager: AddressManager<'a, C, T>,
command_rx: Option<Receiver<SupervisorCommand>>,
frame_tx: Option<Sender<CanFrame>>,
handle: Option<AddressHandle>,
frames: Option<AddressFrames>,
claimed: Arc<ClaimedAddress>,
}
impl<'a, C, T> AddressService<'a, C, T>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub fn new(manager: AddressManager<'a, C, T>, cmd_cap: usize, frame_cap: usize) -> Self {
let (cmd_tx, cmd_rx) = if cmd_cap > 0 {
let (tx, rx) = channel(cmd_cap);
(Some(tx), Some(rx))
} else {
(None, None)
};
let (frame_tx, frame_rx) = if frame_cap > 0 {
let (tx, rx) = channel(frame_cap);
(Some(tx), Some(rx))
} else {
(None, None)
};
let claimed = Arc::new(ClaimedAddress::new());
Self {
manager,
command_rx: cmd_rx,
frame_tx,
handle: cmd_tx.map(|tx| AddressHandle {
sender: tx,
claimed: Arc::clone(&claimed),
}),
frames: frame_rx.map(|rx| AddressFrames { receiver: rx }),
claimed,
}
}
pub fn with_name(
can_bus: C,
timer: T,
my_name: IsoName,
strategy: crate::protocol::management::address_claiming::AddressClaimStrategy<'a>,
cmd_cap: usize,
frame_cap: usize,
) -> Result<Self, ClaimFault> {
let manager = AddressManager::new(can_bus, timer, my_name, strategy)?;
Ok(Self::new(manager, cmd_cap, frame_cap))
}
pub fn into_parts(self) -> AddressServiceParts<'a, C, T> {
AddressServiceParts {
handle: self.handle,
frames: self.frames,
runner: AddressRunner {
manager: self.manager,
command_rx: self.command_rx,
frame_tx: self.frame_tx,
claimed: self.claimed,
},
}
}
}
pub struct AddressServiceParts<'a, C, T>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub handle: Option<AddressHandle>,
pub frames: Option<AddressFrames>,
pub runner: AddressRunner<'a, C, T>,
}
pub struct AddressRunner<'a, C, T>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
manager: AddressManager<'a, C, T>,
command_rx: Option<Receiver<SupervisorCommand>>,
frame_tx: Option<Sender<CanFrame>>,
claimed: Arc<ClaimedAddress>,
}
impl<'a, C, T> AddressRunner<'a, C, T>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub async fn drive(mut self) -> Result<(), AddressSupervisorRunError<C::Error>> {
let mut rx: Option<CanFrame> = None;
loop {
let mut output = self.manager.poll(rx.as_ref());
self.claimed.set(Some(output.status));
if let Some(frame) = rx.take() {
self.forward_frame(frame);
}
if let Some(frame) = output.tx {
self.manager
.emit_claim(&frame)
.await
.map_err(AddressSupervisorRunError::Send)?;
output = self.manager.tx_sent();
}
let mut command = None;
let mut channel_closed = false;
{
let command_rx = &mut self.command_rx;
let command_future = async {
match command_rx {
Some(rx) => rx.recv().await,
None => pending::<Option<SupervisorCommand>>().await,
}
};
pin_mut!(command_future);
let recv = self.manager.recv_until(output.wake_at_ms);
pin_mut!(recv);
match select(recv, command_future).await {
Either::Left((frame, _)) => {
rx = frame.map_err(AddressSupervisorRunError::Receive)?;
}
Either::Right((received, _)) => match received {
Some(cmd) => command = Some(cmd),
None => channel_closed = true,
},
}
}
if channel_closed {
self.command_rx = None;
}
if let Some(cmd) = command {
self.run_command(cmd).await?;
}
}
}
async fn run_command(
&mut self,
command: SupervisorCommand,
) -> Result<(), AddressSupervisorRunError<C::Error>> {
match handle_command(&mut self.manager, command).await {
Ok(()) => Ok(()),
Err(SendPgnError::Send(err)) => Err(AddressSupervisorRunError::Send(err)),
Err(_rejected) => {
#[cfg(feature = "defmt")]
defmt::warn!("supervisor command rejected");
Ok(())
}
}
}
fn forward_frame(&mut self, frame: CanFrame) {
let Some(tx) = self.frame_tx.as_ref() else {
return;
};
match tx.try_send(frame) {
Ok(()) => {}
Err(TrySendError::Full(_)) => {}
Err(TrySendError::Closed(_)) => self.frame_tx = None,
}
}
}
impl<'a, C, T> Drop for AddressRunner<'a, C, T>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
fn drop(&mut self) {
self.claimed.set(None);
}
}
pub struct AddressHandle {
sender: Sender<SupervisorCommand>,
claimed: Arc<ClaimedAddress>,
}
impl AddressHandle {
pub fn claim_status(&self) -> Option<ClaimStatus> {
self.claimed.status()
}
pub fn claimed_address(&self) -> Option<u8> {
self.claimed.get()
}
pub async fn send_command(&self, command: SupervisorCommand) -> Result<(), AddressHandleError> {
self.sender
.send(command)
.await
.map_err(|_| AddressHandleError::RunnerGone)
}
pub async fn send_raw_frame(&self, frame: &CanFrame) -> Result<(), AddressHandleError> {
let command = SupervisorCommand::SendRawFrame(*frame);
self.sender
.send(command)
.await
.map_err(|_| AddressHandleError::RunnerGone)
}
pub async fn send_pgn<P: PgnData>(
&self,
pgn_data: &P,
pgn: u32,
priority: u8,
destination: Option<u8>,
) -> Result<(), AddressHandleError> {
let mut payload = [0u8; MAX_FAST_PACKET_PAYLOAD];
let len = pgn_data
.to_payload(&mut payload)
.map_err(|_| AddressHandleError::Serialization)?;
let command = SupervisorCommand::SendPayload {
pgn,
priority,
destination,
len,
payload,
};
self.sender
.send(command)
.await
.map_err(|_| AddressHandleError::RunnerGone)
}
}
pub struct AddressFrames {
receiver: Receiver<CanFrame>,
}
impl AddressFrames {
pub async fn recv(&mut self) -> Option<CanFrame> {
self.receiver.recv().await
}
}