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, bbq2::queue::BBQueue, irq::StatePRX,
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 if let Some(irq_timer) = &mut *irq_timer {
43 irq_timer.timer_interrupt();
44 }
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 if let Some(esb_irq) = &mut *esb_irq {
64 if let Err(e) = esb_irq.radio_interrupt() {
65 rktk_log::warn!("Irq error: {:?}", Debug2Format(&e));
66 }
67 }
68 }
69 }
70}
71
72pub struct EsbDongleDriverBuilder {
75 _timer: DongleTimer,
76 _radio: DongleRadio,
77 config: Config,
78}
79
80impl EsbDongleDriverBuilder {
81 pub fn new(
82 timer: DongleTimer,
83 radio: DongleRadio,
84 _irqs: impl Binding<<DongleTimer as timer::Instance>::Interrupt, TimerInterruptHandler>,
85 config: Config,
86 ) -> Self {
87 Self {
88 _timer: timer,
89 _radio: radio,
90 config,
91 }
92 }
93}
94
95impl DongleDriverBuilder for EsbDongleDriverBuilder {
96 type Output = EsbDongleDriver;
97
98 type Error = &'static str;
99
100 async fn build(self) -> Result<(Self::Output, impl Future<Output = ()>), Self::Error> {
101 static BUFFER: EsbBuffer<1024, 1024> = EsbBuffer {
102 app_to_radio_buf: BBQueue::new(),
103 radio_to_app_buf: BBQueue::new(),
104 timer_flag: AtomicBool::new(false),
105 };
106 let config = self
107 .config
108 .config
109 .max_payload_size(192)
110 .check()
111 .map_err(|_| "Invalid config")?;
112 let (esb_app, esb_irq, esb_timer) = BUFFER
113 .try_split(
114 unsafe { DongleTimerEsb::take() },
115 DONGLE_RADIO_PAC,
116 self.config.addresses,
117 config,
118 )
119 .map_err(|_| "Failed to initialize")?;
120 let mut esb_irq = esb_irq.into_prx();
121 esb_irq
122 .start_receiving()
123 .map_err(|_| "Failed to start receiving")?;
124 ESB_IRQ.lock().await.replace(esb_irq);
125 IRQ_TIMER.lock().await.replace(esb_timer);
126
127 unsafe {
128 cortex_m::peripheral::NVIC::unmask(Interrupt::RADIO);
129 cortex_m::peripheral::NVIC::unmask(Interrupt::TIMER0);
130 }
131
132 Ok((
133 EsbDongleDriver {
134 esb: esb_app,
135 cnt: 0,
136 },
137 async {},
138 ))
139 }
140}
141
142pub struct EsbDongleDriver {
145 esb: EsbApp<1024, 1024>,
146 cnt: u8,
147}
148
149#[derive(Debug)]
150#[cfg_attr(feature = "defmt", derive(defmt::Format))]
151pub enum EsbDongleError {
152 Esb(#[cfg_attr(feature = "defmt", defmt(Debug2Format))] esb_ng::Error),
153 Deserialization(postcard::Error),
154}
155
156impl rktk::drivers::interface::Error for EsbDongleError {}
157
158impl DongleDriver for EsbDongleDriver {
159 type Error = EsbDongleError;
160
161 async fn recv(&mut self) -> Result<DongleData, Self::Error> {
162 let payload = self.esb.wait_read_packet().await;
163 let (cnt, data) = match postcard::from_bytes::<'_, (u8, DongleData)>(&payload) {
164 Ok(d) => d,
165 Err(e) => {
166 payload.release();
167 return Err(EsbDongleError::Deserialization(e));
168 }
169 };
170 payload.release();
171
172 rktk::print!("recv:{:?}", cnt);
173
174 if cnt.wrapping_sub(self.cnt) > 1 {
175 rktk_log::warn!("Packet dropped: {} -> {}", self.cnt, cnt);
176 }
177 self.cnt = cnt;
178
179 Ok(data)
180 }
181}