diff --git a/src/can.rs b/src/can.rs index 3904e83..c3f33d3 100644 --- a/src/can.rs +++ b/src/can.rs @@ -64,6 +64,10 @@ pub enum Error { InvalidRamAddress(u16), /// Payload buffer length not a multiple of 4 bytes InvalidBufferSize(usize), + /// RX Fifo buffer is empty + RxFifoEmpty, + /// TX fifo buffer is full + TxFifoFull, } impl From> for Error { @@ -95,10 +99,16 @@ pub trait CanController { type Error; /// Transmit CAN message - fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::Error>; + /// * `blocking`: if true, function blocks until TX fifo buffer is empty + fn transmit>( + &mut self, + message: &TxMessage, + blocking: bool, + ) -> Result<(), Self::Error>; /// Receive CAN message - fn receive(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error>; + /// * `blocking`: if true, function blocks until RX fifo contains at least one message + fn receive(&mut self, data: &mut [u8; L], blocking: bool) -> Result<(), Self::Error>; /// Set corresponding filter and mask registers fn set_filter_object(&mut self, filter: Filter) -> Result<(), Self::Error>; } @@ -106,18 +116,18 @@ pub trait CanController { impl, CS: OutputPin, CLK: Clock> CanController for MCP2517 { type Error = Error; - fn transmit>(&mut self, message: &TxMessage) -> Result<(), Self::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); - - 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(status_reg_addr)?; - txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + fn transmit>( + &mut self, + message: &TxMessage, + blocking: bool, + ) -> Result<(), Self::Error> { + let fifo_status_reg = Self::fifo_status_register(FIFO_TX_INDEX); + + // Check if TX fifo is full + if blocking { + while !self.fifo_not_full(fifo_status_reg)? {} + } else if !self.fifo_not_full(fifo_status_reg)? { + return Err(Error::TxFifoFull); } // make sure length of payload is consistent with CAN operation mode @@ -143,28 +153,22 @@ impl, CS: OutputPin, CLK: Clock> CanController for MCP2517(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error> { + fn receive(&mut self, data: &mut [u8; L], blocking: bool) -> Result<(), Self::Error> { 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 rx contains at least one message - while !rxfifo_status_reg0.tfnrfnif() { - rxfifo_status_byte0 = self.read_register(fifo_status_reg)?; - rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + // Make sure RX fifo is not empty + if blocking { + while !self.fifo_not_empty(fifo_status_reg)? {} + } else if !self.fifo_not_empty(fifo_status_reg)? { + return Err(Error::RxFifoEmpty); } let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?; @@ -475,6 +479,40 @@ impl, CS: OutputPin, CLK: Clock> MCP2517 { buffer } + /// Returns true if TX fifo is not full + fn fifo_not_full(&mut self, fifo_reg_addr: u16) -> Result> { + let txfifo_status_byte0 = self.read_register(fifo_reg_addr)?; + let txfifo_status_reg0 = FifoStatusReg0::from(txfifo_status_byte0); + + if txfifo_status_reg0.tfnrfnif() { + return Ok(true); + } + Ok(false) + } + + /// Returns true if RX fifo is not empty + fn fifo_not_empty(&mut self, fifo_reg_addr: u16) -> Result> { + let rxfifo_status_byte0 = self.read_register(fifo_reg_addr)?; + let rxfifo_status_reg0 = FifoStatusReg0::from(rxfifo_status_byte0); + + if rxfifo_status_reg0.tfnrfnif() { + return Ok(true); + } + Ok(false) + } + + /// Returns true if `TXREQ` bit of TX fifo is cleared i.e. all messages contained are transmitted + fn txfifo_cleared(&mut self, fifo_ctrl_reg: u16) -> Result> { + // read TX FIFO control register byte 1 + let txfifo_control_byte1 = self.read_register(fifo_ctrl_reg)?; + let txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1); + + if txfifo_control_reg.txreq() { + return Ok(false); + } + Ok(true) + } + /// Returns the configuration register address for the given FIFO index fn fifo_control_register(fifo_index: u8) -> u16 { 0x05C + 12 * (fifo_index as u16 - 1) diff --git a/src/tests/can.rs b/src/tests/can.rs index 6b22863..d86a005 100644 --- a/src/tests/can.rs +++ b/src/tests/can.rs @@ -283,7 +283,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); - mocks.into_controller().transmit(&tx_message_copy).unwrap(); + mocks.into_controller().transmit(&tx_message_copy, true).unwrap(); } #[test] @@ -390,7 +390,7 @@ fn test_transmit_can20_3_bytes() { // 2nd attempt -> txreq cleared -> all messages inside tx fifo have been transmitted mocks.mock_register_read::<0x00>([0x30, 0x69], &mut seq); - mocks.into_controller().transmit(&tx_message_copy).unwrap(); + mocks.into_controller().transmit(&tx_message_copy, true).unwrap(); } #[test] @@ -496,7 +496,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); - mocks.into_controller().transmit(&tx_message_copy).unwrap(); + mocks.into_controller().transmit(&tx_message_copy, true).unwrap(); } #[test] @@ -584,13 +584,49 @@ fn test_receive() { .return_const(Ok(())) .in_sequence(&mut seq); - let result = mocks.into_controller().receive(&mut message_buff); + let result = mocks.into_controller().receive(&mut message_buff, true); assert!(result.is_ok()); assert_eq!(message_buff, [1, 2, 3, 4, 5, 6, 7, 8]); } +#[test] +fn test_receive_fifo_empty() { + let mut mocks = Mocks::default(); + + let mut seq = Sequence::new(); + + let mut message_buff = [0u8; 8]; + + // status register read (fifo not empty flag is not set) + mocks.mock_register_read::<0b0000_0000>([0x30, 0x60], &mut seq); + + let result = mocks.into_controller().receive(&mut message_buff, false); + + assert_eq!(result.unwrap_err(), Error::RxFifoEmpty); +} + +#[test] +fn test_transmit_fifo_full() { + 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::<8> {}; + + let identifier = ExtendedId::new(EXTENDED_ID).unwrap(); + let tx_message = TxMessage::new(msg_type, payload_bytes, Id::Extended(identifier)).unwrap(); + + // mock fifo status register read byte 0 (1st attempt) -> tx fifo full + mocks.mock_register_read::<0b0000_0000>([0x30, 0x6C], &mut seq); + + let res = mocks.into_controller().transmit(&tx_message, false); + + assert_eq!(res.unwrap_err(), Error::TxFifoFull); +} + #[test] fn test_reset_command() { let mut mocks = Mocks::default();