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 {
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
192pub 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}