Skip to content

Commit

Permalink
Merge pull request #54 from LechevSpace/feat/retry-time-and-count
Browse files Browse the repository at this point in the history
Feat: Retry time and count
  • Loading branch information
ryan-summers authored Jul 25, 2023
2 parents 3da66e6 + 545debf commit 42791c2
Show file tree
Hide file tree
Showing 5 changed files with 430 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add `defmt` features for enabling `defmt::Format` to most structs and errors by [@elpiel](https://github.com/elpiel) ([#39](https://github.com/kellerkindt/w5500/issues/39))
- Fixed an issue where internal function names were conflicting with trait names by [@ryan-summers](https://github.com/ryan-summers) ([#36](https://github.com/kellerkindt/w5500/issues/36))
- Add `RetryTime` and `RetryCount` common register methods to `Device` and `UninitializedDevice` by [@elpiel](https://github.com/elpiel) ([#54][PR54])

### Fixed

Expand Down
167 changes: 157 additions & 10 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use crate::host::Host;
use crate::net::Ipv4Addr;
use crate::socket::Socket;
use crate::uninitialized_device::UninitializedDevice;
use crate::{register, MacAddress};
use crate::{
register::{self, common::RetryTime},
MacAddress, Mode,
};

#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -58,11 +61,8 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
}

fn clear_mode(&mut self) -> Result<(), SpiBus::Error> {
// reset bit
let mode = [0b10000000];
self.bus
.write_frame(register::COMMON, register::common::MODE, &mode)?;
Ok(())
// Set RST common register of the w5500
self.as_mut().reset_device()
}

#[inline]
Expand Down Expand Up @@ -95,6 +95,47 @@ impl<SpiBus: Bus, HostImpl: Host> Device<SpiBus, HostImpl> {
self.as_mut().version()
}

/// Get the currently set Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
self.as_mut().current_retry_timeout()
}

/// Set a new value for the Retry Time-value Register.
///
/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.as_mut().set_retry_timeout(retry_time_value)
}

/// Get the current Retry Count Register value.
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
self.as_mut().current_retry_count()
}

/// Set a new value for the Retry Count register.
#[inline]
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.as_mut().set_retry_count(retry_count)
}

#[inline]
pub(crate) fn as_mut(&mut self) -> DeviceRefMut<'_, BusRef<'_, SpiBus>, HostImpl> {
DeviceRefMut {
Expand Down Expand Up @@ -187,10 +228,116 @@ impl<SpiBus: Bus, HostImpl: Host> DeviceRefMut<'_, SpiBus, HostImpl> {
Ok(phy[0].into())
}

pub fn version(&mut self) -> Result<u8, SpiBus::Error> {
let mut version = [0u8];
#[inline]
pub fn reset_device(&mut self) -> Result<(), SpiBus::Error> {
// Set RST common register of the w5500
let mode = [0b10000000];
self.bus
.read_frame(register::COMMON, register::common::VERSION, &mut version)?;
Ok(version[0])
.write_frame(register::COMMON, register::common::MODE, &mode)
}

#[inline]
pub fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON,
register::common::MODE,
&mode_options.to_register(),
)
}

#[inline]
pub fn version(&mut self) -> Result<u8, SpiBus::Error> {
let mut version_register = [0_u8];
self.bus.read_frame(
register::COMMON,
register::common::VERSION,
&mut version_register,
)?;

Ok(version_register[0])
}

/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
///
/// # Example
///
/// ```
/// use w5500::register::common::RetryTime;
///
/// let default = RetryTime::from_millis(200);
/// assert_eq!(RetryTime::default(), default);
///
/// // E.g. 4000 (register) = 400ms
/// let four_hundred_ms = RetryTime::from_millis(400);
/// assert_eq!(four_hundred_ms.to_u16(), 4000);
/// ```
#[inline]
pub fn set_retry_timeout(&mut self, retry_time_value: RetryTime) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON,
register::common::RETRY_TIME,
&retry_time_value.to_register(),
)?;

Ok(())
}

/// RTR (Retry Time-value Register) [R/W] [0x0019 – 0x001A] [0x07D0]
///
/// E.g. 4000 = 400ms
#[inline]
pub fn current_retry_timeout(&mut self) -> Result<RetryTime, SpiBus::Error> {
let mut retry_time_register: [u8; 2] = [0, 0];
self.bus.read_frame(
register::COMMON,
register::common::RETRY_TIME,
&mut retry_time_register,
)?;

Ok(RetryTime::from_register(retry_time_register))
}

/// Set a new value for the Retry Count register.
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// For more details check out the rest of the datasheet documentation on the Retry count.
///
/// From datasheet:
///
/// RCR configures the number of time of retransmission. When retransmission occurs
/// as many as ‘RCR+1’, Timeout interrupt is issued (Sn_IR[TIMEOUT] = ‘1’).
///
/// The timeout of W5500 can be configurable with RTR and RCR. W5500 has two kind
/// timeout such as Address Resolution Protocol (ARP) and TCP retransmission.
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
pub fn set_retry_count(&mut self, retry_count: u8) -> Result<(), SpiBus::Error> {
self.bus.write_frame(
register::COMMON,
register::common::RETRY_COUNT,
&[retry_count],
)?;

Ok(())
}

/// Get the current Retry Count value
///
/// RCR (Retry Count Register) [R/W] [0x001B] [0x08]
///
/// E.g. In case of errors it will retry for 7 times:
/// `RCR = 0x0007`
#[inline]
pub fn current_retry_count(&mut self) -> Result<u8, SpiBus::Error> {
let mut retry_count_register: [u8; 1] = [0];
self.bus.read_frame(
register::COMMON,
register::common::RETRY_COUNT,
&mut retry_count_register,
)?;

Ok(retry_count_register[0])
}
}
90 changes: 81 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,66 @@ pub mod tcp;
pub mod udp;
mod uninitialized_device;

pub use device::{Device, DeviceRefMut, InactiveDevice};
pub use host::{Dhcp, Host, HostConfig, Manual};
pub use net::MacAddress;
pub use uninitialized_device::{InitializeError, UninitializedDevice};
#[doc(inline)]
pub use self::{
device::{Device, DeviceRefMut, InactiveDevice},
host::{Dhcp, Host, HostConfig, Manual},
net::MacAddress,
uninitialized_device::{InitializeError, UninitializedDevice},
};

// TODO add better docs to all public items, add unit tests.

/// Settings for wake on LAN. Allows the W5500 to optionally emit an interrupt upon receiving a packet
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OnWakeOnLan {
InvokeInterrupt = 0b00100000,
Ignore = 0b00000000,
}

/// Ping Block Mode
///
/// Settings for ping. Allows the W5500 to respond to or ignore network ping requests
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OnPingRequest {
/// 0: Disable Ping block
Respond = 0b00000000,
/// 1 : Enable Ping block
///
/// If the bit is ‘1’, it blocks the response to a ping request.
Ignore = 0b00010000,
}

/// Use [ConnectionType::PPoE] when talking
/// to an ADSL modem. Otherwise use [ConnectionType::Ethernet]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConnectionType {
PPoE = 0b00001000,
Ethernet = 0b00000000,
}

#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
/// Force ARP
///
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum ArpResponses {
/// 0 : Disable Force ARP mode
Cache = 0b00000000,
/// 1 : Enable Force ARP mode
///
/// In Force ARP mode, It forces on sending ARP Request whenever data is
/// sent.
DropAfterUse = 0b00000010,
}

#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Mode {
pub on_wake_on_lan: OnWakeOnLan,
Expand All @@ -67,6 +83,22 @@ pub struct Mode {
pub arp_responses: ArpResponses,
}

impl Mode {
pub fn to_register(self) -> [u8; 1] {
[self.to_u8()]
}

pub fn to_u8(self) -> u8 {
let mut register = 0;
register |= self.on_wake_on_lan as u8;
register |= self.on_ping_request as u8;
register |= self.connection_type as u8;
register |= self.arp_responses as u8;

register
}
}

impl Default for Mode {
fn default() -> Self {
Self {
Expand All @@ -77,3 +109,43 @@ impl Default for Mode {
}
}
}

#[cfg(test)]
mod test {
use crate::Mode;

#[test]
fn test_mode_register() {
let ping_respond_and_force_arp = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 should be 0 - Disable WOL mode
on_wake_on_lan: crate::OnWakeOnLan::Ignore,
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 0 - PPoE disabled
connection_type: crate::ConnectionType::Ethernet,
// Bit: 2 reserved
// Bit: 1 should be 0 - Disabled Force ARP
arp_responses: crate::ArpResponses::Cache,
// Bit: 0 reserved
};
assert_eq!(0b0000_0000, ping_respond_and_force_arp.to_u8());

let all_enabled = Mode {
// Bit: 7 Reset (RST) should be 0
// Bit: 6 reserved
// Bit: 5 should be 1 - Enable WOL mode
on_wake_on_lan: crate::OnWakeOnLan::InvokeInterrupt,
// Bit: 4 should be 0 - Disable Ping Block Mode
on_ping_request: crate::OnPingRequest::Respond,
// Bit: 3 should be 1 - PPoE enable
connection_type: crate::ConnectionType::PPoE,
// Bit: 2 reserved
// Bit: 1 should be 1 - Enable Force ARP
arp_responses: crate::ArpResponses::DropAfterUse,
// Bit: 0 reserved
};
assert_eq!(0b0010_1010, all_enabled.to_u8());
}
}
Loading

0 comments on commit 42791c2

Please sign in to comment.