wasefire_board_api/usb/
ctap.rs1use usb_device::bus::UsbBus;
18use usbd_hid::UsbError;
19use usbd_hid::hid_class::HIDClass;
20use wasefire_error::Code;
21use {ssmarshal as _, wasefire_logger as log};
22
23use crate::Error;
24
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27#[derive(Debug, PartialEq, Eq)]
28pub enum Event {
29 Read,
33
34 Write,
38}
39
40impl<B: crate::Api> From<Event> for crate::Event<B> {
41 fn from(event: Event) -> Self {
42 super::Event::Ctap(event).into()
43 }
44}
45
46pub trait Api: Send {
48 fn read(output: &mut [u8; 64]) -> Result<bool, Error>;
52
53 fn write(input: &[u8; 64]) -> Result<bool, Error>;
57
58 fn enable(event: &Event) -> Result<(), Error>;
60
61 fn disable(event: &Event) -> Result<(), Error>;
63}
64
65pub trait HasHid: Send {
67 type UsbBus: UsbBus;
69
70 fn with_hid<R>(f: impl FnOnce(&mut Ctap<Self::UsbBus>) -> R) -> R;
72}
73
74pub struct WithHid<T: HasHid> {
76 _never: !,
77 _has_hid: T,
78}
79
80pub struct Ctap<'a, T: UsbBus> {
82 class: HIDClass<'a, T>,
83 read_enabled: bool,
84 write_enabled: bool,
85}
86
87impl<'a, T: UsbBus> Ctap<'a, T> {
88 pub fn new(class: HIDClass<'a, T>) -> Self {
90 Self { class, read_enabled: false, write_enabled: false }
91 }
92
93 pub fn class(&mut self) -> &mut HIDClass<'a, T> {
95 &mut self.class
96 }
97
98 pub fn tick(&mut self, polled: bool, mut push: impl FnMut(Event)) {
100 if self.read_enabled && polled {
101 push(Event::Read);
102 }
103 if self.write_enabled {
104 push(Event::Write);
105 }
106 }
107
108 fn set(&mut self, event: &Event, enabled: bool) -> Result<(), Error> {
109 match event {
110 Event::Read => self.read_enabled = enabled,
111 Event::Write => self.write_enabled = enabled,
112 }
113 Ok(())
114 }
115}
116
117impl<T: HasHid> Api for WithHid<T> {
118 fn read(output: &mut [u8; 64]) -> Result<bool, Error> {
119 T::with_hid(|x| match x.class.pull_raw_output(output) {
120 Ok(64) => Ok(true),
121 Ok(len) => {
122 log::warn!("bad read len {}", len);
123 Err(Error::world(Code::InvalidLength))
124 }
125 Err(UsbError::WouldBlock) => Ok(false),
126 Err(_) => Err(Error::world(0)),
127 })
128 }
129
130 fn write(input: &[u8; 64]) -> Result<bool, Error> {
131 T::with_hid(|x| match x.class.push_raw_input(input) {
132 Ok(64) => Ok(true),
133 Ok(len) => {
134 log::warn!("bad write len {}", len);
135 Err(Error::world(Code::InvalidLength))
136 }
137 Err(UsbError::WouldBlock) => Ok(false),
138 Err(_) => Err(Error::world(0)),
139 })
140 }
141
142 fn enable(event: &Event) -> Result<(), Error> {
143 T::with_hid(|x| x.set(event, true))
144 }
145
146 fn disable(event: &Event) -> Result<(), Error> {
147 T::with_hid(|x| x.set(event, false))
148 }
149}