use core::fmt::Debug;
use portable_atomic::{AtomicU16, Ordering};
use crate::{
error::SendPgnError,
protocol::{
management::{address_claiming::engine::ClaimStatus, address_manager::AddressManager},
transport::{
can_frame::CanFrame,
fast_packet::MAX_FAST_PACKET_PAYLOAD,
traits::{can_bus::CanBus, korri_timer::KorriTimer},
},
},
};
#[cfg(all(feature = "embassy", not(feature = "tokio")))]
pub mod runner_embassy;
#[cfg(feature = "tokio")]
pub mod runner_tokio;
#[cfg(all(feature = "embassy", not(feature = "tokio")))]
pub use runner_embassy::{AddressFrames, AddressHandle, AddressRunner, AddressService};
#[cfg(feature = "tokio")]
pub use runner_tokio::{AddressFrames, AddressHandle, AddressRunner, AddressService};
#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
pub enum SupervisorCommand {
SendRawFrame(CanFrame),
SendPayload {
pgn: u32,
priority: u8,
destination: Option<u8>,
len: usize,
payload: [u8; MAX_FAST_PACKET_PAYLOAD],
},
}
#[derive(Debug)]
pub enum AddressHandleError {
Serialization,
RunnerGone,
}
pub struct ClaimedAddress(AtomicU16);
const STATUS_CLAIMING: u16 = 0x0100;
const STATUS_CANNOT_CLAIM: u16 = 0x0200;
const STATUS_UNAVAILABLE: u16 = u16::MAX;
impl Default for ClaimedAddress {
fn default() -> Self {
Self::new()
}
}
impl ClaimedAddress {
pub const fn new() -> Self {
Self(AtomicU16::new(STATUS_UNAVAILABLE))
}
pub fn get(&self) -> Option<u8> {
self.status().and_then(|status| status.claimed_address())
}
pub fn status(&self) -> Option<ClaimStatus> {
match self.0.load(Ordering::Relaxed) {
STATUS_UNAVAILABLE => None,
STATUS_CANNOT_CLAIM => Some(ClaimStatus::CannotClaim),
encoded if encoded & STATUS_CLAIMING != 0 => Some(ClaimStatus::Claiming(encoded as u8)),
address => Some(ClaimStatus::Claimed(address as u8)),
}
}
pub(crate) fn set(&self, status: Option<ClaimStatus>) {
let encoded = match status {
Some(ClaimStatus::Claiming(address)) => STATUS_CLAIMING | u16::from(address),
Some(ClaimStatus::Claimed(address)) => u16::from(address),
Some(ClaimStatus::CannotClaim) => STATUS_CANNOT_CLAIM,
None => STATUS_UNAVAILABLE,
};
self.0.store(encoded, Ordering::Relaxed);
}
}
#[derive(Debug)]
pub enum AddressSupervisorRunError<E: Debug> {
Receive(E),
Send(E),
}
async fn handle_command<'a, C: CanBus, T: KorriTimer>(
manager: &mut AddressManager<'a, C, T>,
command: SupervisorCommand,
) -> Result<(), SendPgnError<C::Error>>
where
C::Error: Debug,
{
match command {
SupervisorCommand::SendRawFrame(frame) => match manager.claimed_address() {
Some(claimed) if frame.id.source_address() == claimed => {
manager.emit_claim(&frame).await.map_err(SendPgnError::Send)
}
_ => Err(SendPgnError::NotClaimed),
},
SupervisorCommand::SendPayload {
pgn,
priority,
destination,
len,
payload,
} => {
let payload = payload.get(..len).ok_or(SendPgnError::Serialization)?;
manager
.send_payload(pgn, priority, destination, payload)
.await
}
}
}