Converter for Consul 262.5 terminal keyboard and VDX 52600 terminal.
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

484 linhas
9.8 KiB

  1. // Resources:
  2. // [Consul 262.4 Converter] https://deskthority.net/viewtopic.php?t=26908
  3. // [Consul 262.5 manual in CS] http://www.sapi.cz/prislusenstvi/c262-5.php#odkazp4
  4. #define KEYBOARD
  5. #ifdef KEYBOARD
  6. #include <Keyboard.h>
  7. #endif
  8. #include <TimerOne.h>
  9. // pinout config
  10. const int pinLedOffline = 10; // out
  11. const int pinLedOnline = 9; // out
  12. const int pinSpeaker = 8; // out
  13. const int pinData = 6; // out, host data
  14. const int pinStatus = 7; // in, host status
  15. const int clockPin = 5; // out, kbd clock
  16. const int dataPin = 3; // in, kbd data
  17. const int outPin = 4; // out, kbd led
  18. // constant config
  19. const int slaveClockDivider = 8;
  20. const int timerDelay = 520 / slaveClockDivider;
  21. // variables
  22. volatile int slaveClockStep = 0;
  23. char m[255];
  24. volatile int data = 0;
  25. int test = 0;
  26. volatile int counter = 0;
  27. int numbits = 10;
  28. volatile int typedKey = -1;
  29. bool hostOnline = false;
  30. // MODS >>>
  31. // [1] send debug scancode information to serial port
  32. bool modConsoleLog = true;
  33. // <<< MODS
  34. // ----------
  35. // KBD Output
  36. // ----------
  37. volatile long lastChange = -100000;
  38. volatile int x = 0;
  39. volatile int dataWord = 0;
  40. volatile int dataState = 0;
  41. volatile int dataDelay = 0;
  42. volatile int packetDelay = 0;
  43. volatile int packetTail = 0;
  44. volatile bool nextKeyReady = false;
  45. volatile byte nextKey = 0;
  46. void typeKey(byte key) {
  47. nextKey = key;
  48. nextKeyReady = true;
  49. //Serial.print("Typing key "); Serial.println((int) key);
  50. }
  51. void sendKey(byte key) {
  52. dataWord = key;
  53. dataState = 8;
  54. dataDelay = 0;
  55. packetDelay = 0;
  56. packetTail = 15;
  57. typedKey = key;
  58. //Serial.print("Sending key "); Serial.println((int) key);
  59. }
  60. void onHostStatusChange() {
  61. long timeNow = millis();
  62. long changeDiff = timeNow - lastChange;
  63. lastChange = timeNow;
  64. if (changeDiff >= 10 && nextKeyReady) {
  65. nextKeyReady = false;
  66. sendKey(nextKey);
  67. Timer1.start(); // synchronize with the host
  68. slaveClockStep = 0;
  69. }
  70. }
  71. void onHostClockCycle(void)
  72. {
  73. int dataBit = HIGH;
  74. if (packetDelay > 0) {
  75. packetDelay--;
  76. } else if (dataDelay > 0) {
  77. dataDelay--;
  78. dataBit = LOW;
  79. } else if (dataState > 0) {
  80. int bitToSend = (dataWord >> (dataState - 1)) & 1;
  81. dataBit = !bitToSend ? LOW : HIGH;
  82. dataState--;
  83. } else if (packetTail > 0) {
  84. packetTail--;
  85. dataBit = LOW;
  86. } else {
  87. }
  88. digitalWrite(pinData, dataBit);
  89. }
  90. // ---------
  91. // KBD Input
  92. // ---------
  93. const int receivingSteps = 16;
  94. volatile int clockStep = 0;
  95. volatile int receivingStep = 0;
  96. volatile int receivingData = 0;
  97. volatile int receivingBit = 0;
  98. void onSlaveClockInterrupt() {
  99. clockStep = (clockStep + 1) % 2;
  100. int clockValue = (clockStep % 2) ? HIGH : LOW;
  101. digitalWrite(clockPin, clockValue);
  102. int dataBit = digitalRead(dataPin);
  103. if (clockValue == LOW) {
  104. if (receivingData == 0 && dataBit == LOW) {
  105. receivingData = 1;
  106. receivingStep = 0;
  107. receivingBit = 0;
  108. test = 0;
  109. } else if (receivingData == 1) {
  110. receivingStep++;
  111. }
  112. if (receivingData == 1 && test == 0) {
  113. test = 1;
  114. receivingBit += dataBit == HIGH ? 1 : 0;
  115. if (receivingStep >= receivingSteps) {
  116. if (counter <= 8) {
  117. data = data >> 1;
  118. if (receivingBit > receivingSteps / 2) {
  119. bitSet(data, 7);
  120. }
  121. }
  122. counter++;
  123. receivingStep = 0;
  124. receivingBit = 0;
  125. if (counter >= numbits) {
  126. receivingData = 0;
  127. }
  128. }
  129. }
  130. }
  131. if (clockValue == HIGH && test == 1) {
  132. test = 0;
  133. }
  134. }
  135. void setupKeyMapping() {
  136. m[0] = 0;
  137. // top row special
  138. m[63] = 0x12; // ?? Setup
  139. m[62] = 'j'; // up
  140. m[61] = 'k'; // down
  141. m[59] = 'h'; // left
  142. m[60] = 'l'; // right
  143. // top numbers row
  144. m[228] = 0x1B; // ESC
  145. m[206] = '1';
  146. m[205] = '2';
  147. m[204] = '3';
  148. m[203] = '4';
  149. m[202] = '5';
  150. m[201] = '6';
  151. m[200] = '7';
  152. m[199] = '8';
  153. m[198] = '9';
  154. m[207] = '0';
  155. m[210] = '-';
  156. m[161] = '^';
  157. m[0] = ' '; // Empty cap
  158. m[247] = 0x08; // Backspace
  159. m[56] = 0x10; // Break
  160. // top letter row
  161. m[246] = '\t';
  162. m[142] = 'q';
  163. m[142+32] = 'Q';
  164. m[136] = 'w';
  165. m[136+32] = 'W';
  166. m[154] = 'e';
  167. m[154+32] = 'E';
  168. m[141] = 'r';
  169. m[141+32] = 'R';
  170. m[139] = 't';
  171. m[139+32] = 'T';
  172. m[134] = 'y';
  173. m[134+32] = 'Y';
  174. m[138] = 'u';
  175. m[138+32] = 'U';
  176. m[150] = 'i';
  177. m[150+32] = 'I';
  178. m[144] = 'o';
  179. m[144+32] = 'O';
  180. m[143] = 'p';
  181. m[143+32] = 'P';
  182. m[191] = '@';
  183. m[164] = '[';
  184. m[245] = 0x0A;
  185. m[128] = 0x7F;
  186. // middle letter row
  187. m[158] = 'a';
  188. m[158+32] = 'A';
  189. m[140] = 's';
  190. m[140+32] = 'S';
  191. m[155] = 'd';
  192. m[155+32] = 'D';
  193. m[153] = 'f';
  194. m[153+32] = 'F';
  195. m[152] = 'g';
  196. m[152+32] = 'G';
  197. m[151] = 'h';
  198. m[151+32] = 'H';
  199. m[149] = 'j';
  200. m[149+32] = 'J';
  201. m[148] = 'k';
  202. m[148+32] = 'K';
  203. m[147] = 'l';
  204. m[147+32] = 'L';
  205. m[196] = ';';
  206. m[196+32] = '+';
  207. m[197] = ':';
  208. m[197+32] = '*';
  209. m[162] = ']';
  210. m[162+32] = '}';
  211. m[242] = 0x0D;
  212. // bottom letter row
  213. m[58] = 0x11; // No Scroll
  214. m[133] = 'z';
  215. m[133+32] = 'Z';
  216. m[135] = 'x';
  217. m[135+32] = 'X';
  218. m[156] = 'c';
  219. m[156+32] = 'C';
  220. m[137] = 'v';
  221. m[137+32] = 'V';
  222. m[157] = 'b';
  223. m[157+32] = 'B';
  224. m[145] = 'n';
  225. m[145+32] = 'N';
  226. m[146] = 'm';
  227. m[146+32] = 'M';
  228. m[211] = ',';
  229. m[211+32] = '<';
  230. m[209] = '.';
  231. m[209+32] = '>';
  232. m[208] = '/';
  233. m[208+32] = '?';
  234. m[163] = '\\';
  235. m[163+32] = '|';
  236. m[78] = 'x'; // Blank cap
  237. m[77] = 'X'; // Blank cap + shift
  238. // spacebar
  239. m[223] = ' '; // Spacebar
  240. /*/ numpad
  241. m[] = '';
  242. m[+32] = '';
  243. m[] = '';
  244. m[+32] = '';
  245. m[] = '';
  246. m[+32] = '';
  247. m[] = '';
  248. m[+32] = '';
  249. m[] = '';
  250. m[+32] = '';
  251. /*
  252. m[] = '';
  253. m[] = '';
  254. m[] = '';
  255. m[] = '';
  256. m[] = '';
  257. m[] = '';
  258. m[] = '';
  259. m[] = '';
  260. m[] = '';
  261. m[] = '';
  262. m[] = '';
  263. m[] = '';
  264. m[] = '';
  265. m[] = '';
  266. m[] = '';
  267. m[] = '';
  268. m[] = '';
  269. m[] = '';
  270. m[] = '';
  271. m[] = '';
  272. m[] = '';
  273. m[] = '';
  274. m[] = '';
  275. m[] = '';
  276. m[] = '';
  277. m[] = '';
  278. m[] = '';
  279. m[] = '';
  280. m[] = '';
  281. m[] = '';
  282. m[] = '';
  283. m[] = '';
  284. m[] = '';
  285. m[] = '';
  286. m[] = '';
  287. m[] = '';
  288. m[] = '';
  289. m[] = '';
  290. m[] = '';
  291. m[] = '';
  292. m[] = '';
  293. m[] = '';
  294. m[] = '';
  295. m[] = '';
  296. m[] = '';
  297. m[] = '';
  298. m[] = '';
  299. m[] = '';
  300. /**/
  301. //
  302. // 208 local ON
  303. // 209 leave local
  304. // 210 half/full duplex
  305. // 211 go home?
  306. // 212 print Ps junk
  307. // 213 mem protect
  308. // 214 disable NAT
  309. // 217 clear line?
  310. // 218 shows cursor
  311. // 219 hides cursor
  312. // 221 mem prot
  313. // 223 reset prompt
  314. // 241 random junk symbols
  315. // 243 random junk symbols
  316. // 244 stop junk
  317. // 248 hides cursor
  318. // 251 Hard copy
  319. // 250 Keyb. Inh.
  320. }
  321. char translateKeyToChar(int key) {
  322. if (sizeof(m) <= key) {
  323. return 0;
  324. }
  325. return m[key];
  326. }
  327. void printChar(char keyChar) {
  328. Serial.print("'"); Serial.print(keyChar); Serial.print("' ("); Serial.print(int(keyChar)); Serial.println(")");
  329. }
  330. void processKbdByte(int data) {
  331. int key = data;
  332. char keyChar = translateKeyToChar(key);
  333. if (modConsoleLog) {
  334. Serial.print("Key: <"); Serial.print(int(key)); Serial.print("> ");
  335. Serial.print("Char: "); printChar(keyChar);
  336. }
  337. #ifdef KEYBOARD
  338. if (!hostOnline) {
  339. Keyboard.press(keyChar);
  340. delay(10);
  341. Keyboard.release(keyChar);
  342. }
  343. #endif
  344. typeKey(keyChar);
  345. }
  346. // ----------------------
  347. // Input and Output Merge
  348. // ----------------------
  349. void onTimerInterrupt()
  350. {
  351. onSlaveClockInterrupt();
  352. if (slaveClockStep == 0) {
  353. onHostClockCycle();
  354. }
  355. slaveClockStep = (slaveClockStep + 1) % slaveClockDivider;
  356. }
  357. // --------------
  358. // User Interface
  359. // --------------
  360. void updateOnlineStatus()
  361. {
  362. long timeNow = millis();
  363. hostOnline = (lastChange > timeNow) || ((timeNow - lastChange) < 10000);
  364. digitalWrite(pinLedOffline, hostOnline ? LOW : HIGH);
  365. digitalWrite(pinLedOnline, hostOnline ? HIGH : LOW);
  366. }
  367. // ----
  368. // Main
  369. // ----
  370. void setup(void)
  371. {
  372. Serial.begin(9600);
  373. setupKeyMapping();
  374. pinMode(pinLedOffline, OUTPUT);
  375. pinMode(pinLedOnline, OUTPUT);
  376. pinMode(pinSpeaker, OUTPUT);
  377. pinMode(pinData, OUTPUT);
  378. pinMode(dataPin, INPUT);
  379. pinMode(outPin, OUTPUT);
  380. pinMode(clockPin, OUTPUT);
  381. pinMode(pinStatus, INPUT_PULLUP);
  382. digitalWrite(pinLedOffline, HIGH);
  383. digitalWrite(pinLedOnline, HIGH);
  384. digitalWrite(pinData, HIGH);
  385. digitalWrite(outPin, LOW);
  386. attachInterrupt(digitalPinToInterrupt(pinStatus), onHostStatusChange, CHANGE);
  387. Timer1.initialize(timerDelay);
  388. Timer1.attachInterrupt(onTimerInterrupt);
  389. delay(500);
  390. tone(pinSpeaker, 650, 200);
  391. digitalWrite(pinLedOffline, LOW);
  392. digitalWrite(pinLedOnline, HIGH);
  393. delay(200);
  394. tone(pinSpeaker, 500, 200);
  395. digitalWrite(pinLedOffline, HIGH);
  396. digitalWrite(pinLedOnline, LOW);
  397. delay(200);
  398. digitalWrite(pinLedOffline, LOW);
  399. digitalWrite(pinLedOnline, LOW);
  400. delay(500);
  401. updateOnlineStatus();
  402. tone(pinSpeaker, 440, 200);
  403. delay(200);
  404. Serial.println("Keyboard ready");
  405. }
  406. int qwe = 0;
  407. void loop(void)
  408. {
  409. // type key from serial
  410. if (!nextKeyReady && Serial.available() > 0) {
  411. long key = Serial.parseInt(SKIP_ALL);
  412. if (key != 0) {
  413. typeKey(key);
  414. }
  415. }
  416. /**/
  417. // type key from keyboard
  418. if (counter >= numbits) {
  419. processKbdByte(data);
  420. data = B0;
  421. counter = 0;
  422. }
  423. /**/
  424. /*/ auto-type test
  425. delay(2000);
  426. int k = 128 + qwe;
  427. typeKey(k);
  428. qwe = (qwe + 1) % 128;
  429. Serial.print("QWE "); Serial.println((int)k);
  430. if (qwe % 5 == 0) delay(2000);
  431. /**/
  432. updateOnlineStatus();
  433. if (nextKeyReady && !hostOnline) { // skip sending key without a host (used for USB)
  434. nextKeyReady = false;
  435. typedKey = nextKey;
  436. }
  437. if (!nextKeyReady && typedKey != -1) {
  438. tone(pinSpeaker, 200 + typedKey, 100);
  439. typedKey = -1;
  440. }
  441. delay(5);
  442. }