w5500/
register.rs

1#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]
2
3// TODO change from u8 to a custom struct implementing a trait.
4pub const COMMON: u8 = 0;
5pub mod common {
6    use bit_field::BitArray;
7
8    pub const MODE: u16 = 0x0;
9
10    /// Register: GAR (Gateway IP Address Register) [R/W] [0x0001 – 0x0004] [0x00]
11    pub const GATEWAY: u16 = 0x01;
12
13    /// Register: SUBR (Subnet Mask Register) [R/W] [0x0005 – 0x0008] [0x00]
14    pub const SUBNET_MASK: u16 = 0x05;
15
16    /// Register: SHAR (Source Hardware Address Register) [R/W] [0x0009 – 0x000E] [0x00]
17    pub const MAC: u16 = 0x09;
18
19    /// Register: SIPR (Source IP Address Register) [R/W] [0x000F – 0x0012] [0x00]
20    pub const IP: u16 = 0x0F;
21
22    /// Register: INTLEVEL (Interrupt Low Level Timer Register) [R/W] [0x0013 – 0x0014] [0x0000]
23    pub const INTERRUPT_TIMER: u16 = 0x13;
24
25    /// Register: SIMR (Socket Interrupt Mask Register) [R/W] [0x0018] [0x00]
26    pub const SOCKET_INTERRUPT_MASK: u16 = 0x18;
27
28    /// Register: RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
29    pub const RETRY_TIME: u16 = 0x19;
30
31    /// Register: RCR (Retry Count Register) [R/W] [0x001B] [0x08]
32    pub const RETRY_COUNT: u16 = 0x1B;
33
34    pub const PHY_CONFIG: u16 = 0x2E;
35    pub const VERSION: u16 = 0x39;
36
37    /// A Retry Time-value
38    ///
39    /// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
40    ///
41    /// From datasheet:
42    ///
43    /// RTR configures the retransmission timeout period. The unit of timeout period is
44    /// 100us and the default of RTR is ‘0x07D0’ or ‘2000’. And so the default timeout period
45    /// is 200ms(100us X 2000).
46    /// During the time configured by RTR, W5500 waits for the peer response to the packet
47    /// that is transmitted by Sn_CR(CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP
48    /// command). If the peer does not respond within the RTR time, W5500 retransmits the
49    /// packet or issues timeout.
50    ///
51    ///
52    /// > Ex) When timeout-period is set as 400ms, RTR = (400ms / 1ms) X 10 = 4000(0x0FA0)
53    #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
54    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
55    pub struct RetryTime(pub(crate) u16);
56
57    impl RetryTime {
58        #[inline]
59        pub fn to_u16(&self) -> u16 {
60            self.0
61        }
62
63        #[inline]
64        pub fn to_register(&self) -> [u8; 2] {
65            self.0.to_be_bytes()
66        }
67
68        #[inline]
69        pub fn from_register(register: [u8; 2]) -> Self {
70            Self(u16::from_be_bytes(register))
71        }
72
73        #[inline]
74        pub fn from_millis(milliseconds: u16) -> Self {
75            Self(milliseconds * 10)
76        }
77
78        #[inline]
79        pub fn to_millis(&self) -> u16 {
80            self.0 / 10
81        }
82    }
83
84    impl Default for RetryTime {
85        fn default() -> Self {
86            Self::from_millis(200)
87        }
88    }
89
90    #[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
91    #[repr(u8)]
92    pub enum PhyOperationMode {
93        /// 10BT half-duplex. Auto-negotiation disabled.
94        HalfDuplex10bt = 0b000_000,
95        /// 10BT full-duplex. Auto-negotiation disabled.
96        FullDuplex10bt = 0b001_000,
97        /// 100BT half-duplex. Auto-negotiation disabled.
98        HalfDuplex100bt = 0b010_000,
99        /// 100BT full-duplex. Auto-negotiation disabled.
100        FullDuplex100bt = 0b011_000,
101        /// 100BT half-duplex. Auto-negotiation enabled.
102        HalfDuplex100btAuto = 0b100_000,
103        /// Power down mode.
104        PowerDown = 0b110_000,
105        /// All capable. Auto-negotiation enabled.
106        #[default]
107        Auto = 0b111_000,
108    }
109
110    impl From<PhyOperationMode> for u8 {
111        fn from(val: PhyOperationMode) -> u8 {
112            val as u8
113        }
114    }
115
116    #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
117    #[repr(u8)]
118    pub enum PhySpeedStatus {
119        /// 10Mbps based.
120        Mbps10 = 0,
121        /// 100Mbps based.
122        Mbps100 = 1,
123    }
124
125    #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
126    #[repr(u8)]
127    pub enum PhyDuplexStatus {
128        /// Half duplex.
129        HalfDuplex = 0,
130        /// Full duplex.
131        FullDuplex = 1,
132    }
133
134    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
135    pub struct PhyConfig([u8; 1]);
136
137    impl PhyConfig {
138        // Link status bit position.
139        const LNK_POS: usize = 0;
140        // Speed status bit position.
141        const SPD_POS: usize = 1;
142        // Duplex status bit position.
143        const DPX_POS: usize = 2;
144        // Operation mode bit position.
145        // const OPMDC_POS = 3;
146        // Configure PHY opeartion mode bit position.
147        // const OPMD_POS = 6;
148        // Reset bit position.
149        // const RST_POS = 7;
150
151        /// PHY link status.
152        ///
153        /// `true` if the link is up, `false` if the link is down.
154        pub fn link_up(&self) -> bool {
155            self.0.get_bit(Self::LNK_POS)
156        }
157
158        /// PHY speed status.
159        pub fn speed(&self) -> PhySpeedStatus {
160            if !self.0.get_bit(Self::SPD_POS) {
161                PhySpeedStatus::Mbps10
162            } else {
163                PhySpeedStatus::Mbps100
164            }
165        }
166
167        /// PHY duplex status.
168        pub fn duplex(&self) -> PhyDuplexStatus {
169            if !self.0.get_bit(Self::DPX_POS) {
170                PhyDuplexStatus::HalfDuplex
171            } else {
172                PhyDuplexStatus::FullDuplex
173            }
174        }
175
176        /// PHY operation mode.
177        pub fn operation_mode(&self) -> PhyOperationMode {
178            match self.0[0] & 0b111_000u8 {
179                0b000_000 => PhyOperationMode::HalfDuplex10bt,
180                0b001_000 => PhyOperationMode::FullDuplex10bt,
181                0b010_000 => PhyOperationMode::HalfDuplex100bt,
182                0b011_000 => PhyOperationMode::FullDuplex100bt,
183                0b100_000 => PhyOperationMode::HalfDuplex100btAuto,
184                0b110_000 => PhyOperationMode::PowerDown,
185                0b111_000 => PhyOperationMode::Auto,
186                _ => unreachable!(),
187            }
188        }
189    }
190
191    impl core::convert::From<u8> for PhyConfig {
192        fn from(val: u8) -> Self {
193            PhyConfig([val])
194        }
195    }
196}
197
198pub const SOCKET0: u8 = 0b000_00001;
199pub const SOCKET0_BUFFER_TX: u8 = 0b000_00010;
200pub const SOCKET0_BUFFER_RX: u8 = 0b000_00011;
201
202pub const SOCKET1: u8 = 0b000_00101;
203pub const SOCKET1_BUFFER_TX: u8 = 0b000_00110;
204pub const SOCKET1_BUFFER_RX: u8 = 0b000_00111;
205
206pub const SOCKET2: u8 = 0b000_01001;
207pub const SOCKET2_BUFFER_TX: u8 = 0b000_01010;
208pub const SOCKET2_BUFFER_RX: u8 = 0b000_01011;
209
210pub const SOCKET3: u8 = 0b000_01101;
211pub const SOCKET3_BUFFER_TX: u8 = 0b000_01110;
212pub const SOCKET3_BUFFER_RX: u8 = 0b000_01111;
213
214pub const SOCKET4: u8 = 0b000_10001;
215pub const SOCKET4_BUFFER_TX: u8 = 0b000_10010;
216pub const SOCKET4_BUFFER_RX: u8 = 0b000_10011;
217
218pub const SOCKET5: u8 = 0b000_10101;
219pub const SOCKET5_BUFFER_TX: u8 = 0b000_10110;
220pub const SOCKET5_BUFFER_RX: u8 = 0b000_10111;
221
222pub const SOCKET6: u8 = 0b000_11001;
223pub const SOCKET6_BUFFER_TX: u8 = 0b000_11010;
224pub const SOCKET6_BUFFER_RX: u8 = 0b000_11011;
225
226pub const SOCKET7: u8 = 0b000_11101;
227pub const SOCKET7_BUFFER_TX: u8 = 0b000_11110;
228pub const SOCKET7_BUFFER_RX: u8 = 0b000_11111;
229
230pub mod socketn {
231    use derive_try_from_primitive::TryFromPrimitive;
232
233    /// The Protocol mode
234    pub const MODE: u16 = 0x00;
235
236    /// The protocol modes that can be used with the `w5500`
237    #[repr(u8)]
238    pub enum Protocol {
239        Closed = 0b00,
240        Tcp = 0b01,
241        Udp = 0b10,
242        MacRaw = 0b100,
243    }
244
245    /// Socket n Command Register
246    ///
247    /// `Sn_CR`
248    pub const COMMAND: u16 = 0x01;
249
250    /// Socket n Commands
251    ///
252    /// `Sn_CR` register
253    #[repr(u8)]
254    pub enum Command {
255        Open = 0x01,
256        /// [Datasheet page 46](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
257        ///
258        /// > This is valid only in TCP mode (Sn_MR(P3:P0) = Sn_MR_TCP). In this
259        /// > mode, Socket n operates as a ‘TCP server’ and waits for connection-
260        /// > request (SYN packet) from any ‘TCP client
261        Listen = 0x02,
262        Connect = 0x04,
263        Discon = 0x08,
264        Close = 0x10,
265        Send = 0x20,
266
267        /// [Datasheet page 48](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
268        ///
269        /// > RECV completes the processing of the received data in Socket n RX
270        /// > Buffer by using a RX read pointer register (Sn_RX_RD).
271        /// > For more details, refer to Socket n RX Received Size Register
272        /// > (Sn_RX_RSR), Socket n RX Write Pointer Register (Sn_RX_WR), and
273        /// > Socket n RX Read Pointer Register (Sn_RX_RD).
274        Receive = 0x40,
275    }
276
277    pub const INTERRUPT: u16 = 0x02;
278    /// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
279    /// | Reserved | Reserved | Reserved | SEND_OK | TIMEOUT | RECV | DISCON | CON |
280    ///
281    /// | Bit | Symbol | Description |
282    /// | 7~5 | Reserved | Reserved |
283    /// | 4 | SENDOK | Sn_IR(SENDOK) | Interrupt Mask |
284    /// | 3 | TIMEOUT | Sn_IR(TIMEOUT) | Interrupt Mask |
285    /// | 2 | RECV | Sn_IR(RECV) | Interrupt Mask |
286    /// | 1 | DISCON | Sn_IR(DISCON) | Interrupt Mask |
287    /// | 0 | CON | Sn_IR(CON) | Interrupt Mask |
288    #[repr(u8)]
289    pub enum Interrupt {
290        All = 0b11111111u8,
291        SendOk = 0b10000u8,
292        Timeout = 0b1000u8,
293
294        /// Receive data
295        ///
296        /// bit 2, symbol `RECV`, `Sn_IR(RECV) Interrupt Mask`
297        Receive = 0b100u8,
298
299        /// Disconnect
300        ///
301        /// bit 1, symbol `DISCON`, `Sn_IR(DISCON) Interrupt Mask`
302        Disconnect = 0b10u8,
303
304        /// Connect
305        ///
306        /// bit 0, symbol `CON`, `Sn_IR(CON) Interrupt Mask`
307        Connect = 0b1u8,
308    }
309
310    pub const STATUS: u16 = 0x03;
311
312    /// Socket status register
313    ///
314    /// `W5500 Datasheet Version 1.1.0` page 49:
315    ///
316    /// > Sn_SR (Socket n Status Register) [R] [0x0003] [0x00]
317    ///
318    /// - 0x18 SOCK_FIN_WAIT
319    /// - 0x1A SOCK_CLOSING
320    /// - 0X1B SOCK_TIME_WAIT
321    /// > These indicate Socket n is closing.
322    /// > These are shown in disconnect-process such as active-close
323    /// > and passive-close.
324    /// > When Disconnect-process is successfully completed, or
325    /// > when timeout occurs, these change to SOCK_CLOSED.
326    ///
327    #[derive(TryFromPrimitive, Debug, Copy, Clone, PartialEq, Eq)]
328    #[repr(u8)]
329    pub enum Status {
330        Closed = 0x00,
331        Init = 0x13,
332
333        /// [Datasheet page 49](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
334        ///
335        /// > This indicates Socket n is operating as ‘TCP server’ mode and
336        /// > waiting for connection-request (SYN packet) from a peer
337        /// > (‘TCP client’).
338        Listen = 0x14,
339        Established = 0x17,
340        CloseWait = 0x1c,
341        Udp = 0x22,
342        MacRaw = 0x42,
343
344        // Transient states.
345        SynSent = 0x15,
346        SynRecv = 0x16,
347        FinWait = 0x18,
348        Closing = 0x1a,
349        TimeWait = 0x1b,
350        LastAck = 0x1d,
351    }
352
353    #[cfg(feature = "defmt")]
354    impl defmt::Format for Status {
355        fn format(&self, fmt: defmt::Formatter) {
356            // Format as hexadecimal.
357            defmt::write!(
358                fmt,
359                "Status::{} ({=u8:#x})",
360                defmt::Debug2Format(self),
361                *self as u8
362            );
363        }
364    }
365
366    pub const SOURCE_PORT: u16 = 0x04;
367
368    pub const DESTINATION_IP: u16 = 0x0C;
369
370    pub const DESTINATION_PORT: u16 = 0x10;
371
372    pub const RXBUF_SIZE: u16 = 0x1E;
373
374    /// Socket n TX Buffer Size Register
375    ///
376    /// `Sn_TXBUF_SIZE`
377    ///
378    /// From datasheet:
379    ///
380    /// > .. can be configured with 1,2,4,8, and 16 Kbytes.
381    /// >
382    /// > Although Socket n TX Buffer Block size is initially configured to 2Kbytes, user can
383    /// > be re-configure its size using Sn_TXBUF_SIZE. The total sum of Sn_TXBUF_SIZE
384    /// > cannot be exceed 16Kbytes. When exceeded, the data transmission error is
385    /// > occurred.
386    pub const TXBUF_SIZE: u16 = 0x1F;
387
388    /// TX Free Size Register
389    ///
390    /// `Sn_TX_FSR`
391    ///
392    /// Socket n TX Free Size
393    ///
394    /// offset (register)
395    /// 0x0020 (Sn_TX_FSR0)
396    /// 0x0021 (Sn_TX_FSR1)
397    pub const TX_FREE_SIZE: u16 = 0x20;
398
399    /// Socket n TX Read Pointer
400    ///
401    /// offset (register)
402    /// 0x0022 (Sn_TX_RD0)
403    /// 0x0023 (Sn_TX_RD1)
404    pub const TX_DATA_READ_POINTER: u16 = 0x22;
405
406    /// Socket n TX Write Pointer
407    ///
408    /// offset (register)
409    /// 0x0024 (Sn_TX_WR0)
410    /// 0x0025 (Sn_TX_WR1)
411    ///
412    /// [Datasheet page 54](https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf):
413    ///
414    /// > Sn_TX_WR (Socket n TX Write Pointer Register) [R/W] [0x0024-0x0025] [0x0000]
415    /// >
416    /// > Sn_TX_WR is initialized by OPEN command. However, if Sn_MR(P[3:0]) is TCP
417    /// > mode(‘0001’), it is re-initialized while connecting with TCP.
418    /// > It should be read or to be updated like as follows.
419    /// > 1. Read the starting address for saving the transmitting data.
420    /// > 2. Save the transmitting data from the starting address of Socket n TX
421    /// >    buffer.
422    /// > 3. After saving the transmitting data, update Sn_TX_WR to the
423    /// >    increased value as many as transmitting data size. If the increment value
424    /// >    exceeds the maximum value 0xFFFF(greater than 0x10000 and the carry
425    /// >    bit occurs), then the carry bit is ignored and will automatically update
426    /// >    with the lower 16bits value.
427    /// > 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND
428    /// >    command
429    pub const TX_DATA_WRITE_POINTER: u16 = 0x24;
430
431    /// Socket n Received Size Register
432    ///
433    /// `Sn_RX_RSR`
434    pub const RECEIVED_SIZE: u16 = 0x26;
435
436    pub const RX_DATA_READ_POINTER: u16 = 0x28;
437
438    /// Socket n Interrupt Mask
439    ///
440    /// offset (register)
441    /// 0x002C (Sn_IMR)
442    pub const INTERRUPT_MASK: u16 = 0x2C;
443
444    #[cfg(test)]
445    mod tests {
446        use core::convert::TryFrom;
447
448        use super::Status;
449
450        #[test]
451        fn test_status_from_byte() {
452            let udp = 0x22_u8;
453            let status = Status::try_from(udp).expect("Should parse to Status");
454            assert_eq!(status, Status::Udp);
455        }
456    }
457}