Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5 add docs for crate usage #14

Merged
merged 28 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34543a0
#2 added sequence in unit tests
HusseinAbdelhamid Apr 25, 2024
c2f9481
#2 BytesMut used for TxMessage object
HusseinAbdelhamid Apr 25, 2024
d1d9b04
#2 supress clippy warnings for bitfield structs
HusseinAbdelhamid Apr 25, 2024
bf3cff1
#2 linting
HusseinAbdelhamid Apr 25, 2024
1ae0a99
#2 comments + lints
HusseinAbdelhamid Apr 26, 2024
703d7fa
#2 struct comments
HusseinAbdelhamid Apr 26, 2024
ce1a74a
#3 filter/mask config, message reception logic
HusseinAbdelhamid Apr 17, 2024
0cc7c40
rebase
HusseinAbdelhamid Apr 19, 2024
109a20f
#3 added filter object tests
HusseinAbdelhamid Apr 23, 2024
c56e130
#5 remove duplicate code
HusseinAbdelhamid Sep 2, 2024
b7a8b43
#5 add example spi and clock
HusseinAbdelhamid Sep 2, 2024
c5bab20
#5 merge with #11
HusseinAbdelhamid Sep 2, 2024
eec6a5a
#5 add rust doc examples
HusseinAbdelhamid Sep 3, 2024
6684a50
#5 add .vscode to .gitignore
HusseinAbdelhamid Sep 3, 2024
effef23
#5 add bytes patch to library Cargo.toml
HusseinAbdelhamid Sep 5, 2024
790e6f6
#5 add config/message examples
HusseinAbdelhamid Sep 10, 2024
e1b6fad
Merge branch '19-add-configuration-for-bit-timing-register' into 5-ad…
HusseinAbdelhamid Sep 10, 2024
169c950
#5 add rustdocs for modules
HusseinAbdelhamid Sep 10, 2024
10a4793
Merge branch 'main' into 5-add-docs-for-crate-usage
HusseinAbdelhamid Sep 10, 2024
bd68c67
#5 update rustdoc examples
HusseinAbdelhamid Sep 10, 2024
3baffd4
#5 update docs + add comments + add can fd message construction example
HusseinAbdelhamid Sep 26, 2024
9562399
#5 modify rust docs code and comments
HusseinAbdelhamid Oct 1, 2024
0b95c28
#5 comment out empty lines in rustdoc
HusseinAbdelhamid Oct 1, 2024
ff9450d
#5 add example crate feature to remove example code
HusseinAbdelhamid Oct 1, 2024
e8ca7f7
#5 unhide use statements from main rust doc example
HusseinAbdelhamid Oct 1, 2024
66049d4
#5: Removed trailing whitespace of main example doc
marius-meissner Oct 2, 2024
b07503a
#5 add comment for example file
HusseinAbdelhamid Oct 14, 2024
44823b6
#5: Adjusted docs of example and status module
marius-meissner Oct 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea/*
target/*
example/target/*
Cargo.lock
Cargo.lock
.vscode/*
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ readme = "README.md"
documentation = "https://docs.rs/mcp2517"

[dependencies]
byteorder = { version = "1.5.0", default-features = false }
byteorder = { version = "^1.3.0", default-features = false }
bytes = { version = "1.6.0", default-features = false }
embedded-can = "0.4.1"
embedded-hal = { version = "0.2.7", features = ["unproven"] }
Expand All @@ -26,5 +26,10 @@ serde = { version = "1.0.197", features = ["derive"], default-features = false }
mockall = "0.11.0"

[features]
default = []
default = ["example"]
# Mocks for doc examples
example = []

strict = []


6 changes: 4 additions & 2 deletions example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,14 @@ fn main() -> ! {
let can_id = Id::Standard(StandardId::new(0x55).unwrap());

// Create filter object for RX
let filter = Filter::new(can_id, 0).unwrap();
let mut filter = Filter::new(can_id, 0).unwrap();
// Set mask to match if only 2 LSB of ID match with filter
filter.set_mask_standard_id(0xFF);
let _ = can_controller.set_filter_object(filter);

// Create message frame
let message_type = Can20::<8> {};
let payload = [1, 2, 3, 4, 5, 6, 7, 8];
let payload = [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8];
let pl_bytes = Bytes::copy_from_slice(&payload);
let can_message = TxMessage::new(message_type, pl_bytes, can_id).unwrap();

Expand Down
36 changes: 28 additions & 8 deletions src/can.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
//!# CAN Controller device
//!
//!```
//!# use mcp2517::can::MCP2517;
//!# use mcp2517::config::Configuration;
//!# use mcp2517::example::*;
//!#
//! let sys_clk = ExampleClock::default();
//! let spi_bus = ExampleSPIBus::default();
//! let cs_pin = ExampleCSPin{};
//!
//! // Initialize controller object
//! let mut can_controller = MCP2517::new(spi_bus,cs_pin);
//!
//! // Use default configuration settings
//! let can_config = Configuration::default();
//!
//! // Configure CAN controller
//! can_controller.configure(&can_config, &sys_clk).unwrap();
//! ```
use crate::can::BusError::{CSError, TransferError};
use crate::can::ConfigError::{ClockError, ConfigurationModeTimeout, RequestModeTimeout};
use crate::config::{ClockConfiguration, Configuration};
Expand Down Expand Up @@ -249,6 +269,14 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
Ok(())
}

/// Disable corresponding filter
pub fn disable_filter(&mut self, filter_index: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let filter_reg = Self::filter_control_register_byte(filter_index);
self.write_register(filter_reg, 0x00)?;

Ok(())
}

/// Reads and returns the operation status
pub fn read_operation_status(&mut self) -> Result<OperationStatus, BusError<B::Error, CS::Error>> {
let data = self.read_register(REGISTER_C1CON + 2)?;
Expand Down Expand Up @@ -312,14 +340,6 @@ impl<B: Transfer<u8>, CS: OutputPin, CLK: Clock> MCP2517<B, CS, CLK> {
Ok(())
}

/// Disable corresponding filter
pub fn disable_filter(&mut self, filter_index: u8) -> Result<(), BusError<B::Error, CS::Error>> {
let filter_reg = Self::filter_control_register_byte(filter_index);
self.write_register(filter_reg, 0x00)?;

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
50 changes: 50 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
//! # CAN Module configuration
marius-meissner marked this conversation as resolved.
Show resolved Hide resolved
//! The [Configuration] struct provides an abstraction for configuring the CAN module registers.
//! ## Fifo configuration
//! The following example shows a FIFO buffer configuration. At the moment, there is one TX Fifo and one
//! RX Fifo. The configuration sets the max payload size of messages transmitted/received in both Fifo buffers
//! to 8 bytes. The number of message the RX Fifo buffer can hold is 10 while it is 32 for the TX Fifo.
//!
//! The priority for the messages in the TX Fifo are given the highest possible priority (32) and the retransmission
//! attemps are set to be unlimited.
//!```
//!# use mcp2517::config::{FifoConfiguration,PayloadSize,RetransmissionAttempts};
//!#
//! let fifo_config = FifoConfiguration{
//! pl_size: PayloadSize::EightBytes,
//! rx_size: 10,
//! tx_attempts: RetransmissionAttempts::Unlimited,
//! tx_enable: true,
//! tx_priority: 32,
//! tx_size: 32,
//! };
//!```
//! ## Clock configuration
//! The CAN system clock is determined through setting the `system_clock` and `pll`. In this example,
//! the pll setting used is to directly use the crystal oscillator without any multiplication, and the
//! `system_clock` divisor is set to 1. Meaning the frequency of the SYSCLK matches the crystal used.
//! The `clock_output` divisior is set to 2. So that the CLKO outputs half the freq of the crystal.
//! Refer to the [datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2517FD-External-CAN-FD-Controller-with-SPI-Interface-20005688B.pdf) section 5.0
//!
//!```
//!# use mcp2517::config::{ClockConfiguration, ClockOutputDivisor, PLLSetting, SystemClockDivisor};
//!#
//! let clock_config = ClockConfiguration{
//! clock_output: ClockOutputDivisor::DivideBy2,
//! system_clock: SystemClockDivisor::DivideBy1,
//! pll: PLLSetting::DirectXTALOscillator,
//! disable_clock: false,
//! };
//!```
//! ## Bit rate configuration
//! It is recommended to use a SYSCLK frequency of 20 MHz or 40 MHz for the MCP2517FD CAN chip.
//! Based on the SYSCLK frequency used and the baud rate chosen, the CiNBTCFG regsiter values are configured.
//!```
//!# use mcp2517::config::{BitRateConfig,CanBaudRate,SysClk};
//!#
//! let bit_rate_config = BitRateConfig{
//! sys_clk: SysClk::MHz20,
//! can_speed: CanBaudRate::Kpbs500
//! };
//!
//!
use crate::status::OperationMode;

/// Entire configuration currently supported
Expand Down
124 changes: 124 additions & 0 deletions src/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//! # Mock dummy structure for doc examples
//!
//! This code can be removed by disabling the `example` feature
use alloc::vec;
HusseinAbdelhamid marked this conversation as resolved.
Show resolved Hide resolved
use alloc::vec::Vec;
use core::cell::RefCell;
use core::convert::Infallible;
use embedded_hal::blocking::spi::Transfer;
use embedded_hal::digital::v2::OutputPin;
use embedded_time::clock::Error;
use embedded_time::duration::{Duration, Fraction};
use embedded_time::fixed_point::FixedPoint;
use embedded_time::timer::param::{Armed, OneShot};
use embedded_time::{Clock, Instant, Timer};

#[derive(Default)]
pub struct ExampleSPIBus {
read_calls: u32,
}

impl Transfer<u8> for ExampleSPIBus {
type Error = Infallible;

fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
// write command -> returns empty buffer
if (words[0] >> 4) == 0x2 {
return Ok(&[0u8; 3]);
}

// RAM read command
if words.len() == 8 && words == [0u8; 8] {
words.iter_mut().enumerate().for_each(|(i, val)| {
*val += (i + 1) as u8;
});
return Ok(&[0u8; 8]);
}

// SFR Read command
if words[0] >= 0x3 {
return match words[1] {
// addr: C1CON reg 2
0x2 => {
// configuration mode
if self.read_calls == 0 {
self.read_calls += 1;
return Ok(&[0, 0, 0b1001_0100]);
}

// return operation mode NormalCANFD mode (called in configure and during transmission)
Ok(&[0x0, 0x0, 0b0000_0000])
}
// C1FIFOSTA2
0x6C => Ok(&[0, 0, 0x1]),
// C1FIFOUA2 (2 extra bytes in beginning for cmd+addr)
0x70 => Ok(&[0, 0, 0, 0, 0x04, 0xA2]),
// C1FIFOCON2 register 1
0x69 => Ok(&[0, 0, 0]),
// C1FIFOSTA1
0x60 => Ok(&[0, 0, 0x1]),
// C1FIFOUA1
0x64 => Ok(&[0, 0, 0, 0x04, 0x7C]),

_ => Ok(&[0, 0, 0]),
};
}

Ok(&[0u8; 3])
}
}

pub struct ExampleCSPin {}

impl OutputPin for ExampleCSPin {
type Error = Infallible;

fn set_low(&mut self) -> Result<(), Self::Error> {
Ok(())
}

fn set_high(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}

#[derive(Debug, PartialEq, Eq)]
pub struct ExampleClock {
pub next_instants: RefCell<Vec<u64>>,
}

impl ExampleClock {
pub fn new(next_instants: Vec<u64>) -> Self {
Self {
next_instants: RefCell::new(next_instants),
}
}
}

impl Default for ExampleClock {
fn default() -> Self {
Self::new(vec![
100, // Config mode: Timer start,
200, // Config mode: First expiration check
10_000, // Request mode: Timer start
10_100, // Request mode: First expiration check
])
}
}

impl Clock for ExampleClock {
type T = u64;
const SCALING_FACTOR: Fraction = Fraction::new(1, 1_000_000);

fn try_now(&self) -> Result<Instant<Self>, Error> {
if self.next_instants.borrow().len() == 0 {
return Err(Error::Unspecified);
}

Ok(Instant::new(self.next_instants.borrow_mut().remove(0)))
}

fn new_timer<Dur: Duration + FixedPoint>(&self, duration: Dur) -> Timer<OneShot, Armed, Self, Dur> {
Timer::new(self, duration)
}
}
24 changes: 20 additions & 4 deletions src/filter.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
//!# CAN Filter
//! The [Filter] object is used to create a CAN filter. The MCP2517FD CAN chip has 32 filter/mask registers.
//! Lower index of the filter means higher priority (highest priority =0, lowest priority = 31).
//!
//! ```
//!# use mcp2517::filter::Filter;
//!# use embedded_can::{Id,ExtendedId};
//!#
//! // ID to match
//! let id = Id::Extended(ExtendedId::new(0xC672).unwrap());
//! // Create filter with index 2
//! let mut filter = Filter::new(id,2).unwrap();
//! // Set mask MSB bits, so that only the MSB of the message ID needs to match the filter
//! filter.set_mask_extended_id(0xFF00);
//!
//!
use crate::message::{EXTENDED_IDENTIFIER_MASK, STANDARD_IDENTIFIER_MASK};
use crate::registers::{FilterMaskReg, FilterObjectReg};
use embedded_can::{ExtendedId, Id, StandardId};
Expand All @@ -6,15 +22,15 @@ use embedded_can::{ExtendedId, Id, StandardId};
#[derive(Default, Debug)]
pub struct Filter {
/// filter & mask index
pub index: u8,
pub(crate) index: u8,
/// mask register bitfield
pub mask_bits: FilterMaskReg,
pub(crate) mask_bits: FilterMaskReg,
/// filter register bitfield
pub filter_bits: FilterObjectReg,
pub(crate) filter_bits: FilterObjectReg,
}

impl Filter {
/// Create new filter from embedded_can::Id and index, no mask
/// Create new filter from [embedded_can::Id] and index, no mask
pub fn new(identifier: Id, index: u8) -> Option<Self> {
if index > 31 {
return None;
Expand Down
Loading
Loading