Improved documentation in README and doc comments in library

This commit is contained in:
Jonah Dahlquist 2019-08-02 10:15:26 -05:00
commit b9aa4f9ca1
2 changed files with 119 additions and 35 deletions

View file

@ -1,47 +1,82 @@
# Example usage # W5500 Driver
Below some really basic usage how I am ca using it: This crate is a driver for the WIZnet W5500 chips. The W5500 chip is a hardwired TCP/IP embedded Ethernet controller
that enables easier internet connection for embedded systems using SPI (Serial Peripheral Interface). It is one of the
more popular platforms for Ethernet modules on Arduino platforms.
## Embedded-HAL
Embedded-HAL is a standard set of traits meant to permit communication between MCU implementations and hardware drivers
like this one. Any microcontroller that implements the
[`spi::FullDuplex<u8>`](https://docs.rs/embedded-hal/0.2.3/embedded_hal/spi/trait.FullDuplex.html) interface can use
this driver.
## Implementation
This driver is built in several layers of structs.
The lowest level (and the first a program would instantiate) is the `W5500` struct. It contains a reference to the
chip-select [pin](https://docs.rs/embedded-hal/0.2.3/embedded_hal/digital/v2/trait.OutputPin.html).
The next layer is the `ActiveW5500` struct. It contains a reference to a `W5500` instance, and an implementation of
the [`spi::FullDuplex<u8>`](https://docs.rs/embedded-hal/0.2.3/embedded_hal/spi/trait.FullDuplex.html) trait. It has
the ability to actually communicate with the chip. It has general methods for reading/writing to the chip, and
higher-level functions that can set up specific configuration, like the MAC address, etc.
The last layer is the network protocol. Currently that is only `Udp`. `Udp` is a tuple struct made up of an
`ActiveW5500` and a `Socket`. This last layer can be used to send and receive UDP packets over the network via the
`receive` and `blocking_send` methods.
# Example Usage
Below is a basic example of listening for UDP packets and replying. An important thing to confirm is the configuration
of the SPI implementation. It must be set up to work as the W5500 chip requires. That configuration is as follows:
* Data Order: Most significant bit first
* Clock Polarity: Idle low
* Clock Phase: Sample leading edge
* Clock speed: 33MHz maximum
```rust ```rust
let mut spi = ...; // SPI interface to use let mut spi = ...; // SPI interface to use
let mut cs_w5500 : OutputPin = ...; // chip select let mut cs_w5500 : OutputPin = ...; // chip select
let mut w5500: Option<W5500> = W5500::with_initialisation( let mut w5500 = W5500::with_initialisation(
&mut cs_w5500, // borrowed for whole W5500 lifetime &mut cs_w5500, // borrowed for whole W5500 lifetime
&mut spi, // borrowed for call to `with_initialisation` only &mut spi, // borrowed for call to `with_initialisation` only
OnWakeOnLan::Ignore, OnWakeOnLan::Ignore,
OnPingRequest::Respond, OnPingRequest::Respond,
ConnectionType::Ethernet, ConnectionType::Ethernet,
ArpResponses::Cache, ArpResponses::Cache,
) ).unwrap();
.ok();
if let Some(ref mut w5500) = w5500 { let mut active = w5500.activate(&mut spi).unwrap();
let mut w5500: ActiveW5500<_> = w5500.activate(&mut spi).unwrap(); // using a 'locally administered' MAC address
// using a 'locally administered' MAC address active.set_mac(MacAddress::new(0x02, 0x01, 0x02, 0x03, 0x04, 0x05)).unwrap();
active.set_mac(MacAddress::new(0x02, 0x01, 0x02, 0x03, 0x04, 0x05)).unwrap(); active.set_ip(IpAddress::new(192, 168, 0, 222)).unwrap();
active.set_ip(IpAddress::new(192, 168, 0, 222)).unwrap(); active.set_subnet(IpAddress::new(255, 255, 255, 0)).unwrap();
active.set_subnet(IpAddress::new(255, 255, 255, 0)).unwrap(); active.set_gateway(IpAddress::new(192, 168, 0, 1)).unwrap();
active.set_gateway(IpAddress::new(192, 168, 0, 1)).unwrap();
}
let mut udp_server_socket: Option<UdpSocket> = w5500.as_mut().and_then(|w5500| { let socket0: UninitializedSocket = w5500.take_socket(Socket::Socket0).unwrap();
let mut w5500: ActiveW5500<_> = w5500.activate(&mut spi).ok()?; let udp_server_socket = (&mut w5500, socket0).try_into_udp_server_socket(1234).unwrap();
let socket0: UninitializedSocket = w5500.take_socket(Socket::Socket0)?;
(&mut w5500, socket0).try_into_udp_server_socket(1234).ok()
});
let mut buffer = [0u8; 256]; let mut buffer = [0u8; 256];
if let (Some(ref mut w5500), Some(ref socket)) = ( let response = [104, 101, 108, 108, 111, 10];// "hello" as ASCII
w5500.as_mut().and_then(w5500.activate(&mut spi).ok()), loop {
udp_server_socket, if let Ok(Some((ip, port, len))) = udp_server_socket.receive(&mut buffer[..]) {
) { udp_server_socket.blocking_send(ip, port, response[..]).unwrap();
if let Ok(Some((ip, port, len))) = (w5500, socket).receive(&mut buffer[..]) {
let (request_buffer, response_buffer) = buffer.split_mut_at(len);
// ... fill the response_buffer with some data ...
(w5500, socket).blocking_send(ip, port, response_buffer[..response_len]).unwrap();
} }
} }
``` ```
## To To
In no particular order, things to do to improve this driver.
* Add support for TCP
* Add support for DHCP
* Method to return socket back to the pool
* Make reset safe by requiring that all sockets be returned to the pool first
* Support a 3-wire SPI bus
* Sane defaults for IP/Gateway/Subnet
* Improve documentation

View file

@ -21,12 +21,14 @@ const FIXED_DATA_LENGTH_1_BYTE: u8 = 0b_01;
const FIXED_DATA_LENGTH_2_BYTES: u8 = 0b_10; const FIXED_DATA_LENGTH_2_BYTES: u8 = 0b_10;
const FIXED_DATA_LENGTH_4_BYTES: u8 = 0b_11; const FIXED_DATA_LENGTH_4_BYTES: u8 = 0b_11;
/// IP Address struct. Represents an IP address as a u8 array of length 4. Can be instantiated with `IpAddress::new`
#[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)] #[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)]
pub struct IpAddress { pub struct IpAddress {
pub address: [u8; 4], pub address: [u8; 4],
} }
impl IpAddress { impl IpAddress {
/// Instantiate a new IP address with u8s for each address fragment
pub fn new(a0: u8, a1: u8, a2: u8, a3: u8) -> IpAddress { pub fn new(a0: u8, a1: u8, a2: u8, a3: u8) -> IpAddress {
IpAddress { IpAddress {
address: [a0, a1, a2, a3], address: [a0, a1, a2, a3],
@ -35,6 +37,7 @@ impl IpAddress {
} }
impl ::core::fmt::Display for IpAddress { impl ::core::fmt::Display for IpAddress {
/// String formatter for IP addresses, useful for debugging output
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!( write!(
f, f,
@ -44,12 +47,14 @@ impl ::core::fmt::Display for IpAddress {
} }
} }
/// MAC address struct. Represents a MAC address as a u8 array of length 6. Can be instantiated with `MacAddress::new`
#[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)] #[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)]
pub struct MacAddress { pub struct MacAddress {
pub address: [u8; 6], pub address: [u8; 6],
} }
impl MacAddress { impl MacAddress {
/// Instantiate a new MAC address with u8s for each address fragment
pub fn new(a0: u8, a1: u8, a2: u8, a3: u8, a4: u8, a5: u8) -> MacAddress { pub fn new(a0: u8, a1: u8, a2: u8, a3: u8, a4: u8, a5: u8) -> MacAddress {
MacAddress { MacAddress {
address: [a0, a1, a2, a3, a4, a5], address: [a0, a1, a2, a3, a4, a5],
@ -58,6 +63,7 @@ impl MacAddress {
} }
impl ::core::fmt::Display for MacAddress { impl ::core::fmt::Display for MacAddress {
/// String formatter for MAC addresses, useful for debugging output
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!( write!(
f, f,
@ -72,18 +78,22 @@ impl ::core::fmt::Display for MacAddress {
} }
} }
/// Error enum that represents the union between SPI hardware errors and digital IO pin errors. Returned as an Error
/// type by many W5500 that talk to the chip
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum TransferError<SpiError, ChipSelectError> { pub enum TransferError<SpiError, ChipSelectError> {
SpiError(SpiError), SpiError(SpiError),
ChipSelectError(ChipSelectError), ChipSelectError(ChipSelectError),
} }
/// Settings for wake on LAN. Allows the W5500 to optionally emit an interrupt upon receiving a packet
#[derive(Copy, Clone, PartialOrd, PartialEq)] #[derive(Copy, Clone, PartialOrd, PartialEq)]
pub enum OnWakeOnLan { pub enum OnWakeOnLan {
InvokeInterrupt, InvokeInterrupt,
Ignore, Ignore,
} }
/// Settings for ping. Allows the W5500 to respond to or ignore network ping requests
#[derive(Copy, Clone, PartialOrd, PartialEq)] #[derive(Copy, Clone, PartialOrd, PartialEq)]
pub enum OnPingRequest { pub enum OnPingRequest {
Respond, Respond,
@ -104,9 +114,14 @@ pub enum ArpResponses {
DropAfterUse, DropAfterUse,
} }
/// Represents a socket that has not yet been initialized for a particular protocol
pub struct UninitializedSocket(Socket); pub struct UninitializedSocket(Socket);
/// Represents a socket that has been initialized to use the UDP protocol
pub struct UdpSocket(Socket); pub struct UdpSocket(Socket);
/// The first level of instantiating communication with the W5500. It can not communicate by itself, but calling
/// `activate` will return an `ActiveW5500` which can.
pub struct W5500<'a, ChipSelect: OutputPin> { pub struct W5500<'a, ChipSelect: OutputPin> {
chip_select: &'a mut ChipSelect, chip_select: &'a mut ChipSelect,
sockets: u8, // each bit represents whether the corresponding socket is available for take sockets: u8, // each bit represents whether the corresponding socket is available for take
@ -122,6 +137,7 @@ impl<'b, 'a: 'b, ChipSelectError, ChipSelect: OutputPin<Error = ChipSelectError>
} }
} }
/// Primary method for instantiating. Briefly activates the W5500, and sets it up with the specified configuration
pub fn with_initialisation<'c, Spi: FullDuplex<u8>>( pub fn with_initialisation<'c, Spi: FullDuplex<u8>>(
chip_select: &'a mut ChipSelect, chip_select: &'a mut ChipSelect,
spi: &'c mut Spi, spi: &'c mut Spi,
@ -141,6 +157,7 @@ impl<'b, 'a: 'b, ChipSelectError, ChipSelect: OutputPin<Error = ChipSelectError>
Ok(w5500) Ok(w5500)
} }
/// Returns the requested socket if it is not already used.
pub fn take_socket(&mut self, socket: Socket) -> Option<UninitializedSocket> { pub fn take_socket(&mut self, socket: Socket) -> Option<UninitializedSocket> {
let mask = (0x01 << socket.number()); let mask = (0x01 << socket.number());
if self.sockets & mask == mask { if self.sockets & mask == mask {
@ -151,6 +168,7 @@ impl<'b, 'a: 'b, ChipSelectError, ChipSelect: OutputPin<Error = ChipSelectError>
} }
} }
/// Creates a new `ActiveW5500` with the provided `FullDuplex` implementation
pub fn activate<'c, Spi: FullDuplex<u8>>( pub fn activate<'c, Spi: FullDuplex<u8>>(
&'b mut self, &'b mut self,
spi: &'c mut Spi, spi: &'c mut Spi,
@ -160,6 +178,7 @@ impl<'b, 'a: 'b, ChipSelectError, ChipSelect: OutputPin<Error = ChipSelectError>
} }
} }
/// Struct that can communicate with the W5500 chip, configuring it and reading/writing to the registers on a low level
pub struct ActiveW5500<'a, 'b: 'a, 'c, ChipSelect: OutputPin, Spi: FullDuplex<u8>>( pub struct ActiveW5500<'a, 'b: 'a, 'c, ChipSelect: OutputPin, Spi: FullDuplex<u8>>(
&'a mut W5500<'b, ChipSelect>, &'a mut W5500<'b, ChipSelect>,
&'c mut Spi, &'c mut Spi,
@ -172,10 +191,12 @@ impl<
Spi: FullDuplex<u8, Error = SpiError>, Spi: FullDuplex<u8, Error = SpiError>,
> ActiveW5500<'_, '_, '_, ChipSelect, Spi> > ActiveW5500<'_, '_, '_, ChipSelect, Spi>
{ {
/// Returns the requested socket if it is not already used
pub fn take_socket(&mut self, socket: Socket) -> Option<UninitializedSocket> { pub fn take_socket(&mut self, socket: Socket) -> Option<UninitializedSocket> {
self.0.take_socket(socket) self.0.take_socket(socket)
} }
/// Set up basic configuration of the W5500 chip
pub fn update_operation_mode( pub fn update_operation_mode(
&mut self, &mut self,
wol: OnWakeOnLan, wol: OnWakeOnLan,
@ -204,6 +225,7 @@ impl<
self.write_to(Register::CommonRegister(0x00_00_u16), &[value]) self.write_to(Register::CommonRegister(0x00_00_u16), &[value])
} }
/// Sets the IP address of the network gateway (router)
pub fn set_gateway( pub fn set_gateway(
&mut self, &mut self,
gateway: IpAddress, gateway: IpAddress,
@ -211,6 +233,7 @@ impl<
self.write_to(Register::CommonRegister(0x00_01_u16), &gateway.address) self.write_to(Register::CommonRegister(0x00_01_u16), &gateway.address)
} }
/// Sets the subnet on the network
pub fn set_subnet( pub fn set_subnet(
&mut self, &mut self,
subnet: IpAddress, subnet: IpAddress,
@ -218,6 +241,7 @@ impl<
self.write_to(Register::CommonRegister(0x00_05_u16), &subnet.address) self.write_to(Register::CommonRegister(0x00_05_u16), &subnet.address)
} }
/// Sets the MAC address of the W5500 device on the network
pub fn set_mac( pub fn set_mac(
&mut self, &mut self,
mac: MacAddress, mac: MacAddress,
@ -225,6 +249,7 @@ impl<
self.write_to(Register::CommonRegister(0x00_09_u16), &mac.address) self.write_to(Register::CommonRegister(0x00_09_u16), &mac.address)
} }
/// Sets the IP address of the W5500 device on network. Must be within the range permitted by the gateway
pub fn set_ip( pub fn set_ip(
&mut self, &mut self,
ip: IpAddress, ip: IpAddress,
@ -232,6 +257,7 @@ impl<
self.write_to(Register::CommonRegister(0x00_0F_u16), &ip.address) self.write_to(Register::CommonRegister(0x00_0F_u16), &ip.address)
} }
/// Reads 4 bytesfrom any register location and returns the value as an IP address
pub fn read_ip( pub fn read_ip(
&mut self, &mut self,
register: Register, register: Register,
@ -255,6 +281,7 @@ impl<
Ok(()) Ok(())
} }
/// TODO document
fn is_interrupt_set( fn is_interrupt_set(
&mut self, &mut self,
socket: Socket, socket: Socket,
@ -265,6 +292,7 @@ impl<
Ok(state[0] & interrupt as u8 != 0) Ok(state[0] & interrupt as u8 != 0)
} }
/// TODO document
pub fn reset_interrupt( pub fn reset_interrupt(
&mut self, &mut self,
socket: Socket, socket: Socket,
@ -273,6 +301,7 @@ impl<
self.write_to(socket.at(SocketRegister::Interrupt), &[interrupt as u8]) self.write_to(socket.at(SocketRegister::Interrupt), &[interrupt as u8])
} }
/// Reads one byte from any register address as a u8
fn read_u8( fn read_u8(
&mut self, &mut self,
register: Register, register: Register,
@ -282,6 +311,7 @@ impl<
Ok(buffer[0]) Ok(buffer[0])
} }
/// Reads two bytes from any register address and returns as a u16
fn read_u16( fn read_u16(
&mut self, &mut self,
register: Register, register: Register,
@ -291,6 +321,7 @@ impl<
Ok(BigEndian::read_u16(&buffer)) Ok(BigEndian::read_u16(&buffer))
} }
/// Reads enough bytes from any register address to fill the `target` u8 slice
fn read_from( fn read_from(
&mut self, &mut self,
register: Register, register: Register,
@ -316,6 +347,7 @@ impl<
result.map_err(|error| TransferError::SpiError(error)) result.map_err(|error| TransferError::SpiError(error))
} }
/// Reads enough bytes over SPI to fill the `target` u8 slice
fn read_bytes(&mut self, bytes: &mut [u8]) -> Result<(), SpiError> { fn read_bytes(&mut self, bytes: &mut [u8]) -> Result<(), SpiError> {
for byte in bytes { for byte in bytes {
*byte = self.read()?; *byte = self.read()?;
@ -323,11 +355,13 @@ impl<
Ok(()) Ok(())
} }
/// Reads a single byte over SPI by writing a zero and reading the response
fn read(&mut self) -> Result<u8, SpiError> { fn read(&mut self) -> Result<u8, SpiError> {
block!(self.1.send(0x00))?; block!(self.1.send(0x00))?;
block!(self.1.read()) block!(self.1.read())
} }
/// Write a single u8 byte to any register address
fn write_u8( fn write_u8(
&mut self, &mut self,
register: Register, register: Register,
@ -336,6 +370,7 @@ impl<
self.write_to(register, &[value]) self.write_to(register, &[value])
} }
/// Write a u16 as two bytes o any register address
fn write_u16( fn write_u16(
&mut self, &mut self,
register: Register, register: Register,
@ -346,6 +381,7 @@ impl<
self.write_to(register, &data) self.write_to(register, &data)
} }
/// Write a slice of u8 bytes to any register address
fn write_to( fn write_to(
&mut self, &mut self,
register: Register, register: Register,
@ -371,6 +407,7 @@ impl<
result.map_err(|error| TransferError::SpiError(error)) result.map_err(|error| TransferError::SpiError(error))
} }
/// Write a slice of u8 bytes over SPI
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SpiError> { fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SpiError> {
for b in bytes { for b in bytes {
self.write(*b)?; self.write(*b)?;
@ -378,16 +415,19 @@ impl<
Ok(()) Ok(())
} }
/// Write a single byte over SPI
fn write(&mut self, byte: u8) -> Result<(), SpiError> { fn write(&mut self, byte: u8) -> Result<(), SpiError> {
block!(self.1.send(byte))?; block!(self.1.send(byte))?;
block!(self.1.read())?; block!(self.1.read())?;
Ok(()) Ok(())
} }
/// Begin a SPI frame by setting the CS signal to low
fn chip_select(&mut self) -> Result<(), ChipSelectError> { fn chip_select(&mut self) -> Result<(), ChipSelectError> {
self.0.chip_select.set_low() self.0.chip_select.set_low()
} }
/// End a SPI frame by setting the CS signal to high
fn chip_deselect(&mut self) -> Result<(), ChipSelectError> { fn chip_deselect(&mut self) -> Result<(), ChipSelectError> {
self.0.chip_select.set_high() self.0.chip_select.set_high()
} }
@ -405,6 +445,7 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> IntoUdpSocket<UninitializedSock
UninitializedSocket, UninitializedSocket,
) )
{ {
/// Initialize a socket to operate in UDP mode
fn try_into_udp_server_socket(self, port: u16) -> Result<UdpSocket, UninitializedSocket> { fn try_into_udp_server_socket(self, port: u16) -> Result<UdpSocket, UninitializedSocket> {
let socket = (self.1).0; let socket = (self.1).0;
(|| { (|| {
@ -425,6 +466,7 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> IntoUdpSocket<UninitializedSock
} }
} }
/// UDP trait that can send and receive UDP packets
pub trait Udp { pub trait Udp {
type Error; type Error;
@ -446,6 +488,7 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> Udp
{ {
type Error = TransferError<Spi::Error, ChipSelect::Error>; type Error = TransferError<Spi::Error, ChipSelect::Error>;
/// Returns a UDP packet if one is available. Will return `None` if no UDP packets are in the socket's buffer
fn receive( fn receive(
&mut self, &mut self,
destination: &mut [u8], destination: &mut [u8],
@ -481,9 +524,6 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> Udp
&mut destination[..data_length], &mut destination[..data_length],
)?; )?;
// self.read_from(socket.register_at(0x00_0C), &mut ip.address)?;
// self.read_u16(socket.register_at(0x00_10))?;
// reset // reset
w5500.write_u16( w5500.write_u16(
socket.at(SocketRegister::RxReadPointer), socket.at(SocketRegister::RxReadPointer),
@ -500,6 +540,7 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> Udp
} }
} }
/// Sends a UDP packet to the specified IP and port, and blocks until it is sent
fn blocking_send( fn blocking_send(
&mut self, &mut self,
host: &IpAddress, host: &IpAddress,
@ -564,10 +605,6 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> Udp
} }
} }
// restore listen state // restore listen state
/*
self.network
.listen_udp(self.spi, SOCKET_UDP, SOCKET_UDP_PORT)
*/
w5500.write_to( w5500.write_to(
socket.at(SocketRegister::Mode), socket.at(SocketRegister::Mode),
&[ &[
@ -579,6 +616,7 @@ impl<ChipSelect: OutputPin, Spi: FullDuplex<u8>> Udp
} }
} }
/// Offset addresses in each socket register
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum SocketRegister { pub enum SocketRegister {
@ -609,6 +647,7 @@ pub enum SocketRegister {
// Reserved 0x0030 - 0xFFFF // Reserved 0x0030 - 0xFFFF
} }
/// Interrupt state bits
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum Interrupt { pub enum Interrupt {
@ -619,6 +658,7 @@ pub enum Interrupt {
Connected = 1, // 1 << 0 Connected = 1, // 1 << 0
} }
/// Register protocol mode bits
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum Protocol { pub enum Protocol {
@ -627,6 +667,7 @@ pub enum Protocol {
MACRAW = 0b0100, MACRAW = 0b0100,
} }
/// Bits for socket commands
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum SocketCommand { pub enum SocketCommand {
@ -641,6 +682,7 @@ pub enum SocketCommand {
Recv = 0x40, Recv = 0x40,
} }
/// Identifiers for each socket on the W5500
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub enum Socket { pub enum Socket {
Socket0, Socket0,
@ -654,6 +696,7 @@ pub enum Socket {
} }
impl Socket { impl Socket {
/// Gets the number of any given socket
pub fn number(self) -> usize { pub fn number(self) -> usize {
match self { match self {
Socket::Socket0 => 0, Socket::Socket0 => 0,
@ -667,6 +710,7 @@ impl Socket {
} }
} }
/// Returns the register address for a socket instance's TX
fn tx_register_at(self, address: u16) -> Register { fn tx_register_at(self, address: u16) -> Register {
match self { match self {
Socket::Socket0 => Register::Socket0TxBuffer(address), Socket::Socket0 => Register::Socket0TxBuffer(address),
@ -680,6 +724,7 @@ impl Socket {
} }
} }
/// Returns the register address for a socket instance's RX
fn rx_register_at(self, address: u16) -> Register { fn rx_register_at(self, address: u16) -> Register {
match self { match self {
Socket::Socket0 => Register::Socket0RxBuffer(address), Socket::Socket0 => Register::Socket0RxBuffer(address),
@ -693,6 +738,7 @@ impl Socket {
} }
} }
/// Returns the register address for a socket instance's register
fn register_at(self, address: u16) -> Register { fn register_at(self, address: u16) -> Register {
match self { match self {
Socket::Socket0 => Register::Socket0Register(address), Socket::Socket0 => Register::Socket0Register(address),
@ -711,6 +757,7 @@ impl Socket {
} }
} }
/// Chip register names
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum Register { pub enum Register {
CommonRegister(u16), CommonRegister(u16),
@ -749,6 +796,7 @@ pub enum Register {
} }
impl Register { impl Register {
/// Gets the control bits to identify any given register
fn control_byte(self) -> u8 { fn control_byte(self) -> u8 {
#[allow(clippy::inconsistent_digit_grouping)] #[allow(clippy::inconsistent_digit_grouping)]
match self { match self {
@ -788,6 +836,7 @@ impl Register {
} }
} }
/// Returns the associated address as a u16
fn address(self) -> u16 { fn address(self) -> u16 {
match self { match self {
Register::CommonRegister(address) => address, Register::CommonRegister(address) => address,