Newer
Older
use embedded_hal::{
blocking::{delay::DelayUs, spi::Transfer},
digital::v2::OutputPin,
};
use crate::{
consts::*,
error::{BusError, BusErrorToOtherError, RfError, SpiErrorToOtherError},
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
state::State,
};
use core::{convert::Infallible, fmt::Debug};
pub(crate) struct InternalRadio<SdnPin, CsPin, Delay> {
sdn: SdnPin,
cs: CsPin,
delay: Delay,
}
impl<
SdnPin: OutputPin<Error = Infallible>,
CsPin: OutputPin<Error = Infallible>,
Delay: DelayUs<u16>,
> InternalRadio<SdnPin, CsPin, Delay>
{
pub fn new<Spi: Transfer<u8>>(
spi: &mut Spi,
sdn: SdnPin,
mut cs: CsPin,
delay: Delay,
config: &mut [u8],
) -> Result<Self, RfError<Spi::Error>>
where
Spi::Error: Debug,
{
cs.set_high().unwrap();
let mut s = Self { sdn, cs, delay };
s.reset();
s.configure(spi, config).re()?;
s.clear_interrupts(spi).re()?;
s.enable_interrupts(spi).re()?;
s.sleep(spi)?;
Ok(s)
}
fn reset(&mut self) {
self.sdn.set_high().unwrap();
self.delay.delay_us(50_000);
self.sdn.set_low().unwrap();
self.delay.delay_us(50_000);
}
pub fn sleep<Spi: Transfer<u8>>(&mut self, spi: &mut Spi) -> Result<(), RfError<Spi::Error>>
where
Spi::Error: Debug,
{
if self.get_state(spi)? != State::Tx {
self.set_state(spi, State::Sleep).re()?;
}
Ok(())
}
pub fn get_state<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<State, RfError<Spi::Error>>
where
Spi::Error: Debug,
{
let resp = self.send_command::<_, 1>(spi, &mut [READ_FRR_B]).re()?[0];
Ok(resp.try_into()?)
}
pub fn set_state<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
s: State,
) -> Result<(), BusError<Spi::Error>>
where
Spi::Error: Debug,
{
self.send_command::<_, 0>(spi, &mut [CHANGE_STATE, s.into()])?;
Ok(())
}
pub fn get_temp<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<f32, BusError<Spi::Error>> {
let result: f32 = self.get_adc(spi, ADC_CONV_TEMP, ADC_SPEED << 4, 4)?.into();
Ok(899.0 * result / 4096.0 - 293.0)
}
pub fn get_rssi<Spi: Transfer<u8>>(&mut self, spi: &mut Spi) -> Result<f64, Spi::Error> {
let frr = self.read_frr(spi)?;
Ok((frr[0] as f64) / 2.0 - 136.0)
}
fn configure<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
config: &mut [u8],
let mut i = 0;
while i < config.len() {
let l: usize = config[i].into();
self.send_command::<_, 0>(spi, &mut config[(i + 1)..(i + 1 + l)])?;
i += l + 1;
}
Ok(())
}
fn clear_interrupts<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<(), BusError<Spi::Error>> {
self.send_command::<_, 8>(spi, &mut [GET_INT_STATUS])?;
Ok(())
}
fn enable_interrupts<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<(), BusError<Spi::Error>> {
self.send_command::<_, 0>(
spi,
&mut [SET_PROPERTY, 0x01, 2, 0x00, 0b00000001, 0b00110011],
)?;
Ok(())
}
pub fn clear_ph_and_modem_interrupts<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
self.send_command::<_, 0>(spi, &mut [GET_INT_STATUS, 0, 0, 0xFF])?;
Ok(())
}
// also clears the interrupt
pub fn packet_received_pending<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
let ph_pend =
self.send_command::<_, 3>(spi, &mut [GET_INT_STATUS, 0xFF ^ (1 << 4), 0xFF, 0xFF])?[2];
Ok((ph_pend & (1 << 4)) != 0)
}
// also clears the interrupt
pub fn packet_sent_pending<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
let ph_pend =
self.send_command::<_, 3>(spi, &mut [GET_INT_STATUS, 0xFF ^ (1 << 5), 0xFF, 0xFF])?[2];
Ok((ph_pend & (1 << 5)) != 0)
}
// also clears the interrupt
pub fn fifo_underflow_pending<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
let ch_pend =
self.send_command::<_, 7>(spi, &mut [GET_INT_STATUS, 0xFF, 0xFF, 0xFF ^ (1 << 5)])?[6];
Ok(ch_pend & (1 << 5) != 0)
}
pub fn tx_fifo_space<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<u8, BusError<Spi::Error>> {
let fifo = self.send_command::<_, 2>(spi, &mut [FIFO_INFO, 0])?;
Ok(fifo[1])
}
pub fn rx_fifo_len<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<u8, BusError<Spi::Error>> {
let fifo = self.send_command::<_, 2>(spi, &mut [FIFO_INFO, 0])?;
Ok(fifo[0])
}
pub fn clear_fifo<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
) -> Result<(), BusError<Spi::Error>> {
self.send_command::<_, 0>(spi, &mut [FIFO_INFO, FIFO_CLEAR_RX | FIFO_CLEAR_TX])?;
Ok(())
}
fn get_adc<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
en: u8,
cfg: u8,
part: usize,
let data: [_; 6] = self.send_command(spi, &mut [GET_ADC_READING, en, cfg])?;
Ok((u16::from(data[part]) << 8) | u16::from(data[part + 1]))
}
pub fn send_command<Spi: Transfer<u8>, const NUM_BYTES_OUT: usize>(
&mut self,
spi: &mut Spi,
command: &mut [u8],
) -> Result<[u8; NUM_BYTES_OUT], BusError<Spi::Error>> {
Ok(())
})?;
// Keep trying to read 1 byte until we get 0xFF
// At that point, the SI4463 is ready to dump the bytes we care about
// If we get back something other than 0xFF, toggle the CS line
// and try again
let mut attempts = 0;
while attempts < MAX_ATTEMPTS {
// TODO I don't think we're supposed to send this command on every check?
// Should be leaving the cs line high and continuously polling for when we get 0xFF back
// but it seems to work
s.spi_transfer_byte(spi, READ_CMD_BUF).be()?;
if s.spi_transfer_byte(spi, 0xFF).be()? != 0xFF {
return Ok(None);
}
let mut out = [0xFF; NUM_BYTES_OUT];
Ok(Some(out))
})? {
return Ok(out);
}
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
}
fn read_frr<Spi: Transfer<u8>>(&mut self, spi: &mut Spi) -> Result<[u8; 4], Spi::Error> {
self.with_cs(|s| {
s.spi_transfer_byte(spi, FRR_A_READ)?;
let mut out = [0xFF; 4];
spi.transfer(&mut out)?;
Ok(out)
})
}
pub fn spi_transfer_byte<Spi: Transfer<u8>>(
&mut self,
spi: &mut Spi,
byte: u8,
) -> Result<u8, Spi::Error> {
let mut buf = [byte];
let buf = spi.transfer(&mut buf)?;
Ok(buf[0])
}
// set the CS line low. Run the closure. Set it high
pub fn with_cs<T, F: FnMut(&mut Self) -> T>(&mut self, mut f: F) -> T {
self.cs.set_low().unwrap();
self.delay.delay_us(1);
let ret = f(self);
self.cs.set_high().unwrap();
self.delay.delay_us(1);
ret
}
}