Add parallel port comms to arduino

This commit is contained in:
2025-09-29 18:48:11 +02:00
parent 8b434f4434
commit e20b09f130
6 changed files with 485 additions and 200 deletions

View File

@@ -1,213 +1,67 @@
// keyboard wiring diagram: https://www.minuszerodegrees.net/5150/misc/5150_keyboard_reset.jpg
#include "kbd.h"
#include "paracomm.h"
#include "parallel.h"
constexpr int kClockPin = PC6;
constexpr int kDataPin = PC4;
constexpr int kBitDelayMicros = 100;
constexpr int kCodeDelayMicros = 200;
constexpr int kKeyDelayMicros = 100;
ParaComms pc;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(kClockPin, INPUT);
pinMode(kDataPin, INPUT);
setupKbd();
setupParallel();
Serial.println("kbd 0.1");
}
pc = ParaComms{
.mosi_cb =
[](uint8_t *data, uint8_t len) {
for (int i = 0; i < len; i++) {
Serial.printf("%c", data[i]);
pc.SendByte(data[i]); // echo
if (data[i] == '\r') {
pc.SendByte('\n');
}
}
},
};
// 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 sendCtrlAltDel() {
sendCode(0x1d); // ctrl
sendCode(0x38); // alt
sendCode(0x53); // del
sendCode(0x53 | 0x80);
sendCode(0x38 | 0x80);
sendCode(0x1d | 0x80);
}
void sendCtrlBreak() {
sendCode(0x1d); // ctrl
sendCode(0x46); // break
sendCode(0x46 | 0x80);
sendCode(0x1d | 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);
case 0: return sendCtrlAltDel();
case 27: return sendCtrlBreak(); // escape
}
Serial.println("kbd 0.1");
}
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;
static int led_counter = 0;
static int led = HIGH;
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!");
static int mode = 0; // 0 = keyboard, 1 = parallel
if (led_counter > 400000) {
led_counter = 0;
led = (led == HIGH) ? LOW : HIGH;
digitalWrite(LED_BUILTIN, led);
}
}
led_counter += 1;
if (Serial.available() > 0) {
int c = Serial.read();
sendAsciiChar(c);
//delayMicroseconds(kKeyDelayMicros);
}
checkKbdReset();
uint8_t mosib;
if (strobeOccurred(mosib)) {
pc.FeedMosiData(mosib);
uint8_t misob = pc.NextMisoNibble();
writeParallel(misob);
}
if (Serial.available() > 0) {
int c = Serial.read();
if (c == 2) {
mode = 0;
} else if (c == 3) {
mode = 1;
} else {
if (mode == 0) {
sendAsciiChar(c);
} else {
pc.SendByte(c);
}
}
}
}