1use core::fmt::Debug;
2use core::marker::PhantomData;
3
4use embedded_hal::delay::blocking::DelayUs;
5use log::{debug, warn};
6
7
8use radio::{BasicInfo, Channel as _, Interrupts, Registers as _, State as _};
9
10pub mod base;
11pub mod device;
12pub mod prelude;
13
14use base::Base;
15use device::*;
16
17pub use device::CHANNELS;
18
19pub struct At86Rf23x<B: Base> {
21 hal: B,
22 auto_crc: bool,
23}
24
25#[derive(Clone, PartialEq, Debug)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub struct Config {
30 pub xtal_mode: XtalMode,
31 pub channel: Ch,
32 pub auto_crc: bool,
33}
34
35impl Default for Config {
36 fn default() -> Self {
37 Self {
38 xtal_mode: XtalMode::InternalOscillator,
39 channel: Ch {
40 bitrate: OqpskDataRate::D250kbps,
41 channel: CHANNELS[0],
42 },
43 auto_crc: true,
44 }
45 }
46}
47
48#[derive(Debug, Clone, PartialEq)]
50#[cfg_attr(feature = "thiserror", derive(thiserror::Error))]
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum Error<SpiErr: Debug, PinErr: Debug, DelayErr: Debug> {
54 #[error("SPI error: {0}")]
55 Spi(SpiErr),
57
58 #[error("Pin error: {0}")]
59 Pin(PinErr),
61
62 #[error("Delay error: {0}")]
63 Delay(DelayErr),
65
66 #[error("Unsupported state command")]
67 Unsupported,
69
70 #[error("No response from device")]
71 NoResponse,
73
74 #[error("Unexpected register value (reg: 0x{0:02x} val: 0x:{1:02x}")]
75 UnexpectedValue(u8, u8),
77
78 #[cfg(feature="common-modulation")]
79 #[error("Unsupported modulation configuration")]
80 Modulation(radio::modulation::ModError),
82}
83
84#[cfg(feature="common-modulation")]
85impl <SpiErr: Debug, PinErr: Debug, DelayErr: Debug> From<radio::modulation::ModError> for Error<B::SpiErr, B::PinErr, B::DelayErr> {
86 fn from(m: radio::modulation::ModError) -> Self {
87 Error::Modulation(m)
88 }
89}
90
91#[derive(Copy, Clone, PartialEq, Debug, strum_macros::Display)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub enum State {
95 Init,
96 Idle,
97 PllOn,
98 BusyTx,
99 RxOn,
100 BusyRx,
101 Sleep,
102 Busy,
103}
104
105impl radio::RadioState for State {
106 fn idle() -> Self {
107 State::Idle
108 }
109
110 fn sleep() -> Self {
111 State::Sleep
112 }
113}
114
115#[derive(Debug, Clone, PartialEq)]
117pub struct Info {
118 pub part: Part,
119 pub ver: u8,
120 pub mfr: u16,
121}
122
123impl<B> At86Rf23x<B>
124where
125 B: Base,
126{
127 pub fn new(hal: B, config: Config) -> Result<Self, Error<B::SpiErr, B::PinErr, B::DelayErr>> {
128 let mut s = Self {
129 hal,
130 auto_crc: config.auto_crc,
131 };
132
133 debug!("Connecting to device");
134
135 s.hal.slp_tr(false)?;
137
138 s.hal.reset()?;
140
141 s.write_register::<TrxCmd>(TrxCmd::TrxOff)?;
145
146 let i = s.info()?;
150 if i.part == Part::None && i.ver == 0 && i.mfr == 0 {
151 warn!("Init failed, communication error");
152 return Err(Error::NoResponse);
153 }
154
155 s.set_channel(&config.channel)?;
161
162 s.update_register::<XahCtrl1, _>(|r| r.with_aack_prom_mode(true))?;
166
167 if s.auto_crc {
168 s.update_register::<TrxCtrl1, _>(|r| r.with_tx_auto_crc_on(true))?;
170 }
171
172 s.update_register::<TrxCtrl2, _>(|r| r.with_rx_safe_mode(true))?;
174
175 debug!("Device info: {:02x?}", i);
176
177 Ok(s)
178 }
179
180 pub fn info(&mut self) -> Result<Info, Error<B::SpiErr, B::PinErr, B::DelayErr>> {
182 let i = Info {
183 part: self.read_register::<PartNum>().map(|p| p.part())?,
184 ver: self.read_register::<VersionNum>()?.into(),
185 mfr: u16::from_le_bytes([
186 self.read_register::<ManId0>()?.into(),
187 self.read_register::<ManId1>()?.into(),
188 ]),
189 };
190 Ok(i)
191 }
192
193 pub fn set_pan_id(&mut self, pan_id: u16) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
195 let b = pan_id.to_le_bytes();
196 self.write_register::<PanId0>(b[0].into())?;
197 self.write_register::<PanId1>(b[1].into())?;
198 Ok(())
199 }
200
201 pub fn set_short_addr(&mut self, short_addr: u16) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
203 let b = short_addr.to_le_bytes();
204 self.write_register::<ShortAddr0>(b[0].into())?;
205 self.write_register::<ShortAddr1>(b[1].into())?;
206 Ok(())
207 }
208
209 pub fn set_long_addr(&mut self, long_addr: u64) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
211 let b = long_addr.to_le_bytes();
212 self.write_register::<IeeeAddr0>(b[0].into())?;
213 self.write_register::<IeeeAddr1>(b[1].into())?;
214 self.write_register::<IeeeAddr2>(b[2].into())?;
215 self.write_register::<IeeeAddr3>(b[3].into())?;
216 self.write_register::<IeeeAddr0>(b[4].into())?;
217 self.write_register::<IeeeAddr1>(b[5].into())?;
218 self.write_register::<IeeeAddr2>(b[6].into())?;
219 self.write_register::<IeeeAddr3>(b[7].into())?;
220 Ok(())
221 }
222
223 pub fn fifo_write(&mut self, data: &[u8]) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
225 self.hal.spi_write(&[CommandFlags::BUFF_WR.bits()], data)
226 }
227
228 pub fn fifo_read(&mut self, data: &mut [u8]) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
230 self.hal.spi_read(&[CommandFlags::BUFF_RD.bits()], data)
231 }
232
233 pub fn sram_write(
235 &mut self,
236 offset: u8,
237 data: &[u8],
238 ) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
239 self.hal
240 .spi_write(&[CommandFlags::SRAM_WR.bits(), offset], data)
241 }
242
243 pub fn sram_read(
245 &mut self,
246 offset: u8,
247 data: &mut [u8],
248 ) -> Result<(), Error<B::SpiErr, B::PinErr, B::DelayErr>> {
249 self.hal
250 .spi_read(&[CommandFlags::SRAM_RD.bits(), offset], data)
251 }
252}
253
254impl<B> radio::Registers<u8> for At86Rf23x<B>
255where
256 B: Base,
257{
258 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
259
260 fn read_register<R: radio::Register<Word = u8>>(&mut self) -> Result<R, Self::Error> {
262 let mut d = [0u8];
263 self.hal
264 .spi_read(&[R::ADDRESS as u8 | CommandFlags::REG_RD.bits()], &mut d)?;
265
266 R::try_from(d[0]).map_err(|_e| Error::UnexpectedValue(R::ADDRESS, d[0]))
267 }
268
269 fn write_register<R: radio::Register<Word = u8>>(
271 &mut self,
272 value: R,
273 ) -> Result<(), Self::Error> {
274 self.hal.spi_write(
275 &[R::ADDRESS as u8 | CommandFlags::REG_WR.bits()],
276 &[value.into()],
277 )
278 }
279}
280
281impl<B> radio::Registers<u16> for At86Rf23x<B>
282where
283 B: Base,
284{
285 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
286
287 fn read_register<R: radio::Register<Word = u16>>(&mut self) -> Result<R, Self::Error> {
289 let mut r = [0u8, 0u8];
290 self.hal
291 .spi_read(&[R::ADDRESS as u8 | CommandFlags::REG_RD.bits()], &mut r)?;
292
293 let d = u16::from_le_bytes(r);
294
295 R::try_from(d).map_err(|_e| Error::UnexpectedValue(R::ADDRESS, r[0]))
296 }
297
298 fn write_register<R: radio::Register<Word = u16>>(
300 &mut self,
301 value: R,
302 ) -> Result<(), Self::Error> {
303 let v = u16::to_le_bytes(value.into());
304
305 self.hal
306 .spi_write(&[R::ADDRESS as u8 | CommandFlags::REG_WR.bits()], &v)
307 }
308}
309
310impl<B> radio::State for At86Rf23x<B>
311where
312 B: Base,
313{
314 type State = State;
315 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
316
317 fn set_state(&mut self, s: State) -> Result<(), Self::Error> {
318 let v = match s {
320 State::Idle => TrxCmd::ForceTrxOff,
321 State::PllOn => TrxCmd::PllOn,
322 State::RxOn => TrxCmd::RxOn,
323 State::Sleep => todo!("Set slp_tr high to sleep"),
324 _ => return Err(Error::Unsupported),
326 };
327
328 debug!("Set state cmd: {:?} (requested: {:?})", v, s);
329
330 self.write_register::<TrxCmd>(v)?;
334
335 Ok(())
336 }
337
338 fn get_state(&mut self) -> Result<Self::State, Self::Error> {
339 use TrxStatus::*;
340
341 let trx_status = self.read_register::<TrxStatus>()?;
343
344 let s = match trx_status {
346 POn => State::Init,
347 BusyRx | BusyRxAack => State::BusyRx,
348 BusyTx | BusyTxAret => State::BusyTx,
349 RxOn => State::RxOn,
350 TrxOff => State::Idle,
351 PllOn => State::PllOn,
352 Sleep | PrepDeepSleep => State::Sleep,
353 RxAackOn => State::BusyRx,
354 TxAretOn => State::BusyTx,
355 StateTransition => State::Busy,
356 };
357
358 debug!("TRX status: {:?} state: {:?}", trx_status, s);
359
360 Ok(s)
361 }
362}
363
364impl<B> radio::Interrupts for At86Rf23x<B>
365where
366 B: Base,
367{
368 type Irq = Irqs;
369 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
370
371 fn get_interrupts(&mut self, _: bool) -> Result<Self::Irq, Self::Error> {
373 let irqs = self.read_register::<Irqs>()?;
374
375 if !irqs.is_empty() {
376 debug!("IRQs: {:?}", irqs);
377 }
378
379 Ok(irqs)
380 }
381}
382
383#[derive(Copy, Clone, PartialEq, Debug)]
385#[cfg_attr(feature = "defmt", derive(defmt::Format))]
386pub struct Ch {
387 pub bitrate: OqpskDataRate,
389 pub channel: Channel,
391}
392
393#[cfg(feature="common-modulation")]
394impl TryFrom<radio::modulation::gfsk::GfskChannel> for Ch {
395 type Error = radio::modulation::ModError;
396
397 fn try_from(ch: radio::modulation::gfsk::GfskChannel) -> Result<Self, Self::Error> {
398 use radio::modulation::ModError;
399
400 let bitrate = OqpskDataRate::try_from(ch.bitrate_bps)
401 .map_err(|_| ModError::UnsupportedBitrate)?;
402
403 let channel = Channel::try_from(ch.freq_khz)
404 .map_err(|_| ModError::UnsupportedFrequency)?;
405
406 if ch.bw_khz != 5 {
407 return Err(ModError::UnsupportedBandwidth);
408 }
409
410 Ok(Ch{ bitrate, channel })
411 }
412}
413
414impl<B> radio::Channel for At86Rf23x<B>
415where
416 B: Base,
417{
418 type Channel = Ch;
419 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
420
421 fn set_channel(&mut self, ch: &Ch) -> Result<(), Self::Error> {
422 self.set_state(State::PllOn)?;
424
425 self.update_register::<PhyCcCca, _>(|r| r.with_channel(ch.channel))?;
429
430 self.update_register::<TrxCtrl2, _>(|r| r.with_oqpsk_data_rate(ch.bitrate))?;
432
433 Ok(())
434 }
435}
436
437impl<B> DelayUs for At86Rf23x<B>
438where
439 B: Base,
440{
441 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
442
443 fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
444 self.hal.delay_us(us)
445 }
446}
447
448impl<B> radio::Power for At86Rf23x<B>
449where
450 B: Base,
451{
452 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
453
454 fn set_power(&mut self, _power: i8) -> Result<(), Self::Error> {
455 let p = Power::P4dBm;
457
458 self.update_register::<PhyTxPwr, _>(|r| r.with_tx_pwr(p))?;
460
461 Ok(())
462 }
463}
464
465impl<B> radio::Rssi for At86Rf23x<B>
466where
467 B: Base,
468{
469 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
470
471 fn poll_rssi(&mut self) -> Result<i16, Self::Error> {
472 let r = self.read_register::<PhyRssi>()?;
473 Ok(-94 + r.rssi() as i16 * 3)
474 }
475}
476impl<B> radio::Transmit for At86Rf23x<B>
477where
478 B: Base,
479{
480 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
481
482 fn start_transmit(&mut self, data: &[u8]) -> Result<(), Self::Error> {
483 self.set_state(State::PllOn)?;
485
486 debug!("TX data: {:02x?}", data);
490
491 let mut len = data.len() as u8;
493 if self.auto_crc {
494 len += 2;
495 }
496
497 self.sram_write(0, &[len])?;
499
500 self.sram_write(1, data)?;
502
503 if self.auto_crc {
505 let crc = [0xFFu8; 2];
506 self.sram_write(1 + data.len() as u8, &crc)?;
507 }
508
509 let irqs = Irqs::TRX_END | Irqs::TRX_UR | Irqs::AMI;
511 self.write_register::<IrqMask>(irqs.bits().into())?;
512 let _ = self.get_interrupts(true)?;
513
514 debug!("Entering TX state");
515
516 self.write_register::<TrxCmd>(TrxCmd::TxStart)?;
518
519 Ok(())
520 }
521
522 fn check_transmit(&mut self) -> Result<bool, Self::Error> {
523 if !self.hal.irq()? {
526 return Ok(false);
527 }
528
529 let irqs = self.read_register::<Irqs>()?;
531
532 if !irqs.is_empty() {
533 debug!("TX IRQs: {:?}", irqs);
534 }
535
536 if irqs.contains(Irqs::TRX_END) {
538 debug!("TX complete");
539 Ok(true)
540 } else {
541 Ok(false)
542 }
543 }
544}
545
546impl<B> radio::Receive for At86Rf23x<B>
547where
548 B: Base,
549{
550 type Error = Error<B::SpiErr, B::PinErr, B::DelayErr>;
551
552 type Info = BasicInfo;
553
554 fn start_receive(&mut self) -> Result<(), Self::Error> {
555 self.set_state(State::PllOn)?;
558
559 let irqs = Irqs::RX_START | Irqs::TRX_END | Irqs::TRX_UR | Irqs::AMI;
561 self.write_register::<IrqMask>(irqs.bits().into())?;
562 let _ = self.get_interrupts(true)?;
563
564 debug!("Entering RX state");
565
566 self.write_register::<TrxCmd>(TrxCmd::RxOn)?;
568
569 Ok(())
570 }
571
572 fn check_receive(&mut self, _restart: bool) -> Result<bool, Self::Error> {
574 if !self.hal.irq()? {
577 return Ok(false);
578 }
579
580 let irqs = self.read_register::<Irqs>()?;
582
583 if !irqs.is_empty() {
584 debug!("RX IRQs: {:?}", irqs);
585 }
586
587 if irqs.contains(Irqs::TRX_END) {
589 debug!("RX complete");
590 Ok(true)
591
592 } else if irqs.contains(Irqs::TRX_UR) {
596 todo!()
597
598 } else if irqs.contains(Irqs::RX_START) {
600 debug!("RX start");
601 Ok(true)
602
603 } else {
605 Ok(false)
606 }
607 }
608
609 fn get_received(&mut self, buff: &mut [u8]) -> Result<(usize, Self::Info), Self::Error> {
610 let ed = self.read_register::<PhyEdLevel>()?;
612 let info = if ed.ed_level() < 0x54 {
613 BasicInfo::new(-94 + ed.ed_level() as i16, u16::MIN)
614 } else {
615 BasicInfo::default()
616 };
617
618 self.sram_read(0, &mut buff[..1])?;
623 let n = buff[0] as usize;
624
625 self.sram_read(1, &mut buff[1..][..n])?;
627
628 Ok((n, info))
632 }
633}
634#[cfg(test)]
635mod tests {
636 #[test]
637 fn it_works() {
638 let result = 2 + 2;
639 assert_eq!(result, 4);
640 }
641}