Skip to content

Commit

Permalink
add register definition for can filter
Browse files Browse the repository at this point in the history
  • Loading branch information
Paval-from-Belarus committed Dec 24, 2024
1 parent 2db1958 commit 191efb4
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 76 deletions.
10 changes: 8 additions & 2 deletions examples/ch32v203/src/bin/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@
#![feature(impl_trait_in_assoc_type)]

use ch32_hal::can::{Can, CanFifo, CanFilter, CanFrame, CanMode, StandardId};
use embassy_time::{Duration, Ticker};
use embassy_executor::Spawner;

use embassy_time::{Duration, Ticker};
use {ch32_hal as hal, panic_halt as _};

#[embassy_executor::main(entry = "ch32_hal::entry")]
async fn main(_spawner: Spawner) {
let p = hal::init(Default::default());

let can = Can::new(p.CAN1, p.PA11, p.PA12, CanFifo::Fifo1, CanMode::Normal, 500_000).expect("Valid");
let mut filter = CanFilter::new_id_list();

filter
.get(0)
.unwrap()
.set(StandardId::new(0x580 | 0x42).unwrap().into(), Default::default());

can.add_filter(CanFilter::accept_all());

let mut ticker = Ticker::every(Duration::from_millis(200));
Expand Down
5 changes: 3 additions & 2 deletions src/can/can.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::enums::*;
use super::CanFrame;
use super::filter::{BitMode, FilterMode};
use super::{CanFilter, CanFrame};
use crate as hal;
use crate::can::registers::Registers;
use crate::can::util;
Expand Down Expand Up @@ -64,7 +65,7 @@ impl<'d, T: Instance> Can<'d, T> {
Ok(this)
}

pub fn add_filter(&self, filter: CanFilter) {
pub fn add_filter<BIT: BitMode, MODE: FilterMode>(&self, filter: CanFilter<BIT, MODE>) {
Registers(T::regs()).add_filter(filter, &self.fifo);
}

Expand Down
72 changes: 4 additions & 68 deletions src/can/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,14 @@ impl core::fmt::Display for CanError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Overrun => write!(f, "The peripheral receive buffer was overrun"),
Self::Bit => write!(
f,
"Bit value that is monitored differs from the bit value sent"
),
Self::Bit => write!(f, "Bit value that is monitored differs from the bit value sent"),
Self::Stuff => write!(f, "Sixth consecutive equal bits detected"),
Self::Crc => write!(f, "Calculated CRC sequence does not equal the received one"),
Self::Form => write!(
f,
"A fixed-form bit field contains one or more illegal bits"
),
Self::Form => write!(f, "A fixed-form bit field contains one or more illegal bits"),
Self::Acknowledge => write!(f, "Transmitted frame was not acknowledged"),
Self::BusOff => write!(f, "The peripheral is in Bus Off mode"),
Self::BusPassive => write!(f, "The peripheral is in Bus Passive mode"),
Self::BusWarning => write!(
f,
"A peripheral error counter has reached the Warning threshold"
),
Self::BusWarning => write!(f, "A peripheral error counter has reached the Warning threshold"),
}
}
}
Expand Down Expand Up @@ -100,10 +91,7 @@ impl CanMode {
lbkm: true,
silm: false,
},
CanMode::SilentLoopback => CanModeRegs {
lbkm: true,
silm: true,
},
CanMode::SilentLoopback => CanModeRegs { lbkm: true, silm: true },
}
}
}
Expand All @@ -129,58 +117,6 @@ impl CanFifo {
}
}

pub enum CanFilterMode {
/// Matches the incoming ID to a predefined value after applying a predefined bit mask.
IdMask,
/// Matches the incoming ID to a predefined set of values.
IdList,
}

impl CanFilterMode {
pub(crate) fn val_bool(&self) -> bool {
match self {
CanFilterMode::IdMask => false,
CanFilterMode::IdList => true,
}
}
}

/// See table 24-1 of the reference manual for more details on filtering and modes.
pub struct CanFilter {
/// Filter bank number, 0-27
pub bank: usize,
/// Filter mode, either identifier mask or identifier list
pub mode: CanFilterMode,
/// Values for `STID:EXID:IDE:RTR:0` from msb to lsb to be matched with an incoming message's values.
/// In IdList mode, value should be a 32-bit id or two 16-bit ids.
pub id_value: u32,
/// Bit mask to be applied to incoming message before comparing it to a predefined value.
/// In IdList mode, this is used in the same way as `id_value` is.
pub id_mask: u32,
}

impl CanFilter {
/// Creates a filter that accepts all frames
pub fn accept_all() -> Self {
Self {
bank: 0,
mode: CanFilterMode::IdMask,
id_value: 0,
id_mask: 0,
}
}

/// Offset in `usize` for bank `n` filter register 1
pub(crate) fn fr_id_value_reg(&self) -> usize {
self.bank * 2 + 0
}

/// Offset in `usize` for bank `n` filter register 2
pub(crate) fn fr_id_mask_reg(&self) -> usize {
self.bank * 2 + 1
}
}

#[derive(Debug)]
pub enum TxStatus {
/// Message was sent correctly
Expand Down
90 changes: 90 additions & 0 deletions src/can/filter/bit16.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use embedded_can::StandardId;

use super::{Bit16Mode, CanFilter, FilterOptions, ListMode, MaskMode};

pub struct Bit16IdReg<'a>(&'a mut u16);

pub struct Bit16MaskReg<'a> {
mask: &'a mut u16,
id: &'a mut u16,
}

impl Bit16IdReg<'_> {
pub fn set(&mut self, id: StandardId, opts: FilterOptions) {
let bits = (id.as_raw() << 3) | ((opts.rtr_enabled as u16) << 2);
*self.0 &= 0x0000;
*self.0 |= bits;
}
}

impl Bit16MaskReg<'_> {
pub fn set(&mut self, id: u16, mask: u16, opts: FilterOptions) {
*self.mask &= 0xFFFF;
*self.id &= 0xFFFF;

*self.mask |= (id << 3) | ((opts.rtr_enabled as u16) << 2);
*self.id |= (mask << 3) | ((opts.rtr_enabled as u16) << 2);
}
}

impl CanFilter<Bit16Mode, ListMode> {
pub fn get(&mut self, index: usize) -> Option<Bit16IdReg> {
use core::mem;

match index {
0 => {
let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) };
Some(Bit16IdReg(&mut bytes[0]))
}

1 => {
let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) };
Some(Bit16IdReg(&mut bytes[1]))
}

2 => {
let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) };
Some(Bit16IdReg(&mut bytes[0]))
}

3 => {
let bytes = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) };
Some(Bit16IdReg(&mut bytes[0]))
}

_ => None,
}
}
}

impl From<[(StandardId, FilterOptions); 4]> for CanFilter<Bit16Mode, ListMode> {
fn from(value: [(StandardId, FilterOptions); 4]) -> Self {
let mut filter = CanFilter::new_id_list().use_16bit();

for (index, (id, opts)) in value.into_iter().enumerate() {
filter.get(index).expect("index less 4").set(id, opts);
}

filter
}
}

impl CanFilter<Bit16Mode, MaskMode> {
pub fn get(&mut self, index: usize) -> Option<Bit16MaskReg> {
use core::mem;

match index {
0 => {
let [id, mask] = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_value) };

Some(Bit16MaskReg { id, mask })
}
1 => {
let [id, mask] = unsafe { &mut *mem::transmute::<*mut u32, *mut [u16; 2]>(&mut self.id_mask) };

Some(Bit16MaskReg { id, mask })
}
_ => None,
}
}
}
88 changes: 88 additions & 0 deletions src/can/filter/bit32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use core::marker::PhantomData;

use embedded_can::Id;

use super::{Bit16Mode, Bit32Mode, CanFilter, FilterMode, FilterOptions, ListMode, MaskMode};

impl<MODE: FilterMode> CanFilter<Bit32Mode, MODE> {
pub fn use_16bit(self) -> CanFilter<Bit16Mode, MODE> {
CanFilter {
id_mask: self.id_mask,
id_value: self.id_value,
mode: self.mode,
bank: self.bank,
bit_mode: PhantomData,
}
}
}

impl CanFilter<Bit32Mode, ListMode> {
/// Creates a filter that accepts all frames
pub fn accept_all() -> Self {
CanFilter {
bank: 0,
mode: ListMode,
id_value: 0,
id_mask: 0,
bit_mode: PhantomData,
}
}

pub fn new_id_list() -> Self {
Self {
bank: 0,
bit_mode: PhantomData,
mode: ListMode,

id_mask: 0,
id_value: 0,
}
}
}

impl CanFilter<Bit32Mode, MaskMode> {
pub fn new_id_mask() -> Self {
Self {
bank: 0,
bit_mode: PhantomData,
mode: MaskMode,

id_mask: 0,
id_value: 0,
}
}
}

pub struct Bit32IdReg<'a>(&'a mut u32);

impl Bit32IdReg<'_> {
pub fn set(&mut self, id: Id, opts: FilterOptions) {
*self.0 = 0;
*self.0 |= (opts.rtr_enabled as u32) << 1;

match id {
Id::Standard(id) => {
let id_bits = id.as_raw() as u32;

*self.0 |= ((id_bits << 3) << 24) | ((id_bits & 0x7) << 20);
}

Id::Extended(id) => {
let std_id = (id.as_raw() as u16) as u32;
let ext_id = id.as_raw() >> 11;

*self.0 |= ((std_id << 3) << 24) | ((std_id & 0x7) << 20) | (ext_id << 3);
}
}
}
}

impl CanFilter<Bit32Mode, ListMode> {
pub fn get(&mut self, index: usize) -> Option<Bit32IdReg> {
match index {
0 => Some(Bit32IdReg(&mut self.id_value)),
1 => Some(Bit32IdReg(&mut self.id_mask)),
_ => None,
}
}
}
73 changes: 73 additions & 0 deletions src/can/filter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
mod bit16;
mod bit32;

use core::marker::PhantomData;

/// Filter mode, either identifier mask or identifier list
pub trait FilterMode {
fn val_bool(&self) -> bool;
}

/// Matches the incoming ID to a predefined value after applying a predefined bit mask.
pub struct MaskMode;
pub struct ListMode;

impl FilterMode for MaskMode {
fn val_bool(&self) -> bool {
false
}
}

impl FilterMode for ListMode {
fn val_bool(&self) -> bool {
true
}
}

pub trait BitMode {}

pub struct Bit16Mode;
pub struct Bit32Mode;

impl BitMode for Bit16Mode {}
impl BitMode for Bit32Mode {}

/// See table 24-1 of the reference manual for more details on filtering and modes.
/// Each filter is applied for only one bank and for one register on it bank
pub struct CanFilter<BIT: BitMode, MODE: FilterMode> {
/// Filter bank number, 0-27
pub bank: usize,
/// Values for `STID:EXID:IDE:RTR:0` from msb to lsb to be matched with an incoming message's values.
/// In IdList mode, value should be a 32-bit id or two 16-bit ids.
pub id_value: u32,
/// Bit mask to be applied to incoming message before comparing it to a predefined value.
/// In IdList mode, this is used in the same way as `id_value` is.
pub id_mask: u32,
pub bit_mode: PhantomData<BIT>,
pub mode: MODE,
}

impl<BIT: BitMode, MODE: FilterMode> CanFilter<BIT, MODE> {
pub fn set_bank(&mut self, bank: usize) -> &mut Self {
self.bank = bank;

self
}

/// Offset in `usize` for bank `n` filter register 1
pub(crate) fn fr_id_value_reg(&self) -> usize {
self.bank * 2 + 0
}

/// Offset in `usize` for bank `n` filter register 2
pub(crate) fn fr_id_mask_reg(&self) -> usize {
self.bank * 2 + 1
}
}

/// By default rtr is disabled
#[derive(Default)]
pub struct FilterOptions {
pub rtr_enabled: bool,
//todo: add ide?
}
Loading

0 comments on commit 191efb4

Please sign in to comment.