1use crate::page::Keyboard;
4use crate::usb_class::prelude::*;
5use fugit::ExtU32;
6use packed_struct::prelude::*;
7#[allow(clippy::wildcard_imports)]
8use usb_device::class_prelude::*;
9use usb_device::UsbError;
10
11pub struct BootKeyboard<'a, B: UsbBus> {
15 interface: ManagedIdleInterface<'a, B, BootKeyboardReport, InBytes8, OutBytes8>,
16}
17
18impl<B> BootKeyboard<'_, B>
19where
20 B: UsbBus,
21{
22 pub fn write_report<K: IntoIterator<Item = Keyboard>>(
23 &mut self,
24 keys: K,
25 ) -> Result<(), UsbHidError> {
26 self.interface.write_report(&BootKeyboardReport::new(keys))
27 }
28
29 pub fn read_report(&mut self) -> usb_device::Result<KeyboardLedsReport> {
30 let data = &mut [0];
31 match self.interface.read_report(data) {
32 Err(e) => Err(e),
33 Ok(_) => match KeyboardLedsReport::unpack(data) {
34 Ok(r) => Ok(r),
35 Err(_) => Err(UsbError::ParseError),
36 },
37 }
38 }
39}
40
41impl<'a, B> DeviceClass<'a> for BootKeyboard<'a, B>
42where
43 B: UsbBus,
44{
45 type I = Interface<'a, B, InBytes8, OutBytes8, ReportSingle>;
46
47 fn interface(&mut self) -> &mut Self::I {
48 self.interface.interface()
49 }
50
51 fn reset(&mut self) {
52 self.interface.reset();
53 }
54
55 fn tick(&mut self) -> Result<(), UsbHidError> {
56 self.interface.tick()
57 }
58}
59
60pub struct BootKeyboardConfig<'a> {
61 interface: ManagedIdleInterfaceConfig<'a, BootKeyboardReport, InBytes8, OutBytes8>,
62}
63
64impl Default for BootKeyboardConfig<'_> {
65 fn default() -> Self {
66 Self::new(ManagedIdleInterfaceConfig::new(
67 unwrap!(unwrap!(unwrap!(unwrap!(InterfaceBuilder::new(
68 BOOT_KEYBOARD_REPORT_DESCRIPTOR
69 ))
70 .boot_device(InterfaceProtocol::Keyboard)
71 .description("Keyboard")
72 .idle_default(500.millis()))
73 .in_endpoint(10.millis()))
74 .with_out_endpoint(100.millis()))
77 .build(),
78 ))
79 }
80}
81
82impl<'a> BootKeyboardConfig<'a> {
83 #[must_use]
84 pub fn new(
85 interface: ManagedIdleInterfaceConfig<'a, BootKeyboardReport, InBytes8, OutBytes8>,
86 ) -> Self {
87 Self { interface }
88 }
89}
90
91impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for BootKeyboardConfig<'a> {
92 type Allocated = BootKeyboard<'a, B>;
93
94 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
95 Self::Allocated {
96 interface: self.interface.allocate(usb_alloc),
97 }
98 }
99}
100
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct)]
104#[packed_struct(endian = "lsb", bit_numbering = "lsb0", size_bytes = "1")]
105pub struct KeyboardLedsReport {
106 #[packed_field(bits = "0")]
107 pub num_lock: bool,
108 #[packed_field(bits = "1")]
109 pub caps_lock: bool,
110 #[packed_field(bits = "2")]
111 pub scroll_lock: bool,
112 #[packed_field(bits = "3")]
113 pub compose: bool,
114 #[packed_field(bits = "4")]
115 pub kana: bool,
116}
117
118#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
121#[packed_struct(endian = "lsb", bit_numbering = "msb0", size_bytes = "8")]
122pub struct BootKeyboardReport {
123 #[packed_field(bits = "0")]
124 pub right_gui: bool,
125 #[packed_field(bits = "1")]
126 pub right_alt: bool,
127 #[packed_field(bits = "2")]
128 pub right_shift: bool,
129 #[packed_field(bits = "3")]
130 pub right_ctrl: bool,
131 #[packed_field(bits = "4")]
132 pub left_gui: bool,
133 #[packed_field(bits = "5")]
134 pub left_alt: bool,
135 #[packed_field(bits = "6")]
136 pub left_shift: bool,
137 #[packed_field(bits = "7")]
138 pub left_ctrl: bool,
139 #[packed_field(bytes = "2..8", ty = "enum", element_size_bytes = "1")]
140 pub keys: [Keyboard; 6],
141}
142
143impl BootKeyboardReport {
144 pub fn new<K: IntoIterator<Item = Keyboard>>(keys: K) -> Self {
145 let mut report = Self::default();
146
147 let mut error = false;
148 let mut i = 0;
149 for k in keys {
150 match k {
151 Keyboard::LeftControl => {
152 report.left_ctrl = true;
153 }
154 Keyboard::LeftShift => {
155 report.left_shift = true;
156 }
157 Keyboard::LeftAlt => {
158 report.left_alt = true;
159 }
160 Keyboard::LeftGUI => {
161 report.left_gui = true;
162 }
163 Keyboard::RightControl => {
164 report.right_ctrl = true;
165 }
166 Keyboard::RightShift => {
167 report.right_shift = true;
168 }
169 Keyboard::RightAlt => {
170 report.right_alt = true;
171 }
172 Keyboard::RightGUI => {
173 report.right_gui = true;
174 }
175 Keyboard::NoEventIndicated => {}
176 Keyboard::ErrorRollOver | Keyboard::POSTFail | Keyboard::ErrorUndefine => {
177 if !error {
178 error = true;
179 i = report.keys.len();
180 report.keys.fill(k);
181 }
182 }
183 _ => {
184 if error {
185 continue;
186 }
187
188 if i < report.keys.len() {
189 report.keys[i] = k;
190 i += 1;
191 } else {
192 error = true;
193 i = report.keys.len();
194 report.keys.fill(Keyboard::ErrorRollOver);
195 }
196 }
197 }
198 }
199 report
200 }
201}
202
203#[rustfmt::skip]
210pub const BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[
211 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2A, 0xFF, 0x00, 0x81, 0x00, 0xC0, ];
244
245#[rustfmt::skip]
256pub const NKRO_BOOT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[
257 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0x75, 0x38, 0x95, 0x01, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x03, 0x95, 0x88, 0x75, 0x01, 0x15, 0x00, 0x25, 0x01, 0x05, 0x07, 0x19, 0x00, 0x29, 0x87, 0x81, 0x02, 0xc0 ];
294
295#[cfg_attr(feature = "defmt", derive(defmt::Format))]
301#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
302#[packed_struct(endian = "lsb", bit_numbering = "msb0", size_bytes = "25")]
303pub struct NKROBootKeyboardReport {
304 #[packed_field(bits = "0")]
305 pub right_gui: bool,
306 #[packed_field(bits = "1")]
307 pub right_alt: bool,
308 #[packed_field(bits = "2")]
309 pub right_shift: bool,
310 #[packed_field(bits = "3")]
311 pub right_ctrl: bool,
312 #[packed_field(bits = "4")]
313 pub left_gui: bool,
314 #[packed_field(bits = "5")]
315 pub left_alt: bool,
316 #[packed_field(bits = "6")]
317 pub left_shift: bool,
318 #[packed_field(bits = "7")]
319 pub left_ctrl: bool,
320 #[packed_field(bytes = "2..8", ty = "enum", element_size_bytes = "1")]
321 pub boot_keys: [Keyboard; 6],
322 #[packed_field(bytes = "8..25", element_size_bits = "8")]
324 pub nkro_keys: [u8; 17],
325}
326
327impl NKROBootKeyboardReport {
328 pub fn new<K: IntoIterator<Item = Keyboard>>(keys: K) -> Self {
329 let mut report = Self::default();
330
331 let mut boot_keys_error = false;
332 let mut i = 0;
333 for k in keys {
334 match k {
335 Keyboard::LeftControl => {
336 report.left_ctrl = true;
337 }
338 Keyboard::LeftShift => {
339 report.left_shift = true;
340 }
341 Keyboard::LeftAlt => {
342 report.left_alt = true;
343 }
344 Keyboard::LeftGUI => {
345 report.left_gui = true;
346 }
347 Keyboard::RightControl => {
348 report.right_ctrl = true;
349 }
350 Keyboard::RightShift => {
351 report.right_shift = true;
352 }
353 Keyboard::RightAlt => {
354 report.right_alt = true;
355 }
356 Keyboard::RightGUI => {
357 report.right_gui = true;
358 }
359 Keyboard::NoEventIndicated => {}
360 Keyboard::ErrorRollOver | Keyboard::POSTFail | Keyboard::ErrorUndefine => {
361 report.nkro_keys[0] |= 1 << u8::from(k);
362
363 if !boot_keys_error {
364 boot_keys_error = true;
365 i = report.boot_keys.len();
366 report.boot_keys.fill(k);
367 }
368 }
369 _ => {
370 if report.nkro_keys.len() * 8 > u8::from(k).into() {
371 let byte = u8::from(k) / 8;
372 let bit = u8::from(k) % 8;
373 report.nkro_keys[usize::from(byte)] |= 1 << bit;
374 }
375
376 if boot_keys_error {
377 continue;
378 }
379
380 if i < report.boot_keys.len() {
381 report.boot_keys[i] = k;
382 i += 1;
383 } else {
384 boot_keys_error = true;
385 i = report.boot_keys.len();
386 report.boot_keys.fill(Keyboard::ErrorRollOver);
387 }
388 }
389 }
390 }
391 report
392 }
393}
394
395pub struct NKROBootKeyboard<'a, B: UsbBus> {
399 interface: ManagedIdleInterface<'a, B, NKROBootKeyboardReport, InBytes32, OutBytes8>,
400}
401
402impl<B> NKROBootKeyboard<'_, B>
403where
404 B: UsbBus,
405{
406 pub fn write_report<K: IntoIterator<Item = Keyboard>>(
407 &mut self,
408 keys: K,
409 ) -> Result<(), UsbHidError> {
410 self.interface
411 .write_report(&NKROBootKeyboardReport::new(keys))
412 }
413
414 pub fn read_report(&mut self) -> usb_device::Result<KeyboardLedsReport> {
415 let data = &mut [0];
416 match self.interface.read_report(data) {
417 Err(e) => Err(e),
418 Ok(_) => match KeyboardLedsReport::unpack(data) {
419 Ok(r) => Ok(r),
420 Err(_) => Err(UsbError::ParseError),
421 },
422 }
423 }
424}
425
426pub struct NKROBootKeyboardConfig<'a> {
427 interface: ManagedIdleInterfaceConfig<'a, NKROBootKeyboardReport, InBytes32, OutBytes8>,
428}
429
430impl Default for NKROBootKeyboardConfig<'_> {
431 fn default() -> Self {
432 Self::new(ManagedIdleInterfaceConfig::new(
433 unwrap!(unwrap!(unwrap!(unwrap!(InterfaceBuilder::new(
434 NKRO_BOOT_KEYBOARD_REPORT_DESCRIPTOR
435 ))
436 .description("NKRO Keyboard")
437 .boot_device(InterfaceProtocol::Keyboard)
438 .idle_default(500.millis()))
439 .in_endpoint(10.millis()))
440 .with_out_endpoint(100.millis()))
441 .build(),
442 ))
443 }
444}
445
446impl<'a> NKROBootKeyboardConfig<'a> {
447 #[must_use]
448 pub fn new(
449 interface: ManagedIdleInterfaceConfig<'a, NKROBootKeyboardReport, InBytes32, OutBytes8>,
450 ) -> Self {
451 Self { interface }
452 }
453}
454
455impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for NKROBootKeyboardConfig<'a> {
456 type Allocated = NKROBootKeyboard<'a, B>;
457
458 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
459 Self::Allocated {
460 interface: self.interface.allocate(usb_alloc),
461 }
462 }
463}
464
465impl<'a, B> DeviceClass<'a> for NKROBootKeyboard<'a, B>
466where
467 B: UsbBus,
468{
469 type I = Interface<'a, B, InBytes32, OutBytes8, ReportSingle>;
470
471 fn interface(&mut self) -> &mut Self::I {
472 self.interface.interface()
473 }
474
475 fn reset(&mut self) {
476 self.interface.reset();
477 }
478
479 fn tick(&mut self) -> core::result::Result<(), UsbHidError> {
480 self.interface.tick()
481 }
482}
483
484#[rustfmt::skip]
490pub const NKRO_COMPACT_KEYBOARD_REPORT_DESCRIPTOR: &[u8] = &[
491 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x75, 0x01, 0x95, 0x08, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x81, 0x02, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x03, 0x95, 0x88, 0x75, 0x01, 0x15, 0x00, 0x25, 0x01, 0x05, 0x07, 0x19, 0x00, 0x29, 0x87, 0x81, 0x02, 0xc0 ];
524
525#[cfg(test)]
526mod test {
527 #![allow(clippy::unwrap_used)]
528 #![allow(clippy::expect_used)]
529
530 use packed_struct::prelude::*;
531
532 use crate::device::keyboard::{BootKeyboardReport, KeyboardLedsReport};
533 use crate::page::Keyboard;
534
535 #[test]
536 fn leds_num_lock() {
537 assert_eq!(
538 KeyboardLedsReport::unpack(&[1]),
539 Ok(KeyboardLedsReport {
540 num_lock: true,
541 caps_lock: false,
542 scroll_lock: false,
543 compose: false,
544 kana: false,
545 })
546 );
547 }
548
549 #[test]
550 fn leds_caps_lock() {
551 assert_eq!(
552 KeyboardLedsReport::unpack(&[2]),
553 Ok(KeyboardLedsReport {
554 num_lock: false,
555 caps_lock: true,
556 scroll_lock: false,
557 compose: false,
558 kana: false,
559 })
560 );
561
562 assert_eq!(
563 KeyboardLedsReport {
564 num_lock: false,
565 caps_lock: true,
566 scroll_lock: false,
567 compose: false,
568 kana: false,
569 }
570 .pack(),
571 Ok([2])
572 );
573 }
574
575 #[test]
576 fn boot_keyboard_report_mixed() {
577 let bytes = BootKeyboardReport::new([
578 Keyboard::LeftAlt,
579 Keyboard::A,
580 Keyboard::B,
581 Keyboard::C,
582 Keyboard::RightGUI,
583 ])
584 .pack()
585 .unwrap();
586
587 let key_mod: u8 = (0x1_u8
588 << (u8::from(Keyboard::LeftAlt) - u8::from(Keyboard::LeftControl)))
589 | (0x1_u8 << (u8::from(Keyboard::RightGUI) - u8::from(Keyboard::LeftControl)));
590
591 assert_eq!(
592 bytes,
593 [
594 key_mod,
595 0,
596 Keyboard::A.into(),
597 Keyboard::B.into(),
598 Keyboard::C.into(),
599 0,
600 0,
601 0
602 ]
603 );
604 }
605
606 #[test]
607 fn boot_keyboard_report_keys() {
608 let bytes = BootKeyboardReport::new([
609 Keyboard::A,
610 Keyboard::B,
611 Keyboard::C,
612 Keyboard::D,
613 Keyboard::E,
614 Keyboard::F,
615 ])
616 .pack()
617 .unwrap();
618
619 assert_eq!(
620 bytes,
621 [
622 0,
623 0,
624 Keyboard::A.into(),
625 Keyboard::B.into(),
626 Keyboard::C.into(),
627 Keyboard::D.into(),
628 Keyboard::E.into(),
629 Keyboard::F.into()
630 ]
631 );
632 }
633
634 #[test]
635 fn boot_keyboard_report_rollover() {
636 let bytes = BootKeyboardReport::new([
637 Keyboard::LeftAlt,
638 Keyboard::A,
639 Keyboard::B,
640 Keyboard::C,
641 Keyboard::D,
642 Keyboard::E,
643 Keyboard::F,
644 Keyboard::G,
645 Keyboard::RightGUI,
646 ])
647 .pack()
648 .unwrap();
649
650 let key_mod: u8 = (0x1_u8
651 << (u8::from(Keyboard::LeftAlt) - u8::from(Keyboard::LeftControl)))
652 | (0x1_u8 << (u8::from(Keyboard::RightGUI) - u8::from(Keyboard::LeftControl)));
653 assert_eq!(
654 bytes,
655 [
656 key_mod,
657 0,
658 Keyboard::ErrorRollOver.into(),
659 Keyboard::ErrorRollOver.into(),
660 Keyboard::ErrorRollOver.into(),
661 Keyboard::ErrorRollOver.into(),
662 Keyboard::ErrorRollOver.into(),
663 Keyboard::ErrorRollOver.into(),
664 ]
665 );
666 }
667}