Added bootloader module to handle how to enter bootloader during runtime
This commit is contained in:
parent
33531719d6
commit
7be20ad841
77
rp2040/src/bootloader.rs
Normal file
77
rp2040/src/bootloader.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//! Bootloader entry helpers shared between power-on checks and runtime combos.
|
||||||
|
|
||||||
|
use crate::{layout, status::StatusMode, StatusLed, 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: &[bool; NUMBER_OF_KEYS]) -> 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: &[bool; NUMBER_OF_KEYS], 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@
|
|||||||
//! details, status handling, and keyboard processing modular.
|
//! details, status handling, and keyboard processing modular.
|
||||||
|
|
||||||
pub mod button_matrix;
|
pub mod button_matrix;
|
||||||
|
pub mod bootloader;
|
||||||
pub mod hardware;
|
pub mod hardware;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use cmdr_keyboard_42::hardware::{self, timers};
|
use cmdr_keyboard_42::hardware::{self, timers};
|
||||||
use cmdr_keyboard_42::{ButtonMatrix, KeyboardState, StatusLed, StatusMode};
|
use cmdr_keyboard_42::{bootloader, ButtonMatrix, KeyboardState, StatusLed, StatusMode};
|
||||||
use cortex_m::delay::Delay;
|
use cortex_m::delay::Delay;
|
||||||
use embedded_hal::digital::{InputPin, OutputPin};
|
use embedded_hal::digital::{InputPin, OutputPin};
|
||||||
use embedded_hal_0_2::timer::CountDown;
|
use embedded_hal_0_2::timer::CountDown;
|
||||||
@ -26,6 +26,7 @@ use rp2040_hal::{
|
|||||||
use usb_device::class_prelude::*;
|
use usb_device::class_prelude::*;
|
||||||
use usb_device::prelude::*;
|
use usb_device::prelude::*;
|
||||||
use usb_device::device::UsbDeviceState;
|
use usb_device::device::UsbDeviceState;
|
||||||
|
use usbd_human_interface_device::page::Keyboard;
|
||||||
use usbd_human_interface_device::prelude::*;
|
use usbd_human_interface_device::prelude::*;
|
||||||
|
|
||||||
#[unsafe(link_section = ".boot2")]
|
#[unsafe(link_section = ".boot2")]
|
||||||
@ -127,11 +128,9 @@ fn main() -> ! {
|
|||||||
button_matrix.scan_matrix(&mut delay);
|
button_matrix.scan_matrix(&mut delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
if button_matrix.buttons_pressed()[0] {
|
let initial_pressed = button_matrix.buttons_pressed();
|
||||||
status_led.update(StatusMode::Bootloader);
|
if initial_pressed[0] {
|
||||||
let gpio_activity_pin_mask: u32 = 0;
|
bootloader::enter(&mut status_led);
|
||||||
let disable_interface_mask: u32 = 0;
|
|
||||||
rp2040_hal::rom_data::reset_to_usb_boot(gpio_activity_pin_mask, disable_interface_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let usb_bus = UsbBusAllocator::new(rp2040_hal::usb::UsbBus::new(
|
let usb_bus = UsbBusAllocator::new(rp2040_hal::usb::UsbBus::new(
|
||||||
@ -186,6 +185,26 @@ fn main() -> ! {
|
|||||||
button_matrix.scan_matrix(&mut delay);
|
button_matrix.scan_matrix(&mut delay);
|
||||||
let pressed_keys = button_matrix.buttons_pressed();
|
let pressed_keys = button_matrix.buttons_pressed();
|
||||||
|
|
||||||
|
if bootloader::chord_requested(&pressed_keys) {
|
||||||
|
if !usb_suspended {
|
||||||
|
let mut attempts: u8 = 0;
|
||||||
|
while attempts < 3 {
|
||||||
|
let clear_report = [Keyboard::NoEventIndicated; hardware::NUMBER_OF_KEYS];
|
||||||
|
match keyboard.device().write_report(clear_report) {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(UsbHidError::WouldBlock) | Err(UsbHidError::Duplicate) => {
|
||||||
|
let _ = keyboard.tick();
|
||||||
|
}
|
||||||
|
Err(_) => break,
|
||||||
|
}
|
||||||
|
attempts = attempts.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay.delay_ms(5);
|
||||||
|
bootloader::enter(&mut status_led);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for input activity
|
// Check for input activity
|
||||||
if pressed_keys.iter().any(|pressed| *pressed) {
|
if pressed_keys.iter().any(|pressed| *pressed) {
|
||||||
last_activity_ms = status_time_ms;
|
last_activity_ms = status_time_ms;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user