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            && 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
71// ---- Builder -------
72
73pub 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
141// ----- Driver -------
142
143pub 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}