aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-net-adin1110/.gitignore1
-rw-r--r--embassy-net-adin1110/.vscode/settings.json8
-rw-r--r--embassy-net-adin1110/Cargo.toml41
-rw-r--r--embassy-net-adin1110/README.md55
-rw-r--r--embassy-net-adin1110/rust-toolchain.toml3
-rw-r--r--embassy-net-adin1110/src/crc32.rs101
-rw-r--r--embassy-net-adin1110/src/crc8.rs53
-rw-r--r--embassy-net-adin1110/src/lib.rs1246
-rw-r--r--embassy-net-adin1110/src/mdio.rs174
-rw-r--r--embassy-net-adin1110/src/phy.rs137
-rw-r--r--embassy-net-adin1110/src/regs.rs407
11 files changed, 2226 insertions, 0 deletions
diff --git a/embassy-net-adin1110/.gitignore b/embassy-net-adin1110/.gitignore
new file mode 100644
index 000000000..c41cc9e35
--- /dev/null
+++ b/embassy-net-adin1110/.gitignore
@@ -0,0 +1 @@
/target \ No newline at end of file
diff --git a/embassy-net-adin1110/.vscode/settings.json b/embassy-net-adin1110/.vscode/settings.json
new file mode 100644
index 000000000..daa2ccf0a
--- /dev/null
+++ b/embassy-net-adin1110/.vscode/settings.json
@@ -0,0 +1,8 @@
1{
2 "rust-analyzer.check.command": "clippy",
3 "rust-analyzer.showUnlinkedFileNotification": false,
4 "[rust]": {
5 "editor.defaultFormatter": "rust-lang.rust-analyzer",
6 "editor.formatOnSave": true
7 }
8} \ No newline at end of file
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
new file mode 100644
index 000000000..e74fb7cd4
--- /dev/null
+++ b/embassy-net-adin1110/Cargo.toml
@@ -0,0 +1,41 @@
1[package]
2name = "embassy-net-adin1110"
3version = "0.1.0"
4description = "embassy-net driver for the ADIN1110 ethernet chip"
5keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0"
8edition = "2021"
9
10# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
11
12[dependencies]
13heapless = "0.7.16"
14defmt = { version = "0.3", optional = true }
15log = { version = "0.4.4", default-features = false, optional = true }
16embedded-hal-1 = { package = "embedded-hal", 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"] }
19embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
20embassy-time = { version = "0.1.0" }
21embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
22bitfield = "0.14.0"
23
24
25[dev-dependencies]
26# 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"] }] }
28embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
29crc = "3.0.1"
30env_logger = "0.10"
31critical-section = { version = "1.1.1", features = ["std"] }
32futures-test = "0.3.17"
33
34[features]
35default = [ ]
36defmt = [ "dep:defmt" ]
37
38[package.metadata.embassy_docs]
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/"
41target = "thumbv7em-none-eabi"
diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md
new file mode 100644
index 000000000..9b7b4e0e3
--- /dev/null
+++ b/embassy-net-adin1110/README.md
@@ -0,0 +1,55 @@
1# SPE ADIN1110 `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for the `Analog ADIN1110` SPI SPE ethernet chips.
4
5## What is SPE or Single Pair Ethernet / 10 BASE-T1L
6
7SPE is Single Pair Ethernet, what the names implies, it uses a single twisted/differancial pair (only 2 wires) to transmit ethernet packet in full-duplex.
8SPE is still ethernet, only the phissical layer is different.
9
10SPE also supports [`PoDL(Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similair to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but additional hardware and handshake protocol is needed.
11
12SPE has many link speeds but only `10 BASE-T1L` is able to reach cable length up to 1000 meters in `2.4 Vpp` transmit amplitude.
13Currently in 2023, none of the standards are compatiable with eachother.
14So `10 BASE-T1L` don't work with a `10 BASE-T1S` or `100 BASE-T1`.
15
16In the industry SPE is also called [`APL(Advanced Physical Layer)`](https://www.ethernet-apl.org), it is based on the `10 BASE-T1L` standard.
17
18APL can be use in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has it's own name and standard [`2-WISE(2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292).
19
20`10 BASE-T1L` and `ADIN1110` are designed to support intrinsic safety applications. The power supply energy is fixed and PDoL is not supported.
21
22## Supported SPI modes
23
24`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
25
26Both modes support with and without additional CRC.
27Currently only `Generic` SPI with or without CRC is supported.
28
29*NOTE:* SPI Mode is selected by the hardware pins `SPI_CFG0` and `SPI_CFG1`. Software can't detect nor change the mode.
30
31## Hardware
32
33- Testen on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with a `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) 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), the kit supports multiple microcontrollers, please check if get the right microcontroller that is supported by Embassy!
35
36## Other SPE chips
37
38* [`Analog ADIN2111`](https://www.analog.com/en/products/adin2111.html) 2 Port SPI version. Can work with this driver.
39* [`Analog ADIN1100`](https://www.analog.com/en/products/adin1100.html) RGMII version.
40
41## Testing
42
43ADIN1110 library can tested on the host with a mock SPI driver
44
45$ `cargo test --target x86_64-unknown-linux-gnu`
46
47## License
48
49This work is licensed under either of
50
51- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
52 http://www.apache.org/licenses/LICENSE-2.0)
53- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
54
55at your option.
diff --git a/embassy-net-adin1110/rust-toolchain.toml b/embassy-net-adin1110/rust-toolchain.toml
new file mode 100644
index 000000000..d5f51a7f5
--- /dev/null
+++ b/embassy-net-adin1110/rust-toolchain.toml
@@ -0,0 +1,3 @@
1[toolchain]
2channel = "nightly"
3components = [ "rustfmt", "rustc-dev" ]
diff --git a/embassy-net-adin1110/src/crc32.rs b/embassy-net-adin1110/src/crc32.rs
new file mode 100644
index 000000000..75a7d65b7
--- /dev/null
+++ b/embassy-net-adin1110/src/crc32.rs
@@ -0,0 +1,101 @@
1pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
2 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
3 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
4 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
5 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
6 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
7 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
8 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
9 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
10 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
11 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
12 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
13 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
14 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
15 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
16 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
17 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
18 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
19 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
20 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
21 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
22 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
23 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
24 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
25 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
26 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
27 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
28 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
29 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
30 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
31];
32
33#[allow(non_camel_case_types)]
34#[derive(Debug)]
35pub struct ETH_FSC(pub u32);
36
37impl ETH_FSC {
38 pub const CRC32_OK: u32 = 0x2144df1c;
39
40 pub fn new(data: &[u8]) -> Self {
41 let fsc = data.iter().fold(u32::MAX, |crc, byte| {
42 let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
43 CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
44 }) ^ u32::MAX;
45 Self(fsc)
46 }
47
48 pub fn crc_ok(&self) -> bool {
49 self.0 == Self::CRC32_OK
50 }
51
52 pub fn hton_bytes(&self) -> [u8; 4] {
53 self.0.to_le_bytes()
54 }
55
56 pub fn hton(&self) -> u32 {
57 self.0.to_le()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn crc32_ethernet_frame() {
67 let packet_a = &[
68 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xff, 0x06, 0x00, 0x01, 0x08, 0x00,
69 0x06, 0x04, 0x00, 0x01, 0x00, 0xe0, 0x4c, 0x68, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0xc0, 0xa8, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x65, 0x90, 0x3d,
72 ];
73
74 let packet_b = &[
75 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00,
76 0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78,
77 0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c,
79 ];
80
81 // Packet A
82 let own_crc = ETH_FSC::new(&packet_a[0..60]);
83 let crc_bytes = own_crc.hton_bytes();
84 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
85 assert_eq!(&crc_bytes, &packet_a[60..64]);
86
87 let own_crc = ETH_FSC::new(packet_a);
88 println!("{:08x}", own_crc.0);
89 assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
90
91 // Packet B
92 let own_crc = ETH_FSC::new(&packet_b[0..60]);
93 let crc_bytes = own_crc.hton_bytes();
94 println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
95 assert_eq!(&crc_bytes, &packet_b[60..64]);
96
97 let own_crc = ETH_FSC::new(packet_b);
98 println!("{:08x}", own_crc.0);
99 assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
100 }
101}
diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs
new file mode 100644
index 000000000..7d20a7401
--- /dev/null
+++ b/embassy-net-adin1110/src/crc8.rs
@@ -0,0 +1,53 @@
1/// CRC-8/ITU
2const CRC8X_TABLE: [u8; 256] = [
3 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e,
4 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb,
5 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8,
6 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6,
7 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d,
8 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50,
9 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95,
10 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
11 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f,
12 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a,
13 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e,
14 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
15 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc,
16 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
17];
18
19/// Calculate the crc of a pease of data.
20pub fn crc8(data: &[u8]) -> u8 {
21 data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
22}
23
24#[cfg(test)]
25mod tests {
26 use ::crc::{Crc, CRC_8_SMBUS};
27
28 use super::crc8;
29
30 #[test]
31 fn spi_header_crc8() {
32 let data = &[0x80, 0x00];
33
34 let c = Crc::<u8>::new(&CRC_8_SMBUS);
35 let mut dig = c.digest();
36 dig.update(data);
37 let sw_crc = dig.finalize();
38
39 let own_crc = crc8(data);
40
41 assert_eq!(own_crc, sw_crc);
42 assert_eq!(own_crc, 182);
43
44 let data = &[0x80, 0x01];
45 let mut dig = c.digest();
46 dig.update(data);
47 let sw_crc = dig.finalize();
48 let own_crc = crc8(data);
49
50 assert_eq!(own_crc, sw_crc);
51 assert_eq!(own_crc, 177);
52 }
53}
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs
new file mode 100644
index 000000000..a4010d251
--- /dev/null
+++ b/embassy-net-adin1110/src/lib.rs
@@ -0,0 +1,1246 @@
1#![allow(clippy::pedantic)]
2#![feature(type_alias_impl_trait)]
3#![feature(async_fn_in_trait)]
4#![cfg_attr(not(any(test, feature = "std")), no_std)]
5
6use ch::driver::LinkState;
7use embassy_futures::select::{select, Either};
8use embassy_net_driver_channel as ch;
9use embassy_time::{Duration, Timer};
10use embedded_hal_1::digital::OutputPin;
11use embedded_hal_async::digital::Wait;
12use embedded_hal_async::spi::{Operation, SpiDevice};
13use heapless::Vec;
14
15mod crc32;
16mod crc8;
17mod mdio;
18mod phy;
19mod regs;
20
21pub use crc32::ETH_FSC;
22use crc8::crc8;
23pub use mdio::MdioBus;
24pub use phy::{Phy10BaseT1x, RegsC22, RegsC45};
25pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
26
27use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
28
29pub const PHYID: u32 = 0x0283BC91;
30
31/// Error values ADIN1110
32#[derive(Debug)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34#[allow(non_camel_case_types)]
35pub enum AdinError<E> {
36 Spi(E),
37 SENDERROR,
38 READERROR,
39 CRC,
40 PACKET_TOO_BIG,
41 PACKET_TOO_SMALL,
42 MDIO_ACC_TIMEOUT,
43}
44
45pub type AEResult<T, SPIE> = core::result::Result<T, AdinError<SPIE>>;
46pub const MDIO_PHY_ADDR: u8 = 0x01;
47pub const MTU: usize = 1500;
48/// Max SPI/Frame buffer size
49pub const MAX_BUFF: usize = 2048;
50
51const DONT_CARE_BYTE: u8 = 0x00;
52const TURN_AROUND_BYTE: u8 = 0x00;
53
54const FEC_LEN: usize = 4;
55const FRAME_HEADER_LEN: usize = 2;
56const WR_HEADER_LEN: usize = 2;
57
58// P1 = 0x00, P2 = 0x01
59const PORT_ID_BYTE: u8 = 0x00;
60
61pub type Packet = Vec<u8, { MTU + FEC_LEN + WR_HEADER_LEN }>;
62
63/// Type alias for the embassy-net driver for ADIN1110
64pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
65
66/// Internal state for the embassy-net integration.
67pub struct State<const N_RX: usize, const N_TX: usize> {
68 ch_state: ch::State<MTU, N_RX, N_TX>,
69}
70impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
71 /// Create a new `State`.
72 pub const fn new() -> Self {
73 Self {
74 ch_state: ch::State::new(),
75 }
76 }
77}
78
79#[derive(Debug)]
80pub struct ADIN1110<SPI> {
81 /// SPI bus
82 spi: SPI,
83 /// Enable CRC on SPI transfer.
84 /// This must match with the hardware pin SPI_CFG0 were 0 = CRC enable, 1 CRC disabled.
85 crc: bool,
86}
87
88// Round size up the N u32;
89pub(crate) fn size_align_u32(size: u32) -> u32 {
90 (size + 3) & 0xFFFF_FFFC
91}
92
93impl<SpiE, SPI> ADIN1110<SPI>
94where
95 SPI: SpiDevice<u8, Error = SpiE>,
96 SpiE: core::fmt::Debug,
97{
98 pub fn new(spi: SPI, crc: bool) -> Self {
99 Self { spi, crc }
100 }
101
102 pub async fn read_reg(&mut self, reg: sr) -> AEResult<u32, SpiE> {
103 let mut tx_buf = Vec::<u8, 16>::new();
104
105 let mut spi_hdr = SpiHeader(0);
106 spi_hdr.set_control(true);
107 spi_hdr.set_addr(reg);
108 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
109
110 if self.crc {
111 // Add CRC for header data
112 let _ = tx_buf.push(crc8(&tx_buf));
113 }
114
115 // Turn around byte, TODO: Unknown that this is.
116 let _ = tx_buf.push(TURN_AROUND_BYTE);
117
118 let mut rx_buf = [0; 5];
119
120 let spi_read_len = if self.crc { rx_buf.len() } else { rx_buf.len() - 1 };
121
122 let mut spi_op = [Operation::Write(&tx_buf), Operation::Read(&mut rx_buf[0..spi_read_len])];
123
124 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
125
126 if self.crc {
127 let crc = crc8(&rx_buf[0..4]);
128 if crc != rx_buf[4] {
129 return Err(AdinError::CRC);
130 }
131 }
132
133 let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap());
134
135 #[cfg(feature = "defmt")]
136 defmt::trace!("REG Read {} = {:08x} SPI {:02x}", reg, value, &tx_buf);
137
138 Ok(value)
139 }
140
141 pub async fn write_reg(&mut self, reg: sr, value: u32) -> AEResult<(), SpiE> {
142 let mut tx_buf = Vec::<u8, 16>::new();
143
144 let mut spi_hdr = SpiHeader(0);
145 spi_hdr.set_control(true);
146 spi_hdr.set_write(true);
147 spi_hdr.set_addr(reg);
148 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
149
150 if self.crc {
151 // Add CRC for header data
152 let _ = tx_buf.push(crc8(&tx_buf));
153 }
154
155 let val = value.to_be_bytes();
156 let _ = tx_buf.extend_from_slice(val.as_slice());
157
158 if self.crc {
159 // Add CRC for header data
160 let _ = tx_buf.push(crc8(val.as_slice()));
161 }
162
163 #[cfg(feature = "defmt")]
164 defmt::trace!("REG Write {} = {:08x} SPI {:02x}", reg, value, &tx_buf);
165
166 self.spi.write(&tx_buf).await.map_err(AdinError::Spi)
167 }
168
169 // helper function for write to MDIO_ACC register and wait for ready!
170 async fn write_mdio_acc_reg(&mut self, mdio_acc_val: u32) -> AEResult<u32, SpiE> {
171 self.write_reg(sr::MDIO_ACC, mdio_acc_val).await?;
172
173 // TODO: Add proper timeout!
174 for _ in 0..100_000 {
175 let val = self.read_reg(sr::MDIO_ACC).await?;
176 if val & 0x8000_0000 != 0 {
177 return Ok(val);
178 }
179 }
180
181 Err(AdinError::MDIO_ACC_TIMEOUT)
182 }
183
184 pub async fn read_fifo(&mut self, packet: &mut [u8]) -> AEResult<usize, SpiE> {
185 let mut tx_buf = Vec::<u8, 16>::new();
186
187 // Size of the frame, also includes the appednded header.
188 let packet_size = self.read_reg(sr::RX_FSIZE).await?;
189
190 // Packet read of write to the MAC packet buffer must be a multipul of 4!
191 let read_size = size_align_u32(packet_size);
192
193 if packet_size < u32::try_from(FRAME_HEADER_LEN + FEC_LEN).unwrap()
194 || read_size > u32::try_from(packet.len()).unwrap()
195 {
196 return Err(AdinError::PACKET_TOO_BIG);
197 }
198
199 let mut spi_hdr = SpiHeader(0);
200 spi_hdr.set_control(true);
201 spi_hdr.set_addr(sr::RX);
202 let _ = tx_buf.extend_from_slice(spi_hdr.0.to_be_bytes().as_slice());
203
204 if self.crc {
205 // Add CRC for header data
206 let _ = tx_buf.push(crc8(&tx_buf));
207 }
208
209 // Turn around byte, TODO: Unknown that this is.
210 let _ = tx_buf.push(TURN_AROUND_BYTE);
211
212 let spi_packet = &mut packet[0..read_size as usize];
213
214 assert_eq!(spi_packet.len() & 0x03, 0x00);
215
216 let mut pkt_header = [0, 0];
217
218 let mut spi_op = [
219 Operation::Write(&tx_buf),
220 Operation::Read(&mut pkt_header),
221 Operation::Read(spi_packet),
222 ];
223
224 self.spi.transaction(&mut spi_op).await.map_err(AdinError::Spi)?;
225
226 Ok(packet_size as usize)
227 }
228
229 pub async fn write_fifo(&mut self, frame: &[u8]) -> AEResult<(), SpiE> {
230 let header_len = self.header_write_len();
231 // if packet.len() < header_len {
232 // return Err(AdinError::PACKET_TOO_SMALL);
233 // }
234
235 let mut packet = Packet::new();
236
237 let mut spi_hdr = SpiHeader(0);
238 spi_hdr.set_control(true);
239 spi_hdr.set_write(true);
240 spi_hdr.set_addr(sr::TX);
241
242 packet
243 .extend_from_slice(spi_hdr.0.to_be_bytes().as_slice())
244 .map_err(|_| AdinError::PACKET_TOO_BIG)?;
245
246 if self.crc {
247 assert_eq!(header_len, 5);
248 // Add CRC for header data
249 packet
250 .push(crc8(&packet[0..2]))
251 .map_err(|_| AdinError::PACKET_TOO_BIG)?;
252 }
253
254 // Add port number
255 // packet[header_len - FRAME_HEADER_LEN..header_len]
256 // .copy_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice());
257 packet
258 .extend_from_slice(u16::from(PORT_ID_BYTE).to_be_bytes().as_slice())
259 .map_err(|_| AdinError::PACKET_TOO_BIG)?;
260
261 packet.extend_from_slice(frame).map_err(|_| AdinError::PACKET_TOO_BIG)?;
262
263 // Pad data up to 64
264 for _ in packet.len()..(64 - FEC_LEN + header_len) {
265 let _ = packet.push(0x00);
266 }
267
268 // // add ethernet crc32
269 let crc = ETH_FSC::new(&packet[header_len..]);
270 let _ = packet.extend_from_slice(crc.hton_bytes().as_slice());
271
272 let crc = ETH_FSC::new(&packet[header_len..]);
273 assert!(crc.crc_ok());
274
275 let send_len = packet.len() - header_len + FRAME_HEADER_LEN;
276
277 // Packet read of write to the MAC packet buffer must be a multipul of 4!
278 while packet.len() & 0x3 != 0 {
279 let _ = packet.push(DONT_CARE_BYTE);
280 }
281
282 #[cfg(feature = "defmt")]
283 defmt::trace!(
284 "TX: hdr {} [{}] {:02x} SIZE: {}",
285 header_len,
286 packet.len(),
287 &packet,
288 send_len,
289 );
290
291 self.write_reg(sr::TX_FSIZE, send_len as u32).await?;
292
293 // Spi packet must be half word / even length
294 if send_len & 1 != 0 {
295 let _ = packet.push(0x00);
296 }
297
298 self.spi.write(&packet).await.map_err(AdinError::Spi)
299 }
300
301 pub fn header_write_len(&self) -> usize {
302 // u16 + [CRC] + PORT
303 WR_HEADER_LEN + FRAME_HEADER_LEN + usize::from(self.crc)
304 }
305
306 pub fn header_len_read(&self) -> usize {
307 // u16 + [CRC] + u8
308 WR_HEADER_LEN + 1 + usize::from(self.crc)
309 }
310
311 /// Programs the mac address in the mac filters.
312 /// Also set the boardcast address.
313 /// The chip supports 2 priority queues but current code doesn't support this mode.
314 pub async fn set_mac_addr(&mut self, mac: &[u8; 6]) -> AEResult<(), SpiE> {
315 let mac_high_part = u16::from_be_bytes(mac[0..2].try_into().unwrap());
316 let mac_low_part = u32::from_be_bytes(mac[2..6].try_into().unwrap());
317
318 // program our mac address in the mac address filter
319 self.write_reg(sr::ADDR_FILT_UPR0, (1 << 16) | (1 << 30) | u32::from(mac_high_part))
320 .await?;
321 self.write_reg(sr::ADDR_FILT_LWR0, mac_low_part).await?;
322
323 self.write_reg(sr::ADDR_MSK_UPR0, u32::from(mac_high_part)).await?;
324 self.write_reg(sr::ADDR_MSK_LWR0, mac_low_part).await?;
325
326 // Also program broadcast address in the mac address filter
327 self.write_reg(sr::ADDR_FILT_UPR1, (1 << 16) | (1 << 30) | 0xFFFF)
328 .await?;
329 self.write_reg(sr::ADDR_FILT_LWR1, 0xFFFF_FFFF).await?;
330 self.write_reg(sr::ADDR_MSK_UPR1, 0xFFFF).await?;
331 self.write_reg(sr::ADDR_MSK_LWR1, 0xFFFF_FFFF).await?;
332
333 Ok(())
334 }
335}
336
337impl<SpiE, SPI> mdio::MdioBus for ADIN1110<SPI>
338where
339 SPI: SpiDevice<u8, Error = SpiE>,
340 SpiE: core::fmt::Debug,
341{
342 type Error = AdinError<SpiE>;
343
344 /// Read from the PHY Registers as Clause 22.
345 async fn read_cl22(&mut self, phy_id: u8, reg: u8) -> Result<u16, Self::Error> {
346 let mdio_acc_val: u32 =
347 (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x3 << 26);
348
349 self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16)
350 }
351
352 /// Read from the PHY Registers as Clause 45.
353 async fn read_cl45(&mut self, phy_id: u8, regc45: (u8, u16)) -> Result<u16, Self::Error> {
354 let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | u32::from(regc45.1);
355
356 self.write_mdio_acc_reg(mdio_acc_val).await?;
357
358 let mdio_acc_val: u32 = u32::from(phy_id & 0x1F) << 21 | u32::from(regc45.0 & 0x1F) << 16 | (0x03 << 26);
359
360 self.write_mdio_acc_reg(mdio_acc_val).await.map(|val| val as u16)
361 }
362
363 /// Write to the PHY Registers as Clause 22.
364 async fn write_cl22(&mut self, phy_id: u8, reg: u8, val: u16) -> Result<(), Self::Error> {
365 let mdio_acc_val: u32 =
366 (0x1 << 28) | u32::from(phy_id & 0x1F) << 21 | u32::from(reg & 0x1F) << 16 | (0x1 << 26) | u32::from(val);
367
368 self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ())
369 }
370
371 /// Write to the PHY Registers as Clause 45.
372 async fn write_cl45(&mut self, phy_id: u8, regc45: (u8, u16), value: u16) -> AEResult<(), SpiE> {
373 let phy_id = u32::from(phy_id & 0x1F) << 21;
374 let dev_addr = u32::from(regc45.0 & 0x1F) << 16;
375 let reg = u32::from(regc45.1);
376
377 let mdio_acc_val: u32 = phy_id | dev_addr | reg;
378 self.write_mdio_acc_reg(mdio_acc_val).await?;
379
380 let mdio_acc_val: u32 = phy_id | dev_addr | (0x01 << 26) | u32::from(value);
381 self.write_mdio_acc_reg(mdio_acc_val).await.map(|_| ())
382 }
383}
384
385/// Background runner for the ADIN110.
386///
387/// You must call `.run()` in a background task for the ADIN1100 to operate.
388pub struct Runner<'d, SPI, INT, RST> {
389 mac: ADIN1110<SPI>,
390 ch: ch::Runner<'d, MTU>,
391 int: INT,
392 is_link_up: bool,
393 _reset: RST,
394}
395
396impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
397 pub async fn run(mut self) -> ! {
398 loop {
399 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
400
401 loop {
402 #[cfg(feature = "defmt")]
403 defmt::debug!("Waiting for interrupts");
404 match select(self.int.wait_for_low(), tx_chan.tx_buf()).await {
405 Either::First(_) => {
406 let mut status1_clr = Status1(0);
407 let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap());
408
409 while status1.p1_rx_rdy() {
410 #[cfg(feature = "defmt")]
411 defmt::debug!("alloc RX packet buffer");
412 match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await {
413 // Handle frames that needs to transmit from the wire.
414 // Note: rx_chan.rx_buf() channel don´t accept new request
415 // when the tx_chan is full. So these will be handled
416 // automaticly.
417 Either::First(frame) => match self.mac.read_fifo(frame).await {
418 Ok(n) => {
419 rx_chan.rx_done(n);
420 }
421 Err(e) => match e {
422 AdinError::PACKET_TOO_BIG => {
423 #[cfg(feature = "defmt")]
424 defmt::error!("RX Packet to big, DROP");
425 self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap();
426 }
427 AdinError::Spi(_) => {
428 #[cfg(feature = "defmt")]
429 defmt::error!("RX Spi error")
430 }
431 _ => {
432 #[cfg(feature = "defmt")]
433 defmt::error!("RX Error")
434 }
435 },
436 },
437 Either::Second(frame) => {
438 // Handle frames that needs to transmit to the wire.
439 self.mac.write_fifo(frame).await.unwrap();
440 tx_chan.tx_done();
441 }
442 }
443 status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap());
444 }
445
446 let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap());
447 if status1.0 & !0x1b != 0 {
448 #[cfg(feature = "defmt")]
449 defmt::error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0);
450 }
451
452 if status1.tx_rdy() {
453 status1_clr.set_tx_rdy(true);
454 #[cfg(feature = "defmt")]
455 defmt::info!("TX_DONE");
456 }
457
458 if status1.link_change() {
459 let link = status1.p1_link_status();
460 self.is_link_up = link;
461
462 #[cfg(feature = "defmt")]
463 if link {
464 let link_status = self
465 .mac
466 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA7::AN_STATUS_EXTRA.into())
467 .await
468 .unwrap();
469
470 let volt = if link_status & (0b11 << 5) == (0b11 << 5) {
471 "2.4"
472 } else {
473 "1.0"
474 };
475
476 let mse = self
477 .mac
478 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1::MSE_VAL.into())
479 .await
480 .unwrap();
481
482 defmt::info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse);
483 } else {
484 defmt::info!("LINK Changed: Link Down");
485 }
486
487 state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down });
488 status1_clr.set_link_change(true);
489 }
490
491 if status1.tx_ecc_err() {
492 #[cfg(feature = "defmt")]
493 defmt::error!("SPI TX_ECC_ERR error, CLEAR TX FIFO");
494 self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap();
495 status1_clr.set_tx_ecc_err(true);
496 }
497
498 if status1.rx_ecc_err() {
499 #[cfg(feature = "defmt")]
500 defmt::error!("SPI RX_ECC_ERR error");
501 status1_clr.set_rx_ecc_err(true);
502 }
503
504 if status1.spi_err() {
505 #[cfg(feature = "defmt")]
506 defmt::error!("SPI SPI_ERR CRC error");
507 status1_clr.set_spi_err(true);
508 }
509
510 if status0.phyint() {
511 let crsm_irq_st = self
512 .mac
513 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into())
514 .await
515 .unwrap();
516
517 let phy_irq_st = self
518 .mac
519 .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into())
520 .await
521 .unwrap();
522 #[cfg(feature = "defmt")]
523 defmt::warn!(
524 "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}",
525 crsm_irq_st,
526 phy_irq_st
527 );
528 }
529
530 if status0.txfcse() {
531 #[cfg(feature = "defmt")]
532 defmt::error!("SPE CHIP PHY TX Frame CRC error");
533 }
534
535 // Clear status0
536 self.mac.write_reg(sr::STATUS0, 0xFFF).await.unwrap();
537 self.mac.write_reg(sr::STATUS1, status1_clr.0).await.unwrap();
538 }
539 Either::Second(packet) => {
540 // Handle frames that needs to transmit to the wire.
541 self.mac.write_fifo(packet).await.unwrap();
542 tx_chan.tx_done();
543 }
544 }
545 }
546 }
547 }
548}
549
550/// Obtain a driver for using the ADIN1110 with [`embassy-net`](crates.io/crates/embassy-net).
551pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
552 mac_addr: [u8; 6],
553 state: &'_ mut State<N_RX, N_TX>,
554 spi_dev: SPI,
555 int: INT,
556 mut reset: RST,
557 crc: bool,
558) -> (Device<'_>, Runner<'_, SPI, INT, RST>) {
559 use crate::regs::{IMask0, IMask1};
560
561 #[cfg(feature = "defmt")]
562 defmt::info!("INIT ADIN1110");
563
564 // Reset sequence
565 reset.set_low().unwrap();
566 // Wait t1: 20-43mS
567 Timer::after(Duration::from_millis(30)).await;
568
569 reset.set_high().unwrap();
570
571 // Wait t3: 50mS
572 Timer::after(Duration::from_millis(50)).await;
573
574 // Create device
575 let mut mac = ADIN1110::new(spi_dev, crc);
576
577 // Check PHYID
578 let id = mac.read_reg(sr::PHYID).await.unwrap();
579 assert_eq!(id, PHYID);
580
581 #[cfg(feature = "defmt")]
582 defmt::debug!("SPE: CHIP MAC/ID: {:08x}", id);
583
584 #[cfg(feature = "defmt")]
585 let adin_phy = Phy10BaseT1x::default();
586 #[cfg(feature = "defmt")]
587 let phy_id = adin_phy.get_id(&mut mac).await.unwrap();
588 #[cfg(feature = "defmt")]
589 defmt::debug!("SPE: CHIP: PHY ID: {:08x}", phy_id);
590
591 let mi_control = mac.read_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8).await.unwrap();
592 #[cfg(feature = "defmt")]
593 defmt::println!("SPE CHIP PHY MI_CONTROL {:04x}", mi_control);
594 if mi_control & 0x0800 != 0 {
595 let val = mi_control & !0x0800;
596 #[cfg(feature = "defmt")]
597 defmt::println!("SPE CHIP PHY MI_CONTROL Disable PowerDown");
598 mac.write_cl22(MDIO_PHY_ADDR, RegsC22::CONTROL as u8, val)
599 .await
600 .unwrap();
601 }
602
603 // Config2: CRC_APPEND
604 let mut config2 = Config2(0x00000800);
605 config2.set_crc_append(true);
606 mac.write_reg(sr::CONFIG2, config2.0).await.unwrap();
607
608 // Pin Mux Config 1
609 let led_val = (0b11 << 6) | (0b11 << 4); // | (0b00 << 1);
610 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::DIGIO_PINMUX.into(), led_val)
611 .await
612 .unwrap();
613
614 let mut led_pol = LedPolarity(0);
615 led_pol.set_led1_polarity(LedPol::ActiveLow);
616 led_pol.set_led0_polarity(LedPol::ActiveLow);
617
618 // Led Polarity Regisgere Active Low
619 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_POLARITY.into(), led_pol.0)
620 .await
621 .unwrap();
622
623 // Led Both On
624 let mut led_cntr = LedCntrl(0x0);
625
626 // LED1: Yellow
627 led_cntr.set_led1_en(true);
628 led_cntr.set_led1_function(LedFunc::TxLevel2P4);
629 // LED0: Green
630 led_cntr.set_led0_en(true);
631 led_cntr.set_led0_function(LedFunc::LinkupTxRxActicity);
632
633 mac.write_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::LED_CNTRL.into(), led_cntr.0)
634 .await
635 .unwrap();
636
637 // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE
638 // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR
639 // Have to clear the mask the enable it.
640 let mut imask0_val = IMask0(0x0000_1FBF);
641 imask0_val.set_txfcsem(false);
642 imask0_val.set_phyintm(false);
643 imask0_val.set_txboem(false);
644 imask0_val.set_rxboem(false);
645 imask0_val.set_txpem(false);
646
647 mac.write_reg(sr::IMASK0, imask0_val.0).await.unwrap();
648
649 // Set ADIN1110 Interrupts, RX_READY and LINK_CHANGE
650 // Enable interrupts LINK_CHANGE, TX_RDY, RX_RDY(P1), SPI_ERR
651 // Have to clear the mask the enable it.
652 let mut imask1_val = IMask1(0x43FA_1F1A);
653 imask1_val.set_link_change_mask(false);
654 imask1_val.set_p1_rx_rdy_mask(false);
655 imask1_val.set_spi_err_mask(false);
656 imask1_val.set_tx_ecc_err_mask(false);
657 imask1_val.set_rx_ecc_err_mask(false);
658
659 mac.write_reg(sr::IMASK1, imask1_val.0).await.unwrap();
660
661 // Program mac address but also sets mac filters.
662 mac.set_mac_addr(&mac_addr).await.unwrap();
663
664 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr));
665 (
666 device,
667 Runner {
668 ch: runner,
669 mac,
670 int,
671 is_link_up: false,
672 _reset: reset,
673 },
674 )
675}
676
677#[cfg(test)]
678mod tests {
679 use core::convert::Infallible;
680
681 use embedded_hal_1::digital::{ErrorType, OutputPin};
682 use embedded_hal_async::delay::DelayUs;
683 use embedded_hal_bus::spi::ExclusiveDevice;
684 use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
685
686 #[derive(Debug, Default)]
687 struct CsPinMock {
688 pub high: u32,
689 pub low: u32,
690 }
691 impl OutputPin for CsPinMock {
692 fn set_low(&mut self) -> Result<(), Self::Error> {
693 self.low += 1;
694 Ok(())
695 }
696
697 fn set_high(&mut self) -> Result<(), Self::Error> {
698 self.high += 1;
699 Ok(())
700 }
701 }
702 impl ErrorType for CsPinMock {
703 type Error = Infallible;
704 }
705
706 use super::*;
707
708 // TODO: This is currently a workaround unit `ExclusiveDevice` is moved to `embedded-hal-bus`
709 // see https://github.com/rust-embedded/embedded-hal/pull/462#issuecomment-1560014426
710 struct MockDelay {}
711
712 impl DelayUs for MockDelay {
713 async fn delay_us(&mut self, _us: u32) {
714 todo!()
715 }
716
717 async fn delay_ms(&mut self, _ms: u32) {
718 todo!()
719 }
720 }
721
722 #[futures_test::test]
723 async fn mac_read_registers_without_crc() {
724 // Configure expectations
725 let expectations = [
726 // 1st
727 SpiTransaction::write_vec(vec![0x80, 0x01, TURN_AROUND_BYTE]),
728 SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91]),
729 SpiTransaction::flush(),
730 // 2nd
731 SpiTransaction::write_vec(vec![0x80, 0x02, TURN_AROUND_BYTE]),
732 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3]),
733 SpiTransaction::flush(),
734 ];
735 let mut spi = SpiMock::new(&expectations);
736
737 let cs = CsPinMock::default();
738 let delay = MockDelay {};
739 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
740 let mut spe = ADIN1110::new(spi_dev, false);
741
742 // Read PHIID
743 match spe.read_reg(sr::PHYID).await {
744 Ok(val) => assert_eq!(val, 0x0283BC91),
745 Err(_e) => panic!("Error:"),
746 };
747
748 // Read CAPAVILITY
749 match spe.read_reg(sr::CAPABILITY).await {
750 Ok(val) => assert_eq!(val, 0x000006C3),
751 Err(_e) => panic!("Error:"),
752 };
753
754 spi.done();
755 }
756
757 #[futures_test::test]
758 async fn mac_read_registers_with_crc() {
759 // Configure expectations
760 let expectations = [
761 // 1st
762 SpiTransaction::write_vec(vec![0x80, 0x01, 177, TURN_AROUND_BYTE]),
763 SpiTransaction::read_vec(vec![0x02, 0x83, 0xBC, 0x91, 215]),
764 SpiTransaction::flush(),
765 // 2nd
766 SpiTransaction::write_vec(vec![0x80, 0x02, 184, TURN_AROUND_BYTE]),
767 SpiTransaction::read_vec(vec![0x00, 0x00, 0x06, 0xC3, 57]),
768 SpiTransaction::flush(),
769 ];
770 let mut spi = SpiMock::new(&expectations);
771
772 let cs = CsPinMock::default();
773 let delay = MockDelay {};
774 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
775
776 let mut spe = ADIN1110::new(spi_dev, true);
777
778 assert_eq!(crc8(0x0283BC91_u32.to_be_bytes().as_slice()), 215);
779 assert_eq!(crc8(0x000006C3_u32.to_be_bytes().as_slice()), 57);
780
781 // Read PHIID
782 match spe.read_reg(sr::PHYID).await {
783 Ok(val) => assert_eq!(val, 0x0283BC91),
784 Err(e) => panic!("Error: {e:?}"),
785 };
786
787 // Read CAPAVILITY
788 match spe.read_reg(sr::CAPABILITY).await {
789 Ok(val) => assert_eq!(val, 0x000006C3),
790 Err(_e) => panic!("Error:"),
791 };
792
793 spi.done();
794 }
795
796 #[futures_test::test]
797 async fn mac_write_registers_without_crc() {
798 // Configure expectations
799 let expectations = [
800 SpiTransaction::write_vec(vec![0xA0, 0x09, 0x12, 0x34, 0x56, 0x78]),
801 SpiTransaction::flush(),
802 ];
803 let mut spi = SpiMock::new(&expectations);
804
805 let cs = CsPinMock::default();
806 let delay = MockDelay {};
807 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
808
809 let mut spe = ADIN1110::new(spi_dev, false);
810
811 // Write reg: 0x1FFF
812 assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
813
814 spi.done();
815 }
816
817 #[futures_test::test]
818 async fn mac_write_registers_with_crc() {
819 // Configure expectations
820 let expectations = [
821 SpiTransaction::write_vec(vec![0xA0, 0x09, 39, 0x12, 0x34, 0x56, 0x78, 28]),
822 SpiTransaction::flush(),
823 ];
824 let mut spi = SpiMock::new(&expectations);
825
826 let cs = CsPinMock::default();
827 let delay = MockDelay {};
828 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
829
830 let mut spe = ADIN1110::new(spi_dev, true);
831
832 // Write reg: 0x1FFF
833 assert!(spe.write_reg(sr::STATUS1, 0x1234_5678).await.is_ok());
834
835 spi.done();
836 }
837
838 #[test]
839 fn align_size() {
840 assert_eq!(size_align_u32(1), 4);
841 assert_eq!(size_align_u32(2), 4);
842 assert_eq!(size_align_u32(3), 4);
843 assert_eq!(size_align_u32(4), 4);
844 assert_eq!(size_align_u32(5), 8);
845 assert_eq!(size_align_u32(6), 8);
846 assert_eq!(size_align_u32(7), 8);
847 assert_eq!(size_align_u32(8), 8);
848 }
849
850 // #[test]
851 // fn write_packet_to_fifo_less_64b_with_crc() {
852 // // Configure expectations
853 // let mut expectations = vec![
854 // // HEADER
855 // SpiTransaction::send(0xA0),
856 // SpiTransaction::read(DONT_CARE_BYTE),
857 // SpiTransaction::send(0x30),
858 // SpiTransaction::read(DONT_CARE_BYTE),
859 // SpiTransaction::send(136),
860 // SpiTransaction::read(DONT_CARE_BYTE),
861 // // Frame Size
862 // SpiTransaction::send(0x00),
863 // SpiTransaction::read(DONT_CARE_BYTE),
864 // SpiTransaction::send(0x00),
865 // SpiTransaction::read(DONT_CARE_BYTE),
866 // SpiTransaction::send(0x00),
867 // SpiTransaction::read(DONT_CARE_BYTE),
868 // SpiTransaction::send(66),
869 // SpiTransaction::read(DONT_CARE_BYTE),
870 // SpiTransaction::send(201),
871 // SpiTransaction::read(DONT_CARE_BYTE),
872 // // HEADER
873 // SpiTransaction::send(0xA0),
874 // SpiTransaction::read(DONT_CARE_BYTE),
875 // SpiTransaction::send(0x31),
876 // SpiTransaction::read(DONT_CARE_BYTE),
877 // // Port
878 // SpiTransaction::send(0x00),
879 // SpiTransaction::read(DONT_CARE_BYTE),
880 // SpiTransaction::send(PORT_ID_BYTE),
881 // SpiTransaction::read(DONT_CARE_BYTE),
882 // ];
883
884 // let mut packet = Packet::new();
885 // packet.resize(64, 0).unwrap();
886
887 // for &byte in &packet[4..] {
888 // expectations.push(SpiTransaction::send(byte));
889 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
890 // }
891
892 // // padding
893 // for _ in packet.len() as u32..65 {
894 // expectations.push(SpiTransaction::send(0x00));
895 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
896 // }
897
898 // // fcs
899 // for &byte in &[8, 137, 18, 4] {
900 // expectations.push(SpiTransaction::send(byte));
901 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
902 // }
903
904 // let spi = SpiMock::new(&expectations);
905
906 // let cs = CsPinMock {};
907 // let mut spe = Adin1110::new(spi, cs, true);
908
909 // assert!(spe.write_fifo(&mut packet).is_ok());
910 // }
911
912 // #[test]
913 // fn write_packet_to_fifo_less_64b_no_crc() {
914 // // Configure expectations
915 // let mut expectations = vec![
916 // // HEADER
917 // SpiTransaction::send(0xA0),
918 // SpiTransaction::read(DONT_CARE_BYTE),
919 // SpiTransaction::send(0x30),
920 // SpiTransaction::read(DONT_CARE_BYTE),
921 // // Frame Size
922 // SpiTransaction::send(0x00),
923 // SpiTransaction::read(DONT_CARE_BYTE),
924 // SpiTransaction::send(0x00),
925 // SpiTransaction::read(DONT_CARE_BYTE),
926 // SpiTransaction::send(0x00),
927 // SpiTransaction::read(DONT_CARE_BYTE),
928 // SpiTransaction::send(66),
929 // SpiTransaction::read(DONT_CARE_BYTE),
930 // // HEADER
931 // SpiTransaction::send(0xA0),
932 // SpiTransaction::read(DONT_CARE_BYTE),
933 // SpiTransaction::send(0x31),
934 // SpiTransaction::read(DONT_CARE_BYTE),
935 // // Port
936 // SpiTransaction::send(0x00),
937 // SpiTransaction::read(DONT_CARE_BYTE),
938 // SpiTransaction::send(PORT_ID_BYTE),
939 // SpiTransaction::read(DONT_CARE_BYTE),
940 // ];
941
942 // let mut packet = Packet::new();
943 // packet.resize(64, 0).unwrap();
944
945 // for &byte in &packet[4..] {
946 // expectations.push(SpiTransaction::send(byte));
947 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
948 // }
949
950 // // padding
951 // for _ in packet.len() as u32..64 {
952 // expectations.push(SpiTransaction::send(0x00));
953 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
954 // }
955
956 // // fcs
957 // for &byte in &[8, 137, 18, 4] {
958 // expectations.push(SpiTransaction::send(byte));
959 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
960 // }
961
962 // let spi = SpiMock::new(&expectations);
963
964 // let cs = CsPinMock {};
965 // let mut spe = Adin1110::new(spi, cs, false);
966
967 // assert!(spe.write_fifo(&mut packet).is_ok());
968 // }
969
970 // #[test]
971 // fn write_packet_to_fifo_1500b() {
972 // // Configure expectations
973 // let mut expectations = vec![
974 // // HEADER
975 // SpiTransaction::send(0xA0),
976 // SpiTransaction::read(DONT_CARE_BYTE),
977 // SpiTransaction::send(0x30),
978 // SpiTransaction::read(DONT_CARE_BYTE),
979 // // Frame Size
980 // SpiTransaction::send(0x00),
981 // SpiTransaction::read(DONT_CARE_BYTE),
982 // SpiTransaction::send(0x00),
983 // SpiTransaction::read(DONT_CARE_BYTE),
984 // SpiTransaction::send(0x05),
985 // SpiTransaction::read(DONT_CARE_BYTE),
986 // SpiTransaction::send(0xDE),
987 // SpiTransaction::read(DONT_CARE_BYTE),
988 // // HEADER
989 // SpiTransaction::send(0xA0),
990 // SpiTransaction::read(DONT_CARE_BYTE),
991 // SpiTransaction::send(0x31),
992 // SpiTransaction::read(DONT_CARE_BYTE),
993 // // Port
994 // SpiTransaction::send(0x00),
995 // SpiTransaction::read(DONT_CARE_BYTE),
996 // SpiTransaction::send(PORT_ID_BYTE),
997 // SpiTransaction::read(DONT_CARE_BYTE),
998 // ];
999
1000 // let mut packet = Packet::new();
1001 // packet.resize(1500, 0).unwrap();
1002
1003 // for &byte in &packet[4..] {
1004 // expectations.push(SpiTransaction::send(byte));
1005 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1006 // }
1007
1008 // // fcs
1009 // for &byte in &[212, 114, 18, 50] {
1010 // expectations.push(SpiTransaction::send(byte));
1011 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1012 // }
1013
1014 // let spi = SpiMock::new(&expectations);
1015
1016 // let cs = CsPinMock {};
1017 // let mut spe = Adin1110::new(spi, cs, false);
1018
1019 // assert!(spe.write_fifo(&mut packet).is_ok());
1020 // }
1021
1022 // #[test]
1023 // fn write_packet_to_fifo_65b() {
1024 // // Configure expectations
1025 // let mut expectations = vec![
1026 // // HEADER
1027 // SpiTransaction::send(0xA0),
1028 // SpiTransaction::read(DONT_CARE_BYTE),
1029 // SpiTransaction::send(0x30),
1030 // SpiTransaction::read(DONT_CARE_BYTE),
1031 // // Frame Size
1032 // SpiTransaction::send(0x00),
1033 // SpiTransaction::read(DONT_CARE_BYTE),
1034 // SpiTransaction::send(0x00),
1035 // SpiTransaction::read(DONT_CARE_BYTE),
1036 // SpiTransaction::send(0x00),
1037 // SpiTransaction::read(DONT_CARE_BYTE),
1038 // SpiTransaction::send(67),
1039 // SpiTransaction::read(DONT_CARE_BYTE),
1040 // // HEADER
1041 // SpiTransaction::send(0xA0),
1042 // SpiTransaction::read(DONT_CARE_BYTE),
1043 // SpiTransaction::send(0x31),
1044 // SpiTransaction::read(DONT_CARE_BYTE),
1045 // // Port
1046 // SpiTransaction::send(0x00),
1047 // SpiTransaction::read(DONT_CARE_BYTE),
1048 // SpiTransaction::send(PORT_ID_BYTE),
1049 // SpiTransaction::read(DONT_CARE_BYTE),
1050 // ];
1051
1052 // let mut packet = Packet::new();
1053 // packet.resize(65, 0).unwrap();
1054
1055 // for &byte in &packet[4..] {
1056 // expectations.push(SpiTransaction::send(byte));
1057 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1058 // }
1059
1060 // // padding
1061 // for _ in packet.len() as u32..64 {
1062 // expectations.push(SpiTransaction::send(0x00));
1063 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1064 // }
1065
1066 // // fcs
1067 // for &byte in &[54, 117, 221, 220] {
1068 // expectations.push(SpiTransaction::send(byte));
1069 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1070 // }
1071
1072 // let spi = SpiMock::new(&expectations);
1073
1074 // let cs = CsPinMock {};
1075 // let mut spe = Adin1110::new(spi, cs, false);
1076
1077 // assert!(spe.write_fifo(&mut packet).is_ok());
1078 // }
1079
1080 // #[test]
1081 // fn write_packet_to_fifo_66b() {
1082 // // Configure expectations
1083 // let mut expectations = vec![
1084 // // HEADER
1085 // SpiTransaction::send(0xA0),
1086 // SpiTransaction::read(DONT_CARE_BYTE),
1087 // SpiTransaction::send(0x30),
1088 // SpiTransaction::read(DONT_CARE_BYTE),
1089 // // Frame Size
1090 // SpiTransaction::send(0x00),
1091 // SpiTransaction::read(DONT_CARE_BYTE),
1092 // SpiTransaction::send(0x00),
1093 // SpiTransaction::read(DONT_CARE_BYTE),
1094 // SpiTransaction::send(0x00),
1095 // SpiTransaction::read(DONT_CARE_BYTE),
1096 // SpiTransaction::send(68),
1097 // SpiTransaction::read(DONT_CARE_BYTE),
1098 // // HEADER
1099 // SpiTransaction::send(0xA0),
1100 // SpiTransaction::read(DONT_CARE_BYTE),
1101 // SpiTransaction::send(0x31),
1102 // SpiTransaction::read(DONT_CARE_BYTE),
1103 // // Port
1104 // SpiTransaction::send(0x00),
1105 // SpiTransaction::read(DONT_CARE_BYTE),
1106 // SpiTransaction::send(PORT_ID_BYTE),
1107 // SpiTransaction::read(DONT_CARE_BYTE),
1108 // ];
1109
1110 // let mut packet = Packet::new();
1111 // packet.resize(66, 0).unwrap();
1112
1113 // for &byte in &packet[4..] {
1114 // expectations.push(SpiTransaction::send(byte));
1115 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1116 // }
1117
1118 // // padding
1119 // for _ in packet.len() as u32..64 {
1120 // expectations.push(SpiTransaction::send(0x00));
1121 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1122 // }
1123
1124 // // fcs
1125 // for &byte in &[97, 167, 100, 29] {
1126 // expectations.push(SpiTransaction::send(byte));
1127 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1128 // }
1129 // let spi = SpiMock::new(&expectations);
1130
1131 // let cs = CsPinMock {};
1132 // let mut spe = Adin1110::new(spi, cs, false);
1133
1134 // assert!(spe.write_fifo(&mut packet).is_ok());
1135 // }
1136
1137 // #[test]
1138 // fn write_packet_to_fifo_67b() {
1139 // // Configure expectations
1140 // let mut expectations = vec![
1141 // // HEADER
1142 // SpiTransaction::send(0xA0),
1143 // SpiTransaction::read(DONT_CARE_BYTE),
1144 // SpiTransaction::send(0x30),
1145 // SpiTransaction::read(DONT_CARE_BYTE),
1146 // // Frame Size
1147 // SpiTransaction::send(0x00),
1148 // SpiTransaction::read(DONT_CARE_BYTE),
1149 // SpiTransaction::send(0x00),
1150 // SpiTransaction::read(DONT_CARE_BYTE),
1151 // SpiTransaction::send(0x00),
1152 // SpiTransaction::read(DONT_CARE_BYTE),
1153 // SpiTransaction::send(69),
1154 // SpiTransaction::read(DONT_CARE_BYTE),
1155 // // HEADER
1156 // SpiTransaction::send(0xA0),
1157 // SpiTransaction::read(DONT_CARE_BYTE),
1158 // SpiTransaction::send(0x31),
1159 // SpiTransaction::read(DONT_CARE_BYTE),
1160 // // Port
1161 // SpiTransaction::send(0x00),
1162 // SpiTransaction::read(DONT_CARE_BYTE),
1163 // SpiTransaction::send(PORT_ID_BYTE),
1164 // SpiTransaction::read(DONT_CARE_BYTE),
1165 // ];
1166
1167 // let mut packet = Packet::new();
1168 // packet.resize(67, 0).unwrap();
1169
1170 // for &byte in &packet[4..] {
1171 // expectations.push(SpiTransaction::send(byte));
1172 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1173 // }
1174
1175 // // padding
1176 // for _ in packet.len() as u32..64 {
1177 // expectations.push(SpiTransaction::send(0x00));
1178 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1179 // }
1180
1181 // // fcs
1182 // for &byte in &[228, 218, 170, 232] {
1183 // expectations.push(SpiTransaction::send(byte));
1184 // expectations.push(SpiTransaction::read(DONT_CARE_BYTE));
1185 // }
1186 // let spi = SpiMock::new(&expectations);
1187
1188 // let cs = CsPinMock {};
1189 // let mut spe = Adin1110::new(spi, cs, false);
1190
1191 // assert!(spe.write_fifo(&mut packet).is_ok());
1192 // }
1193
1194 #[futures_test::test]
1195 async fn write_packet_to_fifo_arp_46bytes() {
1196 // Configure expectations
1197 let mut expectations = vec![];
1198
1199 let mut packet = Packet::new();
1200 //arp packet;
1201 packet
1202 .extend_from_slice(&[
1203 34, 51, 68, 85, 102, 119, 18, 52, 86, 120, 154, 188, 8, 6, 0, 1, 8, 0, 6, 4, 0, 2, 18, 52, 86, 120,
1204 154, 188, 192, 168, 16, 4, 34, 51, 68, 85, 102, 119, 192, 168, 16, 1,
1205 ])
1206 .unwrap();
1207
1208 let mut spi_packet = Packet::new();
1209
1210 // Write TX_SIZE reg
1211 expectations.push(SpiTransaction::write_vec(vec![160, 48, 136, 0, 0, 0, 66, 201]));
1212 expectations.push(SpiTransaction::flush());
1213
1214 // Write TX reg.
1215 // Header
1216 spi_packet.extend_from_slice(&[160, 49, 143, 0, 0]).unwrap();
1217 // Packet data
1218 spi_packet.extend_from_slice(&packet).unwrap();
1219 // Packet padding up to 60 (64 - FCS)
1220 for _ in packet.len() as u32..60 {
1221 spi_packet.push(0x00).unwrap();
1222 }
1223 // Packet FCS
1224 spi_packet.extend_from_slice(&[147, 149, 213, 68]).unwrap();
1225
1226 // SPI HEADER Padding of u32
1227 for _ in spi_packet.len() as u32..size_align_u32(spi_packet.len() as u32) {
1228 spi_packet.push(0x00).unwrap();
1229 }
1230
1231 expectations.push(SpiTransaction::write_vec(spi_packet.to_vec()));
1232 expectations.push(SpiTransaction::flush());
1233
1234 let mut spi = SpiMock::new(&expectations);
1235
1236 let cs = CsPinMock::default();
1237 let delay = MockDelay {};
1238 let spi_dev = ExclusiveDevice::new(spi.clone(), cs, delay);
1239
1240 let mut spe = ADIN1110::new(spi_dev, true);
1241
1242 assert!(spe.write_fifo(&mut packet).await.is_ok());
1243
1244 spi.done();
1245 }
1246}
diff --git a/embassy-net-adin1110/src/mdio.rs b/embassy-net-adin1110/src/mdio.rs
new file mode 100644
index 000000000..ab7629d3d
--- /dev/null
+++ b/embassy-net-adin1110/src/mdio.rs
@@ -0,0 +1,174 @@
1/// PHY Address: (0..=0x1F), 5-bits long.
2#[allow(dead_code)]
3type PhyAddr = u8;
4
5/// PHY Register: (0..=0x1F), 5-bits long.
6#[allow(dead_code)]
7type RegC22 = u8;
8
9/// PHY Register Clause 45.
10#[allow(dead_code)]
11type RegC45 = u16;
12
13/// PHY Register Value
14#[allow(dead_code)]
15type RegVal = u16;
16
17#[allow(dead_code)]
18const REG13: RegC22 = 13;
19#[allow(dead_code)]
20const REG14: RegC22 = 14;
21
22#[allow(dead_code)]
23const PHYADDR_MASK: u8 = 0x1f;
24#[allow(dead_code)]
25const DEV_MASK: u8 = 0x1f;
26
27#[allow(dead_code)]
28#[repr(u16)]
29enum Reg13Op {
30 Addr = 0b00 << 14,
31 Write = 0b01 << 14,
32 PostReadIncAddr = 0b10 << 14,
33 Read = 0b11 << 14,
34}
35/// MdioBus trait
36/// Driver needs to implemnt the Claus 22
37/// Optional Clause 45 is the device supports this.
38///
39/// Claus 45 methodes are bases on https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf
40pub trait MdioBus {
41 type Error;
42
43 /// Read, Clause 22
44 async fn read_cl22(&mut self, phy_id: PhyAddr, reg: RegC22) -> Result<RegVal, Self::Error>;
45
46 /// Write, Clause 22
47 async fn write_cl22(&mut self, phy_id: PhyAddr, reg: RegC22, reg_val: RegVal) -> Result<(), Self::Error>;
48
49 /// Read, Clause 45
50 /// This is the default implementation.
51 /// Many hardware these days support direct Clause 45 operations.
52 /// Implement this function when your hardware supports it.
53 async fn read_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45)) -> Result<RegVal, Self::Error> {
54 // Write FN
55 let val = (Reg13Op::Addr as RegVal) | (regc45.0 & DEV_MASK) as RegVal;
56 self.write_cl22(phy_id, REG13, val).await?;
57 // Write Addr
58 self.write_cl22(phy_id, REG14, regc45.1).await?;
59
60 // Write FN
61 let val = (Reg13Op::Read as RegVal) | (regc45.0 & DEV_MASK) as RegVal;
62 self.write_cl22(phy_id, REG13, val).await?;
63 // Write Addr
64 self.read_cl22(phy_id, REG14).await
65 }
66
67 /// Write, Clause 45
68 /// This is the default implementation.
69 /// Many hardware these days support direct Clause 45 operations.
70 /// Implement this function when your hardware supports it.
71 async fn write_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45), reg_val: RegVal) -> Result<(), Self::Error> {
72 let dev_addr = (regc45.0 & DEV_MASK) as RegVal;
73 let reg = regc45.1;
74
75 // Write FN
76 let val = (Reg13Op::Addr as RegVal) | dev_addr;
77 self.write_cl22(phy_id, REG13, val).await?;
78 // Write Addr
79 self.write_cl22(phy_id, REG14, reg).await?;
80
81 // Write FN
82 let val = (Reg13Op::Write as RegVal) | dev_addr;
83 self.write_cl22(phy_id, REG13, val).await?;
84 // Write Addr
85 self.write_cl22(phy_id, REG14, reg_val).await
86 }
87}
88
89// #[cfg(test)]
90// mod tests {
91// use core::convert::Infallible;
92
93// use super::{MdioBus, PhyAddr, RegC22, RegVal};
94
95// #[derive(Debug, PartialEq, Eq)]
96// enum A {
97// Read(PhyAddr, RegC22),
98// Write(PhyAddr, RegC22, RegVal),
99// }
100
101// struct MockMdioBus(Vec<A>);
102
103// impl MockMdioBus {
104// pub fn clear(&mut self) {
105// self.0.clear();
106// }
107// }
108
109// impl MdioBus for MockMdioBus {
110// type Error = Infallible;
111
112// fn write_cl22(
113// &mut self,
114// phy_id: super::PhyAddr,
115// reg: super::RegC22,
116// reg_val: super::RegVal,
117// ) -> Result<(), Self::Error> {
118// self.0.push(A::Write(phy_id, reg, reg_val));
119// Ok(())
120// }
121
122// fn read_cl22(
123// &mut self,
124// phy_id: super::PhyAddr,
125// reg: super::RegC22,
126// ) -> Result<super::RegVal, Self::Error> {
127// self.0.push(A::Read(phy_id, reg));
128// Ok(0)
129// }
130// }
131
132// #[test]
133// fn read_test() {
134// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
135
136// mdiobus.clear();
137// mdiobus.read_cl22(0x01, 0x00).unwrap();
138// assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]);
139
140// mdiobus.clear();
141// mdiobus.read_cl45(0x01, (0xBB, 0x1234)).unwrap();
142// assert_eq!(
143// mdiobus.0,
144// vec![
145// #[allow(clippy::identity_op)]
146// A::Write(0x01, 13, (0b00 << 14) | 27),
147// A::Write(0x01, 14, 0x1234),
148// A::Write(0x01, 13, (0b11 << 14) | 27),
149// A::Read(0x01, 14)
150// ]
151// );
152// }
153
154// #[test]
155// fn write_test() {
156// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
157
158// mdiobus.clear();
159// mdiobus.write_cl22(0x01, 0x00, 0xABCD).unwrap();
160// assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]);
161
162// mdiobus.clear();
163// mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).unwrap();
164// assert_eq!(
165// mdiobus.0,
166// vec![
167// A::Write(0x01, 13, 27),
168// A::Write(0x01, 14, 0x1234),
169// A::Write(0x01, 13, (0b01 << 14) | 27),
170// A::Write(0x01, 14, 0xABCD)
171// ]
172// );
173// }
174// }
diff --git a/embassy-net-adin1110/src/phy.rs b/embassy-net-adin1110/src/phy.rs
new file mode 100644
index 000000000..78d3fdf77
--- /dev/null
+++ b/embassy-net-adin1110/src/phy.rs
@@ -0,0 +1,137 @@
1use crate::mdio::MdioBus;
2
3#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
4#[repr(u8)]
5/// Clause 22 Registers
6pub enum RegsC22 {
7 /// MII Control Register
8 CONTROL = 0x00,
9 /// MII Status Register
10 STATUS = 0x01,
11 /// PHY Identifier 1 Register
12 PHY_ID1 = 0x02,
13 /// PHY Identifier 2 Register.
14 PHY_ID2 = 0x03,
15}
16
17/// Clause 45 Registers
18#[allow(non_snake_case, dead_code)]
19pub mod RegsC45 {
20 /// Device Address: 0x01
21 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
22 #[repr(u16)]
23 pub enum DA1 {
24 /// PMA/PMD Control 1 Register
25 PMA_PMD_CNTRL1 = 0x0000,
26 /// PMA/PMD Status 1 Register
27 PMA_PMD_STAT1 = 0x0001,
28 /// MSE Value Register
29 MSE_VAL = 0x830B,
30 }
31
32 impl DA1 {
33 pub fn into(self) -> (u8, u16) {
34 (0x01, self as u16)
35 }
36 }
37
38 /// Device Address: 0x03
39 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
40 #[repr(u16)]
41 pub enum DA3 {
42 /// PCS Control 1 Register
43 PCS_CNTRL1 = 0x0000,
44 /// PCS Status 1 Register
45 PCS_STAT1 = 0x0001,
46 /// PCS Status 2 Register
47 PCS_STAT2 = 0x0008,
48 }
49
50 impl DA3 {
51 pub fn into(self) -> (u8, u16) {
52 (0x03, self as u16)
53 }
54 }
55
56 /// Device Address: 0x07
57 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
58 #[repr(u16)]
59 pub enum DA7 {
60 /// Extra Autonegotiation Status Register
61 AN_STATUS_EXTRA = 0x8001,
62 }
63
64 impl DA7 {
65 pub fn into(self) -> (u8, u16) {
66 (0x07, self as u16)
67 }
68 }
69
70 /// Device Address: 0x1E
71 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
72 #[repr(u16)]
73 pub enum DA1E {
74 /// System Interrupt Status Register
75 CRSM_IRQ_STATUS = 0x0010,
76 /// System Interrupt Mask Register
77 CRSM_IRQ_MASK = 0x0020,
78 /// Pin Mux Configuration 1 Register
79 DIGIO_PINMUX = 0x8c56,
80 /// LED Control Register.
81 LED_CNTRL = 0x8C82,
82 /// LED Polarity Register
83 LED_POLARITY = 0x8C83,
84 }
85
86 impl DA1E {
87 pub fn into(self) -> (u8, u16) {
88 (0x1e, self as u16)
89 }
90 }
91
92 /// Device Address: 0x1F
93 #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
94 #[repr(u16)]
95 pub enum DA1F {
96 /// PHY Subsystem Interrupt Status Register
97 PHY_SYBSYS_IRQ_STATUS = 0x0011,
98 /// PHY Subsystem Interrupt Mask Register
99 PHY_SYBSYS_IRQ_MASK = 0x0021,
100 }
101
102 impl DA1F {
103 pub fn into(self) -> (u8, u16) {
104 (0x1f, self as u16)
105 }
106 }
107}
108
109pub struct Phy10BaseT1x(u8);
110
111impl Default for Phy10BaseT1x {
112 fn default() -> Self {
113 Self(0x01)
114 }
115}
116
117impl Phy10BaseT1x {
118 /// Get the both parts of the PHYID.
119 pub async fn get_id<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u32, MDE>
120 where
121 MDIOBUS: MdioBus<Error = MDE>,
122 MDE: core::fmt::Debug,
123 {
124 let mut phyid = (mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await? as u32) << 16;
125 phyid |= mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await? as u32;
126 Ok(phyid)
127 }
128
129 /// Get the Mean Squared Error Value.
130 pub async fn get_sqi<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u16, MDE>
131 where
132 MDIOBUS: MdioBus<Error = MDE>,
133 MDE: core::fmt::Debug,
134 {
135 mdiobus.read_cl45(self.0, RegsC45::DA1::MSE_VAL.into()).await
136 }
137}
diff --git a/embassy-net-adin1110/src/regs.rs b/embassy-net-adin1110/src/regs.rs
new file mode 100644
index 000000000..93ce812db
--- /dev/null
+++ b/embassy-net-adin1110/src/regs.rs
@@ -0,0 +1,407 @@
1use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
2
3#[allow(non_camel_case_types)]
4#[derive(Debug, Copy, Clone)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6#[repr(u16)]
7/// SPI REGISTER DETAILS
8/// Table 38.
9pub enum SpiRegisters {
10 IDVER = 0x00,
11 PHYID = 0x01,
12 CAPABILITY = 0x02,
13 RESET = 0x03,
14 CONFIG0 = 0x04,
15 CONFIG2 = 0x06,
16 STATUS0 = 0x08,
17 STATUS1 = 0x09,
18 IMASK0 = 0x0C,
19 IMASK1 = 0x0D,
20 MDIO_ACC = 0x20,
21 TX_FSIZE = 0x30,
22 TX = 0x31,
23 TX_SPACE = 0x32,
24 FIFO_CLR = 0x36,
25 ADDR_FILT_UPR0 = 0x50,
26 ADDR_FILT_LWR0 = 0x51,
27 ADDR_FILT_UPR1 = 0x52,
28 ADDR_FILT_LWR1 = 0x53,
29 ADDR_MSK_LWR0 = 0x70,
30 ADDR_MSK_UPR0 = 0x71,
31 ADDR_MSK_LWR1 = 0x72,
32 ADDR_MSK_UPR1 = 0x73,
33 RX_FSIZE = 0x90,
34 RX = 0x91,
35}
36
37impl From<SpiRegisters> for u16 {
38 fn from(val: SpiRegisters) -> Self {
39 val as u16
40 }
41}
42
43impl From<u16> for SpiRegisters {
44 fn from(value: u16) -> Self {
45 match value {
46 0x00 => Self::IDVER,
47 0x01 => Self::PHYID,
48 0x02 => Self::CAPABILITY,
49 0x03 => Self::RESET,
50 0x04 => Self::CONFIG0,
51 0x06 => Self::CONFIG2,
52 0x08 => Self::STATUS0,
53 0x09 => Self::STATUS1,
54 0x0C => Self::IMASK0,
55 0x0D => Self::IMASK1,
56 0x20 => Self::MDIO_ACC,
57 0x30 => Self::TX_FSIZE,
58 0x31 => Self::TX,
59 0x32 => Self::TX_SPACE,
60 0x36 => Self::FIFO_CLR,
61 0x50 => Self::ADDR_FILT_UPR0,
62 0x51 => Self::ADDR_FILT_LWR0,
63 0x52 => Self::ADDR_FILT_UPR1,
64 0x53 => Self::ADDR_FILT_LWR1,
65 0x70 => Self::ADDR_MSK_LWR0,
66 0x71 => Self::ADDR_MSK_UPR0,
67 0x72 => Self::ADDR_MSK_LWR1,
68 0x73 => Self::ADDR_MSK_UPR1,
69 0x90 => Self::RX_FSIZE,
70 0x91 => Self::RX,
71 e => panic!("Unknown value {e}"),
72 }
73 }
74}
75
76// Register definitions
77
78bitfield! {
79 /// Status0 Register bits
80 pub struct Status0(u32);
81 impl Debug;
82 u32;
83 /// Control Data Protection Error
84 pub cdpe, _ : 12;
85 /// Transmit Frame Check Squence Error
86 pub txfcse, _: 11;
87 /// Transmit Time Stamp Capture Available C
88 pub ttscac, _ : 10;
89 /// Transmit Time Stamp Capture Available B
90 pub ttscab, _ : 9;
91 /// Transmit Time Stamp Capture Available A
92 pub ttscaa, _ : 8;
93 /// PHY Interrupt for Port 1
94 pub phyint, _ : 7;
95 /// Reset Complete
96 pub resetc, _ : 6;
97 /// Header error
98 pub hdre, _ : 5;
99 /// Loss of Frame Error
100 pub lofe, _ : 4;
101 /// Receiver Buffer Overflow Error
102 pub rxboe, _ : 3;
103 /// Host Tx FIFO Under Run Error
104 pub txbue, _ : 2;
105 /// Host Tx FIFO Overflow
106 pub txboe, _ : 1;
107 /// Transmit Protocol Error
108 pub txpe, _ : 0;
109}
110
111bitfield! {
112 /// Status1 Register bits
113 pub struct Status1(u32);
114 impl Debug;
115 u32;
116 /// ECC Error on Reading the Frame Size from a Tx FIFO
117 pub tx_ecc_err, set_tx_ecc_err: 12;
118 /// ECC Error on Reading the Frame Size from an Rx FIFO
119 pub rx_ecc_err, set_rx_ecc_err : 11;
120 /// Detected an Error on an SPI Transaction
121 pub spi_err, set_spi_err: 10;
122 /// Rx MAC Interframe Gap Error
123 pub p1_rx_ifg_err, set_p1_rx_ifg_err : 8;
124 /// Port1 Rx Ready High Priority
125 pub p1_rx_rdy_hi, set_p1_rx_rdy_hi : 5;
126 /// Port 1 Rx FIFO Contains Data
127 pub p1_rx_rdy, set_p1_rx_rdy : 4;
128 /// Tx Ready
129 pub tx_rdy, set_tx_rdy : 3;
130 /// Link Status Changed
131 pub link_change, set_link_change : 1;
132 /// Port 1 Link Status
133 pub p1_link_status, _ : 0;
134}
135
136bitfield! {
137 /// Config0 Register bits
138 pub struct Config0(u32);
139 impl Debug;
140 u32;
141 /// Configuration Synchronization
142 pub sync, set_sync : 15;
143 /// Transmit Frame Check Sequence Validation Enable
144 pub txfcsve, set_txfcsve : 14;
145 /// !CS Align Receive Frame Enable
146 pub csarfe, set_csarfe : 13;
147 /// Zero Align Receive Frame Enable
148 pub zarfe, set_zarfe : 12;
149 /// Transmit Credit Threshold
150 pub tcxthresh, set_tcxthresh : 11, 10;
151 /// Transmit Cut Through Enable
152 pub txcte, set_txcte : 9;
153 /// Receive Cut Through Enable
154 pub rxcte, set_rxcte : 8;
155 /// Frame Time Stamp Enable
156 pub ftse, set_ftse : 7;
157 /// Receive Frame Time Stamp Select
158 pub ftss, set_ftss : 6;
159 /// Enable Control Data Read Write Protection
160 pub prote, set_prote : 5;
161 /// Enable TX Data Chunk Sequence and Retry
162 pub seqe, set_seqe : 4;
163 /// Chunk Payload Selector (N).
164 pub cps, set_cps : 2, 0;
165}
166
167bitfield! {
168 /// Config2 Register bits
169 pub struct Config2(u32);
170 impl Debug;
171 u32;
172 /// Assert TX_RDY When the Tx FIFO is Empty
173 pub tx_rdy_on_empty, set_tx_rdy_on_empty : 8;
174 /// Determines If the SFD is Detected in the PHY or MAC
175 pub sdf_detect_src, set_sdf_detect_src : 7;
176 /// Statistics Clear on Reading
177 pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
178 /// Enable CRC Append
179 pub crc_append, set_crc_append : 5;
180 /// Admit Frames with IFG Errors on Port 1 (P1)
181 pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
182 /// Forward Frames Not Matching Any MAC Address to the Host
183 pub p1_fwd_unk2host, set_p1_fwd_unk2host : 2;
184 /// SPI to MDIO Bridge MDC Clock Speed
185 pub mspeed, set_mspeed : 0;
186}
187
188bitfield! {
189 /// IMASK0 Register bits
190 pub struct IMask0(u32);
191 impl Debug;
192 u32;
193 /// Control Data Protection Error Mask
194 pub cppem, set_cppem : 12;
195 /// Transmit Frame Check Sequence Error Mask
196 pub txfcsem, set_txfcsem : 11;
197 /// Transmit Time Stamp Capture Available C Mask
198 pub ttscacm, set_ttscacm : 10;
199 /// Transmit Time Stamp Capture Available B Mask
200 pub ttscabm, set_ttscabm : 9;
201 /// Transmit Time Stamp Capture Available A Mask
202 pub ttscaam, set_ttscaam : 8;
203 /// Physical Layer Interrupt Mask
204 pub phyintm, set_phyintm : 7;
205 /// RESET Complete Mask
206 pub resetcm, set_resetcm : 6;
207 /// Header Error Mask
208 pub hdrem, set_hdrem : 5;
209 /// Loss of Frame Error Mask
210 pub lofem, set_lofem : 4;
211 /// Receive Buffer Overflow Error Mask
212 pub rxboem, set_rxboem : 3;
213 /// Transmit Buffer Underflow Error Mask
214 pub txbuem, set_txbuem : 2;
215 /// Transmit Buffer Overflow Error Mask
216 pub txboem, set_txboem : 1;
217 /// Transmit Protocol Error Mask
218 pub txpem, set_txpem : 0;
219}
220
221bitfield! {
222 /// IMASK1 Register bits
223 pub struct IMask1(u32);
224 impl Debug;
225 u32;
226 /// Mask Bit for TXF_ECC_ERR
227 pub tx_ecc_err_mask, set_tx_ecc_err_mask : 12;
228 /// Mask Bit for RXF_ECC_ERR
229 pub rx_ecc_err_mask, set_rx_ecc_err_mask : 11;
230 /// Mask Bit for SPI_ERR
231 /// This field is only used with the generic SPI protocol
232 pub spi_err_mask, set_spi_err_mask : 10;
233 /// Mask Bit for RX_IFG_ERR
234 pub p1_rx_ifg_err_mask, set_p1_rx_ifg_err_mask : 8;
235 /// Mask Bit for P1_RX_RDY
236 /// This field is only used with the generic SPI protocol
237 pub p1_rx_rdy_mask, set_p1_rx_rdy_mask : 4;
238 /// Mask Bit for TX_FRM_DONE
239 /// This field is only used with the generic SPI protocol
240 pub tx_rdy_mask, set_tx_rdy_mask : 3;
241 /// Mask Bit for LINK_CHANGE
242 pub link_change_mask, set_link_change_mask : 1;
243}
244
245#[repr(u8)]
246pub enum LedFunc {
247 LinkupTxRxActicity = 0,
248 LinkupTxActicity,
249 LinkupRxActicity,
250 LinkupOnly,
251 TxRxActivity,
252 TxActivity,
253 RxActivity,
254 LinkupRxEr,
255 LinkupRxTxEr,
256 RxEr,
257 RxTxEr,
258 TxSop,
259 RxSop,
260 On,
261 Off,
262 Blink,
263 TxLevel2P4,
264 TxLevel1P0,
265 Master,
266 Slave,
267 IncompatiableLinkCfg,
268 AnLinkGood,
269 AnComplete,
270 TsTimer,
271 LocRcvrStatus,
272 RemRcvrStatus,
273 Clk25Ref,
274 TxTCLK,
275 Clk120MHz,
276}
277
278impl From<LedFunc> for u8 {
279 fn from(val: LedFunc) -> Self {
280 val as u8
281 }
282}
283
284impl From<u8> for LedFunc {
285 fn from(value: u8) -> Self {
286 match value {
287 0 => LedFunc::LinkupTxRxActicity,
288 1 => LedFunc::LinkupTxActicity,
289 2 => LedFunc::LinkupRxActicity,
290 3 => LedFunc::LinkupOnly,
291 4 => LedFunc::TxRxActivity,
292 5 => LedFunc::TxActivity,
293 6 => LedFunc::RxActivity,
294 7 => LedFunc::LinkupRxEr,
295 8 => LedFunc::LinkupRxTxEr,
296 9 => LedFunc::RxEr,
297 10 => LedFunc::RxTxEr,
298 11 => LedFunc::TxSop,
299 12 => LedFunc::RxSop,
300 13 => LedFunc::On,
301 14 => LedFunc::Off,
302 15 => LedFunc::Blink,
303 16 => LedFunc::TxLevel2P4,
304 17 => LedFunc::TxLevel1P0,
305 18 => LedFunc::Master,
306 19 => LedFunc::Slave,
307 20 => LedFunc::IncompatiableLinkCfg,
308 21 => LedFunc::AnLinkGood,
309 22 => LedFunc::AnComplete,
310 23 => LedFunc::TsTimer,
311 24 => LedFunc::LocRcvrStatus,
312 25 => LedFunc::RemRcvrStatus,
313 26 => LedFunc::Clk25Ref,
314 27 => LedFunc::TxTCLK,
315 28 => LedFunc::Clk120MHz,
316 e => panic!("Invalid value {e}"),
317 }
318 }
319}
320
321/// LED Control Register
322#[derive(Copy, Clone, PartialEq, Eq, Hash)]
323pub struct LedCntrl(pub u16);
324bitfield_bitrange! {struct LedCntrl(u16)}
325
326impl LedCntrl {
327 bitfield_fields! {
328 u8;
329 /// LED_0 Pin Function
330 pub from into LedFunc, led0_function, set_led0_function: 4, 0;
331 /// LED 0 Mode Selection
332 pub led0_mode, set_led0_mode: 5;
333 /// Qualify Certain LED 0 Options with Link Status.
334 pub led0_link_st_qualify, set_led0_link_st_qualify: 6;
335 /// LED 0 Enable
336 pub led0_en, set_led0_en: 7;
337 /// LED_1 Pin Function
338 pub from into LedFunc, led1_function, set_led1_function: 12, 8;
339 /// /// LED 1 Mode Selection
340 pub led1_mode, set_led1_mode: 13;
341 /// Qualify Certain LED 1 Options with Link Status.
342 pub led1_link_st_qualify, set_led1_link_st_qualify: 14;
343 /// LED 1 Enable
344 pub led1_en, set_led1_en: 15;
345 }
346
347 pub fn new() -> Self {
348 LedCntrl(0)
349 }
350}
351
352// #[allow(dead_code)]
353#[repr(u8)]
354pub enum LedPol {
355 AutoSense = 0,
356 ActiveHigh,
357 ActiveLow,
358}
359
360impl From<LedPol> for u8 {
361 fn from(val: LedPol) -> Self {
362 val as u8
363 }
364}
365
366impl From<u8> for LedPol {
367 fn from(value: u8) -> Self {
368 match value {
369 0 => LedPol::AutoSense,
370 1 => LedPol::ActiveHigh,
371 2 => LedPol::ActiveLow,
372 e => panic!("Invalid value {e}"),
373 }
374 }
375}
376
377/// LED Control Register
378#[derive(Copy, Clone, PartialEq, Eq, Hash)]
379pub struct LedPolarity(pub u16);
380bitfield_bitrange! {struct LedPolarity(u16)}
381
382impl LedPolarity {
383 bitfield_fields! {
384 u8;
385 /// LED 1 Polarity
386 pub from into LedPol, led1_polarity, set_led1_polarity: 3, 2;
387 /// LED_0 Polarity
388 pub from into LedPol, led0_polarity, set_led0_polarity: 1, 0;
389 }
390}
391
392/// LED Control Register
393#[derive(Copy, Clone, PartialEq, Eq, Hash)]
394pub struct SpiHeader(pub u16);
395bitfield_bitrange! {struct SpiHeader(u16)}
396
397impl SpiHeader {
398 bitfield_fields! {
399 u16;
400 /// Mask Bit for TXF_ECC_ERR
401 pub control, set_control : 15;
402 pub full_duplex, set_full_duplex : 14;
403 pub write, set_write : 13;
404 /// LED_0 Polarity
405 pub from into SpiRegisters, addr, set_addr: 11, 0;
406 }
407}