From 9c7d826007466ad687bf41a82d309948294718f6 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 17 Apr 2024 11:34:39 +0200 Subject: [PATCH 01/22] #3 filter/mask config, message reception logic --- src/can.rs | 112 +++++++++++++++++++++++++++++++++++++++-- src/message.rs | 29 ++++++++++- src/registers.rs | 41 ++++++++++++++- src/tests/registers.rs | 2 +- 4 files changed, 176 insertions(+), 8 deletions(-) diff --git a/src/can.rs b/src/can.rs index e3a34bd..ca5c721 100644 --- a/src/can.rs +++ b/src/can.rs @@ -1,8 +1,8 @@ use crate::can::BusError::{CSError, TransferError}; use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout}; use crate::config::{ClockConfiguration, Configuration}; -use crate::message::TxMessage; -use crate::registers::{FifoControlReg1, FifoStatusReg0}; +use crate::message::{RxHeader, TxMessage}; +use crate::registers::{FifoControlReg1, FifoStatusReg0, FilterMaskReg, FilterObjectReg}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; use core::marker::PhantomData; use embedded_hal::blocking::spi::Transfer; @@ -112,6 +112,8 @@ impl, CS: OutputPin, CLK: Clock> Controller { config.fifo.as_tx_register_0(), )?; + self.enable_filter(FIFO_RX_INDEX, 0)?; + self.enable_mode(config.mode.to_operation_mode(), clock, RequestModeTimeout)?; Ok(()) } @@ -158,7 +160,45 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } + /// Enable filter for corresponding RX FIFO + pub fn enable_filter(&mut self, fifo_index: u8, filter_index: u8) -> Result<(), BusError> { + let filter_reg = Self::filter_control_register_byte(filter_index); + // Filter must be disabled to modify FmBP + self.disable_filter(filter_index)?; + self.write_register(filter_reg, fifo_index)?; + // Set FLTENm to enable filter + self.write_register(filter_reg, (1 << 7) & fifo_index)?; + Ok(()) + } + 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, !(1 << 7))?; + Ok(()) + } + /// Set corresponding filter object + pub fn set_filter_object( + &mut self, + filter_index: u8, + filter: FilterObjectReg, + ) -> Result<(), BusError> { + let filter_object_reg = Self::filter_object_register(filter_index); + self.disable_filter(filter_index)?; + let filter_value = u32::from(filter); + self.write32(filter_object_reg, filter_value)?; + Ok(()) + } + /// Set corresponding filter mask + pub fn set_filter_mask( + &mut self, + filter_index: u8, + filter_mask: FilterMaskReg, + ) -> Result<(), BusError> { + let filter_mask_reg = Self::filter_mask_register(filter_index); + let mask_value = u32::from(filter_mask); + self.write32(filter_mask_reg, mask_value)?; + Ok(()) + } /// Writes a single register byte fn write_register(&mut self, register: u16, value: u8) -> Result<(), BusError> { let mut buffer = self.cmd_buffer(register, Operation::Write); @@ -168,6 +208,22 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } + fn write32(&mut self, register: u16, value: u32) -> Result<(), BusError> { + let mut buffer = [0u8; 2]; + let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); + + buffer[0] = (command >> 8) as u8; + buffer[1] = (command & 0xFF) as u8; + let mut value_bytes = value.to_le_bytes(); + + self.pin_cs.set_low().map_err(CSError)?; + self.bus.transfer(&mut buffer).map_err(TransferError)?; + self.bus.transfer(&mut value_bytes).map_err(TransferError)?; + self.pin_cs.set_high().map_err(CSError)?; + + Ok(()) + } + pub fn reset(&mut self) -> Result<(), BusError> { let mut buffer = self.cmd_buffer(0u16, Operation::Reset); self.transfer(&mut buffer[..2])?; @@ -178,7 +234,8 @@ impl, CS: OutputPin, CLK: Clock> Controller { // make sure there is space for new message in TX FIFO // read byte 0 of TX FIFO status register let txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; - let txfifo_status_reg0 = FifoStatusReg0::from_bytes([txfifo_status_byte0]); + let 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() {} @@ -199,13 +256,34 @@ impl, CS: OutputPin, CLK: Clock> Controller { // read TX FIFO control register byte 1 let txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; - let txfifo_control_reg = FifoControlReg1::from_bytes([txfifo_control_byte1]); + let 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() {} Ok(()) } + pub fn receive(&mut self, data: &mut [u8]) -> Result> { + let rxfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_RX_INDEX))?; + let rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + + // block until fifo contains at least one message + while !rxfifo_status_reg0.tfnrfnif() {} + + let address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; + // read message object + self.read_fifo(address as u16, data)?; + + // set uinc + self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; + + let mut header_bytes = [0u8; 8]; + header_bytes.copy_from_slice(&data[..8]); + let message_header = RxHeader::from_bytes(header_bytes); + + Ok(message_header) + } + /// Insert message object in TX FIFO fn write_fifo(&mut self, register: u16, mut message: TxMessage) -> Result<(), Error> { self.verify_ram_address(register, message.length)?; @@ -225,6 +303,20 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_high().map_err(CSError)?; Ok(()) } + /// Read message from RX FIFO + 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); + + buffer[0] = (command >> 8) as u8; + buffer[1] = (command & 0xFF) as u8; + + self.pin_cs.set_low().map_err(CSError)?; + self.bus.transfer(&mut buffer).map_err(TransferError)?; + self.bus.transfer(data).map_err(TransferError)?; + self.pin_cs.set_high().map_err(CSError)?; + Ok(()) + } /// 4-byte register read fn read32(&mut self, register: u16) -> Result> { @@ -292,6 +384,18 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn fifo_user_address_register(fifo_index: u8) -> u16 { 0x64 + 12 * (fifo_index as u16 - 1) } + /// returns the filter control register address byte of the corresponding filter + 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) + } + /// returns the filter mask register address of corresponding filter + fn filter_mask_register(filter_index: u8) -> u16 { + 0x1F4 + 8 * (filter_index as u16) + } } /// Register operation type diff --git a/src/message.rs b/src/message.rs index 1041310..0fe7241 100644 --- a/src/message.rs +++ b/src/message.rs @@ -79,8 +79,6 @@ pub struct TxHeader { pub data_length_code: DLC, } -impl TxHeader {} - /// Transmit Message Object #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxMessage { @@ -134,3 +132,30 @@ impl TxMessage { }) } } +/// Receive message object header +#[bitfield(bits = 64)] +pub struct RxHeader { + // R0 + #[skip] + __: B2, + sid11: bool, + eid: B18, + sid: B11, + // R1 + #[skip] + __: B16, + filhit: B5, + #[skip] + __: B2, + esi: bool, + fdf: bool, + brs: bool, + rtr: bool, + ide: bool, + dlc: DLC, +} +impl Default for RxHeader { + fn default() -> Self { + Self::new() + } +} diff --git a/src/registers.rs b/src/registers.rs index ccc80bc..04e3898 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -14,13 +14,19 @@ impl FifoControlReg3 { self } /// get FIFO size - pub fn get_fifo_size(&self) -> u8 { + pub fn fifo_size(&self) -> u8 { self.fsize() + 1 } } +impl Default for FifoControlReg3 { + fn default() -> Self { + Self::new() + } +} /// Third byte of FIFO Control register #[bitfield] +#[repr(u8)] pub struct FifoControlReg2 { #[skip] __: B1, @@ -30,6 +36,7 @@ pub struct FifoControlReg2 { /// Second byte of FIFO Control register #[bitfield] +#[repr(u8)] pub struct FifoControlReg1 { #[skip] __: B5, @@ -40,6 +47,7 @@ pub struct FifoControlReg1 { /// First byte of FIFO Control register #[bitfield] +#[repr(u8)] pub struct FifoControlReg0 { pub txen: bool, pub rtren: bool, @@ -53,6 +61,7 @@ pub struct FifoControlReg0 { /// Second byte of FIFO Status register #[bitfield] +#[repr(u8)] pub struct FifoStatusReg1 { #[skip] __: B3, @@ -60,6 +69,7 @@ pub struct FifoStatusReg1 { } /// First byte of FIFO Status register #[bitfield] +#[repr(u8)] pub struct FifoStatusReg0 { pub txabt: bool, pub txlarb: bool, @@ -70,3 +80,32 @@ pub struct FifoStatusReg0 { pub tfhrfhif: bool, pub tfnrfnif: bool, } +/// filter mask +#[bitfield] +#[repr(u32)] +pub struct FilterMaskReg { + #[skip] + __: B1, + pub mide: bool, + pub msid11: bool, + pub meid: B18, + pub msid: B11, +} + +impl Default for FilterMaskReg { + fn default() -> Self { + Self::new() + } +} + +/// filter object +#[bitfield] +#[repr(u32)] +pub struct FilterObjectReg { + #[skip] + __: B1, + pub exide: bool, + pub sid11: bool, + pub eid: B18, + pub sid: B11, +} diff --git a/src/tests/registers.rs b/src/tests/registers.rs index c45b1b6..2d3c1b4 100644 --- a/src/tests/registers.rs +++ b/src/tests/registers.rs @@ -28,7 +28,7 @@ fn test_fifocontrolreg3() { .with_plsize(PayloadSize::TwentyFourBytes as u8) .with_fifo_size(32); - assert_eq!(32, fifo_control_reg3.get_fifo_size()); + assert_eq!(32, fifo_control_reg3.fifo_size()); assert_eq!([0b1001_1111], fifo_control_reg3.into_bytes()); } From cc38004540f2791b23376fd24da467119f7a72a4 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 19 Apr 2024 15:52:41 +0200 Subject: [PATCH 02/22] rebase --- src/can.rs | 33 +++++++++++++-------- src/lib.rs | 4 +-- src/message.rs | 6 ++-- src/registers.rs | 16 ++++++----- src/tests/can.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 24 deletions(-) diff --git a/src/can.rs b/src/can.rs index ca5c721..bf1d33c 100644 --- a/src/can.rs +++ b/src/can.rs @@ -49,7 +49,7 @@ pub enum ConfigError { /// Device did not enter given request mode within timeout of 2 ms RequestModeTimeout, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Error { ConfigErr(ConfigError), BusErr(BusError), @@ -233,11 +233,15 @@ 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 txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; - let txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + + let mut txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; + 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() {} + while !txfifo_status_reg0.tfnrfnif() { + txfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_TX_INDEX))?; + txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + } // make sure length of payload is consistent with CAN operation mode let operation_status = self.read_operation_status()?; @@ -255,11 +259,15 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.write_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1, 0x03)?; // read TX FIFO control register byte 1 - let txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; - let txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); + + let mut txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; + 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() {} + while txfifo_control_reg.txreq() { + txfifo_control_byte1 = self.read_register(Self::fifo_control_register(FIFO_TX_INDEX) + 1)?; + txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); + } Ok(()) } @@ -288,15 +296,15 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn write_fifo(&mut self, register: u16, mut message: TxMessage) -> Result<(), Error> { self.verify_ram_address(register, message.length)?; - let mut buffer = [0u8; 2]; + let mut buffer = [0u8; 10]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); 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.header.into_bytes()).map_err(TransferError)?; self.bus .transfer(&mut message.payload[..message.length]) .map_err(TransferError)?; @@ -328,18 +336,19 @@ impl, CS: OutputPin, CLK: Clock> Controller { buffer[1] = (command & 0xFF) as u8; self.pin_cs.set_low().map_err(CSError)?; - self.bus.transfer(&mut buffer).map_err(TransferError)?; + let result = 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(&buffer[2..]); + data_read.clone_from_slice(&result[2..]); + // reverse so that msb byte of register is at the first index 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 { + if addr < 0x400 || (addr + (data_length as u16)) > 0xBFF { return Err(Error::InvalidRamAddress(addr)); } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index bbdb710..a05a99b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,9 +6,9 @@ pub mod can; pub mod config; pub mod status; -mod message; +pub mod message; #[cfg(test)] pub(crate) mod mocks; -mod registers; +pub mod registers; #[cfg(test)] mod tests; diff --git a/src/message.rs b/src/message.rs index 0fe7241..0bcf706 100644 --- a/src/message.rs +++ b/src/message.rs @@ -8,7 +8,7 @@ pub const MAX_PAYLOAD_CAN_2_0: usize = 8; pub const MAX_PAYLOAD_CAN_FD: usize = 64; /// Data length code -#[derive(BitfieldSpecifier, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(BitfieldSpecifier, Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] #[bits = 4] pub enum DLC { Zero, @@ -59,7 +59,7 @@ impl DLC { /// Transmit message object header #[bitfield(bits = 64)] -#[derive(BitfieldSpecifier, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(BitfieldSpecifier, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxHeader { // T0 #[skip] @@ -80,7 +80,7 @@ pub struct TxHeader { } /// Transmit Message Object -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxMessage { pub(crate) header: TxHeader, pub(crate) payload: [u8; MAX_PAYLOAD_CAN_FD], diff --git a/src/registers.rs b/src/registers.rs index 04e3898..00eebea 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -1,7 +1,8 @@ use modular_bitfield_msb::prelude::*; - /// Fourth byte of FIFO Control register #[bitfield] +#[derive(Default)] +#[repr(u8)] pub struct FifoControlReg3 { pub plsize: B3, fsize: B5, @@ -9,7 +10,7 @@ pub struct FifoControlReg3 { impl FifoControlReg3 { /// set FIFO size (number of messages 1-32) pub fn with_fifo_size(mut self, value: u8) -> Self { - let size = value.max(1).min(32); + let size = value.clamp(1, 32); self.set_fsize(size - 1); self } @@ -18,14 +19,10 @@ impl FifoControlReg3 { self.fsize() + 1 } } -impl Default for FifoControlReg3 { - fn default() -> Self { - Self::new() - } -} /// Third byte of FIFO Control register #[bitfield] +#[derive(Default)] #[repr(u8)] pub struct FifoControlReg2 { #[skip] @@ -36,6 +33,7 @@ pub struct FifoControlReg2 { /// Second byte of FIFO Control register #[bitfield] +#[derive(Default)] #[repr(u8)] pub struct FifoControlReg1 { #[skip] @@ -47,6 +45,7 @@ pub struct FifoControlReg1 { /// First byte of FIFO Control register #[bitfield] +#[derive(Default)] #[repr(u8)] pub struct FifoControlReg0 { pub txen: bool, @@ -61,6 +60,7 @@ pub struct FifoControlReg0 { /// Second byte of FIFO Status register #[bitfield] +#[derive(Default)] #[repr(u8)] pub struct FifoStatusReg1 { #[skip] @@ -68,7 +68,9 @@ pub struct FifoStatusReg1 { pub fifoci: B5, } /// First byte of FIFO Status register + #[bitfield] +#[derive(Default)] #[repr(u8)] pub struct FifoStatusReg0 { pub txabt: bool, diff --git a/src/tests/can.rs b/src/tests/can.rs index 8beb56c..6595174 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -3,9 +3,12 @@ use crate::config::{ ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, }; +use crate::message::TxMessage; use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; +use embedded_can::{ExtendedId, Id}; +use mockall::mock; #[test] fn test_configure_correct() { @@ -144,6 +147,59 @@ fn test_configure_mode_timeout() { ); } +const EXTENDED_ID: u32 = 0x14C92A2B; +#[test] +fn test_transmit() { + let mut mocks = Mocks::default(); + + let message_payload: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; + + let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); + 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 read operation status + mocks.mock_register_read::<0b1100_0000>([0x30, 0x2]); + + // mock fifo user address register read (reading 32 bits) --> address = 0x4A2 + mocks.mock_read32::<0x00_00_04_A2>([0x30, 0x70]); + + // 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]) + }); + // transfer payload + mocks.bus.expect_transfer().times(1).returning(move |data| { + assert_eq!(message_payload, data); + Ok(&[0u8; 8]) + }); + + // 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(())); + + // mock reading of fifo control register + mocks.mock_register_read::<0x00>([0x30, 0x69]); + + let result = mocks.into_controller().transmit(tx_message_copy); + assert_eq!(result, Ok(())); +} + #[test] fn test_request_mode_timeout() { let clock = TestClock::new(vec![ @@ -359,6 +415,24 @@ impl Mocks { Ok(&[0x0, 0x0, REG]) }); + self.pin_cs.expect_set_low().times(1).return_const(Ok(())); + self.pin_cs.expect_set_high().times(1).return_const(Ok(())); + } + pub fn mock_read32(&mut self, expected_command: [u8; 2]) { + 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(())); } From e87527bf60d04a69eef99705126e0bdafe85f8fc Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 19 Apr 2024 16:09:48 +0200 Subject: [PATCH 03/22] rebasing --- Cargo.toml | 1 + src/lib.rs | 1 + src/tests/message.rs | 23 +++++++++++++++++++++++ src/tests/registers.rs | 2 ++ 4 files changed, 27 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 83f2cd6..f6a9a28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ readme = "README.md" documentation = "https://docs.rs/mcp2517" [dependencies] +bytes = "1.6.0" embedded-can = "0.4.1" embedded-hal = { version = "0.2.7", features = ["unproven"] } embedded-time = "0.12.1" diff --git a/src/lib.rs b/src/lib.rs index a05a99b..adfcbb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), no_std)] +#![allow(dead_code)] extern crate alloc; diff --git a/src/tests/message.rs b/src/tests/message.rs index dde69a7..e4a4f3f 100644 --- a/src/tests/message.rs +++ b/src/tests/message.rs @@ -8,40 +8,63 @@ const STANDARD_ID: u16 = 0x6A5; #[test] fn test_extended_id() { let data = [0u8; 8]; + let extended_id = ExtendedId::new(EXTENDED_ID).unwrap(); + let message = TxMessage::new(Id::Extended(extended_id), &data, 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 data = [0u8; 8]; + let standard_id = StandardId::new(STANDARD_ID).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), &data, 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 data = [0u8; 13]; + let standard_id = StandardId::new(STANDARD_ID).unwrap(); + let message = TxMessage::new(Id::Standard(standard_id), &data, 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(); + assert_eq!(header_bytes[7], 0b1000_1010); } #[test] fn test_dlc_error() { let data_2_0 = [0u8; 10]; + let data_fd = [0u8; 65]; + 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_fd = TxMessage::new(Id::Standard(standard_id), &data_fd, true, false); + assert_eq!(message_2_0.unwrap_err(), DLCError::InvalidLength(10)); + assert_eq!(message_fd.unwrap_err(), DLCError::InvalidLength(65)); } diff --git a/src/tests/registers.rs b/src/tests/registers.rs index 2d3c1b4..4c337d5 100644 --- a/src/tests/registers.rs +++ b/src/tests/registers.rs @@ -4,6 +4,7 @@ use crate::registers::*; fn test_fifocontrolreg0() { assert_eq!([0b1000_0000], FifoControlReg0::new().with_txen(true).into_bytes()); } + #[test] fn test_fifocontrolreg1() { assert_eq!( @@ -22,6 +23,7 @@ fn test_fifocontrolreg2() { .into_bytes() ); } + #[test] fn test_fifocontrolreg3() { let fifo_control_reg3 = FifoControlReg3::new() From 95b2d126d228e63ded174d2c7e7424c56602569d Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 19 Apr 2024 20:21:50 +0200 Subject: [PATCH 04/22] #2 use bytes crate for payload buffer --- src/can.rs | 7 ++++--- src/config.rs | 2 +- src/message.rs | 13 +++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/can.rs b/src/can.rs index bf1d33c..8c9cdef 100644 --- a/src/can.rs +++ b/src/can.rs @@ -305,9 +305,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 message.payload[..message.length]) - .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/config.rs b/src/config.rs index 964b44a..106d437 100644 --- a/src/config.rs +++ b/src/config.rs @@ -205,7 +205,7 @@ impl FifoConfiguration { /// Limits the size to valid values fn limit_size(size: u8) -> u8 { - size.max(1).min(32) + size.clamp(1, 32) } } diff --git a/src/message.rs b/src/message.rs index 0bcf706..97dda84 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,3 +1,4 @@ +use bytes::BytesMut; use embedded_can::Id; use log::debug; use modular_bitfield_msb::prelude::*; @@ -59,7 +60,7 @@ impl DLC { /// Transmit message object header #[bitfield(bits = 64)] -#[derive(BitfieldSpecifier, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(BitfieldSpecifier, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)] pub struct TxHeader { // T0 #[skip] @@ -80,10 +81,10 @@ pub struct TxHeader { } /// Transmit Message Object -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct TxMessage { pub(crate) header: TxHeader, - pub(crate) payload: [u8; MAX_PAYLOAD_CAN_FD], + pub(crate) buff: BytesMut, pub(crate) length: usize, } @@ -108,8 +109,8 @@ impl TxMessage { // make sure length divisible by four (word size) let length = (payload_length + 3) & !3; - let mut buffer = [0u8; MAX_PAYLOAD_CAN_FD]; - buffer[..payload_length].copy_from_slice(data); + let mut bytes = BytesMut::with_capacity(payload_length); + bytes.extend_from_slice(data); while let Err(DLCError::InvalidLength(_)) = DLC::from_length(payload_length) { payload_length += 1; @@ -127,7 +128,7 @@ impl TxMessage { } Ok(TxMessage { header, - payload: buffer, + buff: bytes, length, }) } From 96cf96244fab9d2bae8f71263db35d4dc4603bec Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Fri, 19 Apr 2024 22:53:14 +0200 Subject: [PATCH 05/22] #2 added reset cmd test --- src/can.rs | 2 +- src/tests/can.rs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/can.rs b/src/can.rs index 8c9cdef..d3af584 100644 --- a/src/can.rs +++ b/src/can.rs @@ -226,7 +226,7 @@ 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[..2])?; + self.transfer(&mut buffer)?; Ok(()) } diff --git a/src/tests/can.rs b/src/tests/can.rs index 6595174..6b15d44 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -197,9 +197,22 @@ fn test_transmit() { mocks.mock_register_read::<0x00>([0x30, 0x69]); let result = mocks.into_controller().transmit(tx_message_copy); - assert_eq!(result, Ok(())); + assert!(result.is_ok()); } +#[test] +fn test_reset_command() { + let mut mocks = Mocks::default(); + 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(())); + + let result = mocks.into_controller().reset(); + assert!(result.is_ok()); +} #[test] fn test_request_mode_timeout() { let clock = TestClock::new(vec![ From e9d8c303cfa395b6b57d3c7964b1eed1cde31ff0 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Mon, 22 Apr 2024 11:07:34 +0200 Subject: [PATCH 06/22] #2 formatting --- src/can.rs | 1 + src/tests/can.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index d3af584..e99e4e2 100644 --- a/src/can.rs +++ b/src/can.rs @@ -390,6 +390,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn fifo_status_register(fifo_index: u8) -> u16 { 0x60 + 12 * (fifo_index as u16 - 1) } + /// Returns the address of fifo user address register for the given index fn fifo_user_address_register(fifo_index: u8) -> u16 { 0x64 + 12 * (fifo_index as u16 - 1) diff --git a/src/tests/can.rs b/src/tests/can.rs index 6b15d44..c69e5a1 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -8,7 +8,6 @@ use crate::mocks::{MockPin, MockSPIBus, TestClock}; use crate::status::OperationMode; use alloc::vec; use embedded_can::{ExtendedId, Id}; -use mockall::mock; #[test] fn test_configure_correct() { From 299a19aa77c33a70c9cfd4b08e96a9d6ff63643f Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Mon, 22 Apr 2024 12:06:54 +0200 Subject: [PATCH 07/22] #3 modified tests to include filter enable --- src/can.rs | 9 +++++---- src/tests/can.rs | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/can.rs b/src/can.rs index e99e4e2..9dca33a 100644 --- a/src/can.rs +++ b/src/can.rs @@ -162,18 +162,19 @@ impl, CS: OutputPin, CLK: Clock> Controller { } /// Enable filter for corresponding RX FIFO pub fn enable_filter(&mut self, fifo_index: u8, filter_index: u8) -> Result<(), BusError> { - let filter_reg = Self::filter_control_register_byte(filter_index); + let filter_control_reg = Self::filter_control_register_byte(filter_index); // Filter must be disabled to modify FmBP self.disable_filter(filter_index)?; - self.write_register(filter_reg, fifo_index)?; + // Write index of fifo where the message that matches the filter is stored in + self.write_register(filter_control_reg, fifo_index)?; // Set FLTENm to enable filter - self.write_register(filter_reg, (1 << 7) & fifo_index)?; + self.write_register(filter_control_reg, (1 << 7) | fifo_index)?; Ok(()) } 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, !(1 << 7))?; + self.write_register(filter_reg, 0x00)?; Ok(()) } /// Set corresponding filter object diff --git a/src/tests/can.rs b/src/tests/can.rs index c69e5a1..4776f6c 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -68,6 +68,25 @@ fn test_configure_correct() { Ok(&[0x0, 0x0, 0x0]) }); + // Enable filter for RX Fifo + // filter disable + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0x00], data); + Ok(&[0u8, 0u8, 0u8]) + }); + + // write F02BP + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0x01], data); + Ok(&[0u8, 0u8, 0u8]) + }); + + // enable filter + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0b1000_0001], data); + Ok(&[0u8, 0u8, 0u8]) + }); + // Request normal CAN 2.0B mode bus.expect_transfer().times(1).returning(move |data| { assert_eq!([0x20, 0x3, 0b0000_1110], data); @@ -81,8 +100,8 @@ fn test_configure_correct() { }); let mut pin_cs = MockPin::new(); - pin_cs.expect_set_low().times(10).return_const(Ok(())); - pin_cs.expect_set_high().times(10).return_const(Ok(())); + pin_cs.expect_set_low().times(13).return_const(Ok(())); + pin_cs.expect_set_high().times(13).return_const(Ok(())); let mut controller = Controller::new(bus, pin_cs); controller @@ -236,6 +255,25 @@ fn test_request_mode_timeout() { // Writing configuration registers bus.expect_transfer().times(5).returning(move |_| Ok(&[0x0, 0x0, 0x0])); + // Enable filter for RX Fifo + // filter disable + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0x00], data); + Ok(&[0u8, 0u8, 0u8]) + }); + + // write F02BP + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0x01], data); + Ok(&[0u8, 0u8, 0u8]) + }); + + // enable filter + bus.expect_transfer().times(1).returning(move |data| { + assert_eq!([0x21, 0xD0, 0b1000_0001], data); + Ok(&[0u8, 0u8, 0u8]) + }); + // Request normal CAN FD mode bus.expect_transfer().times(1).returning(move |data| { assert_eq!([0x20, 0x3, 0b0000_1000], data); @@ -249,8 +287,8 @@ fn test_request_mode_timeout() { }); let mut pin_cs = MockPin::new(); - pin_cs.expect_set_low().times(11).return_const(Ok(())); - pin_cs.expect_set_high().times(11).return_const(Ok(())); + pin_cs.expect_set_low().times(14).return_const(Ok(())); + pin_cs.expect_set_high().times(14).return_const(Ok(())); let mut controller = Controller::new(bus, pin_cs); assert_eq!( From be90b32c1798cbc0f3b4ff0a8e5d0c07b63edf48 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 23 Apr 2024 12:51:51 +0200 Subject: [PATCH 08/22] #3 added filter object tests --- src/can.rs | 71 +++++++++++++------------- src/filter.rs | 72 ++++++++++++++++++++++++++ src/lib.rs | 1 + src/message.rs | 51 ++++++++++++++----- src/registers.rs | 3 ++ src/tests/can.rs | 130 +++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 276 insertions(+), 52 deletions(-) create mode 100644 src/filter.rs diff --git a/src/can.rs b/src/can.rs index 79273d1..e53b909 100644 --- a/src/can.rs +++ b/src/can.rs @@ -1,6 +1,7 @@ use crate::can::BusError::{CSError, TransferError}; use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout}; use crate::config::{ClockConfiguration, Configuration}; +use crate::filter::Filter; use crate::message::{RxHeader, TxMessage}; use crate::registers::{FifoControlReg1, FifoStatusReg0, FilterMaskReg, FilterObjectReg}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; @@ -161,6 +162,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } + /// Enable filter for corresponding RX FIFO pub fn enable_filter(&mut self, fifo_index: u8, filter_index: u8) -> Result<(), BusError> { let filter_control_reg = Self::filter_control_register_byte(filter_index); @@ -173,34 +175,29 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } + /// Disable corresponding filter 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(()) } - /// Set corresponding filter object - pub fn set_filter_object( - &mut self, - filter_index: u8, - filter: FilterObjectReg, - ) -> Result<(), BusError> { - let filter_object_reg = Self::filter_object_register(filter_index); - self.disable_filter(filter_index)?; - let filter_value = u32::from(filter); + + /// Set corresponding filter and mask registers + pub fn set_filter_object(&mut self, filter: Filter) -> Result<(), BusError> { + let filter_object_reg = Self::filter_object_register(filter.index); + let filter_mask_reg = Self::filter_mask_register(filter.index); + + self.disable_filter(filter.index)?; + + let filter_value = u32::from(filter.filter_bits); + let mask_value = u32::from(filter.mask_bits); + self.write32(filter_object_reg, filter_value)?; - Ok(()) - } - /// Set corresponding filter mask - pub fn set_filter_mask( - &mut self, - filter_index: u8, - filter_mask: FilterMaskReg, - ) -> Result<(), BusError> { - let filter_mask_reg = Self::filter_mask_register(filter_index); - let mask_value = u32::from(filter_mask); self.write32(filter_mask_reg, mask_value)?; + Ok(()) } + /// Writes a single register byte fn write_register(&mut self, register: u16, value: u8) -> Result<(), BusError> { let mut buffer = self.cmd_buffer(register, Operation::Write); @@ -211,16 +208,17 @@ impl, CS: OutputPin, CLK: Clock> Controller { } fn write32(&mut self, register: u16, value: u32) -> Result<(), BusError> { - let mut buffer = [0u8; 2]; + let mut buffer = [0u8; 6]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); + let value_bytes = value.to_le_bytes(); + buffer[0] = (command >> 8) as u8; buffer[1] = (command & 0xFF) as u8; - let mut value_bytes = value.to_le_bytes(); + buffer[2..].copy_from_slice(&value_bytes); self.pin_cs.set_low().map_err(CSError)?; self.bus.transfer(&mut buffer).map_err(TransferError)?; - self.bus.transfer(&mut value_bytes).map_err(TransferError)?; self.pin_cs.set_high().map_err(CSError)?; Ok(()) @@ -275,25 +273,25 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } - pub fn receive(&mut self, data: &mut [u8]) -> Result> { - let rxfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_RX_INDEX))?; - let rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + /// 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 mut rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); // block until fifo contains at least one message - while !rxfifo_status_reg0.tfnrfnif() {} + while !rxfifo_status_reg0.tfnrfnif() { + rxfifo_status_byte0 = self.read_register(Self::fifo_status_register(FIFO_RX_INDEX))?; + rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + } let address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; // read message object - self.read_fifo(address as u16, data)?; + let message = self.read_fifo(address as u16, data)?; // set uinc self.write_register(Self::fifo_control_register(FIFO_RX_INDEX) + 1, 1)?; - let mut header_bytes = [0u8; 8]; - header_bytes.copy_from_slice(&data[..8]); - let message_header = RxHeader::from_bytes(header_bytes); - - Ok(message_header) + Ok(message) } /// Insert message object in TX FIFO @@ -313,8 +311,9 @@ impl, CS: OutputPin, CLK: Clock> Controller { self.pin_cs.set_high().map_err(CSError)?; Ok(()) } + /// Read message from RX FIFO - fn read_fifo(&mut self, register: u16, data: &mut [u8]) -> Result<(), Error> { + fn read_fifo<'a>(&mut self, register: u16, data: &'a mut [u8]) -> Result<&'a [u8], Error> { let mut buffer = [0u8; 2]; let command = (register & 0x0FFF) | ((Operation::Read as u16) << 12); @@ -323,9 +322,9 @@ 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(()) + Ok(res) } /// 4-byte register read @@ -396,6 +395,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn fifo_user_address_register(fifo_index: u8) -> u16 { 0x64 + 12 * (fifo_index as u16 - 1) } + /// returns the filter control register address byte of the corresponding filter fn filter_control_register_byte(filter_index: u8) -> u16 { 0x1D0 + filter_index as u16 @@ -404,6 +404,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { fn filter_object_register(filter_index: u8) -> u16 { 0x1F0 + 8 * (filter_index as u16) } + /// returns the filter mask register address of corresponding filter fn filter_mask_register(filter_index: u8) -> u16 { 0x1F4 + 8 * (filter_index as u16) diff --git a/src/filter.rs b/src/filter.rs new file mode 100644 index 0000000..2dcd1d1 --- /dev/null +++ b/src/filter.rs @@ -0,0 +1,72 @@ +use crate::message::{EXTENDED_IDENTIFIER_MASK, STANDARD_IDENTIFIER_MASK}; +use crate::registers::{FilterMaskReg, FilterObjectReg}; +use embedded_can::{ExtendedId, Id, StandardId}; + +/// Struct representing a filter object +#[derive(Default, Debug)] +pub struct Filter { + /// filter & mask index + pub index: u8, + /// mask register bitfield + pub mask_bits: FilterMaskReg, + /// filter register bitfield + pub filter_bits: FilterObjectReg, +} + +impl Filter { + /// Create new filter from embedded_can::Id and index, no mask + pub fn new(identifier: Id, index: u8) -> Option { + if index > 31 { + return None; + } + + let mut filter = Self::default(); + + filter.set_id(identifier); + filter.index = index; + + Some(filter) + } + + /// Set mask for extended Id + pub fn set_mask_extended_id(&mut self, mask: u32) { + self.set_mask(Id::Extended(ExtendedId::new(mask).unwrap())); + } + + /// Set mask for standard Id + pub fn set_mask_standard_id(&mut self, mask: u16) { + self.set_mask(Id::Standard(StandardId::new(mask).unwrap())); + } + + /// Set filter and mask so that only messages with Standard Id match + pub fn match_standard_only(&mut self) { + self.mask_bits.set_mide(true); + self.filter_bits.set_exide(false); + } + + /// Set filter and mask so that only messages with Extended Id match + pub fn match_extended_only(&mut self) { + self.mask_bits.set_mide(true); + self.filter_bits.set_exide(true); + } + + fn set_id(&mut self, identifier: Id) { + match identifier { + Id::Standard(sid) => self.filter_bits.set_sid(sid.as_raw()), + Id::Extended(eid) => { + self.filter_bits.set_eid(eid.as_raw() & EXTENDED_IDENTIFIER_MASK); + self.filter_bits.set_sid((eid.as_raw() >> 18) as u16 & STANDARD_IDENTIFIER_MASK); + } + } + } + + fn set_mask(&mut self, identifier: Id) { + match identifier { + Id::Standard(sid) => self.mask_bits.set_msid(sid.as_raw()), + Id::Extended(eid) => { + self.mask_bits.set_meid(eid.as_raw() & EXTENDED_IDENTIFIER_MASK); + self.mask_bits.set_msid((eid.as_raw() >> 18) as u16 & STANDARD_IDENTIFIER_MASK); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index adfcbb2..7a25fa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod can; pub mod config; pub mod status; +pub mod filter; pub mod message; #[cfg(test)] pub(crate) mod mocks; diff --git a/src/message.rs b/src/message.rs index 97dda84..11ccbda 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,5 +1,5 @@ use bytes::BytesMut; -use embedded_can::Id; +use embedded_can::{ExtendedId, Id, StandardId}; use log::debug; use modular_bitfield_msb::prelude::*; @@ -133,30 +133,53 @@ impl TxMessage { }) } } + /// Receive message object header #[bitfield(bits = 64)] +#[derive(Default, PartialEq, Eq, Debug)] +#[repr(u64)] pub struct RxHeader { // R0 #[skip] __: B2, sid11: bool, - eid: B18, - sid: B11, - // R1 + extended_identifier: B18, + standard_identifier: B11, #[skip] __: B16, - filhit: B5, + filter_hit: B5, #[skip] __: B2, - esi: bool, - fdf: bool, - brs: bool, - rtr: bool, - ide: bool, - dlc: DLC, + error_status_indicator: bool, + fd_frame: bool, + bit_rate_switch: bool, + remote_transmission_request: bool, + identifier_extension_flag: bool, + data_length_code: DLC, } -impl Default for RxHeader { - fn default() -> Self { - Self::new() + +impl RxHeader { + fn get_id(&self) -> Id { + if self.identifier_extension_flag() { + let id = ((self.standard_identifier() as u32) << 18) | (self.extended_identifier()); + let extended_id = ExtendedId::new(id); + Id::Extended(extended_id.unwrap()) + } else { + let id = StandardId::new(self.standard_identifier()); + Id::Standard(id.unwrap()) + } + } + #[cfg(test)] + pub fn new_test_cfg(identifier: Id) -> Self { + match identifier { + Id::Extended(eid) => Self::new() + .with_data_length_code(DLC::Eight) + .with_standard_identifier((eid.as_raw() >> 18) as u16 & STANDARD_IDENTIFIER_MASK) + .with_extended_identifier(eid.as_raw() & EXTENDED_IDENTIFIER_MASK) + .with_identifier_extension_flag(true), + Id::Standard(sid) => Self::new() + .with_data_length_code(DLC::Eight) + .with_standard_identifier(sid.as_raw()), + } } } diff --git a/src/registers.rs b/src/registers.rs index 05bb325..a6432a0 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)] @@ -84,6 +85,7 @@ pub struct FifoStatusReg0 { } /// filter mask #[bitfield] +#[derive(Default, Debug, Eq, PartialEq)] #[repr(u32)] pub struct FilterMaskReg { #[skip] @@ -96,6 +98,7 @@ pub struct FilterMaskReg { /// filter object #[bitfield] +#[derive(Default, Debug, Eq, PartialEq)] #[repr(u32)] pub struct FilterObjectReg { #[skip] diff --git a/src/tests/can.rs b/src/tests/can.rs index 4776f6c..d7b3989 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -3,11 +3,13 @@ use crate::config::{ ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize, RequestMode, RetransmissionAttempts, SystemClockDivisor, }; -use crate::message::TxMessage; +use crate::filter::Filter; +use crate::message::{RxHeader, TxMessage, STANDARD_IDENTIFIER_MASK}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; +use crate::registers::{FilterMaskReg, FilterObjectReg}; use crate::status::OperationMode; use alloc::vec; -use embedded_can::{ExtendedId, Id}; +use embedded_can::{ExtendedId, Id, StandardId}; #[test] fn test_configure_correct() { @@ -165,7 +167,9 @@ fn test_configure_mode_timeout() { ); } -const EXTENDED_ID: u32 = 0x14C92A2B; +const EXTENDED_ID: u32 = 0x14C92A2B; //0b000(1_0100_1100_10)(01_0010_1010_0010_1011) +const STANDARD_ID: u16 = 0x6A5; + #[test] fn test_transmit() { let mut mocks = Mocks::default(); @@ -218,6 +222,51 @@ fn test_transmit() { assert!(result.is_ok()); } +#[test] +fn test_receive() { + let mut mocks = Mocks::default(); + + let id = ExtendedId::new(EXTENDED_ID).unwrap(); + + // 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]); + + // user address register read + mocks.mock_read32::<0x00_00_04_7C>([0x30, 0x64]); + + // 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 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]) + }); + + // 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(())); + + let result = mocks.into_controller().receive(&mut message_buff).unwrap(); + + assert_eq!(result[..8], message_header.into_bytes()); + assert_eq!(result[8..], [1, 2, 3, 4, 5, 6, 7, 8]); +} + #[test] fn test_reset_command() { let mut mocks = Mocks::default(); @@ -231,6 +280,81 @@ fn test_reset_command() { let result = mocks.into_controller().reset(); 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![ From acc4bc11950b8cd4dbffaa992217859db91b5bf7 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 23 Apr 2024 12:52:41 +0200 Subject: [PATCH 09/22] #3 formatting --- src/can.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/can.rs b/src/can.rs index e53b909..354e34e 100644 --- a/src/can.rs +++ b/src/can.rs @@ -166,10 +166,13 @@ impl, CS: OutputPin, CLK: Clock> Controller { /// Enable filter for corresponding RX FIFO pub fn enable_filter(&mut self, fifo_index: u8, filter_index: u8) -> Result<(), BusError> { let filter_control_reg = Self::filter_control_register_byte(filter_index); + // Filter must be disabled to modify FmBP self.disable_filter(filter_index)?; + // Write index of fifo where the message that matches the filter is stored in self.write_register(filter_control_reg, fifo_index)?; + // Set FLTENm to enable filter self.write_register(filter_control_reg, (1 << 7) | fifo_index)?; Ok(()) From ded2fc9626afaf97eb3205f1d6d0be8909e3019c Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 23 Apr 2024 12:54:33 +0200 Subject: [PATCH 10/22] #3 rmv unused imports --- src/can.rs | 4 ++-- src/tests/can.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/can.rs b/src/can.rs index 354e34e..a19826a 100644 --- a/src/can.rs +++ b/src/can.rs @@ -2,8 +2,8 @@ use crate::can::BusError::{CSError, TransferError}; use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout}; use crate::config::{ClockConfiguration, Configuration}; use crate::filter::Filter; -use crate::message::{RxHeader, TxMessage}; -use crate::registers::{FifoControlReg1, FifoStatusReg0, FilterMaskReg, FilterObjectReg}; +use crate::message::TxMessage; +use crate::registers::{FifoControlReg1, FifoStatusReg0}; use crate::status::{OperationMode, OperationStatus, OscillatorStatus}; use core::marker::PhantomData; use embedded_hal::blocking::spi::Transfer; diff --git a/src/tests/can.rs b/src/tests/can.rs index d7b3989..13bfd29 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -4,9 +4,8 @@ use crate::config::{ RetransmissionAttempts, SystemClockDivisor, }; use crate::filter::Filter; -use crate::message::{RxHeader, TxMessage, STANDARD_IDENTIFIER_MASK}; +use crate::message::{RxHeader, TxMessage}; use crate::mocks::{MockPin, MockSPIBus, TestClock}; -use crate::registers::{FilterMaskReg, FilterObjectReg}; use crate::status::OperationMode; use alloc::vec; use embedded_can::{ExtendedId, Id, StandardId}; From b37a6ba331b121611f83f6ee2e531c3c5426ecc4 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 23 Apr 2024 13:01:51 +0200 Subject: [PATCH 11/22] #3 comments --- src/can.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/can.rs b/src/can.rs index a19826a..37cbcda 100644 --- a/src/can.rs +++ b/src/can.rs @@ -210,6 +210,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(()) } + /// 4-byte SFR write fn write32(&mut self, register: u16, value: u32) -> Result<(), BusError> { let mut buffer = [0u8; 6]; let command = (register & 0x0FFF) | ((Operation::Write as u16) << 12); @@ -330,7 +331,7 @@ impl, CS: OutputPin, CLK: Clock> Controller { Ok(res) } - /// 4-byte register read + /// 4-byte SFR read 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]; From 2c750080a330df3675c70fe84cbadf437bdd1faa Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Wed, 24 Apr 2024 12:21:12 +0200 Subject: [PATCH 12/22] #3 build for thmbv7m-none-eabi --- Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6a9a28..ea1cc0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,14 +12,16 @@ readme = "README.md" documentation = "https://docs.rs/mcp2517" [dependencies] -bytes = "1.6.0" +bytes = { version = "1", 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] mockall = "0.11.0" + + From 5e4bacfcfc3e799e2a246d0661d044bc252ec7d4 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 12:47:49 +0200 Subject: [PATCH 13/22] #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 14/22] #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 15/22] #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 afc657db51d94ceaab76d7e20e1b0072fb00ccf1 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 28 May 2024 15:35:51 +0200 Subject: [PATCH 16/22] #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 17/22] #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 18/22] #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 5048b35fbe8e6c42f26545fb66b36dbe1b914f69 Mon Sep 17 00:00:00 2001 From: Hussein Hazem Date: Tue, 11 Jun 2024 11:17:05 +0200 Subject: [PATCH 19/22] #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 20/22] #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 21/22] #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 f08997fcb65ba95c207bd851371354f1d176adce Mon Sep 17 00:00:00 2001 From: Marius Meissner Date: Thu, 20 Jun 2024 16:55:21 +0200 Subject: [PATCH 22/22] #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]