aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-enc28j60
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-net-enc28j60')
-rw-r--r--embassy-net-enc28j60/Cargo.toml23
-rw-r--r--embassy-net-enc28j60/README.md1
-rw-r--r--embassy-net-enc28j60/src/bank0.rs69
-rw-r--r--embassy-net-enc28j60/src/bank1.rs84
-rw-r--r--embassy-net-enc28j60/src/bank2.rs86
-rw-r--r--embassy-net-enc28j60/src/bank3.rs53
-rw-r--r--embassy-net-enc28j60/src/common.rs106
-rw-r--r--embassy-net-enc28j60/src/fmt.rs225
-rw-r--r--embassy-net-enc28j60/src/header.rs30
-rw-r--r--embassy-net-enc28j60/src/lib.rs693
-rw-r--r--embassy-net-enc28j60/src/macros.rs89
-rw-r--r--embassy-net-enc28j60/src/phy.rs36
-rw-r--r--embassy-net-enc28j60/src/traits.rs57
13 files changed, 1552 insertions, 0 deletions
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
new file mode 100644
index 000000000..c502ed04b
--- /dev/null
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -0,0 +1,23 @@
1[package]
2name = "embassy-net-enc28j60"
3version = "0.1.0"
4description = "embassy-net driver for the ENC28J60 ethernet chip"
5keywords = ["embedded", "enc28j60", "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[dependencies]
11embedded-hal = { version = "1.0.0-alpha.11" }
12embedded-hal-async = { version = "=0.2.0-alpha.2" }
13embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
14embassy-time = { version = "0.1.2", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
16
17defmt = { version = "0.3", optional = true }
18log = { version = "0.4.14", optional = true }
19
20[package.metadata.embassy_docs]
21src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/"
22src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/"
23target = "thumbv7em-none-eabi" \ No newline at end of file
diff --git a/embassy-net-enc28j60/README.md b/embassy-net-enc28j60/README.md
new file mode 100644
index 000000000..e12d240c3
--- /dev/null
+++ b/embassy-net-enc28j60/README.md
@@ -0,0 +1 @@
# `embassy-net-enc28j60`
diff --git a/embassy-net-enc28j60/src/bank0.rs b/embassy-net-enc28j60/src/bank0.rs
new file mode 100644
index 000000000..1c1b3a7f6
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank0.rs
@@ -0,0 +1,69 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 ERDPTL = 0x00,
5 ERDPTH = 0x01,
6 EWRPTL = 0x02,
7 EWRPTH = 0x03,
8 ETXSTL = 0x04,
9 ETXSTH = 0x05,
10 ETXNDL = 0x06,
11 ETXNDH = 0x07,
12 ERXSTL = 0x08,
13 ERXSTH = 0x09,
14 ERXNDL = 0x0a,
15 ERXNDH = 0x0b,
16 ERXRDPTL = 0x0c,
17 ERXRDPTH = 0x0d,
18 ERXWRPTL = 0x0e,
19 ERXWRPTH = 0x0f,
20 EDMASTL = 0x10,
21 EDMASTH = 0x11,
22 EDMANDL = 0x12,
23 EDMANDH = 0x13,
24 EDMADSTL = 0x14,
25 EDMADSTH = 0x15,
26 EDMACSL = 0x16,
27 EDMACSH = 0x17,
28}
29
30impl Register {
31 pub(crate) fn addr(&self) -> u8 {
32 *self as u8
33 }
34
35 pub(crate) fn is_eth_register(&self) -> bool {
36 match *self {
37 Register::ERDPTL => true,
38 Register::ERDPTH => true,
39 Register::EWRPTL => true,
40 Register::EWRPTH => true,
41 Register::ETXSTL => true,
42 Register::ETXSTH => true,
43 Register::ETXNDL => true,
44 Register::ETXNDH => true,
45 Register::ERXSTL => true,
46 Register::ERXSTH => true,
47 Register::ERXNDL => true,
48 Register::ERXNDH => true,
49 Register::ERXRDPTL => true,
50 Register::ERXRDPTH => true,
51 Register::ERXWRPTL => true,
52 Register::ERXWRPTH => true,
53 Register::EDMASTL => true,
54 Register::EDMASTH => true,
55 Register::EDMANDL => true,
56 Register::EDMANDH => true,
57 Register::EDMADSTL => true,
58 Register::EDMADSTH => true,
59 Register::EDMACSL => true,
60 Register::EDMACSH => true,
61 }
62 }
63}
64
65impl Into<super::Register> for Register {
66 fn into(self) -> super::Register {
67 super::Register::Bank0(self)
68 }
69}
diff --git a/embassy-net-enc28j60/src/bank1.rs b/embassy-net-enc28j60/src/bank1.rs
new file mode 100644
index 000000000..30560edf6
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank1.rs
@@ -0,0 +1,84 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 EHT0 = 0x00,
5 EHT1 = 0x01,
6 EHT2 = 0x02,
7 EHT3 = 0x03,
8 EHT4 = 0x04,
9 EHT5 = 0x05,
10 EHT6 = 0x06,
11 EHT7 = 0x07,
12 EPMM0 = 0x08,
13 EPMM1 = 0x09,
14 EPMM2 = 0x0a,
15 EPMM3 = 0x0b,
16 EPMM4 = 0x0c,
17 EPMM5 = 0x0d,
18 EPMM6 = 0x0e,
19 EPMM7 = 0x0f,
20 EPMCSL = 0x10,
21 EPMCSH = 0x11,
22 EPMOL = 0x14,
23 EPMOH = 0x15,
24 ERXFCON = 0x18,
25 EPKTCNT = 0x19,
26}
27
28impl Register {
29 pub(crate) fn addr(&self) -> u8 {
30 *self as u8
31 }
32
33 pub(crate) fn is_eth_register(&self) -> bool {
34 match *self {
35 Register::EHT0 => true,
36 Register::EHT1 => true,
37 Register::EHT2 => true,
38 Register::EHT3 => true,
39 Register::EHT4 => true,
40 Register::EHT5 => true,
41 Register::EHT6 => true,
42 Register::EHT7 => true,
43 Register::EPMM0 => true,
44 Register::EPMM1 => true,
45 Register::EPMM2 => true,
46 Register::EPMM3 => true,
47 Register::EPMM4 => true,
48 Register::EPMM5 => true,
49 Register::EPMM6 => true,
50 Register::EPMM7 => true,
51 Register::EPMCSL => true,
52 Register::EPMCSH => true,
53 Register::EPMOL => true,
54 Register::EPMOH => true,
55 Register::ERXFCON => true,
56 Register::EPKTCNT => true,
57 }
58 }
59}
60
61impl Into<super::Register> for Register {
62 fn into(self) -> super::Register {
63 super::Register::Bank1(self)
64 }
65}
66
67register!(ERXFCON, 0b1010_0001, u8, {
68 #[doc = "Broadcast Filter Enable bit"]
69 bcen @ 0,
70 #[doc = "Multicast Filter Enable bit"]
71 mcen @ 1,
72 #[doc = "Hash Table Filter Enable bit"]
73 hten @ 2,
74 #[doc = "Magic Packetâ„¢ Filter Enable bit"]
75 mpen @ 3,
76 #[doc = "Pattern Match Filter Enable bit"]
77 pmen @ 4,
78 #[doc = "Post-Filter CRC Check Enable bit"]
79 crcen @ 5,
80 #[doc = "AND/OR Filter Select bit"]
81 andor @ 6,
82 #[doc = "Unicast Filter Enable bit"]
83 ucen @ 7,
84});
diff --git a/embassy-net-enc28j60/src/bank2.rs b/embassy-net-enc28j60/src/bank2.rs
new file mode 100644
index 000000000..74a1d245f
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank2.rs
@@ -0,0 +1,86 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 MACON1 = 0x00,
5 MACON3 = 0x02,
6 MACON4 = 0x03,
7 MABBIPG = 0x04,
8 MAIPGL = 0x06,
9 MAIPGH = 0x07,
10 MACLCON1 = 0x08,
11 MACLCON2 = 0x09,
12 MAMXFLL = 0x0a,
13 MAMXFLH = 0x0b,
14 MICMD = 0x12,
15 MIREGADR = 0x14,
16 MIWRL = 0x16,
17 MIWRH = 0x17,
18 MIRDL = 0x18,
19 MIRDH = 0x19,
20}
21
22impl Register {
23 pub(crate) fn addr(&self) -> u8 {
24 *self as u8
25 }
26
27 pub(crate) fn is_eth_register(&self) -> bool {
28 match *self {
29 Register::MACON1 => false,
30 Register::MACON3 => false,
31 Register::MACON4 => false,
32 Register::MABBIPG => false,
33 Register::MAIPGL => false,
34 Register::MAIPGH => false,
35 Register::MACLCON1 => false,
36 Register::MACLCON2 => false,
37 Register::MAMXFLL => false,
38 Register::MAMXFLH => false,
39 Register::MICMD => false,
40 Register::MIREGADR => false,
41 Register::MIWRL => false,
42 Register::MIWRH => false,
43 Register::MIRDL => false,
44 Register::MIRDH => false,
45 }
46 }
47}
48
49impl Into<super::Register> for Register {
50 fn into(self) -> super::Register {
51 super::Register::Bank2(self)
52 }
53}
54
55register!(MACON1, 0, u8, {
56 #[doc = "Enable packets to be received by the MAC"]
57 marxen @ 0,
58 #[doc = "Control frames will be discarded after being processed by the MAC"]
59 passall @ 1,
60 #[doc = "Inhibit transmissions when pause control frames are received"]
61 rxpaus @ 2,
62 #[doc = "Allow the MAC to transmit pause control frames"]
63 txpaus @ 3,
64});
65
66register!(MACON3, 0, u8, {
67 #[doc = "MAC will operate in Full-Duplex mode"]
68 fuldpx @ 0,
69 #[doc = "The type/length field of transmitted and received frames will be checked"]
70 frmlnen @ 1,
71 #[doc = "Frames bigger than MAMXFL will be aborted when transmitted or received"]
72 hfrmen @ 2,
73 #[doc = "No proprietary header is present"]
74 phdren @ 3,
75 #[doc = "MAC will append a valid CRC to all frames transmitted regardless of PADCFG bit"]
76 txcrcen @ 4,
77 #[doc = "All short frames will be zero-padded to 64 bytes and a valid CRC will then be appended"]
78 padcfg @ 5..7,
79});
80
81register!(MICMD, 0, u8, {
82 #[doc = "MII Read Enable bit"]
83 miird @ 0,
84 #[doc = "MII Scan Enable bit"]
85 miiscan @ 1,
86});
diff --git a/embassy-net-enc28j60/src/bank3.rs b/embassy-net-enc28j60/src/bank3.rs
new file mode 100644
index 000000000..4f7eb9406
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank3.rs
@@ -0,0 +1,53 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 MAADR5 = 0x00,
5 MAADR6 = 0x01,
6 MAADR3 = 0x02,
7 MAADR4 = 0x03,
8 MAADR1 = 0x04,
9 MAADR2 = 0x05,
10 EBSTSD = 0x06,
11 EBSTCON = 0x07,
12 EBSTCSL = 0x08,
13 EBSTCSH = 0x09,
14 MISTAT = 0x0a,
15 EREVID = 0x12,
16 ECOCON = 0x15,
17 EFLOCON = 0x17,
18 EPAUSL = 0x18,
19 EPAUSH = 0x19,
20}
21
22impl Register {
23 pub(crate) fn addr(&self) -> u8 {
24 *self as u8
25 }
26
27 pub(crate) fn is_eth_register(&self) -> bool {
28 match *self {
29 Register::MAADR5 => false,
30 Register::MAADR6 => false,
31 Register::MAADR3 => false,
32 Register::MAADR4 => false,
33 Register::MAADR1 => false,
34 Register::MAADR2 => false,
35 Register::EBSTSD => true,
36 Register::EBSTCON => true,
37 Register::EBSTCSL => true,
38 Register::EBSTCSH => true,
39 Register::MISTAT => false,
40 Register::EREVID => true,
41 Register::ECOCON => true,
42 Register::EFLOCON => true,
43 Register::EPAUSL => true,
44 Register::EPAUSH => true,
45 }
46 }
47}
48
49impl Into<super::Register> for Register {
50 fn into(self) -> super::Register {
51 super::Register::Bank3(self)
52 }
53}
diff --git a/embassy-net-enc28j60/src/common.rs b/embassy-net-enc28j60/src/common.rs
new file mode 100644
index 000000000..ef339dd2a
--- /dev/null
+++ b/embassy-net-enc28j60/src/common.rs
@@ -0,0 +1,106 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 ECON1 = 0x1f,
5 ECON2 = 0x1e,
6 EIE = 0x1b,
7 EIR = 0x1c,
8 ESTAT = 0x1d,
9}
10
11impl Register {
12 pub(crate) fn addr(&self) -> u8 {
13 *self as u8
14 }
15
16 pub(crate) fn is_eth_register(&self) -> bool {
17 match *self {
18 Register::ECON1 => true,
19 Register::ECON2 => true,
20 Register::EIE => true,
21 Register::EIR => true,
22 Register::ESTAT => true,
23 }
24 }
25}
26
27impl Into<super::Register> for Register {
28 fn into(self) -> super::Register {
29 super::Register::Common(self)
30 }
31}
32
33register!(EIE, 0, u8, {
34 #[doc = "Receive Error Interrupt Enable bit"]
35 rxerie @ 0,
36 #[doc = "Transmit Error Interrupt Enable bit"]
37 txerie @ 1,
38 #[doc = "Transmit Enable bit"]
39 txie @ 3,
40 #[doc = "Link Status Change Interrupt Enable bit"]
41 linkie @ 4,
42 #[doc = "DMA Interrupt Enable bit"]
43 dmaie @ 5,
44 #[doc = "Receive Packet Pending Interrupt Enable bit"]
45 pktie @ 6,
46 #[doc = "Global INT Interrupt Enable bit"]
47 intie @ 7,
48});
49
50register!(EIR, 0, u8, {
51 #[doc = "Receive Error Interrupt Flag bit"]
52 rxerif @ 0,
53 #[doc = "Transmit Error Interrupt Flag bit"]
54 txerif @ 1,
55 #[doc = "Transmit Interrupt Flag bit"]
56 txif @ 3,
57 #[doc = "Link Change Interrupt Flag bit"]
58 linkif @ 4,
59 #[doc = "DMA Interrupt Flag bit"]
60 dmaif @ 5,
61 #[doc = "Receive Packet Pending Interrupt Flag bit"]
62 pktif @ 6,
63});
64
65register!(ESTAT, 0, u8, {
66 #[doc = "Clock Ready bit"]
67 clkrdy @ 0,
68 #[doc = "Transmit Abort Error bit"]
69 txabrt @ 1,
70 #[doc = "Receive Busy bit"]
71 rxbusy @ 2,
72 #[doc = "Late Collision Error bit"]
73 latecol @ 4,
74 #[doc = "Ethernet Buffer Error Status bit"]
75 bufer @ 6,
76 #[doc = "INT Interrupt Flag bit"]
77 int @ 7,
78});
79
80register!(ECON2, 0b1000_0000, u8, {
81 #[doc = "Voltage Regulator Power Save Enable bit"]
82 vrps @ 3,
83 #[doc = "Power Save Enable bit"]
84 pwrsv @ 5,
85 #[doc = "Packet Decrement bit"]
86 pktdec @ 6,
87 #[doc = "Automatic Buffer Pointer Increment Enable bit"]
88 autoinc @ 7,
89});
90
91register!(ECON1, 0, u8, {
92 #[doc = "Bank Select bits"]
93 bsel @ 0..1,
94 #[doc = "Receive Enable bi"]
95 rxen @ 2,
96 #[doc = "Transmit Request to Send bit"]
97 txrts @ 3,
98 #[doc = "DMA Checksum Enable bit"]
99 csumen @ 4,
100 #[doc = "DMA Start and Busy Status bit"]
101 dmast @ 5,
102 #[doc = "Receive Logic Reset bit"]
103 rxrst @ 6,
104 #[doc = "Transmit Logic Reset bit"]
105 txrst @ 7,
106});
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-net-enc28j60/src/fmt.rs
@@ -0,0 +1,225 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-net-enc28j60/src/header.rs b/embassy-net-enc28j60/src/header.rs
new file mode 100644
index 000000000..c2d4e468f
--- /dev/null
+++ b/embassy-net-enc28j60/src/header.rs
@@ -0,0 +1,30 @@
1register!(RxStatus, 0, u32, {
2 #[doc = "Indicates length of the received frame"]
3 byte_count @ 0..15,
4 #[doc = "Indicates a packet over 50,000 bit times occurred or that a packet was dropped since the last receive"]
5 long_event @ 16,
6 #[doc = "Indicates that at some time since the last receive, a carrier event was detected"]
7 carrier_event @ 18,
8 #[doc = "Indicates that frame CRC field value does not match the CRC calculated by the MAC"]
9 crc_error @ 20,
10 #[doc = "Indicates that frame length field value in the packet does not match the actual data byte length and specifies a valid length"]
11 length_check_error @ 21,
12 #[doc = "Indicates that frame type/length field was larger than 1500 bytes (type field)"]
13 length_out_of_range @ 22,
14 #[doc = "Indicates that at the packet had a valid CRC and no symbol errors"]
15 received_ok @ 23,
16 #[doc = "Indicates packet received had a valid Multicast address"]
17 multicast @ 24,
18 #[doc = "Indicates packet received had a valid Broadcast address."]
19 broadcast @ 25,
20 #[doc = "Indicates that after the end of this packet, an additional 1 to 7 bits were received"]
21 dribble_nibble @ 26,
22 #[doc = "Current frame was recognized as a control frame for having a valid type/length designating it as a control frame"]
23 receive_control_frame @ 27,
24 #[doc = "Current frame was recognized as a control frame containing a valid pause frame opcode and a valid destination address"]
25 receive_pause_control_frame @ 28,
26 #[doc = "Current frame was recognized as a control frame but it contained an unknown opcode"]
27 receive_unknown_opcode @ 29,
28 #[doc = "Current frame was recognized as a VLAN tagged frame"]
29 receive_vlan_type_detected @ 30,
30});
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs
new file mode 100644
index 000000000..4f129b6b2
--- /dev/null
+++ b/embassy-net-enc28j60/src/lib.rs
@@ -0,0 +1,693 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3
4// must go first.
5mod fmt;
6
7#[macro_use]
8mod macros;
9mod bank0;
10mod bank1;
11mod bank2;
12mod bank3;
13mod common;
14mod header;
15mod phy;
16mod traits;
17
18use core::cmp;
19use core::convert::TryInto;
20
21use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
22use embassy_time::Duration;
23use embedded_hal::digital::OutputPin;
24use embedded_hal::spi::{Operation, SpiDevice};
25use traits::U16Ext;
26
27// Total buffer size (see section 3.2)
28const BUF_SZ: u16 = 8 * 1024;
29
30// Maximum frame length
31const MAX_FRAME_LENGTH: u16 = 1518; // value recommended in the data sheet
32
33// Size of the Frame check sequence (32-bit CRC)
34const CRC_SZ: u16 = 4;
35
36// define the boundaries of the TX and RX buffers
37// to workaround errata #5 we do the opposite of what section 6.1 of the data sheet
38// says: we place the RX buffer at address 0 and the TX buffer after it
39const RXST: u16 = 0x0000;
40const RXND: u16 = 0x19ff;
41const TXST: u16 = 0x1a00;
42const _TXND: u16 = 0x1fff;
43
44const MTU: usize = 1514; // 1500 IP + 14 ethernet header
45
46pub struct Enc28j60<S, O> {
47 mac_addr: [u8; 6],
48
49 spi: S,
50 rst: Option<O>,
51
52 bank: Bank,
53
54 // address of the next packet in buffer memory
55 next_packet: u16,
56}
57
58impl<S, O> Enc28j60<S, O>
59where
60 S: SpiDevice,
61 O: OutputPin,
62{
63 pub fn new(spi: S, rst: Option<O>, mac_addr: [u8; 6]) -> Self {
64 let mut res = Self {
65 mac_addr,
66 spi,
67 rst,
68
69 bank: Bank::Bank0,
70 next_packet: RXST,
71 };
72 res.init();
73 res
74 }
75
76 fn init(&mut self) {
77 if let Some(rst) = &mut self.rst {
78 rst.set_low().unwrap();
79 embassy_time::block_for(Duration::from_millis(5));
80 rst.set_high().unwrap();
81 embassy_time::block_for(Duration::from_millis(5));
82 } else {
83 embassy_time::block_for(Duration::from_millis(5));
84 self.soft_reset();
85 embassy_time::block_for(Duration::from_millis(5));
86 }
87
88 debug!(
89 "enc28j60: erevid {=u8:x}",
90 self.read_control_register(bank3::Register::EREVID)
91 );
92 debug!("enc28j60: waiting for clk");
93 while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {}
94 debug!("enc28j60: clk ok");
95
96 if self.read_control_register(bank3::Register::EREVID) == 0 {
97 panic!("ErevidIsZero");
98 }
99
100 // disable CLKOUT output
101 self.write_control_register(bank3::Register::ECOCON, 0);
102
103 // RX start
104 // "It is recommended that the ERXST Pointer be programmed with an even address"
105 self.write_control_register(bank0::Register::ERXSTL, RXST.low());
106 self.write_control_register(bank0::Register::ERXSTH, RXST.high());
107
108 // RX read pointer
109 // NOTE Errata #14 so we are using an *odd* address here instead of ERXST
110 self.write_control_register(bank0::Register::ERXRDPTL, RXND.low());
111 self.write_control_register(bank0::Register::ERXRDPTH, RXND.high());
112
113 // RX end
114 self.write_control_register(bank0::Register::ERXNDL, RXND.low());
115 self.write_control_register(bank0::Register::ERXNDH, RXND.high());
116
117 // TX start
118 // "It is recommended that an even address be used for ETXST"
119 debug_assert_eq!(TXST % 2, 0);
120 self.write_control_register(bank0::Register::ETXSTL, TXST.low());
121 self.write_control_register(bank0::Register::ETXSTH, TXST.high());
122
123 // TX end is set in `transmit`
124
125 // MAC initialization (see section 6.5)
126 // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
127 self.write_control_register(
128 bank2::Register::MACON1,
129 bank2::MACON1::default().marxen(1).passall(0).rxpaus(1).txpaus(1).bits(),
130 );
131
132 // 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3.
133 self.write_control_register(
134 bank2::Register::MACON3,
135 bank2::MACON3::default().frmlnen(1).txcrcen(1).padcfg(0b001).bits(),
136 );
137
138 // 4. Program the MAMXFL registers with the maximum frame length to be permitted to be
139 // received or transmitted
140 self.write_control_register(bank2::Register::MAMXFLL, MAX_FRAME_LENGTH.low());
141 self.write_control_register(bank2::Register::MAMXFLH, MAX_FRAME_LENGTH.high());
142
143 // 5. Configure the Back-to-Back Inter-Packet Gap register, MABBIPG.
144 // Use recommended value of 0x12
145 self.write_control_register(bank2::Register::MABBIPG, 0x12);
146
147 // 6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
148 // Use recommended value of 0x12
149 self.write_control_register(bank2::Register::MAIPGL, 0x12);
150 self.write_control_register(bank2::Register::MAIPGH, 0x0c);
151
152 // 9. Program the local MAC address into the MAADR1:MAADR6 registers
153 self.write_control_register(bank3::Register::MAADR1, self.mac_addr[0]);
154 self.write_control_register(bank3::Register::MAADR2, self.mac_addr[1]);
155 self.write_control_register(bank3::Register::MAADR3, self.mac_addr[2]);
156 self.write_control_register(bank3::Register::MAADR4, self.mac_addr[3]);
157 self.write_control_register(bank3::Register::MAADR5, self.mac_addr[4]);
158 self.write_control_register(bank3::Register::MAADR6, self.mac_addr[5]);
159
160 // Set the PHCON2.HDLDIS bit to prevent automatic loopback of the data which is transmitted
161 self.write_phy_register(phy::Register::PHCON2, phy::PHCON2::default().hdldis(1).bits());
162
163 // Globally enable interrupts
164 //self.bit_field_set(common::Register::EIE, common::EIE::mask().intie());
165
166 // Set the per packet control byte; we'll always use the value 0
167 self.write_buffer_memory(Some(TXST), &mut [0]);
168
169 // decrease the packet count to 0
170 while self.read_control_register(bank1::Register::EPKTCNT) != 0 {
171 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
172 }
173
174 // Enable reception
175 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
176 }
177
178 /// Flushes the transmit buffer, ensuring all pending transmissions have completed
179 /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
180 /// return `None` on subsequent invocations
181 pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
182 if self.pending_packets() == 0 {
183 // Errata #6: we can't rely on PKTIF so we check PKTCNT
184 return None;
185 }
186
187 let curr_packet = self.next_packet;
188
189 // read out the first 6 bytes
190 let mut temp_buf = [0; 6];
191 self.read_buffer_memory(Some(curr_packet), &mut temp_buf);
192
193 // next packet pointer
194 let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]);
195 if next_packet > RXND {
196 panic!("CorruptRxBuffer");
197 }
198
199 // status vector
200 let status = header::RxStatus(u32::from_le_bytes(temp_buf[2..].try_into().unwrap()));
201 let len = status.byte_count() as u16 - CRC_SZ;
202
203 if len > RXND {
204 panic!("CorruptRxBuffer 2");
205 }
206
207 self.read_buffer_memory(None, &mut buf[..len as usize]);
208
209 // update ERXRDPT
210 // due to Errata #14 we must write an odd address to ERXRDPT
211 // we know that ERXST = 0, that ERXND is odd and that next_packet is even
212 let rxrdpt = if self.next_packet < 1 || self.next_packet > RXND + 1 {
213 RXND
214 } else {
215 self.next_packet - 1
216 };
217 // "To move ERXRDPT, the host controller must write to ERXRDPTL first."
218 self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low());
219 self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high());
220
221 // decrease the packet count
222 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
223
224 self.next_packet = next_packet;
225
226 Some(&mut buf[..len as usize])
227 }
228
229 fn wait_tx_ready(&mut self) {
230 for _ in 0u32..10000 {
231 if common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 0 {
232 return;
233 }
234 }
235
236 // work around errata #12 by resetting the transmit logic before every new
237 // transmission
238 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst());
239 self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst());
240 //self.bit_field_clear(common::Register::EIR, {
241 // let mask = common::EIR::mask();
242 // mask.txerif() | mask.txif()
243 //});
244 }
245
246 /// Starts the transmission of `bytes`
247 ///
248 /// It's up to the caller to ensure that `bytes` is a valid Ethernet frame. The interface will
249 /// take care of appending a (4 byte) CRC to the frame and of padding the frame to the minimum
250 /// size allowed by the Ethernet specification (64 bytes, or 46 bytes of payload).
251 ///
252 /// NOTE This method will flush any previous transmission that's in progress
253 ///
254 /// # Panics
255 ///
256 /// If `bytes` length is greater than 1514, the maximum frame length allowed by the interface,
257 /// or greater than the transmit buffer
258 pub fn transmit(&mut self, bytes: &[u8]) {
259 assert!(bytes.len() <= self.mtu() as usize);
260
261 self.wait_tx_ready();
262
263 // NOTE the plus one is to not overwrite the per packet control byte
264 let wrpt = TXST + 1;
265
266 // 1. ETXST was set during initialization
267
268 // 2. write the frame to the IC memory
269 self.write_buffer_memory(Some(wrpt), bytes);
270
271 let txnd = wrpt + bytes.len() as u16 - 1;
272
273 // 3. Set the end address of the transmit buffer
274 self.write_control_register(bank0::Register::ETXNDL, txnd.low());
275 self.write_control_register(bank0::Register::ETXNDH, txnd.high());
276
277 // 4. reset interrupt flag
278 //self.bit_field_clear(common::Register::EIR, common::EIR::mask().txif());
279
280 // 5. start transmission
281 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts());
282
283 // Wait until transmission finishes
284 //while common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 1 {}
285
286 /*
287 // read the transmit status vector
288 let mut tx_stat = [0; 7];
289 self.read_buffer_memory(None, &mut tx_stat);
290
291 let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT));
292
293 if stat.txabrt() == 1 {
294 // work around errata #12 by reading the transmit status vector
295 if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 {
296 panic!("LateCollision")
297 } else {
298 panic!("TransmitAbort")
299 }
300 }*/
301 }
302
303 pub fn is_link_up(&mut self) -> bool {
304 let bits = self.read_phy_register(phy::Register::PHSTAT2);
305 phy::PHSTAT2(bits).lstat() == 1
306 }
307
308 /// Returns the interface Maximum Transmission Unit (MTU)
309 ///
310 /// The value returned by this function will never exceed 1514 bytes. The actual value depends
311 /// on the memory assigned to the transmission buffer when initializing the device
312 pub fn mtu(&self) -> u16 {
313 cmp::min(BUF_SZ - RXND - 1, MAX_FRAME_LENGTH - CRC_SZ)
314 }
315
316 /* Miscellaneous */
317 /// Returns the number of packets that have been received but have not been processed yet
318 pub fn pending_packets(&mut self) -> u8 {
319 self.read_control_register(bank1::Register::EPKTCNT)
320 }
321
322 /// Adjusts the receive filter to *accept* these packet types
323 pub fn accept(&mut self, packets: &[Packet]) {
324 let mask = bank1::ERXFCON::mask();
325 let mut val = 0;
326 for packet in packets {
327 match packet {
328 Packet::Broadcast => val |= mask.bcen(),
329 Packet::Multicast => val |= mask.mcen(),
330 Packet::Unicast => val |= mask.ucen(),
331 }
332 }
333
334 self.bit_field_set(bank1::Register::ERXFCON, val)
335 }
336
337 /// Adjusts the receive filter to *ignore* these packet types
338 pub fn ignore(&mut self, packets: &[Packet]) {
339 let mask = bank1::ERXFCON::mask();
340 let mut val = 0;
341 for packet in packets {
342 match packet {
343 Packet::Broadcast => val |= mask.bcen(),
344 Packet::Multicast => val |= mask.mcen(),
345 Packet::Unicast => val |= mask.ucen(),
346 }
347 }
348
349 self.bit_field_clear(bank1::Register::ERXFCON, val)
350 }
351
352 /* Private */
353 /* Read */
354 fn read_control_register<R>(&mut self, register: R) -> u8
355 where
356 R: Into<Register>,
357 {
358 self._read_control_register(register.into())
359 }
360
361 fn _read_control_register(&mut self, register: Register) -> u8 {
362 self.change_bank(register);
363
364 let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0];
365 self.spi.transfer_in_place(&mut buffer).unwrap();
366
367 buffer[1]
368 }
369
370 fn read_phy_register(&mut self, register: phy::Register) -> u16 {
371 embassy_time::block_for(Duration::from_millis(1));
372
373 // set PHY register address
374 self.write_control_register(bank2::Register::MIREGADR, register.addr());
375
376 // start read operation
377 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(1).bits());
378
379 // wait until the read operation finishes
380 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
381
382 let h = self.read_control_register(bank2::Register::MIRDH);
383 let l = self.read_control_register(bank2::Register::MIRDL);
384
385 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(0).bits());
386
387 (l as u16) | (h as u16) << 8
388 }
389
390 /* Write */
391 fn _write_control_register(&mut self, register: Register, value: u8) {
392 self.change_bank(register);
393
394 let buffer = [Instruction::WCR.opcode() | register.addr(), value];
395 self.spi.write(&buffer).unwrap();
396 }
397
398 fn write_control_register<R>(&mut self, register: R, value: u8)
399 where
400 R: Into<Register>,
401 {
402 self._write_control_register(register.into(), value)
403 }
404
405 fn write_phy_register(&mut self, register: phy::Register, value: u16) {
406 // set PHY register address
407 self.write_control_register(bank2::Register::MIREGADR, register.addr());
408
409 self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8);
410 // this starts the write operation
411 self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8);
412
413 // wait until the write operation finishes
414 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
415 }
416
417 /* RMW */
418 fn modify_control_register<R, F>(&mut self, register: R, f: F)
419 where
420 F: FnOnce(u8) -> u8,
421 R: Into<Register>,
422 {
423 self._modify_control_register(register.into(), f)
424 }
425
426 fn _modify_control_register<F>(&mut self, register: Register, f: F)
427 where
428 F: FnOnce(u8) -> u8,
429 {
430 let r = self._read_control_register(register);
431 self._write_control_register(register, f(r))
432 }
433
434 /* Auxiliary */
435 fn change_bank(&mut self, register: Register) {
436 let bank = register.bank();
437
438 if let Some(bank) = bank {
439 if self.bank == bank {
440 // already on the register bank
441 return;
442 }
443
444 // change bank
445 self.bank = bank;
446 match bank {
447 Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11),
448 Bank::Bank1 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01),
449 Bank::Bank2 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10),
450 Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11),
451 }
452 } else {
453 // common register
454 }
455 }
456
457 /* Primitive operations */
458 fn bit_field_clear<R>(&mut self, register: R, mask: u8)
459 where
460 R: Into<Register>,
461 {
462 self._bit_field_clear(register.into(), mask)
463 }
464
465 fn _bit_field_clear(&mut self, register: Register, mask: u8) {
466 debug_assert!(register.is_eth_register());
467
468 self.change_bank(register);
469
470 self.spi
471 .write(&[Instruction::BFC.opcode() | register.addr(), mask])
472 .unwrap();
473 }
474
475 fn bit_field_set<R>(&mut self, register: R, mask: u8)
476 where
477 R: Into<Register>,
478 {
479 self._bit_field_set(register.into(), mask)
480 }
481
482 fn _bit_field_set(&mut self, register: Register, mask: u8) {
483 debug_assert!(register.is_eth_register());
484
485 self.change_bank(register);
486
487 self.spi
488 .write(&[Instruction::BFS.opcode() | register.addr(), mask])
489 .unwrap();
490 }
491
492 fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) {
493 if let Some(addr) = addr {
494 self.write_control_register(bank0::Register::ERDPTL, addr.low());
495 self.write_control_register(bank0::Register::ERDPTH, addr.high());
496 }
497
498 self.spi
499 .transaction(&mut [Operation::Write(&[Instruction::RBM.opcode()]), Operation::Read(buf)])
500 .unwrap();
501 }
502
503 fn soft_reset(&mut self) {
504 self.spi.write(&[Instruction::SRC.opcode()]).unwrap();
505 }
506
507 fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) {
508 if let Some(addr) = addr {
509 self.write_control_register(bank0::Register::EWRPTL, addr.low());
510 self.write_control_register(bank0::Register::EWRPTH, addr.high());
511 }
512
513 self.spi
514 .transaction(&mut [Operation::Write(&[Instruction::WBM.opcode()]), Operation::Write(buffer)])
515 .unwrap();
516 }
517}
518
519#[derive(Clone, Copy, PartialEq)]
520enum Bank {
521 Bank0,
522 Bank1,
523 Bank2,
524 Bank3,
525}
526
527#[derive(Clone, Copy)]
528enum Instruction {
529 /// Read Control Register
530 RCR = 0b000_00000,
531 /// Read Buffer Memory
532 RBM = 0b001_11010,
533 /// Write Control Register
534 WCR = 0b010_00000,
535 /// Write Buffer Memory
536 WBM = 0b011_11010,
537 /// Bit Field Set
538 BFS = 0b100_00000,
539 /// Bit Field Clear
540 BFC = 0b101_00000,
541 /// System Reset Command
542 SRC = 0b111_11111,
543}
544
545impl Instruction {
546 fn opcode(&self) -> u8 {
547 *self as u8
548 }
549}
550
551#[derive(Clone, Copy)]
552enum Register {
553 Bank0(bank0::Register),
554 Bank1(bank1::Register),
555 Bank2(bank2::Register),
556 Bank3(bank3::Register),
557 Common(common::Register),
558}
559
560impl Register {
561 fn addr(&self) -> u8 {
562 match *self {
563 Register::Bank0(r) => r.addr(),
564 Register::Bank1(r) => r.addr(),
565 Register::Bank2(r) => r.addr(),
566 Register::Bank3(r) => r.addr(),
567 Register::Common(r) => r.addr(),
568 }
569 }
570
571 fn bank(&self) -> Option<Bank> {
572 Some(match *self {
573 Register::Bank0(_) => Bank::Bank0,
574 Register::Bank1(_) => Bank::Bank1,
575 Register::Bank2(_) => Bank::Bank2,
576 Register::Bank3(_) => Bank::Bank3,
577 Register::Common(_) => return None,
578 })
579 }
580
581 fn is_eth_register(&self) -> bool {
582 match *self {
583 Register::Bank0(r) => r.is_eth_register(),
584 Register::Bank1(r) => r.is_eth_register(),
585 Register::Bank2(r) => r.is_eth_register(),
586 Register::Bank3(r) => r.is_eth_register(),
587 Register::Common(r) => r.is_eth_register(),
588 }
589 }
590}
591
592/// Packet type, used to configure receive filters
593#[non_exhaustive]
594#[derive(Clone, Copy, Eq, PartialEq)]
595pub enum Packet {
596 /// Broadcast packets
597 Broadcast,
598 /// Multicast packets
599 Multicast,
600 /// Unicast packets
601 Unicast,
602}
603
604static mut TX_BUF: [u8; MTU] = [0; MTU];
605static mut RX_BUF: [u8; MTU] = [0; MTU];
606
607impl<S, O> embassy_net_driver::Driver for Enc28j60<S, O>
608where
609 S: SpiDevice,
610 O: OutputPin,
611{
612 type RxToken<'a> = RxToken<'a>
613 where
614 Self: 'a;
615
616 type TxToken<'a> = TxToken<'a, S, O>
617 where
618 Self: 'a;
619
620 fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
621 let rx_buf = unsafe { &mut RX_BUF };
622 let tx_buf = unsafe { &mut TX_BUF };
623 if let Some(pkt) = self.receive(rx_buf) {
624 let n = pkt.len();
625 Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
626 } else {
627 cx.waker().wake_by_ref();
628 None
629 }
630 }
631
632 fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
633 let tx_buf = unsafe { &mut TX_BUF };
634 Some(TxToken { buf: tx_buf, eth: self })
635 }
636
637 fn link_state(&mut self, cx: &mut core::task::Context) -> LinkState {
638 cx.waker().wake_by_ref();
639 match self.is_link_up() {
640 true => LinkState::Up,
641 false => LinkState::Down,
642 }
643 }
644
645 fn capabilities(&self) -> Capabilities {
646 let mut caps = Capabilities::default();
647 caps.max_transmission_unit = MTU;
648 caps.medium = Medium::Ethernet;
649 caps
650 }
651
652 fn hardware_address(&self) -> HardwareAddress {
653 HardwareAddress::Ethernet(self.mac_addr)
654 }
655}
656
657pub struct RxToken<'a> {
658 buf: &'a mut [u8],
659}
660
661impl<'a> embassy_net_driver::RxToken for RxToken<'a> {
662 fn consume<R, F>(self, f: F) -> R
663 where
664 F: FnOnce(&mut [u8]) -> R,
665 {
666 f(self.buf)
667 }
668}
669
670pub struct TxToken<'a, S, O>
671where
672 S: SpiDevice,
673 O: OutputPin,
674{
675 eth: &'a mut Enc28j60<S, O>,
676 buf: &'a mut [u8],
677}
678
679impl<'a, S, O> embassy_net_driver::TxToken for TxToken<'a, S, O>
680where
681 S: SpiDevice,
682 O: OutputPin,
683{
684 fn consume<R, F>(self, len: usize, f: F) -> R
685 where
686 F: FnOnce(&mut [u8]) -> R,
687 {
688 assert!(len <= self.buf.len());
689 let r = f(&mut self.buf[..len]);
690 self.eth.transmit(&self.buf[..len]);
691 r
692 }
693}
diff --git a/embassy-net-enc28j60/src/macros.rs b/embassy-net-enc28j60/src/macros.rs
new file mode 100644
index 000000000..8d0649572
--- /dev/null
+++ b/embassy-net-enc28j60/src/macros.rs
@@ -0,0 +1,89 @@
1macro_rules! register {
2 ($REGISTER:ident, $reset_value:expr, $uxx:ty, {
3 $(#[$($attr:tt)*] $bitfield:ident @ $range:expr,)+
4 }) => {
5 #[derive(Clone, Copy)]
6 pub(crate) struct $REGISTER<MODE> {
7 bits: $uxx,
8 _mode: ::core::marker::PhantomData<MODE>,
9 }
10
11 impl $REGISTER<super::traits::Mask> {
12 #[allow(dead_code)]
13 pub(crate) fn mask() -> $REGISTER<super::traits::Mask> {
14 $REGISTER { bits: 0, _mode: ::core::marker::PhantomData }
15 }
16
17 $(
18 #[allow(dead_code)]
19 pub(crate) fn $bitfield(&self) -> $uxx {
20 use super::traits::OffsetSize;
21
22 let size = $range.size();
23 let offset = $range.offset();
24 ((1 << size) - 1) << offset
25 }
26 )+
27 }
28
29 impl ::core::default::Default for $REGISTER<super::traits::W> {
30 fn default() -> Self {
31 $REGISTER { bits: $reset_value, _mode: ::core::marker::PhantomData }
32 }
33 }
34
35 #[allow(non_snake_case)]
36 #[allow(dead_code)]
37 pub(crate) fn $REGISTER(bits: $uxx) -> $REGISTER<super::traits::R> {
38 $REGISTER { bits, _mode: ::core::marker::PhantomData }
39 }
40
41 impl $REGISTER<super::traits::R> {
42 #[allow(dead_code)]
43 pub(crate) fn modify(self) -> $REGISTER<super::traits::W> {
44 $REGISTER { bits: self.bits, _mode: ::core::marker::PhantomData }
45 }
46
47 $(
48 #[$($attr)*]
49 #[allow(dead_code)]
50 pub(crate) fn $bitfield(&self) -> $uxx {
51 use super::traits::OffsetSize;
52
53 let offset = $range.offset();
54 let size = $range.size();
55 let mask = (1 << size) - 1;
56
57 (self.bits >> offset) & mask
58 }
59 )+
60 }
61
62 impl $REGISTER<super::traits::W> {
63 #[allow(dead_code)]
64 pub(crate) fn bits(self) -> $uxx {
65 self.bits
66 }
67
68 $(
69 #[$($attr)*]
70 #[allow(dead_code)]
71 pub(crate) fn $bitfield(&mut self, mut bits: $uxx) -> &mut Self {
72 use super::traits::OffsetSize;
73
74 let offset = $range.offset();
75 let size = $range.size();
76 let mask = (1 << size) - 1;
77
78 debug_assert!(bits <= mask);
79 bits &= mask;
80
81 self.bits &= !(mask << offset);
82 self.bits |= bits << offset;
83
84 self
85 }
86 )+
87 }
88 }
89}
diff --git a/embassy-net-enc28j60/src/phy.rs b/embassy-net-enc28j60/src/phy.rs
new file mode 100644
index 000000000..7f62b5f27
--- /dev/null
+++ b/embassy-net-enc28j60/src/phy.rs
@@ -0,0 +1,36 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 PHCON1 = 0x00,
5 PHSTAT1 = 0x01,
6 PHID1 = 0x02,
7 PHID2 = 0x03,
8 PHCON2 = 0x10,
9 PHSTAT2 = 0x11,
10 PHIE = 0x12,
11 PHIR = 0x13,
12 PHLCON = 0x14,
13}
14
15impl Register {
16 pub(crate) fn addr(&self) -> u8 {
17 *self as u8
18 }
19}
20
21register!(PHCON2, 0, u16, {
22 #[doc = "PHY Half-Duplex Loopback Disable bit"]
23 hdldis @ 8,
24 #[doc = "Jabber Correction Disable bit"]
25 jabber @ 10,
26 #[doc = "Twisted-Pair Transmitter Disable bit"]
27 txdis @ 13,
28 #[doc = "PHY Force Linkup bit"]
29 frclnk @ 14,
30});
31
32register!(PHSTAT2, 0, u16, {
33 // Datasheet says it's bit 10, but it's actually bit 2 ?!?!
34 #[doc = "Link Status bit"]
35 lstat @ 2,
36});
diff --git a/embassy-net-enc28j60/src/traits.rs b/embassy-net-enc28j60/src/traits.rs
new file mode 100644
index 000000000..08f94045a
--- /dev/null
+++ b/embassy-net-enc28j60/src/traits.rs
@@ -0,0 +1,57 @@
1use core::ops::Range;
2
3pub(crate) trait OffsetSize {
4 fn offset(self) -> u8;
5 fn size(self) -> u8;
6}
7
8impl OffsetSize for u8 {
9 fn offset(self) -> u8 {
10 self
11 }
12
13 fn size(self) -> u8 {
14 1
15 }
16}
17
18impl OffsetSize for Range<u8> {
19 fn offset(self) -> u8 {
20 self.start
21 }
22
23 fn size(self) -> u8 {
24 self.end - self.start
25 }
26}
27
28pub(crate) trait U16Ext {
29 fn from_parts(low: u8, high: u8) -> Self;
30
31 fn low(self) -> u8;
32
33 fn high(self) -> u8;
34}
35
36impl U16Ext for u16 {
37 fn from_parts(low: u8, high: u8) -> u16 {
38 ((high as u16) << 8) + low as u16
39 }
40
41 fn low(self) -> u8 {
42 (self & 0xff) as u8
43 }
44
45 fn high(self) -> u8 {
46 (self >> 8) as u8
47 }
48}
49
50#[derive(Clone, Copy)]
51pub struct Mask;
52
53#[derive(Clone, Copy)]
54pub struct R;
55
56#[derive(Clone, Copy)]
57pub struct W;