use core::fmt::Debug;
use core::future::pending;
use embassy_sync::{
blocking_mutex::raw::CriticalSectionRawMutex,
channel::{Channel, Receiver, Sender},
};
use futures_util::{future::select, future::Either, pin_mut};
use crate::error::{ClaimFault, SendPgnError};
use crate::infra::codec::traits::PgnData;
use crate::protocol::management::address_claiming::{engine::ClaimStatus, AddressClaimStrategy};
use crate::protocol::management::address_manager::AddressManager;
use crate::protocol::management::address_supervisor::{
handle_command, AddressHandleError, AddressSupervisorRunError, ClaimedAddress,
SupervisorCommand,
};
use crate::protocol::management::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,
const CMD_CAP: usize,
const FRAME_CAP: usize,
> where
C::Error: Debug,
{
manager: AddressManager<'a, C, T>,
command_channel: Option<&'a Channel<CriticalSectionRawMutex, SupervisorCommand, CMD_CAP>>,
frame_channel: Option<&'a Channel<CriticalSectionRawMutex, CanFrame, FRAME_CAP>>,
claimed: &'a ClaimedAddress,
}
impl<'a, C, T, const CMD_CAP: usize, const FRAME_CAP: usize>
AddressService<'a, C, T, CMD_CAP, FRAME_CAP>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub fn new(
manager: AddressManager<'a, C, T>,
command_channel: Option<&'a Channel<CriticalSectionRawMutex, SupervisorCommand, CMD_CAP>>,
frame_channel: Option<&'a Channel<CriticalSectionRawMutex, CanFrame, FRAME_CAP>>,
claimed: &'a ClaimedAddress,
) -> Self {
Self {
manager,
command_channel,
frame_channel,
claimed,
}
}
pub fn with_name(
can_bus: C,
timer: T,
my_name: IsoName,
strategy: AddressClaimStrategy<'a>,
command_channel: Option<&'a Channel<CriticalSectionRawMutex, SupervisorCommand, CMD_CAP>>,
frame_channel: Option<&'a Channel<CriticalSectionRawMutex, CanFrame, FRAME_CAP>>,
claimed: &'a ClaimedAddress,
) -> Result<Self, ClaimFault> {
let manager = AddressManager::new(can_bus, timer, my_name, strategy)?;
Ok(Self::new(manager, command_channel, frame_channel, claimed))
}
pub fn into_parts(self) -> AddressServiceParts<'a, C, T, CMD_CAP, FRAME_CAP> {
let handle = self.command_channel.map(|channel| AddressHandle {
sender: channel.sender(),
claimed: self.claimed,
});
let frames = self.frame_channel.map(|channel| AddressFrames {
receiver: channel.receiver(),
});
AddressServiceParts {
handle,
frames,
runner: AddressRunner {
manager: self.manager,
command_channel: self.command_channel,
frame_channel: self.frame_channel,
claimed: self.claimed,
},
}
}
}
pub struct AddressServiceParts<'a, C, T, const CMD_CAP: usize, const FRAME_CAP: usize>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub handle: Option<AddressHandle<'a, CMD_CAP>>,
pub frames: Option<AddressFrames<'a, FRAME_CAP>>,
pub runner: AddressRunner<'a, C, T, CMD_CAP, FRAME_CAP>,
}
pub struct AddressRunner<'a, C, T, const CMD_CAP: usize, const FRAME_CAP: usize>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
manager: AddressManager<'a, C, T>,
command_channel: Option<&'a Channel<CriticalSectionRawMutex, SupervisorCommand, CMD_CAP>>,
frame_channel: Option<&'a Channel<CriticalSectionRawMutex, CanFrame, FRAME_CAP>>,
claimed: &'a ClaimedAddress,
}
impl<'a, C, T, const CMD_CAP: usize, const FRAME_CAP: usize>
AddressRunner<'a, C, T, CMD_CAP, FRAME_CAP>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
pub async fn drive(mut self) -> Result<(), AddressSupervisorRunError<C::Error>> {
let frame_channel = self.frame_channel;
let command_channel = self.command_channel;
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() {
if let Some(frame_ch) = frame_channel {
let _ = frame_ch.try_send(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 command_future = async {
match command_channel {
Some(cmd_ch) => cmd_ch.receive().await,
None => pending::<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, _)) => command = Some(received),
}
}
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(())
}
}
}
}
impl<'a, C, T, const CMD_CAP: usize, const FRAME_CAP: usize> Drop
for AddressRunner<'a, C, T, CMD_CAP, FRAME_CAP>
where
C: CanBus,
C::Error: Debug,
T: KorriTimer,
{
fn drop(&mut self) {
self.claimed.set(None);
}
}
pub struct AddressHandle<'a, const CMD_CAP: usize> {
sender: Sender<'a, CriticalSectionRawMutex, SupervisorCommand, CMD_CAP>,
claimed: &'a ClaimedAddress,
}
impl<'a, const CMD_CAP: usize> AddressHandle<'a, CMD_CAP> {
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) {
self.sender.send(command).await;
}
pub async fn send_raw_frame(&self, frame: &CanFrame) {
self.sender
.send(SupervisorCommand::SendRawFrame(*frame))
.await;
}
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;
Ok(())
}
}
pub struct AddressFrames<'a, const FRAME_CAP: usize> {
receiver: Receiver<'a, CriticalSectionRawMutex, CanFrame, FRAME_CAP>,
}
impl<'a, const FRAME_CAP: usize> AddressFrames<'a, FRAME_CAP> {
pub async fn recv(&mut self) -> CanFrame {
self.receiver.receive().await
}
}