Skip to content

Instantly share code, notes, and snippets.

@micolous
Created May 26, 2018 10:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micolous/1f09a4033f1b7af00a85cc0f757b1752 to your computer and use it in GitHub Desktop.
Save micolous/1f09a4033f1b7af00a85cc0f757b1752 to your computer and use it in GitHub Desktop.
Teensy steno (tx bolt protocol)
// teensy_steno
// Michael Farrell <micolous+git@gmail.com>
//
// This implements the TX Bolt protocol. It works with Teensy LC, but should work
// with other Arduino compatibles (once you fix touch inputs).
//
// This version supports arbitrary keymaps, so you don't need to wire the keyboard
// the same as the TX Bolt protocol. This should make scanning around twice as fast.
//
// This uses a "touch" sensitive pin (18) for the number bar.
//
// Adapted from https://github.com/CharleyShattuck/Steno-Keyboard-Arduino
// (released into public domain)
//
// TODO: Fix ghosting issues even when there are diodes
boolean pressed;
#define NO_BYTES 4
uint32_t bolt_msg;
#define NO_ROWS 2
const byte row[]={16, 17};
#define NO_COLS 11
const byte column[]={0, 1, 11, 3, 4, 5, 6, 7, 8, 9, 10};
// Bit offsets per https://github.com/openstenoproject/plover/blob/master/plover/machine/txbolt.py
const byte keymap[][NO_COLS] = {
{ /* stph */ 0, 1, 3, 5, /* ae */ 9, 12, /* fpltd */ 16, 18, 20, 24, 26 },
{ /* *kwr */ 11, 2, 4, 8, /* ou */ 10, 13, /* rbgsz */ 17, 19, 21, 25, 27 },
};
#define NUMBER_TOUCH_PIN 18
#define TOUCH_THRESHOLD 800
void setup() {
for(int i=0; i<NO_COLS; i++) pinMode(column[i], INPUT_PULLUP);
for(int i=0; i<NO_ROWS; i++) pinMode(row[i], INPUT);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Serial.begin(9600);
delay(1000); // Apparently Arduino Micro needs this
}
void loop() {
// Reset to have header structure.
bolt_msg = 0xC0804000;
do {scan();} while(!pressed);
delay(5); // Debounce the first key pressed for 5 ms
do {
do {scan();} while(pressed);
delay(10);
} while(pressed); // Debounce the last release
// This always transmits "full" messages, even when we could get
// away with less.
Serial.write(bolt_msg & 0xff);
Serial.write((bolt_msg >> 8) & 0xff);
Serial.write((bolt_msg >> 16) & 0xff);
Serial.write((bolt_msg >> 24) & 0xff);
// Terminating byte.
Serial.write(0);
Serial.send_now();
}
void scan() {
digitalWrite(13, HIGH); // toggle LED to time the scan
pressed = false;
for(int i=0; i<NO_ROWS; i++) bolt_msg |= getRow(i);
// Do the number touch.
if (touchRead(NUMBER_TOUCH_PIN) > TOUCH_THRESHOLD) {
bolt_msg |= 0x10000000;
pressed = true;
}
digitalWrite(13, LOW);
}
// Activate and read one row
uint32_t getRow(byte r) {
int pin = row[r];
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
uint32_t o = 0;
for(byte i=0; i<NO_COLS; i++) {
o |= pinState(column[i]) << (keymap[r][i]);
//o |= pinState(column[i]) << i;
}
pinMode(pin, INPUT);
return o;
}
uint32_t pinState(int pin) {
uint32_t state = (!digitalRead(pin)) & 0x01;
if(state == 1) pressed = true;
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment