Skip to content

Commit

Permalink
Merge pull request #26 from atlas-aero/24-add-controller-trait-to-can…
Browse files Browse the repository at this point in the history
…-controller-struct

24 add controller trait to can controller struct
  • Loading branch information
marius-meissner authored Sep 24, 2024
2 parents d13cce8 + 92baca2 commit 4910813
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 110 deletions.
1 change: 1 addition & 0 deletions example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rp-pico = "0.9.0"
rp2040-boot2 = "0.3.0"
embedded-can = "0.4.1"
bytes = { version = "1.6.0", default-features = false }
portable-atomic = { version = "1.8.0", features = ["critical-section"] }
log = "0.4.21"
usb-device = "0.3.2"
usbd-serial = "0.2.2"
Expand Down
5 changes: 3 additions & 2 deletions example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![no_std]
#![no_main]
#![allow(static_mut_refs)]
extern crate alloc;

pub mod clock;
Expand All @@ -13,7 +14,7 @@ use core::fmt::Write;
use embedded_can::{Id, StandardId};
use embedded_hal::delay::DelayNs;
use fugit::RateExtU32;
use mcp2517::can::Controller;
use mcp2517::can::{CanController, MCP2517};
use mcp2517::config::{
BitRateConfig, ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, RequestMode,
SystemClockDivisor,
Expand Down Expand Up @@ -93,7 +94,7 @@ fn main() -> ! {
)
.unwrap();

let mut can_controller: Controller<_, _, SystemClock> = Controller::new(spi, pin_cs);
let mut can_controller: MCP2517<_, _, SystemClock> = MCP2517::new(spi, pin_cs);

// Setup clk config
let clk_config = ClockConfiguration {
Expand Down
216 changes: 114 additions & 102 deletions src/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl<B, CS> From<ConfigError<B, CS>> for Error<B, CS> {
}

/// Main MCP2517 CAN controller device
pub struct Controller<B: Transfer<u8>, CS: OutputPin, CLK: Clock> {
pub struct MCP2517<B: Transfer<u8>, CS: OutputPin, CLK: Clock> {
/// SPI bus
bus: B,

Expand All @@ -90,7 +90,119 @@ pub struct Controller<B: Transfer<u8>, CS: OutputPin, CLK: Clock> {
clock: PhantomData<CLK>,
}

impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
/// Trait for CAN controller
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>;

/// Receive CAN message
fn receive<const L: usize>(&mut self, data: &mut [u8; L]) -> 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);
}

// make sure length of payload is consistent with CAN operation mode
let operation_status = self.read_operation_status()?;

if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD {
return Err(Error::InvalidPayloadLength(message.buff.len()));
}

// get address in which to write next message in TX FIFO (should not be read in configuration mode)
let user_address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?;

// calculate address of next Message Object according to
// Equation 4-1 in MCP251XXFD Family Reference Manual
let address = user_address + 0x400;

// get address of TX FIFO control register byte 1
let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1;

// load message in TX FIFO
self.write_fifo::<T, L>(address as u16, message)?;

// Request transmission (set txreq) and set uinc in TX FIFO control register byte 1
self.write_register(fifo_control_reg1, 0x03)?;

// 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);
}
Ok(())
}

fn receive<const L: usize>(&mut self, data: &mut [u8; L]) -> 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);
}

let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?;

let address = 0x400 + user_address;

// read message object
self.read_fifo(address as u16, data)?;

// 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(())
}

/// Set corresponding filter and mask registers
fn set_filter_object(&mut self, filter: Filter) -> Result<(), Self::Error> {
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)?;

self.write32(filter_mask_reg, mask_value)?;

let filter_control_reg = Self::filter_control_register_byte(filter.index);

self.write_register(filter_control_reg, (1 << 7) | 1)?;

Ok(())
}
}

impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
pub fn new(bus: B, pin_cs: CS) -> Self {
Self {
bus,
Expand Down Expand Up @@ -208,27 +320,6 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
Ok(())
}

/// Set corresponding filter and mask registers
pub fn set_filter_object(&mut self, filter: Filter) -> Result<(), BusError<B::Error, CS::Error>> {
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)?;

self.write32(filter_mask_reg, mask_value)?;

let filter_control_reg = Self::filter_control_register_byte(filter.index);

self.write_register(filter_control_reg, (1 << 7) | 1)?;

Ok(())
}

/// Writes a single register byte
fn write_register(&mut self, register: u16, value: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let mut buffer = self.cmd_buffer(register, Operation::Write);
Expand Down Expand Up @@ -264,85 +355,6 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> Controller<B, CS, CLK> {
Ok(())
}

/// Transmit CAN Message
pub fn transmit<T, const L: usize>(&mut self, message: &TxMessage<T, L>) -> Result<(), Error<B::Error, CS::Error>>
where
T: MessageType<L>,
{
// 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);
}

// make sure length of payload is consistent with CAN operation mode
let operation_status = self.read_operation_status()?;

if message.buff.len() > 8 && operation_status.mode != OperationMode::NormalCANFD {
return Err(Error::InvalidPayloadLength(message.buff.len()));
}

// get address in which to write next message in TX FIFO (should not be read in configuration mode)
let user_address = self.read32(Self::fifo_user_address_register(FIFO_TX_INDEX))?;

// calculate address of next Message Object according to
// Equation 4-1 in MCP251XXFD Family Reference Manual
let address = user_address + 0x400;

// get address of TX FIFO control register byte 1
let fifo_control_reg1 = Self::fifo_control_register(FIFO_TX_INDEX) + 1;

// load message in TX FIFO
self.write_fifo::<T, L>(address as u16, message)?;

// Request transmission (set txreq) and set uinc in TX FIFO control register byte 1
self.write_register(fifo_control_reg1, 0x03)?;

// 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);
}
Ok(())
}

/// Receive CAN Message
pub fn receive<const L: usize>(&mut self, data: &mut [u8; L]) -> Result<(), Error<B::Error, CS::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);
}

let user_address = self.read32(Self::fifo_user_address_register(FIFO_RX_INDEX))?;

let address = 0x400 + user_address;

// read message object
self.read_fifo(address as u16, data)?;

// 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(())
}

/// Insert message object in TX FIFO
fn write_fifo<T, const L: usize>(
&mut self,
Expand Down
13 changes: 7 additions & 6 deletions src/tests/can.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::can::{BusError, ConfigError, Controller, Error};
use crate::can::CanController;
use crate::can::{BusError, ConfigError, Error, MCP2517};
use crate::config::{
BitRateConfig, ClockConfiguration, ClockOutputDivisor, Configuration, FifoConfiguration, PLLSetting, PayloadSize,
RequestMode, RetransmissionAttempts, SystemClockDivisor,
Expand Down Expand Up @@ -112,7 +113,7 @@ fn test_configure_correct() {
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);
let mut controller = MCP2517::new(bus, pin_cs);
controller
.configure(
&Configuration {
Expand Down Expand Up @@ -168,7 +169,7 @@ fn test_configure_mode_timeout() {
pin_cs.expect_set_low().times(3).return_const(Ok(()));
pin_cs.expect_set_high().times(3).return_const(Ok(()));

let mut controller = Controller::new(bus, pin_cs);
let mut controller = MCP2517::new(bus, pin_cs);
assert_eq!(
ConfigError::ConfigurationModeTimeout,
controller.configure(&Configuration::default(), &clock).unwrap_err()
Expand Down Expand Up @@ -676,7 +677,7 @@ fn test_request_mode_timeout() {
pin_cs.expect_set_low().times(15).return_const(Ok(()));
pin_cs.expect_set_high().times(15).return_const(Ok(()));

let mut controller = Controller::new(bus, pin_cs);
let mut controller = MCP2517::new(bus, pin_cs);
assert_eq!(
ConfigError::RequestModeTimeout,
controller.configure(&Configuration::default(), &clock).unwrap_err()
Expand Down Expand Up @@ -947,8 +948,8 @@ pub(crate) struct Mocks {
}

impl Mocks {
pub fn into_controller(self) -> Controller<MockSPIBus, MockPin, TestClock> {
Controller::new(self.bus, self.pin_cs)
pub fn into_controller(self) -> MCP2517<MockSPIBus, MockPin, TestClock> {
MCP2517::new(self.bus, self.pin_cs)
}

/// Simulates a SPI transfer fault
Expand Down
1 change: 1 addition & 0 deletions src/tests/filter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::can::CanController;
use crate::filter::Filter;
use crate::tests::can::Mocks;
use embedded_can::{ExtendedId, Id, StandardId};
Expand Down

0 comments on commit 4910813

Please sign in to comment.