diff --git a/crates/rf24-rs/Cargo.toml b/crates/rf24-rs/Cargo.toml index 990d956..4a304d2 100644 --- a/crates/rf24-rs/Cargo.toml +++ b/crates/rf24-rs/Cargo.toml @@ -20,7 +20,7 @@ defmt = {version = "1.0.1", optional = true} embedded-hal = "1.0.0" [dev-dependencies] -embedded-hal-mock = "0.11.1" +embedded-hal-mock = {git = "https://github.com/2bndy5/embedded-hal-mock.git", branch = "dev"} [features] defmt = ["dep:defmt"] diff --git a/crates/rf24-rs/src/radio/prelude.rs b/crates/rf24-rs/src/radio/prelude.rs index 8cde431..2bb2a05 100644 --- a/crates/rf24-rs/src/radio/prelude.rs +++ b/crates/rf24-rs/src/radio/prelude.rs @@ -12,11 +12,14 @@ use crate::types::{CrcLength, DataRate, FifoState, PaLevel, StatusFlags}; use super::RadioConfig; +/// A trait to alias hardware related errors about the radio. +pub trait RadioErrorType { + type Error; +} + /// A trait to represent manipulation of data pipes /// for an ESB capable transceiver. -pub trait EsbPipe { - type PipeErrorType; - +pub trait EsbPipe: RadioErrorType { /// Open a specified `pipe` for receiving data when radio is in RX mode. /// /// If the specified `pipe` is not in range [0, 5], then this function does nothing. @@ -54,45 +57,41 @@ pub trait EsbPipe { /// /// Read [maniacBug's blog post](http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html) /// to understand how to avoid using malformed addresses. - fn open_rx_pipe(&mut self, pipe: u8, address: &[u8]) -> Result<(), Self::PipeErrorType>; + fn open_rx_pipe(&mut self, pipe: u8, address: &[u8]) -> Result<(), Self::Error>; /// Set an address to pipe 0 for transmitting when radio is in TX mode. /// - fn open_tx_pipe(&mut self, address: &[u8]) -> Result<(), Self::PipeErrorType>; + fn open_tx_pipe(&mut self, address: &[u8]) -> Result<(), Self::Error>; /// Close a specified pipe from receiving data when radio is in RX mode. - fn close_rx_pipe(&mut self, pipe: u8) -> Result<(), Self::PipeErrorType>; + fn close_rx_pipe(&mut self, pipe: u8) -> Result<(), Self::Error>; /// Set the address length (applies to all pipes). /// /// If the specified length is clamped to the range [2, 5]. /// Any value outside that range defaults to 5. - fn set_address_length(&mut self, length: u8) -> Result<(), Self::PipeErrorType>; + fn set_address_length(&mut self, length: u8) -> Result<(), Self::Error>; /// Get the currently configured address length (applied to all pipes). - fn get_address_length(&mut self) -> Result; + fn get_address_length(&mut self) -> Result; } /// A trait to represent manipulation of a channel (aka frequency) /// for an ESB capable transceiver. -pub trait EsbChannel { - type ChannelErrorType; - +pub trait EsbChannel: RadioErrorType { /// Set the radio's currently selected channel. /// /// These channels translate to the RF frequency as an offset of Hz from 2400 MHz. /// The default channel is 76 (2400 + 76 = 2.476 GHz). - fn set_channel(&mut self, channel: u8) -> Result<(), Self::ChannelErrorType>; + fn set_channel(&mut self, channel: u8) -> Result<(), Self::Error>; /// Get the radio's currently selected channel. - fn get_channel(&mut self) -> Result; + fn get_channel(&mut self) -> Result; } /// A trait to represent manipulation of [`StatusFlags`] /// for an ESB capable transceiver. -pub trait EsbStatus { - type StatusErrorType; - +pub trait EsbStatus: RadioErrorType { /// Get the [`StatusFlags`] state that was cached from the latest SPI transaction. fn get_status_flags(&self, flags: &mut StatusFlags); @@ -102,7 +101,7 @@ pub trait EsbStatus { /// IRQ pin ignore the corresponding event. /// By default, all events are enabled and will trigger the IRQ pin, /// a behavior equivalent to `set_status_flags(None)`. - fn set_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::StatusErrorType>; + fn set_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::Error>; /// Clear the radio's IRQ status flags /// @@ -112,40 +111,38 @@ pub trait EsbStatus { /// interrupt event. Setting any member of [`StatusFlags`] to `false` will leave /// the corresponding status flag untouched. This means that the IRQ pin can remain /// active (LOW) when multiple events occurred but only flag was cleared. - fn clear_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::StatusErrorType>; + fn clear_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::Error>; /// Refresh the internal cache of status byte /// (which is also saved from every SPI transaction). /// /// Use [`EsbStatus::get_status_flags()`] to get the updated status flags. - fn update(&mut self) -> Result<(), Self::StatusErrorType>; + fn update(&mut self) -> Result<(), Self::Error>; } /// A trait to represent manipulation of RX and TX FIFOs /// for an ESB capable transceiver. -pub trait EsbFifo { - type FifoErrorType; - +pub trait EsbFifo: RadioErrorType { /// Flush the radio's RX FIFO. - fn flush_rx(&mut self) -> Result<(), Self::FifoErrorType>; + fn flush_rx(&mut self) -> Result<(), Self::Error>; /// Flush the radio's TX FIFO. /// /// This function is automatically called by [`EsbRadio::as_tx()`] /// if ACK payloads are enabled. - fn flush_tx(&mut self) -> Result<(), Self::FifoErrorType>; + fn flush_tx(&mut self) -> Result<(), Self::Error>; /// Get the state of the specified FIFO. /// /// - Pass `true` to `about_tx` parameter to get the state of the TX FIFO. /// - Pass `false` to `about_tx` parameter to get the state of the RX FIFO. - fn get_fifo_state(&mut self, about_tx: bool) -> Result; + fn get_fifo_state(&mut self, about_tx: bool) -> Result; /// Is there a payload available in the radio's RX FIFO? /// /// This function simply returns true if there is data to [`EsbRadio::read()`] from the RX FIFO. /// Use [`EsbFifo::available_pipe()`] to get information about the pipe that received the data. - fn available(&mut self) -> Result; + fn available(&mut self) -> Result; /// This is similar to [`EsbFifo::available()`] except the `pipe` parameter is given /// a mutable [`u8`] value, and the pipe number that received the data is stored to it. @@ -171,23 +168,21 @@ pub trait EsbFifo { /// before calling this function. /// /// - fn available_pipe(&mut self, pipe: &mut u8) -> Result; + fn available_pipe(&mut self, pipe: &mut u8) -> Result; } /// A trait to represent manipulation of payload lengths (static or dynamic) /// for an ESB capable transceiver. -pub trait EsbPayloadLength { - type PayloadLengthErrorType; - +pub trait EsbPayloadLength: RadioErrorType { /// Set the radio's static payload length. /// /// Note, this has no effect when dynamic payloads are enabled. - fn set_payload_length(&mut self, length: u8) -> Result<(), Self::PayloadLengthErrorType>; + fn set_payload_length(&mut self, length: u8) -> Result<(), Self::Error>; /// Get the currently configured static payload length used on pipe 0 /// /// Use [`EsbPayloadLength::get_dynamic_payload_length()`] instead when dynamic payloads are enabled. - fn get_payload_length(&mut self) -> Result; + fn get_payload_length(&mut self) -> Result; /// Set the dynamic payloads feature for all pipes. /// @@ -212,7 +207,7 @@ pub trait EsbPayloadLength { /// } /// } /// ``` - fn set_dynamic_payloads(&mut self, enable: bool) -> Result<(), Self::PayloadLengthErrorType>; + fn set_dynamic_payloads(&mut self, enable: bool) -> Result<(), Self::Error>; /// Get the current setting of the dynamic payloads feature. /// @@ -224,14 +219,12 @@ pub trait EsbPayloadLength { /// When dynamic payloads are disabled (via [`EsbPayloadLength::set_dynamic_payloads()`]) /// or there is no [`EsbFifo::available()`] payload in the RX FIFO, this function's /// returned value shall be considered invalid. - fn get_dynamic_payload_length(&mut self) -> Result; + fn get_dynamic_payload_length(&mut self) -> Result; } /// A trait to represent manipulation of the automatic acknowledgement feature /// for an ESB capable transceiver. -pub trait EsbAutoAck: EsbPayloadLength { - type AutoAckErrorType; - +pub trait EsbAutoAck: EsbPayloadLength + RadioErrorType { /// Enable or disable the custom ACK (acknowledgement) payloads attached to auto-ack packets. /// /// By default this feature is disabled. @@ -243,7 +236,7 @@ pub trait EsbAutoAck: EsbPayloadLength { /// Use [`EsbRadio::read()`] to fetch the payloads from the RX FIFO. /// /// To append a payload to an auto ack packet, use [`EsbAutoAck::write_ack_payload()`]. - fn set_ack_payloads(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType>; + fn set_ack_payloads(&mut self, enable: bool) -> Result<(), Self::Error>; /// Get the current setting of the ACK payloads feature. /// @@ -282,7 +275,7 @@ pub trait EsbAutoAck: EsbPayloadLength { /// /// See also [`EsbAutoAck::set_ack_payloads()`], /// [`EsbPayloadLength::set_dynamic_payloads`], and [`EsbAutoAck::set_auto_ack()`]. - fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result; + fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result; /// Enable or disable the auto-ack (automatic acknowledgement) feature for all /// pipes. @@ -304,7 +297,7 @@ pub trait EsbAutoAck: EsbPayloadLength { /// If disabling auto-acknowledgment packets, the ACK payloads /// feature is also disabled as this feature is required to send ACK /// payloads. - fn set_auto_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType>; + fn set_auto_ack(&mut self, enable: bool) -> Result<(), Self::Error>; /// Set the auto-ack feature for an individual `pipe`. /// @@ -324,7 +317,7 @@ pub trait EsbAutoAck: EsbPayloadLength { /// If disabling auto-acknowledgment packets on pipe 0, the ACK /// payloads feature is also disabled as this feature is required on pipe 0 /// to send ACK payloads. - fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<(), Self::AutoAckErrorType>; + fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<(), Self::Error>; /// Set the number of retry attempts and delay between retry attempts when /// transmitting a payload. @@ -344,7 +337,7 @@ pub trait EsbAutoAck: EsbPayloadLength { /// Disabling the auto-retry feature on a transmitter still uses the /// auto-ack feature (if enabled), except it will not retry to transmit if /// the payload was not acknowledged on the first attempt. - fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<(), Self::AutoAckErrorType>; + fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<(), Self::Error>; /// Allow the functionality of the `ask_no_ack` parameter in [`EsbRadio::send()`] and /// [`EsbRadio::write()`]. @@ -354,26 +347,22 @@ pub trait EsbAutoAck: EsbPayloadLength { /// allow disabling the auto-ack feature on a per-payload basis. Such behavior would be /// desirable when transmitting to multiple radios that are setup to receive data from the /// same address. - fn allow_ask_no_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType>; + fn allow_ask_no_ack(&mut self, enable: bool) -> Result<(), Self::Error>; } /// A trait to represent manipulation of the power amplitude level /// for an ESB capable transceiver. -pub trait EsbPaLevel { - type PaLevelErrorType; - +pub trait EsbPaLevel: RadioErrorType { /// Get the currently configured Power Amplitude Level (PA Level) - fn get_pa_level(&mut self) -> Result; + fn get_pa_level(&mut self) -> Result; /// Set the radio's Power Amplitude Level (PA Level) - fn set_pa_level(&mut self, pa_level: PaLevel) -> Result<(), Self::PaLevelErrorType>; + fn set_pa_level(&mut self, pa_level: PaLevel) -> Result<(), Self::Error>; } /// A trait to represent manipulation of the state of power /// for an ESB capable transceiver. -pub trait EsbPower { - type PowerErrorType; - +pub trait EsbPower: RadioErrorType { /// Power down the radio. /// ///
@@ -381,7 +370,7 @@ pub trait EsbPower { /// The nRF24L01 cannot receive nor transmit data when powered down. /// ///
- fn power_down(&mut self) -> Result<(), Self::PowerErrorType>; + fn power_down(&mut self) -> Result<(), Self::Error>; /// Power up the radio. /// @@ -399,7 +388,7 @@ pub trait EsbPower { /// // ... do something else for 5 milliseconds /// radio.as_rx().unwrap(); /// ``` - fn power_up(&mut self, delay: Option) -> Result<(), Self::PowerErrorType>; + fn power_up(&mut self, delay: Option) -> Result<(), Self::Error>; /// Get the current (cached) state of the radio's power. /// @@ -409,44 +398,36 @@ pub trait EsbPower { /// A trait to represent manipulation of Cyclical Redundancy Checksums /// for an ESB capable transceiver. -pub trait EsbCrcLength { - type CrcLengthErrorType; - +pub trait EsbCrcLength: RadioErrorType { /// Get the currently configured CRC (Cyclical Redundancy Checksum) length - fn get_crc_length(&mut self) -> Result; + fn get_crc_length(&mut self) -> Result; /// Set the radio's CRC (Cyclical Redundancy Checksum) length - fn set_crc_length(&mut self, crc_length: CrcLength) -> Result<(), Self::CrcLengthErrorType>; + fn set_crc_length(&mut self, crc_length: CrcLength) -> Result<(), Self::Error>; } /// A trait to represent manipulation of the Data Rate /// for an ESB capable transceiver. -pub trait EsbDataRate { - type DataRateErrorType; - +pub trait EsbDataRate: RadioErrorType { /// Get the currently configured Data Rate - fn get_data_rate(&mut self) -> Result; + fn get_data_rate(&mut self) -> Result; /// Set the radio's Data Rate - fn set_data_rate(&mut self, data_rate: DataRate) -> Result<(), Self::DataRateErrorType>; + fn set_data_rate(&mut self, data_rate: DataRate) -> Result<(), Self::Error>; } /// A trait to represent debug output /// for an ESB capable transceiver. -pub trait EsbDetails { - type DetailsErrorType; - +pub trait EsbDetails: RadioErrorType { /// Print details about radio's current configuration. /// /// This should only be used for debugging development. /// Using this in production should be limited due to a significant increase in /// compile size. - fn print_details(&mut self) -> Result<(), Self::DetailsErrorType>; + fn print_details(&mut self) -> Result<(), Self::Error>; } -pub trait EsbInit { - type ConfigErrorType; - +pub trait EsbInit: RadioErrorType { /// Initialize the radio's hardware. /// /// This is similar to [`EsbInit::with_config()`] (with [`RadioConfig::default()`]), @@ -459,28 +440,26 @@ pub trait EsbInit { /// This function should only be called once after instantiating the radio object. /// Afterward, it is quicker to use [`EsbInit::with_config()`] to reconfigure the /// radio for different network requirements. - fn init(&mut self) -> Result<(), Self::ConfigErrorType>; + fn init(&mut self) -> Result<(), Self::Error>; /// Reconfigure the radio using the given `config` object. /// /// See [`RadioConfig`] for more detail. /// This function is a convenience where calling multiple configuration functions may /// be cumbersome. - fn with_config(&mut self, config: &RadioConfig) -> Result<(), Self::ConfigErrorType>; + fn with_config(&mut self, config: &RadioConfig) -> Result<(), Self::Error>; } /// A trait to represent manipulation of an ESB capable transceiver. /// /// Although the name is rather generic, this trait describes the /// behavior of a radio's rudimentary modes (RX and TX). -pub trait EsbRadio { - type RadioErrorType; - +pub trait EsbRadio: RadioErrorType { /// Put the radio into active RX mode. /// /// Conventionally, this should be called after setting the RX addresses via /// [`EsbPipe::open_rx_pipe()`] - fn as_rx(&mut self) -> Result<(), Self::RadioErrorType>; + fn as_rx(&mut self) -> Result<(), Self::Error>; /// Put the radio into inactive TX mode. /// @@ -488,7 +467,7 @@ pub trait EsbRadio { /// [`EsbRadio::write()`]. /// Conventionally, this should be called after setting the TX address via /// [`EsbPipe::open_tx_pipe()`]. - fn as_tx(&mut self) -> Result<(), Self::RadioErrorType>; + fn as_tx(&mut self) -> Result<(), Self::Error>; /// Is the radio in RX mode? fn is_rx(&self) -> bool; @@ -500,7 +479,7 @@ pub trait EsbRadio { /// /// See [`EsbRadio::write()`] for description of `ask_no_ack` parameter and more /// detail about how the radio processes data in the TX FIFO. - fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> Result; + fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> Result; /// Non-blocking function to prepare radio for transmitting payload(s). /// @@ -526,12 +505,7 @@ pub trait EsbRadio { /// Set the `start_tx` parameter `false` to prevent entering active TX mode. If the radio /// is already in active TX mode (because it is processing payloads in the TX FIFO), then /// this parameter has no effect. - fn write( - &mut self, - buf: &[u8], - ask_no_ack: bool, - start_tx: bool, - ) -> Result; + fn write(&mut self, buf: &[u8], ask_no_ack: bool, start_tx: bool) -> Result; /// Similar to [`EsbRadio::send()`] but specifically for failed transmissions. /// @@ -542,7 +516,7 @@ pub trait EsbRadio { /// /// Unlike [`EsbRadio::rewrite()`], this function will only make one attempt to /// resend the failed payload. - fn resend(&mut self) -> Result; + fn resend(&mut self) -> Result; /// Similar to [`EsbRadio::write()`] but specifically for failed transmissions. /// @@ -561,14 +535,14 @@ pub trait EsbRadio { /// - The radio's TX FIFO is flushed (via [`EsbFifo::flush_tx()`]). /// - The radio's CE pin is set to inactive LOW. This can be done directly on the pin or by calling /// [`EsbRadio::as_tx()`]. - fn rewrite(&mut self) -> Result<(), Self::RadioErrorType>; + fn rewrite(&mut self) -> Result<(), Self::Error>; /// Get the Auto-Retry Count (ARC) about the previous transmission. /// /// This data is reset for every payload attempted to transmit. /// It cannot exceed 15 per the `count` parameter in [`EsbAutoAck::set_auto_retries()`]. /// If auto-ack feature is disabled, then this function provides no useful data. - fn get_last_arc(&mut self) -> Result; + fn get_last_arc(&mut self) -> Result; /// Read data from the radio's RX FIFO into the specified `buf`. /// @@ -581,5 +555,5 @@ pub trait EsbRadio { /// (set by [`EsbPayloadLength::set_payload_length()`]) or the dynamic payload length /// (fetched internally using [`EsbPayloadLength::get_dynamic_payload_length()`]) if /// dynamic payload lengths are enable (see [`EsbPayloadLength::set_dynamic_payloads()`]). - fn read(&mut self, buf: &mut [u8], len: Option) -> Result; + fn read(&mut self, buf: &mut [u8], len: Option) -> Result; } diff --git a/crates/rf24-rs/src/radio/rf24/auto_ack.rs b/crates/rf24-rs/src/radio/rf24/auto_ack.rs index 34fd951..335c6a8 100644 --- a/crates/rf24-rs/src/radio/rf24/auto_ack.rs +++ b/crates/rf24-rs/src/radio/rf24/auto_ack.rs @@ -1,6 +1,6 @@ use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; -use crate::radio::{prelude::EsbAutoAck, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbAutoAck, RF24}; use super::{commands, registers, Feature}; @@ -10,9 +10,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type AutoAckErrorType = Nrf24Error; - - fn set_ack_payloads(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> { + fn set_ack_payloads(&mut self, enable: bool) -> Result<(), Self::Error> { if self.feature.ack_payloads() != enable { self.spi_read(1, registers::FEATURE)?; self.feature = @@ -36,7 +34,7 @@ where self.feature.ack_payloads() } - fn set_auto_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> { + fn set_auto_ack(&mut self, enable: bool) -> Result<(), Self::Error> { self.spi_write_byte(registers::EN_AA, 0x3F * enable as u8)?; // accommodate ACK payloads feature if !enable && self.feature.ack_payloads() { @@ -45,7 +43,7 @@ where Ok(()) } - fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<(), Self::AutoAckErrorType> { + fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<(), Self::Error> { if pipe > 5 { return Ok(()); } @@ -58,12 +56,12 @@ where self.spi_write_byte(registers::EN_AA, reg_val & !mask | (mask * enable as u8)) } - fn allow_ask_no_ack(&mut self, enable: bool) -> Result<(), Self::AutoAckErrorType> { + fn allow_ask_no_ack(&mut self, enable: bool) -> Result<(), Self::Error> { self.spi_read(1, registers::FEATURE)?; self.spi_write_byte(registers::FEATURE, self.buf[1] & !1 | enable as u8) } - fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result { + fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result { if self.feature.ack_payloads() && pipe <= 5 { let len = buf.len().min(32); self.spi_write_buf(commands::W_ACK_PAYLOAD | pipe, &buf[..len])?; @@ -72,7 +70,7 @@ where Ok(false) } - fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<(), Self::AutoAckErrorType> { + fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<(), Self::Error> { self.spi_write_byte(registers::SETUP_RETR, count.min(15) | (delay.min(15) << 4)) } } diff --git a/crates/rf24-rs/src/radio/rf24/channel.rs b/crates/rf24-rs/src/radio/rf24/channel.rs index e13e2ee..94dd58a 100644 --- a/crates/rf24-rs/src/radio/rf24/channel.rs +++ b/crates/rf24-rs/src/radio/rf24/channel.rs @@ -1,5 +1,5 @@ use super::registers; -use crate::radio::{prelude::EsbChannel, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbChannel, RF24}; use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; impl EsbChannel for RF24 @@ -8,16 +8,14 @@ where DO: OutputPin, DELAY: DelayNs, { - type ChannelErrorType = Nrf24Error; - /// The nRF24L01 support 126 channels. The specified `channel` is /// clamped to the range [0, 125]. - fn set_channel(&mut self, channel: u8) -> Result<(), Self::ChannelErrorType> { + fn set_channel(&mut self, channel: u8) -> Result<(), Self::Error> { self.spi_write_byte(registers::RF_CH, channel.min(125)) } /// See also [`RF24::set_channel()`]. - fn get_channel(&mut self) -> Result { + fn get_channel(&mut self) -> Result { self.spi_read(1, registers::RF_CH)?; Ok(self.buf[1]) } diff --git a/crates/rf24-rs/src/radio/rf24/crc_length.rs b/crates/rf24-rs/src/radio/rf24/crc_length.rs index e067091..07bc541 100644 --- a/crates/rf24-rs/src/radio/rf24/crc_length.rs +++ b/crates/rf24-rs/src/radio/rf24/crc_length.rs @@ -10,9 +10,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type CrcLengthErrorType = Nrf24Error; - - fn get_crc_length(&mut self) -> Result { + fn get_crc_length(&mut self) -> Result { self.spi_read(1, registers::CONFIG)?; if self.buf[1] & ConfigReg::CRC_MASK == 4 { return Err(Nrf24Error::BinaryCorruption); @@ -21,7 +19,7 @@ where Ok(self.config_reg.crc_length()) } - fn set_crc_length(&mut self, crc_length: CrcLength) -> Result<(), Self::CrcLengthErrorType> { + fn set_crc_length(&mut self, crc_length: CrcLength) -> Result<(), Self::Error> { self.spi_read(1, registers::CONFIG)?; self.config_reg = self.config_reg.with_crc_length(crc_length); self.spi_write_byte(registers::CONFIG, self.config_reg.into_bits()) diff --git a/crates/rf24-rs/src/radio/rf24/data_rate.rs b/crates/rf24-rs/src/radio/rf24/data_rate.rs index 4709eb1..a91c485 100644 --- a/crates/rf24-rs/src/radio/rf24/data_rate.rs +++ b/crates/rf24-rs/src/radio/rf24/data_rate.rs @@ -21,9 +21,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type DataRateErrorType = Nrf24Error; - - fn get_data_rate(&mut self) -> Result { + fn get_data_rate(&mut self) -> Result { self.spi_read(1, registers::RF_SETUP)?; let da_bin = self.buf[1] & DataRate::MASK; if da_bin == DataRate::MASK { @@ -32,7 +30,7 @@ where Ok(DataRate::from_bits(da_bin)) } - fn set_data_rate(&mut self, data_rate: DataRate) -> Result<(), Self::DataRateErrorType> { + fn set_data_rate(&mut self, data_rate: DataRate) -> Result<(), Self::Error> { self.tx_delay = set_tx_delay(data_rate); self.spi_read(1, registers::RF_SETUP)?; let da_bin = data_rate.into_bits(); diff --git a/crates/rf24-rs/src/radio/rf24/details.rs b/crates/rf24-rs/src/radio/rf24/details.rs index a3dbe12..2daaae1 100644 --- a/crates/rf24-rs/src/radio/rf24/details.rs +++ b/crates/rf24-rs/src/radio/rf24/details.rs @@ -1,4 +1,4 @@ -use super::{Nrf24Error, RF24}; +use super::RF24; use crate::radio::prelude::EsbDetails; use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; @@ -18,11 +18,9 @@ where DO: OutputPin, DELAY: DelayNs, { - type DetailsErrorType = Nrf24Error; - #[cfg(feature = "defmt")] #[cfg(target_os = "none")] - fn print_details(&mut self) -> Result<(), Self::DetailsErrorType> { + fn print_details(&mut self) -> Result<(), Self::Error> { defmt::println!("Is a plus variant_________{=bool}", self.is_plus_variant()); let channel = self.get_channel()?; @@ -157,13 +155,13 @@ where } #[cfg(not(any(feature = "defmt", feature = "std")))] - fn print_details(&mut self) -> Result<(), Self::DetailsErrorType> { + fn print_details(&mut self) -> Result<(), Self::Error> { Ok(()) } #[cfg(not(target_os = "none"))] #[cfg(feature = "std")] - fn print_details(&mut self) -> Result<(), Self::DetailsErrorType> { + fn print_details(&mut self) -> Result<(), Self::Error> { use crate::radio::rf24::ConfigReg; std::println!("Is a plus variant_________{}", self.is_plus_variant()); diff --git a/crates/rf24-rs/src/radio/rf24/fifo.rs b/crates/rf24-rs/src/radio/rf24/fifo.rs index 93cb3ce..afab541 100644 --- a/crates/rf24-rs/src/radio/rf24/fifo.rs +++ b/crates/rf24-rs/src/radio/rf24/fifo.rs @@ -1,9 +1,9 @@ use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; -use crate::radio::{prelude::EsbFifo, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbFifo, RF24}; use crate::FifoState; -use super::{commands, registers}; +use super::{commands, registers, Nrf24Error}; impl EsbFifo for RF24 where @@ -11,14 +11,12 @@ where DO: OutputPin, DELAY: DelayNs, { - type FifoErrorType = Nrf24Error; - - fn available(&mut self) -> Result { + fn available(&mut self) -> Result { self.spi_read(1, registers::FIFO_STATUS)?; Ok(self.buf[1] & 1 == 0) } - fn available_pipe(&mut self, pipe: &mut u8) -> Result { + fn available_pipe(&mut self, pipe: &mut u8) -> Result { if self.available()? { // RX FIFO is not empty // get last used pipe @@ -30,23 +28,24 @@ where } /// Use this to discard all 3 layers in the radio's RX FIFO. - fn flush_rx(&mut self) -> Result<(), Self::FifoErrorType> { + fn flush_rx(&mut self) -> Result<(), Self::Error> { self.spi_read(0, commands::FLUSH_RX) } /// Use this to discard all 3 layers in the radio's TX FIFO. - fn flush_tx(&mut self) -> Result<(), Self::FifoErrorType> { + fn flush_tx(&mut self) -> Result<(), Self::Error> { self.spi_read(0, commands::FLUSH_TX) } - fn get_fifo_state(&mut self, about_tx: bool) -> Result { + fn get_fifo_state(&mut self, about_tx: bool) -> Result { self.spi_read(1, registers::FIFO_STATUS)?; let offset = about_tx as u8 * 4; let status = (self.buf[1] & (3 << offset)) >> offset; match status { + 0 => Ok(FifoState::Occupied), 1 => Ok(FifoState::Empty), 2 => Ok(FifoState::Full), - _ => Ok(FifoState::Occupied), + _ => Err(Nrf24Error::BinaryCorruption), } } } @@ -56,7 +55,7 @@ where #[cfg(test)] mod test { extern crate std; - use super::{commands, registers, EsbFifo, FifoState}; + use super::{commands, registers, EsbFifo, FifoState, Nrf24Error}; use crate::{spi_test_expects, test::mk_radio}; use embedded_hal_mock::eh1::spi::Transaction as SpiTransaction; use std::vec; @@ -102,17 +101,19 @@ mod test { pub fn get_fifo_state() { let spi_expectations = spi_test_expects![ // read FIFO register value with empty TX FIFO_STATUS - (vec![registers::FIFO_STATUS, 0u8], vec![0xEu8, 0x10u8]), + (vec![registers::FIFO_STATUS, 0], vec![0xEu8, 0x10]), // read FIFO register value with full TX FIFO_STATUS - (vec![registers::FIFO_STATUS, 0x10u8], vec![0xEu8, 0x20u8]), + (vec![registers::FIFO_STATUS, 0x10], vec![0xEu8, 0x20]), // read FIFO register value with occupied TX FIFO_STATUS - (vec![registers::FIFO_STATUS, 0x20u8], vec![0xEu8, 0u8]), + (vec![registers::FIFO_STATUS, 0x20], vec![0xEu8, 0]), // read FIFO register value with empty RX FIFO_STATUS - (vec![registers::FIFO_STATUS, 0u8], vec![0xEu8, 1u8]), + (vec![registers::FIFO_STATUS, 0], vec![0xEu8, 1]), // read FIFO register value with full RX FIFO_STATUS - (vec![registers::FIFO_STATUS, 1u8], vec![0xEu8, 2u8]), + (vec![registers::FIFO_STATUS, 1], vec![0xEu8, 2]), // read FIFO register value with occupied RX FIFO_STATUS - (vec![registers::FIFO_STATUS, 2u8], vec![0xEu8, 0u8]), + (vec![registers::FIFO_STATUS, 2], vec![0xEu8, 0]), + // read FIFO register value with binary corruption + (vec![registers::FIFO_STATUS, 0], vec![0xEu8, 3]), ]; let mocks = mk_radio(&[], &spi_expectations); let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2); @@ -122,6 +123,10 @@ mod test { assert_eq!(radio.get_fifo_state(false), Ok(FifoState::Empty)); assert_eq!(radio.get_fifo_state(false), Ok(FifoState::Full)); assert_eq!(radio.get_fifo_state(false), Ok(FifoState::Occupied)); + assert_eq!( + radio.get_fifo_state(false), + Err(Nrf24Error::BinaryCorruption) + ); spi.done(); ce_pin.done(); } diff --git a/crates/rf24-rs/src/radio/rf24/init.rs b/crates/rf24-rs/src/radio/rf24/init.rs index 8043459..a7fbed6 100644 --- a/crates/rf24-rs/src/radio/rf24/init.rs +++ b/crates/rf24-rs/src/radio/rf24/init.rs @@ -14,11 +14,9 @@ where DO: OutputPin, DELAY: DelayNs, { - type ConfigErrorType = Nrf24Error; - /// Initialize the radio's hardware using the [`SpiDevice`] and [`OutputPin`] given /// to [`RF24::new()`]. - fn init(&mut self) -> Result<(), Self::ConfigErrorType> { + fn init(&mut self) -> Result<(), Self::Error> { // Must allow the radio time to settle else configuration bits will not necessarily stick. // This is actually only required following power up but some settling time also appears to // be required after resets too. For full coverage, we'll always assume the worst. @@ -49,7 +47,7 @@ where self.with_config(&RadioConfig::default()) } - fn with_config(&mut self, config: &RadioConfig) -> Result<(), Self::ConfigErrorType> { + fn with_config(&mut self, config: &RadioConfig) -> Result<(), Self::Error> { self.clear_status_flags(StatusFlags::new())?; self.power_down()?; diff --git a/crates/rf24-rs/src/radio/rf24/mod.rs b/crates/rf24-rs/src/radio/rf24/mod.rs index 89628c4..2d0edbd 100644 --- a/crates/rf24-rs/src/radio/rf24/mod.rs +++ b/crates/rf24-rs/src/radio/rf24/mod.rs @@ -1,4 +1,8 @@ -use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; +use embedded_hal::{ + delay::DelayNs, + digital::{Error as _, ErrorKind as OutputPinError, OutputPin}, + spi::{Error as _, ErrorKind as SpiError, SpiDevice}, +}; mod auto_ack; pub(crate) mod bit_fields; mod channel; @@ -17,7 +21,7 @@ pub use constants::{commands, mnemonics, registers}; mod details; mod status; use super::prelude::{ - EsbAutoAck, EsbChannel, EsbCrcLength, EsbFifo, EsbPaLevel, EsbPower, EsbRadio, + EsbAutoAck, EsbChannel, EsbCrcLength, EsbFifo, EsbPaLevel, EsbPower, EsbRadio, RadioErrorType, }; use crate::{ types::{CrcLength, PaLevel}, @@ -40,6 +44,27 @@ pub enum Nrf24Error { NotAsTxError, } +impl From for Nrf24Error { + fn from(value: SpiError) -> Self { + Nrf24Error::Spi(value) + } +} + +impl From for Nrf24Error { + fn from(value: OutputPinError) -> Self { + Nrf24Error::Gpo(value) + } +} + +impl RadioErrorType for RF24 +where + SPI: SpiDevice, + DO: OutputPin, + DELAY: DelayNs, +{ + type Error = Nrf24Error; +} + /// This struct implements the [`Esb*` traits](mod@crate::radio::prelude) /// for the nRF24L01 transceiver. /// @@ -113,10 +138,10 @@ where } } - fn spi_transfer(&mut self, len: u8) -> Result<(), Nrf24Error> { + fn spi_transfer(&mut self, len: u8) -> Result<(), Nrf24Error> { self.spi .transfer_in_place(&mut self.buf[..len as usize]) - .map_err(Nrf24Error::Spi)?; + .map_err(|e| e.kind())?; self.status = StatusFlags::from_bits(self.buf[0]); Ok(()) } @@ -126,7 +151,11 @@ where /// self.spi_read(0, commands::NOP)?; /// // STATUS register is now stored in self._status /// ``` - fn spi_read(&mut self, len: u8, command: u8) -> Result<(), Nrf24Error> { + fn spi_read( + &mut self, + len: u8, + command: u8, + ) -> Result<(), Nrf24Error> { self.buf[0] = command; self.spi_transfer(len + 1) } @@ -135,7 +164,7 @@ where &mut self, command: u8, byte: u8, - ) -> Result<(), Nrf24Error> { + ) -> Result<(), Nrf24Error> { self.buf[0] = command | commands::W_REGISTER; self.buf[1] = byte; self.spi_transfer(2) @@ -145,7 +174,7 @@ where &mut self, command: u8, buf: &[u8], - ) -> Result<(), Nrf24Error> { + ) -> Result<(), Nrf24Error> { self.buf[0] = command | commands::W_REGISTER; let buf_len = buf.len(); self.buf[1..(buf_len + 1)].copy_from_slice(&buf[..buf_len]); @@ -154,7 +183,7 @@ where /// A private function to write a special SPI command specific to older /// non-plus variants of the nRF24L01 radio module. It has no effect on plus variants. - fn toggle_features(&mut self) -> Result<(), Nrf24Error> { + fn toggle_features(&mut self) -> Result<(), Nrf24Error> { self.buf[0] = commands::ACTIVATE; self.buf[1] = 0x73; self.spi_transfer(2) @@ -168,7 +197,7 @@ where self.feature.is_plus_variant() } - pub fn rpd(&mut self) -> Result> { + pub fn rpd(&mut self) -> Result> { self.spi_read(1, registers::RPD)?; Ok(self.buf[1] & 1 == 1) } @@ -177,7 +206,7 @@ where &mut self, level: PaLevel, channel: u8, - ) -> Result<(), Nrf24Error> { + ) -> Result<(), Nrf24Error> { self.as_tx()?; self.spi_read(1, registers::RF_SETUP)?; self.spi_write_byte(registers::RF_SETUP, self.buf[1] | 0x90)?; @@ -197,7 +226,7 @@ where } self.set_pa_level(level)?; self.set_channel(channel)?; - self.ce_pin.set_high().map_err(Nrf24Error::Gpo)?; + self.ce_pin.set_high().map_err(|e| e.kind())?; if self.feature.is_plus_variant() { self.delay_impl.delay_ns(1000000); // datasheet says 1 ms is ok in this instance self.rewrite()?; @@ -205,7 +234,7 @@ where Ok(()) } - pub fn stop_carrier_wave(&mut self) -> Result<(), Nrf24Error> { + pub fn stop_carrier_wave(&mut self) -> Result<(), Nrf24Error> { /* * A note from the datasheet: * Do not use REUSE_TX_PL together with CONT_WAVE=1. When both these @@ -215,7 +244,8 @@ where self.power_down()?; // per datasheet recommendation (just to be safe) self.spi_read(1, registers::RF_SETUP)?; self.spi_write_byte(registers::RF_SETUP, self.buf[1] & !0x90)?; - self.ce_pin.set_low().map_err(Nrf24Error::Gpo) + self.ce_pin.set_low().map_err(|e| e.kind())?; + Ok(()) } /// Control the builtin LNA feature on nRF24L01 (older non-plus variants) and Si24R1 @@ -226,7 +256,7 @@ where /// /// This function has no effect on nRF24L01+ modules and PA/LNA variants because /// the LNA feature is always enabled. - pub fn set_lna(&mut self, enable: bool) -> Result<(), Nrf24Error> { + pub fn set_lna(&mut self, enable: bool) -> Result<(), Nrf24Error> { self.spi_read(1, registers::RF_SETUP)?; let out = self.buf[1] & !1 | enable as u8; self.spi_write_byte(registers::RF_SETUP, out) @@ -239,7 +269,8 @@ where mod test { extern crate std; use super::{commands, mnemonics, registers}; - use crate::{spi_test_expects, test::mk_radio}; + use crate::{radio::prelude::EsbRadio, spi_test_expects, test::mk_radio}; + use embedded_hal::{digital::ErrorKind as OutputPinError, spi::ErrorKind as SpiError}; use embedded_hal_mock::eh1::{ digital::{State as PinState, Transaction as PinTransaction}, spi::Transaction as SpiTransaction, @@ -416,4 +447,18 @@ mod test { spi.done(); ce_pin.done(); } + + #[test] + fn mock_hw_errors() { + let ce_expectations = + [PinTransaction::set(PinState::Low).with_error(OutputPinError::Other)]; + let spi_expectations = + [SpiTransaction::transaction_start().with_error(SpiError::ChipSelectFault)]; + let mocks = mk_radio(&ce_expectations, &spi_expectations); + let (mut radio, mut spi, mut ce_pin) = (mocks.0, mocks.1, mocks.2); + assert!(radio.as_tx().is_err()); + assert!(radio.spi_transfer(1).is_err()); + spi.done(); + ce_pin.done(); + } } diff --git a/crates/rf24-rs/src/radio/rf24/pa_level.rs b/crates/rf24-rs/src/radio/rf24/pa_level.rs index b2b98d6..d29ab08 100644 --- a/crates/rf24-rs/src/radio/rf24/pa_level.rs +++ b/crates/rf24-rs/src/radio/rf24/pa_level.rs @@ -1,7 +1,7 @@ use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; use super::registers; -use crate::radio::{prelude::EsbPaLevel, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbPaLevel, RF24}; use crate::PaLevel; impl EsbPaLevel for RF24 @@ -10,14 +10,12 @@ where DO: OutputPin, DELAY: DelayNs, { - type PaLevelErrorType = Nrf24Error; - - fn get_pa_level(&mut self) -> Result { + fn get_pa_level(&mut self) -> Result { self.spi_read(1, registers::RF_SETUP)?; Ok(PaLevel::from_bits(self.buf[1] & PaLevel::MASK)) } - fn set_pa_level(&mut self, pa_level: PaLevel) -> Result<(), Self::PaLevelErrorType> { + fn set_pa_level(&mut self, pa_level: PaLevel) -> Result<(), Self::Error> { self.spi_read(1, registers::RF_SETUP)?; let out = self.buf[1] & !PaLevel::MASK | pa_level.into_bits(); self.spi_write_byte(registers::RF_SETUP, out) diff --git a/crates/rf24-rs/src/radio/rf24/payload_length.rs b/crates/rf24-rs/src/radio/rf24/payload_length.rs index a9f2c3c..de61a97 100644 --- a/crates/rf24-rs/src/radio/rf24/payload_length.rs +++ b/crates/rf24-rs/src/radio/rf24/payload_length.rs @@ -9,9 +9,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type PayloadLengthErrorType = Nrf24Error; - - fn set_payload_length(&mut self, length: u8) -> Result<(), Self::PayloadLengthErrorType> { + fn set_payload_length(&mut self, length: u8) -> Result<(), Self::Error> { let len = length.clamp(1, 32); for i in 0..6 { self.spi_write_byte(registers::RX_PW_P0 + i, len)?; @@ -20,12 +18,12 @@ where Ok(()) } - fn get_payload_length(&mut self) -> Result { + fn get_payload_length(&mut self) -> Result { self.spi_read(1, registers::RX_PW_P0)?; Ok(self.buf[1]) } - fn set_dynamic_payloads(&mut self, enable: bool) -> Result<(), Self::PayloadLengthErrorType> { + fn set_dynamic_payloads(&mut self, enable: bool) -> Result<(), Self::Error> { self.spi_read(1, registers::FEATURE)?; self.feature = Feature::from_bits(self.feature.into_bits() & !Feature::REG_MASK | self.buf[1]) @@ -42,7 +40,7 @@ where self.feature.dynamic_payloads() } - fn get_dynamic_payload_length(&mut self) -> Result { + fn get_dynamic_payload_length(&mut self) -> Result { self.spi_read(1, commands::R_RX_PL_WID)?; if self.buf[1] > 32 { return Err(Nrf24Error::BinaryCorruption); diff --git a/crates/rf24-rs/src/radio/rf24/pipe.rs b/crates/rf24-rs/src/radio/rf24/pipe.rs index deec9bf..6024950 100644 --- a/crates/rf24-rs/src/radio/rf24/pipe.rs +++ b/crates/rf24-rs/src/radio/rf24/pipe.rs @@ -1,6 +1,6 @@ use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; -use crate::radio::{prelude::EsbPipe, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbPipe, RF24}; use super::registers; @@ -10,9 +10,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type PipeErrorType = Nrf24Error; - - fn open_rx_pipe(&mut self, pipe: u8, address: &[u8]) -> Result<(), Self::PipeErrorType> { + fn open_rx_pipe(&mut self, pipe: u8, address: &[u8]) -> Result<(), Self::Error> { if pipe > 5 { return Ok(()); } @@ -42,13 +40,13 @@ where self.spi_write_byte(registers::EN_RXADDR, out) } - fn open_tx_pipe(&mut self, address: &[u8]) -> Result<(), Self::PipeErrorType> { + fn open_tx_pipe(&mut self, address: &[u8]) -> Result<(), Self::Error> { self.spi_write_buf(registers::TX_ADDR, address)?; self.spi_write_buf(registers::RX_ADDR_P0, address) } /// If the given `pipe` number is not in range [0, 5], then this function does nothing. - fn close_rx_pipe(&mut self, pipe: u8) -> Result<(), Self::PipeErrorType> { + fn close_rx_pipe(&mut self, pipe: u8) -> Result<(), Self::Error> { if pipe > 5 { return Ok(()); } @@ -61,14 +59,14 @@ where Ok(()) } - fn set_address_length(&mut self, length: u8) -> Result<(), Self::PipeErrorType> { + fn set_address_length(&mut self, length: u8) -> Result<(), Self::Error> { let width = length.clamp(2, 5); self.spi_write_byte(registers::SETUP_AW, width - 2)?; self.feature.set_address_length(width); Ok(()) } - fn get_address_length(&mut self) -> Result { + fn get_address_length(&mut self) -> Result { self.spi_read(1, registers::SETUP_AW)?; let addr_length = self.buf[1].min(0xFD) + 2; self.feature.set_address_length(addr_length); diff --git a/crates/rf24-rs/src/radio/rf24/power.rs b/crates/rf24-rs/src/radio/rf24/power.rs index 9e1f42a..b57ac50 100644 --- a/crates/rf24-rs/src/radio/rf24/power.rs +++ b/crates/rf24-rs/src/radio/rf24/power.rs @@ -1,6 +1,10 @@ -use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; +use embedded_hal::{ + delay::DelayNs, + digital::{Error, OutputPin}, + spi::SpiDevice, +}; -use crate::radio::{prelude::EsbPower, Nrf24Error, RF24}; +use crate::radio::{prelude::EsbPower, RF24}; use super::registers; @@ -10,8 +14,6 @@ where DO: OutputPin, DELAY: DelayNs, { - type PowerErrorType = Nrf24Error; - /// After calling [`EsbRadio::as_rx()`](fn@crate::radio::prelude::EsbRadio::as_rx), /// a non-PA/LNA radio will consume about /// 13.5mA at [`PaLevel::MAX`](type@crate::types::PaLevel::Max). @@ -21,14 +23,14 @@ where /// will consume about 26uA (.026mA). /// In full power down mode (a sleep state), the radio will consume approximately /// 900nA (.0009mA). - fn power_down(&mut self) -> Result<(), Self::PowerErrorType> { - self.ce_pin.set_low().map_err(Nrf24Error::Gpo)?; // Guarantee CE is low on powerDown + fn power_down(&mut self) -> Result<(), Self::Error> { + self.ce_pin.set_low().map_err(|e| e.kind())?; // Guarantee CE is low on powerDown self.config_reg = self.config_reg.with_power(false); self.spi_write_byte(registers::CONFIG, self.config_reg.into_bits())?; Ok(()) } - fn power_up(&mut self, delay: Option) -> Result<(), Self::PowerErrorType> { + fn power_up(&mut self, delay: Option) -> Result<(), Self::Error> { // if not powered up then power up and wait for the radio to initialize if self.config_reg.power() { return Ok(()); diff --git a/crates/rf24-rs/src/radio/rf24/radio.rs b/crates/rf24-rs/src/radio/rf24/radio.rs index 67d7f49..da9d0a7 100644 --- a/crates/rf24-rs/src/radio/rf24/radio.rs +++ b/crates/rf24-rs/src/radio/rf24/radio.rs @@ -1,9 +1,13 @@ -use super::{commands, mnemonics, registers, Nrf24Error, RF24}; +use super::{commands, mnemonics, registers, RF24}; use crate::{ radio::prelude::{EsbFifo, EsbPayloadLength, EsbPipe, EsbRadio, EsbStatus}, StatusFlags, }; -use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; +use embedded_hal::{ + delay::DelayNs, + digital::{Error, OutputPin}, + spi::SpiDevice, +}; impl EsbRadio for RF24 where @@ -11,13 +15,11 @@ where DO: OutputPin, DELAY: DelayNs, { - type RadioErrorType = Nrf24Error; - - fn as_rx(&mut self) -> Result<(), Self::RadioErrorType> { + fn as_rx(&mut self) -> Result<(), Self::Error> { self.config_reg = self.config_reg.as_rx(); self.spi_write_byte(registers::CONFIG, self.config_reg.into_bits())?; self.clear_status_flags(StatusFlags::new())?; - self.ce_pin.set_high().map_err(Nrf24Error::Gpo)?; + self.ce_pin.set_high().map_err(|e| e.kind())?; // Restore the pipe0 address, if exists if let Some(addr) = self.pipe0_rx_addr { @@ -31,8 +33,8 @@ where Ok(()) } - fn as_tx(&mut self) -> Result<(), Self::RadioErrorType> { - self.ce_pin.set_low().map_err(Nrf24Error::Gpo)?; + fn as_tx(&mut self) -> Result<(), Self::Error> { + self.ce_pin.set_low().map_err(|e| e.kind())?; self.delay_impl.delay_ns(self.tx_delay * 1000); if self.feature.ack_payloads() { @@ -55,8 +57,8 @@ where /// /// This function calls [`RF24::flush_tx()`] upon entry, but it does not /// deactivate the radio's CE pin upon exit. - fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> Result { - self.ce_pin.set_low().map_err(Nrf24Error::Gpo)?; + fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> Result { + self.ce_pin.set_low().map_err(|e| e.kind())?; // this function only handles 1 payload at a time self.flush_tx()?; // flush the TX FIFO to ensure we are sending the given buf if !self.write(buf, ask_no_ack, true)? { @@ -81,15 +83,10 @@ where /// microseconds when using this function, thus non-blocking behavior. /// /// - fn write( - &mut self, - buf: &[u8], - ask_no_ack: bool, - start_tx: bool, - ) -> Result { + fn write(&mut self, buf: &[u8], ask_no_ack: bool, start_tx: bool) -> Result { if self.is_rx() { // check if in RX mode to prevent improper radio usage - return Err(Self::RadioErrorType::NotAsTxError); + return Err(Self::Error::NotAsTxError); } self.clear_status_flags(StatusFlags::from_bits( mnemonics::MASK_MAX_RT | mnemonics::MASK_TX_DS, @@ -98,25 +95,24 @@ where // TX FIFO is full already return Ok(false); } - let mut buf_len = buf.len().min(32) as u8; + let buf_len = buf.len().min(32); // to avoid resizing the given buf, we'll have to use self._buf directly self.buf[0] = if !ask_no_ack { commands::W_TX_PAYLOAD } else { commands::W_TX_PAYLOAD_NO_ACK }; - self.buf[1..(buf_len + 1) as usize].copy_from_slice(&buf[..buf_len as usize]); + self.buf[1..buf_len + 1].copy_from_slice(&buf[..buf_len]); // ensure payload_length setting is respected - if !self.feature.dynamic_payloads() && buf_len < self.payload_length { + if !self.feature.dynamic_payloads() && (buf_len as u8) < self.payload_length { // pad buf with zeros - for i in (buf_len + 1)..(self.payload_length + 1) { - self.buf[i as usize] = 0; - } - buf_len = self.payload_length; + self.buf[buf_len + 1..self.payload_length as usize + 1].fill(0); + self.spi_transfer(self.payload_length + 1)?; + } else { + self.spi_transfer(buf_len as u8 + 1)?; } - self.spi_transfer(buf_len + 1)?; if start_tx { - self.ce_pin.set_high().map_err(Nrf24Error::Gpo)?; + self.ce_pin.set_high().map_err(|e| e.kind())?; } Ok(true) } @@ -139,7 +135,7 @@ where /// padding for the data saved to the `buf` parameter's object. /// The nRF24L01 will repeatedly use the last byte from the last /// payload even when [`RF24::read()`] is called with an empty RX FIFO. - fn read(&mut self, buf: &mut [u8], len: Option) -> Result { + fn read(&mut self, buf: &mut [u8], len: Option) -> Result { let buf_len = (buf.len().min(32) as u8).min(len.unwrap_or(if self.feature.dynamic_payloads() { self.get_dynamic_payload_length()? @@ -150,15 +146,13 @@ where return Ok(0); } self.spi_read(buf_len, commands::R_RX_PAYLOAD)?; - for i in 0..buf_len { - buf[i as usize] = self.buf[i as usize + 1]; - } + buf[0..buf_len as usize].copy_from_slice(&self.buf[1..buf_len as usize + 1]); let flags = StatusFlags::from_bits(mnemonics::MASK_RX_DR); self.clear_status_flags(flags)?; Ok(buf_len) } - fn resend(&mut self) -> Result { + fn resend(&mut self) -> Result { if self.is_rx() { // if in RX mode, prevent infinite loop below return Ok(false); @@ -172,15 +166,16 @@ where Ok(self.status.tx_ds()) } - fn rewrite(&mut self) -> Result<(), Self::RadioErrorType> { - self.ce_pin.set_low().map_err(Nrf24Error::Gpo)?; + fn rewrite(&mut self) -> Result<(), Self::Error> { + self.ce_pin.set_low().map_err(|e| e.kind())?; let flags = StatusFlags::from_bits(mnemonics::MASK_TX_DS | mnemonics::MASK_MAX_RT); self.clear_status_flags(flags)?; self.spi_read(0, commands::REUSE_TX_PL)?; - self.ce_pin.set_high().map_err(Nrf24Error::Gpo) + self.ce_pin.set_high().map_err(|e| e.kind())?; + Ok(()) } - fn get_last_arc(&mut self) -> Result { + fn get_last_arc(&mut self) -> Result { self.spi_read(1, registers::OBSERVE_TX)?; Ok(self.buf[1] & 0xF) } diff --git a/crates/rf24-rs/src/radio/rf24/status.rs b/crates/rf24-rs/src/radio/rf24/status.rs index b863001..2927c26 100644 --- a/crates/rf24-rs/src/radio/rf24/status.rs +++ b/crates/rf24-rs/src/radio/rf24/status.rs @@ -1,7 +1,7 @@ use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; use crate::{ - radio::{prelude::EsbStatus, Nrf24Error, RF24}, + radio::{prelude::EsbStatus, RF24}, types::StatusFlags, }; @@ -13,9 +13,7 @@ where DO: OutputPin, DELAY: DelayNs, { - type StatusErrorType = Nrf24Error; - - fn set_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::StatusErrorType> { + fn set_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::Error> { self.spi_read(1, registers::CONFIG)?; self.config_reg = ConfigReg::from_bits( self.buf[1] & !StatusFlags::IRQ_MASK | (!flags.into_bits() & StatusFlags::IRQ_MASK), @@ -23,11 +21,11 @@ where self.spi_write_byte(registers::CONFIG, self.config_reg.into_bits()) } - fn clear_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::StatusErrorType> { + fn clear_status_flags(&mut self, flags: StatusFlags) -> Result<(), Self::Error> { self.spi_write_byte(registers::STATUS, flags.into_bits() & StatusFlags::IRQ_MASK) } - fn update(&mut self) -> Result<(), Self::StatusErrorType> { + fn update(&mut self) -> Result<(), Self::Error> { self.spi_read(0, commands::NOP) } diff --git a/crates/rf24ble-rs/src/radio.rs b/crates/rf24ble-rs/src/radio.rs index 9380753..919b64e 100644 --- a/crates/rf24ble-rs/src/radio.rs +++ b/crates/rf24ble-rs/src/radio.rs @@ -2,7 +2,11 @@ use crate::{ data_manipulation::{crc24_ble, reverse_bits, whiten}, services::BlePayload, }; -use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiDevice}; +use embedded_hal::{ + delay::DelayNs, + digital::{ErrorKind as OutputPinError, OutputPin}, + spi::{ErrorKind as SpiError, SpiDevice}, +}; use rf24::{ radio::{ prelude::{EsbChannel, EsbPaLevel, EsbRadio}, @@ -183,7 +187,7 @@ impl FakeBle { pub fn hop_channel( &self, radio: &mut RF24, - ) -> Result<(), Nrf24Error> + ) -> Result<(), Nrf24Error> where SPI: SpiDevice, DO: OutputPin, @@ -284,7 +288,7 @@ impl FakeBle { &self, radio: &mut RF24, buf: &[u8], - ) -> Result> + ) -> Result> where SPI: SpiDevice, DO: OutputPin, @@ -325,7 +329,7 @@ impl FakeBle { pub fn read( &self, radio: &mut RF24, - ) -> Result, Nrf24Error> + ) -> Result, Nrf24Error> where SPI: SpiDevice, DO: OutputPin,