diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index e74fb7cd..c13f1018 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -21,7 +21,6 @@ embassy-time = { version = "0.1.0" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" - [dev-dependencies] # reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged. #embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] } @@ -33,9 +32,11 @@ futures-test = "0.3.17" [features] default = [ ] -defmt = [ "dep:defmt" ] +defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] +log = ["dep:log"] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/" target = "thumbv7em-none-eabi" +features = ["defmt"] diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs new file mode 100644 index 00000000..12737c69 --- /dev/null +++ b/embassy-net-adin1110/src/fmt.rs @@ -0,0 +1,254 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ignored = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 8d73e024..4af054ae 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -6,6 +6,9 @@ #![allow(clippy::missing_panics_doc)] #![doc = include_str!("../README.md")] +// must go first! +mod fmt; + mod crc32; mod crc8; mod mdio; @@ -20,12 +23,13 @@ use embassy_net_driver_channel as ch; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; use embedded_hal_async::digital::Wait; -use embedded_hal_async::spi::{Operation, SpiDevice}; +use embedded_hal_async::spi::{Error, Operation, SpiDevice}; use heapless::Vec; pub use mdio::MdioBus; pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; +use crate::fmt::Bytes; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; pub const PHYID: u32 = 0x0283_BC91; @@ -153,8 +157,7 @@ impl ADIN1110 { let value = u32::from_be_bytes(rx_buf[0..4].try_into().unwrap()); - #[cfg(feature = "defmt")] - defmt::trace!("REG Read {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + trace!("REG Read {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf)); Ok(value) } @@ -181,8 +184,7 @@ impl ADIN1110 { let _ = tx_buf.push(crc8(val.as_slice())); } - #[cfg(feature = "defmt")] - defmt::trace!("REG Write {} = {:08x} SPI {:02x}", reg, value, &tx_buf); + trace!("REG Write {} = {:08x} SPI {}", reg, value, Bytes(&tx_buf)); self.spi.write(&tx_buf).await.map_err(AdinError::Spi) } @@ -219,8 +221,7 @@ impl ADIN1110 { let packet_size = fifo_frame_size - FRAME_HEADER_LEN - FCS_LEN; if packet_size > frame.len() { - #[cfg(feature = "defmt")] - defmt::trace!("MAX: {} WANT: {}", frame.len(), packet_size); + trace!("MAX: {} WANT: {}", frame.len(), packet_size); return Err(AdinError::PACKET_TOO_BIG); } @@ -333,14 +334,13 @@ impl ADIN1110 { self.write_reg(sr::TX_FSIZE, send_len).await?; - #[cfg(feature = "defmt")] - defmt::trace!( - "TX: hdr {} [{}] {:02x}-{:02x}-{:02x} SIZE: {}", + trace!( + "TX: hdr {} [{}] {}-{}-{} SIZE: {}", head_data.len(), frame.len(), - head_data.as_slice(), - frame, - tail_data.as_slice(), + Bytes(head_data.as_slice()), + Bytes(frame), + Bytes(tail_data.as_slice()), send_len, ); @@ -445,16 +445,14 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); loop { - #[cfg(feature = "defmt")] - defmt::debug!("Waiting for interrupts"); + debug!("Waiting for interrupts"); match select(self.int.wait_for_low(), tx_chan.tx_buf()).await { Either::First(_) => { let mut status1_clr = Status1(0); let mut status1 = Status1(self.mac.read_reg(sr::STATUS1).await.unwrap()); while status1.p1_rx_rdy() { - #[cfg(feature = "defmt")] - defmt::debug!("alloc RX packet buffer"); + debug!("alloc RX packet buffer"); match select(rx_chan.rx_buf(), tx_chan.tx_buf()).await { // Handle frames that needs to transmit from the wire. // Note: rx_chan.rx_buf() channel donĀ“t accept new request @@ -466,22 +464,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } Err(e) => match e { AdinError::PACKET_TOO_BIG => { - #[cfg(feature = "defmt")] - defmt::error!("RX Packet too big, DROP"); + error!("RX Packet too big, DROP"); self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); } AdinError::PACKET_TOO_SMALL => { - #[cfg(feature = "defmt")] - defmt::error!("RX Packet too small, DROP"); + error!("RX Packet too small, DROP"); self.mac.write_reg(sr::FIFO_CLR, 1).await.unwrap(); } - AdinError::Spi(_) => { - #[cfg(feature = "defmt")] - defmt::error!("RX Spi error") + AdinError::Spi(e) => { + error!("RX Spi error {}", e.kind()); } _ => { - #[cfg(feature = "defmt")] - defmt::error!("RX Error") + error!("RX Error"); } }, }, @@ -496,21 +490,18 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { let status0 = Status0(self.mac.read_reg(sr::STATUS0).await.unwrap()); if status1.0 & !0x1b != 0 { - #[cfg(feature = "defmt")] - defmt::error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0); + error!("SPE CHIP STATUS 0:{:08x} 1:{:08x}", status0.0, status1.0); } if status1.tx_rdy() { status1_clr.set_tx_rdy(true); - #[cfg(feature = "defmt")] - defmt::info!("TX_DONE"); + trace!("TX_DONE"); } if status1.link_change() { let link = status1.p1_link_status(); self.is_link_up = link; - #[cfg(feature = "defmt")] if link { let link_status = self .mac @@ -530,9 +521,9 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { .await .unwrap(); - defmt::info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); + info!("LINK Changed: Link Up, Volt: {} V p-p, MSE: {:0004}", volt, mse); } else { - defmt::info!("LINK Changed: Link Down"); + info!("LINK Changed: Link Down"); } state_chan.set_link_state(if link { LinkState::Up } else { LinkState::Down }); @@ -540,50 +531,42 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } if status1.tx_ecc_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI TX_ECC_ERR error, CLEAR TX FIFO"); + error!("SPI TX_ECC_ERR error, CLEAR TX FIFO"); self.mac.write_reg(sr::FIFO_CLR, 2).await.unwrap(); status1_clr.set_tx_ecc_err(true); } if status1.rx_ecc_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI RX_ECC_ERR error"); + error!("SPI RX_ECC_ERR error"); status1_clr.set_rx_ecc_err(true); } if status1.spi_err() { - #[cfg(feature = "defmt")] - defmt::error!("SPI SPI_ERR CRC error"); + error!("SPI SPI_ERR CRC error"); status1_clr.set_spi_err(true); } if status0.phyint() { - #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let crsm_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1E::CRSM_IRQ_STATUS.into()) .await .unwrap(); - #[cfg_attr(not(feature = "defmt"), allow(unused_variables))] let phy_irq_st = self .mac .read_cl45(MDIO_PHY_ADDR, RegsC45::DA1F::PHY_SYBSYS_IRQ_STATUS.into()) .await .unwrap(); - #[cfg(feature = "defmt")] - defmt::warn!( + warn!( "SPE CHIP PHY CRSM_IRQ_STATUS {:04x} PHY_SUBSYS_IRQ_STATUS {:04x}", - crsm_irq_st, - phy_irq_st + crsm_irq_st, phy_irq_st ); } if status0.txfcse() { - #[cfg(feature = "defmt")] - defmt::error!("SPE CHIP PHY TX Frame CRC error"); + error!("Ethernet Frame FCS and calc FCS don't match!"); } // Clear status0 @@ -613,8 +596,7 @@ pub async fn new (Device<'_>, Runner<'_, SPI, INT, RST>) { use crate::regs::{IMask0, IMask1}; - #[cfg(feature = "defmt")] - defmt::info!("INIT ADIN1110"); + info!("INIT ADIN1110"); // Reset sequence reset.set_low().unwrap(); @@ -634,23 +616,20 @@ pub async fn new) -> core::fmt::Result { + write!(f, "{self:?}") + } +} + impl From for u16 { fn from(val: SpiRegisters) -> Self { val as u16 @@ -68,7 +76,7 @@ impl From for SpiRegisters { 0x73 => Self::ADDR_MSK_UPR1, 0x90 => Self::RX_FSIZE, 0x91 => Self::RX, - e => panic!("Unknown value {e}"), + e => panic!("Unknown value {}", e), } } } @@ -313,7 +321,7 @@ impl From for LedFunc { 26 => LedFunc::Clk25Ref, 27 => LedFunc::TxTCLK, 28 => LedFunc::Clk120MHz, - e => panic!("Invalid value {e}"), + e => panic!("Invalid value {}", e), } } } @@ -369,7 +377,7 @@ impl From for LedPol { 0 => LedPol::AutoSense, 1 => LedPol::ActiveHigh, 2 => LedPol::ActiveLow, - e => panic!("Invalid value {e}"), + e => panic!("Invalid value {}", e), } } }