1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-16 18:30:32 +00:00

Use BACK state; accept other ACKs at any time.

This commit is contained in:
Thomas Harte 2024-03-23 21:02:35 -04:00
parent 55f92e2411
commit 0e07f802ac

View File

@ -17,9 +17,13 @@ struct Keyboard {
Keyboard(HalfDuplexSerial &serial) : serial_(serial) {} Keyboard(HalfDuplexSerial &serial) : serial_(serial) {}
void set_key_state(int row, int column, bool is_pressed) { void set_key_state(int row, int column, bool is_pressed) {
// if(!scan_keyboard_) return; if(!scan_keyboard_) return;
// TODO: scan_keyboard_ seems to end up in the wrong state. Investigate.
// Don't waste bandwidth on repeating facts.
if(states_[row][column] == is_pressed) return;
states_[row][column] = is_pressed;
// Post new key event.
const uint8_t prefix = is_pressed ? 0b1100'0000 : 0b1101'0000; const uint8_t prefix = is_pressed ? 0b1100'0000 : 0b1101'0000;
enqueue(static_cast<uint8_t>(prefix | row), static_cast<uint8_t>(prefix | column)); enqueue(static_cast<uint8_t>(prefix | row), static_cast<uint8_t>(prefix | column));
consider_dequeue(); consider_dequeue();
@ -43,6 +47,14 @@ struct Keyboard {
} }
switch(phase_) { switch(phase_) {
case Phase::ExpectingACK:
if(input != NACK && input != SMAK && input != MACK && input != SACK) {
reset();
break;
}
phase_ = Phase::Idle;
[[fallthrough]];
case Phase::Idle: case Phase::Idle:
switch(input) { switch(input) {
case RQID: // Post keyboard ID. case RQID: // Post keyboard ID.
@ -58,14 +70,29 @@ struct Keyboard {
enqueue(0, 0); enqueue(0, 0);
break; break;
case NACK:
scan_keyboard_ = scan_mouse_ = false;
break;
case SMAK:
scan_keyboard_ = scan_mouse_ = true;
break;
case MACK:
scan_keyboard_ = false;
scan_mouse_ = true;
break;
case SACK:
scan_keyboard_ = true;
scan_mouse_ = false;
break;
default: default:
if((input & 0b1111'0000) == 0b0100'0000) { if((input & 0b1111'0000) == 0b0100'0000) {
// RQPD; request to echo the low nibble. // RQPD; request to echo the low nibble.
serial_.output(KeyboardParty, 0b1110'0000 | (input & 0b1111)); serial_.output(KeyboardParty, 0b1110'0000 | (input & 0b1111));
} } else if(!(input & 0b1111'1000)) {
if(!(input & 0b1111'1000)) {
// LEDS: should set LEd outputs. // LEDS: should set LEd outputs.
} else {
reset();
} }
break; break;
} }
@ -94,32 +121,9 @@ struct Keyboard {
reset(); reset();
break; break;
} }
dequeue_next();
phase_ = Phase::ExpectingACK; phase_ = Phase::ExpectingACK;
break; break;
case Phase::ExpectingACK:
switch(input) {
default:
reset();
break;
case NACK:
scan_keyboard_ = scan_mouse_ = false;
break;
case SMAK:
scan_keyboard_ = scan_mouse_ = true;
break;
case MACK:
scan_keyboard_ = false;
scan_mouse_ = true;
break;
case SACK:
scan_keyboard_ = true;
scan_mouse_ = false;
break;
}
phase_ = Phase::Idle;
break;
} }
consider_dequeue(); consider_dequeue();
@ -127,14 +131,16 @@ struct Keyboard {
} }
void consider_dequeue() { void consider_dequeue() {
if(phase_ == Phase::Idle) { if(phase_ == Phase::Idle && dequeue_next()) {
dequeue_next(); phase_ = Phase::ExpectingBACK;
} }
} }
private: private:
HalfDuplexSerial &serial_; HalfDuplexSerial &serial_;
bool states_[16][16]{};
bool scan_keyboard_ = false; bool scan_keyboard_ = false;
bool scan_mouse_ = false; bool scan_mouse_ = false;
enum class Phase { enum class Phase {