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