|
|
- /*
- * Evil Copyright (c) 2015 Kevin Nygaard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- /*
- * Pinout for Stentura 200 (NOT FOR FLASH)
- * Ribbon
- * ||||||
- * ||||||
- * ||||||
- * xxxxxx (contacts facing up)
- * \\\\\\_ Power +5V
- * \\\\\_ 2 Test
- * \\\\_ 3 Shift load
- * \\\_ 4 Serial out
- * \\_ 5 Clock
- * \_ Ground
- */
-
- /* IO Definitions STENTURA 200*/
- /*
- #define CLK 5
- #define DATA_IN 4
- #define LATCH_EN 3
- #define TEST_EN 2
- #define BAUD 115200
- */
-
-
-
-
-
- /*
- * Pinout for ProCAT Flash
- * IO Board Pads
- * (NOTE: THIS IS NOT THE RIBBON CABLE, that is different)
- *
- * Pads are in two columns, 1,2,3 and 4,5,6. 1 being the square pad (visible from top).
- *
- * 1 ??? (Must be test. Connects to Resistors)
- * 2 PWR
- * 3 GND
- *
- * 4 Serial Out (Pin 9 of first IC)
- * 5 CLK (Clk rail)
- * 6 SH/LD (Shift Load rail)
- *
- */
-
-
- /* IO Definitions ProCAT Flash*/
- #define CLK 5
- #define DATA_IN 4
- #define LATCH_EN 6
- #define TEST_EN 2 //Can't put TEST on 1, which would be UART TX
- #define BAUD 9600
-
- #define DEBUG 0 //set to 1 when using Arduino to debug
-
- #define DEBOUNCE_PERIOD 10
-
-
-
- #define ARRAY_SIZE(array) \
- (sizeof(array) / sizeof(*array))
-
- /*
- * Setup IO and serial connections
- */
- void setup()
- {
- // Initialize serial
- Serial.begin(BAUD);
- if(DEBUG){
- Serial.println("Hax Steno Begin");
- }
- // Setup IOs
- pinMode(CLK, OUTPUT);
- pinMode(LATCH_EN, OUTPUT);
- pinMode(DATA_IN, INPUT);
- //pinMode(TEST_EN, OUTPUT); //Not needed
-
- // Drive known values to outputs
- digitalWrite(CLK, LOW);
- digitalWrite(LATCH_EN, LOW);
- //digitalWrite(TEST_EN, LOW); //Not needed
- }
-
- /*
- * Convert raw Stentura byte data into packed Gemini PR format
- *
- * Data that is seemingly skipped is rendundant, and as far as I can tell,
- * unnecessary
- *
- * Raw matrix mapping of Stentura 200 SRT from serial shift registers
- * 0: S-
- * 1: T-
- * 2: K-
- * 3: P-
- * 4: W-
- * 5: H-
- * 6: R-
- * 7: A-
- * 8: O-
- * 9: *
- * 10: -E
- * 11: -U
- * 12: -F
- * 13: -R
- * 14: -P
- * 15: -B
- * 16: -L
- * 17: -G
- * 18: -T
- * 19: -S
- * 20: -D
- * 21: -Z
- * 22: #
- * 23: N/A
- *
- * Gemini PR protocol (from plover source ./plover/machine/geminipr.py)
- *
- * In the Gemini PR protocol, each packet consists of exactly six bytes and the
- * most significant bit (MSB) of every byte is used exclusively to indicate
- * whether that byte is the first byte of the packet (MSB=1) or one of the
- * remaining five bytes of the packet (MSB=0). As such, there are really only
- * seven bits of steno data in each packet byte. This is why the STENO_KEY_CHART
- * below is visually presented as six rows of seven elements instead of six rows
- * of eight elements.
- * STENO_KEY_CHART = ("Fn" , "#" , "#" , "#" , "#" , "#" , "#" ,
- * "S-" , "S-", "T-", "K-", "P-", "W-" , "H-" ,
- * "R-" , "A-", "O-", "*" , "*" , "res", "res",
- * "pwr", "*" , "*" , "-E", "-U", "-F" , "-R" ,
- * "-P" , "-B", "-L", "-G", "-T", "-S" , "-D" ,
- * "#" , "#" , "#" , "#" , "#" , "#" , "-Z")
- *
- */
-
- //void construct_data(char raw_data[], char packed_data[])
- //{
- // packed_data[0] = 0x80;
- // packed_data[1] = (raw_data[ 0] << 6) /* S- */
- // | (raw_data[ 1] << 1) /* T- */
- // | (raw_data[ 2] << 3) /* K- */
- // | (raw_data[ 3] << 2) /* P- */
- // | (raw_data[ 4] << 0) /* W- */
- // | (raw_data[ 5] << 0); /* H- */
-
- //packed_data[2] = (raw_data[ 6] << 6) /* R- */
- // | (raw_data[ 7] << 5) /* A- */
- // | (raw_data[ 8] << 4) /* O- */
- // | (raw_data[ 9] << 3); /* * */
-
- //packed_data[3] = (raw_data[10] << 3) /* -E */
- // | (raw_data[11] << 2) /* -U */
- // | (raw_data[12] << 1) /* -F */
- // | (raw_data[13] << 0); /* -R */
-
- //packed_data[4] = (raw_data[14] << 6) /* -P */
- // | (raw_data[15] << 5) /* -B */
- // | (raw_data[16] << 4) /* -L */
- // | (raw_data[17] << 3) /* -G */
- // | (raw_data[18] << 2) /* -T */
- // | (raw_data[19] << 1) /* -S */
- // | (raw_data[20] << 0); /* -D */
-
- //packed_data[5] = (raw_data[22] << 6) /* # */
- // | (raw_data[21] << 0); /* -Z */
- //}
-
-
-
- /* ProCAT Flash Mapping
- *
- * The ProCAT Flash is somewhat different. The above Stentura 200 will not work. Instead we have:
- *
- * * Raw matrix mapping of ProCAT Flash from serial shift registers
- * * You can somewhat infer this from the PCB (cheat) by reading letter order, but not all are logical
- * 0: H- //
- * 1: W- //
- * 2: P- //
- * 3: K- //
- * 4: T- //changes marked with comments
- * 5: S- //
- * 6: # // //old was R-
- *
- * 7: A-
- * 8: -R //
- * 9: F //
- * 10: -U //
- * 11: -E //
- * 12: * //
- * 13: -R
- *
- * 14: -P
- * 15: R //was -B
- * 16: -Z //
- * 17: -D //
- * 18: -S //
- * 19: -T //
- * 20: -G //
- *
- * 21: -L ??
- * 22: #
- * 23: ????
- *
- * need -B
- */
- void construct_data(char raw_data[], char packed_data[])
- {
- packed_data[0] = 0x80;
- packed_data[1] = (raw_data[ 5] << 6) /* S- */ //Have to move arrays entries around here, if you are going to
- | (raw_data[ 4] << 4) /* T- */ //change values. Need all 24 bits.
- | (raw_data[ 3] << 3) /* K- */
- | (raw_data[ 2] << 2) /* P- */
- | (raw_data[ 1] << 1) /* W- */
- | (raw_data[ 0] << 0); /* H- */
-
- packed_data[2] = (raw_data[ 15] << 6) /* R- */
- | (raw_data[ 14] << 5) /* A- */
- | (raw_data[ 13] << 4) /* O- */
- | (raw_data[ 12] << 3); /* * */
-
- packed_data[3] = (raw_data[11] << 3) /* -E */
- | (raw_data[10] << 2) /* -U */
- | (raw_data[9] << 1) /* -F */
- | (raw_data[8] << 0); /* -R */
-
- packed_data[4] = (raw_data[23] << 6) /* -P */ // was 14
- | (raw_data[22] << 5) /* -B */ // was dupe 0
- | (raw_data[21] << 4) /* -L */
- | (raw_data[20] << 3) /* -G */
- | (raw_data[19] << 2) /* -T */
- | (raw_data[18] << 1) /* -S */
- | (raw_data[17] << 0); /* -D */
-
- packed_data[5] = (raw_data[6] << 6) /* # */ //
- | (raw_data[16] << 0); /* -Z */
- }
-
- /*
- * Read keystrokes and return them to the host
- */
- void loop(){
- // Byte array of depressed keys, following mapping above
- // 0 means not pressed, 1 means pressed
- static char pressed_keys[24];
-
- // Keys packed in Gemini PR format, ready for transmission over serial
- static char packed_keys[6];
-
- // Chord has been started, but is not complete (all keys released)
- static char in_progress;
-
- // Send data to host over serial
- static char send_data;
-
- // Debounce counter
- static int debounce_count;
-
-
-
- int i;
- char pressed;
- char keys_down;
-
-
- //If keys have already been recorded into pressed_keys array
- if (send_data) {
- construct_data(pressed_keys, packed_keys);
- Serial.write(packed_keys, ARRAY_SIZE(packed_keys));
-
- /*
- * Data returned to host, reset stateful variables
- * Note that we don't need to do this in the setup, because they are all
- * static and guaranteed to be 0 by spec
- */
- memset(pressed_keys, 0, sizeof(pressed_keys));
- send_data = 0;
- in_progress = 0;
-
-
- // Else, record keys into pressed_keys array
- } else {
- // Latch current state of all keys
- digitalWrite(LATCH_EN, HIGH);
-
- // Read all latched data
- keys_down = 0;
- for (i = 0; i < ARRAY_SIZE(pressed_keys); i++){
-
-
- /*
- * All inputs are pulled up. Pressing a key shorts the circuit to
- * ground.
- *
- * We invert the logic here to convert to more conventional positive
- * logic.
- */
- pressed = !digitalRead(DATA_IN);
-
- //At this point, you are reading each individual bit in as a 1 if pressed.
-
-
- //debug
- if(pressed && DEBUG){
- Serial.print(pressed, BIN);
- Serial.print("Pressed was high for i = ");
- Serial.println(i);
- }
-
- // Once a key is pressed, it stays pressed until the chord is over
- // OR result to array
- pressed_keys[i] |= pressed;
-
-
- if (pressed) {
- keys_down = 1;
- in_progress = 1;
- }
-
- /*
- * Toggle clock. Max frequency of shift register MM74HC165 is 30
- * MHz, so it can be switched without any delay by Arduino.
- */
- digitalWrite(CLK, HIGH);
- digitalWrite(CLK, LOW);
-
- }
-
- // Make latch transparent again to capture next set of keystrokes
- digitalWrite(LATCH_EN, LOW);
-
- if (keys_down) {
- debounce_count = 0;
- }
-
- // Return data to host when all keys have been released
- if (in_progress && !keys_down && (++debounce_count >= DEBOUNCE_PERIOD)) {
- send_data = 1;
- }
- }
- }
|