From 5b0b5af92e426f59a1a0f9e021ad0d6b6a4e0f01 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 25 Apr 2024 14:42:14 +0200 Subject: [PATCH 01/48] #2 added sequence in unit tests --- src/can.rs | 15 ++-- src/lib.rs | 2 +- src/tests/can.rs | 181 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 142 insertions(+), 56 deletions(-) diff --git a/src/can.rs b/src/can.rs index 0bb905b..8118700 100644 --- a/src/can.rs +++ b/src/can.rs @@ -46,6 +46,7 @@ pub enum ConfigError { RequestModeTimeout, } +/// Possible errors transmitting CAN message #[derive(Debug, PartialEq)] pub enum Error { /// Configuration error @@ -180,12 +181,14 @@ impl, CS: OutputPin, CLK: Clock> Controller { pub fn transmit(&mut self, message: TxMessage) -> Result<(), Error> { // make sure there is space for new message in TX FIFO // read byte 0 of TX FIFO status register - let mut txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; + let status_reg_addr = Self::fifo_status_register(FIFO_TX_INDEX); + + let mut txfifo_status_byte0 = self.read_register(status_reg_addr)?; let mut txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); // block until there is room available for new message in TX FIFO while !txfifo_status_reg0.tfnrfnif() { - txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; + txfifo_status_byte0 = self.read_register(status_reg_addr)?; txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); } @@ -198,19 +201,21 @@ impl, CS: OutputPin, CLK: Clock> Controller { // get address in which to write next message in TX FIFO (should not be read in configuration mode) let address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; + // get address of TX FIFO control register byte 1 + let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; // load message in TX FIFO self.write_fifo(address as u16, message)?; // Request transmission (set txreq) and set uinc in TX FIFO control register byte 1 - self.write_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1, 0x03)?; + self.write_register(fifo_control_reg1, 0x03)?; // read TX FIFO control register byte 1 - let mut txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; + let mut txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; let mut txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); // block till txreq is cleared confirming that all messages in TX FIFO are transmitted while txfifo_control_reg.txreq() { - txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; + txfifo_control_byte1 = self.read_register(fifo_control_reg1)?; txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index adfcbb2..e03ffdd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,6 @@ pub mod status; pub mod message; #[cfg(test)] pub(crate) mod mocks; -pub mod registers; +mod registers; #[cfg(test)] mod tests; diff --git a/src/tests/can.rs b/src/tests/can.rs index c69e5a1..72dce63 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -8,6 +8,7 @@ use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; use embedded_can::{ExtendedId, Id}; +use mockall::Sequence; #[test] fn test_configure_correct() { @@ -150,6 +151,7 @@ const EXTENDED_ID: u32 = 0x14C92A2B; #[test] fn test_transmit() { let mut mocks = Mocks::default(); + let mut seq = Sequence::new(); let message_payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -157,43 +159,91 @@ fn test_transmit() { let tx_message = TxMessage::new(Id::Extended(identifier), &message_payload, false, false).unwrap(); let tx_message_copy = tx_message.clone(); - // mock fifo status register read byte 0 - mocks.mock_register_read::<0b0000_0001>([0x30, 0x6C]); + // mock fifo status register read byte 0 (1st attempt) -> tx fifo full + mocks.mock_register_read::<0b0000_0000>([0x30, 0x6C], &mut seq); + + // mock fifo status register read byte 0 (2nd attempt) -> tx fifo not full + mocks.mock_register_read::<0b0000_0001>([0x30, 0x6C], &mut seq); // mock read operation status - mocks.mock_register_read::<0b1100_0000>([0x30, 0x2]); + mocks.mock_register_read::<0b1100_0000>([0x30, 0x2], &mut seq); // mock fifo user address register read (reading 32 bits) --> address = 0x4A2 - mocks.mock_read32::<0x00_00_04_A2>([0x30, 0x70]); + mocks.mock_read32::<0x00_00_04_A2>([0x30, 0x70], &mut seq); // mock writing message in RAM specified by fifo user address (0x4A2) // transfer cmd+tx_header - mocks.bus.expect_transfer().times(1).returning(move |data| { - let mut cmd_and_header_buffer = [0u8; 10]; - cmd_and_header_buffer[0] = 0x24; - cmd_and_header_buffer[1] = 0xA2; - cmd_and_header_buffer[2..].copy_from_slice(&tx_message.header.into_bytes()); - assert_eq!(cmd_and_header_buffer, data); - Ok(&[0u8; 10]) - }); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + let mut cmd_and_header_buffer = [0u8; 10]; + cmd_and_header_buffer[0] = 0x24; + cmd_and_header_buffer[1] = 0xA2; + cmd_and_header_buffer[2..].copy_from_slice(&tx_message.header.into_bytes()); + + assert_eq!(cmd_and_header_buffer, data); + Ok(&[0u8; 10]) + }) + .in_sequence(&mut seq); // transfer payload - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!(message_payload, data); - Ok(&[0u8; 8]) - }); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!(message_payload, data); + Ok(&[0u8; 8]) + }) + .in_sequence(&mut seq); + + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // mock setting of bits txreq and uinc - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x20, 0x69, 0x03], data); - Ok(&[0u8; 3]) - }); - mocks.pin_cs.expect_set_low().times(2).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(2).return_const(Ok(())); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x20, 0x69, 0x03], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // mock reading of fifo control register - mocks.mock_register_read::<0x00>([0x30, 0x69]); + // 1st attempt -> txreq still set ->not all messages inside tx fifo have been transmitted + mocks.mock_register_read::<0x02>([0x30, 0x69], &mut seq); + // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted + mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); let result = mocks.into_controller().transmit(tx_message_copy); assert!(result.is_ok()); @@ -202,12 +252,27 @@ fn test_transmit() { #[test] fn test_reset_command() { let mut mocks = Mocks::default(); + + let mut seq = Sequence::new(); + mocks.bus.expect_transfer().times(1).returning(move |data| { assert_eq!([0x00, 0x00, 0x00], data); Ok(&[0u8; 3]) }); - mocks.pin_cs.expect_set_high().times(1).return_const(Ok(())); - mocks.pin_cs.expect_set_low().times(1).return_const(Ok(())); + + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); let result = mocks.into_controller().reset(); assert!(result.is_ok()); @@ -292,7 +357,9 @@ fn test_configure_transfer_error() { #[test] fn test_read_operation_status_correct() { let mut mocks = Mocks::default(); - mocks.mock_register_read::<0b0001_0100>([0x30, 0x2]); + let mut seq = Sequence::new(); + + mocks.mock_register_read::<0b0001_0100>([0x30, 0x2], &mut seq); let status = mocks.into_controller().read_operation_status().unwrap(); @@ -329,7 +396,9 @@ fn test_read_operation_status_transfer_error() { #[test] fn test_read_oscillator_status_correct() { let mut mocks = Mocks::default(); - mocks.mock_register_read::<0b0001_0100>([0x3E, 0x1]); + let mut seq = Sequence::new(); + + mocks.mock_register_read::<0b0001_0100>([0x3E, 0x1], &mut seq); let status = mocks.into_controller().read_oscillator_status().unwrap(); @@ -363,7 +432,9 @@ fn test_read_oscillator_transfer_error() { #[test] fn test_read_clock_configuration_correct() { let mut mocks = Mocks::default(); - mocks.mock_register_read::<0b0110_0000>([0x3E, 0x0]); + let mut seq = Sequence::new(); + + mocks.mock_register_read::<0b0110_0000>([0x3E, 0x0], &mut seq); let status = mocks.into_controller().read_clock_configuration().unwrap(); @@ -419,33 +490,43 @@ impl Mocks { } /// Mocks the reading of a single register byte - pub fn mock_register_read(&mut self, expected_command: [u8; 2]) { + pub fn mock_register_read(&mut self, expected_command: [u8; 2], seq: &mut Sequence) { let expected_buffer = [expected_command[0], expected_command[1], 0x0]; - self.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!(expected_buffer, data); - Ok(&[0x0, 0x0, REG]) - }); + self.pin_cs.expect_set_low().times(1).return_const(Ok(())).in_sequence(seq); - self.pin_cs.expect_set_low().times(1).return_const(Ok(())); - self.pin_cs.expect_set_high().times(1).return_const(Ok(())); + self.bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!(expected_buffer, data); + Ok(&[0x0, 0x0, REG]) + }) + .in_sequence(seq); + + self.pin_cs.expect_set_high().times(1).return_const(Ok(())).in_sequence(seq); } - pub fn mock_read32(&mut self, expected_command: [u8; 2]) { + pub fn mock_read32(&mut self, expected_command: [u8; 2], seq: &mut Sequence) { let expected_buffer = [expected_command[0], expected_command[1], 0u8, 0u8, 0u8, 0u8]; - self.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!(expected_buffer, data); - Ok(&[ - 0x0, - 0x0, - REG as u8, - (REG >> 8) as u8, - (REG >> 16) as u8, - (REG >> 24) as u8, - ]) - }); - - self.pin_cs.expect_set_low().times(1).return_const(Ok(())); - self.pin_cs.expect_set_high().times(1).return_const(Ok(())); + self.pin_cs.expect_set_low().times(1).return_const(Ok(())).in_sequence(seq); + + self.bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!(expected_buffer, data); + Ok(&[ + 0x0, + 0x0, + REG as u8, + (REG >> 8) as u8, + (REG >> 16) as u8, + (REG >> 24) as u8, + ]) + }) + .in_sequence(seq); + + self.pin_cs.expect_set_high().times(1).return_const(Ok(())).in_sequence(seq); } } From f288088e7c75881165ab62c941ebf86bddb79abc Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 25 Apr 2024 15:48:36 +0200 Subject: [PATCH 02/48] #2 BytesMut used for TxMessage object --- src/can.rs | 3 --- src/message.rs | 9 ++++----- src/tests/can.rs | 10 ++++++---- src/tests/message.rs | 26 ++++++++++++++++++-------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/can.rs b/src/can.rs index 8118700..a451866 100644 --- a/src/can.rs +++ b/src/can.rs @@ -234,9 +234,6 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - // self.bus - // .transfer(&mut message.payload[..message.length]) - // .map_err(TransferError)?; self.bus.transfer(&mut message.buff).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; Ok(()) diff --git a/src/message.rs b/src/message.rs index 368b5d5..9c03aa3 100644 --- a/src/message.rs +++ b/src/message.rs @@ -91,7 +91,7 @@ pub struct TxMessage { } impl TxMessage { - pub fn new(identifier: Id, data: &[u8], can_fd: bool, bitrate_switch: bool) -> Result { + pub fn new(identifier: Id, mut data: BytesMut, can_fd: bool, bitrate_switch: bool) -> Result { let mut header = TxHeader::new(); let mut payload_length = data.len(); @@ -108,11 +108,10 @@ impl TxMessage { debug!("Maximum of 8 data bytes allowed for CAN2.0 message. Current size: {payload_length}"); return Err(DLCError::InvalidLength(data.len())); } + // make sure length divisible by four (word size) let length = (payload_length + 3) & !3; - - let mut bytes = BytesMut::with_capacity(payload_length); - bytes.extend_from_slice(data); + data.resize(length, 0); while let Err(DLCError::InvalidLength(_)) = DLC::from_length(payload_length) { payload_length += 1; @@ -130,7 +129,7 @@ impl TxMessage { } Ok(TxMessage { header, - buff: bytes, + buff: data, length, }) } diff --git a/src/tests/can.rs b/src/tests/can.rs index 72dce63..908d589 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -7,6 +7,7 @@ use crate::message::TxMessage; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; +use bytes::{BufMut, BytesMut}; use embedded_can::{ExtendedId, Id}; use mockall::Sequence; @@ -152,11 +153,12 @@ const EXTENDED_ID: u32 = 0x14C92A2B; fn test_transmit() { let mut mocks = Mocks::default(); let mut seq = Sequence::new(); - - let message_payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut payload_bytes = BytesMut::with_capacity(8); + payload_bytes.put_slice(&payload); let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); - let tx_message = TxMessage::new(Id::Extended(identifier), &message_payload, false, false).unwrap(); + let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, false, false).unwrap(); let tx_message_copy = tx_message.clone(); // mock fifo status register read byte 0 (1st attempt) -> tx fifo full @@ -201,7 +203,7 @@ fn test_transmit() { .expect_transfer() .times(1) .returning(move |data| { - assert_eq!(message_payload, data); + assert_eq!(payload, data); Ok(&[0u8; 8]) }) .in_sequence(&mut seq); diff --git a/src/tests/message.rs b/src/tests/message.rs index e4a4f3f..590fd7c 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -1,4 +1,5 @@ use crate::message::{DLCError, TxMessage, DLC}; +use bytes::{BufMut, BytesMut}; use embedded_can::Id; use embedded_can::{ExtendedId, StandardId}; @@ -7,11 +8,12 @@ const STANDARD_ID: u16 = 0x6A5; #[test] fn test_extended_id() { - let data = [0u8; 8]; + let mut payload_bytes = BytesMut::with_capacity(8); + payload_bytes.put_slice(&[0u8; 8]); let extended_id = ExtendedId::new(EXTENDED_ID).unwrap(); - let message = TxMessage::new(Id::Extended(extended_id), &data, false, false).unwrap(); + let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, false, false).unwrap(); assert!(message.header.identifier_extension_flag()); @@ -21,11 +23,12 @@ fn test_extended_id() { } #[test] fn test_standard_id() { - let data = [0u8; 8]; + let mut payload_bytes = BytesMut::with_capacity(8); + payload_bytes.put_slice(&[0u8; 8]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), &data, false, false).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, false, false).unwrap(); assert!(!message.header.identifier_extension_flag()); @@ -35,11 +38,12 @@ fn test_standard_id() { } #[test] fn test_dlc_success() { - let data = [0u8; 13]; + let mut payload_bytes = BytesMut::with_capacity(13); + payload_bytes.put_slice(&[0u8; 13]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), &data, true, false).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, true, false).unwrap(); assert_eq!(message.header.data_length_code(), DLC::Sixteen); @@ -58,11 +62,17 @@ fn test_dlc_error() { let data_fd = [0u8; 65]; + let mut payload_bytes_2_0 = BytesMut::with_capacity(10); + payload_bytes_2_0.put_slice(&data_2_0); + + let mut payload_bytes_fd = BytesMut::with_capacity(65); + payload_bytes_fd.put_slice(&data_fd); + let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message_2_0 = TxMessage::new(Id::Standard(standard_id), &data_2_0, false, false); + let message_2_0 = TxMessage::new(Id::Standard(standard_id), payload_bytes_2_0, false, false); - let message_fd = TxMessage::new(Id::Standard(standard_id), &data_fd, true, false); + let message_fd = TxMessage::new(Id::Standard(standard_id), payload_bytes_fd, true, false); assert_eq!(message_2_0.unwrap_err(), DLCError::InvalidLength(10)); From 96570139288ba196e20eadbec18d75ab91d19536 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 25 Apr 2024 16:10:20 +0200 Subject: [PATCH 03/48] #2 supress clippy warnings for bitfield structs --- src/lib.rs | 1 + src/tests/can.rs | 4 ++-- src/tests/message.rs | 14 -------------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e03ffdd..9350f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(dead_code)] +#![allow(clippy::identity_op)] extern crate alloc; diff --git a/src/tests/can.rs b/src/tests/can.rs index 908d589..90e1a2c 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -216,7 +216,6 @@ fn test_transmit() { .in_sequence(&mut seq); // mock setting of bits txreq and uinc - mocks .pin_cs .expect_set_low() @@ -254,7 +253,6 @@ fn test_transmit() { #[test] fn test_reset_command() { let mut mocks = Mocks::default(); - let mut seq = Sequence::new(); mocks.bus.expect_transfer().times(1).returning(move |data| { @@ -508,6 +506,8 @@ impl Mocks { self.pin_cs.expect_set_high().times(1).return_const(Ok(())).in_sequence(seq); } + + /// mocks 4-byte register read pub fn mock_read32(&mut self, expected_command: [u8; 2], seq: &mut Sequence) { let expected_buffer = [expected_command[0], expected_command[1], 0u8, 0u8, 0u8, 0u8]; diff --git a/src/tests/message.rs b/src/tests/message.rs index 590fd7c..ba16930 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -10,30 +10,22 @@ const STANDARD_ID: u16 = 0x6A5; fn test_extended_id() { let mut payload_bytes = BytesMut::with_capacity(8); payload_bytes.put_slice(&[0u8; 8]); - let extended_id = ExtendedId::new(EXTENDED_ID).unwrap(); - let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, false, false).unwrap(); assert!(message.header.identifier_extension_flag()); - assert_eq!(message.header.extended_identifier(), 0b01_0010_1010_0010_1011); - assert_eq!(message.header.standard_identifier(), 0b101_0011_0010); } #[test] fn test_standard_id() { let mut payload_bytes = BytesMut::with_capacity(8); payload_bytes.put_slice(&[0u8; 8]); - let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, false, false).unwrap(); assert!(!message.header.identifier_extension_flag()); - assert_eq!(message.header.extended_identifier(), 0b00_0000_0000_0000_0000); - assert_eq!(message.header.standard_identifier(), 0b110_1010_0101); } #[test] @@ -42,13 +34,10 @@ fn test_dlc_success() { payload_bytes.put_slice(&[0u8; 13]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, true, false).unwrap(); assert_eq!(message.header.data_length_code(), DLC::Sixteen); - assert!(message.header.fd_frame()); - assert_eq!(message.length, 16); let header_bytes = message.header.into_bytes(); @@ -59,7 +48,6 @@ fn test_dlc_success() { #[test] fn test_dlc_error() { let data_2_0 = [0u8; 10]; - let data_fd = [0u8; 65]; let mut payload_bytes_2_0 = BytesMut::with_capacity(10); @@ -71,10 +59,8 @@ fn test_dlc_error() { let standard_id = StandardId::new(STANDARD_ID).unwrap(); let message_2_0 = TxMessage::new(Id::Standard(standard_id), payload_bytes_2_0, false, false); - let message_fd = TxMessage::new(Id::Standard(standard_id), payload_bytes_fd, true, false); assert_eq!(message_2_0.unwrap_err(), DLCError::InvalidLength(10)); - assert_eq!(message_fd.unwrap_err(), DLCError::InvalidLength(65)); } From 018d5104c4fc0418de3fe7f9a258c748c9d3f67a Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 25 Apr 2024 16:47:17 +0200 Subject: [PATCH 04/48] #2 linting --- src/registers.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/registers.rs b/src/registers.rs index 139e805..9e48194 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,4 +1,5 @@ use modular_bitfield_msb::prelude::*; + /// Fourth byte of FIFO Control register #[bitfield] #[derive(Default)] @@ -7,6 +8,7 @@ pub struct FifoControlReg3 { pub plsize: B3, fsize: B5, } + impl FifoControlReg3 { /// set FIFO size (number of messages 1-32) pub fn with_fifo_size(mut self, value: u8) -> Self { @@ -67,8 +69,8 @@ pub struct FifoStatusReg1 { __: B3, pub fifoci: B5, } -/// First byte of FIFO Status register +/// First byte of FIFO Status register #[bitfield] #[derive(Default)] #[repr(u8)] From 4dac5b7176936ef35504ef39727c8243238eac52 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 09:49:45 +0200 Subject: [PATCH 05/48] #2 comments + lints --- src/can.rs | 1 + src/config.rs | 2 ++ src/message.rs | 17 +++++++++++++++++ src/registers.rs | 1 + 4 files changed, 21 insertions(+) diff --git a/src/can.rs b/src/can.rs index a451866..765dfb1 100644 --- a/src/can.rs +++ b/src/can.rs @@ -259,6 +259,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { let result = u32::from_le_bytes(data_read); Ok(result) } + /// Verify address within RAM bounds fn verify_ram_address(&self, addr: u16, data_length: usize) -> Result<(), Error> { if addr < 0x400 || (addr + (data_length as u16)) > 0xBFF { diff --git a/src/config.rs b/src/config.rs index 106d437..37a893c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -154,6 +154,8 @@ pub struct FifoConfiguration { /// Enables/Disables TX FIFO pub tx_enable: bool, } + +/// Permitted sizes of the message payload for a FIFO #[derive(Copy, Clone, Debug, PartialEq)] pub enum PayloadSize { EightBytes = 0b000, diff --git a/src/message.rs b/src/message.rs index 9c03aa3..d2fd9f6 100644 --- a/src/message.rs +++ b/src/message.rs @@ -10,6 +10,7 @@ pub const MAX_PAYLOAD_CAN_FD: usize = 64; /// Data length code #[derive(BitfieldSpecifier, Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] +#[allow(clippy::upper_case_acronyms)] #[bits = 4] pub enum DLC { Zero, @@ -29,6 +30,8 @@ pub enum DLC { FortyEight, SixtyFour, } + +/// Invalid data length code error #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum DLCError { InvalidLength(usize), @@ -65,18 +68,28 @@ pub struct TxHeader { // T0 #[skip] __: B2, + /// standard ID in FD mode can be extended to 12 bits if sid11 is set pub sid11: bool, + /// 18 lsb of extended ID pub extended_identifier: B18, + /// standard ID bits or msb 11 bits of extended ID pub standard_identifier: B11, // T1 #[skip] __: B16, + /// Sequence keeping track of transmitted messages in Transmit Event FIFO pub sequence: B7, + /// In normal ESI mode, set if node is error passive, cleared if node is error active pub error_status_indicator: bool, + /// Bit distinguishing between CAN and CAN FD formats pub fd_frame: bool, + /// Enables bit rate switching in CAN FD frames pub bit_rate_switch: bool, + /// Set if the frame is a RTR frame pub remote_transmission_request: bool, + /// Set if extended ID is used pub identifier_extension_flag: bool, + /// 4 bits identifying the payload length pub data_length_code: DLC, } @@ -97,10 +110,12 @@ impl TxMessage { if can_fd { header.set_fd_frame(true); + if data.len() > MAX_PAYLOAD_CAN_FD { debug!("Maximum of 64 data bytes allowed for CANFD message. Current size: {payload_length}"); return Err(DLCError::InvalidLength(data.len())); } + if bitrate_switch { header.set_bit_rate_switch(true); } @@ -111,6 +126,7 @@ impl TxMessage { // make sure length divisible by four (word size) let length = (payload_length + 3) & !3; + data.resize(length, 0); while let Err(DLCError::InvalidLength(_)) = DLC::from_length(payload_length) { @@ -127,6 +143,7 @@ impl TxMessage { header.set_identifier_extension_flag(true); } } + Ok(TxMessage { header, buff: data, diff --git a/src/registers.rs b/src/registers.rs index 9e48194..964f2bc 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -16,6 +16,7 @@ impl FifoControlReg3 { self.set_fsize(size - 1); self } + /// get FIFO size pub fn get_fifo_size(&self) -> u8 { self.fsize() + 1 From a8ee29b591263674b80a802e9fff6da3d5b9de58 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 09:57:08 +0200 Subject: [PATCH 06/48] #2 struct comments --- src/message.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/message.rs b/src/message.rs index d2fd9f6..05c4606 100644 --- a/src/message.rs +++ b/src/message.rs @@ -98,8 +98,11 @@ impl TxHeader {} /// Transmit Message Object #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxMessage { + /// first 2 bytes of Transmit Message Object pub(crate) header: TxHeader, + /// Payload bytes of Message Object pub(crate) buff: BytesMut, + /// Size of payload bytes pub(crate) length: usize, } From c985f2ed2c30004c821e8b0db8dc697ad270f4ae Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 14:12:51 +0200 Subject: [PATCH 07/48] #9 copied workflow file from rt-PCA9539 --- .github/workflows/qa.yaml | 171 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 .github/workflows/qa.yaml diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml new file mode 100644 index 0000000..bc10bf2 --- /dev/null +++ b/.github/workflows/qa.yaml @@ -0,0 +1,171 @@ +name: QA + +on: + push: + pull_request: + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: full + +jobs: + test: + name: Tests + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + rust: + - stable + - beta + - nightly + + runs-on: ${{ matrix.os }} + + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + default: true + profile: minimal + + - name: Restore cache + uses: Swatinem/rust-cache@v1 + + - name: Build & test + env: + RUST_VERSION: ${{ matrix.rust }} + OS: ${{ matrix.os }} + RUSTFLAGS: -D warnings + run: cargo test --features strict + + - name: Build default features + run: cargo build --release --features strict + + - name: Build spin mutex feature + run: cargo build --release --features spin,strict + + no_std_atomics_builds: + name: Build no_std targets with atomics support + runs-on: ubuntu-latest + strategy: + matrix: + target: + - thumbv7m-none-eabi + rust: + - stable + - beta + - nightly + feature: + - default + - spin + - cortex-m + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + default: true + profile: minimal + + - name: Restore cache + uses: Swatinem/rust-cache@v1 + + - name: Build + run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict + + no_std_no_atomics_builds: + name: Build no_std targets without full atomics support + runs-on: ubuntu-latest + strategy: + matrix: + target: + - thumbv6m-none-eabi + rust: + - stable + - beta + - nightly + feature: + - default + - cortex-m + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + default: true + profile: minimal + + - name: Restore cache + uses: Swatinem/rust-cache@v1 + + - name: Build + run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict + + code_style: + name: Check code style + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + components: rustfmt + + - run: cargo fmt --all -- --check + + documentation: + name: Check documentation + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + default: true + + - name: Restore cache + uses: Swatinem/rust-cache@v1 + + - name: Check documentation + run: cargo rustdoc -- -D warnings + + clippy: + name: Linting + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + default: true + + - name: Restore cache + uses: Swatinem/rust-cache@v1 + + - name: Clippy + run: cargo clippy --all-targets --all-features -- -D warnings \ No newline at end of file From 84479a9e49d3889614384c64c597b92aeece4d60 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 14:28:35 +0200 Subject: [PATCH 08/48] #9 added strict and default feature --- .github/workflows/qa.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index bc10bf2..740d8f2 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -89,7 +89,7 @@ jobs: strategy: matrix: target: - - thumbv6m-none-eabi + - thumbv7m-none-eabi rust: - stable - beta From ecd635c3e519c2cba7fab8ffc6748f9a5d922616 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 14:28:52 +0200 Subject: [PATCH 09/48] #9 added strict and default feature --- Cargo.toml | 8 ++++++-- src/lib.rs | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7452aed..c2e5e99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "mcp2517" description = "Library for MCP2517 CAN controller" keywords = ["MCP2517", "no_std", "CAN"] -categories = ["embedded", "hardware-support", "no-std", "network-programming"] +categories = ["embedded", "hardware-support", "no-std", "network-programming"] authors = ["AtlasAero GmbH "] license = "MIT OR Apache-2.0" version = "0.0.1" @@ -17,4 +17,8 @@ embedded-time = "0.12.1" log = "0.4.17" [dev-dependencies] -mockall = "0.11.0" \ No newline at end of file +mockall = "0.11.0" + +[features] +default = [] +strict = [] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 119b5c2..b2f546e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), no_std)] +#![cfg_attr(feature = "strict", deny(warnings))] extern crate alloc; From 631a5f7348964ea0e98db080ce04ab9349622f5b Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 14:34:00 +0200 Subject: [PATCH 10/48] #9 remove spin/cortex-m features from .yaml file --- .github/workflows/qa.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 740d8f2..5e671f5 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -47,8 +47,6 @@ jobs: - name: Build default features run: cargo build --release --features strict - - name: Build spin mutex feature - run: cargo build --release --features spin,strict no_std_atomics_builds: name: Build no_std targets with atomics support @@ -63,8 +61,6 @@ jobs: - nightly feature: - default - - spin - - cortex-m steps: - name: checkout uses: actions/checkout@v2 @@ -96,7 +92,6 @@ jobs: - nightly feature: - default - - cortex-m steps: - name: checkout uses: actions/checkout@v2 From 0ed8cfa250cc5fc2a0b8bab489ff2edf253e73a8 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 26 Apr 2024 14:52:02 +0200 Subject: [PATCH 11/48] #9 update some actions version in .yaml file --- .github/workflows/qa.yaml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 5e671f5..fa2a2ed 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -25,7 +25,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -35,7 +35,7 @@ jobs: profile: minimal - name: Restore cache - uses: Swatinem/rust-cache@v1 + uses: Swatinem/rust-cache@v2 - name: Build & test env: @@ -63,7 +63,7 @@ jobs: - default steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -74,7 +74,7 @@ jobs: profile: minimal - name: Restore cache - uses: Swatinem/rust-cache@v1 + uses: Swatinem/rust-cache@v2 - name: Build run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict @@ -94,7 +94,7 @@ jobs: - default steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -105,7 +105,7 @@ jobs: profile: minimal - name: Restore cache - uses: Swatinem/rust-cache@v1 + uses: Swatinem/rust-cache@v2 - name: Build run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict @@ -115,7 +115,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -132,7 +132,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -141,7 +141,7 @@ jobs: default: true - name: Restore cache - uses: Swatinem/rust-cache@v1 + uses: Swatinem/rust-cache@v2 - name: Check documentation run: cargo rustdoc -- -D warnings @@ -151,7 +151,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 @@ -160,7 +160,7 @@ jobs: default: true - name: Restore cache - uses: Swatinem/rust-cache@v1 + uses: Swatinem/rust-cache@v2 - name: Clippy run: cargo clippy --all-targets --all-features -- -D warnings \ No newline at end of file From 75cf2410db5779dec85c57b3f68f50eb485525f5 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Mon, 13 May 2024 12:06:30 +0200 Subject: [PATCH 12/48] #2 use Bytes for message payload --- src/can.rs | 33 ++++++++++++++++++++++++++++++--- src/message.rs | 14 +++++++------- src/registers.rs | 22 ++++++++++++++++++++++ src/tests/can.rs | 7 +++---- src/tests/message.rs | 25 ++++++++++++------------- 5 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/can.rs b/src/can.rs index 765dfb1..5ae7f73 100644 --- a/src/can.rs +++ b/src/can.rs @@ -4,6 +4,7 @@ use crate::config::{ClockConfiguration, Configuration}; use crate::message::TxMessage; use crate::registers::{FifoControlReg1, FifoStatusReg0}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; +use bytes::BytesMut; use core::marker::PhantomData; use embedded_hal::blocking::spi::Transfer; use embedded_hal::digital::v2::OutputPin; @@ -12,6 +13,7 @@ use embedded_time::Clock; use log::debug; const REGISTER_C1CON: u16 = 0x000; + const REGISTER_OSC: u16 = 0xE00; /// FIFO index for receiving CAN messages @@ -95,44 +97,52 @@ impl, CS: OutputPin, CLK: Clock> Controller { /// Configures the controller with the given settings pub fn configure(&mut self, config: &Configuration, clock: &CLK) -> Result<(), ConfigError> { self.enable_mode(OperationMode::Configuration, clock, ConfigurationModeTimeout)?; + self.write_register(REGISTER_OSC, config.clock.as_register())?; self.write_register( Self::fifo_control_register(FIFO_RX_INDEX) + 3, config.fifo.as_rx_register(), )?; + self.write_register( Self::fifo_control_register(FIFO_TX_INDEX) + 2, config.fifo.as_tx_register_2(), )?; + self.write_register( Self::fifo_control_register(FIFO_TX_INDEX) + 3, config.fifo.as_tx_register_3(), )?; + self.write_register( Self::fifo_control_register(FIFO_TX_INDEX), config.fifo.as_tx_register_0(), )?; self.enable_mode(config.mode.to_operation_mode(), clock, RequestModeTimeout)?; + Ok(()) } /// Reads and returns the operation status pub fn read_operation_status(&mut self) -> Result> { let data = self.read_register(REGISTER_C1CON + 2)?; + Ok(OperationStatus::from_register(data)) } /// Reads and returns the oscillator status pub fn read_oscillator_status(&mut self) -> Result> { let data = self.read_register(REGISTER_OSC + 1)?; + Ok(OscillatorStatus::from_register(data)) } /// Reads and returns the current clock configuration pub fn read_clock_configuration(&mut self) -> Result> { let data = self.read_register(REGISTER_OSC)?; + Ok(ClockConfiguration::from_register(data)) } @@ -147,6 +157,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.write_register(REGISTER_C1CON + 3, mode as u8 | (1 << 3))?; let target = clock.try_now()?.checked_add(Milliseconds::new(2)).ok_or(ClockError)?; + let mut current_mode = None; while current_mode.is_none() || current_mode.unwrap() != mode { @@ -167,6 +178,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { buffer[2] = value; self.transfer(&mut buffer)?; + Ok(()) } @@ -174,11 +186,12 @@ impl, CS: OutputPin, CLK: Clock> Controller { pub fn reset(&mut self) -> Result<(), BusError> { let mut buffer = self.cmd_buffer(0u16, Operation::Reset); self.transfer(&mut buffer)?; + Ok(()) } /// Transmit CAN Message - pub fn transmit(&mut self, message: TxMessage) -> Result<(), Error> { + pub fn transmit(&mut self, message: &TxMessage) -> Result<(), Error> { // make sure there is space for new message in TX FIFO // read byte 0 of TX FIFO status register let status_reg_addr = Self::fifo_status_register(FIFO_TX_INDEX); @@ -201,11 +214,13 @@ impl, CS: OutputPin, CLK: Clock> Controller { // get address in which to write next message in TX FIFO (should not be read in configuration mode) let address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; + // get address of TX FIFO control register byte 1 let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; // load message in TX FIFO self.write_fifo(address as u16, message)?; + // Request transmission (set txreq) and set uinc in TX FIFO control register byte 1 self.write_register(fifo_control_reg1, 0x03)?; @@ -222,20 +237,27 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Insert message object in TX FIFO - fn write_fifo(&mut self, register: u16, mut message: TxMessage) -> Result<(), Error> { + fn write_fifo(&mut self, register: u16, message: &TxMessage) -> Result<(), Error> { self.verify_ram_address(register, message.length)?; let mut buffer = [0u8; 10]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); + // copy message data into mutable buffer + //(BytesMut used due to unknown length of message object at compile time) + let mut data = BytesMut::new(); + data.resize(message.length, 0); + data.copy_from_slice(message.buff.as_ref()); + buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; buffer[2..].copy_from_slice(&message.header.into_bytes()); self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(&mut message.buff).map_err(TransferError)?; + self.bus.transfer(&mut data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; + Ok(()) } @@ -243,6 +265,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn read32(&mut self, register: u16) -> Result> { // create 6 byte cmd buffer (2 bytes cmd+addr , 4 bytes for register value) let mut buffer = [0u8; 6]; + let command = (register & 0x0FFF) | ((Operation::Read as u16) << 12); buffer[0] = (command >> 8) as u8; @@ -257,6 +280,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { // reverse so that msb byte of register is at the first index let result = u32::from_le_bytes(data_read); + Ok(result) } @@ -265,12 +289,14 @@ impl, CS: OutputPin, CLK: Clock> Controller { if addr < 0x400 || (addr + (data_length as u16)) > 0xBFF { return Err(Error::InvalidRamAddress(addr)); } + Ok(()) } /// Reads a single register byte fn read_register(&mut self, register: u16) -> Result> { let mut buffer = self.cmd_buffer(register, Operation::Read); + self.transfer(&mut buffer) } @@ -312,6 +338,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { /// Register operation type #[derive(Copy, Clone)] + enum Operation { Reset = 0b0000, Write = 0b0010, diff --git a/src/message.rs b/src/message.rs index 05c4606..2a00bfc 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,11 +1,14 @@ -use bytes::BytesMut; +use bytes::Bytes; use embedded_can::Id; use log::debug; use modular_bitfield_msb::prelude::*; pub const STANDARD_IDENTIFIER_MASK: u16 = 0x7FF; + pub const EXTENDED_IDENTIFIER_MASK: u32 = 0x3FFFF; + pub const MAX_PAYLOAD_CAN_2_0: usize = 8; + pub const MAX_PAYLOAD_CAN_FD: usize = 64; /// Data length code @@ -93,22 +96,21 @@ pub struct TxHeader { pub data_length_code: DLC, } -impl TxHeader {} - /// Transmit Message Object #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxMessage { /// first 2 bytes of Transmit Message Object pub(crate) header: TxHeader, /// Payload bytes of Message Object - pub(crate) buff: BytesMut, + pub(crate) buff: Bytes, /// Size of payload bytes pub(crate) length: usize, } impl TxMessage { - pub fn new(identifier: Id, mut data: BytesMut, can_fd: bool, bitrate_switch: bool) -> Result { + pub fn new(identifier: Id, data: Bytes, can_fd: bool, bitrate_switch: bool) -> Result { let mut header = TxHeader::new(); + let mut payload_length = data.len(); if can_fd { @@ -130,8 +132,6 @@ impl TxMessage { // make sure length divisible by four (word size) let length = (payload_length + 3) & !3; - data.resize(length, 0); - while let Err(DLCError::InvalidLength(_)) = DLC::from_length(payload_length) { payload_length += 1; } diff --git a/src/registers.rs b/src/registers.rs index 964f2bc..c39b1b9 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -30,7 +30,9 @@ impl FifoControlReg3 { pub struct FifoControlReg2 { #[skip] __: B1, + /// Retransmission attempts bits pub txat: B2, + /// Message transmit priority bits pub txpri: B5, } @@ -41,8 +43,11 @@ pub struct FifoControlReg2 { pub struct FifoControlReg1 { #[skip] __: B5, + /// FIFO Reset bit pub freset: bool, + /// Message Send Request bit pub txreq: bool, + /// Increment FIFO Head/Tail bit pub uinc: bool, } @@ -51,13 +56,21 @@ pub struct FifoControlReg1 { #[derive(Default)] #[repr(u8)] pub struct FifoControlReg0 { + /// TX/RX FIFO Selection bit pub txen: bool, + /// Auto RTR Enable bit pub rtren: bool, + /// Received Message Time Stamp Enable bit pub rxtsen: bool, + /// Transmit Attempts Exhausted Interrupt Enable bit pub txatie: bool, + /// Overflow Interrupt Enable bit pub rxovie: bool, + /// Transmit/Receive FIFO Empty/Full Interrupt Enable bit pub tferffie: bool, + /// Transmit/Receive FIFO Half Empty/Half Full Interrupt Enable bit pub tfhrfhie: bool, + /// Transmit/Receive FIFO Not Full/Not ETransmit/Receive FIFO Not Full/Not Empty Interrupt Flag bitmpty Interrupt Enable bit pub tfnrfnie: bool, } @@ -68,6 +81,7 @@ pub struct FifoControlReg0 { pub struct FifoStatusReg1 { #[skip] __: B3, + /// FIFO Message Index bits pub fifoci: B5, } @@ -76,12 +90,20 @@ pub struct FifoStatusReg1 { #[derive(Default)] #[repr(u8)] pub struct FifoStatusReg0 { + /// Message Aborted Status bit pub txabt: bool, + /// Message Lost Arbitration Status bit pub txlarb: bool, + /// Error Detected During Transmission bit pub txerr: bool, + /// Transmit Attempts Exhausted Interrupt Pending bit pub txatif: bool, + /// Receive FIFO Overflow Interrupt Flag bit pub rxovif: bool, + /// Transmit/Receive FIFO Empty/Full Interrupt Flag bit pub tferffif: bool, + /// Transmit/Receive FIFO Half Empty/Half Full Interrupt Flag bit pub tfhrfhif: bool, + /// Transmit/Receive FIFO Not Full/Not Empty Interrupt Flag bit pub tfnrfnif: bool, } diff --git a/src/tests/can.rs b/src/tests/can.rs index 90e1a2c..40ccd43 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -7,7 +7,7 @@ use crate::message::TxMessage; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; -use bytes::{BufMut, BytesMut}; +use bytes::Bytes; use embedded_can::{ExtendedId, Id}; use mockall::Sequence; @@ -154,8 +154,7 @@ fn test_transmit() { let mut mocks = Mocks::default(); let mut seq = Sequence::new(); let payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; - let mut payload_bytes = BytesMut::with_capacity(8); - payload_bytes.put_slice(&payload); + let payload_bytes = Bytes::copy_from_slice(&payload); let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, false, false).unwrap(); @@ -246,7 +245,7 @@ fn test_transmit() { // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); - let result = mocks.into_controller().transmit(tx_message_copy); + let result = mocks.into_controller().transmit(&tx_message_copy); assert!(result.is_ok()); } diff --git a/src/tests/message.rs b/src/tests/message.rs index ba16930..b9ef336 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -1,39 +1,41 @@ use crate::message::{DLCError, TxMessage, DLC}; -use bytes::{BufMut, BytesMut}; +use bytes::Bytes; use embedded_can::Id; use embedded_can::{ExtendedId, StandardId}; const EXTENDED_ID: u32 = 0x14C92A2B; + const STANDARD_ID: u16 = 0x6A5; #[test] fn test_extended_id() { - let mut payload_bytes = BytesMut::with_capacity(8); - payload_bytes.put_slice(&[0u8; 8]); + let payload_bytes = Bytes::copy_from_slice(&[0u8; 8]); let extended_id = ExtendedId::new(EXTENDED_ID).unwrap(); + let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, false, false).unwrap(); assert!(message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b01_0010_1010_0010_1011); assert_eq!(message.header.standard_identifier(), 0b101_0011_0010); } + #[test] fn test_standard_id() { - let mut payload_bytes = BytesMut::with_capacity(8); - payload_bytes.put_slice(&[0u8; 8]); + let payload_bytes = Bytes::copy_from_slice(&[0u8; 8]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, false, false).unwrap(); assert!(!message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b00_0000_0000_0000_0000); assert_eq!(message.header.standard_identifier(), 0b110_1010_0101); } + #[test] fn test_dlc_success() { - let mut payload_bytes = BytesMut::with_capacity(13); - payload_bytes.put_slice(&[0u8; 13]); - + let payload_bytes = Bytes::copy_from_slice(&[0u8; 13]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, true, false).unwrap(); assert_eq!(message.header.data_length_code(), DLC::Sixteen); @@ -50,11 +52,8 @@ fn test_dlc_error() { let data_2_0 = [0u8; 10]; let data_fd = [0u8; 65]; - let mut payload_bytes_2_0 = BytesMut::with_capacity(10); - payload_bytes_2_0.put_slice(&data_2_0); - - let mut payload_bytes_fd = BytesMut::with_capacity(65); - payload_bytes_fd.put_slice(&data_fd); + let payload_bytes_2_0 = Bytes::copy_from_slice(&data_2_0); + let payload_bytes_fd = Bytes::copy_from_slice(&data_fd); let standard_id = StandardId::new(STANDARD_ID).unwrap(); From 062827bc4df7ba1c2c468c834a330b2ff1d44530 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 16 May 2024 10:33:57 +0200 Subject: [PATCH 13/48] #2 write_fifo using 64 byte array workaround --- src/can.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/can.rs b/src/can.rs index 5ae7f73..1637b9d 100644 --- a/src/can.rs +++ b/src/can.rs @@ -244,10 +244,11 @@ impl, CS: OutputPin, CLK: Clock> Controller { let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); // copy message data into mutable buffer - //(BytesMut used due to unknown length of message object at compile time) - let mut data = BytesMut::new(); - data.resize(message.length, 0); - data.copy_from_slice(message.buff.as_ref()); + let mut data = [0u8; 64]; + + for (scr, dst) in message.buff.as_ref().iter().zip(data.iter_mut()) { + *dst = *scr; + } buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; @@ -255,7 +256,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(&mut data).map_err(TransferError)?; + self.bus.transfer(&mut data[..message.length]).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; Ok(()) From 840df978dee827885bfb0b90e8e186a04b883c52 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 16 May 2024 14:49:58 +0200 Subject: [PATCH 14/48] #2 added test for CAN FD with 64 bytes --- src/can.rs | 27 +++++++---- src/message.rs | 61 ++++++++++++++++-------- src/tests/can.rs | 111 +++++++++++++++++++++++++++++++++++++++++-- src/tests/message.rs | 21 +++++--- 4 files changed, 181 insertions(+), 39 deletions(-) diff --git a/src/can.rs b/src/can.rs index 1637b9d..5866167 100644 --- a/src/can.rs +++ b/src/can.rs @@ -1,7 +1,7 @@ use crate::can::BusError::{CSError, TransferError}; use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout}; use crate::config::{ClockConfiguration, Configuration}; -use crate::message::TxMessage; +use crate::message::{MessageType, TxMessage}; use crate::registers::{FifoControlReg1, FifoStatusReg0}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; use bytes::BytesMut; @@ -191,7 +191,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Transmit CAN Message - pub fn transmit(&mut self, message: &TxMessage) -> Result<(), Error> { + pub fn transmit(&mut self, message: &TxMessage) -> Result<(), Error> + where + T: MessageType, + { // make sure there is space for new message in TX FIFO // read byte 0 of TX FIFO status register let status_reg_addr = Self::fifo_status_register(FIFO_TX_INDEX); @@ -219,7 +222,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; // load message in TX FIFO - self.write_fifo(address as u16, message)?; + self.write_fifo::(address as u16, message)?; // Request transmission (set txreq) and set uinc in TX FIFO control register byte 1 self.write_register(fifo_control_reg1, 0x03)?; @@ -237,18 +240,22 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Insert message object in TX FIFO - fn write_fifo(&mut self, register: u16, message: &TxMessage) -> Result<(), Error> { + fn write_fifo( + &mut self, + register: u16, + message: &TxMessage, + ) -> Result<(), Error> + where + T: MessageType, + { self.verify_ram_address(register, message.length)?; let mut buffer = [0u8; 10]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); // copy message data into mutable buffer - let mut data = [0u8; 64]; - - for (scr, dst) in message.buff.as_ref().iter().zip(data.iter_mut()) { - *dst = *scr; - } + let mut data = [0u8; L]; + data.copy_from_slice(&message.buff.as_ref()[..L]); buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; @@ -256,7 +263,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(&mut data[..message.length]).map_err(TransferError)?; + self.bus.transfer(&mut data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; Ok(()) diff --git a/src/message.rs b/src/message.rs index 2a00bfc..09e2557 100644 --- a/src/message.rs +++ b/src/message.rs @@ -96,42 +96,62 @@ pub struct TxHeader { pub data_length_code: DLC, } +/// CAN 2.0 message type +#[derive(Debug, Copy, Clone)] +pub struct Can20 {} + +impl MessageType<8> for Can20 { + fn setup_header(&self, _header: &mut TxHeader) -> Result<(), DLCError> { + Ok(()) + } +} + +/// CAN FD message type +#[derive(Debug, Copy, Clone)] +pub struct CanFd { + pub bitrate_switch: bool, +} + +impl MessageType<64> for CanFd { + fn setup_header(&self, header: &mut TxHeader) -> Result<(), DLCError> { + header.set_bit_rate_switch(self.bitrate_switch); + header.set_fd_frame(true); + Ok(()) + } +} + +pub trait MessageType { + /// Setup CAN message header depending on message type + fn setup_header(&self, header: &mut TxHeader) -> Result<(), DLCError>; +} + /// Transmit Message Object #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct TxMessage { +pub struct TxMessage { /// first 2 bytes of Transmit Message Object pub(crate) header: TxHeader, /// Payload bytes of Message Object pub(crate) buff: Bytes, /// Size of payload bytes pub(crate) length: usize, + /// CAN message type (CAN 2.0 or CAN FD) + pub(crate) message_type: T, } -impl TxMessage { - pub fn new(identifier: Id, data: Bytes, can_fd: bool, bitrate_switch: bool) -> Result { +impl, const MAX_LENGTH: usize> TxMessage { + pub fn new(identifier: Id, data: Bytes, message_type: T) -> Result { let mut header = TxHeader::new(); let mut payload_length = data.len(); - if can_fd { - header.set_fd_frame(true); - - if data.len() > MAX_PAYLOAD_CAN_FD { - debug!("Maximum of 64 data bytes allowed for CANFD message. Current size: {payload_length}"); - return Err(DLCError::InvalidLength(data.len())); - } - - if bitrate_switch { - header.set_bit_rate_switch(true); - } - } else if data.len() > MAX_PAYLOAD_CAN_2_0 { - debug!("Maximum of 8 data bytes allowed for CAN2.0 message. Current size: {payload_length}"); - return Err(DLCError::InvalidLength(data.len())); + if payload_length > MAX_LENGTH { + debug!("Maximum of {MAX_LENGTH} bytes allowed. Current size: {payload_length} bytes"); + return Err(DLCError::InvalidLength(payload_length)); } - // make sure length divisible by four (word size) - let length = (payload_length + 3) & !3; + message_type.setup_header(&mut header)?; + // length used to choose the next supported DLC while let Err(DLCError::InvalidLength(_)) = DLC::from_length(payload_length) { payload_length += 1; } @@ -150,7 +170,8 @@ impl TxMessage { Ok(TxMessage { header, buff: data, - length, + length: payload_length, + message_type, }) } } diff --git a/src/tests/can.rs b/src/tests/can.rs index 40ccd43..a971805 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -3,7 +3,7 @@ use crate::config::{ ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, }; -use crate::message::TxMessage; +use crate::message::{Can20, CanFd, TxMessage}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; @@ -150,14 +150,16 @@ fn test_configure_mode_timeout() { const EXTENDED_ID: u32 = 0x14C92A2B; #[test] -fn test_transmit() { +fn test_transmit_can20() { let mut mocks = Mocks::default(); let mut seq = Sequence::new(); let payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; let payload_bytes = Bytes::copy_from_slice(&payload); + let msg_type = Can20 {}; + let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); - let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, false, false).unwrap(); + let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, msg_type).unwrap(); let tx_message_copy = tx_message.clone(); // mock fifo status register read byte 0 (1st attempt) -> tx fifo full @@ -196,6 +198,7 @@ fn test_transmit() { Ok(&[0u8; 10]) }) .in_sequence(&mut seq); + // transfer payload mocks .bus @@ -249,6 +252,108 @@ fn test_transmit() { assert!(result.is_ok()); } +#[test] +fn test_transmit_can_fd() { + let mut mocks = Mocks::default(); + let mut seq = Sequence::new(); + let payload = [1u8; 64]; + let payload_bytes = Bytes::copy_from_slice(&payload); + + let msg_type = CanFd { bitrate_switch: false }; + + let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); + let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, msg_type).unwrap(); + let tx_message_copy = tx_message.clone(); + + // mock fifo status register read byte 0 (1st attempt) -> tx fifo full + mocks.mock_register_read::<0b0000_0000>([0x30, 0x6C], &mut seq); + + // mock fifo status register read byte 0 (2nd attempt) -> tx fifo not full + mocks.mock_register_read::<0b0000_0001>([0x30, 0x6C], &mut seq); + + // mock read operation status + mocks.mock_register_read::<0b0000_0000>([0x30, 0x2], &mut seq); + + // mock fifo user address register read (reading 32 bits) --> address = 0x4A2 + mocks.mock_read32::<0x00_00_04_A2>([0x30, 0x70], &mut seq); + + // mock writing message in RAM specified by fifo user address (0x4A2) + // transfer cmd+tx_header + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + let mut cmd_and_header_buffer = [0u8; 10]; + cmd_and_header_buffer[0] = 0x24; + cmd_and_header_buffer[1] = 0xA2; + cmd_and_header_buffer[2..].copy_from_slice(&tx_message.header.into_bytes()); + + assert_eq!(cmd_and_header_buffer, data); + Ok(&[0u8; 10]) + }) + .in_sequence(&mut seq); + + // transfer payload + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!(payload, data); + Ok(&[1u8; 64]) + }) + .in_sequence(&mut seq); + + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + // mock setting of bits txreq and uinc + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x20, 0x69, 0x03], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + // mock reading of fifo control register + // 1st attempt -> txreq still set ->not all messages inside tx fifo have been transmitted + mocks.mock_register_read::<0x02>([0x30, 0x69], &mut seq); + // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted + mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); + + let result = mocks.into_controller().transmit(&tx_message_copy); + assert!(result.is_ok()); +} + #[test] fn test_reset_command() { let mut mocks = Mocks::default(); diff --git a/src/tests/message.rs b/src/tests/message.rs index b9ef336..612def2 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -1,4 +1,4 @@ -use crate::message::{DLCError, TxMessage, DLC}; +use crate::message::{Can20, CanFd, DLCError, TxMessage, DLC}; use bytes::Bytes; use embedded_can::Id; use embedded_can::{ExtendedId, StandardId}; @@ -12,7 +12,9 @@ fn test_extended_id() { let payload_bytes = Bytes::copy_from_slice(&[0u8; 8]); let extended_id = ExtendedId::new(EXTENDED_ID).unwrap(); - let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, false, false).unwrap(); + let msg_type = Can20 {}; + + let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, msg_type).unwrap(); assert!(message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b01_0010_1010_0010_1011); @@ -24,7 +26,9 @@ fn test_standard_id() { let payload_bytes = Bytes::copy_from_slice(&[0u8; 8]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, false, false).unwrap(); + let msg_type = Can20 {}; + + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, msg_type).unwrap(); assert!(!message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b00_0000_0000_0000_0000); @@ -36,7 +40,9 @@ fn test_dlc_success() { let payload_bytes = Bytes::copy_from_slice(&[0u8; 13]); let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, true, false).unwrap(); + let msg_type = CanFd { bitrate_switch: false }; + + let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, msg_type).unwrap(); assert_eq!(message.header.data_length_code(), DLC::Sixteen); assert!(message.header.fd_frame()); @@ -55,10 +61,13 @@ fn test_dlc_error() { let payload_bytes_2_0 = Bytes::copy_from_slice(&data_2_0); let payload_bytes_fd = Bytes::copy_from_slice(&data_fd); + let can_msg_20 = Can20 {}; + let can_msg_fd = CanFd { bitrate_switch: false }; + let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message_2_0 = TxMessage::new(Id::Standard(standard_id), payload_bytes_2_0, false, false); - let message_fd = TxMessage::new(Id::Standard(standard_id), payload_bytes_fd, true, false); + let message_2_0 = TxMessage::new(Id::Standard(standard_id), payload_bytes_2_0, can_msg_20); + let message_fd = TxMessage::new(Id::Standard(standard_id), payload_bytes_fd, can_msg_fd); assert_eq!(message_2_0.unwrap_err(), DLCError::InvalidLength(10)); assert_eq!(message_fd.unwrap_err(), DLCError::InvalidLength(65)); From c9c7b52ecd6333f9e8fce7a2ef7e96391b54d6b7 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 16 May 2024 15:16:37 +0200 Subject: [PATCH 15/48] #2 small modifications --- src/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 5866167..14da48f 100644 --- a/src/can.rs +++ b/src/can.rs @@ -255,7 +255,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { // copy message data into mutable buffer let mut data = [0u8; L]; - data.copy_from_slice(&message.buff.as_ref()[..L]); + data.copy_from_slice(message.buff.as_ref()); buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; From d2ab02ce975a823ef507761e8ee1ba28621bd224 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Thu, 16 May 2024 15:22:57 +0200 Subject: [PATCH 16/48] #2 removed length member of TxMessage --- src/can.rs | 2 +- src/message.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/can.rs b/src/can.rs index 14da48f..8dc0f48 100644 --- a/src/can.rs +++ b/src/can.rs @@ -211,7 +211,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { // make sure length of payload is consistent with CAN operation mode let operation_status = self.read_operation_status()?; - if message.length > 8 && operation_status.mode != OperationMode::NormalCANFD { + if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD { return Err(Error::InvalidPayloadLength(message.length)); } diff --git a/src/message.rs b/src/message.rs index 09e2557..6ba3f20 100644 --- a/src/message.rs +++ b/src/message.rs @@ -132,8 +132,6 @@ pub struct TxMessage { pub(crate) header: TxHeader, /// Payload bytes of Message Object pub(crate) buff: Bytes, - /// Size of payload bytes - pub(crate) length: usize, /// CAN message type (CAN 2.0 or CAN FD) pub(crate) message_type: T, } @@ -170,7 +168,6 @@ impl, const MAX_LENGTH: usize> TxMessage Date: Thu, 16 May 2024 15:25:07 +0200 Subject: [PATCH 17/48] #2 removed length usages --- src/can.rs | 4 ++-- src/tests/message.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/can.rs b/src/can.rs index 8dc0f48..aeca785 100644 --- a/src/can.rs +++ b/src/can.rs @@ -212,7 +212,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { let operation_status = self.read_operation_status()?; if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD { - return Err(Error::InvalidPayloadLength(message.length)); + return Err(Error::InvalidPayloadLength(message.buff.len())); } // get address in which to write next message in TX FIFO (should not be read in configuration mode) @@ -248,7 +248,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { where T: MessageType, { - self.verify_ram_address(register, message.length)?; + self.verify_ram_address(register, message.buff.len())?; let mut buffer = [0u8; 10]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); diff --git a/src/tests/message.rs b/src/tests/message.rs index 612def2..eda329b 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -46,7 +46,6 @@ fn test_dlc_success() { assert_eq!(message.header.data_length_code(), DLC::Sixteen); assert!(message.header.fd_frame()); - assert_eq!(message.length, 16); let header_bytes = message.header.into_bytes(); From d95f1eb47484c62fa3f34b2d9ca4ebd2bb80edcb Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 17 May 2024 10:53:10 +0200 Subject: [PATCH 18/48] #2 fn signature refactoring --- src/can.rs | 1 - src/message.rs | 2 +- src/tests/can.rs | 4 ++-- src/tests/message.rs | 10 +++++----- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/can.rs b/src/can.rs index aeca785..eb52607 100644 --- a/src/can.rs +++ b/src/can.rs @@ -4,7 +4,6 @@ use crate::config::{ClockConfiguration, Configuration}; use crate::message::{MessageType, TxMessage}; use crate::registers::{FifoControlReg1, FifoStatusReg0}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; -use bytes::BytesMut; use core::marker::PhantomData; use embedded_hal::blocking::spi::Transfer; use embedded_hal::digital::v2::OutputPin; diff --git a/src/message.rs b/src/message.rs index 6ba3f20..e104217 100644 --- a/src/message.rs +++ b/src/message.rs @@ -137,7 +137,7 @@ pub struct TxMessage { } impl, const MAX_LENGTH: usize> TxMessage { - pub fn new(identifier: Id, data: Bytes, message_type: T) -> Result { + pub fn new(message_type: T, data: Bytes, identifier: Id) -> Result { let mut header = TxHeader::new(); let mut payload_length = data.len(); diff --git a/src/tests/can.rs b/src/tests/can.rs index a971805..f10df82 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -159,7 +159,7 @@ fn test_transmit_can20() { let msg_type = Can20 {}; let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); - let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, msg_type).unwrap(); + let tx_message = TxMessage::new(msg_type, payload_bytes, Id::Extended(identifier)).unwrap(); let tx_message_copy = tx_message.clone(); // mock fifo status register read byte 0 (1st attempt) -> tx fifo full @@ -262,7 +262,7 @@ fn test_transmit_can_fd() { let msg_type = CanFd { bitrate_switch: false }; let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); - let tx_message = TxMessage::new(Id::Extended(identifier), payload_bytes, msg_type).unwrap(); + let tx_message = TxMessage::new(msg_type, payload_bytes, Id::Extended(identifier)).unwrap(); let tx_message_copy = tx_message.clone(); // mock fifo status register read byte 0 (1st attempt) -> tx fifo full diff --git a/src/tests/message.rs b/src/tests/message.rs index eda329b..f42d1fa 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -14,7 +14,7 @@ fn test_extended_id() { let msg_type = Can20 {}; - let message = TxMessage::new(Id::Extended(extended_id), payload_bytes, msg_type).unwrap(); + let message = TxMessage::new(msg_type, payload_bytes, Id::Extended(extended_id)).unwrap(); assert!(message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b01_0010_1010_0010_1011); @@ -28,7 +28,7 @@ fn test_standard_id() { let msg_type = Can20 {}; - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, msg_type).unwrap(); + let message = TxMessage::new(msg_type, payload_bytes, Id::Standard(standard_id)).unwrap(); assert!(!message.header.identifier_extension_flag()); assert_eq!(message.header.extended_identifier(), 0b00_0000_0000_0000_0000); @@ -42,7 +42,7 @@ fn test_dlc_success() { let msg_type = CanFd { bitrate_switch: false }; - let message = TxMessage::new(Id::Standard(standard_id), payload_bytes, msg_type).unwrap(); + let message = TxMessage::new(msg_type, payload_bytes, Id::Standard(standard_id)).unwrap(); assert_eq!(message.header.data_length_code(), DLC::Sixteen); assert!(message.header.fd_frame()); @@ -65,8 +65,8 @@ fn test_dlc_error() { let standard_id = StandardId::new(STANDARD_ID).unwrap(); - let message_2_0 = TxMessage::new(Id::Standard(standard_id), payload_bytes_2_0, can_msg_20); - let message_fd = TxMessage::new(Id::Standard(standard_id), payload_bytes_fd, can_msg_fd); + let message_2_0 = TxMessage::new(can_msg_20, payload_bytes_2_0, Id::Standard(standard_id)); + let message_fd = TxMessage::new(can_msg_fd, payload_bytes_fd, Id::Standard(standard_id)); assert_eq!(message_2_0.unwrap_err(), DLCError::InvalidLength(10)); assert_eq!(message_fd.unwrap_err(), DLCError::InvalidLength(65)); From 260d9eedcae9cb24e174641d6e07c2527f2fa499 Mon Sep 17 00:00:00 2001 From: Marius Meissner Date: Fri, 17 May 2024 11:15:31 +0200 Subject: [PATCH 19/48] #9: Added example for thumbv6 target RP2040 --- .gitignore | 1 + example/Cargo.toml | 23 ++++++++++++++++ example/src/clock.rs | 50 ++++++++++++++++++++++++++++++++++ example/src/heap.rs | 17 ++++++++++++ example/src/main.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++ example/src/mutex.rs | 41 ++++++++++++++++++++++++++++ 6 files changed, 197 insertions(+) create mode 100644 example/Cargo.toml create mode 100644 example/src/clock.rs create mode 100644 example/src/heap.rs create mode 100644 example/src/main.rs create mode 100644 example/src/mutex.rs diff --git a/.gitignore b/.gitignore index f32812d..9a77ea6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/* target/* +example/target/* Cargo.lock \ No newline at end of file diff --git a/example/Cargo.toml b/example/Cargo.toml new file mode 100644 index 0000000..544159c --- /dev/null +++ b/example/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rt-mcp2517-example-rp-pico" +description = "Example/Test crate for testing thumbv6" +authors = ["AtlasAero GmbH ", "Neomium GmbH "] +version = "0.1.0" +edition = "2021" + +[dependencies] +mcp2517 = { path = "..", version = "*" } + +# Embedded crates +embedded-hal = "1.0.0" +embedded-time = "0.12.1" +embedded-alloc = "0.5.1" +critical-section = "1.1.2" +panic-halt= "0.2.0" + +# Hardware support crates +rp2040-hal = "0.10.1" +cortex-m = "0.7.7" +cortex-m-rt = "0.7.4" +rp-pico = "0.9.0" +rp2040-boot2 = "0.3.0" \ No newline at end of file diff --git a/example/src/clock.rs b/example/src/clock.rs new file mode 100644 index 0000000..3fa6c91 --- /dev/null +++ b/example/src/clock.rs @@ -0,0 +1,50 @@ +use crate::mutex::Mutex; +use embedded_time::clock::Error; +use embedded_time::duration::{Duration, Fraction}; +use embedded_time::fixed_point::FixedPoint; +use embedded_time::timer::param::{Armed, OneShot}; +use embedded_time::{Clock, Instant, Timer}; +use rp2040_hal::Timer as PicoTimer; + +pub struct SystemClock { + inner: Mutex>, +} + +impl SystemClock { + pub const fn default() -> Self { + Self { + inner: Mutex::new(None), + } + } + + pub fn initialize(&self, timer: PicoTimer) { + self.inner.replace(Some(timer)) + } + + /// Returns the current ticks in us since startup + pub fn get_ticks(&self) -> u64 { + let mut ticks = 0; + + self.inner.access(|timer| { + ticks = timer.as_ref().unwrap().get_counter().ticks(); + }); + + ticks + } +} + +impl Clock for SystemClock { + type T = u64; + const SCALING_FACTOR: Fraction = Fraction::new(1, 1_000_000); + + fn try_now(&self) -> Result, Error> { + Ok(Instant::new(self.get_ticks())) + } + + fn new_timer(&self, duration: Dur) -> Timer + where + Dur: FixedPoint, + { + Timer::new(self, duration) + } +} diff --git a/example/src/heap.rs b/example/src/heap.rs new file mode 100644 index 0000000..22cc1be --- /dev/null +++ b/example/src/heap.rs @@ -0,0 +1,17 @@ +use embedded_alloc::Heap as EmbeddedAllocHeap; + +#[global_allocator] +static HEAP: EmbeddedAllocHeap = EmbeddedAllocHeap::empty(); + +const HEAP_SIZE: usize = 65_536; + +pub struct Heap {} + +impl Heap { + pub fn init() { + use core::mem::MaybeUninit; + + static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; + unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) } + } +} diff --git a/example/src/main.rs b/example/src/main.rs new file mode 100644 index 0000000..d98c186 --- /dev/null +++ b/example/src/main.rs @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] + +pub mod clock; +pub mod heap; +pub mod mutex; + +use crate::clock::SystemClock; +use crate::heap::Heap; +use hal::clocks::Clock; +use hal::fugit::RateExtU32; +use hal::pac; +use mcp2517::can::Controller; +use panic_halt as _; +use rp2040_hal as hal; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H; + +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +#[rp2040_hal::entry] +fn main() -> ! { + Heap::init(); + + let mut pac = pac::Peripherals::take().unwrap(); + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .unwrap(); + + let sio = hal::Sio::new(pac.SIO); + + let pins = hal::gpio::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS); + + let spi_mosi = pins.gpio7.into_function::(); + let spi_miso = pins.gpio4.into_function::(); + let spi_sclk = pins.gpio6.into_function::(); + let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk)); + + // Exchange the uninitialised SPI driver for an initialised one + let spi = spi.init( + &mut pac.RESETS, + clocks.peripheral_clock.freq(), + 16.MHz(), + embedded_hal::spi::MODE_0, + ); + + // Configure GPIO5 as an CS pin + let pin_cs = pins.gpio5.into_push_pull_output(); + + let _controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs); + + loop {} +} diff --git a/example/src/mutex.rs b/example/src/mutex.rs new file mode 100644 index 0000000..b925226 --- /dev/null +++ b/example/src/mutex.rs @@ -0,0 +1,41 @@ +use core::cell::RefCell; +use core::ops::DerefMut; +use critical_section::with; + +pub struct Mutex { + inner: RefCell, +} + +impl Mutex { + pub const fn new(inner: T) -> Self { + Self { + inner: RefCell::new(inner), + } + } + + /// Exclusive mutable access to inner value + pub fn access(&self, f: F) + where + F: FnOnce(&mut T), + { + with(|_cs| { + f(self.inner.borrow_mut().deref_mut()); + }) + } + + /// Replaces the inner value + pub fn replace(&self, value: T) { + with(|_cs| { + self.inner.replace(value); + }); + } +} + +impl Mutex { + /// Returns a copy of the inner value + pub fn clone_inner(&self) -> T { + with(|_cs| self.inner.borrow().clone()) + } +} + +unsafe impl Sync for Mutex {} From 5e4bacfcfc3e799e2a246d0661d044bc252ec7d4 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 12:47:49 +0200 Subject: [PATCH 20/48] #3 updated tests --- src/can.rs | 17 ++++++----- src/message.rs | 13 +++++++- src/tests/can.rs | 78 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/can.rs b/src/can.rs index 7263e01..2b3f75c 100644 --- a/src/can.rs +++ b/src/can.rs @@ -298,12 +298,14 @@ impl, CS: OutputPin, CLK: Clock> Controller { /// Receive CAN Message pub fn receive<'a>(&mut self, data: &'a mut [u8]) -> Result<&'a [u8], Error> { - let mut rxfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_RX_INDEX))?; + let fifo_status_reg = Self::fifo_status_register(FIFO_RX_INDEX); + + let mut rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; let mut rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); - // block until fifo contains at least one message + // block until fifo rx contains at least one message while !rxfifo_status_reg0.tfnrfnif() { - rxfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_RX_INDEX))?; + rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); } @@ -341,10 +343,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(&mut data).map_err(TransferError)?; + let res = self.bus.transfer(&mut data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - Ok(()) + Ok(res) } /// Read message from RX FIFO @@ -357,9 +359,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - let res = self.bus.transfer(data).map_err(TransferError)?; + self.bus.transfer(data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - Ok(res) + + Ok(data) } /// 4-byte SFR read diff --git a/src/message.rs b/src/message.rs index ae971ac..c83ecff 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,5 +1,5 @@ use bytes::Bytes; -use embedded_can::Id; +use embedded_can::{ExtendedId, Id, StandardId}; use log::debug; use modular_bitfield_msb::prelude::*; @@ -181,19 +181,29 @@ pub struct RxHeader { // R0 #[skip] __: B2, + /// In FD mode the standard ID can be extended to 12 bit using r1 sid11: bool, + /// Extended Identifier extended_identifier: B18, + /// Standard Identifier standard_identifier: B11, #[skip] __: B16, + /// Filter Hit, number of filter that matched filter_hit: B5, #[skip] __: B2, + /// Error Status Indicator error_status_indicator: bool, + /// FD Frame; distinguishes between CAN and CAN FD formats fd_frame: bool, + /// Bit Rate Switch; indicates if data bit rate was switched bit_rate_switch: bool, + /// Remote Transmission Request; not used in CAN FD remote_transmission_request: bool, + /// Identifier Extension Flag; distinguishes between base and extended format identifier_extension_flag: bool, + /// Data Length Code data_length_code: DLC, } @@ -208,6 +218,7 @@ impl RxHeader { Id::Standard(id.unwrap()) } } + #[cfg(test)] pub fn new_test_cfg(identifier: Id) -> Self { match identifier { diff --git a/src/tests/can.rs b/src/tests/can.rs index 0dfc4e1..4d01707 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -4,13 +4,13 @@ use crate::config::{ RetransmissionAttempts, SystemClockDivisor, }; use crate::filter::Filter; -use crate::message::{Can20, CanFd, TxMessage,RxHeader}; +use crate::message::{Can20, CanFd, RxHeader, TxMessage}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; use bytes::Bytes; -use mockall::Sequence; use embedded_can::{ExtendedId, Id, StandardId}; +use mockall::Sequence; #[test] fn test_configure_correct() { @@ -382,38 +382,76 @@ fn test_receive() { let id = ExtendedId::new(EXTENDED_ID).unwrap(); + let mut seq = Sequence::new(); + // custom Rx message header for testing let message_header = RxHeader::new_test_cfg(Id::Extended(id)); let mut message_buff = [0u8; 16]; // status register read - mocks.mock_register_read::<0b0000_0001>([0x30, 0x60]); + mocks.mock_register_read::<0b0000_0001>([0x30, 0x60], &mut seq); // user address register read - mocks.mock_read32::<0x00_00_04_7C>([0x30, 0x64]); + mocks.mock_read32::<0x00_00_04_7C>([0x30, 0x64], &mut seq); // Message read from RAM address 0x47C - //transfer cmd+address - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x34, 0x7C], data); - Ok(&[0u8; 2]) - }); + // transfer cmd+address + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x34, 0x7C], data); + Ok(&[0u8; 2]) + }) + .in_sequence(&mut seq); // transfer message_buff where message bytes are placed - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0u8; 16], data); - Ok(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]) - }); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0u8; 16], data); + Ok(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // set uinc bit in Rx FIFO control register - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x20, 0x5D, 0b0000_0001], data); - Ok(&[0u8; 3]) - }); - - mocks.pin_cs.expect_set_low().times(2).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(2).return_const(Ok(())); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x20, 0x5D, 0b0000_0001], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); let result = mocks.into_controller().receive(&mut message_buff).unwrap(); From 226c384a42f1abb47cf4c5f0c52d6ab1551e99cd Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 12:49:05 +0200 Subject: [PATCH 21/48] #3 tests successful --- src/can.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/can.rs b/src/can.rs index 2b3f75c..b1b4bdb 100644 --- a/src/can.rs +++ b/src/can.rs @@ -343,10 +343,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - let res = self.bus.transfer(&mut data).map_err(TransferError)?; + self.bus.transfer(&mut data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - Ok(res) + Ok(()) } /// Read message from RX FIFO @@ -359,10 +359,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(data).map_err(TransferError)?; + let res = self.bus.transfer(data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - Ok(data) + Ok(res) } /// 4-byte SFR read From 74d51267d17bb0f2f0e6a3bd24444c95ddaec6df Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 13:08:13 +0200 Subject: [PATCH 22/48] #3 modified receive fn signature and test --- src/can.rs | 12 ++++++------ src/registers.rs | 17 +++++++++++++++-- src/tests/can.rs | 12 ++++++++---- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/can.rs b/src/can.rs index b1b4bdb..324a089 100644 --- a/src/can.rs +++ b/src/can.rs @@ -297,7 +297,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Receive CAN Message - pub fn receive<'a>(&mut self, data: &'a mut [u8]) -> Result<&'a [u8], Error> { + pub fn receive(&mut self, data: &mut [u8]) -> Result<(), Error> { let fifo_status_reg = Self::fifo_status_register(FIFO_RX_INDEX); let mut rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; @@ -311,12 +311,12 @@ impl, CS: OutputPin, CLK: Clock> Controller { let address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; // read message object - let message = self.read_fifo(address as u16, data)?; + self.read_fifo(address as u16, data)?; // set uinc self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; - Ok(message) + Ok(()) } /// Insert message object in TX FIFO @@ -350,7 +350,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Read message from RX FIFO - fn read_fifo<'a>(&mut self, register: u16, data: &'a mut [u8]) -> Result<&'a [u8], Error> { + fn read_fifo(&mut self, register: u16, data: &mut [u8]) -> Result<(), Error> { let mut buffer = [0u8; 2]; let command = (register & 0x0FFF) | ((Operation::Read as u16) << 12); @@ -359,10 +359,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - let res = self.bus.transfer(data).map_err(TransferError)?; + self.bus.transfer(data).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - Ok(res) + Ok(()) } /// 4-byte SFR read diff --git a/src/registers.rs b/src/registers.rs index 07ae712..8abd1a2 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -107,28 +107,41 @@ pub struct FifoStatusReg0 { /// Transmit/Receive FIFO Not Full/Not Empty Interrupt Flag bit pub tfnrfnif: bool, } -/// filter mask + +/// Filter mask register #[bitfield] #[derive(Default, Debug, Eq, PartialEq)] #[repr(u32)] pub struct FilterMaskReg { #[skip] __: B1, + /// Identifier Receive mode bit, + /// if 1, match either standard or extended (corresponding to EXIDE bit in filter), + /// if 0 match either pub mide: bool, + /// Standard ID Mask bit pub msid11: bool, + /// Extended ID Mask bits pub meid: B18, + /// Standard ID Mask bits pub msid: B11, } -/// filter object +/// Filter object register #[bitfield] #[derive(Default, Debug, Eq, PartialEq)] #[repr(u32)] pub struct FilterObjectReg { #[skip] __: B1, + /// Extended ID enable bit + /// If MIDE 1, setting this bit matches Extended ID only + /// if MIDE 1, clearing this bit matches Standard ID only pub exide: bool, + /// Standard ID filter bit pub sid11: bool, + /// Extended ID filter bits pub eid: B18, + /// Standard ID filter rbits pub sid: B11, } diff --git a/src/tests/can.rs b/src/tests/can.rs index 4d01707..588f443 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -418,8 +418,9 @@ fn test_receive() { .bus .expect_transfer() .times(1) - .returning(move |data| { + .returning(|data| { assert_eq!([0u8; 16], data); + data.copy_from_slice(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]); Ok(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]) }) .in_sequence(&mut seq); @@ -453,10 +454,12 @@ fn test_receive() { .return_const(Ok(())) .in_sequence(&mut seq); - let result = mocks.into_controller().receive(&mut message_buff).unwrap(); + let result = mocks.into_controller().receive(&mut message_buff); + + assert!(result.is_ok()); - assert_eq!(result[..8], message_header.into_bytes()); - assert_eq!(result[8..], [1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(message_buff[..8], message_header.into_bytes()); + assert_eq!(message_buff[8..], [1, 2, 3, 4, 5, 6, 7, 8]); } #[test] @@ -525,6 +528,7 @@ fn test_set_filter_object_standard_id() { assert!(result.is_ok()); } + #[test] fn test_set_filter_object_extended_id() { let id_extended = ExtendedId::new(EXTENDED_ID).unwrap(); From 645e04a2b9be42ee38e37cb03184545bd792fce2 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 13:59:25 +0200 Subject: [PATCH 23/48] #9 remove duplicate qa build --- .github/workflows/qa.yaml | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index fa2a2ed..6acdd95 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -79,37 +79,6 @@ jobs: - name: Build run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict - no_std_no_atomics_builds: - name: Build no_std targets without full atomics support - runs-on: ubuntu-latest - strategy: - matrix: - target: - - thumbv7m-none-eabi - rust: - - stable - - beta - - nightly - feature: - - default - steps: - - name: checkout - uses: actions/checkout@v4 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} - default: true - profile: minimal - - - name: Restore cache - uses: Swatinem/rust-cache@v2 - - - name: Build - run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict - code_style: name: Check code style runs-on: ubuntu-latest From 0a6d7eeaa66c3a25078903bd922a0e6edee0fad5 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 14:35:16 +0200 Subject: [PATCH 24/48] #9 testing bytes patch --- example/Cargo.toml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index 544159c..27aeca8 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -13,11 +13,14 @@ embedded-hal = "1.0.0" embedded-time = "0.12.1" embedded-alloc = "0.5.1" critical-section = "1.1.2" -panic-halt= "0.2.0" +panic-halt = "0.2.0" # Hardware support crates rp2040-hal = "0.10.1" cortex-m = "0.7.7" -cortex-m-rt = "0.7.4" +cortex-m-rt = "0.7.3" rp-pico = "0.9.0" -rp2040-boot2 = "0.3.0" \ No newline at end of file +rp2040-boot2 = "0.3.0" + +[patch.crates-io] +bytes = { git = "ssh://git@github.com/pegasus-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.1.0" } \ No newline at end of file From 79d68421ecae8d44c93fddb2f905e9c61360ed07 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 14:50:11 +0200 Subject: [PATCH 25/48] #9 testing bytes patch for thumbv7m and thumbv6m targets --- .github/workflows/qa.yaml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 6acdd95..62f5249 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -51,6 +51,37 @@ jobs: no_std_atomics_builds: name: Build no_std targets with atomics support runs-on: ubuntu-latest + strategy: + matrix: + target: + - thumbv6m-none-eabi + rust: + - stable + - beta + - nightly + feature: + - default + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + default: true + profile: minimal + + - name: Restore cache + uses: Swatinem/rust-cache@v2 + + - name: Build + run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict + + no_std_no_atomics_builds: + name: Build no_std targets without full atomics support + runs-on: ubuntu-latest strategy: matrix: target: @@ -79,6 +110,7 @@ jobs: - name: Build run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict + code_style: name: Check code style runs-on: ubuntu-latest From 619970e1299683ae23d3b833476f61ae4b9ff629 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 14:54:50 +0200 Subject: [PATCH 26/48] #9 lint fix --- src/mocks.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mocks.rs b/src/mocks.rs index 05cb65c..2e83553 100644 --- a/src/mocks.rs +++ b/src/mocks.rs @@ -35,9 +35,9 @@ impl Clock for TestClock { Ok(Instant::new(self.next_instants.borrow_mut().remove(0))) } - fn new_timer(&self, duration: Dur) -> Timer + fn new_timer(&self, duration: Dur) -> Timer where - Dur: FixedPoint, + Dur: Duration + FixedPoint, { Timer::new(self, duration) } From afc657db51d94ceaab76d7e20e1b0072fb00ccf1 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 15:35:51 +0200 Subject: [PATCH 27/48] #3 seperate file for filter test --- src/tests/can.rs | 84 +++------------------------------------------ src/tests/filter.rs | 81 +++++++++++++++++++++++++++++++++++++++++++ src/tests/mod.rs | 1 + 3 files changed, 86 insertions(+), 80 deletions(-) create mode 100644 src/tests/filter.rs diff --git a/src/tests/can.rs b/src/tests/can.rs index 588f443..e797cf3 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -3,13 +3,12 @@ use crate::config::{ ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, }; -use crate::filter::Filter; use crate::message::{Can20, CanFd, RxHeader, TxMessage}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; use bytes::Bytes; -use embedded_can::{ExtendedId, Id, StandardId}; +use embedded_can::{ExtendedId, Id}; use mockall::Sequence; #[test] @@ -490,81 +489,6 @@ fn test_reset_command() { assert!(result.is_ok()); } -#[test] -fn test_set_filter_object_standard_id() { - let id_standard = StandardId::new(STANDARD_ID).unwrap(); - let mut filter = Filter::new(Id::Standard(id_standard), 1).unwrap(); - - // mask 2 lsb of standard id -> MSID <1:0> should be set - filter.set_mask_standard_id(0b000_0000_0011); - - // MIDE should be set and EXIDE should be cleared - filter.match_standard_only(); - - let mut mocks = Mocks::default(); - - // disable filter 0 - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xD1, 0x00], data); - Ok(&[0u8; 3]) - }); - - // write filter value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF8, 0xA5, 0x6, 0x0, 0x0], data); - Ok(&[0u8; 2]) - }); - - // write mask value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xFC, 0x3, 0u8, 0u8, 0x40], data); - Ok(&[0u8; 6]) - }); - - mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); - - let result = mocks.into_controller().set_filter_object(filter); - - assert!(result.is_ok()); -} - -#[test] -fn test_set_filter_object_extended_id() { - let id_extended = ExtendedId::new(EXTENDED_ID).unwrap(); - let mut filter = Filter::new(Id::Extended(id_extended), 0).unwrap(); - - // mask the 2 msb of extended id -> MSID<10:9> should be set - filter.set_mask_extended_id(0b1_1000_0000_0000_0000_0000_0000_0000); - - let mut mocks = Mocks::default(); - - // disable filter 0 - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xD0, 0x00], data); - Ok(&[0u8; 3]) - }); - - // write filter value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF0, 0x32, 0x5D, 0x51, 0x09], data); - Ok(&[0u8; 2]) - }); - - // write mask value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF4, 0u8, 0x6, 0u8, 0u8], data); - Ok(&[0u8; 6]) - }); - - mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); - - let result_extended = mocks.into_controller().set_filter_object(filter); - - assert!(result_extended.is_ok()); -} - #[test] fn test_request_mode_timeout() { let clock = TestClock::new(vec![ @@ -774,9 +698,9 @@ fn test_read_clock_configuration_transfer_error() { } #[derive(Default)] -struct Mocks { - bus: MockSPIBus, - pin_cs: MockPin, +pub(crate) struct Mocks { + pub(crate) bus: MockSPIBus, + pub(crate) pin_cs: MockPin, } impl Mocks { diff --git a/src/tests/filter.rs b/src/tests/filter.rs new file mode 100644 index 0000000..92fa787 --- /dev/null +++ b/src/tests/filter.rs @@ -0,0 +1,81 @@ +use crate::filter::Filter; +use crate::tests::can::Mocks; +use embedded_can::{ExtendedId, Id, StandardId}; + +const EXTENDED_ID: u32 = 0x14C92A2B; //0b000(1_0100_1100_10)(01_0010_1010_0010_1011) +const STANDARD_ID: u16 = 0x6A5; + +#[test] +fn test_set_filter_object_standard_id() { + let id_standard = StandardId::new(STANDARD_ID).unwrap(); + let mut filter = Filter::new(Id::Standard(id_standard), 1).unwrap(); + + // mask 2 lsb of standard id -> MSID <1:0> should be set + filter.set_mask_standard_id(0b000_0000_0011); + + // MIDE should be set and EXIDE should be cleared + filter.match_standard_only(); + + let mut mocks = Mocks::default(); + + // disable filter 0 + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD1, 0x00], data); + Ok(&[0u8; 3]) + }); + + // write filter value + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xF8, 0xA5, 0x6, 0x0, 0x0], data); + Ok(&[0u8; 2]) + }); + + // write mask value + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xFC, 0x3, 0u8, 0u8, 0x40], data); + Ok(&[0u8; 6]) + }); + + mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); + mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); + + let result = mocks.into_controller().set_filter_object(filter); + + assert!(result.is_ok()); +} + +#[test] +fn test_set_filter_object_extended_id() { + let id_extended = ExtendedId::new(EXTENDED_ID).unwrap(); + let mut filter = Filter::new(Id::Extended(id_extended), 0).unwrap(); + + // mask the 2 msb of extended id -> MSID<10:9> should be set + filter.set_mask_extended_id(0b1_1000_0000_0000_0000_0000_0000_0000); + + let mut mocks = Mocks::default(); + + // disable filter 0 + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0x00], data); + Ok(&[0u8; 3]) + }); + + // write filter value + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xF0, 0x32, 0x5D, 0x51, 0x09], data); + Ok(&[0u8; 2]) + }); + + // write mask value + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xF4, 0u8, 0x6, 0u8, 0u8], data); + Ok(&[0u8; 6]) + }); + + mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); + mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); + + let result_extended = mocks.into_controller().set_filter_object(filter); + + assert!(result_extended.is_ok()); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 8d14b34..ba6746c 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,5 +1,6 @@ mod can; mod config; +mod filter; mod message; mod registers; mod status; From b1bac2b49b4e902a9c81f0e6e7ffab1f146b8e40 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 15:46:23 +0200 Subject: [PATCH 28/48] #3 added sequence for filter tests --- src/tests/filter.rs | 161 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 131 insertions(+), 30 deletions(-) diff --git a/src/tests/filter.rs b/src/tests/filter.rs index 92fa787..2b3e565 100644 --- a/src/tests/filter.rs +++ b/src/tests/filter.rs @@ -1,6 +1,7 @@ use crate::filter::Filter; use crate::tests::can::Mocks; use embedded_can::{ExtendedId, Id, StandardId}; +use mockall::Sequence; const EXTENDED_ID: u32 = 0x14C92A2B; //0b000(1_0100_1100_10)(01_0010_1010_0010_1011) const STANDARD_ID: u16 = 0x6A5; @@ -10,6 +11,8 @@ fn test_set_filter_object_standard_id() { let id_standard = StandardId::new(STANDARD_ID).unwrap(); let mut filter = Filter::new(Id::Standard(id_standard), 1).unwrap(); + let mut seq = Sequence::new(); + // mask 2 lsb of standard id -> MSID <1:0> should be set filter.set_mask_standard_id(0b000_0000_0011); @@ -19,25 +22,73 @@ fn test_set_filter_object_standard_id() { let mut mocks = Mocks::default(); // disable filter 0 - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xD1, 0x00], data); - Ok(&[0u8; 3]) - }); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD1, 0x00], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // write filter value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF8, 0xA5, 0x6, 0x0, 0x0], data); - Ok(&[0u8; 2]) - }); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xF8, 0xA5, 0x6, 0x0, 0x0], data); + Ok(&[0u8; 2]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // write mask value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xFC, 0x3, 0u8, 0u8, 0x40], data); - Ok(&[0u8; 6]) - }); - - mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xFC, 0x3, 0u8, 0u8, 0x40], data); + Ok(&[0u8; 6]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); let result = mocks.into_controller().set_filter_object(filter); @@ -49,31 +100,81 @@ fn test_set_filter_object_extended_id() { let id_extended = ExtendedId::new(EXTENDED_ID).unwrap(); let mut filter = Filter::new(Id::Extended(id_extended), 0).unwrap(); + let mut seq = Sequence::new(); + // mask the 2 msb of extended id -> MSID<10:9> should be set filter.set_mask_extended_id(0b1_1000_0000_0000_0000_0000_0000_0000); let mut mocks = Mocks::default(); // disable filter 0 - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xD0, 0x00], data); - Ok(&[0u8; 3]) - }); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD0, 0x00], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // write filter value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF0, 0x32, 0x5D, 0x51, 0x09], data); - Ok(&[0u8; 2]) - }); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xF0, 0x32, 0x5D, 0x51, 0x09], data); + Ok(&[0u8; 2]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); // write mask value - mocks.bus.expect_transfer().times(1).returning(move |data| { - assert_eq!([0x21, 0xF4, 0u8, 0x6, 0u8, 0u8], data); - Ok(&[0u8; 6]) - }); - - mocks.pin_cs.expect_set_low().times(3).return_const(Ok(())); - mocks.pin_cs.expect_set_high().times(3).return_const(Ok(())); + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xF4, 0u8, 0x6, 0u8, 0u8], data); + Ok(&[0u8; 6]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); let result_extended = mocks.into_controller().set_filter_object(filter); From 6fe7e6cf0fe091282b1580b1b62d1c7e67411c77 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 29 May 2024 11:51:45 +0200 Subject: [PATCH 29/48] #3 small optimizations --- src/can.rs | 11 ++++++----- src/tests/can.rs | 5 +++-- src/tests/registers.rs | 11 ++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/can.rs b/src/can.rs index 324a089..2fe3f6c 100644 --- a/src/can.rs +++ b/src/can.rs @@ -375,14 +375,15 @@ impl, CS: OutputPin, CLK: Clock> Controller { buffer[1] = (command & 0xFF) as u8; self.pin_cs.set_low().map_err(CSError)?; - let result = self.bus.transfer(&mut buffer).map_err(TransferError)?; + self.bus.transfer(&mut buffer).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; - let mut data_read = [0u8; 4]; - data_read.clone_from_slice(&result[2..]); + let slice = &buffer[2..]; - // reverse so that msb byte of register is at the first index - let result = u32::from_le_bytes(data_read); + // SFR addresses are at the LSB of the registers + // so last read byte is the MSB of the register + // and since bitfield_msb is used, order of bytes is reversed + let result = u32::from_le_bytes(slice.try_into().expect("wrong slice length")); Ok(result) } diff --git a/src/tests/can.rs b/src/tests/can.rs index e797cf3..3d681a5 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -749,14 +749,15 @@ impl Mocks { .times(1) .returning(move |data| { assert_eq!(expected_buffer, data); - Ok(&[ + data.copy_from_slice(&[ 0x0, 0x0, REG as u8, (REG >> 8) as u8, (REG >> 16) as u8, (REG >> 24) as u8, - ]) + ]); + Ok(&[0u8; 6]) }) .in_sequence(seq); diff --git a/src/tests/registers.rs b/src/tests/registers.rs index 4c337d5..587f952 100644 --- a/src/tests/registers.rs +++ b/src/tests/registers.rs @@ -1,12 +1,13 @@ use crate::config::{PayloadSize, RetransmissionAttempts}; use crate::registers::*; + #[test] -fn test_fifocontrolreg0() { +fn test_fifo_control_reg0() { assert_eq!([0b1000_0000], FifoControlReg0::new().with_txen(true).into_bytes()); } #[test] -fn test_fifocontrolreg1() { +fn test_fifo_control_reg1() { assert_eq!( [0b0000_0011], FifoControlReg1::new().with_uinc(true).with_txreq(true).into_bytes() @@ -14,7 +15,7 @@ fn test_fifocontrolreg1() { } #[test] -fn test_fifocontrolreg2() { +fn test_fifo_control_reg2() { assert_eq!( [0b0100_0011], FifoControlReg2::new() @@ -25,7 +26,7 @@ fn test_fifocontrolreg2() { } #[test] -fn test_fifocontrolreg3() { +fn test_fifo_control_reg3() { let fifo_control_reg3 = FifoControlReg3::new() .with_plsize(PayloadSize::TwentyFourBytes as u8) .with_fifo_size(32); @@ -35,6 +36,6 @@ fn test_fifocontrolreg3() { } #[test] -fn test_fifostatusreg0() { +fn test_fifo_status_reg0() { assert_eq!([0b0000_0001], FifoStatusReg0::new().with_tfnrfnif(true).into_bytes()); } From 61c9929a45184745dba94483023ac2613e32c411 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 5 Jun 2024 13:34:08 +0200 Subject: [PATCH 30/48] #9 include example build in QA + use http to fetch rt-bytes --- .github/workflows/qa.yaml | 27 +++++++++++++++++++++++++++ example/Cargo.toml | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 62f5249..0cc113d 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -110,7 +110,34 @@ jobs: - name: Build run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict + example_build: + name: Build example crate + runs-on: ubuntu-latest + matrix: + target: + - thumbv6m-none-eabi + rust: + - stable + - beta + - nightly + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + default: true + profile: minimal + - name: Restore cache + uses: Swatinem/rust-cache@v2 + + - name: Build + run: cargo build --release --target ${{ matrix.target }} --manifest-path example/Cargo.toml + code_style: name: Check code style runs-on: ubuntu-latest diff --git a/example/Cargo.toml b/example/Cargo.toml index 27aeca8..5460b09 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -23,4 +23,4 @@ rp-pico = "0.9.0" rp2040-boot2 = "0.3.0" [patch.crates-io] -bytes = { git = "ssh://git@github.com/pegasus-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.1.0" } \ No newline at end of file +bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.1.0" } \ No newline at end of file From 6759ecac0e933c71d7407a47f4d5e446d2aab8be Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 5 Jun 2024 13:37:43 +0200 Subject: [PATCH 31/48] #9 qa.yaml syntax error fix --- .github/workflows/qa.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 0cc113d..32e75e1 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -113,13 +113,14 @@ jobs: example_build: name: Build example crate runs-on: ubuntu-latest - matrix: - target: - - thumbv6m-none-eabi - rust: - - stable - - beta - - nightly + strategy: + matrix: + target: + - thumbv6m-none-eabi + rust: + - stable + - beta + - nightly steps: - name: checkout uses: actions/checkout@v4 From c6f9a424880a93fd556a292ed46d70636098ba5b Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 5 Jun 2024 13:49:38 +0200 Subject: [PATCH 32/48] #9 adjust documentation in register.rs --- src/registers.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/registers.rs b/src/registers.rs index c39b1b9..a48f737 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,9 +1,9 @@ use modular_bitfield_msb::prelude::*; -/// Fourth byte of FIFO Control register #[bitfield] #[derive(Default)] #[repr(u8)] +/// Fourth byte of FIFO Control register pub struct FifoControlReg3 { pub plsize: B3, fsize: B5, @@ -23,10 +23,10 @@ impl FifoControlReg3 { } } -/// Third byte of FIFO Control register #[bitfield] #[derive(Default)] #[repr(u8)] +/// Third byte of FIFO Control register pub struct FifoControlReg2 { #[skip] __: B1, @@ -36,10 +36,10 @@ pub struct FifoControlReg2 { pub txpri: B5, } -/// Second byte of FIFO Control register #[bitfield] #[derive(Default)] #[repr(u8)] +/// Second byte of FIFO Control register pub struct FifoControlReg1 { #[skip] __: B5, @@ -51,10 +51,10 @@ pub struct FifoControlReg1 { pub uinc: bool, } -/// First byte of FIFO Control register #[bitfield] #[derive(Default)] #[repr(u8)] +/// First byte of FIFO Control register pub struct FifoControlReg0 { /// TX/RX FIFO Selection bit pub txen: bool, @@ -74,10 +74,10 @@ pub struct FifoControlReg0 { pub tfnrfnie: bool, } -/// Second byte of FIFO Status register #[bitfield] #[derive(Default)] #[repr(u8)] +/// Second byte of FIFO Status register pub struct FifoStatusReg1 { #[skip] __: B3, @@ -85,10 +85,10 @@ pub struct FifoStatusReg1 { pub fifoci: B5, } -/// First byte of FIFO Status register #[bitfield] #[derive(Default)] #[repr(u8)] +/// First byte of FIFO Status register pub struct FifoStatusReg0 { /// Message Aborted Status bit pub txabt: bool, From 34ff512d03e6b8da6c629b260dc9f7a86bb610db Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 5 Jun 2024 15:24:45 +0200 Subject: [PATCH 33/48] #9 disable default features for bytes and serde crates --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0f81934..a20b68d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,13 @@ readme = "README.md" documentation = "https://docs.rs/mcp2517" [dependencies] -bytes = "1.6.0" +bytes = { version = "1.6.0", default-features = false } embedded-can = "0.4.1" embedded-hal = { version = "0.2.7", features = ["unproven"] } embedded-time = "0.12.1" log = "0.4.17" modular-bitfield-msb = "0.11.2" -serde = { version = "1.0.197", features = ["derive"] } +serde = { version = "1.0.197", features = ["derive"], default-features = false } [dev-dependencies] From 5048b35fbe8e6c42f26545fb66b36dbe1b914f69 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 11 Jun 2024 11:17:05 +0200 Subject: [PATCH 34/48] #3 added filter enable test --- src/tests/can.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/tests/can.rs b/src/tests/can.rs index 3d681a5..3c059ca 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -697,6 +697,86 @@ fn test_read_clock_configuration_transfer_error() { ); } +#[test] +fn test_filter_enable() { + let mut mocks = Mocks::default(); + let mut seq = Sequence::new(); + + // Disable filter 2 + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD2, 0x00], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + // write the fifo index where the message that matches the filter is stored + // Fifo rx index is 1 in our case + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD2, 0x01], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + // Set FLTENm to enable filter + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD2, 0x81], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + let result = mocks.into_controller().enable_filter(1, 2); + + assert!(result.is_ok()); +} + #[derive(Default)] pub(crate) struct Mocks { pub(crate) bus: MockSPIBus, From 9d85852aba6d12bc672118f120bd84a5d50417c3 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 11 Jun 2024 12:11:37 +0200 Subject: [PATCH 35/48] #3 added filter disable test + covered fifo not empty flag not set in can receive test --- src/tests/can.rs | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/tests/can.rs b/src/tests/can.rs index 3c059ca..952d5ff 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -197,7 +197,6 @@ fn test_transmit_can20() { // mock writing message in RAM specified by fifo user address (0x4A2) // transfer cmd+tx_header - mocks .pin_cs .expect_set_low() @@ -388,7 +387,10 @@ fn test_receive() { let mut message_buff = [0u8; 16]; - // status register read + // status register read (wait till fifo not empty flag is set) + mocks.mock_register_read::<0b0000_0000>([0x30, 0x60], &mut seq); + + // status register read (fifo not empty flag is set) mocks.mock_register_read::<0b0000_0001>([0x30, 0x60], &mut seq); // user address register read @@ -777,6 +779,41 @@ fn test_filter_enable() { assert!(result.is_ok()); } +#[test] +fn test_filter_disable() { + let mut mocks = Mocks::default(); + let mut seq = Sequence::new(); + + // Disable filter 6 + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + // byte0+byte1 -> cmd+addr + // byte2 -> byte value written + assert_eq!([0x21, 0xD6, 0x00], data); + Ok(&[0u8; 3]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + + let result = mocks.into_controller().disable_filter(6); + + assert!(result.is_ok()); +} + #[derive(Default)] pub(crate) struct Mocks { pub(crate) bus: MockSPIBus, From 86ae6b1898f50f6fc668e55daf0ef61ce1e7e297 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 11 Jun 2024 12:12:06 +0200 Subject: [PATCH 36/48] #3 improve comments + formatting --- src/can.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index 2fe3f6c..bcd33b1 100644 --- a/src/can.rs +++ b/src/can.rs @@ -313,7 +313,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { // read message object self.read_fifo(address as u16, data)?; - // set uinc + // set UINC bit for incrementing the FIFO head by a single message self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; Ok(()) @@ -443,6 +443,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn filter_control_register_byte(filter_index: u8) -> u16 { 0x1D0 + filter_index as u16 } + /// returns the filter object register address of corresponding filter fn filter_object_register(filter_index: u8) -> u16 { 0x1F0 + 8 * (filter_index as u16) From b285696f71cbc6d4d38969a0006e5391f4586ee8 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 18 Jun 2024 12:48:02 +0200 Subject: [PATCH 37/48] #9 use updated patch for successful buld of thumbv6m target --- example/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index 5460b09..fcb2b9e 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -23,4 +23,4 @@ rp-pico = "0.9.0" rp2040-boot2 = "0.3.0" [patch.crates-io] -bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.1.0" } \ No newline at end of file +bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" } \ No newline at end of file From 20958fd629b12eb723595a960eae13944f092ccf Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 18 Jun 2024 14:53:42 +0200 Subject: [PATCH 38/48] #9 allow unused braces in registers.rs --- src/registers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registers.rs b/src/registers.rs index a48f737..4f9d9c0 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,3 +1,4 @@ +#![allow(unused_braces)] use modular_bitfield_msb::prelude::*; #[bitfield] From 939f71d97a9c62ce904fd05604ae2ef0e2f280df Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 18 Jun 2024 15:12:02 +0200 Subject: [PATCH 39/48] #9 remove build for thumb targets job in QA pipeline for CAN library --- .github/workflows/qa.yaml | 66 ++------------------------------------- 1 file changed, 2 insertions(+), 64 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 32e75e1..2e63e4e 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -47,76 +47,14 @@ jobs: - name: Build default features run: cargo build --release --features strict - - no_std_atomics_builds: - name: Build no_std targets with atomics support - runs-on: ubuntu-latest - strategy: - matrix: - target: - - thumbv6m-none-eabi - rust: - - stable - - beta - - nightly - feature: - - default - steps: - - name: checkout - uses: actions/checkout@v4 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} - default: true - profile: minimal - - - name: Restore cache - uses: Swatinem/rust-cache@v2 - - - name: Build - run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict - - no_std_no_atomics_builds: - name: Build no_std targets without full atomics support - runs-on: ubuntu-latest - strategy: - matrix: - target: - - thumbv7m-none-eabi - rust: - - stable - - beta - - nightly - feature: - - default - steps: - - name: checkout - uses: actions/checkout@v4 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - target: ${{ matrix.target }} - default: true - profile: minimal - - - name: Restore cache - uses: Swatinem/rust-cache@v2 - - - name: Build - run: cargo build --release --target ${{ matrix.target }} --features ${{ matrix.feature }},strict - example_build: - name: Build example crate + name: Build example crate for no_std target runs-on: ubuntu-latest strategy: matrix: target: - thumbv6m-none-eabi + - thumbv7m-none-eabi rust: - stable - beta From 247fb9fd8cf6badf21082405e0853e8ca1f642e6 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 18 Jun 2024 15:16:24 +0200 Subject: [PATCH 40/48] #9 no bytes patch use for thumbv7m target --- .github/workflows/qa.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 2e63e4e..1ab22a6 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -48,13 +48,12 @@ jobs: run: cargo build --release --features strict example_build: - name: Build example crate for no_std target + name: Build example crate for no_std thumbv6m runs-on: ubuntu-latest strategy: matrix: target: - thumbv6m-none-eabi - - thumbv7m-none-eabi rust: - stable - beta From 1775947572e22ffca4153b28e7ddd4687057f082 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 18 Jun 2024 15:20:56 +0200 Subject: [PATCH 41/48] #9 add build job for thumbv7m target --- .github/workflows/qa.yaml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 1ab22a6..6e04008 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -47,7 +47,36 @@ jobs: - name: Build default features run: cargo build --release --features strict - example_build: + build: + name: Build for no_std thumbv7m target + runs-on: ubuntu-latest + strategy: + matrix: + target: + - thumbv7m-none-eabi + rust: + - stable + - beta + - nightly + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + target: ${{ matrix.target }} + default: true + profile: minimal + + - name: Restore cache + uses: Swatinem/rust-cache@v2 + + - name: Build + run: cargo build --release --target ${{ matrix.target }} --features default,strict + + example_crate_build: name: Build example crate for no_std thumbv6m runs-on: ubuntu-latest strategy: From f08997fcb65ba95c207bd851371354f1d176adce Mon Sep 17 00:00:00 2001 From: Marius Meissner Date: Thu, 20 Jun 2024 16:55:21 +0200 Subject: [PATCH 42/48] #3: Replaced is_ok() assertions by unwrap() in tests --- src/tests/can.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tests/can.rs b/src/tests/can.rs index 952d5ff..68f29eb 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -268,8 +268,7 @@ fn test_transmit_can20() { // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); - let result = mocks.into_controller().transmit(&tx_message_copy); - assert!(result.is_ok()); + mocks.into_controller().transmit(&tx_message_copy).unwrap(); } #[test] @@ -370,8 +369,7 @@ fn test_transmit_can_fd() { // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); - let result = mocks.into_controller().transmit(&tx_message_copy); - assert!(result.is_ok()); + mocks.into_controller().transmit(&tx_message_copy).unwrap(); } #[test] @@ -487,8 +485,7 @@ fn test_reset_command() { .return_const(Ok(())) .in_sequence(&mut seq); - let result = mocks.into_controller().reset(); - assert!(result.is_ok()); + mocks.into_controller().reset().unwrap(); } #[test] From 23706e6ffae2d19a36ae48c95fa3fe59318b96c0 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 26 Jun 2024 14:35:35 +0200 Subject: [PATCH 43/48] #11 add support for listen only mode --- src/config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config.rs b/src/config.rs index 37a893c..457dbf1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -234,6 +234,8 @@ pub enum RequestMode { InternalLoopback, /// External loop back mode ExternalLoopback, + /// Listen only mode + ListenOnly, /// CAN 2.0 mode, possible error frames on CAN FD frames NormalCAN2_0, } @@ -250,6 +252,7 @@ impl RequestMode { RequestMode::NormalCANFD => OperationMode::NormalCANFD, RequestMode::InternalLoopback => OperationMode::InternalLoopback, RequestMode::ExternalLoopback => OperationMode::ExternalLoopback, + RequestMode::ListenOnly => OperationMode::ListenOnly, RequestMode::NormalCAN2_0 => OperationMode::NormalCAN2_0, } } From a043e498e7c508a5cd529d146536441641e5c8b4 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 26 Jun 2024 17:04:51 +0200 Subject: [PATCH 44/48] #11 add TX/RX using internal loopback mode in example crate --- example/Cargo.toml | 5 +++- example/src/main.rs | 70 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index fcb2b9e..8ec674f 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -21,6 +21,9 @@ cortex-m = "0.7.7" cortex-m-rt = "0.7.3" rp-pico = "0.9.0" rp2040-boot2 = "0.3.0" +embedded-can = "0.4.1" +bytes = { version = "1.6.0", default-features = false } +log = "0.4.21" [patch.crates-io] -bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" } \ No newline at end of file +bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" } diff --git a/example/src/main.rs b/example/src/main.rs index d98c186..84694df 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -7,10 +7,21 @@ pub mod mutex; use crate::clock::SystemClock; use crate::heap::Heap; +use bytes::Bytes; +use cortex_m::asm::delay; +use embedded_can::{Id, StandardId}; +use embedded_hal::delay::DelayNs; use hal::clocks::Clock; use hal::fugit::RateExtU32; use hal::pac; +use log::info; use mcp2517::can::Controller; +use mcp2517::config::{ + ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, + RetransmissionAttempts, SystemClockDivisor, +}; +use mcp2517::filter::Filter; +use mcp2517::message::{Can20, TxMessage}; use panic_halt as _; use rp2040_hal as hal; @@ -56,10 +67,65 @@ fn main() -> ! { embedded_hal::spi::MODE_0, ); + let mut timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); + let sys_clk = SystemClock::default(); + sys_clk.initialize(timer); + // Configure GPIO5 as an CS pin let pin_cs = pins.gpio5.into_push_pull_output(); - let _controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs); + let mut can_controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs); + + // Setup clk config + let clk_config = ClockConfiguration { + clock_output: ClockOutputDivisor::DivideBy1, + system_clock: SystemClockDivisor::DivideBy1, + pll: PLLSetting::DirectXTALOscillator, + disable_clock: false, + }; + + // Setup fifo config + let fifo_config = FifoConfiguration { + rx_size: 1, + tx_size: 1, + pl_size: PayloadSize::EightBytes, + tx_priority: 32, + tx_enable: true, + tx_attempts: RetransmissionAttempts::Unlimited, + }; + + // Setup CAN Controller config + let config = Configuration { + clock: clk_config, + fifo: fifo_config, + mode: RequestMode::InternalLoopback, + }; + + let _ = can_controller.configure(&config, &sys_clk); + + let can_id = Id::Standard(StandardId::new(0x55).unwrap()); + + // Create filter object for RX + let filter = Filter::new(can_id, 0).unwrap(); + let _ = can_controller.set_filter_object(filter); + + // Create message frame + let message_type = Can20 {}; + let payload = [1, 2, 3, 4, 5, 6, 7, 8]; + let pl_bytes = bytes::Bytes::copy_from_slice(&payload); + let can_message = TxMessage::new(message_type, pl_bytes, can_id).unwrap(); + + let mut receive_buffer = [0u8; 8]; + + loop { + can_controller.transmit(&can_message).unwrap(); + info!("Message sent"); + + match can_controller.receive(&mut receive_buffer).unwrap() { + Ok(_) => info!("message received {receive_buffer:?}"), + Err(e) => info!("Error while attempting to read message: {e:?}"), + } - loop {} + timer.delay_ms(500); + } } From 0088eebc2d34d4b3c284f2c7ba0ba4a917a5484c Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 26 Jun 2024 17:06:40 +0200 Subject: [PATCH 45/48] #11 renove reduntant prefix --- example/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/src/main.rs b/example/src/main.rs index 84694df..fb5357d 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -112,7 +112,7 @@ fn main() -> ! { // Create message frame let message_type = Can20 {}; let payload = [1, 2, 3, 4, 5, 6, 7, 8]; - let pl_bytes = bytes::Bytes::copy_from_slice(&payload); + let pl_bytes = Bytes::copy_from_slice(&payload); let can_message = TxMessage::new(message_type, pl_bytes, can_id).unwrap(); let mut receive_buffer = [0u8; 8]; From a5361a7232626c37e6e35db9157fc5cd6640c2f2 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 30 Aug 2024 12:02:01 +0200 Subject: [PATCH 46/48] #11 fix bugs with impl of transmission and reception of CAN messages --- Cargo.toml | 1 + example/.cargo/config.toml | 24 +++++++++ example/Cargo.toml | 7 +++ example/memory.x | 15 ++++++ example/src/main.rs | 104 +++++++++++++++++++++++-------------- src/can.rs | 31 +++++++++-- src/config.rs | 6 ++- src/registers.rs | 2 +- src/tests/can.rs | 38 ++++++++------ src/tests/config.rs | 12 ++--- src/tests/filter.rs | 46 ++++++++++++++++ 11 files changed, 217 insertions(+), 69 deletions(-) create mode 100644 example/.cargo/config.toml create mode 100644 example/memory.x diff --git a/Cargo.toml b/Cargo.toml index 31e7a84..4eb77df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ readme = "README.md" documentation = "https://docs.rs/mcp2517" [dependencies] +byteorder = { version = "1.5.0", default-features = false } bytes = { version = "1.6.0", default-features = false } embedded-can = "0.4.1" embedded-hal = { version = "0.2.7", features = ["unproven"] } diff --git a/example/.cargo/config.toml b/example/.cargo/config.toml new file mode 100644 index 0000000..f15cc44 --- /dev/null +++ b/example/.cargo/config.toml @@ -0,0 +1,24 @@ +[build] +# Set the default target to match the Cortex-M0+ in the RP2040 +target = "thumbv6m-none-eabi" + +# Target specific options +[target.thumbv6m-none-eabi] +# Pass some extra options to rustc, some of which get passed on to the linker. +# +# * linker argument --nmagic turns off page alignment of sections (which saves +# flash space) +# * linker argument -Tlink.x tells the linker to use link.x as the linker +# script. This is usually provided by the cortex-m-rt crate, and by default +# the version in that crate will include a file called `memory.x` which +# describes the particular memory layout for your specific chip. +# * inline-threshold=5 makes the compiler more aggressive and inlining functions +# * no-vectorize-loops turns off the loop vectorizer (seeing as the M0+ doesn't +# have SIMD) +rustflags = [ + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "no-vectorize-loops", +] + +runner = "elf2uf2-rs" diff --git a/example/Cargo.toml b/example/Cargo.toml index 8ec674f..706996b 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -24,6 +24,13 @@ rp2040-boot2 = "0.3.0" embedded-can = "0.4.1" bytes = { version = "1.6.0", default-features = false } log = "0.4.21" +usb-device = "0.3.2" +usbd-serial = "0.2.2" +defmt = "0.3.8" +defmt-serial = "0.10.0" +static_cell = "2.1.0" +embedded-serial = "0.5.0" +fugit = { version = "0.3.7", features = ["defmt"] } [patch.crates-io] bytes = { git = "https://github.com/atlas-aero/rt-bytes.git", branch = "cfg_target_has_atomic_v1.6.0" } diff --git a/example/memory.x b/example/memory.x new file mode 100644 index 0000000..070eac7 --- /dev/null +++ b/example/memory.x @@ -0,0 +1,15 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +EXTERN(BOOT2_FIRMWARE) + +SECTIONS { + /* ### Boot loader */ + .boot2 ORIGIN(BOOT2) : + { + KEEP(*(.boot2)); + } > BOOT2 +} INSERT BEFORE .text; \ No newline at end of file diff --git a/example/src/main.rs b/example/src/main.rs index fb5357d..229843f 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +extern crate alloc; pub mod clock; pub mod heap; @@ -8,38 +9,45 @@ pub mod mutex; use crate::clock::SystemClock; use crate::heap::Heap; use bytes::Bytes; -use cortex_m::asm::delay; +use core::fmt::Write; use embedded_can::{Id, StandardId}; use embedded_hal::delay::DelayNs; -use hal::clocks::Clock; -use hal::fugit::RateExtU32; -use hal::pac; -use log::info; +use embedded_hal::digital::OutputPin; +use fugit::RateExtU32; use mcp2517::can::Controller; use mcp2517::config::{ - ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, - RetransmissionAttempts, SystemClockDivisor, + ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, RequestMode, + SystemClockDivisor, }; use mcp2517::filter::Filter; use mcp2517::message::{Can20, TxMessage}; -use panic_halt as _; -use rp2040_hal as hal; - -#[link_section = ".boot2"] -#[used] -pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H; +use panic_halt as panic; +use rp_pico as bsp; + +use bsp::{ + entry, + hal::{ + clocks::{init_clocks_and_plls, Clock}, + gpio::FunctionSpi, + pac, + sio::Sio, + uart::*, + watchdog::Watchdog, + Spi, Timer, + }, +}; const XTAL_FREQ_HZ: u32 = 12_000_000u32; -#[rp2040_hal::entry] +#[entry] fn main() -> ! { Heap::init(); let mut pac = pac::Peripherals::take().unwrap(); - let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + let mut watchdog = Watchdog::new(pac.WATCHDOG); // Configure the clocks - let clocks = hal::clocks::init_clocks_and_plls( + let clocks = init_clocks_and_plls( XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, @@ -50,49 +58,55 @@ fn main() -> ! { ) .unwrap(); - let sio = hal::Sio::new(pac.SIO); + let sio = Sio::new(pac.SIO); - let pins = hal::gpio::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS); + let pins = bsp::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS); - let spi_mosi = pins.gpio7.into_function::(); - let spi_miso = pins.gpio4.into_function::(); - let spi_sclk = pins.gpio6.into_function::(); - let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk)); + let spi_mosi = pins.gpio11.into_function::(); + let spi_miso = pins.gpio12.into_function::(); + let spi_sclk = pins.gpio10.into_function::(); + let spi = Spi::<_, _, _, 8>::new(pac.SPI1, (spi_mosi, spi_miso, spi_sclk)); // Exchange the uninitialised SPI driver for an initialised one let spi = spi.init( &mut pac.RESETS, clocks.peripheral_clock.freq(), - 16.MHz(), + 1.MHz(), embedded_hal::spi::MODE_0, ); - let mut timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); + let mut led_pin = pins.led.into_push_pull_output(); + + let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); let sys_clk = SystemClock::default(); sys_clk.initialize(timer); // Configure GPIO5 as an CS pin - let pin_cs = pins.gpio5.into_push_pull_output(); + let pin_cs = pins.gpio13.into_push_pull_output(); + + let mut uart = bsp::hal::uart::UartPeripheral::new( + pac.UART0, + (pins.gpio0.into_function(), pins.gpio1.into_function()), + &mut pac.RESETS, + ) + .enable( + UartConfig::new(9600.Hz(), DataBits::Eight, None, StopBits::One), + clocks.peripheral_clock.freq(), + ) + .unwrap(); let mut can_controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs); // Setup clk config let clk_config = ClockConfiguration { clock_output: ClockOutputDivisor::DivideBy1, - system_clock: SystemClockDivisor::DivideBy1, + system_clock: SystemClockDivisor::DivideBy2, pll: PLLSetting::DirectXTALOscillator, disable_clock: false, }; // Setup fifo config - let fifo_config = FifoConfiguration { - rx_size: 1, - tx_size: 1, - pl_size: PayloadSize::EightBytes, - tx_priority: 32, - tx_enable: true, - tx_attempts: RetransmissionAttempts::Unlimited, - }; + let fifo_config = FifoConfiguration::default(); // Setup CAN Controller config let config = Configuration { @@ -101,7 +115,9 @@ fn main() -> ! { mode: RequestMode::InternalLoopback, }; - let _ = can_controller.configure(&config, &sys_clk); + if let Err(_) = can_controller.configure(&config, &sys_clk) { + panic!() + } let can_id = Id::Standard(StandardId::new(0x55).unwrap()); @@ -119,11 +135,21 @@ fn main() -> ! { loop { can_controller.transmit(&can_message).unwrap(); - info!("Message sent"); + uart.write_raw(b"can message sent\n\r").unwrap(); + + timer.delay_ms(500); + + match can_controller.receive(&mut receive_buffer) { + Ok(_) => { + uart.write_fmt(format_args!("can message received\n\r")).unwrap(); + + for val in receive_buffer { + uart.write_fmt(format_args!("{val}\n\r")).unwrap(); + } - match can_controller.receive(&mut receive_buffer).unwrap() { - Ok(_) => info!("message received {receive_buffer:?}"), - Err(e) => info!("Error while attempting to read message: {e:?}"), + led_pin.set_high().unwrap(); + } + Err(e) => uart.write_fmt(format_args!("error reading message {:?}\n\r", e)).unwrap(), } timer.delay_ms(500); diff --git a/src/can.rs b/src/can.rs index bcd33b1..3f2f9c8 100644 --- a/src/can.rs +++ b/src/can.rs @@ -5,6 +5,7 @@ use crate::filter::Filter; use crate::message::{MessageType, TxMessage}; use crate::registers::{FifoControlReg1, FifoStatusReg0}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; +use byteorder::{BigEndian, ByteOrder, LittleEndian}; use core::marker::PhantomData; use embedded_hal::blocking::spi::Transfer; use embedded_hal::digital::v2::OutputPin; @@ -102,7 +103,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.write_register( Self::fifo_control_register(FIFO_RX_INDEX) + 3, - config.fifo.as_rx_register(), + config.fifo.as_rx_register_3(), )?; self.write_register( @@ -186,6 +187,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { // Set FLTENm to enable filter self.write_register(filter_control_reg, (1 << 7) | fifo_index)?; + Ok(()) } @@ -193,6 +195,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { pub fn disable_filter(&mut self, filter_index: u8) -> Result<(), BusError> { let filter_reg = Self::filter_control_register_byte(filter_index); self.write_register(filter_reg, 0x00)?; + Ok(()) } @@ -207,8 +210,13 @@ impl, CS: OutputPin, CLK: Clock> Controller { let mask_value = u32::from(filter.mask_bits); self.write32(filter_object_reg, filter_value)?; + self.write32(filter_mask_reg, mask_value)?; + let filter_control_reg = Self::filter_control_register_byte(filter.index); + + self.write_register(filter_control_reg, (1 << 7) | 1)?; + Ok(()) } @@ -273,7 +281,11 @@ impl, CS: OutputPin, CLK: Clock> Controller { } // get address in which to write next message in TX FIFO (should not be read in configuration mode) - let address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; + let user_address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?; + + // calculate address of next Message Object according to + // Equation 4-1 in MCP251XXFD Family Reference Manual + let address = user_address + 0x400; // get address of TX FIFO control register byte 1 let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1; @@ -309,7 +321,10 @@ impl, CS: OutputPin, CLK: Clock> Controller { rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); } - let address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; + let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; + + let address = 0x400 + user_address; + // read message object self.read_fifo(address as u16, data)?; @@ -335,12 +350,17 @@ impl, CS: OutputPin, CLK: Clock> Controller { // copy message data into mutable buffer let mut data = [0u8; L]; - data.copy_from_slice(message.buff.as_ref()); + data.copy_from_slice(&message.buff); buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; buffer[2..].copy_from_slice(&message.header.into_bytes()); + for word in buffer[2..].chunks_exact_mut(4) { + let num = BigEndian::read_u32(word); + LittleEndian::write_u32(word, num); + } + self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; self.bus.transfer(&mut data).map_err(TransferError)?; @@ -351,8 +371,9 @@ impl, CS: OutputPin, CLK: Clock> Controller { /// Read message from RX FIFO fn read_fifo(&mut self, register: u16, data: &mut [u8]) -> Result<(), Error> { + let payload_address = register + 8; let mut buffer = [0u8; 2]; - let command = (register & 0x0FFF) | ((Operation::Read as u16) << 12); + let command = (payload_address & 0x0FFF) | ((Operation::Read as u16) << 12); buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; diff --git a/src/config.rs b/src/config.rs index 457dbf1..725c634 100644 --- a/src/config.rs +++ b/src/config.rs @@ -182,13 +182,15 @@ impl Default for FifoConfiguration { } impl FifoConfiguration { - /// Encodes the configuration to RX FIFO configuration register byte - pub(crate) fn as_rx_register(&self) -> u8 { + /// Encodes the configuration for the third RX fifo control register byte + pub(crate) fn as_rx_register_3(&self) -> u8 { (Self::limit_size(self.rx_size) - 1) | ((self.pl_size as u8) << 5) } /// Encodes the configuration for the first TX configuration register byte pub(crate) fn as_tx_register_0(&self) -> u8 { + // bit 7 -> tx enable + // bit 0 -> tx fifo not full interrupt flag enable match self.tx_enable { true => 0b1000_0000, false => 0b0000_0000, diff --git a/src/registers.rs b/src/registers.rs index ef15bea..e505b88 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -137,7 +137,7 @@ pub struct FilterObjectReg { __: B1, /// Extended ID enable bit /// If MIDE 1, setting this bit matches Extended ID only - /// if MIDE 1, clearing this bit matches Standard ID only + /// If MIDE 0, clearing this bit matches Standard ID only pub exide: bool, /// Standard ID filter bit pub sid11: bool, diff --git a/src/tests/can.rs b/src/tests/can.rs index 68f29eb..b770946 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -3,10 +3,11 @@ use crate::config::{ ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, }; -use crate::message::{Can20, CanFd, RxHeader, TxMessage}; +use crate::message::{Can20, CanFd, TxMessage}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; +use byteorder::{BigEndian, ByteOrder, LittleEndian}; use bytes::Bytes; use embedded_can::{ExtendedId, Id}; use mockall::Sequence; @@ -210,10 +211,16 @@ fn test_transmit_can20() { .times(1) .returning(move |data| { let mut cmd_and_header_buffer = [0u8; 10]; - cmd_and_header_buffer[0] = 0x24; + cmd_and_header_buffer[0] = 0x28; cmd_and_header_buffer[1] = 0xA2; + cmd_and_header_buffer[2..].copy_from_slice(&tx_message.header.into_bytes()); + for chunk in cmd_and_header_buffer[2..].chunks_exact_mut(4) { + let num = BigEndian::read_u32(chunk); + LittleEndian::write_u32(chunk, num); + } + assert_eq!(cmd_and_header_buffer, data); Ok(&[0u8; 10]) }) @@ -311,10 +318,15 @@ fn test_transmit_can_fd() { .times(1) .returning(move |data| { let mut cmd_and_header_buffer = [0u8; 10]; - cmd_and_header_buffer[0] = 0x24; + cmd_and_header_buffer[0] = 0x28; cmd_and_header_buffer[1] = 0xA2; cmd_and_header_buffer[2..].copy_from_slice(&tx_message.header.into_bytes()); + for chunk in cmd_and_header_buffer[2..].chunks_exact_mut(4) { + let num = BigEndian::read_u32(chunk); + LittleEndian::write_u32(chunk, num); + } + assert_eq!(cmd_and_header_buffer, data); Ok(&[0u8; 10]) }) @@ -376,14 +388,9 @@ fn test_transmit_can_fd() { fn test_receive() { let mut mocks = Mocks::default(); - let id = ExtendedId::new(EXTENDED_ID).unwrap(); - let mut seq = Sequence::new(); - // custom Rx message header for testing - let message_header = RxHeader::new_test_cfg(Id::Extended(id)); - - let mut message_buff = [0u8; 16]; + let mut message_buff = [0u8; 8]; // status register read (wait till fifo not empty flag is set) mocks.mock_register_read::<0b0000_0000>([0x30, 0x60], &mut seq); @@ -394,7 +401,7 @@ fn test_receive() { // user address register read mocks.mock_read32::<0x00_00_04_7C>([0x30, 0x64], &mut seq); - // Message read from RAM address 0x47C + // Message read from RAM address (0x47C+8) to start reading received message object payload // transfer cmd+address mocks .pin_cs @@ -407,7 +414,7 @@ fn test_receive() { .expect_transfer() .times(1) .returning(move |data| { - assert_eq!([0x34, 0x7C], data); + assert_eq!([0x38, 0x84], data); Ok(&[0u8; 2]) }) .in_sequence(&mut seq); @@ -418,9 +425,9 @@ fn test_receive() { .expect_transfer() .times(1) .returning(|data| { - assert_eq!([0u8; 16], data); - data.copy_from_slice(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]); - Ok(&[0x09, 0x51, 0x5D, 0x32, 0u8, 0u8, 0u8, 0x18, 1, 2, 3, 4, 5, 6, 7, 8]) + assert_eq!([0u8; 8], data); + data.copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]); + Ok(&[1, 2, 3, 4, 5, 6, 7, 8]) }) .in_sequence(&mut seq); mocks @@ -457,8 +464,7 @@ fn test_receive() { assert!(result.is_ok()); - assert_eq!(message_buff[..8], message_header.into_bytes()); - assert_eq!(message_buff[8..], [1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(message_buff, [1, 2, 3, 4, 5, 6, 7, 8]); } #[test] diff --git a/src/tests/config.rs b/src/tests/config.rs index 7a15ccb..24d3dc0 100644 --- a/src/tests/config.rs +++ b/src/tests/config.rs @@ -94,14 +94,14 @@ fn test_clock_configuration_to_register() { #[test] fn test_fifo_configuration_as_rx_register() { - assert_eq!(0b0000_0000, fifo_rx_config(0).as_rx_register()); - assert_eq!(0b0000_0000, fifo_rx_config(1).as_rx_register()); + assert_eq!(0b0000_0000, fifo_rx_config(0).as_rx_register_3()); + assert_eq!(0b0000_0000, fifo_rx_config(1).as_rx_register_3()); - assert_eq!(0b0000_0001, fifo_rx_config(2).as_rx_register()); - assert_eq!(0b0000_1011, fifo_rx_config(12).as_rx_register()); + assert_eq!(0b0000_0001, fifo_rx_config(2).as_rx_register_3()); + assert_eq!(0b0000_1011, fifo_rx_config(12).as_rx_register_3()); - assert_eq!(0b0001_1111, fifo_rx_config(32).as_rx_register()); - assert_eq!(0b0001_1111, fifo_rx_config(33).as_rx_register()); + assert_eq!(0b0001_1111, fifo_rx_config(32).as_rx_register_3()); + assert_eq!(0b0001_1111, fifo_rx_config(33).as_rx_register_3()); } #[test] diff --git a/src/tests/filter.rs b/src/tests/filter.rs index 2b3e565..f39be39 100644 --- a/src/tests/filter.rs +++ b/src/tests/filter.rs @@ -90,6 +90,29 @@ fn test_set_filter_object_standard_id() { .return_const(Ok(())) .in_sequence(&mut seq); + // enable filter + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD1, 0x81], data); + Ok(&[0u8; 6]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + let result = mocks.into_controller().set_filter_object(filter); assert!(result.is_ok()); @@ -176,6 +199,29 @@ fn test_set_filter_object_extended_id() { .return_const(Ok(())) .in_sequence(&mut seq); + // enable filter + mocks + .pin_cs + .expect_set_low() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + mocks + .bus + .expect_transfer() + .times(1) + .returning(move |data| { + assert_eq!([0x21, 0xD0, 0x81], data); + Ok(&[0u8; 6]) + }) + .in_sequence(&mut seq); + mocks + .pin_cs + .expect_set_high() + .times(1) + .return_const(Ok(())) + .in_sequence(&mut seq); + let result_extended = mocks.into_controller().set_filter_object(filter); assert!(result_extended.is_ok()); From 2d18baed10e47bceb925848259b88f10bbd1e47d Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Mon, 2 Sep 2024 10:21:34 +0200 Subject: [PATCH 47/48] #11 remove debugging code using led --- example/src/main.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/example/src/main.rs b/example/src/main.rs index 229843f..53eacb1 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -12,7 +12,6 @@ use bytes::Bytes; use core::fmt::Write; use embedded_can::{Id, StandardId}; use embedded_hal::delay::DelayNs; -use embedded_hal::digital::OutputPin; use fugit::RateExtU32; use mcp2517::can::Controller; use mcp2517::config::{ @@ -75,8 +74,6 @@ fn main() -> ! { embedded_hal::spi::MODE_0, ); - let mut led_pin = pins.led.into_push_pull_output(); - let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); let sys_clk = SystemClock::default(); sys_clk.initialize(timer); @@ -146,8 +143,6 @@ fn main() -> ! { for val in receive_buffer { uart.write_fmt(format_args!("{val}\n\r")).unwrap(); } - - led_pin.set_high().unwrap(); } Err(e) => uart.write_fmt(format_args!("error reading message {:?}\n\r", e)).unwrap(), } From a878b3cc3a3bd391d867f71407a1da1594383d81 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Mon, 2 Sep 2024 10:29:04 +0200 Subject: [PATCH 48/48] #11 adjust/add comments for example code --- example/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/src/main.rs b/example/src/main.rs index 53eacb1..bba4c25 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -78,9 +78,10 @@ fn main() -> ! { let sys_clk = SystemClock::default(); sys_clk.initialize(timer); - // Configure GPIO5 as an CS pin + // Configure GPIO13 as an CS pin let pin_cs = pins.gpio13.into_push_pull_output(); + // Enable uart to print to terminal let mut uart = bsp::hal::uart::UartPeripheral::new( pac.UART0, (pins.gpio0.into_function(), pins.gpio1.into_function()),