// 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 pinLedOffline = 10; // out const int pinLedOnline = 9; // out const int pinSpeaker = 8; // out 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; volatile int typedKey = -1; bool hostOnline = false; // MODS >>> // [1] send debug scancode information to serial port bool modConsoleLog = true; // <<< MODS // ---------- // KBD Output // ---------- volatile long lastChange = -100000; 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; typedKey = key; //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; } 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() { m[0] = 0; // 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[158] = 'a'; m[158+32] = 'A'; m[140] = 's'; m[140+32] = 'S'; m[155] = 'd'; m[155+32] = 'D'; 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; // 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 // spacebar m[223] = ' '; // Spacebar /*/ numpad m[] = ''; m[+32] = ''; m[] = ''; m[+32] = ''; m[] = ''; m[+32] = ''; m[] = ''; m[+32] = ''; m[] = ''; m[+32] = ''; /* 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. } 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; } // -------------- // User Interface // -------------- void updateOnlineStatus() { long timeNow = millis(); hostOnline = (lastChange > timeNow) || ((timeNow - lastChange) < 10000); digitalWrite(pinLedOffline, hostOnline ? LOW : HIGH); digitalWrite(pinLedOnline, hostOnline ? HIGH : LOW); } // ---- // Main // ---- void setup(void) { Serial.begin(9600); setupKeyMapping(); pinMode(pinLedOffline, OUTPUT); pinMode(pinLedOnline, OUTPUT); pinMode(pinSpeaker, OUTPUT); pinMode(pinData, OUTPUT); pinMode(dataPin, INPUT); pinMode(outPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(pinStatus, INPUT_PULLUP); digitalWrite(pinLedOffline, HIGH); digitalWrite(pinLedOnline, HIGH); 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); updateOnlineStatus(); tone(pinSpeaker, 440, 200); delay(200); Serial.println("Keyboard ready"); } int qwe = 0; 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(2000); int k = 128 + qwe; typeKey(k); qwe = (qwe + 1) % 128; Serial.print("QWE "); Serial.println((int)k); if (qwe % 5 == 0) delay(2000); /**/ 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); }