rpk_firmware/
exec.rs

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
25// How many scanned keys can be stored before blocking scanner
26const SCANNER_BUFFER_SIZE: usize = 32;
27// How many key events can be sent to usb before blocking mapper
28const REPORT_BUFFER_SIZE: usize = 32;
29// How sensitive DEBOUNCE is higher numbers are more likely to stop debounce
30const DEBOUNCE_TUNE: usize = 8;
31
32// Configure comms channels
33type 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, // Output is Row
240                INPUT_COUNT,  // Input is Column
241                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,  // Input is Row
253                OUTPUT_COUNT, // Output is Column
254                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}