rktk_drivers_nrf/esb/
dongle.rs1use core::{marker::PhantomData, sync::atomic::AtomicBool};
2
3use embassy_nrf::{
4 interrupt::{self, typelevel::Binding},
5 pac::Interrupt,
6 radio::{self},
7 timer,
8};
9use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
10use esb_ng::{
11 EsbApp, EsbBuffer, EsbIrq, IrqTimer, irq::StatePRX, payload::BBQueueType,
12 peripherals::PtrTimer as _,
13};
14use rktk::drivers::interface::dongle::{DongleData, DongleDriver, DongleDriverBuilder};
15use rktk_log::helper::Debug2Format;
16
17use super::Config;
18
19macro_rules! use_peripheral {
20 ($radio:ident, $timer:ident, $esb_timer:ident) => {
21 type DongleRadio = embassy_nrf::peripherals::$radio;
22 const DONGLE_RADIO_PAC: embassy_nrf::pac::radio::Radio = embassy_nrf::pac::$radio;
23 type DongleTimer = embassy_nrf::peripherals::$timer;
24 type DongleTimerEsb = esb_ng::peripherals::$esb_timer;
25 };
26}
27
28use_peripheral!(RADIO, TIMER0, Timer0);
29
30static IRQ_TIMER: Mutex<CriticalSectionRawMutex, Option<IrqTimer<DongleTimerEsb>>> =
31 Mutex::new(None);
32
33pub struct TimerInterruptHandler {
34 _phantom: PhantomData<()>,
35}
36
37impl interrupt::typelevel::Handler<<DongleTimer as timer::Instance>::Interrupt>
38 for TimerInterruptHandler
39{
40 unsafe fn on_interrupt() {
41 if let Ok(mut irq_timer) = IRQ_TIMER.try_lock()
42 && let Some(irq_timer) = &mut *irq_timer
43 {
44 irq_timer.timer_interrupt();
45 }
46 }
47}
48
49static ESB_IRQ: Mutex<
50 CriticalSectionRawMutex,
51 Option<EsbIrq<1024, 1024, DongleTimerEsb, StatePRX>>,
52> = Mutex::new(None);
53
54pub struct EsbInterruptHandler {
55 _phantom: PhantomData<()>,
56}
57
58impl interrupt::typelevel::Handler<<DongleRadio as radio::Instance>::Interrupt>
59 for EsbInterruptHandler
60{
61 unsafe fn on_interrupt() {
62 if let Ok(mut esb_irq) = ESB_IRQ.try_lock()
63 && let Some(esb_irq) = &mut *esb_irq
64 && let Err(e) = esb_irq.radio_interrupt()
65 {
66 rktk_log::warn!("Irq error: {:?}", Debug2Format(&e));
67 }
68 }
69}
70
71pub struct EsbDongleDriverBuilder {
74 _timer: DongleTimer,
75 _radio: DongleRadio,
76 config: Config,
77}
78
79impl EsbDongleDriverBuilder {
80 pub fn new(
81 timer: DongleTimer,
82 radio: DongleRadio,
83 _irqs: impl Binding<<DongleTimer as timer::Instance>::Interrupt, TimerInterruptHandler>,
84 config: Config,
85 ) -> Self {
86 Self { _timer: timer, _radio: radio, config }
87 }
88}
89
90impl DongleDriverBuilder for EsbDongleDriverBuilder {
91 type Output = EsbDongleDriver;
92
93 type Error = &'static str;
94
95 async fn build(self) -> Result<(Self::Output, impl Future<Output = ()>), Self::Error> {
96 static BUFFER: EsbBuffer<1024, 1024> = EsbBuffer {
97 app_to_radio_buf: BBQueueType::new(),
98 radio_to_app_buf: BBQueueType::new(),
99 timer_flag: AtomicBool::new(false),
100 };
101 let config =
102 self.config.config.max_payload_size(192).check().map_err(|_| "Invalid config")?;
103 let (esb_app, esb_irq, esb_timer) = BUFFER
104 .try_split(
105 unsafe { DongleTimerEsb::take() },
106 DONGLE_RADIO_PAC,
107 self.config.addresses,
108 config,
109 )
110 .map_err(|_| "Failed to initialize")?;
111 let mut esb_irq = esb_irq.into_prx();
112 esb_irq.start_receiving().map_err(|_| "Failed to start receiving")?;
113 ESB_IRQ.lock().await.replace(esb_irq);
114 IRQ_TIMER.lock().await.replace(esb_timer);
115
116 unsafe {
117 cortex_m::peripheral::NVIC::unmask(Interrupt::RADIO);
118 cortex_m::peripheral::NVIC::unmask(Interrupt::TIMER0);
119 }
120
121 Ok((EsbDongleDriver { esb: esb_app, cnt: 0 }, async {}))
122 }
123}
124
125pub struct EsbDongleDriver {
128 esb: EsbApp<1024, 1024>,
129 cnt: u8,
130}
131
132#[derive(Debug)]
133#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134pub enum EsbDongleError {
135 Esb(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] esb_ng::Error),
136 Deserialization(postcard::Error),
137}
138
139impl rktk::drivers::interface::Error for EsbDongleError {}
140
141impl DongleDriver for EsbDongleDriver {
142 type Error = EsbDongleError;
143
144 async fn recv(&mut self) -> Result<DongleData, Self::Error> {
145 let payload = self.esb.wait_read_packet().await;
146 let (cnt, data) = match postcard::from_bytes::<'_, (u8, DongleData)>(&payload) {
147 Ok(d) => d,
148 Err(e) => {
149 payload.release();
150 return Err(EsbDongleError::Deserialization(e));
151 }
152 };
153 payload.release();
154
155 rktk::print!("recv:{:?}", cnt);
156
157 if cnt.wrapping_sub(self.cnt) > 1 {
158 rktk_log::warn!("Packet dropped: {} -> {}", self.cnt, cnt);
159 }
160 self.cnt = cnt;
161
162 Ok(data)
163 }
164}