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, 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
77static 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
185pub 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}