RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/esb/
dongle.rs

1use 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
72// ---- Builder -------
73
74pub 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
142// ----- Driver -------
143
144pub 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}