1use core::sync::atomic::{AtomicUsize, Ordering};
2use embassy_usb::{
3 class::hid::{ReadError, ReportId, RequestHandler},
4 driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut},
5};
6
7use crate::warn;
8
9pub struct HidWriter<'d, D: Driver<'d>, const N: usize> {
10 ep_in: D::EndpointIn,
11}
12
13impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
14 pub fn new(ep_in: <D>::EndpointIn) -> Self {
15 Self { ep_in }
16 }
17
18 pub async fn write(&mut self, report: &[u8]) -> Result<(), EndpointError> {
20 assert!(report.len() <= N);
21
22 let max_packet_size = usize::from(self.ep_in.info().max_packet_size);
23 let zlp_needed = report.len() < N && (report.len() % max_packet_size == 0);
24 for chunk in report.chunks(max_packet_size) {
25 self.ep_in.write(chunk).await?;
26 }
27
28 if zlp_needed {
29 self.ep_in.write(&[]).await?;
30 }
31
32 Ok(())
33 }
34}
35
36pub struct HidReader<'d, D: Driver<'d>, const N: usize> {
37 ep_out: D::EndpointOut,
38 offset: &'d AtomicUsize,
39}
40
41impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
42 pub fn new(ep_out: <D>::EndpointOut, offset: &'d AtomicUsize) -> Self {
43 Self { ep_out, offset }
44 }
45
46 pub async fn run<T: RequestHandler>(mut self, use_report_ids: bool, handler: &mut T) -> ! {
51 let offset = self.offset.load(Ordering::Acquire);
52 assert!(offset == 0);
53 let mut buf = [0; N];
54 loop {
55 match self.read(&mut buf).await {
56 Ok(len) => {
57 let id = if use_report_ids { buf[0] } else { 0 };
58 handler.set_report(ReportId::Out(id), &buf[..len]);
59 }
60 Err(ReadError::BufferOverflow) => {
61 warn!(
62 "Host sent output report larger than the configured maximum output report length ({})",
63 N
64 );
65 }
66 Err(ReadError::Disabled) => self.ep_out.wait_enabled().await,
67 Err(ReadError::Sync(_)) => unreachable!(),
68 }
69 }
70 }
71
72 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, ReadError> {
87 assert!(N != 0);
88 assert!(buf.len() >= N);
89
90 let max_packet_size = usize::from(self.ep_out.info().max_packet_size);
92 let starting_offset = self.offset.load(Ordering::Acquire);
93 let mut total = starting_offset;
94 loop {
95 for chunk in buf[starting_offset..N].chunks_mut(max_packet_size) {
96 match self.ep_out.read(chunk).await {
97 Ok(size) => {
98 total += size;
99 if size < max_packet_size || total == N {
100 self.offset.store(0, Ordering::Release);
101 break;
102 }
103 self.offset.store(total, Ordering::Release);
104 }
105 Err(err) => {
106 self.offset.store(0, Ordering::Release);
107 return Err(err.into());
108 }
109 }
110 }
111
112 if total > 0 {
114 break;
115 }
116 }
117
118 if starting_offset > 0 {
119 Err(ReadError::Sync(starting_offset..total))
120 } else {
121 Ok(total)
122 }
123 }
124}