use crate::error::CanIdBuildError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CanId(pub u32);
impl CanId {
pub fn builder(pgn: u32, source_address: u8) -> CanIdBuilder {
CanIdBuilder::new(pgn, source_address)
}
pub fn priority(&self) -> u8 {
((self.0 >> 26) & 0x07) as u8
}
pub fn pgn(&self) -> u32 {
let ps = ((self.0 >> 8) & 0xFF) as u8;
let pf = ((self.0 >> 16) & 0xFF) as u8;
let dp = (self.0 >> 24) & 0x01;
let r = (self.0 >> 25) & 0x01;
if (pf >> 4) & 0xF == 0xF {
(r << 17) | (dp << 16) | ((pf as u32) << 8) | (ps as u32)
} else {
(r << 17) | (dp << 16) | ((pf as u32) << 8)
}
}
pub fn destination(&self) -> Option<u8> {
let pf = ((self.0 >> 16) & 0xFF) as u8;
if (pf >> 4) & 0xF == 0xF {
None
} else {
let ps = ((self.0 >> 8) & 0xFF) as u8;
Some(ps)
}
}
pub fn source_address(&self) -> u8 {
(self.0 & 0xFF) as u8
}
}
#[derive(Debug)]
pub struct CanIdBuilder {
pub priority: u8,
pub pgn: u32,
pub source_address: u8,
pub destination: Option<u8>,
}
impl CanIdBuilder {
pub fn new(pgn: u32, source_address: u8) -> Self {
Self {
priority: 6, pgn,
source_address,
destination: None,
}
}
pub fn with_priority(mut self, priority: u8) -> Self {
self.priority = priority & 0x07;
self
}
pub fn to_destination(mut self, destination_address: u8) -> Self {
self.destination = Some(destination_address);
self
}
pub fn priority(mut self, priority: u8) -> Self {
self.priority = priority & 0x07;
self
}
pub fn destination(mut self, dest: u8) -> Self {
self.destination = Some(dest);
self
}
pub fn build(self) -> Result<CanId, CanIdBuildError> {
let r_from_pgn = (self.pgn >> 17) & 0x01;
let dp_from_pgn = (self.pgn >> 16) & 0x01;
let pf_from_pgn = ((self.pgn >> 8) & 0xFF) as u8;
let ps_from_pgn = (self.pgn & 0xFF) as u8;
match self.destination {
None => {
if pf_from_pgn < 240 {
return Err(CanIdBuildError::InvalidForBroadcast);
}
let id = ((self.priority as u32) << 26)
| (r_from_pgn << 25)
| (dp_from_pgn << 24)
| ((pf_from_pgn as u32) << 16)
| ((ps_from_pgn as u32) << 8)
| (self.source_address as u32);
Ok(CanId(id))
}
Some(da) => {
if pf_from_pgn >= 240 {
return Err(CanIdBuildError::InvalidForFocusedMessage { pgn: pf_from_pgn });
}
if ps_from_pgn != 0 {
return Err(CanIdBuildError::PsFocusMessageMustBeNull);
}
let id = ((self.priority as u32) << 26)
| (r_from_pgn << 25)
| (dp_from_pgn << 24)
| ((pf_from_pgn as u32) << 16)
| ((da as u32) << 8)
| (self.source_address as u32);
Ok(CanId(id))
}
}
}
}
#[cfg(test)]
#[path = "tests.rs"]
mod tests;