2023-04-01 07:39:26 +00:00
|
|
|
// Resources:
|
|
|
|
// [Consul 262.4 Converter] https://deskthority.net/viewtopic.php?t=26908
|
|
|
|
// [Consul 262.5 manual in CS] http://www.sapi.cz/prislusenstvi/c262-5.php#odkazp4
|
|
|
|
|
2023-03-28 13:11:50 +00:00
|
|
|
#include <TimerOne.h>
|
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
// pinout config
|
2023-04-01 20:11:50 +00:00
|
|
|
const int pinData = 6; // out, host data
|
|
|
|
const int pinStatus = 7; // in, host status
|
|
|
|
const int clockPin = 5; // out, kbd clock
|
|
|
|
const int dataPin = 3; // in, kbd data
|
|
|
|
const int outPin = 4; // out, kbd led
|
2023-03-28 13:11:50 +00:00
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
// constant config
|
2023-04-02 08:00:55 +00:00
|
|
|
const int slaveClockDivider = 8;
|
2023-04-02 08:03:32 +00:00
|
|
|
const int timerDelay = 520 / slaveClockDivider;
|
2023-03-29 18:40:53 +00:00
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
// variables
|
|
|
|
volatile int slaveClockStep = 0;
|
|
|
|
char m[255];
|
|
|
|
volatile int data = 0;
|
|
|
|
int test = 0;
|
|
|
|
volatile int counter = 0;
|
|
|
|
int numbits = 10;
|
|
|
|
|
|
|
|
// MODS >>>
|
|
|
|
// [1] send debug scancode information to serial port
|
|
|
|
bool modConsoleLog = true;
|
|
|
|
// <<< MODS
|
2023-03-28 13:11:50 +00:00
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
// ----------
|
|
|
|
// KBD Output
|
|
|
|
// ----------
|
2023-03-28 13:11:50 +00:00
|
|
|
volatile long lastChange = 0;
|
|
|
|
volatile int x = 0;
|
|
|
|
volatile int dataWord = 0;
|
|
|
|
volatile int dataState = 0;
|
|
|
|
volatile int dataDelay = 0;
|
2023-03-29 18:40:53 +00:00
|
|
|
volatile int packetDelay = 0;
|
|
|
|
volatile int packetTail = 0;
|
2023-03-28 13:11:50 +00:00
|
|
|
|
2023-03-30 04:23:06 +00:00
|
|
|
volatile bool nextKeyReady = false;
|
|
|
|
volatile byte nextKey = 0;
|
|
|
|
|
|
|
|
void typeKey(byte key) {
|
|
|
|
nextKey = key;
|
2023-03-30 13:58:00 +00:00
|
|
|
nextKeyReady = true;
|
2023-04-02 08:00:55 +00:00
|
|
|
//Serial.print("Typing key "); Serial.println((int) key);
|
2023-03-30 04:23:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sendKey(byte key) {
|
|
|
|
dataWord = key;
|
2023-03-29 19:25:28 +00:00
|
|
|
dataState = 8;
|
2023-03-29 18:40:53 +00:00
|
|
|
dataDelay = 0;
|
|
|
|
packetDelay = 0;
|
2023-03-30 13:58:00 +00:00
|
|
|
packetTail = 15;
|
2023-04-02 08:00:55 +00:00
|
|
|
//Serial.print("Sending key "); Serial.println((int) key);
|
2023-03-30 04:23:06 +00:00
|
|
|
}
|
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
void onHostStatusChange() {
|
2023-03-30 04:23:06 +00:00
|
|
|
long timeNow = millis();
|
|
|
|
long changeDiff = timeNow - lastChange;
|
|
|
|
lastChange = timeNow;
|
|
|
|
if (changeDiff >= 10 && nextKeyReady) {
|
|
|
|
nextKeyReady = false;
|
2023-03-30 13:58:00 +00:00
|
|
|
sendKey(nextKey);
|
2023-04-02 08:00:55 +00:00
|
|
|
Timer1.start(); // synchronize with the host
|
|
|
|
slaveClockStep = 0;
|
2023-03-28 13:11:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
void onHostClockCycle(void)
|
2023-03-28 13:11:50 +00:00
|
|
|
{
|
2023-03-28 15:00:33 +00:00
|
|
|
int dataBit = HIGH;
|
2023-03-29 18:40:53 +00:00
|
|
|
if (packetDelay > 0) {
|
|
|
|
packetDelay--;
|
|
|
|
} else if (dataDelay > 0) {
|
2023-03-28 15:00:33 +00:00
|
|
|
dataDelay--;
|
2023-03-29 18:40:53 +00:00
|
|
|
dataBit = LOW;
|
2023-03-28 15:00:33 +00:00
|
|
|
} else if (dataState > 0) {
|
|
|
|
int bitToSend = (dataWord >> (dataState - 1)) & 1;
|
|
|
|
dataBit = !bitToSend ? LOW : HIGH;
|
|
|
|
dataState--;
|
2023-03-29 18:40:53 +00:00
|
|
|
} else if (packetTail > 0) {
|
|
|
|
packetTail--;
|
|
|
|
dataBit = LOW;
|
2023-03-28 15:00:33 +00:00
|
|
|
} else {
|
|
|
|
}
|
|
|
|
digitalWrite(pinData, dataBit);
|
2023-03-28 13:11:50 +00:00
|
|
|
}
|
2023-04-01 07:39:26 +00:00
|
|
|
|
|
|
|
// ---------
|
|
|
|
// KBD Input
|
|
|
|
// ---------
|
|
|
|
const int receivingSteps = 16;
|
|
|
|
volatile int clockStep = 0;
|
|
|
|
volatile int receivingStep = 0;
|
|
|
|
volatile int receivingData = 0;
|
|
|
|
volatile int receivingBit = 0;
|
|
|
|
|
|
|
|
void onSlaveClockInterrupt() {
|
|
|
|
clockStep = (clockStep + 1) % 2;
|
|
|
|
int clockValue = (clockStep % 2) ? HIGH : LOW;
|
|
|
|
digitalWrite(clockPin, clockValue);
|
|
|
|
int dataBit = digitalRead(dataPin);
|
|
|
|
if (clockValue == LOW) {
|
|
|
|
if (receivingData == 0 && dataBit == LOW) {
|
|
|
|
receivingData = 1;
|
|
|
|
receivingStep = 0;
|
|
|
|
receivingBit = 0;
|
|
|
|
test = 0;
|
|
|
|
} else if (receivingData == 1) {
|
|
|
|
receivingStep++;
|
|
|
|
}
|
|
|
|
if (receivingData == 1 && test == 0) {
|
|
|
|
test = 1;
|
|
|
|
receivingBit += dataBit == HIGH ? 1 : 0;
|
|
|
|
if (receivingStep >= receivingSteps) {
|
|
|
|
if (counter <= 8) {
|
|
|
|
data = data >> 1;
|
|
|
|
if (receivingBit > receivingSteps / 2) {
|
|
|
|
bitSet(data, 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
counter++;
|
|
|
|
receivingStep = 0;
|
|
|
|
receivingBit = 0;
|
|
|
|
if (counter >= numbits) {
|
|
|
|
receivingData = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (clockValue == HIGH && test == 1) {
|
|
|
|
test = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupKeyMapping() {
|
2023-04-02 08:27:48 +00:00
|
|
|
m[0] = 0;
|
2023-04-02 11:32:19 +00:00
|
|
|
m[223] = ' '; // Spacebar
|
|
|
|
// top row special
|
|
|
|
m[63] = 0x12; // ?? Setup
|
|
|
|
m[62] = 'j'; // up
|
|
|
|
m[61] = 'k'; // down
|
|
|
|
m[59] = 'h'; // left
|
|
|
|
m[60] = 'l'; // right
|
|
|
|
// top numbers row
|
|
|
|
m[228] = 0x1B; // ESC
|
|
|
|
m[206] = '1';
|
|
|
|
m[205] = '2';
|
|
|
|
m[204] = '3';
|
|
|
|
m[203] = '4';
|
|
|
|
m[202] = '5';
|
|
|
|
m[201] = '6';
|
|
|
|
m[200] = '7';
|
|
|
|
m[199] = '8';
|
|
|
|
m[198] = '9';
|
|
|
|
m[207] = '0';
|
|
|
|
m[210] = '-';
|
|
|
|
m[161] = '^';
|
|
|
|
m[0] = ' '; // Empty cap
|
|
|
|
m[247] = 0x08; // Backspace
|
|
|
|
m[56] = 0x10; // Break
|
|
|
|
// top letter row
|
2023-04-02 08:27:48 +00:00
|
|
|
m[246] = '\t';
|
|
|
|
m[142] = 'q';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[142+32] = 'Q';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[136] = 'w';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[136+32] = 'W';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[154] = 'e';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[154+32] = 'E';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[141] = 'r';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[141+32] = 'R';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[139] = 't';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[139+32] = 'T';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[134] = 'y';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[134+32] = 'Y';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[138] = 'u';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[138+32] = 'U';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[150] = 'i';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[150+32] = 'I';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[144] = 'o';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[144+32] = 'O';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[143] = 'p';
|
2023-04-02 11:13:50 +00:00
|
|
|
m[143+32] = 'P';
|
2023-04-02 08:27:48 +00:00
|
|
|
m[191] = '@';
|
|
|
|
m[164] = '[';
|
|
|
|
m[245] = 0x0A;
|
|
|
|
m[128] = 0x7F;
|
|
|
|
// middle letter row
|
2023-04-02 13:21:09 +00:00
|
|
|
m[158] = 'a';
|
|
|
|
m[158+32] = 'A';
|
|
|
|
m[140] = 's';
|
|
|
|
m[140+32] = 'S';
|
|
|
|
m[153] = 'd'; // TODO
|
|
|
|
m[153+32] = 'D'; // TODO
|
|
|
|
m[153] = 'f';
|
|
|
|
m[153+32] = 'F';
|
|
|
|
m[152] = 'g';
|
|
|
|
m[152+32] = 'G';
|
|
|
|
m[151] = 'h';
|
|
|
|
m[151+32] = 'H';
|
|
|
|
m[149] = 'j';
|
|
|
|
m[149+32] = 'J';
|
|
|
|
m[148] = 'k';
|
|
|
|
m[148+32] = 'K';
|
|
|
|
m[147] = 'l';
|
|
|
|
m[147+32] = 'L';
|
|
|
|
m[196] = ';';
|
|
|
|
m[196+32] = '+';
|
|
|
|
m[197] = ':';
|
|
|
|
m[197+32] = '*';
|
|
|
|
m[162] = ']';
|
|
|
|
m[162+32] = '}';
|
|
|
|
m[242] = 0x0D;
|
|
|
|
/*
|
2023-04-02 08:27:48 +00:00
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
m[] = '';
|
|
|
|
/**/
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char translateKeyToChar(int key) {
|
|
|
|
if (sizeof(m) <= key) {
|
|
|
|
return 0;
|
|
|
|
}
|
2023-04-02 08:00:55 +00:00
|
|
|
return m[key];
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void printChar(char keyChar) {
|
|
|
|
Serial.print("'"); Serial.print(keyChar); Serial.print("' ("); Serial.print(int(keyChar)); Serial.println(")");
|
|
|
|
}
|
|
|
|
|
|
|
|
void processKbdByte(int data) {
|
|
|
|
int key = data;
|
2023-04-02 08:27:48 +00:00
|
|
|
char keyChar = translateKeyToChar(key);
|
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
if (modConsoleLog) {
|
|
|
|
Serial.print("Key: <"); Serial.print(int(key)); Serial.print("> ");
|
2023-04-02 08:27:48 +00:00
|
|
|
Serial.print("Char: "); printChar(keyChar);
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
2023-04-02 08:27:48 +00:00
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
#ifdef KEYBOARD
|
|
|
|
Keyboard.press(keyChar);
|
|
|
|
delay(10);
|
|
|
|
Keyboard.release(keyChar);
|
|
|
|
#endif
|
2023-04-01 20:11:50 +00:00
|
|
|
|
|
|
|
typeKey(keyChar);
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------
|
|
|
|
// Input and Output Merge
|
|
|
|
// ----------------------
|
|
|
|
void onTimerInterrupt()
|
|
|
|
{
|
|
|
|
onSlaveClockInterrupt();
|
|
|
|
|
|
|
|
if (slaveClockStep == 0) {
|
|
|
|
onHostClockCycle();
|
|
|
|
}
|
2023-04-02 08:00:55 +00:00
|
|
|
slaveClockStep = (slaveClockStep + 1) % slaveClockDivider;
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----
|
|
|
|
// Main
|
|
|
|
// ----
|
|
|
|
void setup(void)
|
2023-03-28 13:11:50 +00:00
|
|
|
{
|
2023-04-01 07:39:26 +00:00
|
|
|
Serial.begin(9600);
|
|
|
|
|
|
|
|
setupKeyMapping();
|
|
|
|
|
|
|
|
pinMode(pinData, OUTPUT);
|
|
|
|
pinMode(dataPin, INPUT);
|
|
|
|
pinMode(outPin, OUTPUT);
|
|
|
|
pinMode(clockPin, OUTPUT);
|
|
|
|
pinMode(pinStatus, INPUT_PULLUP);
|
|
|
|
|
|
|
|
digitalWrite(pinData, HIGH);
|
|
|
|
digitalWrite(outPin, LOW);
|
|
|
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(pinStatus), onHostStatusChange, CHANGE);
|
|
|
|
|
|
|
|
Timer1.initialize(timerDelay);
|
|
|
|
Timer1.attachInterrupt(onTimerInterrupt);
|
|
|
|
|
|
|
|
Serial.println("Keyboard ready");
|
|
|
|
}
|
2023-03-30 04:23:06 +00:00
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
void loop(void)
|
|
|
|
{
|
|
|
|
// type key from serial
|
|
|
|
if (!nextKeyReady && Serial.available() > 0) {
|
2023-03-30 04:23:06 +00:00
|
|
|
long key = Serial.parseInt(SKIP_ALL);
|
|
|
|
if (key != 0) {
|
|
|
|
typeKey(key);
|
|
|
|
}
|
2023-04-01 07:39:26 +00:00
|
|
|
}
|
2023-04-02 08:00:55 +00:00
|
|
|
/**/
|
|
|
|
|
2023-04-01 07:39:26 +00:00
|
|
|
// type key from keyboard
|
|
|
|
if (counter >= numbits) {
|
|
|
|
processKbdByte(data);
|
|
|
|
data = B0;
|
|
|
|
counter = 0;
|
|
|
|
}
|
2023-04-02 08:00:55 +00:00
|
|
|
/**/
|
|
|
|
|
|
|
|
/*/ auto-type test
|
|
|
|
delay(500);
|
|
|
|
typeKey('B');
|
|
|
|
/**/
|
2023-03-28 13:11:50 +00:00
|
|
|
}
|
2023-03-30 04:23:06 +00:00
|
|
|
|