Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save JosephCatrambone/0df3d9be6a73cfd5b2ae5b924efe3fab to your computer and use it in GitHub Desktop.
Save JosephCatrambone/0df3d9be6a73cfd5b2ae5b924efe3fab to your computer and use it in GitHub Desktop.
TinyPICO BlueTooth BLE Morse Keyboard
#include <BleKeyboard.h>
#include <TinyPICO.h>
TinyPICO tinypico = TinyPICO();
BleKeyboard keyboard; // keyboard("Name", "manufacturer", battery_level_100)
// a .-
// b -...
// c -.-.
// d -..
// e .
// f ..-.
// g -..
// h ....
// i ..
// j .---
// k -.-
// l .-..
// m --
// n -.
// o ---
// p .--.
// q --.-
// r .-.
// s ...
// t -
// u ..-
// v ...-
// w .--
// x -..-
// y -.--
// z --..
// 1 .----
// 2 ..---
// 3 ...--
// 4 ....-
// 5 .....
// 6 -....
// 7 --...
// 8 ---..
// 9 ----.
// 0 -----
// . .-.-.-
// , --..--
// ? ..--..
// ! -.-.--
// ' .----.
// " .-..-.
// ( -.--.
// ) -.--.-
// & .-...
// : ---...
// ; -.-.-.
// / -..-.
// _ ..--.-
// = -...-
// + .-.-.
// - -....-
// $ ...-..-
// @ .--.-.
// RETURN .-.-
// ERR ........
// Pins indicate the physical device pins, not the GPIO numbers.
// IDX values are their position in the assorted arrays, like justPressed.
const byte DOT_PIN = 14; // The one nearest the antenna on the tinypico.
const byte DOT_IDX = 0;
const byte DASH_PIN = 15;
const byte DASH_IDX = 1;
const byte SUBMIT_PIN = 27;
const byte SUBMIT_IDX = 2;
const byte COMMAND_PIN = 26;
const byte COMMAND_IDX = 3;
const byte NUM_PINS = 4;
const uint8_t MORSE_TREE[] = { //char?
' ',
// . -
'e', 't',
//.. .- -. --
'i', 'a', 'n', 'm',
//... ..- .-. .-- -.. -.- --. ---
's', 'u', 'r', 'w', 'd', 'k', 'g', 'o',
//.... ...- ..-. ..-- .-.. .-.- .--. .--- -... -..- -.-. -.-- --.. --.- ---. ----
'h', 'v', 'f', ' ', 'l', '\n', 'p', 'j', 'b', 'x', 'c', 'y', 'z', 'q', ' ', ' ',
// ..... ....- ...-. ...-- ..-.. ..-.- ..--. ..--- .-... .-..- .-.-. .-.-- .--.. .--.- .---. .---- -.... -...- -..-. -..-- -.-.. -.-.- -.--. -.--- --... --..- --.-. --.-- ---.. ---.- ----. -----
'5', '4', ' ', '3', ' ', ' ', ' ', '2', '&', ' ', '+', ' ', ' ', ' ', ' ', '1', '6', '=', '/', ' ', ' ', ' ', '(', ' ', '7', ' ', ' ', ' ', '8', ' ', '9', '0',
// ...... .....- ....-. ....-- ...-.. ...-.- ...--. ...--- ..-... ..-..- ..-.-. ..-.-- ..--.. ..--.- ..---. ..---- .-.... .-...- .-..-. .-..-- .-.-.. .-.-.- .-.--. .-.--- .--... .--..- .--.-. .--.-- .---.. .---.- .----. .-----
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '$', ' ', ' ', '?', '_', ' ', ' ', ' ', ' ', '"', ' ', ' ', '.', ' ', ' ', ' ', ' ', '@', ' ', ' ', ' ', '\'', ' ',
// -..... -....- -...-. -...-- -..-.. -..-.- -..--. -..--- -.-... -.-..- -.-.-. -.-.-- -.--.. -.--.- -.---. -.---- --.... --...- --..-. --..-- --.-.. --.-.- --.--. --.--- ---... ---..- ---.-. ---.-- ----.. ----.- -----. ------
' ', '-', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ';', '!', ' ', ')', ' ', ' ', ' ', ' ', ' ', ',', ' ', ' ', ' ', ' ', ':', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
}; // Start at space, then most down the binary tree. The left subtree of a binary tree is at position (2*n)+1. The right is at 2*(n+1)
const uint8_t COMMAND_TREE[] = {
KEY_BACKSPACE,
KEY_LEFT_ARROW, KEY_RIGHT_ARROW,
KEY_DOWN_ARROW, ' ', ' ', KEY_UP_ARROW,
's', 'u', 'r', 'w', 'd', 'k', 'g', 'o',
'h', 'v', 'f', ' ', 'l', ' ', 'p', 'j', 'b', 'x', 'c', 'y', 'z', 'q', ' ', ' '
}; // TODO: Pad this out with the remaining items in the tree so we don't access out of bounds.
const byte MORSE_TREE_LIMIT = 128; // Must be less than this, not equal to.
const byte keyboardPins[] = {DOT_PIN, DASH_PIN, SUBMIT_PIN, COMMAND_PIN};
bool justPressed[] = {false, false, false, false};
bool justReleased[] = {false, false, false, false};
bool pressed[] = {false, false, false, false};
bool anyKeyPressed = false;
int morseCursor = 0; // Where in the morse tree we are.
void setup() {
Serial.begin(115200);
keyboard.begin();
pinMode(DOT_PIN, INPUT_PULLUP); // Input, output, or INPUT_PULLUP
pinMode(DASH_PIN, INPUT_PULLUP); // pinMode(x, INPUT); digitalWrite(x, HIGH); is no longer necessary w/ new arduinos.
pinMode(SUBMIT_PIN, INPUT_PULLUP);
pinMode(COMMAND_PIN, INPUT_PULLUP);
// Do we want an output pin for digitalWrite debugs?
tinypico.DotStar_SetPower(true);
}
void readInputState() {
anyKeyPressed = false;
for(byte i=0; i < NUM_PINS; i++) {
bool activeThisFrame = (digitalRead(keyboardPins[i]) == LOW);
justReleased[i] = !activeThisFrame && pressed[i]; // This _was_ pressed last frame, so it's just released.
justPressed[i] = activeThisFrame && !pressed[i];
pressed[i] = activeThisFrame;
anyKeyPressed = anyKeyPressed || activeThisFrame;
}
}
void disconnectedLoop() {
// Cycle the DotStar LED colour every 25 milliseconds
tinypico.DotStar_CycleColor(25);
// You can set the DotStar LED colour directly using r,g,b values
// tp.DotStar_SetPixelColor( 255, 128, 0 );
// You can set the DotStar LED colour directly using a uint32_t value
// tp.DotStar_SetPixelColor( 0xFFC900 );
// You can clear the DotStar LED too
// To power down the DotStar LED for deep sleep you call this
}
void connectedLoop() {
// Disengage LED.
tinypico.DotStar_Clear(); // Clear first,
tinypico.DotStar_SetPower( false ); // Then power down the LED when connected to save power.
// Check for tapped 'keys'. If the 'submit' key is just _released_ then we send the key.
if(justReleased[SUBMIT_IDX]) {
Serial.write(MORSE_TREE[morseCursor]); // Write, rather than print, because this is a uint8 instead of a char.
// Send the key.
keyboard.press(MORSE_TREE[morseCursor]); // Or perhaps keyboard.print?
morseCursor = 0;
delay(10);
keyboard.releaseAll();
}
if(justReleased[COMMAND_IDX]) {
keyboard.press(COMMAND_TREE[morseCursor]);
bool wasShift = (COMMAND_TREE[morseCursor] == KEY_LEFT_SHIFT);
morseCursor = 0;
delay(10);
if(!wasShift) {
keyboard.releaseAll();
}
}
if(justReleased[DOT_IDX]) { // Move 'left' in the tree.
morseCursor = (2*morseCursor)+1;
delay(10);
}
if(justReleased[DASH_IDX]) { // Move 'right'.
morseCursor = 2*(morseCursor+1);
delay(10);
}
if(morseCursor >= MORSE_TREE_LIMIT) {
morseCursor = 0;
delay(20);
}
/*
keyboard.print("TEST!");
keyboard.write(KEY_RETURN);
keyboard.press(KEY_LEFT_SHIFT);
keyboard.press(KEY_LEFT_CTRL);
keyboard.press(KEY_LEFT_ALT);
keyboard.press(KEY_DELETE);
keyboard.releaseAll();
*/
}
void loop() {
readInputState();
if(keyboard.isConnected()) {
connectedLoop();
} else {
disconnectedLoop();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment