rktk_drivers_nrf/esb/
reporter.rs1use 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
75static 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
190pub 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}