Skip to content

Commit 9b3a89c

Browse files
committed
Adds a basic keyboard FIFO.
1 parent c312705 commit 9b3a89c

File tree

1 file changed

+88
-32
lines changed

1 file changed

+88
-32
lines changed

neotron-bmc-pico/src/main.rs

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,18 @@ pub enum DcPowerState {
5252
}
5353

5454
/// This is our system state, as accessible via SPI reads and writes.
55-
#[derive(Debug)]
55+
#[derive(Debug, Default)]
5656
pub struct RegisterState {
57+
/// The version of this firmware
5758
firmware_version: [u8; 32],
59+
/// Bytes we've read from the keyboard, ready for sending to the host
60+
ps2_kb_bytes: heapless::Deque<u8, 16>,
61+
/// Used for holding our TX buffer, so we can re-send if required
62+
scratch: [u8; 16],
63+
/// A copy of the last request, so we can spot duplicates and re-send
64+
/// without re-doing a FIFO read. This happens if our response gets a CRC
65+
/// error.
66+
last_req: Option<proto::Request>,
5867
}
5968

6069
#[app(device = crate::pac, peripherals = true, dispatchers = [USB, USART3_4_5_6, TIM14, TIM15, TIM16, TIM17, PVD])]
@@ -339,8 +348,8 @@ mod app {
339348
#[idle(shared = [msg_q_out, msg_q_in, spi])]
340349
fn idle(mut ctx: idle::Context) -> ! {
341350
let mut register_state = RegisterState {
342-
firmware_version:
343-
*b"Neotron BMC v0.3.1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
351+
firmware_version: *b"Neotron BMC v0.4.1-alpha\x00\x00\x00\x00\x00\x00\x00\x00",
352+
..Default::default()
344353
};
345354

346355
defmt::info!("Idle is running...");
@@ -349,8 +358,9 @@ mod app {
349358
Some(Message::Ps2Data0(word)) => {
350359
if let Some(byte) = neotron_bmc_pico::ps2::Ps2Decoder::check_word(word) {
351360
defmt::info!("< KB 0x{:x}", byte);
352-
// TODO: Copy byte to software buffer and turn PS/2 bus off
353-
// if buffer is full
361+
if let Err(_x) = register_state.ps2_kb_bytes.push_back(byte) {
362+
defmt::warn!("KB overflow!");
363+
}
354364
} else {
355365
defmt::warn!("< Bad KB 0x{:x}", word);
356366
}
@@ -362,25 +372,22 @@ mod app {
362372
defmt::warn!("< Bad MS 0x{:x}", word);
363373
}
364374
}
365-
Some(Message::PowerButtonLongPress) => {}
366-
Some(Message::PowerButtonShortPress) => {}
367-
Some(Message::ResetButtonShortPress) => {}
368-
Some(Message::SpiRequest(req)) => match req.request_type {
369-
proto::RequestType::Read | proto::RequestType::ReadAlt => {
370-
process_command(req, &mut register_state, |rsp| {
371-
ctx.shared.spi.lock(|spi| {
372-
spi.set_transmit_sendable(rsp).unwrap();
373-
});
374-
});
375-
}
376-
_ => {
377-
let rsp =
378-
proto::Response::new_without_data(proto::ResponseResult::BadLength);
375+
Some(Message::PowerButtonLongPress) => {
376+
// TODO: Move button handling out of ISR
377+
}
378+
Some(Message::PowerButtonShortPress) => {
379+
// TODO: Move button handling out of ISR
380+
}
381+
Some(Message::ResetButtonShortPress) => {
382+
// TODO: Move button handling out of ISR
383+
}
384+
Some(Message::SpiRequest(req)) => {
385+
process_command(req, &mut register_state, |rsp| {
379386
ctx.shared.spi.lock(|spi| {
380-
spi.set_transmit_sendable(&rsp).unwrap();
387+
spi.set_transmit_sendable(rsp).unwrap();
381388
});
382-
}
383-
},
389+
});
390+
}
384391
Some(Message::UartByte(rx_byte)) => {
385392
defmt::info!("UART RX {:?}", rx_byte);
386393
// TODO: Copy byte to software buffer and turn UART RX
@@ -625,26 +632,75 @@ fn process_command<F>(req: proto::Request, register_state: &mut RegisterState, r
625632
where
626633
F: FnOnce(&proto::Response),
627634
{
628-
let rsp = match Command::parse(req.register) {
629-
Some(Command::ProtocolVersion) => {
635+
if register_state.last_req.as_ref() == Some(&req) {
636+
// A duplicate! Resend what we sent last time (so we don't affect FIFOs with a duplicate read).
637+
let length = req.length_or_data as usize;
638+
let rsp = proto::Response::new_ok_with_data(&register_state.scratch[0..length]);
639+
defmt::warn!("Retry");
640+
rsp_handler(&rsp);
641+
return;
642+
}
643+
644+
// We were not sent what we were sent last time, so forget the previous request.
645+
register_state.last_req = None;
646+
647+
// What do they want?
648+
let rsp = match (req.request_type, Command::parse(req.register)) {
649+
(proto::RequestType::Read, Some(Command::ProtocolVersion))
650+
| (proto::RequestType::ReadAlt, Some(Command::ProtocolVersion)) => {
651+
defmt::debug!("Reading ProtocolVersion");
652+
// They want the Protocol Version we support. Give them v0.1.1.
630653
let length = req.length_or_data as usize;
631-
if length != 3 {
632-
proto::Response::new_without_data(proto::ResponseResult::BadLength)
633-
} else {
654+
if length == 3 {
655+
// No need to cache
634656
proto::Response::new_ok_with_data(&[0, 1, 1])
657+
} else {
658+
proto::Response::new_without_data(proto::ResponseResult::BadLength)
635659
}
636660
}
637-
Some(Command::FirmwareVersion) => {
661+
(proto::RequestType::Read, Some(Command::FirmwareVersion))
662+
| (proto::RequestType::ReadAlt, Some(Command::FirmwareVersion)) => {
663+
defmt::debug!("Reading FirmwareVersion");
664+
// They want the Firmware Version string.
638665
let length = req.length_or_data as usize;
639-
if length > register_state.firmware_version.len() {
640-
proto::Response::new_without_data(proto::ResponseResult::BadLength)
641-
} else {
666+
if length <= register_state.firmware_version.len() {
642667
let bytes = &register_state.firmware_version;
668+
// No need to cache
643669
proto::Response::new_ok_with_data(&bytes[0..length])
670+
} else {
671+
proto::Response::new_without_data(proto::ResponseResult::BadLength)
672+
}
673+
}
674+
(proto::RequestType::Read, Some(Command::Ps2KbBuffer))
675+
| (proto::RequestType::ReadAlt, Some(Command::Ps2KbBuffer)) => {
676+
defmt::debug!("Reading Ps2KbBuffer");
677+
let length = req.length_or_data as usize;
678+
if length > 0 && length <= register_state.scratch.len() {
679+
// First byte is the # bytes in the FIFO
680+
register_state.scratch[0] = register_state.ps2_kb_bytes.len() as u8;
681+
// Then as many of those FIFO bytes as fit
682+
for slot in &mut register_state.scratch[1..] {
683+
if let Some(x) = register_state.ps2_kb_bytes.pop_front() {
684+
*slot = x;
685+
} else {
686+
*slot = 0;
687+
}
688+
}
689+
// OK, cache this one because FIFO reads are damaing.
690+
register_state.last_req = Some(req);
691+
// Send the response
692+
proto::Response::new_ok_with_data(&register_state.scratch[0..length])
693+
} else {
694+
// Can't help you - you want a weird number of bytes
695+
proto::Response::new_without_data(proto::ResponseResult::BadLength)
644696
}
645697
}
646-
_ => proto::Response::new_without_data(proto::ResponseResult::BadRegister),
698+
_ => {
699+
// Sorry, that register / request type is not supported
700+
proto::Response::new_without_data(proto::ResponseResult::BadRegister)
701+
}
647702
};
703+
defmt::debug!("Sending {:?}", rsp);
648704
rsp_handler(&rsp);
649705
}
650706

0 commit comments

Comments
 (0)