diff --git a/src/config.rs b/src/config.rs index ee071a14ef11972f6c13590c1830dad03ffe580f..1ef9b9ac69c4d1446136ebed3db00ca556ee05dc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -250,7 +250,8 @@ pub const RADIO_CONFIG_500_4: [u8; 643] = [ 0xC, 0x11, 0x40, 0x8, 0x0, 0x3A, 0xC, 0xB1, 0x7E, 0x44, 0x44, 0x20, 0xFE, ]; -// 430.5 MHz +// 430.000 MHz @ channel 0 +// 430.500 MHZ @ channel 20 (default CATS frequency) // 9600 baud 2-FSK // Variable packet length up to 8191 bytes pub const RADIO_CONFIG_CATS: [u8; 644] = [ diff --git a/src/error.rs b/src/error.rs index 5e9b9b313652540bbd209c17f3f4eba07bc2c8a9..b7e422fbc6608845cd2664cbc6495516c4bc3e24 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,12 +23,21 @@ pub enum TransferError<SE: Debug> { SpiError(SE), } +#[derive(Debug)] +pub enum TxError<SE: Debug> { + // Given slice was bigger than the maximum packet size + TooMuchData, + SpiError(SE), +} + pub(crate) trait SpiErrorToOtherError<T, E: Debug> { fn re(self) -> Result<T, RfError<E>> where Self: Sized; fn te(self) -> Result<T, TransferError<E>>; + + fn txe(self) -> Result<T, TxError<E>>; } impl<T, E: Debug> SpiErrorToOtherError<T, E> for Result<T, E> { @@ -39,4 +48,8 @@ impl<T, E: Debug> SpiErrorToOtherError<T, E> for Result<T, E> { fn te(self) -> Result<T, TransferError<E>> { self.map_err(|e| TransferError::SpiError(e)) } + + fn txe(self) -> Result<T, TxError<E>> { + self.map_err(|e| TxError::SpiError(e)) + } } diff --git a/src/internal_state.rs b/src/internal_state.rs index 43dab00dfb6a93c4686fc49ae3588b3ffe5c2974..3bdb772f50b7330dd79c4ec4a0823c9342d4c71c 100644 --- a/src/internal_state.rs +++ b/src/internal_state.rs @@ -11,5 +11,6 @@ pub enum InternalState<const PACKET_LEN: usize> { Tx { data: [u8; PACKET_LEN], i: usize, + len: usize, }, } diff --git a/src/lib.rs b/src/lib.rs index afcf228a6d64139e1c8bbbf6a6c399b351126d87..6fcc0faaaf3f54488de62b23400ed995cc8f22e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ mod consts; pub mod error; mod internal_radio; mod internal_state; +pub mod rx; pub(crate) mod state; use core::{convert::Infallible, fmt::Debug}; @@ -14,25 +15,27 @@ use embedded_hal::{ }; use consts::*; -use error::{RfError, SpiErrorToOtherError, TransferError}; +use error::{RfError, SpiErrorToOtherError, TransferError, TxError}; use internal_state::InternalState; +use rx::RxPacket; use state::State; use crate::internal_radio::InternalRadio; -pub struct Rf4463<const PACKET_LEN: usize, Spi, SdnPin, CsPin, Delay> { +pub struct Rf4463<const MAX_PACKET_LEN: usize, Spi, SdnPin, CsPin, Delay> { radio: InternalRadio<Spi, SdnPin, CsPin, Delay>, - state: InternalState<PACKET_LEN>, + state: InternalState<MAX_PACKET_LEN>, rx_forever: bool, + channel: u8, } impl< - const PACKET_LEN: usize, + const MAX_PACKET_LEN: usize, Spi: Transfer<u8>, SdnPin: OutputPin<Error = Infallible>, CsPin: OutputPin<Error = Infallible>, Delay: DelayUs<u16>, - > Rf4463<PACKET_LEN, Spi, SdnPin, CsPin, Delay> + > Rf4463<MAX_PACKET_LEN, Spi, SdnPin, CsPin, Delay> where Spi::Error: Debug, { @@ -44,7 +47,7 @@ where config: &mut [u8], ) -> Result<Self, RfError<Spi::Error>> { assert!( - PACKET_LEN < 8192, + MAX_PACKET_LEN < 8192, "Packet length cannot be above 8191 bytes" ); @@ -54,6 +57,7 @@ where radio: InternalRadio::new(spi, sdn, cs, delay, config)?, state: InternalState::Idle, rx_forever: false, + channel: 0, }) } @@ -69,16 +73,23 @@ where self.radio.get_rssi() } + pub fn set_channel(&mut self, channel: u8) { + self.channel = channel; + } + pub fn is_idle(&mut self) -> bool { matches!(self.state, InternalState::Idle) } - pub fn start_rx(&mut self, rx_forever: bool) -> Result<(), Spi::Error> { + // Len is none when using a variable-length packet + pub fn start_rx(&mut self, len: Option<usize>, rx_forever: bool) -> Result<(), Spi::Error> { self.radio.clear_fifo()?; self.radio.clear_ph_and_modem_interrupts()?; + let len = len.unwrap_or(0); + self.state = InternalState::Rx { - data: [0; PACKET_LEN], + data: [0; MAX_PACKET_LEN], i: 0, received: false, rssi: None, @@ -86,10 +97,10 @@ where self.radio.send_command::<0>(&mut [ START_RX, + self.channel, 0, - 0, - (PACKET_LEN >> 8).try_into().unwrap(), - (PACKET_LEN & 0xff).try_into().unwrap(), + (len >> 8).try_into().unwrap(), + (len & 0xff).try_into().unwrap(), State::Rx.into(), if rx_forever { State::Rx.into() @@ -104,26 +115,26 @@ where Ok(()) } - pub fn finish_rx(&mut self) -> Result<Option<([u8; PACKET_LEN], f64)>, Spi::Error> { + pub fn finish_rx(&mut self) -> Result<Option<RxPacket<MAX_PACKET_LEN>>, Spi::Error> { let pkt = match self.state { InternalState::Rx { data, received, i, rssi, - } if i == PACKET_LEN && received => { + } if received => { let rssi = match rssi { Some(x) => x, None => self.get_rssi()?, }; - let ret = Some((data, rssi)); + let ret = Some(RxPacket::new(data, i, rssi)); if self.rx_forever { self.radio.clear_ph_and_modem_interrupts()?; self.state = InternalState::Rx { - data: [0; PACKET_LEN], + data: [0; MAX_PACKET_LEN], i: 0, received: false, rssi: None, @@ -141,31 +152,46 @@ where Ok(pkt) } - pub fn start_tx(&mut self, mut data: [u8; PACKET_LEN]) -> Result<(), Spi::Error> { - self.radio.clear_fifo()?; - self.radio.clear_ph_and_modem_interrupts()?; + pub fn start_tx(&mut self, data: &[u8]) -> Result<(), TxError<Spi::Error>> { + let len = data.len(); + if len > MAX_PACKET_LEN { + return Err(TxError::TooMuchData); + } + + self.radio.clear_fifo().txe()?; + self.radio.clear_ph_and_modem_interrupts().txe()?; // 128-byte TX buffer let i = data.len().min(128); + let mut segment = [0; 128]; + segment[..i].copy_from_slice(&data[..i]); self.radio.with_cs(|s| { - s.spi_transfer_byte(WRITE_TX_FIFO)?; - s.spi.transfer(&mut data[0..i])?; + s.spi_transfer_byte(WRITE_TX_FIFO).txe()?; + s.spi.transfer(&mut segment[..i]).txe()?; Ok(()) })?; - self.radio.send_command::<0>(&mut [ - START_TX, - 0, - u8::from(State::Sleep) << 4, - (PACKET_LEN >> 8).try_into().unwrap(), - (PACKET_LEN & 0xff).try_into().unwrap(), - 0, - 0, - ])?; - - self.state = InternalState::Tx { data, i }; + self.radio + .send_command::<0>(&mut [ + START_TX, + self.channel, + u8::from(State::Sleep) << 4, + (len >> 8).try_into().unwrap(), + (len & 0xff).try_into().unwrap(), + 0, + 0, + ]) + .txe()?; + + let mut padded_data = [0; MAX_PACKET_LEN]; + padded_data[0..len].copy_from_slice(data); + self.state = InternalState::Tx { + data: padded_data, + i, + len, + }; Ok(()) } @@ -219,12 +245,12 @@ where _ => return Ok(()), }; - let len: usize = self.radio.rx_fifo_len().te()?.into(); - if len == 0 { + let fifo_len: usize = self.radio.rx_fifo_len().te()?.into(); + if fifo_len == 0 { return Ok(()); } - if len + *i > PACKET_LEN { + if fifo_len + *i > MAX_PACKET_LEN { return Err(TransferError::TooMuchData); } @@ -232,7 +258,7 @@ where return Err(TransferError::FifoOverflow); } - let data = &mut data[*i..(*i + len)]; + let data = &mut data[*i..(*i + fifo_len)]; self.radio .with_cs(|s| { s.spi_transfer_byte(READ_RX_FIFO)?; @@ -246,14 +272,14 @@ where *rssi = Some(self.radio.get_rssi().te()?) } - *i += len; + *i += fifo_len; Ok(()) } fn tx_step(&mut self) -> Result<(), TransferError<Spi::Error>> { let (data, i) = match &mut self.state { - InternalState::Tx { data, i, .. } => (data, i), + InternalState::Tx { data, i, len } => (&mut data[0..*len], i), _ => return Ok(()), }; diff --git a/src/rx.rs b/src/rx.rs new file mode 100644 index 0000000000000000000000000000000000000000..7677257b55524951e854a5222fb8619ba57d47fc --- /dev/null +++ b/src/rx.rs @@ -0,0 +1,20 @@ +#[derive(Debug, Clone)] +pub struct RxPacket<const N: usize> { + data: [u8; N], + i: usize, + rssi: f64, +} + +impl<const N: usize> RxPacket<N> { + pub(crate) fn new(data: [u8; N], i: usize, rssi: f64) -> Self { + Self { data, i, rssi } + } + + pub fn data(&self) -> &[u8] { + &self.data[..self.i] + } + + pub fn rssi(&self) -> f64 { + self.rssi + } +}