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