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