aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-09-02 00:49:17 +0200
committerGitHub <[email protected]>2023-09-02 00:49:17 +0200
commit9d8c527308522698bfb6596bdb67bec826e0fb5a (patch)
tree75945e84157e272e3ba1fd69c0aa1d3f739b6999
parent1d87ec9cc36442542814d6dca7ae8e71068820e1 (diff)
parent1db00f54399307e4ec922965f5ca49547ccd14a3 (diff)
Merge pull request #1831 from vDorst/adin1110-part2
embassy-net-adin1110 more improvements
-rw-r--r--embassy-net-adin1110/Cargo.toml15
-rw-r--r--embassy-net-adin1110/README.md37
-rw-r--r--embassy-net-adin1110/src/crc32.rs29
-rw-r--r--embassy-net-adin1110/src/fmt.rs254
-rw-r--r--embassy-net-adin1110/src/lib.rs664
-rw-r--r--embassy-net-adin1110/src/regs.rs16
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs24
8 files changed, 811 insertions, 232 deletions
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
index e74fb7cd4..8de8eadea 100644
--- a/embassy-net-adin1110/Cargo.toml
+++ b/embassy-net-adin1110/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-net-adin1110" 2name = "embassy-net-adin1110"
3version = "0.1.0" 3version = "0.2.0"
4description = "embassy-net driver for the ADIN1110 ethernet chip" 4description = "embassy-net driver for the ADIN1110 ethernet chip"
5keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"] 5keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] 6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
@@ -12,30 +12,31 @@ edition = "2021"
12[dependencies] 12[dependencies]
13heapless = "0.7.16" 13heapless = "0.7.16"
14defmt = { version = "0.3", optional = true } 14defmt = { version = "0.3", optional = true }
15log = { version = "0.4.4", default-features = false, optional = true } 15log = { version = "0.4", default-features = false, optional = true }
16embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } 16embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
17embedded-hal-async = { version = "=1.0.0-rc.1" } 17embedded-hal-async = { version = "=1.0.0-rc.1" }
18embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } 18embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
19embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } 19embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
20embassy-time = { version = "0.1.0" } 20embassy-time = { version = "0.1.3" }
21embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 21embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
22bitfield = "0.14.0" 22bitfield = "0.14.0"
23 23
24
25[dev-dependencies] 24[dev-dependencies]
26# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged. 25# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged.
27#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] } 26#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] }
28embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] } 27embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
29crc = "3.0.1" 28crc = "3.0.1"
30env_logger = "0.10" 29env_logger = "0.10"
31critical-section = { version = "1.1.1", features = ["std"] } 30critical-section = { version = "1.1.2", features = ["std"] }
32futures-test = "0.3.17" 31futures-test = "0.3.28"
33 32
34[features] 33[features]
35default = [ ] 34default = [ ]
36defmt = [ "dep:defmt" ] 35defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ]
36log = ["dep:log"]
37 37
38[package.metadata.embassy_docs] 38[package.metadata.embassy_docs]
39src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/" 39src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/"
40src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/" 40src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/"
41target = "thumbv7em-none-eabi" 41target = "thumbv7em-none-eabi"
42features = ["defmt"]
diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md
index 3c2804183..8ea10b714 100644
--- a/embassy-net-adin1110/README.md
+++ b/embassy-net-adin1110/README.md
@@ -30,8 +30,8 @@ Currently only `Generic` SPI with or without CRC is supported.
30 30
31## Hardware 31## Hardware
32 32
33- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) dor an example. 33- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) for an example.
34- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!** 34- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit (End Of Life)`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!**
35 35
36## Other SPE chips 36## Other SPE chips
37 37
@@ -44,6 +44,39 @@ ADIN1110 library can tested on the host with a mock SPI driver.
44 44
45$ `cargo test --target x86_64-unknown-linux-gnu` 45$ `cargo test --target x86_64-unknown-linux-gnu`
46 46
47## Benchmark
48
49- Benchmarked on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html), with [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example.
50
51Basic `ping` benchmark
52```rust,ignore
53# ping <IP> -c 60
54
5560 packets transmitted, 60 received, 0% packet loss, time 59066ms
56rtt min/avg/max/mdev = 1.089/1.161/1.237/0.018 ms
57
58# ping <IP> -s 1472 -M do -c 60
59
6060 packets transmitted, 60 received, 0% packet loss, time 59066ms
61rtt min/avg/max/mdev = 5.122/5.162/6.177/0.133 ms
62```
63
64HTTP load generator benchmark with [`oha`](https://github.com/hatoo/oha)
65```rust,ignore
66# oha -c 1 http://<IP> -z 60s
67Summary:
68 Success rate: 50.00%
69 Total: 60.0005 secs
70 Slowest: 0.0055 secs
71 Fastest: 0.0033 secs
72 Average: 0.0034 secs
73 Requests/sec: 362.1971
74
75 Total data: 2.99 MiB
76 Size/request: 289 B
77 Size/sec: 51.11 KiB
78```
79
47## License 80## License
48 81
49This work is licensed under either of 82This work is licensed under either of
diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs
index a3474f70a..ec020b70c 100644
--- a/embassy-net-adin1110/src/crc32.rs
+++ b/embassy-net-adin1110/src/crc32.rs
@@ -257,29 +257,30 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
257 0x2D02_EF8D, 257 0x2D02_EF8D,
258]; 258];
259 259
260/// Generate Ethernet Frame Check Sequence
260#[allow(non_camel_case_types)] 261#[allow(non_camel_case_types)]
261#[derive(Debug)] 262#[derive(Debug)]
262pub struct ETH_FSC(pub u32); 263pub struct ETH_FCS(pub u32);
263 264
264impl ETH_FSC { 265impl ETH_FCS {
265 pub const CRC32_OK: u32 = 0x2144_df1c; 266 pub const CRC32_OK: u32 = 0x2144_df1c;
266 267
267 #[must_use] 268 #[must_use]
268 pub fn new(data: &[u8]) -> Self { 269 pub fn new(data: &[u8]) -> Self {
269 let fsc = data.iter().fold(u32::MAX, |crc, byte| { 270 let fcs = data.iter().fold(u32::MAX, |crc, byte| {
270 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; 271 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
271 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) 272 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
272 }) ^ u32::MAX; 273 }) ^ u32::MAX;
273 Self(fsc) 274 Self(fcs)
274 } 275 }
275 276
276 #[must_use] 277 #[must_use]
277 pub fn update(self, data: &[u8]) -> Self { 278 pub fn update(self, data: &[u8]) -> Self {
278 let fsc = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { 279 let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
279 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte; 280 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
280 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8) 281 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
281 }) ^ u32::MAX; 282 }) ^ u32::MAX;
282 Self(fsc) 283 Self(fcs)
283 } 284 }
284 285
285 #[must_use] 286 #[must_use]
@@ -319,24 +320,24 @@ mod tests {
319 ]; 320 ];
320 321
321 // Packet A 322 // Packet A
322 let own_crc = ETH_FSC::new(&packet_a[0..60]); 323 let own_crc = ETH_FCS::new(&packet_a[0..60]);
323 let crc_bytes = own_crc.hton_bytes(); 324 let crc_bytes = own_crc.hton_bytes();
324 println!("{:08x} {:02x?}", own_crc.0, crc_bytes); 325 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
325 assert_eq!(&crc_bytes, &packet_a[60..64]); 326 assert_eq!(&crc_bytes, &packet_a[60..64]);
326 327
327 let own_crc = ETH_FSC::new(packet_a); 328 let own_crc = ETH_FCS::new(packet_a);
328 println!("{:08x}", own_crc.0); 329 println!("{:08x}", own_crc.0);
329 assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); 330 assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
330 331
331 // Packet B 332 // Packet B
332 let own_crc = ETH_FSC::new(&packet_b[0..60]); 333 let own_crc = ETH_FCS::new(&packet_b[0..60]);
333 let crc_bytes = own_crc.hton_bytes(); 334 let crc_bytes = own_crc.hton_bytes();
334 println!("{:08x} {:02x?}", own_crc.0, crc_bytes); 335 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
335 assert_eq!(&crc_bytes, &packet_b[60..64]); 336 assert_eq!(&crc_bytes, &packet_b[60..64]);
336 337
337 let own_crc = ETH_FSC::new(packet_b); 338 let own_crc = ETH_FCS::new(packet_b);
338 println!("{:08x}", own_crc.0); 339 println!("{:08x}", own_crc.0);
339 assert_eq!(own_crc.0, ETH_FSC::CRC32_OK); 340 assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
340 } 341 }
341 342
342 #[test] 343 #[test]
@@ -349,9 +350,9 @@ mod tests {
349 ]; 350 ];
350 351
351 let (part_a, part_b) = full_data.split_at(16); 352 let (part_a, part_b) = full_data.split_at(16);
352 let crc_partially = ETH_FSC::new(part_a).update(part_b); 353 let crc_partially = ETH_FCS::new(part_a).update(part_b);
353 354
354 let crc_full = ETH_FSC::new(full_data); 355 let crc_full = ETH_FCS::new(full_data);
355 356
356 assert_eq!(crc_full.0, crc_partially.0); 357 assert_eq!(crc_full.0, crc_partially.0);
357 } 358 }
diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs
new file mode 100644
index 000000000..12737c690
--- /dev/null
+++ b/embassy-net-adin1110/src/fmt.rs
@@ -0,0 +1,254 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9macro_rules! assert {
10 ($($x:tt)*) => {
11 {
12 #[cfg(not(feature = "defmt"))]
13 ::core::assert!($($x)*);
14 #[cfg(feature = "defmt")]
15 ::defmt::assert!($($x)*);
16 }
17 };
18}
19
20macro_rules! assert_eq {
21 ($($x:tt)*) => {
22 {
23 #[cfg(not(feature = "defmt"))]
24 ::core::assert_eq!($($x)*);
25 #[cfg(feature = "defmt")]
26 ::defmt::assert_eq!($($x)*);
27 }
28 };
29}
30
31macro_rules! assert_ne {
32 ($($x:tt)*) => {
33 {
34 #[cfg(not(feature = "defmt"))]
35 ::core::assert_ne!($($x)*);
36 #[cfg(feature = "defmt")]
37 ::defmt::assert_ne!($($x)*);
38 }
39 };
40}
41
42macro_rules! debug_assert {
43 ($($x:tt)*) => {
44 {
45 #[cfg(not(feature = "defmt"))]
46 ::core::debug_assert!($($x)*);
47 #[cfg(feature = "defmt")]
48 ::defmt::debug_assert!($($x)*);
49 }
50 };
51}
52
53macro_rules! debug_assert_eq {
54 ($($x:tt)*) => {
55 {
56 #[cfg(not(feature = "defmt"))]
57 ::core::debug_assert_eq!($($x)*);
58 #[cfg(feature = "defmt")]
59 ::defmt::debug_assert_eq!($($x)*);
60 }
61 };
62}
63
64macro_rules! debug_assert_ne {
65 ($($x:tt)*) => {
66 {
67 #[cfg(not(feature = "defmt"))]
68 ::core::debug_assert_ne!($($x)*);
69 #[cfg(feature = "defmt")]
70 ::defmt::debug_assert_ne!($($x)*);
71 }
72 };
73}
74
75macro_rules! todo {
76 ($($x:tt)*) => {
77 {
78 #[cfg(not(feature = "defmt"))]
79 ::core::todo!($($x)*);
80 #[cfg(feature = "defmt")]
81 ::defmt::todo!($($x)*);
82 }
83 };
84}
85
86macro_rules! unreachable {
87 ($($x:tt)*) => {
88 {
89 #[cfg(not(feature = "defmt"))]
90 ::core::unreachable!($($x)*);
91 #[cfg(feature = "defmt")]
92 ::defmt::unreachable!($($x)*);
93 }
94 };
95}
96
97macro_rules! panic {
98 ($($x:tt)*) => {
99 {
100 #[cfg(not(feature = "defmt"))]
101 ::core::panic!($($x)*);
102 #[cfg(feature = "defmt")]
103 ::defmt::panic!($($x)*);
104 }
105 };
106}
107
108macro_rules! trace {
109 ($s:literal $(, $x:expr)* $(,)?) => {
110 {
111 #[cfg(feature = "log")]
112 ::log::trace!($s $(, $x)*);
113 #[cfg(feature = "defmt")]
114 ::defmt::trace!($s $(, $x)*);
115 #[cfg(not(any(feature = "log", feature="defmt")))]
116 let _ignored = ($( & $x ),*);
117 }
118 };
119}
120
121macro_rules! debug {
122 ($s:literal $(, $x:expr)* $(,)?) => {
123 {
124 #[cfg(feature = "log")]
125 ::log::debug!($s $(, $x)*);
126 #[cfg(feature = "defmt")]
127 ::defmt::debug!($s $(, $x)*);
128 #[cfg(not(any(feature = "log", feature="defmt")))]
129 let _ignored = ($( & $x ),*);
130 }
131 };
132}
133
134macro_rules! info {
135 ($s:literal $(, $x:expr)* $(,)?) => {
136 {
137 #[cfg(feature = "log")]
138 ::log::info!($s $(, $x)*);
139 #[cfg(feature = "defmt")]
140 ::defmt::info!($s $(, $x)*);
141 #[cfg(not(any(feature = "log", feature="defmt")))]
142 let _ignored = ($( & $x ),*);
143 }
144 };
145}
146
147macro_rules! warn {
148 ($s:literal $(, $x:expr)* $(,)?) => {
149 {
150 #[cfg(feature = "log")]
151 ::log::warn!($s $(, $x)*);
152 #[cfg(feature = "defmt")]
153 ::defmt::warn!($s $(, $x)*);
154 #[cfg(not(any(feature = "log", feature="defmt")))]
155 let _ignored = ($( & $x ),*);
156 }
157 };
158}
159
160macro_rules! error {
161 ($s:literal $(, $x:expr)* $(,)?) => {
162 {
163 #[cfg(feature = "log")]
164 ::log::error!($s $(, $x)*);
165 #[cfg(feature = "defmt")]
166 ::defmt::error!($s $(, $x)*);
167 #[cfg(not(any(feature = "log", feature="defmt")))]
168 let _ignored = ($( & $x ),*);
169 }
170 };
171}
172
173#[cfg(feature = "defmt")]
174macro_rules! unwrap {
175 ($($x:tt)*) => {
176 ::defmt::unwrap!($($x)*)
177 };
178}
179
180#[cfg(not(feature = "defmt"))]
181macro_rules! unwrap {
182 ($arg:expr) => {
183 match $crate::fmt::Try::into_result($arg) {
184 ::core::result::Result::Ok(t) => t,
185 ::core::result::Result::Err(e) => {
186 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
187 }
188 }
189 };
190 ($arg:expr, $($msg:expr),+ $(,)? ) => {
191 match $crate::fmt::Try::into_result($arg) {
192 ::core::result::Result::Ok(t) => t,
193 ::core::result::Result::Err(e) => {
194 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
195 }
196 }
197 }
198}
199
200#[derive(Debug, Copy, Clone, Eq, PartialEq)]
201pub struct NoneError;
202
203pub trait Try {
204 type Ok;
205 type Error;
206 fn into_result(self) -> Result<Self::Ok, Self::Error>;
207}
208
209impl<T> Try for Option<T> {
210 type Ok = T;
211 type Error = NoneError;
212
213 #[inline]
214 fn into_result(self) -> Result<T, NoneError> {
215 self.ok_or(NoneError)
216 }
217}
218
219impl<T, E> Try for Result<T, E> {
220 type Ok = T;
221 type Error = E;
222
223 #[inline]
224 fn into_result(self) -> Self {
225 self
226 }
227}
228
229pub struct Bytes<'a>(pub &'a [u8]);
230
231impl<'a> Debug for Bytes<'a> {
232 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233 write!(f, "{:#02x?}", self.0)
234 }
235}
236
237impl<'a> Display for Bytes<'a> {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 write!(f, "{:#02x?}", self.0)
240 }
241}
242
243impl<'a> LowerHex for Bytes<'a> {
244 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245 write!(f, "{:#02x?}", self.0)
246 }
247}
248
249#[cfg(feature = "defmt")]
250impl<'a> defmt::Format for Bytes<'a> {
251 fn format(&self, fmt: defmt::Formatter) {
252 defmt::write!(fmt, "{:02x}", self.0)
253 }
254}
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs
index c0a9b44ee..e0af7bde9 100644
--- a/embassy-net-adin1110/src/lib.rs
+++ b/embassy-net-adin1110/src/lib.rs
@@ -6,6 +6,9 @@
6#![allow(clippy::missing_panics_doc)] 6#![allow(clippy::missing_panics_doc)]
7#![doc = include_str!("../README.md")] 7#![doc = include_str!("../README.md")]
8 8
9// must go first!
10mod fmt;
11
9mod crc32; 12mod crc32;
10mod crc8; 13mod crc8;
11mod mdio; 14mod mdio;
@@ -13,19 +16,20 @@ mod phy;
13mod regs; 16mod regs;
14 17
15use ch::driver::LinkState; 18use ch::driver::LinkState;
16pub use crc32::ETH_FSC; 19pub use crc32::ETH_FCS;
17use crc8::crc8; 20use crc8::crc8;
18use embassy_futures::select::{select, Either}; 21use embassy_futures::select::{select, Either};
19use embassy_net_driver_channel as ch; 22use embassy_net_driver_channel as ch;
20use embassy_time::{Duration, Timer}; 23use embassy_time::{Duration, Timer};
21use embedded_hal_1::digital::OutputPin; 24use embedded_hal_1::digital::OutputPin;
22use embedded_hal_async::digital::Wait; 25use embedded_hal_async::digital::Wait;
23use embedded_hal_async::spi::{Operation, SpiDevice}; 26use embedded_hal_async::spi::{Error, Operation, SpiDevice};
24use heapless::Vec; 27use heapless::Vec;
25pub use mdio::MdioBus; 28pub use mdio::MdioBus;
26pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; 29pub use phy::{Phy10BaseT1x, RegsC22, RegsC45};
27pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; 30pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
28 31
32use crate::fmt::Bytes;
29use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; 33use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
30 34
31pub const PHYID: u32 = 0x0283_BC91; 35pub const PHYID: u32 = 0x0283_BC91;
@@ -35,16 +39,22 @@ pub const PHYID: u32 = 0x0283_BC91;
35#[cfg_attr(feature = "defmt", derive(defmt::Format))] 39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36#[allow(non_camel_case_types)] 40#[allow(non_camel_case_types)]
37pub enum AdinError<E> { 41pub enum AdinError<E> {
42 /// SPI-BUS Error
38 Spi(E), 43 Spi(E),
39 SENDERROR, 44 /// Ethernet FCS error
40 READERROR, 45 FCS,
41 CRC, 46 /// SPI Header CRC error
47 SPI_CRC,
48 /// Received or sended ethernet packet is too big
42 PACKET_TOO_BIG, 49 PACKET_TOO_BIG,
50 /// Received or sended ethernet packet is too small
43 PACKET_TOO_SMALL, 51 PACKET_TOO_SMALL,
52 /// MDIO transaction timeout
44 MDIO_ACC_TIMEOUT, 53 MDIO_ACC_TIMEOUT,
45} 54}
46 55
47pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>; 56pub type AEResult<T, SPIError> = core::result::Result<T, AdinError<SPIError>>;
57/// Internet PHY address
48pub const MDIO_PHY_ADDR: u8 = 0x01; 58pub const MDIO_PHY_ADDR: u8 = 0x01;
49 59
50/// Maximum Transmission Unit 60/// Maximum Transmission Unit
@@ -58,21 +68,25 @@ const TURN_AROUND_BYTE: u8 = 0x00;
58 68
59/// Packet minimal frame/packet length 69/// Packet minimal frame/packet length
60const ETH_MIN_LEN: usize = 64; 70const ETH_MIN_LEN: usize = 64;
61
62/// Ethernet `Frame Check Sequence` length 71/// Ethernet `Frame Check Sequence` length
63const FSC_LEN: usize = 4; 72const FCS_LEN: usize = 4;
73/// Packet minimal frame/packet length without `Frame Check Sequence` length
74const ETH_MIN_WITHOUT_FCS_LEN: usize = ETH_MIN_LEN - FCS_LEN;
75
64/// SPI Header, contains SPI action and register id. 76/// SPI Header, contains SPI action and register id.
65const SPI_HEADER_LEN: usize = 2; 77const SPI_HEADER_LEN: usize = 2;
66/// SPI Header CRC length 78/// SPI Header CRC length
67const SPI_HEADER_CRC_LEN: usize = 1; 79const SPI_HEADER_CRC_LEN: usize = 1;
68/// Frame Header, 80/// SPI Header Turn Around length
81const SPI_HEADER_TA_LEN: usize = 1;
82/// Frame Header length
69const FRAME_HEADER_LEN: usize = 2; 83const FRAME_HEADER_LEN: usize = 2;
84/// Space for last bytes to create multipule 4 bytes on the end of a FIFO read/write.
85const SPI_SPACE_MULTIPULE: usize = 3;
70 86
71// P1 = 0x00, P2 = 0x01 87/// P1 = 0x00, P2 = 0x01
72const PORT_ID_BYTE: u8 = 0x00; 88const PORT_ID_BYTE: u8 = 0x00;
73 89
74pub type Packet = Vec<u8, { SPI_HEADER_LEN + FRAME_HEADER_LEN + MTU + FSC_LEN + 1 + 4 }>;
75
76/// Type alias for the embassy-net driver for ADIN1110 90/// Type alias for the embassy-net driver for ADIN1110
77pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; 91pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
78 92
@@ -96,12 +110,18 @@ pub struct ADIN1110<SPI> {
96 spi: SPI, 110 spi: SPI,
97 /// Enable CRC on SPI transfer. 111 /// Enable CRC on SPI transfer.
98 /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled. 112 /// This must match with the hardware pin `SPI_CFG0` were low = CRC enable, high = CRC disabled.
99 crc: bool, 113 spi_crc: bool,
114 /// Append FCS by the application of transmit packet, false = FCS is appended by the MAC, true = FCS appended by the application.
115 append_fcs_on_tx: bool,
100} 116}
101 117
102impl<SPI: SpiDevice> ADIN1110<SPI> { 118impl<SPI: SpiDevice> ADIN1110<SPI> {
103 pub fn new(spi: SPI, crc: bool) -> Self { 119 pub fn new(spi: SPI, spi_crc: bool, append_fcs_on_tx: bool) -> Self {
104 Self { spi, crc } 120 Self {
121 spi,
122 spi_crc,
123 append_fcs_on_tx,
124 }
105 } 125 }
106 126
107 pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SPI::Error> { 127 pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SPI::Error> {
@@ -112,33 +132,32 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
112 spi_hdr.set_addr(reg); 132 spi_hdr.set_addr(reg);
113 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); 133 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
114 134
115 if self.crc { 135 if self.spi_crc {
116 // Add CRC for header data 136 // Add CRC for header data
117 let _ = tx_buf.push(crc8(&tx_buf)); 137 let _ = tx_buf.push(crc8(&tx_buf));
118 } 138 }
119 139
120 // Turn around byte, TODO: Unknown that this is. 140 // Turn around byte, give the chip the time to access/setup the answer data.
121 let _ = tx_buf.push(TURN_AROUND_BYTE); 141 let _ = tx_buf.push(TURN_AROUND_BYTE);
122 142
123 let mut rx_buf = [0; 5]; 143 let mut rx_buf = [0; 5];
124 144
125 let spi_read_len = if self.crc { rx_buf.len() } else { rx_buf.len() - 1 }; 145 let spi_read_len = if self.spi_crc { rx_buf.len() } else { rx_buf.len() - 1 };
126 146
127 let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])]; 147 let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])];
128 148
129 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; 149 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
130 150
131 if self.crc { 151 if self.spi_crc {
132 let crc = crc8(&rx_buf[0..4]); 152 let crc = crc8(&rx_buf[0..4]);
133 if crc != rx_buf[4] { 153 if crc != rx_buf[4] {
134 return Err(AdinError::CRC); 154 return Err(AdinError::SPI_CRC);
135 } 155 }
136 } 156 }
137 157
138 let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap()); 158 let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap());
139 159
140 #[cfg(feature = "defmt")] 160 trace!("REG Read {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf));
141 defmt::trace!("REG Read {} = {:08x} SPI {:02x}", reg, value, &tx_buf);
142 161
143 Ok(value) 162 Ok(value)
144 } 163 }
@@ -152,7 +171,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
152 spi_hdr.set_addr(reg); 171 spi_hdr.set_addr(reg);
153 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); 172 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
154 173
155 if self.crc { 174 if self.spi_crc {
156 // Add CRC for header data 175 // Add CRC for header data
157 let _ = tx_buf.push(crc8(&tx_buf)); 176 let _ = tx_buf.push(crc8(&tx_buf));
158 } 177 }
@@ -160,13 +179,12 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
160 let val = value.to_be_bytes(); 179 let val = value.to_be_bytes();
161 let _ = tx_buf.extend_from_slice(val.as_slice()); 180 let _ = tx_buf.extend_from_slice(val.as_slice());
162 181
163 if self.crc { 182 if self.spi_crc {
164 // Add CRC for header data 183 // Add CRC for header data
165 let _ = tx_buf.push(crc8(val.as_slice())); 184 let _ = tx_buf.push(crc8(val.as_slice()));
166 } 185 }
167 186
168 #[cfg(feature = "defmt")] 187 trace!("REG Write {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf));
169 defmt::trace!("REG Write {} = {:08x} SPI {:02x}", reg, value, &tx_buf);
170 188
171 self.spi.write(&tx_buf).await.map_err(AdinError::Spi) 189 self.spi.write(&tx_buf).await.map_err(AdinError::Spi)
172 } 190 }
@@ -187,22 +205,23 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
187 } 205 }
188 206
189 /// Read out fifo ethernet packet memory received via the wire. 207 /// Read out fifo ethernet packet memory received via the wire.
190 pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult<usize, SPI::Error> { 208 pub async fn read_fifo(&mut self, frame: &mut [u8]) -> AEResult<usize, SPI::Error> {
191 let mut tx_buf = Vec::<u8, 16>::new(); 209 const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + SPI_HEADER_TA_LEN;
210 const TAIL_LEN: usize = FCS_LEN + SPI_SPACE_MULTIPULE;
192 211
193 // Size of the frame, also includes the appednded header. 212 let mut tx_buf = Vec::<u8, HEAD_LEN>::new();
194 let packet_size = self.read_reg(sr::RX_FSIZE).await? as usize;
195 213
196 // Packet read of write to the MAC packet buffer must be a multipul of 4! 214 // Size of the frame, also includes the `frame header` and `FCS`.
197 let read_size = packet_size.next_multiple_of(4); 215 let fifo_frame_size = self.read_reg(sr::RX_FSIZE).await? as usize;
198 216
199 if packet_size < (SPI_HEADER_LEN + FSC_LEN) { 217 if fifo_frame_size < ETH_MIN_LEN + FRAME_HEADER_LEN {
200 return Err(AdinError::PACKET_TOO_SMALL); 218 return Err(AdinError::PACKET_TOO_SMALL);
201 } 219 }
202 220
203 if read_size > packet.len() { 221 let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN;
204 #[cfg(feature = "defmt")] 222
205 defmt::trace!("MAX: {} WANT: {}", packet.len(), read_size); 223 if packet_size > frame.len() {
224 trace!("MAX: {} WANT: {}", frame.len(), packet_size);
206 return Err(AdinError::PACKET_TOO_BIG); 225 return Err(AdinError::PACKET_TOO_BIG);
207 } 226 }
208 227
@@ -211,7 +230,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
211 spi_hdr.set_addr(sr::RX); 230 spi_hdr.set_addr(sr::RX);
212 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()); 231 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
213 232
214 if self.crc { 233 if self.spi_crc {
215 // Add CRC for header data 234 // Add CRC for header data
216 let _ = tx_buf.push(crc8(&tx_buf)); 235 let _ = tx_buf.push(crc8(&tx_buf));
217 } 236 }
@@ -219,29 +238,37 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
219 // Turn around byte, TODO: Unknown that this is. 238 // Turn around byte, TODO: Unknown that this is.
220 let _ = tx_buf.push(TURN_AROUND_BYTE); 239 let _ = tx_buf.push(TURN_AROUND_BYTE);
221 240
222 let spi_packet = &mut packet[0..read_size]; 241 let mut frame_header = [0, 0];
242 let mut fcs_and_extra = [0; TAIL_LEN];
223 243
224 assert_eq!(spi_packet.len() & 0x03, 0x00); 244 // Packet read of write to the MAC packet buffer must be a multipul of 4!
225 245 let tail_size = (fifo_frame_size & 0x03) + FCS_LEN;
226 let mut pkt_header = [0, 0];
227 let mut fsc = [0, 0, 0, 0];
228 246
229 let mut spi_op = [ 247 let mut spi_op = [
230 Operation::Write(&tx_buf), 248 Operation::Write(&tx_buf),
231 Operation::Read(&mut pkt_header), 249 Operation::Read(&mut frame_header),
232 Operation::Read(spi_packet), 250 Operation::Read(&mut frame[0..packet_size]),
233 Operation::Read(&mut fsc), 251 Operation::Read(&mut fcs_and_extra[0..tail_size]),
234 ]; 252 ];
235 253
236 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?; 254 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
237 255
238 Ok(packet_size as usize) 256 // According to register `CONFIG2`, bit 5 `CRC_APPEND` discription:
257 // "Similarly, on receive, the CRC32 is forwarded with the frame to the host where the host must verify it is correct."
258 // The application must allways check the FCS. It seems that the MAC/PHY has no option to handle this.
259 let fcs_calc = ETH_FCS::new(&frame[0..packet_size]);
260
261 if fcs_calc.hton_bytes() == fcs_and_extra[0..4] {
262 Ok(packet_size)
263 } else {
264 Err(AdinError::FCS)
265 }
239 } 266 }
240 267
241 /// Write to fifo ethernet packet memory send over the wire. 268 /// Write to fifo ethernet packet memory send over the wire.
242 pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> { 269 pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SPI::Error> {
243 const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN; 270 const HEAD_LEN: usize = SPI_HEADER_LEN + SPI_HEADER_CRC_LEN + FRAME_HEADER_LEN;
244 const TAIL_LEN: usize = ETH_MIN_LEN - FSC_LEN + FSC_LEN + 1; 271 const TAIL_LEN: usize = ETH_MIN_LEN - FCS_LEN + FCS_LEN + SPI_SPACE_MULTIPULE;
245 272
246 if frame.len() < (6 + 6 + 2) { 273 if frame.len() < (6 + 6 + 2) {
247 return Err(AdinError::PACKET_TOO_SMALL); 274 return Err(AdinError::PACKET_TOO_SMALL);
@@ -264,7 +291,7 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
264 .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice()) 291 .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice())
265 .map_err(|_e| AdinError::PACKET_TOO_BIG)?; 292 .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
266 293
267 if self.crc { 294 if self.spi_crc {
268 // Add CRC for header data 295 // Add CRC for header data
269 head_data 296 head_data
270 .push(crc8(&head_data[0..2])) 297 .push(crc8(&head_data[0..2]))
@@ -276,43 +303,47 @@ impl<SPI: SpiDevice> ADIN1110<SPI> {
276 .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice()) 303 .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice())
277 .map_err(|_e| AdinError::PACKET_TOO_BIG)?; 304 .map_err(|_e| AdinError::PACKET_TOO_BIG)?;
278 305
279 let mut frame_fcs = ETH_FSC::new(frame);
280
281 // ADIN1110 MAC and PHY don´t accept ethernet packet smaller than 64 bytes. 306 // ADIN1110 MAC and PHY don´t accept ethernet packet smaller than 64 bytes.
282 // So padded the data minus the FCS, FCS is automatilly added to by the MAC. 307 // So padded the data minus the FCS, FCS is automatilly added to by the MAC.
283 if let Some(pad_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(frame.len()) { 308 if frame.len() < ETH_MIN_WITHOUT_FCS_LEN {
284 let _ = tail_data.resize(pad_len, 0x00); 309 let _ = tail_data.resize(ETH_MIN_WITHOUT_FCS_LEN - frame.len(), 0x00);
285 frame_fcs = frame_fcs.update(&tail_data);
286 } 310 }
287 311
288 // Add ethernet FCS only over the ethernet packet. 312 // Append FCS by the application
289 // Only usefull when `CONFIG0`, `Transmit Frame Check Sequence Validation Enable` bit is enabled. 313 if self.append_fcs_on_tx {
290 let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice()); 314 let mut frame_fcs = ETH_FCS::new(frame);
315
316 if !tail_data.is_empty() {
317 frame_fcs = frame_fcs.update(&tail_data);
318 }
319
320 let _ = tail_data.extend_from_slice(frame_fcs.hton_bytes().as_slice());
321 }
291 322
292 // len = frame_size + optional padding + 2 bytes Frame header 323 // len = frame_size + optional padding + 2 bytes Frame header
293 let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN; 324 let send_len_orig = frame.len() + tail_data.len() + FRAME_HEADER_LEN;
294 let spi_pad_len = send_len_orig.next_multiple_of(4); 325
295 let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?; 326 let send_len = u32::try_from(send_len_orig).map_err(|_| AdinError::PACKET_TOO_BIG)?;
296 327
297 // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes! 328 // Packet read of write to the MAC packet buffer must be a multipul of 4 bytes!
298 if spi_pad_len != send_len_orig { 329 let pad_len = send_len_orig & 0x03;
299 let spi_pad_len = spi_pad_len - send_len_orig; 330 if pad_len != 0 {
300 let _ = tail_data.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE, DONT_CARE_BYTE][..spi_pad_len]); 331 let spi_pad_len = 4 - pad_len + tail_data.len();
332 let _ = tail_data.resize(spi_pad_len, DONT_CARE_BYTE);
301 } 333 }
302 334
303 #[cfg(feature = "defmt")] 335 self.write_reg(sr::TX_FSIZE, send_len).await?;
304 defmt::trace!( 336
305 "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", 337 trace!(
338 "TX: hdr {} [{}] {}-{}-{} SIZE: {}",
306 head_data.len(), 339 head_data.len(),
307 frame.len(), 340 frame.len(),
308 head_data.as_slice(), 341 Bytes(head_data.as_slice()),
309 frame, 342 Bytes(frame),
310 tail_data.as_slice(), 343 Bytes(tail_data.as_slice()),
311 send_len, 344 send_len,
312 ); 345 );
313 346
314 self.write_reg(sr::TX_FSIZE, send_len).await?;
315
316 let mut transaction = [ 347 let mut transaction = [
317 Operation::Write(head_data.as_slice()), 348 Operation::Write(head_data.as_slice()),
318 Operation::Write(frame), 349 Operation::Write(frame),
@@ -414,16 +445,14 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
414 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); 445 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
415 446
416 loop { 447 loop {
417 #[cfg(feature = "defmt")] 448 debug!("Waiting for interrupts");
418 defmt::debug!("Waiting for interrupts");
419 match select(self.int.wait_for_low(), tx_chan.tx_buf()).await { 449 match select(self.int.wait_for_low(), tx_chan.tx_buf()).await {
420 Either::First(_) => { 450 Either::First(_) => {
421 let mut status1_clr = Status1(0); 451 let mut status1_clr = Status1(0);
422 let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap()); 452 let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap());
423 453
424 while status1.p1_rx_rdy() { 454 while status1.p1_rx_rdy() {
425 #[cfg(feature = "defmt")] 455 debug!("alloc RX packet buffer");
426 defmt::debug!("alloc RX packet buffer");
427 match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await { 456 match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await {
428 // Handle frames that needs to transmit from the wire. 457 // Handle frames that needs to transmit from the wire.
429 // Note: rx_chan.rx_buf() channel don´t accept new request 458 // Note: rx_chan.rx_buf() channel don´t accept new request
@@ -435,17 +464,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
435 } 464 }
436 Err(e) => match e { 465 Err(e) => match e {
437 AdinError::PACKET_TOO_BIG => { 466 AdinError::PACKET_TOO_BIG => {
438 #[cfg(feature = "defmt")] 467 error!("RX Packet too big, DROP");
439 defmt::error!("RX Packet to big, DROP");
440 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); 468 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap();
441 } 469 }
442 AdinError::Spi(_) => { 470 AdinError::PACKET_TOO_SMALL => {
443 #[cfg(feature = "defmt")] 471 error!("RX Packet too small, DROP");
444 defmt::error!("RX Spi error") 472 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap();
473 }
474 AdinError::Spi(e) => {
475 error!("RX Spi error {}", e.kind());
445 } 476 }
446 _ => { 477 e => {
447 #[cfg(feature = "defmt")] 478 error!("RX Error {:?}", e);
448 defmt::error!("RX Error")
449 } 479 }
450 }, 480 },
451 }, 481 },
@@ -460,21 +490,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
460 490
461 let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap()); 491 let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap());
462 if status1.0 & !0x1b != 0 { 492 if status1.0 & !0x1b != 0 {
463 #[cfg(feature = "defmt")] 493 error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0);
464 defmt::error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0);
465 } 494 }
466 495
467 if status1.tx_rdy() { 496 if status1.tx_rdy() {
468 status1_clr.set_tx_rdy(true); 497 status1_clr.set_tx_rdy(true);
469 #[cfg(feature = "defmt")] 498 trace!("TX_DONE");
470 defmt::info!("TX_DONE");
471 } 499 }
472 500
473 if status1.link_change() { 501 if status1.link_change() {
474 let link = status1.p1_link_status(); 502 let link = status1.p1_link_status();
475 self.is_link_up = link; 503 self.is_link_up = link;
476 504
477 #[cfg(feature = "defmt")]
478 if link { 505 if link {
479 let link_status = self 506 let link_status = self
480 .mac 507 .mac
@@ -494,9 +521,9 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
494 .await 521 .await
495 .unwrap(); 522 .unwrap();
496 523
497 defmt::info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); 524 info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse);
498 } else { 525 } else {
499 defmt::info!("LINK Changed: Link Down"); 526 info!("LINK Changed: Link Down");
500 } 527 }
501 528
502 state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down }); 529 state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down });
@@ -504,50 +531,42 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
504 } 531 }
505 532
506 if status1.tx_ecc_err() { 533 if status1.tx_ecc_err() {
507 #[cfg(feature = "defmt")] 534 error!("SPI TX_ECC_ERR error, CLEAR TX FIFO");
508 defmt::error!("SPI TX_ECC_ERR error, CLEAR TX FIFO");
509 self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap(); 535 self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap();
510 status1_clr.set_tx_ecc_err(true); 536 status1_clr.set_tx_ecc_err(true);
511 } 537 }
512 538
513 if status1.rx_ecc_err() { 539 if status1.rx_ecc_err() {
514 #[cfg(feature = "defmt")] 540 error!("SPI RX_ECC_ERR error");
515 defmt::error!("SPI RX_ECC_ERR error");
516 status1_clr.set_rx_ecc_err(true); 541 status1_clr.set_rx_ecc_err(true);
517 } 542 }
518 543
519 if status1.spi_err() { 544 if status1.spi_err() {
520 #[cfg(feature = "defmt")] 545 error!("SPI SPI_ERR CRC error");
521 defmt::error!("SPI SPI_ERR CRC error");
522 status1_clr.set_spi_err(true); 546 status1_clr.set_spi_err(true);
523 } 547 }
524 548
525 if status0.phyint() { 549 if status0.phyint() {
526 #[cfg_attr(not(feature = "defmt"), allow(unused_variables))]
527 let crsm_irq_st = self 550 let crsm_irq_st = self
528 .mac 551 .mac
529 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into()) 552 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into())
530 .await 553 .await
531 .unwrap(); 554 .unwrap();
532 555
533 #[cfg_attr(not(feature = "defmt"), allow(unused_variables))]
534 let phy_irq_st = self 556 let phy_irq_st = self
535 .mac 557 .mac
536 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into()) 558 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into())
537 .await 559 .await
538 .unwrap(); 560 .unwrap();
539 561
540 #[cfg(feature = "defmt")] 562 warn!(
541 defmt::warn!(
542 "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}", 563 "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}",
543 crsm_irq_st, 564 crsm_irq_st, phy_irq_st
544 phy_irq_st
545 ); 565 );
546 } 566 }
547 567
548 if status0.txfcse() { 568 if status0.txfcse() {
549 #[cfg(feature = "defmt")] 569 error!("Ethernet Frame FCS and calc FCS don't match!");
550 defmt::error!("SPE CHIP PHY TX Frame CRC error");
551 } 570 }
552 571
553 // Clear status0 572 // Clear status0
@@ -572,12 +591,12 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
572 spi_dev: SPI, 591 spi_dev: SPI,
573 int: INT, 592 int: INT,
574 mut reset: RST, 593 mut reset: RST,
575 crc: bool, 594 spi_crc: bool,
595 append_fcs_on_tx: bool,
576) -> (Device<'_>, Runner<'_, SPI, INT, RST>) { 596) -> (Device<'_>, Runner<'_, SPI, INT, RST>) {
577 use crate::regs::{IMask0, IMask1}; 597 use crate::regs::{IMask0, IMask1};
578 598
579 #[cfg(feature = "defmt")] 599 info!("INIT ADIN1110");
580 defmt::info!("INIT ADIN1110");
581 600
582 // Reset sequence 601 // Reset sequence
583 reset.set_low().unwrap(); 602 reset.set_low().unwrap();
@@ -591,37 +610,40 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
591 Timer::after(Duration::from_millis(50)).await; 610 Timer::after(Duration::from_millis(50)).await;
592 611
593 // Create device 612 // Create device
594 let mut mac = ADIN1110::new(spi_dev, crc); 613 let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
595 614
596 // Check PHYID 615 // Check PHYID
597 let id = mac.read_reg(sr::PHYID).await.unwrap(); 616 let id = mac.read_reg(sr::PHYID).await.unwrap();
598 assert_eq!(id, PHYID); 617 assert_eq!(id, PHYID);
599 618
600 #[cfg(feature = "defmt")] 619 debug!("SPE: CHIP MAC/ID: {:08x}", id);
601 defmt::debug!("SPE: CHIP MAC/ID: {:08x}", id);
602 620
603 #[cfg(feature = "defmt")] 621 #[cfg(any(feature = "defmt", feature = "log"))]
604 let adin_phy = Phy10BaseT1x::default(); 622 {
605 #[cfg(feature = "defmt")] 623 let adin_phy = Phy10BaseT1x::default();
606 let phy_id = adin_phy.get_id(&mut mac).await.unwrap(); 624 let phy_id = adin_phy.get_id(&mut mac).await.unwrap();
607 #[cfg(feature = "defmt")] 625 debug!("SPE: CHIP: PHY ID: {:08x}", phy_id);
608 defmt::debug!("SPE: CHIP: PHY ID: {:08x}", phy_id); 626 }
609 627
610 let mi_control = mac.read_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8).await.unwrap(); 628 let mi_control = mac.read_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8).await.unwrap();
611 #[cfg(feature = "defmt")] 629 debug!("SPE CHIP PHY MI_CONTROL {:04x}", mi_control);
612 defmt::println!("SPE CHIP PHY MI_CONTROL {:04x}", mi_control);
613 if mi_control & 0x0800 != 0 { 630 if mi_control & 0x0800 != 0 {
614 let val = mi_control & !0x0800; 631 let val = mi_control & !0x0800;
615 #[cfg(feature = "defmt")] 632 debug!("SPE CHIP PHY MI_CONTROL Disable PowerDown");
616 defmt::println!("SPE CHIP PHY MI_CONTROL Disable PowerDown");
617 mac.write_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8, val) 633 mac.write_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8, val)
618 .await 634 .await
619 .unwrap(); 635 .unwrap();
620 } 636 }
621 637
622 // Config2: CRC_APPEND 638 // Config0
639 let mut config0 = Config0(0x0000_0006);
640 config0.set_txfcsve(mac.append_fcs_on_tx);
641 mac.write_reg(sr::CONFIG0, config0.0).await.unwrap();
642
643 // Config2
623 let mut config2 = Config2(0x0000_0800); 644 let mut config2 = Config2(0x0000_0800);
624 config2.set_crc_append(true); 645 // crc_append must be disable if tx_fcs_validation_enable is true!
646 config2.set_crc_append(!mac.append_fcs_on_tx);
625 mac.write_reg(sr::CONFIG2, config2.0).await.unwrap(); 647 mac.write_reg(sr::CONFIG2, config2.0).await.unwrap();
626 648
627 // Pin Mux Config 1 649 // Pin Mux Config 1
@@ -701,6 +723,7 @@ mod tests {
701 use embedded_hal_1::digital::{ErrorType, OutputPin}; 723 use embedded_hal_1::digital::{ErrorType, OutputPin};
702 use embedded_hal_async::delay::DelayUs; 724 use embedded_hal_async::delay::DelayUs;
703 use embedded_hal_bus::spi::ExclusiveDevice; 725 use embedded_hal_bus::spi::ExclusiveDevice;
726 use embedded_hal_mock::common::Generic;
704 use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction}; 727 use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
705 728
706 #[derive(Debug, Default)] 729 #[derive(Debug, Default)]
@@ -739,6 +762,30 @@ mod tests {
739 } 762 }
740 } 763 }
741 764
765 struct TestHarnass {
766 spe: ADIN1110<ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>>,
767 spi: Generic<SpiTransaction>,
768 }
769
770 impl TestHarnass {
771 pub fn new(expectations: &[SpiTransaction], spi_crc: bool, append_fcs_on_tx: bool) -> Self {
772 let cs = CsPinMock::default();
773 let delay = MockDelay {};
774 let spi = SpiMock::new(expectations);
775 let spi_dev: ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay> =
776 ExclusiveDevice::new(spi.clone(), cs, delay);
777 let spe: ADIN1110<
778 ExclusiveDevice<embedded_hal_mock::common::Generic<SpiTransaction>, CsPinMock, MockDelay>,
779 > = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
780
781 Self { spe, spi }
782 }
783
784 pub fn done(&mut self) {
785 self.spi.done();
786 }
787 }
788
742 #[futures_test::test] 789 #[futures_test::test]
743 async fn mac_read_registers_without_crc() { 790 async fn mac_read_registers_without_crc() {
744 // Configure expectations 791 // Configure expectations
@@ -752,22 +799,20 @@ mod tests {
752 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]), 799 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]),
753 SpiTransaction::flush(), 800 SpiTransaction::flush(),
754 ]; 801 ];
755 let mut spi = SpiMock::new(&expectations);
756 802
757 let cs = CsPinMock::default(); 803 // Create TestHarnass
758 let delay = MockDelay {}; 804 let mut th = TestHarnass::new(&expectations, false, true);
759 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
760 let mut spe = ADIN1110::new(spi_dev, false);
761 805
762 // Read PHIID 806 // Read PHIID
763 let val = spe.read_reg(sr::PHYID).await.expect("Error"); 807 let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
764 assert_eq!(val, 0x0283_BC91); 808 assert_eq!(val, 0x0283_BC91);
765 809
766 // Read CAPAVILITY 810 // Read CAPAVILITY
767 let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); 811 let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
768 assert_eq!(val, 0x0000_06C3); 812 assert_eq!(val, 0x0000_06C3);
769 813
770 spi.done(); 814 // Mark end of the SPI test.
815 th.done();
771 } 816 }
772 817
773 #[futures_test::test] 818 #[futures_test::test]
@@ -783,26 +828,23 @@ mod tests {
783 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]), 828 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]),
784 SpiTransaction::flush(), 829 SpiTransaction::flush(),
785 ]; 830 ];
786 let mut spi = SpiMock::new(&expectations);
787 831
788 let cs = CsPinMock::default(); 832 // Create TestHarnass
789 let delay = MockDelay {}; 833 let mut th = TestHarnass::new(&expectations, true, true);
790 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
791
792 let mut spe = ADIN1110::new(spi_dev, true);
793 834
794 assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215); 835 assert_eq!(crc8(0x0283_BC91_u32.to_be_bytes().as_slice()), 215);
795 assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57); 836 assert_eq!(crc8(0x0000_06C3_u32.to_be_bytes().as_slice()), 57);
796 837
797 // Read PHIID 838 // Read PHIID
798 let val = spe.read_reg(sr::PHYID).await.expect("Error"); 839 let val = th.spe.read_reg(sr::PHYID).await.expect("Error");
799 assert_eq!(val, 0x0283_BC91); 840 assert_eq!(val, 0x0283_BC91);
800 841
801 // Read CAPAVILITY 842 // Read CAPAVILITY
802 let val = spe.read_reg(sr::CAPABILITY).await.expect("Error"); 843 let val = th.spe.read_reg(sr::CAPABILITY).await.expect("Error");
803 assert_eq!(val, 0x0000_06C3); 844 assert_eq!(val, 0x0000_06C3);
804 845
805 spi.done(); 846 // Mark end of the SPI test.
847 th.done();
806 } 848 }
807 849
808 #[futures_test::test] 850 #[futures_test::test]
@@ -812,18 +854,15 @@ mod tests {
812 SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]), 854 SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]),
813 SpiTransaction::flush(), 855 SpiTransaction::flush(),
814 ]; 856 ];
815 let mut spi = SpiMock::new(&expectations);
816
817 let cs = CsPinMock::default();
818 let delay = MockDelay {};
819 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
820 857
821 let mut spe = ADIN1110::new(spi_dev, false); 858 // Create TestHarnass
859 let mut th = TestHarnass::new(&expectations, false, true);
822 860
823 // Write reg: 0x1FFF 861 // Write reg: 0x1FFF
824 assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); 862 assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
825 863
826 spi.done(); 864 // Mark end of the SPI test.
865 th.done();
827 } 866 }
828 867
829 #[futures_test::test] 868 #[futures_test::test]
@@ -834,17 +873,14 @@ mod tests {
834 SpiTransaction::flush(), 873 SpiTransaction::flush(),
835 ]; 874 ];
836 875
837 // Basic test init block 876 // Create TestHarnass
838 let mut spi = SpiMock::new(&expectations); 877 let mut th = TestHarnass::new(&expectations, true, true);
839 let cs = CsPinMock::default();
840 let delay = MockDelay {};
841 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
842 let mut spe = ADIN1110::new(spi_dev, true);
843 878
844 // Write reg: 0x1FFF 879 // Write reg: 0x1FFF
845 assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok()); 880 assert!(th.spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
846 881
847 spi.done(); 882 // Mark end of the SPI test.
883 th.done();
848 } 884 }
849 885
850 #[futures_test::test] 886 #[futures_test::test]
@@ -865,7 +901,7 @@ mod tests {
865 901
866 let mut tail = std::vec::Vec::<u8>::with_capacity(100); 902 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
867 // Padding 903 // Padding
868 if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { 904 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
869 tail.resize(padding_len, 0x00); 905 tail.resize(padding_len, 0x00);
870 } 906 }
871 // Packet FCS + optinal padding 907 // Packet FCS + optinal padding
@@ -874,17 +910,49 @@ mod tests {
874 expectations.push(SpiTransaction::write_vec(tail)); 910 expectations.push(SpiTransaction::write_vec(tail));
875 expectations.push(SpiTransaction::flush()); 911 expectations.push(SpiTransaction::flush());
876 912
877 let mut spi = SpiMock::new(&expectations); 913 // Create TestHarnass
914 let mut th = TestHarnass::new(&expectations, true, true);
878 915
879 let cs = CsPinMock::default(); 916 assert!(th.spe.write_fifo(&packet).await.is_ok());
880 let delay = MockDelay {};
881 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
882 917
883 let mut spe = ADIN1110::new(spi_dev, true); 918 // Mark end of the SPI test.
919 th.done();
920 }
921
922 #[futures_test::test]
923 async fn write_packet_to_fifo_minimal_with_crc_without_fcs() {
924 // Configure expectations
925 let mut expectations = vec![];
884 926
885 assert!(spe.write_fifo(&packet).await.is_ok()); 927 // Write TX_SIZE reg
928 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 62, 186]));
929 expectations.push(SpiTransaction::flush());
886 930
887 spi.done(); 931 // Write TX reg.
932 // SPI Header + optional CRC + Frame Header
933 expectations.push(SpiTransaction::write_vec(vec![160, 49, 143, 0, 0]));
934 // Packet data
935 let packet = [0xFF_u8; 60];
936 expectations.push(SpiTransaction::write_vec(packet.to_vec()));
937
938 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
939 // Padding
940 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
941 tail.resize(padding_len, 0x00);
942 }
943 // Packet FCS + optinal padding
944 tail.extend_from_slice(&[DONT_CARE_BYTE, DONT_CARE_BYTE]);
945
946 expectations.push(SpiTransaction::write_vec(tail));
947 expectations.push(SpiTransaction::flush());
948
949 // Create TestHarnass
950 let mut th = TestHarnass::new(&expectations, true, false);
951
952 assert!(th.spe.write_fifo(&packet).await.is_ok());
953
954 // Mark end of the SPI test.
955 th.done();
888 } 956 }
889 957
890 #[futures_test::test] 958 #[futures_test::test]
@@ -906,7 +974,7 @@ mod tests {
906 974
907 let mut tail = std::vec::Vec::<u8>::with_capacity(100); 975 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
908 // Padding 976 // Padding
909 if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { 977 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
910 tail.resize(padding_len, 0x00); 978 tail.resize(padding_len, 0x00);
911 } 979 }
912 // Packet FCS + optinal padding 980 // Packet FCS + optinal padding
@@ -915,17 +983,13 @@ mod tests {
915 expectations.push(SpiTransaction::write_vec(tail)); 983 expectations.push(SpiTransaction::write_vec(tail));
916 expectations.push(SpiTransaction::flush()); 984 expectations.push(SpiTransaction::flush());
917 985
918 let mut spi = SpiMock::new(&expectations); 986 // Create TestHarnass
919 987 let mut th = TestHarnass::new(&expectations, true, true);
920 let cs = CsPinMock::default();
921 let delay = MockDelay {};
922 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
923 988
924 let mut spe = ADIN1110::new(spi_dev, true); 989 assert!(th.spe.write_fifo(&packet).await.is_ok());
925 990
926 assert!(spe.write_fifo(&packet).await.is_ok()); 991 // Mark end of the SPI test.
927 992 th.done();
928 spi.done();
929 } 993 }
930 994
931 #[futures_test::test] 995 #[futures_test::test]
@@ -938,24 +1002,23 @@ mod tests {
938 // Max packet size = MAX_BUFF - FRAME_HEADER_LEN 1002 // Max packet size = MAX_BUFF - FRAME_HEADER_LEN
939 let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1]; 1003 let packet = [0xAA_u8; MAX_BUFF - FRAME_HEADER_LEN + 1];
940 1004
941 let mut spi = SpiMock::new(&expectations); 1005 // Create TestHarnass
942 1006 let mut th = TestHarnass::new(&expectations, true, true);
943 let cs = CsPinMock::default();
944 let delay = MockDelay {};
945 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
946
947 let mut spe = ADIN1110::new(spi_dev, true);
948 1007
949 // minimal 1008 // minimal
950 assert!(matches!( 1009 assert!(matches!(
951 spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await, 1010 th.spe.write_fifo(&packet[0..(6 + 6 + 2 - 1)]).await,
952 Err(AdinError::PACKET_TOO_SMALL) 1011 Err(AdinError::PACKET_TOO_SMALL)
953 )); 1012 ));
954 1013
955 // max + 1 1014 // max + 1
956 assert!(matches!(spe.write_fifo(&packet).await, Err(AdinError::PACKET_TOO_BIG))); 1015 assert!(matches!(
1016 th.spe.write_fifo(&packet).await,
1017 Err(AdinError::PACKET_TOO_BIG)
1018 ));
957 1019
958 spi.done(); 1020 // Mark end of the SPI test.
1021 th.done();
959 } 1022 }
960 1023
961 #[futures_test::test] 1024 #[futures_test::test]
@@ -979,7 +1042,7 @@ mod tests {
979 1042
980 let mut tail = std::vec::Vec::<u8>::with_capacity(100); 1043 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
981 // Padding 1044 // Padding
982 if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { 1045 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
983 tail.resize(padding_len, 0x00); 1046 tail.resize(padding_len, 0x00);
984 } 1047 }
985 // Packet FCS + optinal padding 1048 // Packet FCS + optinal padding
@@ -988,17 +1051,13 @@ mod tests {
988 expectations.push(SpiTransaction::write_vec(tail)); 1051 expectations.push(SpiTransaction::write_vec(tail));
989 expectations.push(SpiTransaction::flush()); 1052 expectations.push(SpiTransaction::flush());
990 1053
991 let mut spi = SpiMock::new(&expectations); 1054 // Create TestHarnass
992 1055 let mut th = TestHarnass::new(&expectations, true, true);
993 let cs = CsPinMock::default();
994 let delay = MockDelay {};
995 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
996
997 let mut spe = ADIN1110::new(spi_dev, true);
998 1056
999 assert!(spe.write_fifo(&packet).await.is_ok()); 1057 assert!(th.spe.write_fifo(&packet).await.is_ok());
1000 1058
1001 spi.done(); 1059 // Mark end of the SPI test.
1060 th.done();
1002 } 1061 }
1003 1062
1004 #[futures_test::test] 1063 #[futures_test::test]
@@ -1022,7 +1081,7 @@ mod tests {
1022 1081
1023 let mut tail = std::vec::Vec::<u8>::with_capacity(100); 1082 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1024 // Padding 1083 // Padding
1025 if let Some(padding_len) = (ETH_MIN_LEN - FSC_LEN).checked_sub(packet.len()) { 1084 if let Some(padding_len) = (ETH_MIN_LEN - FCS_LEN).checked_sub(packet.len()) {
1026 tail.resize(padding_len, 0x00); 1085 tail.resize(padding_len, 0x00);
1027 } 1086 }
1028 // Packet FCS + optinal padding 1087 // Packet FCS + optinal padding
@@ -1031,16 +1090,227 @@ mod tests {
1031 expectations.push(SpiTransaction::write_vec(tail)); 1090 expectations.push(SpiTransaction::write_vec(tail));
1032 expectations.push(SpiTransaction::flush()); 1091 expectations.push(SpiTransaction::flush());
1033 1092
1034 let mut spi = SpiMock::new(&expectations); 1093 // Create TestHarnass
1094 let mut th = TestHarnass::new(&expectations, false, true);
1035 1095
1036 let cs = CsPinMock::default(); 1096 assert!(th.spe.write_fifo(&packet).await.is_ok());
1037 let delay = MockDelay {}; 1097
1038 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay); 1098 // Mark end of the SPI test.
1099 th.done();
1100 }
1101
1102 #[futures_test::test]
1103 async fn read_packet_from_fifo_packet_too_big_for_frame_buffer() {
1104 // Configure expectations
1105 let mut expectations = vec![];
1106
1107 // Read RX_SIZE reg
1108 let rx_size: u32 = u32::try_from(ETH_MIN_LEN + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1109 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1110 rx_size_vec.push(crc8(&rx_size_vec));
1111
1112 expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]));
1113 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1114 expectations.push(SpiTransaction::flush());
1115
1116 let mut frame = [0; MTU];
1117
1118 // Create TestHarnass
1119 let mut th = TestHarnass::new(&expectations, true, true);
1120
1121 let ret = th.spe.read_fifo(&mut frame[0..ETH_MIN_LEN - 1]).await;
1122 assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_BIG)));
1123
1124 // Mark end of the SPI test.
1125 th.done();
1126 }
1127
1128 #[futures_test::test]
1129 async fn read_packet_from_fifo_packet_too_small() {
1130 // Configure expectations
1131 let mut expectations = vec![];
1132
1133 // This value is importen for this test!
1134 assert_eq!(ETH_MIN_LEN, 64);
1135
1136 // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN` - 1
1137 let packet = [0; 64 - FCS_LEN - 1];
1138
1139 // Read RX_SIZE reg
1140 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1141 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1142 rx_size_vec.push(crc8(&rx_size_vec));
1143
1144 expectations.push(SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]));
1145 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1146 expectations.push(SpiTransaction::flush());
1147
1148 let mut frame = [0; MTU];
1149
1150 // Create TestHarnass
1151 let mut th = TestHarnass::new(&expectations, true, true);
1152
1153 let ret = th.spe.read_fifo(&mut frame).await;
1154 assert!(matches!(dbg!(ret), Err(AdinError::PACKET_TOO_SMALL)));
1155
1156 // Mark end of the SPI test.
1157 th.done();
1158 }
1159
1160 #[futures_test::test]
1161 async fn read_packet_from_fifo_packet_corrupted_fcs() {
1162 let mut frame = [0; MTU];
1163 // Configure expectations
1164 let mut expectations = vec![];
1165
1166 let packet = [0xDE; 60];
1167 let crc_en = true;
1168
1169 // Read RX_SIZE reg
1170 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1171 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1172 if crc_en {
1173 rx_size_vec.push(crc8(&rx_size_vec));
1174 }
1175
1176 // SPI Header with CRC
1177 let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE];
1178 if !crc_en {
1179 // remove the CRC on idx 2
1180 rx_fsize.swap_remove(2);
1181 }
1182 expectations.push(SpiTransaction::write_vec(rx_fsize));
1183 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1184 expectations.push(SpiTransaction::flush());
1185
1186 // Read RX reg, SPI Header with CRC
1187 let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE];
1188 if !crc_en {
1189 // remove the CRC on idx 2
1190 rx_reg.swap_remove(2);
1191 }
1192 expectations.push(SpiTransaction::write_vec(rx_reg));
1193 // Frame Header
1194 expectations.push(SpiTransaction::read_vec(vec![0, 0]));
1195 // Packet data
1196 expectations.push(SpiTransaction::read_vec(packet.to_vec()));
1197
1198 let packet_crc = ETH_FCS::new(&packet);
1199
1200 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1201
1202 tail.extend_from_slice(&packet_crc.hton_bytes());
1203 // increase last byte with 1.
1204 if let Some(crc) = tail.last_mut() {
1205 *crc = crc.wrapping_add(1);
1206 }
1207
1208 // Need extra bytes?
1209 let pad = (packet.len() + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
1210 if pad != 0 {
1211 // Packet FCS + optinal padding
1212 tail.resize(tail.len() + pad, DONT_CARE_BYTE);
1213 }
1214
1215 expectations.push(SpiTransaction::read_vec(tail));
1216 expectations.push(SpiTransaction::flush());
1217
1218 // Create TestHarnass
1219 let mut th = TestHarnass::new(&expectations, crc_en, false);
1220
1221 let ret = th.spe.read_fifo(&mut frame).await.expect_err("Error!");
1222 assert!(matches!(ret, AdinError::FCS));
1223
1224 // Mark end of the SPI test.
1225 th.done();
1226 }
1227
1228 #[futures_test::test]
1229 async fn read_packet_to_fifo_check_spi_read_multipule_of_u32_valid_lengths() {
1230 let packet_buffer = [0; MTU];
1231 let mut frame = [0; MTU];
1232 let mut expectations = std::vec::Vec::with_capacity(16);
1233
1234 // Packet data, size = `ETH_MIN_LEN` - `FCS_LEN`
1235 for packet_size in [60, 61, 62, 63, 64, MTU - 4, MTU - 3, MTU - 2, MTU - 1, MTU] {
1236 for crc_en in [false, true] {
1237 expectations.clear();
1238
1239 let packet = &packet_buffer[0..packet_size];
1240
1241 // Read RX_SIZE reg
1242 let rx_size: u32 = u32::try_from(packet.len() + FRAME_HEADER_LEN + FCS_LEN).unwrap();
1243 let mut rx_size_vec = rx_size.to_be_bytes().to_vec();
1244 if crc_en {
1245 rx_size_vec.push(crc8(&rx_size_vec));
1246 }
1247
1248 // SPI Header with CRC
1249 let mut rx_fsize = vec![128, 144, 79, TURN_AROUND_BYTE];
1250 if !crc_en {
1251 // remove the CRC on idx 2
1252 rx_fsize.swap_remove(2);
1253 }
1254 expectations.push(SpiTransaction::write_vec(rx_fsize));
1255 expectations.push(SpiTransaction::read_vec(rx_size_vec));
1256 expectations.push(SpiTransaction::flush());
1257
1258 // Read RX reg, SPI Header with CRC
1259 let mut rx_reg = vec![128, 145, 72, TURN_AROUND_BYTE];
1260 if !crc_en {
1261 // remove the CRC on idx 2
1262 rx_reg.swap_remove(2);
1263 }
1264 expectations.push(SpiTransaction::write_vec(rx_reg));
1265 // Frame Header
1266 expectations.push(SpiTransaction::read_vec(vec![0, 0]));
1267 // Packet data
1268 expectations.push(SpiTransaction::read_vec(packet.to_vec()));
1269
1270 let packet_crc = ETH_FCS::new(packet);
1271
1272 let mut tail = std::vec::Vec::<u8>::with_capacity(100);
1273
1274 tail.extend_from_slice(&packet_crc.hton_bytes());
1275
1276 // Need extra bytes?
1277 let pad = (packet_size + FCS_LEN + FRAME_HEADER_LEN) & 0x03;
1278 if pad != 0 {
1279 // Packet FCS + optinal padding
1280 tail.resize(tail.len() + pad, DONT_CARE_BYTE);
1281 }
1282
1283 expectations.push(SpiTransaction::read_vec(tail));
1284 expectations.push(SpiTransaction::flush());
1285
1286 // Create TestHarnass
1287 let mut th = TestHarnass::new(&expectations, crc_en, false);
1288
1289 let ret = th.spe.read_fifo(&mut frame).await.expect("Error!");
1290 assert_eq!(ret, packet_size);
1291
1292 // Mark end of the SPI test.
1293 th.done();
1294 }
1295 }
1296 }
1297
1298 #[futures_test::test]
1299 async fn spi_crc_error() {
1300 // Configure expectations
1301 let expectations = vec![
1302 SpiTransaction::write_vec(vec![128, 144, 79, TURN_AROUND_BYTE]),
1303 SpiTransaction::read_vec(vec![0x00, 0x00, 0x00, 0x00, 0xDD]),
1304 SpiTransaction::flush(),
1305 ];
1039 1306
1040 let mut spe = ADIN1110::new(spi_dev, false); 1307 // Create TestHarnass
1308 let mut th = TestHarnass::new(&expectations, true, false);
1041 1309
1042 assert!(spe.write_fifo(&packet).await.is_ok()); 1310 let ret = th.spe.read_reg(sr::RX_FSIZE).await;
1311 assert!(matches!(dbg!(ret), Err(AdinError::SPI_CRC)));
1043 1312
1044 spi.done(); 1313 // Mark end of the SPI test.
1314 th.done();
1045 } 1315 }
1046} 1316}
diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs
index 4557929f0..beaf9466e 100644
--- a/embassy-net-adin1110/src/regs.rs
+++ b/embassy-net-adin1110/src/regs.rs
@@ -1,3 +1,5 @@
1use core::fmt::{Debug, Display};
2
1use bitfield::{bitfield, bitfield_bitrange, bitfield_fields}; 3use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
2 4
3#[allow(non_camel_case_types)] 5#[allow(non_camel_case_types)]
@@ -34,6 +36,12 @@ pub enum SpiRegisters {
34 RX = 0x91, 36 RX = 0x91,
35} 37}
36 38
39impl Display for SpiRegisters {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 write!(f, "{self:?}")
42 }
43}
44
37impl From<SpiRegisters> for u16 { 45impl From<SpiRegisters> for u16 {
38 fn from(val: SpiRegisters) -> Self { 46 fn from(val: SpiRegisters) -> Self {
39 val as u16 47 val as u16
@@ -68,7 +76,7 @@ impl From<u16> for SpiRegisters {
68 0x73 => Self::ADDR_MSK_UPR1, 76 0x73 => Self::ADDR_MSK_UPR1,
69 0x90 => Self::RX_FSIZE, 77 0x90 => Self::RX_FSIZE,
70 0x91 => Self::RX, 78 0x91 => Self::RX,
71 e => panic!("Unknown value {e}"), 79 e => panic!("Unknown value {}", e),
72 } 80 }
73 } 81 }
74} 82}
@@ -174,7 +182,7 @@ bitfield! {
174 pub sdf_detect_src, set_sdf_detect_src : 7; 182 pub sdf_detect_src, set_sdf_detect_src : 7;
175 /// Statistics Clear on Reading 183 /// Statistics Clear on Reading
176 pub stats_clr_on_rd, set_stats_clr_on_rd : 6; 184 pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
177 /// Enable CRC Append 185 /// Enable SPI CRC
178 pub crc_append, set_crc_append : 5; 186 pub crc_append, set_crc_append : 5;
179 /// Admit Frames with IFG Errors on Port 1 (P1) 187 /// Admit Frames with IFG Errors on Port 1 (P1)
180 pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4; 188 pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
@@ -313,7 +321,7 @@ impl From<u8> for LedFunc {
313 26 => LedFunc::Clk25Ref, 321 26 => LedFunc::Clk25Ref,
314 27 => LedFunc::TxTCLK, 322 27 => LedFunc::TxTCLK,
315 28 => LedFunc::Clk120MHz, 323 28 => LedFunc::Clk120MHz,
316 e => panic!("Invalid value {e}"), 324 e => panic!("Invalid value {}", e),
317 } 325 }
318 } 326 }
319} 327}
@@ -369,7 +377,7 @@ impl From<u8> for LedPol {
369 0 => LedPol::AutoSense, 377 0 => LedPol::AutoSense,
370 1 => LedPol::ActiveHigh, 378 1 => LedPol::ActiveHigh,
371 2 => LedPol::ActiveLow, 379 2 => LedPol::ActiveLow,
372 e => panic!("Invalid value {e}"), 380 e => panic!("Invalid value {}", e),
373 } 381 }
374 } 382 }
375} 383}
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 5fe1499e6..92337e712 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l4-examples" 3name = "embassy-stm32l4-examples"
4version = "0.1.0" 4version = "0.1.1"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
@@ -12,7 +12,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature
12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } 12embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net-adin1110 = { version = "0.1.0", path = "../../embassy-net-adin1110", default-features = false } 15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] } 16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } 18embedded-io-async = { version = "0.5.0", features = ["defmt-03"] }
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 0a677be76..287521582 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -11,7 +11,9 @@
11// Settings switch S201 "HW CFG": 11// Settings switch S201 "HW CFG":
12// - Without SPI CRC: OFF-ON-OFF-OFF-OFF 12// - Without SPI CRC: OFF-ON-OFF-OFF-OFF
13// - With SPI CRC: ON -ON-OFF-OFF-OFF 13// - With SPI CRC: ON -ON-OFF-OFF-OFF
14// Settings switch S303 "uC CFG": CFG0: On = static ip, Off = Dhcp 14// Settings switch S303 "uC CFG":
15// - CFG0: On = static ip, Off = Dhcp
16// - CFG1: Ethernet `FCS` on TX path: On, Off
15// The webserver shows the actual temperature of the onboard i2c temp sensor. 17// The webserver shows the actual temperature of the onboard i2c temp sensor.
16 18
17use core::marker::PhantomData; 19use core::marker::PhantomData;
@@ -107,7 +109,7 @@ async fn main(spawner: Spawner) {
107 109
108 // Read the uc_cfg switches 110 // Read the uc_cfg switches
109 let uc_cfg0 = Input::new(dp.PB2, Pull::None); 111 let uc_cfg0 = Input::new(dp.PB2, Pull::None);
110 let _uc_cfg1 = Input::new(dp.PF11, Pull::None); 112 let uc_cfg1 = Input::new(dp.PF11, Pull::None);
111 let _uc_cfg2 = Input::new(dp.PG6, Pull::None); 113 let _uc_cfg2 = Input::new(dp.PG6, Pull::None);
112 let _uc_cfg3 = Input::new(dp.PG11, Pull::None); 114 let _uc_cfg3 = Input::new(dp.PG11, Pull::None);
113 115
@@ -154,11 +156,13 @@ async fn main(spawner: Spawner) {
154 156
155 let cfg0_without_crc = spe_cfg0.is_high(); 157 let cfg0_without_crc = spe_cfg0.is_high();
156 let cfg1_spi_mode = spe_cfg1.is_high(); 158 let cfg1_spi_mode = spe_cfg1.is_high();
159 let uc_cfg1_fcs_en = uc_cfg1.is_low();
157 160
158 defmt::println!( 161 defmt::println!(
159 "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{}", 162 "ADIN1110: CFG SPI-MODE 1-{}, CRC-bit 0-{} FCS-{}",
160 cfg1_spi_mode, 163 cfg1_spi_mode,
161 cfg0_without_crc 164 cfg0_without_crc,
165 uc_cfg1_fcs_en
162 ); 166 );
163 167
164 // Check the SPI mode selected with the "HW CFG" dip-switch 168 // Check the SPI mode selected with the "HW CFG" dip-switch
@@ -172,8 +176,16 @@ async fn main(spawner: Spawner) {
172 176
173 let state = make_static!(embassy_net_adin1110::State::<8, 8>::new()); 177 let state = make_static!(embassy_net_adin1110::State::<8, 8>::new());
174 178
175 let (device, runner) = 179 let (device, runner) = embassy_net_adin1110::new(
176 embassy_net_adin1110::new(MAC, state, spe_spi, spe_int, spe_reset_n, !cfg0_without_crc).await; 180 MAC,
181 state,
182 spe_spi,
183 spe_int,
184 spe_reset_n,
185 !cfg0_without_crc,
186 uc_cfg1_fcs_en,
187 )
188 .await;
177 189
178 // Start task blink_led 190 // Start task blink_led
179 unwrap!(spawner.spawn(heartbeat_led(led_uc3_yellow))); 191 unwrap!(spawner.spawn(heartbeat_led(led_uc3_yellow)));