// keyboard wiring diagram: https://www.minuszerodegrees.net/5150/misc/5150_keyboard_reset.jpg constexpr int kClockPin = PC6; constexpr int kDataPin = PC4; constexpr int kBitDelayMicros = 100; constexpr int kCodeDelayMicros = 200; constexpr int kKeyDelayMicros = 100; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT); pinMode(kClockPin, INPUT); pinMode(kDataPin, INPUT); Serial.println("kbd 0.1"); } // 0. reset // 0.0. clock line will be held low externally for 20 ms // when back up, keyboard needs to clock 0xAA as a response // // 1. operation // 1.0. just directly clock out scan codes of pressed keys void sendCode(int code) { Serial.printf("sending code 0x%02x\n", code); // preconditions: clock and data pins are INPUT while (digitalRead(kDataPin) == LOW || digitalRead(kClockPin) == LOW) { // wait. we're not allowed to send } digitalWrite(kDataPin, LOW); digitalWrite(kClockPin, LOW); pinMode(kClockPin, OUTPUT); delayMicroseconds(kBitDelayMicros); pinMode(kClockPin, INPUT); // delayMicroseconds(kDelayMicros); for (int i = 0; i < 8; i++) { if ((code & (1 << i)) == 0) { // send a 0 pinMode(kDataPin, OUTPUT); } // else do nothing, it's already a 1 delayMicroseconds(kBitDelayMicros); pinMode(kClockPin, OUTPUT); delayMicroseconds(kBitDelayMicros); pinMode(kDataPin, INPUT); pinMode(kClockPin, INPUT); } delayMicroseconds(kCodeDelayMicros); } enum State { kReady, kMaybeReset, }; constexpr int kResetDelay = 19; State state = State::kReady; int lastclocklow = 0; constexpr int kLetterCodes[] = { 0x1E, // 'a' 0x30, 0x2E, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2c, }; constexpr int kNumberCodes[] = { 0x0B, // '0' 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, }; void sendNormalCode(int code) { sendCode(code); sendCode(code | 0x80); } void sendShiftCode(int code) { sendCode(42); // left shift sendNormalCode(code); sendCode(42 | 0x80); } void sendAsciiChar(int c) { if (c >= 'a' && c <= 'z') { return sendNormalCode(kLetterCodes[c - 'a']); } else if (c >= '0' && c <= '9') { return sendNormalCode(kNumberCodes[c - '0']); } else if (c >= 'A' && c <= 'Z') { return sendShiftCode(kLetterCodes[c - 'A']); } switch (c) { case '-': return sendNormalCode(12); case '=': return sendNormalCode(13); case '[': return sendNormalCode(26); case ']': return sendNormalCode(27); case ';': return sendNormalCode(39); case '\'': return sendNormalCode(40); case ',': return sendNormalCode(51); case '.': return sendNormalCode(52); case '/': return sendNormalCode(53); case ' ': return sendNormalCode(57); case '\n': return sendNormalCode(28); case '!': return sendShiftCode(2); case '@': return sendShiftCode(3); case '#': return sendShiftCode(4); case '$': return sendShiftCode(5); case '%': return sendShiftCode(6); case '^': return sendShiftCode(7); case '&': return sendShiftCode(8); case '*': return sendShiftCode(9); case '(': return sendShiftCode(10); case ')': return sendShiftCode(11); case '_': return sendShiftCode(12); case '+': return sendShiftCode(13); case '{': return sendShiftCode(26); case '}': return sendShiftCode(27); case ':': return sendShiftCode(39); case '"': return sendShiftCode(40); case '<': return sendShiftCode(51); case '>': return sendShiftCode(52); case '?': return sendShiftCode(53); } } void loop() { static int led_counter = 0; static int led = HIGH; if (led_counter > 400000) { led_counter = 0; led = (led == HIGH) ? LOW : HIGH; digitalWrite(LED_BUILTIN, led); } led_counter += 1; int clockp = digitalRead(kClockPin); if (state == State::kReady && clockp == LOW) { state = State::kMaybeReset; lastclocklow = millis(); } else if (state == State::kMaybeReset) { if (clockp == HIGH && millis() - lastclocklow > kResetDelay) { delay(1); state = State::kReady; sendCode(0xaa); Serial.println("Reset!"); } } if (Serial.available() > 0) { int c = Serial.read(); sendAsciiChar(c); //delayMicroseconds(kKeyDelayMicros); } }