// 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 #include // pinout config 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 // constant config const int slaveClockDivider = 8; const int timerDelay = 520 / slaveClockDivider; // 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 // ---------- // KBD Output // ---------- volatile long lastChange = 0; volatile int x = 0; volatile int dataWord = 0; volatile int dataState = 0; volatile int dataDelay = 0; volatile int packetDelay = 0; volatile int packetTail = 0; volatile bool nextKeyReady = false; volatile byte nextKey = 0; void typeKey(byte key) { nextKey = key; nextKeyReady = true; //Serial.print("Typing key "); Serial.println((int) key); } void sendKey(byte key) { dataWord = key; dataState = 8; dataDelay = 0; packetDelay = 0; packetTail = 15; //Serial.print("Sending key "); Serial.println((int) key); } void onHostStatusChange() { long timeNow = millis(); long changeDiff = timeNow - lastChange; lastChange = timeNow; if (changeDiff >= 10 && nextKeyReady) { nextKeyReady = false; sendKey(nextKey); Timer1.start(); // synchronize with the host slaveClockStep = 0; } } void onHostClockCycle(void) { int dataBit = HIGH; if (packetDelay > 0) { packetDelay--; } else if (dataDelay > 0) { dataDelay--; dataBit = LOW; } else if (dataState > 0) { int bitToSend = (dataWord >> (dataState - 1)) & 1; dataBit = !bitToSend ? LOW : HIGH; dataState--; } else if (packetTail > 0) { packetTail--; dataBit = LOW; } else { } digitalWrite(pinData, dataBit); } // --------- // 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; digitalWrite(outPin, HIGH); } else if (receivingData == 1) { receivingStep++; digitalWrite(outPin, HIGH); } 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; digitalWrite(outPin, LOW); if (counter >= numbits) { receivingData = 0; } } } } if (clockValue == HIGH && test == 1) { test = 0; } } void setupKeyMapping() { m[0] = 0; 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 m[246] = '\t'; m[142] = 'q'; m[142+32] = 'Q'; m[136] = 'w'; m[136+32] = 'W'; m[154] = 'e'; m[154+32] = 'E'; m[141] = 'r'; m[141+32] = 'R'; m[139] = 't'; m[139+32] = 'T'; m[134] = 'y'; m[134+32] = 'Y'; m[138] = 'u'; m[138+32] = 'U'; m[150] = 'i'; m[150+32] = 'I'; m[144] = 'o'; m[144+32] = 'O'; m[143] = 'p'; m[143+32] = 'P'; m[191] = '@'; m[164] = '['; m[245] = 0x0A; m[128] = 0x7F; // middle letter row /* 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[] = ''; /**/ } char translateKeyToChar(int key) { if (sizeof(m) <= key) { return 0; } return m[key]; } void printChar(char keyChar) { Serial.print("'"); Serial.print(keyChar); Serial.print("' ("); Serial.print(int(keyChar)); Serial.println(")"); } void processKbdByte(int data) { int key = data; char keyChar = translateKeyToChar(key); if (modConsoleLog) { Serial.print("Key: <"); Serial.print(int(key)); Serial.print("> "); Serial.print("Char: "); printChar(keyChar); } #ifdef KEYBOARD Keyboard.press(keyChar); delay(10); Keyboard.release(keyChar); #endif typeKey(keyChar); } // ---------------------- // Input and Output Merge // ---------------------- void onTimerInterrupt() { onSlaveClockInterrupt(); if (slaveClockStep == 0) { onHostClockCycle(); } slaveClockStep = (slaveClockStep + 1) % slaveClockDivider; } // ---- // Main // ---- void setup(void) { 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"); } void loop(void) { // type key from serial if (!nextKeyReady && Serial.available() > 0) { long key = Serial.parseInt(SKIP_ALL); if (key != 0) { typeKey(key); } } /**/ // type key from keyboard if (counter >= numbits) { processKbdByte(data); data = B0; counter = 0; } /**/ /*/ auto-type test delay(500); typeKey('B'); /**/ }