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}