aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Schuhen <[email protected]>2024-03-07 22:48:25 +1000
committerCorey Schuhen <[email protected]>2024-03-13 17:46:50 +1000
commit12a3af5043fd1d9a32f57b5cab9b5729a304ffc5 (patch)
treef98fe58851d3643363d48cf8b563a280212f0970
parent35f284ec22848d7085e00f377136fd66067ca756 (diff)
Shared frame types.
Remove BXCAN speciffic id and frame modules Remove SizedClassicData
-rw-r--r--embassy-stm32/src/can/bx/frame.rs248
-rw-r--r--embassy-stm32/src/can/bx/id.rs113
-rw-r--r--embassy-stm32/src/can/bx/mod.rs106
-rw-r--r--embassy-stm32/src/can/bxcan.rs17
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs2
-rw-r--r--embassy-stm32/src/can/frame.rs54
-rw-r--r--examples/stm32f1/src/bin/can.rs6
-rw-r--r--examples/stm32f4/src/bin/can.rs4
-rw-r--r--examples/stm32f7/src/bin/can.rs2
-rw-r--r--tests/stm32/src/bin/can.rs4
10 files changed, 139 insertions, 417 deletions
diff --git a/embassy-stm32/src/can/bx/frame.rs b/embassy-stm32/src/can/bx/frame.rs
deleted file mode 100644
index 828f375be..000000000
--- a/embassy-stm32/src/can/bx/frame.rs
+++ /dev/null
@@ -1,248 +0,0 @@
1#[cfg(test)]
2use core::cmp::Ordering;
3use core::ops::{Deref, DerefMut};
4
5use crate::can::bx::{Id, IdReg};
6
7/// A CAN data or remote frame.
8#[derive(Clone, Debug, Eq)]
9//#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub struct Frame {
12 pub(crate) id: IdReg,
13 pub(crate) data: Data,
14}
15
16impl Frame {
17 /// Creates a new data frame.
18 pub fn new_data(id: impl Into<Id>, data: impl Into<Data>) -> Self {
19 let id = match id.into() {
20 Id::Standard(id) => IdReg::new_standard(id),
21 Id::Extended(id) => IdReg::new_extended(id),
22 };
23
24 Self { id, data: data.into() }
25 }
26
27 /// Creates a new remote frame with configurable data length code (DLC).
28 ///
29 /// # Panics
30 ///
31 /// This function will panic if `dlc` is not inside the valid range `0..=8`.
32 pub fn new_remote(id: impl Into<Id>, dlc: u8) -> Self {
33 assert!(dlc <= 8);
34
35 let mut frame = Self::new_data(id, []);
36 // Just extend the data length, even with no data present. The API does not hand out this
37 // `Data` object.
38 frame.data.len = dlc;
39 frame.id = frame.id.with_rtr(true);
40 frame
41 }
42
43 /// Returns true if this frame is an extended frame.
44 #[inline]
45 pub fn is_extended(&self) -> bool {
46 self.id.is_extended()
47 }
48
49 /// Returns true if this frame is a standard frame.
50 #[inline]
51 pub fn is_standard(&self) -> bool {
52 self.id.is_standard()
53 }
54
55 /// Returns true if this frame is a remote frame.
56 #[inline]
57 pub fn is_remote_frame(&self) -> bool {
58 self.id.rtr()
59 }
60
61 /// Returns true if this frame is a data frame.
62 #[inline]
63 pub fn is_data_frame(&self) -> bool {
64 !self.is_remote_frame()
65 }
66
67 /// Returns the frame identifier.
68 #[inline]
69 pub fn id(&self) -> Id {
70 self.id.to_id()
71 }
72
73 /// Returns the priority of this frame.
74 #[inline]
75 pub fn priority(&self) -> FramePriority {
76 FramePriority(self.id)
77 }
78
79 /// Returns the data length code (DLC) which is in the range 0..8.
80 ///
81 /// For data frames the DLC value always matches the length of the data.
82 /// Remote frames do not carry any data, yet the DLC can be greater than 0.
83 #[inline]
84 pub fn dlc(&self) -> u8 {
85 self.data.len() as u8
86 }
87
88 /// Returns the frame data (0..8 bytes in length) if this is a data frame.
89 ///
90 /// If this is a remote frame, returns `None`.
91 pub fn data(&self) -> Option<&Data> {
92 if self.is_data_frame() {
93 Some(&self.data)
94 } else {
95 None
96 }
97 }
98}
99
100impl PartialEq for Frame {
101 fn eq(&self, other: &Self) -> bool {
102 match (self.data(), other.data()) {
103 (None, None) => self.id.eq(&other.id),
104 (Some(a), Some(b)) => self.id.eq(&other.id) && a.eq(b),
105 (None, Some(_)) | (Some(_), None) => false,
106 }
107 }
108}
109
110/// Priority of a CAN frame.
111///
112/// Returned by [`Frame::priority`].
113///
114/// The priority of a frame is determined by the bits that are part of the *arbitration field*.
115/// These consist of the frame identifier bits (including the *IDE* bit, which is 0 for extended
116/// frames and 1 for standard frames), as well as the *RTR* bit, which determines whether a frame
117/// is a data or remote frame. Lower values of the *arbitration field* have higher priority.
118///
119/// This struct wraps the *arbitration field* and implements `PartialOrd` and `Ord` accordingly,
120/// ordering higher priorities greater than lower ones.
121#[derive(Debug, Copy, Clone)]
122pub struct FramePriority(IdReg);
123
124/// Ordering is based on the Identifier and frame type (data vs. remote) and can be used to sort
125/// frames by priority.
126impl Ord for FramePriority {
127 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
128 self.0.cmp(&other.0)
129 }
130}
131
132impl PartialOrd for FramePriority {
133 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
134 Some(self.cmp(other))
135 }
136}
137
138impl PartialEq for FramePriority {
139 fn eq(&self, other: &Self) -> bool {
140 self.cmp(other) == core::cmp::Ordering::Equal
141 }
142}
143
144impl Eq for FramePriority {}
145
146/// Payload of a CAN data frame.
147///
148/// Contains 0 to 8 Bytes of data.
149///
150/// `Data` implements `From<[u8; N]>` for all `N` up to 8, which provides a convenient lossless
151/// conversion from fixed-length arrays.
152#[derive(Debug, Copy, Clone)]
153pub struct Data {
154 pub(crate) len: u8,
155 pub(crate) bytes: [u8; 8],
156}
157
158impl Data {
159 /// Creates a data payload from a raw byte slice.
160 ///
161 /// Returns `None` if `data` contains more than 8 Bytes (which is the maximum).
162 ///
163 /// `Data` can also be constructed from fixed-length arrays up to length 8 via `From`/`Into`.
164 pub fn new(data: &[u8]) -> Option<Self> {
165 if data.len() > 8 {
166 return None;
167 }
168
169 let mut bytes = [0; 8];
170 bytes[..data.len()].copy_from_slice(data);
171
172 Some(Self {
173 len: data.len() as u8,
174 bytes,
175 })
176 }
177
178 /// Creates an empty data payload containing 0 bytes.
179 #[inline]
180 pub const fn empty() -> Self {
181 Self { len: 0, bytes: [0; 8] }
182 }
183}
184
185impl Deref for Data {
186 type Target = [u8];
187
188 #[inline]
189 fn deref(&self) -> &[u8] {
190 &self.bytes[..usize::from(self.len)]
191 }
192}
193
194impl DerefMut for Data {
195 #[inline]
196 fn deref_mut(&mut self) -> &mut [u8] {
197 &mut self.bytes[..usize::from(self.len)]
198 }
199}
200
201impl AsRef<[u8]> for Data {
202 #[inline]
203 fn as_ref(&self) -> &[u8] {
204 self.deref()
205 }
206}
207
208impl AsMut<[u8]> for Data {
209 #[inline]
210 fn as_mut(&mut self) -> &mut [u8] {
211 self.deref_mut()
212 }
213}
214
215impl PartialEq for Data {
216 fn eq(&self, other: &Self) -> bool {
217 self.as_ref() == other.as_ref()
218 }
219}
220
221impl Eq for Data {}
222
223#[cfg(feature = "defmt")]
224impl defmt::Format for Data {
225 fn format(&self, fmt: defmt::Formatter<'_>) {
226 self.as_ref().format(fmt)
227 }
228}
229
230macro_rules! data_from_array {
231 ( $($len:literal),+ ) => {
232 $(
233 impl From<[u8; $len]> for Data {
234 #[inline]
235 fn from(arr: [u8; $len]) -> Self {
236 let mut bytes = [0; 8];
237 bytes[..$len].copy_from_slice(&arr);
238 Self {
239 len: $len,
240 bytes,
241 }
242 }
243 }
244 )+
245 };
246}
247
248data_from_array!(0, 1, 2, 3, 4, 5, 6, 7, 8);
diff --git a/embassy-stm32/src/can/bx/id.rs b/embassy-stm32/src/can/bx/id.rs
deleted file mode 100644
index 9fdcd8319..000000000
--- a/embassy-stm32/src/can/bx/id.rs
+++ /dev/null
@@ -1,113 +0,0 @@
1//! CAN Identifiers.
2
3/// Standard 11-bit CAN Identifier (`0..=0x7FF`).
4#[derive(Debug, Copy, Clone, Eq, PartialEq)]
5pub struct StandardId(u16);
6
7impl StandardId {
8 /// CAN ID `0`, the highest priority.
9 pub const ZERO: Self = Self(0);
10
11 /// CAN ID `0x7FF`, the lowest priority.
12 pub const MAX: Self = Self(0x7FF);
13
14 /// Tries to create a `StandardId` from a raw 16-bit integer.
15 ///
16 /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`).
17 #[inline]
18 pub const fn new(raw: u16) -> Option<Self> {
19 if raw <= 0x7FF {
20 Some(Self(raw))
21 } else {
22 None
23 }
24 }
25
26 /// Creates a new `StandardId` without checking if it is inside the valid range.
27 ///
28 /// # Safety
29 ///
30 /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
31 /// undefined.
32 #[inline]
33 pub const unsafe fn new_unchecked(raw: u16) -> Self {
34 Self(raw)
35 }
36
37 /// Returns this CAN Identifier as a raw 16-bit integer.
38 #[inline]
39 pub fn as_raw(&self) -> u16 {
40 self.0
41 }
42}
43
44/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`).
45#[derive(Debug, Copy, Clone, Eq, PartialEq)]
46pub struct ExtendedId(u32);
47
48impl ExtendedId {
49 /// CAN ID `0`, the highest priority.
50 pub const ZERO: Self = Self(0);
51
52 /// CAN ID `0x1FFFFFFF`, the lowest priority.
53 pub const MAX: Self = Self(0x1FFF_FFFF);
54
55 /// Tries to create a `ExtendedId` from a raw 32-bit integer.
56 ///
57 /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`).
58 #[inline]
59 pub const fn new(raw: u32) -> Option<Self> {
60 if raw <= 0x1FFF_FFFF {
61 Some(Self(raw))
62 } else {
63 None
64 }
65 }
66
67 /// Creates a new `ExtendedId` without checking if it is inside the valid range.
68 ///
69 /// # Safety
70 ///
71 /// The caller must ensure that `raw` is in the valid range, otherwise the behavior is
72 /// undefined.
73 #[inline]
74 pub const unsafe fn new_unchecked(raw: u32) -> Self {
75 Self(raw)
76 }
77
78 /// Returns this CAN Identifier as a raw 32-bit integer.
79 #[inline]
80 pub fn as_raw(&self) -> u32 {
81 self.0
82 }
83
84 /// Returns the Base ID part of this extended identifier.
85 pub fn standard_id(&self) -> StandardId {
86 // ID-28 to ID-18
87 StandardId((self.0 >> 18) as u16)
88 }
89}
90
91/// A CAN Identifier (standard or extended).
92#[derive(Debug, Copy, Clone, Eq, PartialEq)]
93pub enum Id {
94 /// Standard 11-bit Identifier (`0..=0x7FF`).
95 Standard(StandardId),
96
97 /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`).
98 Extended(ExtendedId),
99}
100
101impl From<StandardId> for Id {
102 #[inline]
103 fn from(id: StandardId) -> Self {
104 Id::Standard(id)
105 }
106}
107
108impl From<ExtendedId> for Id {
109 #[inline]
110 fn from(id: ExtendedId) -> Self {
111 Id::Extended(id)
112 }
113}
diff --git a/embassy-stm32/src/can/bx/mod.rs b/embassy-stm32/src/can/bx/mod.rs
index f639260a1..650d4414b 100644
--- a/embassy-stm32/src/can/bx/mod.rs
+++ b/embassy-stm32/src/can/bx/mod.rs
@@ -25,19 +25,26 @@
25 25
26//mod embedded_hal; 26//mod embedded_hal;
27pub mod filter; 27pub mod filter;
28mod frame;
29mod id;
30 28
31#[allow(clippy::all)] // generated code 29#[allow(clippy::all)] // generated code
32use core::cmp::{Ord, Ordering}; 30use core::cmp::{Ord, Ordering};
33use core::convert::{Infallible, TryInto}; 31use core::convert::{Infallible, Into, TryInto};
34use core::marker::PhantomData; 32use core::marker::PhantomData;
35use core::mem; 33use core::mem;
36 34
37pub use id::{ExtendedId, Id, StandardId}; 35pub use embedded_can::{ExtendedId, Id, StandardId};
36
37/// CAN Header: includes ID and length
38pub type Header = crate::can::frame::Header;
39
40/// Data for a CAN Frame
41pub type Data = crate::can::frame::ClassicData;
42
43/// CAN Frame
44pub type Frame = crate::can::frame::ClassicFrame;
38 45
39use crate::can::bx::filter::MasterFilters; 46use crate::can::bx::filter::MasterFilters;
40pub use crate::can::bx::frame::{Data, Frame, FramePriority}; 47use crate::can::frame::ClassicData;
41 48
42/// A bxCAN peripheral instance. 49/// A bxCAN peripheral instance.
43/// 50///
@@ -148,13 +155,13 @@ impl IdReg {
148 /// Sets the remote transmission (RTR) flag. This marks the identifier as 155 /// Sets the remote transmission (RTR) flag. This marks the identifier as
149 /// being part of a remote frame. 156 /// being part of a remote frame.
150 #[must_use = "returns a new IdReg without modifying `self`"] 157 #[must_use = "returns a new IdReg without modifying `self`"]
151 fn with_rtr(self, rtr: bool) -> IdReg { 158 /*fn with_rtr(self, rtr: bool) -> IdReg {
152 if rtr { 159 if rtr {
153 Self(self.0 | Self::RTR_MASK) 160 Self(self.0 | Self::RTR_MASK)
154 } else { 161 } else {
155 Self(self.0 & !Self::RTR_MASK) 162 Self(self.0 & !Self::RTR_MASK)
156 } 163 }
157 } 164 }*/
158 165
159 /// Returns the identifier. 166 /// Returns the identifier.
160 fn to_id(self) -> Id { 167 fn to_id(self) -> Id {
@@ -165,15 +172,28 @@ impl IdReg {
165 } 172 }
166 } 173 }
167 174
175 /// Returns the identifier.
176 fn id(self) -> embedded_can::Id {
177 if self.is_extended() {
178 embedded_can::ExtendedId::new(self.0 >> Self::EXTENDED_SHIFT)
179 .unwrap()
180 .into()
181 } else {
182 embedded_can::StandardId::new((self.0 >> Self::STANDARD_SHIFT) as u16)
183 .unwrap()
184 .into()
185 }
186 }
187
168 /// Returns `true` if the identifier is an extended identifier. 188 /// Returns `true` if the identifier is an extended identifier.
169 fn is_extended(self) -> bool { 189 fn is_extended(self) -> bool {
170 self.0 & Self::IDE_MASK != 0 190 self.0 & Self::IDE_MASK != 0
171 } 191 }
172 192
173 /// Returns `true` if the identifier is a standard identifier. 193 /// Returns `true` if the identifier is a standard identifier.
174 fn is_standard(self) -> bool { 194 /*fn is_standard(self) -> bool {
175 !self.is_extended() 195 !self.is_extended()
176 } 196 }*/
177 197
178 /// Returns `true` if the identifer is part of a remote frame (RTR bit set). 198 /// Returns `true` if the identifer is part of a remote frame (RTR bit set).
179 fn rtr(self) -> bool { 199 fn rtr(self) -> bool {
@@ -181,6 +201,21 @@ impl IdReg {
181 } 201 }
182} 202}
183 203
204impl From<&embedded_can::Id> for IdReg {
205 fn from(eid: &embedded_can::Id) -> Self {
206 match eid {
207 embedded_can::Id::Standard(id) => IdReg::new_standard(StandardId::new(id.as_raw()).unwrap()),
208 embedded_can::Id::Extended(id) => IdReg::new_extended(ExtendedId::new(id.as_raw()).unwrap()),
209 }
210 }
211}
212
213impl From<IdReg> for embedded_can::Id {
214 fn from(idr: IdReg) -> Self {
215 idr.id()
216 }
217}
218
184/// `IdReg` is ordered by priority. 219/// `IdReg` is ordered by priority.
185impl Ord for IdReg { 220impl Ord for IdReg {
186 fn cmp(&self, other: &Self) -> Ordering { 221 fn cmp(&self, other: &Self) -> Ordering {
@@ -682,9 +717,9 @@ where
682 // The controller schedules pending frames of same priority based on the 717 // The controller schedules pending frames of same priority based on the
683 // mailbox index instead. As a workaround check all pending mailboxes 718 // mailbox index instead. As a workaround check all pending mailboxes
684 // and only accept higher priority frames. 719 // and only accept higher priority frames.
685 self.check_priority(0, frame.id)?; 720 self.check_priority(0, frame.id().into())?;
686 self.check_priority(1, frame.id)?; 721 self.check_priority(1, frame.id().into())?;
687 self.check_priority(2, frame.id)?; 722 self.check_priority(2, frame.id().into())?;
688 723
689 let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2); 724 let all_frames_are_pending = !tsr.tme(0) && !tsr.tme(1) && !tsr.tme(2);
690 if all_frames_are_pending { 725 if all_frames_are_pending {
@@ -739,14 +774,15 @@ where
739 debug_assert!(idx < 3); 774 debug_assert!(idx < 3);
740 775
741 let mb = self.canregs.tx(idx); 776 let mb = self.canregs.tx(idx);
742 mb.tdtr().write(|w| w.set_dlc(frame.dlc() as u8)); 777 mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8));
743 778
744 mb.tdlr() 779 mb.tdlr()
745 .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[0..4].try_into().unwrap())); 780 .write(|w| w.0 = u32::from_ne_bytes(frame.data()[0..4].try_into().unwrap()));
746 mb.tdhr() 781 mb.tdhr()
747 .write(|w| w.0 = u32::from_ne_bytes(frame.data.bytes[4..8].try_into().unwrap())); 782 .write(|w| w.0 = u32::from_ne_bytes(frame.data()[4..8].try_into().unwrap()));
783 let id: IdReg = frame.id().into();
748 mb.tir().write(|w| { 784 mb.tir().write(|w| {
749 w.0 = frame.id.0; 785 w.0 = id.0;
750 w.set_txrq(true); 786 w.set_txrq(true);
751 }); 787 });
752 } 788 }
@@ -756,16 +792,17 @@ where
756 debug_assert!(idx < 3); 792 debug_assert!(idx < 3);
757 793
758 let mb = self.canregs.tx(idx); 794 let mb = self.canregs.tx(idx);
759 // Read back the pending frame. 795
760 let mut pending_frame = Frame { 796 let id = IdReg(mb.tir().read().0).id();
761 id: IdReg(mb.tir().read().0), 797 let mut data = [0xff; 8];
762 data: Data::empty(), 798 data[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes());
763 }; 799 data[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes());
764 pending_frame.data.bytes[0..4].copy_from_slice(&mb.tdlr().read().0.to_ne_bytes()); 800 let len = mb.tdtr().read().dlc();
765 pending_frame.data.bytes[4..8].copy_from_slice(&mb.tdhr().read().0.to_ne_bytes()); 801
766 pending_frame.data.len = mb.tdtr().read().dlc(); 802 Some(Frame::new(
767 803 Header::new(id, len, false),
768 Some(pending_frame) 804 ClassicData::new(&data).unwrap(),
805 ))
769 } else { 806 } else {
770 // Abort request failed because the frame was already sent (or being sent) on 807 // Abort request failed because the frame was already sent (or being sent) on
771 // the bus. All mailboxes are now free. This can happen for small prescaler 808 // the bus. All mailboxes are now free. This can happen for small prescaler
@@ -898,18 +935,19 @@ fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Fra
898 } 935 }
899 936
900 // Read the frame. 937 // Read the frame.
901 let mut frame = Frame { 938 let id = IdReg(rx.rir().read().0).id();
902 id: IdReg(rx.rir().read().0), 939 let mut data = [0xff; 8];
903 data: [0; 8].into(), 940 data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes());
904 }; 941 data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
905 frame.data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes()); 942 let len = rx.rdtr().read().dlc();
906 frame.data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
907 frame.data.len = rx.rdtr().read().dlc();
908 943
909 // Release the mailbox. 944 // Release the mailbox.
910 rfr.write(|w| w.set_rfom(true)); 945 rfr.write(|w| w.set_rfom(true));
911 946
912 Ok(frame) 947 Ok(Frame::new(
948 Header::new(id, len, false),
949 ClassicData::new(&data).unwrap(),
950 ))
913} 951}
914 952
915/// Identifies one of the two receive FIFOs. 953/// Identifies one of the two receive FIFOs.
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index acd831937..4d96df8aa 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -6,7 +6,7 @@ use core::task::Poll;
6 6
7pub mod bx; 7pub mod bx;
8 8
9pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Id, StandardId}; 9pub use bx::{filter, Data, ExtendedId, Fifo, Frame, Header, Id, StandardId};
10use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
11use futures::FutureExt; 11use futures::FutureExt;
12 12
@@ -18,19 +18,20 @@ use crate::{interrupt, peripherals, Peripheral};
18 18
19pub mod enums; 19pub mod enums;
20use enums::*; 20use enums::*;
21pub mod frame;
21pub mod util; 22pub mod util;
22 23
23/// Contains CAN frame and additional metadata. 24/// Contains CAN frame and additional metadata.
24/// 25///
25/// Timestamp is available if `time` feature is enabled. 26/// Timestamp is available if `time` feature is enabled.
26#[derive(Debug, Clone, PartialEq, Eq)] 27#[derive(Debug, Clone)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))] 28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub struct Envelope { 29pub struct Envelope {
29 /// Reception time. 30 /// Reception time.
30 #[cfg(feature = "time")] 31 #[cfg(feature = "time")]
31 pub ts: embassy_time::Instant, 32 pub ts: embassy_time::Instant,
32 /// The actual CAN frame. 33 /// The actual CAN frame.
33 pub frame: crate::can::bx::Frame, 34 pub frame: Frame,
34} 35}
35 36
36/// Interrupt handler. 37/// Interrupt handler.
@@ -260,20 +261,20 @@ impl<'d, T: Instance> Can<'d, T> {
260 } 261 }
261 262
262 let rir = fifo.rir().read(); 263 let rir = fifo.rir().read();
263 let id = if rir.ide() == Ide::STANDARD { 264 let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
264 Id::from(StandardId::new_unchecked(rir.stid())) 265 embedded_can::StandardId::new(rir.stid()).unwrap().into()
265 } else { 266 } else {
266 let stid = (rir.stid() & 0x7FF) as u32; 267 let stid = (rir.stid() & 0x7FF) as u32;
267 let exid = rir.exid() & 0x3FFFF; 268 let exid = rir.exid() & 0x3FFFF;
268 let id = (stid << 18) | (exid); 269 let id = (stid << 18) | (exid);
269 Id::from(ExtendedId::new_unchecked(id)) 270 embedded_can::ExtendedId::new(id).unwrap().into()
270 }; 271 };
271 let data_len = fifo.rdtr().read().dlc() as usize; 272 let data_len = fifo.rdtr().read().dlc();
272 let mut data: [u8; 8] = [0; 8]; 273 let mut data: [u8; 8] = [0; 8];
273 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes()); 274 data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
274 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes()); 275 data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
275 276
276 let frame = Frame::new_data(id, Data::new(&data[0..data_len]).unwrap()); 277 let frame = Frame::new(Header::new(id, data_len, false), Data::new(&data).unwrap());
277 let envelope = Envelope { 278 let envelope = Envelope {
278 #[cfg(feature = "time")] 279 #[cfg(feature = "time")]
279 ts, 280 ts,
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 8ec09ac12..cce4e5e8d 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -182,7 +182,7 @@ impl Registers {
182 DataLength::Fdcan(len) => len, 182 DataLength::Fdcan(len) => len,
183 DataLength::Classic(len) => len, 183 DataLength::Classic(len) => len,
184 }; 184 };
185 if len as usize > ClassicFrame::MAX_DATA_LEN { 185 if len as usize > ClassicData::MAX_DATA_LEN {
186 return None; 186 return None;
187 } 187 }
188 188
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 9c293035d..0dc74d299 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -9,6 +9,20 @@ pub struct Header {
9 flags: u8, 9 flags: u8,
10} 10}
11 11
12#[cfg(feature = "defmt")]
13impl defmt::Format for Header {
14 fn format(&self, fmt: defmt::Formatter<'_>) {
15 match self.id() {
16 embedded_can::Id::Standard(id) => {
17 defmt::write!(fmt, "Can Standard ID={:x} len={}", id.as_raw(), self.len,)
18 }
19 embedded_can::Id::Extended(id) => {
20 defmt::write!(fmt, "Can Extended ID={:x} len={}", id.as_raw(), self.len,)
21 }
22 }
23 }
24}
25
12impl Header { 26impl Header {
13 const FLAG_RTR: usize = 0; // Remote 27 const FLAG_RTR: usize = 0; // Remote
14 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN 28 const FLAG_FDCAN: usize = 1; // FDCan vs Classic CAN
@@ -54,6 +68,14 @@ impl Header {
54 pub fn bit_rate_switching(&self) -> bool { 68 pub fn bit_rate_switching(&self) -> bool {
55 self.flags.get_bit(Self::FLAG_BRS) 69 self.flags.get_bit(Self::FLAG_BRS)
56 } 70 }
71
72 /// Get priority of frame
73 pub(crate) fn priority(&self) -> u32 {
74 match self.id() {
75 embedded_can::Id::Standard(id) => (id.as_raw() as u32) << 18,
76 embedded_can::Id::Extended(id) => id.as_raw(),
77 }
78 }
57} 79}
58 80
59/// Trait for FDCAN frame types, providing ability to construct from a Header 81/// Trait for FDCAN frame types, providing ability to construct from a Header
@@ -70,11 +92,13 @@ pub trait CanHeader: Sized {
70/// 92///
71/// Contains 0 to 8 Bytes of data. 93/// Contains 0 to 8 Bytes of data.
72#[derive(Debug, Copy, Clone)] 94#[derive(Debug, Copy, Clone)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct ClassicData { 96pub struct ClassicData {
74 pub(crate) bytes: [u8; 8], 97 pub(crate) bytes: [u8; Self::MAX_DATA_LEN],
75} 98}
76 99
77impl ClassicData { 100impl ClassicData {
101 pub(crate) const MAX_DATA_LEN: usize = 8;
78 /// Creates a data payload from a raw byte slice. 102 /// Creates a data payload from a raw byte slice.
79 /// 103 ///
80 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or 104 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
@@ -110,19 +134,34 @@ impl ClassicData {
110 } 134 }
111} 135}
112 136
137impl From<&[u8]> for ClassicData {
138 fn from(d: &[u8]) -> Self {
139 ClassicData::new(d).unwrap()
140 }
141}
142
113/// Frame with up to 8 bytes of data payload as per Classic CAN 143/// Frame with up to 8 bytes of data payload as per Classic CAN
114#[derive(Debug, Copy, Clone)] 144#[derive(Debug, Copy, Clone)]
145#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115pub struct ClassicFrame { 146pub struct ClassicFrame {
116 can_header: Header, 147 can_header: Header,
117 data: ClassicData, 148 data: ClassicData,
118} 149}
119 150
120impl ClassicFrame { 151impl ClassicFrame {
121 pub(crate) const MAX_DATA_LEN: usize = 8;
122
123 /// Create a new CAN classic Frame 152 /// Create a new CAN classic Frame
124 pub fn new(can_header: Header, data: ClassicData) -> ClassicFrame { 153 pub fn new(can_header: Header, data: impl Into<ClassicData>) -> ClassicFrame {
125 ClassicFrame { can_header, data } 154 ClassicFrame {
155 can_header,
156 data: data.into(),
157 }
158 }
159
160 /// Creates a new data frame.
161 pub fn new_data(id: impl Into<embedded_can::Id>, data: &[u8]) -> Self {
162 let eid: embedded_can::Id = id.into();
163 let header = Header::new(eid, data.len() as u8, false);
164 Self::new(header, data)
126 } 165 }
127 166
128 /// Create new extended frame 167 /// Create new extended frame
@@ -181,6 +220,11 @@ impl ClassicFrame {
181 pub fn data(&self) -> &[u8] { 220 pub fn data(&self) -> &[u8] {
182 &self.data.raw() 221 &self.data.raw()
183 } 222 }
223
224 /// Get priority of frame
225 pub fn priority(&self) -> u32 {
226 self.header().priority()
227 }
184} 228}
185 229
186impl embedded_can::Frame for ClassicFrame { 230impl embedded_can::Frame for ClassicFrame {
diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs
index 00d61096f..a43fb4427 100644
--- a/examples/stm32f1/src/bin/can.rs
+++ b/examples/stm32f1/src/bin/can.rs
@@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) {
46 46
47 let mut i: u8 = 0; 47 let mut i: u8 = 0;
48 loop { 48 loop {
49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i, 0, 1, 2, 3, 4, 5, 6]); 49 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]);
50 can.write(&tx_frame).await; 50 can.write(&tx_frame).await;
51 51
52 match can.read().await { 52 match can.read().await {
53 Ok(env) => match env.frame.id() { 53 Ok(env) => match env.frame.id() {
54 Id::Extended(id) => { 54 Id::Extended(id) => {
55 defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); 55 defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
56 } 56 }
57 Id::Standard(id) => { 57 Id::Standard(id) => {
58 defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data().unwrap()); 58 defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
59 } 59 }
60 }, 60 },
61 Err(err) => { 61 Err(err) => {
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index b20af8cf1..2ed631a46 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) {
51 51
52 let mut i: u8 = 0; 52 let mut i: u8 = 0;
53 loop { 53 loop {
54 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 54 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]);
55 let tx_ts = Instant::now(); 55 let tx_ts = Instant::now();
56 can.write(&tx_frame).await; 56 can.write(&tx_frame).await;
57 57
@@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) {
65 65
66 info!( 66 info!(
67 "loopback frame {=u8}, latency: {} us", 67 "loopback frame {=u8}, latency: {} us",
68 unwrap!(envelope.frame.data())[0], 68 envelope.frame.data()[0],
69 latency.as_micros() 69 latency.as_micros()
70 ); 70 );
71 i += 1; 71 i += 1;
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index c3e14bbf4..2701196ed 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs {
26#[embassy_executor::task] 26#[embassy_executor::task]
27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { 27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
28 loop { 28 loop {
29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); 29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]);
30 tx.write(&frame).await; 30 tx.write(&frame).await;
31 embassy_time::Timer::after_secs(1).await; 31 embassy_time::Timer::after_secs(1).await;
32 } 32 }
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index e869e8fb9..e36137b38 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) {
60 60
61 let mut i: u8 = 0; 61 let mut i: u8 = 0;
62 loop { 62 loop {
63 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 63 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]);
64 64
65 info!("Transmitting frame..."); 65 info!("Transmitting frame...");
66 let tx_ts = Instant::now(); 66 let tx_ts = Instant::now();
@@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) {
70 info!("Frame received!"); 70 info!("Frame received!");
71 71
72 info!("loopback time {}", envelope.ts); 72 info!("loopback time {}", envelope.ts);
73 info!("loopback frame {=u8}", envelope.frame.data().unwrap()[0]); 73 info!("loopback frame {=u8}", envelope.frame.data()[0]);
74 74
75 let latency = envelope.ts.saturating_duration_since(tx_ts); 75 let latency = envelope.ts.saturating_duration_since(tx_ts);
76 info!("loopback latency {} us", latency.as_micros()); 76 info!("loopback latency {} us", latency.as_micros());