80 lines
2.3 KiB
Rust
80 lines
2.3 KiB
Rust
//! Bootloader entry helpers shared between power-on checks and runtime combos.
|
|
|
|
use crate::{KeyMatrix, StatusLed, layout, status::StatusMode};
|
|
#[cfg(all(test, feature = "std"))]
|
|
use crate::NUMBER_OF_KEYS;
|
|
use cortex_m::asm;
|
|
use rp2040_hal::{
|
|
gpio::AnyPin,
|
|
pio::{PIOExt, StateMachineIndex},
|
|
};
|
|
use usbd_human_interface_device::page::Keyboard;
|
|
|
|
/// Returns true when the runtime bootloader chord is held.
|
|
///
|
|
/// The chord requires two Fn buttons, both Shift buttons and the primary Ctrl.
|
|
pub fn chord_requested(pressed_keys: &KeyMatrix) -> bool {
|
|
if !modifier_pressed(pressed_keys, Keyboard::LeftShift)
|
|
|| !modifier_pressed(pressed_keys, Keyboard::RightShift)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if !modifier_pressed(pressed_keys, Keyboard::LeftControl) {
|
|
return false;
|
|
}
|
|
|
|
let active_fn = layout::FN_BUTTONS
|
|
.iter()
|
|
.filter(|index| pressed_keys[**index as usize])
|
|
.count();
|
|
|
|
active_fn >= 2
|
|
}
|
|
|
|
fn modifier_pressed(pressed_keys: &KeyMatrix, key: Keyboard) -> bool {
|
|
layout::MAP[0]
|
|
.iter()
|
|
.enumerate()
|
|
.any(|(index, mapped)| *mapped == key && pressed_keys[index])
|
|
}
|
|
|
|
/// Puts the RP2040 into the ROM bootloader.
|
|
pub fn enter<P, SM, I>(status_led: &mut StatusLed<P, SM, I>) -> !
|
|
where
|
|
P: PIOExt,
|
|
SM: StateMachineIndex,
|
|
I: AnyPin<Function = P::PinFunction>,
|
|
{
|
|
status_led.update(StatusMode::Bootloader);
|
|
let gpio_activity_pin_mask: u32 = 0;
|
|
let disable_interface_mask: u32 = 0;
|
|
rp2040_hal::rom_data::reset_to_usb_boot(gpio_activity_pin_mask, disable_interface_mask);
|
|
loop {
|
|
asm::nop();
|
|
}
|
|
}
|
|
|
|
#[cfg(all(test, feature = "std"))]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn chord_requires_all_modifier_keys_and_two_fn() {
|
|
let mut pressed = [false; NUMBER_OF_KEYS];
|
|
for (index, key) in layout::MAP[0].iter().enumerate() {
|
|
match key {
|
|
Keyboard::LeftShift | Keyboard::RightShift | Keyboard::LeftControl => {
|
|
pressed[index] = true;
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
pressed[layout::FN_BUTTONS[0] as usize] = true;
|
|
assert!(!chord_requested(&pressed));
|
|
|
|
pressed[layout::FN_BUTTONS[1] as usize] = true;
|
|
assert!(chord_requested(&pressed));
|
|
}
|
|
}
|