RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/esb/
reporter.rs

1use core::{convert::Infallible, 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, EsbHeader, EsbIrq, IrqTimer, bbq2::queue::BBQueue, irq::StatePTX,
12    peripherals::PtrTimer as _,
13};
14use postcard::experimental::max_size::MaxSize as _;
15use rktk::{
16    drivers::interface::{
17        dongle::DongleData,
18        reporter::{ReporterDriver, ReporterDriverBuilder},
19        wireless::WirelessReporterDriver,
20    },
21    utils::Channel,
22};
23use rktk_log::{debug, helper::Debug2Format, warn};
24
25macro_rules! use_peripheral {
26    ($radio:ident, $timer:ident, $esb_timer:ident) => {
27        type DongleRadio = embassy_nrf::peripherals::$radio;
28        const DONGLE_RADIO_PAC: embassy_nrf::pac::radio::Radio = embassy_nrf::pac::$radio;
29        type DongleTimer = embassy_nrf::peripherals::$timer;
30        type DongleTimerEsb = esb_ng::peripherals::$esb_timer;
31    };
32}
33
34use_peripheral!(RADIO, TIMER0, Timer0);
35
36static IRQ_TIMER: Mutex<CriticalSectionRawMutex, Option<IrqTimer<DongleTimerEsb>>> =
37    Mutex::new(None);
38
39pub struct TimerInterruptHandler {
40    _phantom: PhantomData<()>,
41}
42
43impl interrupt::typelevel::Handler<<DongleTimer as timer::Instance>::Interrupt>
44    for TimerInterruptHandler
45{
46    unsafe fn on_interrupt() {
47        if let Ok(mut irq_timer) = IRQ_TIMER.try_lock() {
48            if let Some(irq_timer) = &mut *irq_timer {
49                irq_timer.timer_interrupt();
50            }
51        }
52    }
53}
54
55static ESB_IRQ: Mutex<
56    CriticalSectionRawMutex,
57    Option<EsbIrq<1024, 1024, DongleTimerEsb, StatePTX>>,
58> = Mutex::new(None);
59
60pub struct EsbInterruptHandler {
61    _phantom: PhantomData<()>,
62}
63
64impl interrupt::typelevel::Handler<<DongleRadio as radio::Instance>::Interrupt>
65    for EsbInterruptHandler
66{
67    unsafe fn on_interrupt() {
68        if let Ok(mut esb_irq) = ESB_IRQ.try_lock() {
69            if let Some(esb_irq) = &mut *esb_irq {
70                if let Err(e) = esb_irq.radio_interrupt() {
71                    rktk_log::warn!("Irq error: {:?}", Debug2Format(&e));
72                }
73            }
74        }
75    }
76}
77
78// -------- Builder ----------
79
80static REPORT_SEND_CHAN: Channel<DongleData, 16> = Channel::new();
81const MAX_PAYLOAD_SIZE: u8 = 192;
82
83pub struct EsbReporterDriverBuilder {
84    _phantom: PhantomData<()>,
85    config: super::Config,
86}
87
88impl EsbReporterDriverBuilder {
89    pub fn new(
90        _timer: DongleTimer,
91        _radio: DongleRadio,
92        _irqs: impl Binding<<DongleTimer as timer::Instance>::Interrupt, TimerInterruptHandler>
93        + Binding<<DongleRadio as radio::Instance>::Interrupt, EsbInterruptHandler>,
94        config: super::Config,
95    ) -> Self {
96        Self {
97            _phantom: PhantomData,
98            config,
99        }
100    }
101}
102
103impl ReporterDriverBuilder for EsbReporterDriverBuilder {
104    type Output = EsbReporterDriver;
105
106    type Error = &'static str;
107
108    async fn build(self) -> Result<(Self::Output, impl Future<Output = ()>), Self::Error> {
109        static BUFFER: EsbBuffer<1024, 1024> = EsbBuffer {
110            app_to_radio_buf: BBQueue::new(),
111            radio_to_app_buf: BBQueue::new(),
112            timer_flag: AtomicBool::new(false),
113        };
114        let config = self
115            .config
116            .config
117            .max_payload_size(192)
118            .check()
119            .map_err(|_| "Config error")?;
120
121        let (esb_app, esb_irq, esb_timer) = BUFFER
122            .try_split(
123                unsafe { DongleTimerEsb::take() },
124                DONGLE_RADIO_PAC,
125                self.config.addresses,
126                config,
127            )
128            .unwrap();
129        let esb_irq = esb_irq.into_ptx();
130        ESB_IRQ.lock().await.replace(esb_irq);
131        IRQ_TIMER.lock().await.replace(esb_timer);
132        unsafe {
133            cortex_m::peripheral::NVIC::unmask(Interrupt::RADIO);
134            cortex_m::peripheral::NVIC::unmask(Interrupt::TIMER0);
135        }
136
137        Ok((EsbReporterDriver {}, esb_task(esb_app)))
138    }
139}
140
141async fn esb_task(esb_app: EsbApp<1024, 1024>) {
142    let mut cnt: u8 = 0;
143    let mut pid = 0;
144    let (mut s, mut r) = esb_app.split();
145    embassy_futures::join::join(
146        async move {
147            loop {
148                let report = REPORT_SEND_CHAN.receive().await;
149                let mut buf = [0; DongleDataWithCnt::POSTCARD_MAX_SIZE];
150                let Ok(slice) = postcard::to_slice(&(cnt, report), &mut buf) else {
151                    warn!("Postcard error");
152                    continue;
153                };
154
155                let esb_header = EsbHeader::build()
156                    .max_payload(MAX_PAYLOAD_SIZE)
157                    .pid(pid)
158                    .pipe(0)
159                    .no_ack(false)
160                    .check()
161                    .unwrap();
162                let mut packet = match s.wait_grant_packet(esb_header).await {
163                    Ok(p) => p,
164                    Err(e) => {
165                        warn!("Grant packet error: {:?}", Debug2Format(&e));
166                        continue;
167                    }
168                };
169                packet[..slice.len()].copy_from_slice(slice);
170                packet.commit(slice.len());
171                s.start_tx();
172
173                debug!("Sent report: {:?}", slice);
174
175                cnt = cnt.wrapping_add(1);
176                if pid == 3 {
177                    pid = 0;
178                } else {
179                    pid += 1;
180                }
181            }
182        },
183        async move {
184            loop {
185                let p = r.wait_read_packet().await;
186                p.release();
187            }
188        },
189    )
190    .await;
191}
192
193// ----------- Driver ------------
194
195pub struct EsbReporterDriver {}
196
197#[derive(Debug)]
198#[cfg_attr(feature = "defmt", derive(defmt::Format))]
199pub struct ErrorMsg(pub &'static str);
200
201impl rktk::drivers::interface::Error for ErrorMsg {}
202
203type DongleDataWithCnt = (usize, DongleData);
204
205impl ReporterDriver for EsbReporterDriver {
206    type Error = ErrorMsg;
207
208    fn try_send_keyboard_report(
209        &self,
210        report: usbd_hid::descriptor::KeyboardReport,
211    ) -> Result<(), Self::Error> {
212        REPORT_SEND_CHAN
213            .try_send(DongleData::Keyboard(report.into()))
214            .map_err(|_| ErrorMsg("Send error"))
215    }
216
217    fn try_send_media_keyboard_report(
218        &self,
219        report: usbd_hid::descriptor::MediaKeyboardReport,
220    ) -> Result<(), Self::Error> {
221        REPORT_SEND_CHAN
222            .try_send(DongleData::MediaKeyboard(report.into()))
223            .map_err(|_| ErrorMsg("Send error"))
224    }
225
226    fn try_send_mouse_report(
227        &self,
228        report: usbd_hid::descriptor::MouseReport,
229    ) -> Result<(), Self::Error> {
230        REPORT_SEND_CHAN
231            .try_send(DongleData::Mouse(report.into()))
232            .map_err(|_| ErrorMsg("Send error"))
233    }
234
235    async fn send_rrp_data(&self, _data: &[u8]) -> Result<(), Self::Error> {
236        Ok(())
237    }
238
239    fn wakeup(&self) -> Result<bool, Self::Error> {
240        Ok(false)
241    }
242}
243
244impl WirelessReporterDriver for EsbReporterDriver {
245    type Error = Infallible;
246
247    async fn clear_bond_data(&self) -> Result<(), <Self as WirelessReporterDriver>::Error> {
248        Ok(())
249    }
250}