Skip to content

Commit

Permalink
Merge pull request #30 from atlas-aero/29-allow-non-blocking-transmit…
Browse files Browse the repository at this point in the history
…-and-receive

29 allow non blocking transmit and receive
  • Loading branch information
marius-meissner authored Oct 16, 2024
2 parents 6c6181f + c648d76 commit 18d68c0
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 40 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/qa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: QA

on:
push:
branches:
- main
pull_request:
branches:
- main

env:
CARGO_TERM_COLOR: always
Expand Down
4 changes: 2 additions & 2 deletions example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,12 @@ fn main() -> ! {
let mut receive_buffer = [0u8; 8];

loop {
can_controller.transmit(&can_message).unwrap();
can_controller.transmit(&can_message, true).unwrap();
uart.write_raw(b"can message sent\n\r").unwrap();

timer.delay_ms(500);

match can_controller.receive(&mut receive_buffer) {
match can_controller.receive(&mut receive_buffer, true) {
Ok(_) => {
uart.write_fmt(format_args!("can message received\n\r")).unwrap();

Expand Down
87 changes: 57 additions & 30 deletions src/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ pub enum Error<B, CS> {
InvalidRamAddress(u16),
/// Payload buffer length not a multiple of 4 bytes
InvalidBufferSize(usize),
/// RX fifo empty error
RxFifoEmptyErr,
/// TX fifo buffer full error
TxFifoFullErr,
}

impl<B, CS> From<BusError<B, CS>> for Error<B, CS> {
Expand Down Expand Up @@ -115,29 +119,35 @@ pub trait CanController {
type Error;

/// Transmit CAN message
fn transmit<const L: usize, T: MessageType<L>>(&mut self, message: &TxMessage<T, L>) -> Result<(), Self::Error>;
/// * `blocking`: if true, function blocks until TX fifo buffer is empty and till TXREQ bit is cleared
fn transmit<const L: usize, T: MessageType<L>>(
&mut self,
message: &TxMessage<T, L>,
blocking: bool,
) -> Result<(), Self::Error>;

/// Receive CAN message
fn receive<const L: usize>(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error>;
/// * `blocking`: if true, function blocks until RX fifo contains at least one message
fn receive<const L: usize>(&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>;
}

impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> CanController for MCP2517<B, CS, CLK> {
type Error = Error<B::Error, CS::Error>;

fn transmit<const L: usize, T: MessageType<L>>(&mut self, message: &TxMessage<T, L>) -> 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<const L: usize, T: MessageType<L>>(
&mut self,
message: &TxMessage<T, L>,
blocking: bool,
) -> Result<(), Self::Error> {
let fifo_status_reg = Self::fifo_status_register(FIFO_TX_INDEX);

// Check if TX fifo is full
while !self.fifo_tfnrfnif(fifo_status_reg)? {
if !blocking {
return Err(Error::TxFifoFullErr);
}
}

// make sure length of payload is consistent with CAN operation mode
Expand All @@ -163,28 +173,22 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> CanController for MCP2517<B, CS
// Request transmission (set txreq) and set uinc in TX FIFO control register byte 1
self.write_register(fifo_control_reg1, 0x03)?;

// read TX FIFO control register byte 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(fifo_control_reg1)?;
txfifo_control_reg = FifoControlReg1::from(txfifo_control_byte1);
// block till TXREQ is cleared confirming that all messages in TX FIFO are transmitted
if blocking {
while !self.txfifo_cleared(fifo_control_reg1)? {}
}

Ok(())
}

fn receive<const L: usize>(&mut self, data: &mut [u8; L]) -> Result<(), Self::Error> {
fn receive<const L: usize>(&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
while !self.fifo_tfnrfnif(fifo_status_reg)? {
if !blocking {
return Err(Error::RxFifoEmptyErr);
}
}

let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?;
Expand Down Expand Up @@ -495,6 +499,29 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
buffer
}

/// Returns if the TX/RX fifo not full/empty flag is set
fn fifo_tfnrfnif(&mut self, fifo_reg_addr: u16) -> Result<bool, BusError<B::Error, CS::Error>> {
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 `TXREQ` bit of TX fifo is cleared i.e. all messages contained are transmitted
fn txfifo_cleared(&mut self, fifo_ctrl_reg: u16) -> Result<bool, BusError<B::Error, CS::Error>> {
// 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)
Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@
//!let filter = Filter::new(can_id, 0).unwrap();
//!let _ = controller.set_filter_object(filter);
//!
//!// Transmit CAN message
//!controller.transmit(&can_message).unwrap();
//!// Transmit CAN message in blocking mode
//!controller.transmit(&can_message,true).unwrap();
//!
//!// Receive CAN message
//!// Receive CAN message in blocking mode
//!let mut buff = [0u8;8];
//!let result = controller.receive(&mut buff);
//!let result = controller.receive(&mut buff,true);
//!assert!(result.is_ok());
//!assert_eq!(buff,[0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
//!```
Expand Down
44 changes: 40 additions & 4 deletions src/tests/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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::RxFifoEmptyErr);
}

#[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::TxFifoFullErr);
}

#[test]
fn test_reset_command() {
let mut mocks = Mocks::default();
Expand Down

0 comments on commit 18d68c0

Please sign in to comment.