You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
10 KiB

5 years ago
  1. /*
  2. * Evil Copyright (c) 2015 Kevin Nygaard
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. /*
  23. * Pinout for Stentura 200 (NOT FOR FLASH)
  24. * Ribbon
  25. * ||||||
  26. * ||||||
  27. * ||||||
  28. * xxxxxx (contacts facing up)
  29. * \\\\\\_ Power +5V
  30. * \\\\\_ 2 Test
  31. * \\\\_ 3 Shift load
  32. * \\\_ 4 Serial out
  33. * \\_ 5 Clock
  34. * \_ Ground
  35. */
  36. /* IO Definitions STENTURA 200*/
  37. /*
  38. #define CLK 5
  39. #define DATA_IN 4
  40. #define LATCH_EN 3
  41. #define TEST_EN 2
  42. #define BAUD 115200
  43. */
  44. /*
  45. * Pinout for ProCAT Flash
  46. * IO Board Pads
  47. * (NOTE: THIS IS NOT THE RIBBON CABLE, that is different)
  48. *
  49. * Pads are in two columns, 1,2,3 and 4,5,6. 1 being the square pad (visible from top).
  50. *
  51. * 1 ??? (Must be test. Connects to Resistors)
  52. * 2 PWR
  53. * 3 GND
  54. *
  55. * 4 Serial Out (Pin 9 of first IC)
  56. * 5 CLK (Clk rail)
  57. * 6 SH/LD (Shift Load rail)
  58. *
  59. */
  60. /* IO Definitions ProCAT Flash*/
  61. #define CLK 5
  62. #define DATA_IN 4
  63. #define LATCH_EN 6
  64. #define TEST_EN 2 //Can't put TEST on 1, which would be UART TX
  65. #define BAUD 9600
  66. #define DEBUG 0 //set to 1 when using Arduino to debug
  67. #define DEBOUNCE_PERIOD 10
  68. #define ARRAY_SIZE(array) \
  69. (sizeof(array) / sizeof(*array))
  70. /*
  71. * Setup IO and serial connections
  72. */
  73. void setup()
  74. {
  75. // Initialize serial
  76. Serial.begin(BAUD);
  77. if(DEBUG){
  78. Serial.println("Hax Steno Begin");
  79. }
  80. // Setup IOs
  81. pinMode(CLK, OUTPUT);
  82. pinMode(LATCH_EN, OUTPUT);
  83. pinMode(DATA_IN, INPUT);
  84. //pinMode(TEST_EN, OUTPUT); //Not needed
  85. // Drive known values to outputs
  86. digitalWrite(CLK, LOW);
  87. digitalWrite(LATCH_EN, LOW);
  88. //digitalWrite(TEST_EN, LOW); //Not needed
  89. }
  90. /*
  91. * Convert raw Stentura byte data into packed Gemini PR format
  92. *
  93. * Data that is seemingly skipped is rendundant, and as far as I can tell,
  94. * unnecessary
  95. *
  96. * Raw matrix mapping of Stentura 200 SRT from serial shift registers
  97. * 0: S-
  98. * 1: T-
  99. * 2: K-
  100. * 3: P-
  101. * 4: W-
  102. * 5: H-
  103. * 6: R-
  104. * 7: A-
  105. * 8: O-
  106. * 9: *
  107. * 10: -E
  108. * 11: -U
  109. * 12: -F
  110. * 13: -R
  111. * 14: -P
  112. * 15: -B
  113. * 16: -L
  114. * 17: -G
  115. * 18: -T
  116. * 19: -S
  117. * 20: -D
  118. * 21: -Z
  119. * 22: #
  120. * 23: N/A
  121. *
  122. * Gemini PR protocol (from plover source ./plover/machine/geminipr.py)
  123. *
  124. * In the Gemini PR protocol, each packet consists of exactly six bytes and the
  125. * most significant bit (MSB) of every byte is used exclusively to indicate
  126. * whether that byte is the first byte of the packet (MSB=1) or one of the
  127. * remaining five bytes of the packet (MSB=0). As such, there are really only
  128. * seven bits of steno data in each packet byte. This is why the STENO_KEY_CHART
  129. * below is visually presented as six rows of seven elements instead of six rows
  130. * of eight elements.
  131. * STENO_KEY_CHART = ("Fn" , "#" , "#" , "#" , "#" , "#" , "#" ,
  132. * "S-" , "S-", "T-", "K-", "P-", "W-" , "H-" ,
  133. * "R-" , "A-", "O-", "*" , "*" , "res", "res",
  134. * "pwr", "*" , "*" , "-E", "-U", "-F" , "-R" ,
  135. * "-P" , "-B", "-L", "-G", "-T", "-S" , "-D" ,
  136. * "#" , "#" , "#" , "#" , "#" , "#" , "-Z")
  137. *
  138. */
  139. //void construct_data(char raw_data[], char packed_data[])
  140. //{
  141. // packed_data[0] = 0x80;
  142. // packed_data[1] = (raw_data[ 0] << 6) /* S- */
  143. // | (raw_data[ 1] << 1) /* T- */
  144. // | (raw_data[ 2] << 3) /* K- */
  145. // | (raw_data[ 3] << 2) /* P- */
  146. // | (raw_data[ 4] << 0) /* W- */
  147. // | (raw_data[ 5] << 0); /* H- */
  148. //packed_data[2] = (raw_data[ 6] << 6) /* R- */
  149. // | (raw_data[ 7] << 5) /* A- */
  150. // | (raw_data[ 8] << 4) /* O- */
  151. // | (raw_data[ 9] << 3); /* * */
  152. //packed_data[3] = (raw_data[10] << 3) /* -E */
  153. // | (raw_data[11] << 2) /* -U */
  154. // | (raw_data[12] << 1) /* -F */
  155. // | (raw_data[13] << 0); /* -R */
  156. //packed_data[4] = (raw_data[14] << 6) /* -P */
  157. // | (raw_data[15] << 5) /* -B */
  158. // | (raw_data[16] << 4) /* -L */
  159. // | (raw_data[17] << 3) /* -G */
  160. // | (raw_data[18] << 2) /* -T */
  161. // | (raw_data[19] << 1) /* -S */
  162. // | (raw_data[20] << 0); /* -D */
  163. //packed_data[5] = (raw_data[22] << 6) /* # */
  164. // | (raw_data[21] << 0); /* -Z */
  165. //}
  166. /* ProCAT Flash Mapping
  167. *
  168. * The ProCAT Flash is somewhat different. The above Stentura 200 will not work. Instead we have:
  169. *
  170. * * Raw matrix mapping of ProCAT Flash from serial shift registers
  171. * * You can somewhat infer this from the PCB (cheat) by reading letter order, but not all are logical
  172. * 0: H- //
  173. * 1: W- //
  174. * 2: P- //
  175. * 3: K- //
  176. * 4: T- //changes marked with comments
  177. * 5: S- //
  178. * 6: # // //old was R-
  179. *
  180. * 7: A-
  181. * 8: -R //
  182. * 9: F //
  183. * 10: -U //
  184. * 11: -E //
  185. * 12: * //
  186. * 13: -R
  187. *
  188. * 14: -P
  189. * 15: R //was -B
  190. * 16: -Z //
  191. * 17: -D //
  192. * 18: -S //
  193. * 19: -T //
  194. * 20: -G //
  195. *
  196. * 21: -L ??
  197. * 22: #
  198. * 23: ????
  199. *
  200. * need -B
  201. */
  202. void construct_data(char raw_data[], char packed_data[])
  203. {
  204. packed_data[0] = 0x80;
  205. packed_data[1] = (raw_data[ 5] << 6) /* S- */ //Have to move arrays entries around here, if you are going to
  206. | (raw_data[ 4] << 4) /* T- */ //change values. Need all 24 bits.
  207. | (raw_data[ 3] << 3) /* K- */
  208. | (raw_data[ 2] << 2) /* P- */
  209. | (raw_data[ 1] << 1) /* W- */
  210. | (raw_data[ 0] << 0); /* H- */
  211. packed_data[2] = (raw_data[ 15] << 6) /* R- */
  212. | (raw_data[ 14] << 5) /* A- */
  213. | (raw_data[ 13] << 4) /* O- */
  214. | (raw_data[ 12] << 3); /* * */
  215. packed_data[3] = (raw_data[11] << 3) /* -E */
  216. | (raw_data[10] << 2) /* -U */
  217. | (raw_data[9] << 1) /* -F */
  218. | (raw_data[8] << 0); /* -R */
  219. packed_data[4] = (raw_data[23] << 6) /* -P */ // was 14
  220. | (raw_data[22] << 5) /* -B */ // was dupe 0
  221. | (raw_data[21] << 4) /* -L */
  222. | (raw_data[20] << 3) /* -G */
  223. | (raw_data[19] << 2) /* -T */
  224. | (raw_data[18] << 1) /* -S */
  225. | (raw_data[17] << 0); /* -D */
  226. packed_data[5] = (raw_data[6] << 6) /* # */ //
  227. | (raw_data[16] << 0); /* -Z */
  228. }
  229. /*
  230. * Read keystrokes and return them to the host
  231. */
  232. void loop(){
  233. // Byte array of depressed keys, following mapping above
  234. // 0 means not pressed, 1 means pressed
  235. static char pressed_keys[24];
  236. // Keys packed in Gemini PR format, ready for transmission over serial
  237. static char packed_keys[6];
  238. // Chord has been started, but is not complete (all keys released)
  239. static char in_progress;
  240. // Send data to host over serial
  241. static char send_data;
  242. // Debounce counter
  243. static int debounce_count;
  244. int i;
  245. char pressed;
  246. char keys_down;
  247. //If keys have already been recorded into pressed_keys array
  248. if (send_data) {
  249. construct_data(pressed_keys, packed_keys);
  250. Serial.write(packed_keys, ARRAY_SIZE(packed_keys));
  251. /*
  252. * Data returned to host, reset stateful variables
  253. * Note that we don't need to do this in the setup, because they are all
  254. * static and guaranteed to be 0 by spec
  255. */
  256. memset(pressed_keys, 0, sizeof(pressed_keys));
  257. send_data = 0;
  258. in_progress = 0;
  259. // Else, record keys into pressed_keys array
  260. } else {
  261. // Latch current state of all keys
  262. digitalWrite(LATCH_EN, HIGH);
  263. // Read all latched data
  264. keys_down = 0;
  265. for (i = 0; i < ARRAY_SIZE(pressed_keys); i++){
  266. /*
  267. * All inputs are pulled up. Pressing a key shorts the circuit to
  268. * ground.
  269. *
  270. * We invert the logic here to convert to more conventional positive
  271. * logic.
  272. */
  273. pressed = !digitalRead(DATA_IN);
  274. //At this point, you are reading each individual bit in as a 1 if pressed.
  275. //debug
  276. if(pressed && DEBUG){
  277. Serial.print(pressed, BIN);
  278. Serial.print("Pressed was high for i = ");
  279. Serial.println(i);
  280. }
  281. // Once a key is pressed, it stays pressed until the chord is over
  282. // OR result to array
  283. pressed_keys[i] |= pressed;
  284. if (pressed) {
  285. keys_down = 1;
  286. in_progress = 1;
  287. }
  288. /*
  289. * Toggle clock. Max frequency of shift register MM74HC165 is 30
  290. * MHz, so it can be switched without any delay by Arduino.
  291. */
  292. digitalWrite(CLK, HIGH);
  293. digitalWrite(CLK, LOW);
  294. }
  295. // Make latch transparent again to capture next set of keystrokes
  296. digitalWrite(LATCH_EN, LOW);
  297. if (keys_down) {
  298. debounce_count = 0;
  299. }
  300. // Return data to host when all keys have been released
  301. if (in_progress && !keys_down && (++debounce_count >= DEBOUNCE_PERIOD)) {
  302. send_data = 1;
  303. }
  304. }
  305. }