vail-adapter/vail-adapter.ino

161 lines
3.7 KiB
Arduino
Raw Normal View History

2020-05-16 10:58:40 -06:00
// Copyright 2020 Neale Pickett
// Distributed under the MIT license
// Please see https://github.com/nealey/vail-adapter/
2020-05-16 10:43:38 -06:00
// MIDIUSB - Version: Latest
#include <MIDIUSB.h>
#include <Keyboard.h>
2022-05-21 20:14:03 -06:00
#include <Adafruit_FreeTouch.h>
2020-05-16 10:43:38 -06:00
#include "bounce2.h"
2022-05-21 20:14:03 -06:00
#include "touchbounce.h"
#define DIT_PIN 2
#define DAH_PIN 1
#define KEY_PIN 0
#define QT_DIT_PIN A6
#define QT_DAH_PIN A7
#define QT_KEY_PIN A8
#define PIEZO 10
#define LED_ON false // Xiao inverts this logic for some reason
2022-04-20 19:55:30 -06:00
#define LED_OFF (!LED_ON)
2021-01-18 14:56:43 -07:00
#define DIT_KEY KEY_LEFT_CTRL
#define DAH_KEY KEY_RIGHT_CTRL
2022-05-21 20:14:03 -06:00
#define TONE 550
2022-04-21 22:07:39 -06:00
#define MILLISECOND 1
#define SECOND (1 * MILLISECOND)
2020-05-16 10:43:38 -06:00
bool keyboard = true;
2022-04-21 22:07:39 -06:00
bool trs = false; // true if a TRS plug is in a TRRS jack
uint16_t iambicDelay = 80 * MILLISECOND;
2020-05-16 10:43:38 -06:00
Bounce dit = Bounce();
Bounce dah = Bounce();
Bounce key = Bounce();
2022-05-21 20:14:03 -06:00
TouchBounce qt_dit = TouchBounce();
TouchBounce qt_dah = TouchBounce();
TouchBounce qt_key = TouchBounce();
2020-05-16 10:43:38 -06:00
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
2022-04-21 22:07:39 -06:00
pinMode(PIEZO, OUTPUT);
2020-05-16 10:43:38 -06:00
dit.attach(DIT_PIN, INPUT_PULLUP);
dah.attach(DAH_PIN, INPUT_PULLUP);
key.attach(KEY_PIN, INPUT_PULLUP);
2022-05-21 20:14:03 -06:00
qt_dit.attach(QT_DIT_PIN);
qt_dah.attach(QT_DAH_PIN);
qt_key.attach(QT_KEY_PIN);
2020-05-16 10:43:38 -06:00
Keyboard.begin();
2022-04-21 22:07:39 -06:00
// To auto-sense a straight key in a TRRS jack,
// we just check to see if DAH is closed.
// The sleeve on the straight key's TRS plug
// will short the second ring to the sleeve.
2020-05-16 10:43:38 -06:00
for (int i = 0; i < 16; i++) {
2022-04-20 19:55:30 -06:00
delay(20);
2020-05-16 10:43:38 -06:00
dah.update();
}
if (dah.read() == LOW) {
2022-04-21 22:07:39 -06:00
trs = true;
2022-04-21 22:21:07 -06:00
key = dit;
2020-05-16 10:43:38 -06:00
}
2022-04-21 22:07:39 -06:00
}
// A reentrant doodad to blink out the letter V at startup
// After startup, display the status of the keyboard
#define HELLO_BITS 0b0000101010111000
void setLED() {
static bool beepin = false;
int beat = millis() / iambicDelay;
bool on = keyboard; // If we're not in intro, display status of keyboard
2022-04-21 22:07:39 -06:00
if (beat < 16) {
on = HELLO_BITS & (1 << (15-beat));
if (on != beepin) {
if (on) {
tone(PIEZO, TONE);
} else {
noTone(PIEZO);
}
beepin = on;
}
}
2022-04-21 22:07:39 -06:00
digitalWrite(LED_BUILTIN, on?LED_ON:LED_OFF);
2020-05-16 10:43:38 -06:00
}
void midiKey(bool down, uint8_t key) {
midiEventPacket_t event = {down?9:8, down?0x90:0x80, key, 0x7f};
MidiUSB.sendMIDI(event);
MidiUSB.flush();
}
void midiProbe() {
midiEventPacket_t event = MidiUSB.read();
2022-04-21 22:07:39 -06:00
uint16_t msg = (event.byte1 << 8) | (event.byte2 << 0);
switch (msg) {
case 0x8B00: // Controller 0: turn keyboard mode on/off
keyboard = (event.byte3 > 0x3f);
break;
case 0x8B01: // Controller 1: set iambic speed (0-254)
2022-04-21 22:16:32 -06:00
// I am probably never going to use this,
// because as soon as I implement it,
// people are going to want a way to select mode A or B,
// or typeahead,
// or some other thing that I don't want to maintain
// simultaneously in both C and JavaScript
2022-04-21 22:07:39 -06:00
iambicDelay = event.byte3 << 1;
break;
}
}
2020-05-16 10:43:38 -06:00
void loop() {
midiProbe();
2022-04-21 22:07:39 -06:00
setLED();
2020-05-16 10:43:38 -06:00
// Monitor straight key pin
2022-05-21 20:14:03 -06:00
if (key.update() || qt_key.update()) {
bool fell = key.fell() || qt_key.fell();
midiKey(fell, 0);
if (fell) {
2022-04-21 22:07:39 -06:00
tone(PIEZO, TONE);
} else {
noTone(PIEZO);
2020-05-16 10:43:38 -06:00
}
}
2022-04-21 22:07:39 -06:00
// If we made dit = dah, we have a straight key on the dit pin,
// so we skip iambic polling.
if (trs) {
return;
}
2022-05-21 20:14:03 -06:00
if (dit.update() || qt_dit.update()) {
bool fell = dit.fell() || qt_dit.fell();
midiKey(fell, 1);
2020-05-16 10:43:38 -06:00
if (keyboard) {
2022-05-21 20:14:03 -06:00
if (fell) {
2022-04-21 22:07:39 -06:00
Keyboard.press(DIT_KEY);
2020-05-16 10:43:38 -06:00
} else {
Keyboard.release(DIT_KEY);
2020-05-16 10:43:38 -06:00
}
}
}
// Monitor dah pin
2022-05-21 20:14:03 -06:00
if (dah.update() || qt_dah.update()) {
bool fell = dah.fell() || qt_dah.fell();
midiKey(fell, 2);
2020-05-16 10:43:38 -06:00
if (keyboard) {
2022-05-21 20:14:03 -06:00
if (fell) {
2020-05-16 10:43:38 -06:00
Keyboard.press(DAH_KEY);
} else {
Keyboard.release(DAH_KEY);
}
}
}
}