consul-vdx-term-keyboard-co.../consul-vdx-term-keyboard-converter.ino

484 lines
9.8 KiB
Arduino
Raw Normal View History

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-04-06 06:11:52 +00:00
#define KEYBOARD
#ifdef KEYBOARD
#include <Keyboard.h>
#endif
2023-03-28 13:11:50 +00:00
#include <TimerOne.h>
2023-04-01 07:39:26 +00:00
// pinout config
const int pinLedOffline = 10; // out
const int pinLedOnline = 9; // out
const int pinSpeaker = 8; // out
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
const int slaveClockDivider = 8;
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;
volatile int typedKey = -1;
2023-04-06 05:59:00 +00:00
bool hostOnline = false;
2023-04-01 07:39:26 +00:00
// 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
// ----------
volatile long lastChange = -100000;
2023-03-28 13:11:50 +00:00
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;
//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;
typedKey = key;
//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);
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
// 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[155] = 'd';
m[155+32] = 'D';
2023-04-02 13:21:09 +00:00
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 13:28:36 +00:00
// bottom letter row
m[58] = 0x11; // No Scroll
m[133] = 'z';
m[133+32] = 'Z';
m[135] = 'x';
m[135+32] = 'X';
m[156] = 'c';
m[156+32] = 'C';
m[137] = 'v';
m[137+32] = 'V';
m[157] = 'b';
m[157+32] = 'B';
m[145] = 'n';
m[145+32] = 'N';
m[146] = 'm';
m[146+32] = 'M';
m[211] = ',';
m[211+32] = '<';
m[209] = '.';
m[209+32] = '>';
m[208] = '/';
m[208+32] = '?';
m[163] = '\\';
m[163+32] = '|';
m[78] = 'x'; // Blank cap
m[77] = 'X'; // Blank cap + shift
2023-04-02 13:28:36 +00:00
// spacebar
m[223] = ' '; // Spacebar
/*/ numpad
m[] = '';
m[+32] = '';
m[] = '';
m[+32] = '';
m[] = '';
m[+32] = '';
m[] = '';
m[+32] = '';
m[] = '';
m[+32] = '';
2023-04-02 13:21:09 +00:00
/*
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[] = '';
/**/
//
// 208 local ON
// 209 leave local
// 210 half/full duplex
// 211 go home?
// 212 print Ps junk
// 213 mem protect
// 214 disable NAT
// 217 clear line?
// 218 shows cursor
// 219 hides cursor
// 221 mem prot
// 223 reset prompt
// 241 random junk symbols
// 243 random junk symbols
// 244 stop junk
// 248 hides cursor
// 251 Hard copy
// 250 Keyb. Inh.
2023-04-01 07:39:26 +00:00
}
char translateKeyToChar(int key) {
if (sizeof(m) <= key) {
return 0;
}
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
2023-04-06 06:11:52 +00:00
if (!hostOnline) {
Keyboard.press(keyChar);
delay(10);
Keyboard.release(keyChar);
}
2023-04-01 07:39:26 +00:00
#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();
}
slaveClockStep = (slaveClockStep + 1) % slaveClockDivider;
2023-04-01 07:39:26 +00:00
}
// --------------
// User Interface
// --------------
2023-04-06 05:59:00 +00:00
void updateOnlineStatus()
{
long timeNow = millis();
2023-04-06 05:59:00 +00:00
hostOnline = (lastChange > timeNow) || ((timeNow - lastChange) < 10000);
digitalWrite(pinLedOffline, hostOnline ? LOW : HIGH);
digitalWrite(pinLedOnline, hostOnline ? HIGH : LOW);
}
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(pinLedOffline, OUTPUT);
pinMode(pinLedOnline, OUTPUT);
pinMode(pinSpeaker, OUTPUT);
2023-04-01 07:39:26 +00:00
pinMode(pinData, OUTPUT);
pinMode(dataPin, INPUT);
pinMode(outPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(pinStatus, INPUT_PULLUP);
digitalWrite(pinLedOffline, HIGH);
digitalWrite(pinLedOnline, HIGH);
2023-04-01 07:39:26 +00:00
digitalWrite(pinData, HIGH);
digitalWrite(outPin, LOW);
attachInterrupt(digitalPinToInterrupt(pinStatus), onHostStatusChange, CHANGE);
Timer1.initialize(timerDelay);
Timer1.attachInterrupt(onTimerInterrupt);
delay(500);
tone(pinSpeaker, 650, 200);
digitalWrite(pinLedOffline, LOW);
digitalWrite(pinLedOnline, HIGH);
delay(200);
tone(pinSpeaker, 500, 200);
digitalWrite(pinLedOffline, HIGH);
digitalWrite(pinLedOnline, LOW);
delay(200);
digitalWrite(pinLedOffline, LOW);
digitalWrite(pinLedOnline, LOW);
delay(500);
2023-04-06 05:59:00 +00:00
updateOnlineStatus();
tone(pinSpeaker, 440, 200);
delay(200);
2023-04-01 07:39:26 +00:00
Serial.println("Keyboard ready");
}
2023-03-30 04:23:06 +00:00
int qwe = 0;
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-01 07:39:26 +00:00
// type key from keyboard
if (counter >= numbits) {
processKbdByte(data);
data = B0;
counter = 0;
}
/**/
/*/ auto-type test
delay(2000);
int k = 128 + qwe;
typeKey(k);
qwe = (qwe + 1) % 128;
Serial.print("QWE "); Serial.println((int)k);
if (qwe % 5 == 0) delay(2000);
/**/
2023-04-06 05:59:00 +00:00
updateOnlineStatus();
if (nextKeyReady && !hostOnline) { // skip sending key without a host (used for USB)
nextKeyReady = false;
typedKey = nextKey;
}
if (!nextKeyReady && typedKey != -1) {
tone(pinSpeaker, 200 + typedKey, 100);
typedKey = -1;
}
delay(5);
2023-03-28 13:11:50 +00:00
}
2023-03-30 04:23:06 +00:00