1use embassy_executor::Spawner;
2use embassy_futures::select::{select3, select4};
3use embassy_sync::blocking_mutex::raw::NoopRawMutex;
4use embassy_usb::{
5 class::hid::{ReportId, RequestHandler},
6 control::OutResponse,
7 driver::{Driver, Endpoint, EndpointOut},
8 Builder, Config,
9};
10use embedded_hal::digital::{InputPin, OutputPin};
11use embedded_hal_async::digital::Wait;
12use static_cell::StaticCell;
13
14use crate::{
15 config::{ConfigFileIter, ConfigInterface},
16 firmware_functions::{self, ResetFn},
17 info,
18 key_reporter::Reporter,
19 key_scanner::{KeyScanner, KeyScannerChannel},
20 mapper::{self, Mapper, MapperChannel, MapperTimer},
21 ring_fs::RingFs,
22 usb::{Configurator, State, UsbBuffers, SHARED_REPORT_DESC},
23};
24
25const SCANNER_BUFFER_SIZE: usize = 32;
27const REPORT_BUFFER_SIZE: usize = 32;
29const DEBOUNCE_TUNE: usize = 8;
31
32type ScanChannel = KeyScannerChannel<NoopRawMutex, SCANNER_BUFFER_SIZE>;
34type MpChannel = MapperChannel<NoopRawMutex, REPORT_BUFFER_SIZE>;
35type ScanConfigInterface = ConfigInterface<'static, 'static>;
36static KEY_SCAN_CHANNEL: StaticCell<ScanChannel> = StaticCell::new();
37static MAPPER_CHANNEL: StaticCell<MpChannel> = StaticCell::new();
38static CONFIG_INTERFACE: StaticCell<ScanConfigInterface> = StaticCell::new();
39
40static USB_CONFIG: StaticCell<Configurator> = StaticCell::new();
41static USB_BUFFERS: StaticCell<UsbBuffers> = StaticCell::new();
42static SHARED_HID_STATE: StaticCell<State> = StaticCell::new();
43
44#[embassy_executor::task]
45async fn timer_task(timer: &'static MapperTimer) {
46 MapperTimer::run(timer).await;
47}
48
49async fn usb_run<'d, D: Driver<'d>, const REPORT_BUFFER_SIZE: usize>(
50 usb_config: &'d mut Configurator<'d>,
51 mut usb_builder: Builder<'d, D>,
52 config_interface: &'d mut ConfigInterface<'d, 'd>,
53 mapper_channel: &'d MapperChannel<NoopRawMutex, REPORT_BUFFER_SIZE>,
54 keyboard_state: &'d mut State<'d>,
55) {
56 let (shared_hid_writer, shared_hid_reader) = usb_config.add_iface::<_, 10, 34>(
57 &mut usb_builder,
58 &SHARED_REPORT_DESC,
59 true,
60 1,
61 1,
62 keyboard_state,
63 );
64
65 let cfg_fut = {
66 let mut function = usb_builder.function(0xFF, 0, 0);
67 let mut interface = function.interface();
68 let mut alt = interface.alt_setting(0xFF, 0, 0, None);
69 let mut read_ep = alt.endpoint_bulk_out(64);
70 async move {
71 loop {
72 read_ep.wait_enabled().await;
73 loop {
74 let mut buf = [0; 64];
75 match read_ep.read(&mut buf).await {
76 Ok(n) => {
77 if n > 0 {
78 config_interface.receive(&buf[..n]).await
79 }
80 }
81 Err(_) => break,
82 }
83 }
84 }
85 }
86 };
87
88 let key_event_fut = async move {
89 let mut reporter = Reporter::new(shared_hid_writer);
90 loop {
91 reporter.report(mapper_channel.receive().await).await;
92 }
93 };
94
95 let mut request_handler = MyRequestHandler {};
96
97 let hid_fut = shared_hid_reader.unwrap().run(false, &mut request_handler);
98
99 let mut usb = usb_builder.build();
100 let usb_fut = usb.run();
101
102 select4(key_event_fut, usb_fut, hid_fut, cfg_fut).await;
103}
104
105async fn mapper_run<const ROW_COUNT: usize, const COL_COUNT: usize, const LAYOUT_MAX: usize>(
106 mapper_channel: &'static MpChannel,
107 key_scan_channel: &'static ScanChannel,
108 fs: &'static dyn RingFs<'static>,
109 layout_mapping: &'static [u16],
110) {
111 let mut mapper =
112 Mapper::<ROW_COUNT, COL_COUNT, LAYOUT_MAX, _, REPORT_BUFFER_SIZE>::new(mapper_channel);
113
114 {
115 if !match fs.file_reader_by_index(0) {
116 Ok(fr) => {
117 if let Err(err) = mapper.load_layout(ConfigFileIter::new(fr).skip(2)) {
118 crate::info!("error loading layout {:?}", err);
119 false
120 } else {
121 true
122 }
123 }
124 Err(err) => {
125 crate::info!("error reading layout {:?}", err);
126 false
127 }
128 } {
129 mapper.load_layout(layout_mapping.iter().copied()).unwrap();
130 }
131 }
132
133 loop {
134 if let mapper::ControlMessage::LoadLayout { file_location } =
135 mapper.run(key_scan_channel).await
136 {
137 crate::debug!("load layout here {}", file_location);
138 match fs.file_reader_by_location(file_location) {
139 Ok(fr) => {
140 if let Err(err) = mapper.load_layout(ConfigFileIter::new(fr).skip(2)) {
141 crate::info!("error loading layout {:?}", err);
142 mapper.load_layout(layout_mapping.iter().copied()).unwrap();
143 }
144 }
145 Err(err) => crate::info!("error reading layout {:?}", err),
146 }
147 }
148 }
149}
150
151pub struct KeyboardBuilder<
152 D: Driver<'static>,
153 I: InputPin + Wait,
154 O: OutputPin,
155 const INPUT_COUNT: usize,
156 const OUTPUT_COUNT: usize,
157> {
158 reset: Option<ResetFn>,
159 reset_to_usb_boot: Option<ResetFn>,
160 usb_config: Config<'static>,
161 fs: &'static dyn RingFs<'static>,
162 driver: Option<D>,
163 input_pins: Option<[I; INPUT_COUNT]>,
164 output_pins: Option<[O; OUTPUT_COUNT]>,
165 layout_mapping: &'static [u16],
166}
167
168pub struct Keyboard<
169 D: Driver<'static>,
170 I: InputPin + Wait,
171 O: OutputPin,
172 const ROW_IS_OUTPUT: bool,
173 const INPUT_COUNT: usize,
174 const OUTPUT_COUNT: usize,
175 const LAYOUT_MAX: usize,
176> {
177 builder: KeyboardBuilder<D, I, O, INPUT_COUNT, OUTPUT_COUNT>,
178 key_scan_channel: &'static KeyScannerChannel<NoopRawMutex, SCANNER_BUFFER_SIZE>,
179 mapper_channel: &'static MapperChannel<NoopRawMutex, REPORT_BUFFER_SIZE>,
180 config_interface: &'static mut ConfigInterface<'static, 'static>,
181}
182
183const fn check_settings<const INPUT_COUNT: usize, const OUTPUT_COUNT: usize>() -> bool {
184 assert!(DEBOUNCE_TUNE < usize::BITS as usize);
185 assert!(INPUT_COUNT > 0 && INPUT_COUNT < 128);
186 assert!(OUTPUT_COUNT > 0 && OUTPUT_COUNT < 128);
187 true
188}
189
190impl<
191 D: Driver<'static> + 'static,
192 I: InputPin + Wait,
193 O: OutputPin,
194 const ROW_IS_OUTPUT: bool,
195 const INPUT_COUNT: usize,
196 const OUTPUT_COUNT: usize,
197 const LAYOUT_MAX: usize,
198 > Keyboard<D, I, O, ROW_IS_OUTPUT, INPUT_COUNT, OUTPUT_COUNT, LAYOUT_MAX>
199{
200 const OKAY: bool = check_settings::<INPUT_COUNT, OUTPUT_COUNT>();
201
202 pub async fn run(mut self, spawner: Spawner) -> ! {
203 assert!(Self::OKAY);
204
205 firmware_functions::handle_reset(self.builder.reset.take());
206 firmware_functions::handle_reset_to_usb_boot(self.builder.reset_to_usb_boot.take());
207
208 let mut scanner = KeyScanner::new(
209 self.builder.input_pins.take().unwrap(),
210 self.builder.output_pins.take().unwrap(),
211 self.key_scan_channel,
212 );
213 let driver = self.builder.driver.take().unwrap();
214 let usb_config = self.builder.usb_config;
215
216 let usb_config: &'static mut Configurator = USB_CONFIG.init(Configurator::new(usb_config));
217 let usb_buffers: &'static mut UsbBuffers = USB_BUFFERS.init(UsbBuffers::default());
218
219 let usb_builder = usb_config.usb_builder(driver, usb_buffers).unwrap();
220
221 let shared_hid_state: &'static mut State<'static> = SHARED_HID_STATE.init(State::default());
222
223 let usb_fut = usb_run(
224 usb_config,
225 usb_builder,
226 self.config_interface,
227 self.mapper_channel,
228 shared_hid_state,
229 );
230
231 let scanner_fut = scanner.run::<ROW_IS_OUTPUT, DEBOUNCE_TUNE>();
232
233 spawner
234 .spawn(timer_task(self.mapper_channel.timer()))
235 .unwrap();
236
237 if ROW_IS_OUTPUT {
238 let mapper_fut = mapper_run::<
239 OUTPUT_COUNT, INPUT_COUNT, LAYOUT_MAX,
242 >(
243 self.mapper_channel,
244 self.key_scan_channel,
245 self.builder.fs,
246 self.builder.layout_mapping,
247 );
248
249 select3(usb_fut, mapper_fut, scanner_fut).await;
250 } else {
251 let mapper_fut = mapper_run::<
252 INPUT_COUNT, OUTPUT_COUNT, LAYOUT_MAX,
255 >(
256 self.mapper_channel,
257 self.key_scan_channel,
258 self.builder.fs,
259 self.builder.layout_mapping,
260 );
261
262 select3(usb_fut, mapper_fut, scanner_fut).await;
263 }
264 unreachable!()
265 }
266}
267
268impl<
269 D: Driver<'static> + 'static,
270 I: InputPin + Wait,
271 O: OutputPin,
272 const INPUT_COUNT: usize,
273 const OUTPUT_COUNT: usize,
274 > KeyboardBuilder<D, I, O, INPUT_COUNT, OUTPUT_COUNT>
275{
276 pub fn new(
277 vid: u16,
278 pid: u16,
279 fs: &'static dyn RingFs<'static>,
280 driver: D,
281 input_pins: [I; INPUT_COUNT],
282 output_pins: [O; OUTPUT_COUNT],
283 layout_mapping: &'static [u16],
284 ) -> Self {
285 Self {
286 reset: None,
287 reset_to_usb_boot: None,
288 usb_config: Config::new(vid, pid),
289 driver: Some(driver),
290 fs,
291 input_pins: Some(input_pins),
292 output_pins: Some(output_pins),
293 layout_mapping,
294 }
295 }
296
297 pub fn reset(mut self, value: ResetFn) -> Self {
298 self.reset = Some(value);
299 self
300 }
301
302 pub fn reset_to_usb_boot(mut self, value: ResetFn) -> Self {
303 self.reset_to_usb_boot = Some(value);
304 self
305 }
306
307 pub fn manufacturer(mut self, value: &'static str) -> Self {
308 self.usb_config.manufacturer = Some(value);
309 self
310 }
311
312 pub fn product(mut self, value: &'static str) -> Self {
313 self.usb_config.product = Some(value);
314 self
315 }
316
317 pub fn serial_number(mut self, value: &'static str) -> Self {
318 self.usb_config.serial_number = Some(value);
319 self
320 }
321
322 pub fn max_power(mut self, value: u16) -> Self {
323 self.usb_config.max_power = value;
324 self
325 }
326
327 pub fn build<const ROW_IS_OUTPUT: bool, const LAYOUT_MAX: usize>(
328 self,
329 ) -> Keyboard<D, I, O, ROW_IS_OUTPUT, INPUT_COUNT, OUTPUT_COUNT, LAYOUT_MAX> {
330 let key_scan_channel: &'static ScanChannel = KEY_SCAN_CHANNEL.init(ScanChannel::default());
331 let mapper_channel: &'static MpChannel = MAPPER_CHANNEL.init(MpChannel::default());
332 let config_interface: &'static mut ScanConfigInterface =
333 CONFIG_INTERFACE.init(ConfigInterface::new(self.fs, mapper_channel.control()));
334
335 Keyboard {
336 builder: self,
337 key_scan_channel,
338 mapper_channel,
339 config_interface,
340 }
341 }
342}
343
344struct MyRequestHandler {}
345
346impl RequestHandler for MyRequestHandler {
347 fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
348 info!("Get report for {:?}", id);
349 None
350 }
351
352 fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
353 info!("Set report for {:?}: {:?}", id, data);
354 OutResponse::Accepted
355 }
356
357 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
358 info!("Set idle rate for {:?} to {:?}", id, dur);
359 }
360
361 fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
362 info!("Get idle rate for {:?}", id);
363 None
364 }
365}