Skip to content

Commit 4f78d0a

Browse files
committed
Reads keyboard bytes and decodes them into HID events.
1 parent bfb4c5a commit 4f78d0a

4 files changed

Lines changed: 277 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Updated dependencies
66
* Initial support for hardware other than VGA output
7+
* Basic keyboard support
78

89
## v0.3.0 ([Source](https://github.com/neotron-compute/neotron-pico-bios/tree/v0.3.0) | [Release](https://github.com/neotron-compute/neotron-pico-bios/release/tag/v0.3.0))
910

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ critical-section = "1.0"
3636
neotron-bmc-protocol = { version = "0.1.0", git = "https://github.com/neotron-compute/neotron-bmc", tag="v0.4.0" }
3737
# Time and frequency related functions
3838
fugit = "0.3"
39+
# PS/2 scancode decoding
40+
pc-keyboard = "0.6"
41+
# Useful queues and other structures
42+
heapless = "0.7"
3943

4044
[features]
4145
default = [

src/flash1002.bin

1.23 KB
Binary file not shown.

src/main.rs

Lines changed: 272 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub mod vga;
4444
// -----------------------------------------------------------------------------
4545

4646
// Standard Library Stuff
47-
use core::fmt::Write;
47+
use core::{fmt::Write, sync::atomic::AtomicBool};
4848

4949
// Third Party Stuff
5050
use cortex_m_rt::entry;
@@ -89,6 +89,26 @@ struct Hardware {
8989
debug_leds: u8,
9090
/// The last CS pin we selected
9191
last_cs: u8,
92+
/// Our keyboard decoder
93+
keyboard: pc_keyboard::Keyboard<pc_keyboard::layouts::Uk105Key, pc_keyboard::ScancodeSet2>,
94+
/// Our queue of HID events
95+
event_queue: heapless::Deque<neotron_common_bios::hid::HidEvent, 16>,
96+
}
97+
98+
/// Flips between true and false so we always send a unique read request
99+
struct UseAlt(AtomicBool);
100+
101+
impl UseAlt {
102+
const fn new() -> UseAlt {
103+
UseAlt(AtomicBool::new(false))
104+
}
105+
106+
fn get(&self) -> bool {
107+
let use_alt = self.0.load(core::sync::atomic::Ordering::Relaxed);
108+
self.0
109+
.store(!use_alt, core::sync::atomic::Ordering::Relaxed);
110+
use_alt
111+
}
92112
}
93113

94114
/// All the pins we use on the Pico, in the right mode.
@@ -134,6 +154,9 @@ struct Pins {
134154
/// The BIOS version string
135155
static BIOS_VERSION: &str = concat!("Neotron Pico BIOS version ", env!("BIOS_VERSION"), "\0");
136156

157+
/// Ensures we always send a unique read request
158+
static USE_ALT: UseAlt = UseAlt::new();
159+
137160
/// Our global hardware object.
138161
///
139162
/// You need to grab this to do anything with the hardware.
@@ -517,6 +540,8 @@ impl Hardware {
517540
delay,
518541
debug_leds: 0,
519542
last_cs: 0,
543+
keyboard: pc_keyboard::Keyboard::new(pc_keyboard::HandleControl::Ignore),
544+
event_queue: heapless::Deque::new(),
520545
}
521546
}
522547

@@ -720,48 +745,57 @@ impl Hardware {
720745
/// Read the BMC PS/2 keyboard FIFO.
721746
///
722747
/// We ask for 8 bytes of data. We get `1` byte of 'length', then `N` bytes of valid data, and `32 - (N + 1)` bytes of padding.
723-
fn bmc_read_ps2_keyboard_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, ()> {
724-
let req = neotron_bmc_protocol::Request::new_read(false, 0x40, 8);
725-
let mut buffer = [0xFF; 42];
726-
buffer[0..=3].copy_from_slice(&req.as_bytes());
727-
self.with_bus_cs(0, |spi| {
728-
spi.transfer(&mut buffer).unwrap();
729-
});
730-
defmt::info!("buffer: {=[u8]:x}", buffer);
731-
let mut result = &buffer[..];
732-
let mut latency = 0;
733-
while result.len() > 0 && result[0] == 0xFF {
734-
latency += 1;
735-
result = &result[1..];
736-
}
737-
defmt::info!("latency: {}", latency);
738-
// 8 bytes of data requested, plus one bytes of response code and one byte of CRC
739-
if result.len() >= 10 {
740-
match neotron_bmc_protocol::Response::from_bytes(&result[0..10]) {
741-
Ok(res) => {
742-
if res.result == neotron_bmc_protocol::ResponseResult::Ok && res.data.len() == 8
743-
{
744-
defmt::info!("Got PS/2 bytes {=[u8]:x}", res.data);
745-
return Ok(0);
746-
} else {
748+
fn bmc_read_ps2_keyboard_fifo(&mut self, out_buffer: &mut [u8; 8]) -> Result<usize, ()> {
749+
let req = neotron_bmc_protocol::Request::new_read(USE_ALT.get(), 0x40, 8);
750+
for _retry in 0..4 {
751+
let mut buffer = [0xFF; 42];
752+
buffer[0..=3].copy_from_slice(&req.as_bytes());
753+
self.with_bus_cs(0, |spi| {
754+
spi.transfer(&mut buffer).unwrap();
755+
});
756+
defmt::trace!("buffer: {=[u8]:x}", buffer);
757+
let mut result = &buffer[..];
758+
let mut latency = 0;
759+
while result.len() > 0 && result[0] == 0xFF {
760+
latency += 1;
761+
result = &result[1..];
762+
}
763+
defmt::trace!("latency: {}", latency);
764+
// 8 bytes of data requested, plus one bytes of response code and one byte of CRC
765+
if result.len() >= 10 {
766+
match neotron_bmc_protocol::Response::from_bytes(&result[0..10]) {
767+
Ok(res) => {
768+
if res.result == neotron_bmc_protocol::ResponseResult::Ok
769+
&& res.data.len() == 8
770+
{
771+
if res.data[0] == 0 {
772+
defmt::trace!("Got no PS/2 bytes");
773+
} else {
774+
defmt::debug!("Got PS/2 bytes {=[u8]:x}", res.data);
775+
}
776+
for (dest, src) in out_buffer.iter_mut().zip(res.data.iter().skip(1)) {
777+
*dest = *src;
778+
}
779+
return Ok(res.data[0] as usize);
780+
} else {
781+
defmt::warn!(
782+
"Error getting keyboard bytes: Error from BMC {:?} {=[u8]:x}",
783+
res.result,
784+
res.data
785+
);
786+
}
787+
}
788+
Err(e) => {
747789
defmt::warn!(
748-
"Error getting keyboard bytes: Error from BMC {:?} {=[u8]:x}",
749-
res.result,
750-
res.data
790+
"Error getting BMC keyboard bytes: Decoding Error {:?} {=[u8]:x}",
791+
e,
792+
result
751793
);
752794
}
753795
}
754-
Err(e) => {
755-
defmt::warn!(
756-
"Error getting BMC keyboard bytes: Decoding Error {:?} {=[u8]:x}",
757-
e,
758-
result
759-
);
760-
}
761796
}
762797
}
763-
764-
Err(())
798+
panic!("KB retry timeout");
765799
}
766800
}
767801

@@ -1043,12 +1077,206 @@ pub extern "C" fn memory_get_region(region: u8) -> common::Option<common::Memory
10431077
///
10441078
/// This function doesn't block. It will return `Ok(None)` if there is no event ready.
10451079
pub extern "C" fn hid_get_event() -> common::Result<common::Option<common::hid::HidEvent>> {
1046-
// todo: call bmc_read_ps2_keyboard_fifo()
1047-
// todo: decode the PS/2 bytes we receive into HidEvents
1048-
// todo: cache all the bytes that don't make up a full HID event
1080+
let mut buffer = [0u8; 8];
10491081

1050-
// TODO: Support some HID events
1051-
common::Result::Ok(common::Option::None)
1082+
critical_section::with(|cs| {
1083+
let mut lock = HARDWARE.borrow_ref_mut(cs);
1084+
let hw = lock.as_mut().unwrap();
1085+
1086+
if let Some(ev) = hw.event_queue.pop_front() {
1087+
// Queued data available, so short-cut
1088+
return common::Result::Ok(common::Option::Some(ev));
1089+
}
1090+
1091+
match hw.bmc_read_ps2_keyboard_fifo(&mut buffer) {
1092+
Ok(n) if n > 0 => {
1093+
let slice = if n >= 8 { &buffer } else { &buffer[0..n] };
1094+
defmt::info!("{} bytes in KB FIFO, got: {=[u8]:x}", n, &slice);
1095+
for b in slice.iter() {
1096+
match hw.keyboard.add_byte(*b) {
1097+
Ok(Some(key_event)) => {
1098+
convert_hid_event(key_event, &mut hw.event_queue);
1099+
}
1100+
Ok(None) => {
1101+
// Need more data
1102+
}
1103+
Err(e) => {
1104+
panic!("Keyboard decode error!");
1105+
}
1106+
}
1107+
}
1108+
}
1109+
Ok(_) => {
1110+
// Say nothing - FIFO is empty
1111+
}
1112+
Err(e) => {
1113+
defmt::warn!("Read KB error: {:?}", e);
1114+
}
1115+
}
1116+
1117+
if let Some(ev) = hw.event_queue.pop_front() {
1118+
// Queued data available, so short-cut
1119+
common::Result::Ok(common::Option::Some(ev))
1120+
} else {
1121+
common::Result::Ok(common::Option::None)
1122+
}
1123+
})
1124+
}
1125+
1126+
fn convert_hid_event(
1127+
pc_keyboard_ev: pc_keyboard::KeyEvent,
1128+
ev_queue: &mut heapless::Deque<common::hid::HidEvent, 16>,
1129+
) {
1130+
match pc_keyboard_ev.state {
1131+
pc_keyboard::KeyState::Down => {
1132+
ev_queue
1133+
.push_back(common::hid::HidEvent::KeyPress(convert_hid_code(
1134+
pc_keyboard_ev.code,
1135+
)))
1136+
.unwrap();
1137+
}
1138+
pc_keyboard::KeyState::Up => {
1139+
ev_queue
1140+
.push_back(common::hid::HidEvent::KeyRelease(convert_hid_code(
1141+
pc_keyboard_ev.code,
1142+
)))
1143+
.unwrap();
1144+
}
1145+
pc_keyboard::KeyState::SingleShot => {
1146+
ev_queue
1147+
.push_back(common::hid::HidEvent::KeyPress(convert_hid_code(
1148+
pc_keyboard_ev.code,
1149+
)))
1150+
.unwrap();
1151+
ev_queue
1152+
.push_back(common::hid::HidEvent::KeyRelease(convert_hid_code(
1153+
pc_keyboard_ev.code,
1154+
)))
1155+
.unwrap();
1156+
}
1157+
}
1158+
}
1159+
1160+
fn convert_hid_code(pc_code: pc_keyboard::KeyCode) -> common::hid::KeyCode {
1161+
match pc_code {
1162+
pc_keyboard::KeyCode::AltLeft => common::hid::KeyCode::AltLeft,
1163+
pc_keyboard::KeyCode::AltRight => common::hid::KeyCode::AltRight,
1164+
pc_keyboard::KeyCode::ArrowDown => common::hid::KeyCode::ArrowDown,
1165+
pc_keyboard::KeyCode::ArrowLeft => common::hid::KeyCode::ArrowLeft,
1166+
pc_keyboard::KeyCode::ArrowRight => common::hid::KeyCode::ArrowRight,
1167+
pc_keyboard::KeyCode::ArrowUp => common::hid::KeyCode::ArrowUp,
1168+
pc_keyboard::KeyCode::BackSlash => common::hid::KeyCode::BackSlash,
1169+
pc_keyboard::KeyCode::Backspace => common::hid::KeyCode::Backspace,
1170+
pc_keyboard::KeyCode::BackTick => common::hid::KeyCode::BackTick,
1171+
pc_keyboard::KeyCode::BracketSquareLeft => common::hid::KeyCode::BracketSquareLeft,
1172+
pc_keyboard::KeyCode::BracketSquareRight => common::hid::KeyCode::BracketSquareRight,
1173+
pc_keyboard::KeyCode::Break => common::hid::KeyCode::PauseBreak,
1174+
pc_keyboard::KeyCode::CapsLock => common::hid::KeyCode::CapsLock,
1175+
pc_keyboard::KeyCode::Comma => common::hid::KeyCode::Comma,
1176+
pc_keyboard::KeyCode::ControlLeft => common::hid::KeyCode::ControlLeft,
1177+
pc_keyboard::KeyCode::ControlRight => common::hid::KeyCode::ControlRight,
1178+
pc_keyboard::KeyCode::Delete => common::hid::KeyCode::Delete,
1179+
pc_keyboard::KeyCode::End => common::hid::KeyCode::End,
1180+
pc_keyboard::KeyCode::Enter => common::hid::KeyCode::Enter,
1181+
pc_keyboard::KeyCode::Escape => common::hid::KeyCode::Escape,
1182+
pc_keyboard::KeyCode::Equals => common::hid::KeyCode::Equals,
1183+
pc_keyboard::KeyCode::F1 => common::hid::KeyCode::F1,
1184+
pc_keyboard::KeyCode::F2 => common::hid::KeyCode::F2,
1185+
pc_keyboard::KeyCode::F3 => common::hid::KeyCode::F3,
1186+
pc_keyboard::KeyCode::F4 => common::hid::KeyCode::F4,
1187+
pc_keyboard::KeyCode::F5 => common::hid::KeyCode::F5,
1188+
pc_keyboard::KeyCode::F6 => common::hid::KeyCode::F6,
1189+
pc_keyboard::KeyCode::F7 => common::hid::KeyCode::F7,
1190+
pc_keyboard::KeyCode::F8 => common::hid::KeyCode::F8,
1191+
pc_keyboard::KeyCode::F9 => common::hid::KeyCode::F9,
1192+
pc_keyboard::KeyCode::F10 => common::hid::KeyCode::F10,
1193+
pc_keyboard::KeyCode::F11 => common::hid::KeyCode::F11,
1194+
pc_keyboard::KeyCode::F12 => common::hid::KeyCode::F12,
1195+
pc_keyboard::KeyCode::Fullstop => common::hid::KeyCode::Fullstop,
1196+
pc_keyboard::KeyCode::Home => common::hid::KeyCode::Home,
1197+
pc_keyboard::KeyCode::Insert => common::hid::KeyCode::Insert,
1198+
pc_keyboard::KeyCode::Key1 => common::hid::KeyCode::Key1,
1199+
pc_keyboard::KeyCode::Key2 => common::hid::KeyCode::Key2,
1200+
pc_keyboard::KeyCode::Key3 => common::hid::KeyCode::Key3,
1201+
pc_keyboard::KeyCode::Key4 => common::hid::KeyCode::Key4,
1202+
pc_keyboard::KeyCode::Key5 => common::hid::KeyCode::Key5,
1203+
pc_keyboard::KeyCode::Key6 => common::hid::KeyCode::Key6,
1204+
pc_keyboard::KeyCode::Key7 => common::hid::KeyCode::Key7,
1205+
pc_keyboard::KeyCode::Key8 => common::hid::KeyCode::Key8,
1206+
pc_keyboard::KeyCode::Key9 => common::hid::KeyCode::Key9,
1207+
pc_keyboard::KeyCode::Key0 => common::hid::KeyCode::Key0,
1208+
pc_keyboard::KeyCode::Menus => common::hid::KeyCode::Menus,
1209+
pc_keyboard::KeyCode::Minus => common::hid::KeyCode::Minus,
1210+
pc_keyboard::KeyCode::Numpad0 => common::hid::KeyCode::Numpad0,
1211+
pc_keyboard::KeyCode::Numpad1 => common::hid::KeyCode::Numpad1,
1212+
pc_keyboard::KeyCode::Numpad2 => common::hid::KeyCode::Numpad2,
1213+
pc_keyboard::KeyCode::Numpad3 => common::hid::KeyCode::Numpad3,
1214+
pc_keyboard::KeyCode::Numpad4 => common::hid::KeyCode::Numpad4,
1215+
pc_keyboard::KeyCode::Numpad5 => common::hid::KeyCode::Numpad5,
1216+
pc_keyboard::KeyCode::Numpad6 => common::hid::KeyCode::Numpad6,
1217+
pc_keyboard::KeyCode::Numpad7 => common::hid::KeyCode::Numpad7,
1218+
pc_keyboard::KeyCode::Numpad8 => common::hid::KeyCode::Numpad8,
1219+
pc_keyboard::KeyCode::Numpad9 => common::hid::KeyCode::Numpad9,
1220+
pc_keyboard::KeyCode::NumpadEnter => common::hid::KeyCode::NumpadEnter,
1221+
pc_keyboard::KeyCode::NumpadLock => common::hid::KeyCode::NumpadLock,
1222+
pc_keyboard::KeyCode::NumpadSlash => common::hid::KeyCode::NumpadSlash,
1223+
pc_keyboard::KeyCode::NumpadStar => common::hid::KeyCode::NumpadStar,
1224+
pc_keyboard::KeyCode::NumpadMinus => common::hid::KeyCode::NumpadMinus,
1225+
pc_keyboard::KeyCode::NumpadPeriod => common::hid::KeyCode::NumpadPeriod,
1226+
pc_keyboard::KeyCode::NumpadPlus => common::hid::KeyCode::NumpadPlus,
1227+
pc_keyboard::KeyCode::PageDown => common::hid::KeyCode::PageDown,
1228+
pc_keyboard::KeyCode::PageUp => common::hid::KeyCode::PageUp,
1229+
pc_keyboard::KeyCode::PauseBreak => common::hid::KeyCode::PauseBreak,
1230+
pc_keyboard::KeyCode::PrintScreen => common::hid::KeyCode::PrintScreen,
1231+
pc_keyboard::KeyCode::ScrollLock => common::hid::KeyCode::ScrollLock,
1232+
pc_keyboard::KeyCode::SemiColon => common::hid::KeyCode::SemiColon,
1233+
pc_keyboard::KeyCode::ShiftLeft => common::hid::KeyCode::ShiftLeft,
1234+
pc_keyboard::KeyCode::ShiftRight => common::hid::KeyCode::ShiftRight,
1235+
pc_keyboard::KeyCode::Slash => common::hid::KeyCode::Slash,
1236+
pc_keyboard::KeyCode::Spacebar => common::hid::KeyCode::Spacebar,
1237+
pc_keyboard::KeyCode::Tab => common::hid::KeyCode::Tab,
1238+
pc_keyboard::KeyCode::Quote => common::hid::KeyCode::Quote,
1239+
pc_keyboard::KeyCode::WindowsLeft => common::hid::KeyCode::WindowsLeft,
1240+
pc_keyboard::KeyCode::WindowsRight => common::hid::KeyCode::WindowsRight,
1241+
pc_keyboard::KeyCode::A => common::hid::KeyCode::A,
1242+
pc_keyboard::KeyCode::B => common::hid::KeyCode::B,
1243+
pc_keyboard::KeyCode::C => common::hid::KeyCode::C,
1244+
pc_keyboard::KeyCode::D => common::hid::KeyCode::D,
1245+
pc_keyboard::KeyCode::E => common::hid::KeyCode::E,
1246+
pc_keyboard::KeyCode::F => common::hid::KeyCode::F,
1247+
pc_keyboard::KeyCode::G => common::hid::KeyCode::G,
1248+
pc_keyboard::KeyCode::H => common::hid::KeyCode::H,
1249+
pc_keyboard::KeyCode::I => common::hid::KeyCode::I,
1250+
pc_keyboard::KeyCode::J => common::hid::KeyCode::J,
1251+
pc_keyboard::KeyCode::K => common::hid::KeyCode::K,
1252+
pc_keyboard::KeyCode::L => common::hid::KeyCode::L,
1253+
pc_keyboard::KeyCode::M => common::hid::KeyCode::M,
1254+
pc_keyboard::KeyCode::N => common::hid::KeyCode::N,
1255+
pc_keyboard::KeyCode::O => common::hid::KeyCode::O,
1256+
pc_keyboard::KeyCode::P => common::hid::KeyCode::P,
1257+
pc_keyboard::KeyCode::Q => common::hid::KeyCode::Q,
1258+
pc_keyboard::KeyCode::R => common::hid::KeyCode::R,
1259+
pc_keyboard::KeyCode::S => common::hid::KeyCode::S,
1260+
pc_keyboard::KeyCode::T => common::hid::KeyCode::T,
1261+
pc_keyboard::KeyCode::U => common::hid::KeyCode::U,
1262+
pc_keyboard::KeyCode::V => common::hid::KeyCode::V,
1263+
pc_keyboard::KeyCode::W => common::hid::KeyCode::W,
1264+
pc_keyboard::KeyCode::X => common::hid::KeyCode::X,
1265+
pc_keyboard::KeyCode::Y => common::hid::KeyCode::Y,
1266+
pc_keyboard::KeyCode::Z => common::hid::KeyCode::Z,
1267+
pc_keyboard::KeyCode::HashTilde => common::hid::KeyCode::HashTilde,
1268+
pc_keyboard::KeyCode::PrevTrack => common::hid::KeyCode::PrevTrack,
1269+
pc_keyboard::KeyCode::NextTrack => common::hid::KeyCode::NextTrack,
1270+
pc_keyboard::KeyCode::Mute => common::hid::KeyCode::Mute,
1271+
pc_keyboard::KeyCode::Calculator => common::hid::KeyCode::Calculator,
1272+
pc_keyboard::KeyCode::Play => common::hid::KeyCode::Play,
1273+
pc_keyboard::KeyCode::Stop => common::hid::KeyCode::Stop,
1274+
pc_keyboard::KeyCode::VolumeDown => common::hid::KeyCode::VolumeDown,
1275+
pc_keyboard::KeyCode::VolumeUp => common::hid::KeyCode::VolumeUp,
1276+
pc_keyboard::KeyCode::WWWHome => common::hid::KeyCode::WWWHome,
1277+
pc_keyboard::KeyCode::PowerOnTestOk => common::hid::KeyCode::PowerOnTestOk,
1278+
_ => common::hid::KeyCode::X,
1279+
}
10521280
}
10531281

10541282
/// Control the keyboard LEDs.
@@ -1292,7 +1520,8 @@ extern "C" fn block_dev_eject(dev_id: u8) -> common::Result<()> {
12921520

12931521
/// Sleep the CPU until the next interrupt.
12941522
extern "C" fn power_idle() {
1295-
cortex_m::asm::wfe();
1523+
// cortex_m::asm::wfe();
1524+
cortex_m::asm::delay(10_000_000);
12961525
}
12971526

12981527
/// TODO: Get the monotonic run-time of the system from SysTick.

0 commit comments

Comments
 (0)