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