use core::fmt::Debug;
extern crate alloc;
use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::hal::can::{Frame, Receiver, Transmitter};
use crate::{Handler, Id, IdError, Message, GLOBAL_ADDRESS};
const CB_TP_BAM: u8 = 0x40;
const PGN_TP_CM: u32 = 0x00ec00;
const PGN_TP_DT: u32 = 0x00eb00;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BusError {
CouldNotOpenBus,
CouldNotSendMessage,
InvalidId(IdError),
}
impl From<IdError> for BusError {
fn from(error: IdError) -> Self {
BusError::InvalidId(error)
}
}
pub type Result<T> = core::result::Result<T, BusError>;
pub struct Bus<T> {
can: T,
handlers: Vec<Box<dyn Handler>>,
address: u8,
}
impl<T, F, E> Bus<T>
where
F: Frame,
E: core::fmt::Debug,
T: Receiver<Frame = F, Error = E> + Transmitter<Frame = F, Error = E>,
{
pub fn new(can: T) -> Self {
Bus {
can: can,
handlers: Vec::new(),
address: 0,
}
}
pub fn send(&mut self, message: &Message) -> Result<()> {
let id = message.id();
let data = message.data();
let length = data.len();
if length <= 8 {
let frame = &<T as Transmitter>::Frame::new_extended(id.value(), data).unwrap();
self.transmit(frame)?;
Ok(())
} else {
let packets = (length / 7) + 1;
let pgn = id.pgn();
let priority = id.priority();
let tp_cm_id = Id::new(priority, PGN_TP_CM, self.address, GLOBAL_ADDRESS)?;
let tp_cm_id_data = [
CB_TP_BAM,
(length & 0xff) as u8,
((length >> 8) & 0xff) as u8,
packets as u8,
0xff,
(pgn & 0xff) as u8,
((pgn >> 8) & 0xff) as u8,
((pgn >> 16) & 0xff) as u8,
];
let frame = &<T as Transmitter>::Frame::new_extended(tp_cm_id.value(), &tp_cm_id_data).unwrap();
self.transmit(frame)?;
let tp_dt_id = Id::new(priority, PGN_TP_DT, self.address, GLOBAL_ADDRESS)?;
let mut count = 1;
let mut index = 0;
let mut remaining = length;
let mut len;
while remaining > 0 {
len = remaining;
if len > 7 {
len = 7;
}
remaining -= len;
let mut tp_dt_data = [255; 8];
tp_dt_data[0] = count;
count += 1;
for i in 0..len {
tp_dt_data[i + 1] = data[index];
index += 1;
}
let frame = &<T as Transmitter>::Frame::new_extended(tp_dt_id.value(), &tp_dt_data).unwrap();
self.transmit(frame)?;
}
Ok(())
}
}
pub fn register<H: Handler + 'static>(&mut self, handler: H) {
self.handlers.push(Box::new(handler));
}
fn transmit(&mut self, frame: &<T as Transmitter>::Frame) -> Result<()> {
let result = self.can.transmit(frame);
match result {
Ok(None) => Ok(()),
Ok(pending_frame) => {
if let Some(f) = pending_frame {
self.transmit(&f)
} else {
Ok(())
}
}
Err(nb::Error::WouldBlock) => self.transmit(frame),
_ => return Err(BusError::CouldNotSendMessage),
}
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::boxed::Box;
use alloc::vec::Vec;
use crate::hal::can::{Frame, Receiver, Transmitter};
use crate::{Bus, Id, Message, Priority, GLOBAL_ADDRESS};
use core::convert::TryFrom;
use core::fmt::Debug;
#[derive(Clone, Debug)]
pub struct CanFrame {
id: Id,
dlc: usize,
data: [u8; 8],
}
impl CanFrame {
pub fn new(id: Id, data: &[u8]) -> Self {
let mut frame = Self {
id,
dlc: data.len(),
data: [0; 8],
};
frame.data[0..data.len()].copy_from_slice(data);
frame
}
}
impl crate::hal::can::Frame for CanFrame {
fn new_standard(_id: u32, _data: &[u8]) -> Result<Self, ()> {
panic!("NMEA 2000 only supports extended frames")
}
fn new_extended(id: u32, data: &[u8]) -> Result<Self, ()> {
Ok(Self::new(Id::try_from(id).unwrap(), data))
}
fn with_rtr(&mut self, _dlc: usize) -> &mut Self {
panic!("NMEA 2000 only supports extended frames")
}
fn is_extended(&self) -> bool {
true
}
fn is_standard(&self) -> bool {
false
}
fn is_remote_frame(&self) -> bool {
false
}
fn is_data_frame(&self) -> bool {
!self.is_remote_frame()
}
fn id(&self) -> u32 {
self.id.value()
}
fn dlc(&self) -> usize {
self.dlc
}
fn data(&self) -> &[u8] {
if self.is_data_frame() {
&self.data[0..self.dlc]
} else {
&[]
}
}
}
struct MockCan {
pub frames: Vec<CanFrame>,
}
impl MockCan {
pub fn new() -> Self {
MockCan { frames: Vec::new() }
}
}
impl Receiver for MockCan {
type Frame = CanFrame;
type Error = ();
fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
panic!();
}
}
impl Transmitter for MockCan {
type Frame = CanFrame;
type Error = ();
fn transmit(&mut self, frame: &CanFrame) -> nb::Result<Option<Self::Frame>, Self::Error> {
self.frames.push(frame.clone());
Ok(Option::None)
}
}
#[test]
fn bus_send() {
struct TestCase {
message: Message,
}
let test_cases = [
TestCase {
message: Message::new(
Id::new(Priority::Priority0, 12345, 123, GLOBAL_ADDRESS).unwrap(),
Box::new([1, 2, 3, 4, 5, 6, 7]),
)
.unwrap(),
},
TestCase {
message: Message::new(
Id::new(Priority::Priority0, 12345, 123, GLOBAL_ADDRESS).unwrap(),
Box::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]),
)
.unwrap(),
},
];
for i in &test_cases {
let can = MockCan::new();
let mut bus = Bus::new(can);
bus.send(&i.message).unwrap();
let data = i.message.data();
if data.len() <= 8 {
} else {
for b in 0..data.len() {
let frame = (b / 7) + 1;
let index = b - ((frame - 1) * 7) + 1;
assert_eq!(bus.can.frames[frame].data()[index], data[b])
}
}
}
}
}