Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
331 lines (280 sloc) 7.94 KB
#include <UsbKeyboard.h>
/*
************************************************
**************** ShrimpKey *********************
************************************************
////////////////////////////////////////////////
/////////////HOW TO EDIT THE KEYS //////////////
////////////////////////////////////////////////
- Edit keys in the settings.h file
- that file should be open in a tab above (in Arduino IDE)
////////////////////////////////////////////////
/////////// ShrimpKey FIRMWARE /////////////////
////////////////////////////////////////////////
by Sjoerd Dirk Meijer, info@scratched.eu
and Cefn Hoile, shrimping.it@cefn.com
Derived from MakeyMakey Firmware v.1.4.1
by Eric Rosenbaum, Jay Silver, and Jim Lindblom
and the vusb-for-arduino UsbKeyboard demo
http://www.practicalarduino.com/projects/virtual-usb-keyboard
*/
/////////////////////////
// DEBUG DEFINITIONS ////
/////////////////////////
//#define DEBUG
#ifdef DEBUG
//#define DEBUG_CHANGE
//#define DEBUG_TIMING
#endif
////////////////////////
// DEFINED CONSTANTS////
////////////////////////
#define BUFFER_LENGTH 3 // 3 bytes gives us 24 samples
#define NUM_INPUTS 1 // skipping pin 5 as usbConnect and pin 13 as LED
//#define TARGET_LOOP_TIME 694 // (1/60 seconds) / 24 samples = 694 microseconds per sample
//#define TARGET_LOOP_TIME 758 // (1/55 seconds) / 24 samples = 758 microseconds per sample
#define TARGET_LOOP_TIME 744 // (1/56 seconds) / 24 samples = 744 microseconds per sample
#include "settings.h"
/////////////////////////
// STRUCT ///////////////
/////////////////////////
typedef struct {
byte pinNumber;
int keyCode;
byte measurementBuffer[BUFFER_LENGTH];
boolean oldestMeasurement;
byte bufferSum;
boolean pressed;
}
ShrimpKeyInput;
ShrimpKeyInput inputs[NUM_INPUTS];
///////////////////////////////////
// VARIABLES //////////////////////
///////////////////////////////////
int bufferIndex = 0;
byte byteCounter = 0;
byte bitCounter = 0;
int pressThreshold;
int releaseThreshold;
boolean inputChanged;
// Pin Numbers
//TODO CH indicate that this should be used for testing
int pinNumbers[NUM_INPUTS] = {
A5
};
const int ledPin = 13;
// timing
unsigned long loopTime = 0;
unsigned long prevTime = 0;
int loopCounter = 0;
///////////////////////////
// FUNCTIONS //////////////
///////////////////////////
void initializeArduino();
void initializeInputs();
void updateMeasurementBuffers();
void updateBufferSums();
void updateBufferIndex();
void updateInputStates();
void addDelay();
//////////////////////
// SETUP /////////////
//////////////////////
void setup()
{
//V-USB
// Disable timer0 since it can mess with the USB timing. Note that
// this means some functions such as delay() will no longer work.
TIMSK0&=!(1<<TOIE0);
// Clear interrupts while performing time-critical operations
cli();
// Force re-enumeration so the host will detect us
usbDeviceDisconnect();
delayMs(250);
usbDeviceConnect();
// Set interrupts again
sei();
initializeArduino();
initializeInputs();
}
////////////////////
// MAIN LOOP ///////
////////////////////
void loop()
{
updateUsb();
updateMeasurementBuffers();
updateBufferSums();
updateBufferIndex();
updateInputStates();
addDelay();
}
//V-USB
/**
* Define our own delay function so that we don't have to rely on
* operation of timer0, the interrupt used by the internal delay()
*/
void delayMs(unsigned int ms)
{
for (int i = 0; i < ms; i++) {
delayMicroseconds(1000);
}
}
//////////////////////////
// INITIALIZE ARDUINO
//////////////////////////
void initializeArduino() {
#ifdef DEBUG
Serial.begin(9600); // Serial for debugging
#endif
/* Set up input pins
DEactivate the internal pull-ups, since we're using external resistors */
for (int i=0; i<NUM_INPUTS; i++)
{
pinMode(pinNumbers[i], INPUT);
digitalWrite(pinNumbers[i], LOW);
}
pinMode(ledPin, OUTPUT);
#ifdef DEBUG
delayMs(4000); // allow us time to reprogram in case things are freaking out
#endif
}
///////////////////////////
// INITIALIZE INPUTS
///////////////////////////
void initializeInputs() {
float thresholdPerc = SWITCH_THRESHOLD_OFFSET_PERC;
float thresholdCenterBias = SWITCH_THRESHOLD_CENTER_BIAS/50.0;
float pressThresholdAmount = (BUFFER_LENGTH * 8) * (thresholdPerc / 100.0);
float thresholdCenter = ( (BUFFER_LENGTH * 8) / 2.0 ) * (thresholdCenterBias);
pressThreshold = int(thresholdCenter + pressThresholdAmount);
releaseThreshold = int(thresholdCenter - pressThresholdAmount);
#ifdef DEBUG
Serial.println(pressThreshold);
Serial.println(releaseThreshold);
#endif
for (int i=0; i<NUM_INPUTS; i++) {
inputs[i].pinNumber = pinNumbers[i];
inputs[i].keyCode = keyCodes[i];
for (int j=0; j<BUFFER_LENGTH; j++) {
inputs[i].measurementBuffer[j] = 0;
}
inputs[i].oldestMeasurement = 0;
inputs[i].bufferSum = 0;
#ifdef DEBUG
Serial.println(i);
#endif
}
}
void updateUsb(){
UsbKeyboard.update();
}
//////////////////////////////
// UPDATE MEASUREMENT BUFFERS
//////////////////////////////
void updateMeasurementBuffers() {
for (int i=0; i<NUM_INPUTS; i++) {
// store the oldest measurement, which is the one at the current index,
// before we update it to the new one
// we use oldest measurement in updateBufferSums
byte currentByte = inputs[i].measurementBuffer[byteCounter];
inputs[i].oldestMeasurement = (currentByte >> bitCounter) & 0x01;
// make the new measurement
boolean newMeasurement = digitalRead(inputs[i].pinNumber);
// invert so that true means the switch is closed
newMeasurement = !newMeasurement;
// store it
if (newMeasurement) {
currentByte |= (1<<bitCounter);
}
else {
currentByte &= ~(1<<bitCounter);
}
inputs[i].measurementBuffer[byteCounter] = currentByte;
}
}
///////////////////////////
// UPDATE BUFFER SUMS
///////////////////////////
void updateBufferSums() {
// the bufferSum is a running tally of the entire measurementBuffer
// add the new measurement and subtract the old one
for (int i=0; i<NUM_INPUTS; i++) {
byte currentByte = inputs[i].measurementBuffer[byteCounter];
boolean currentMeasurement = (currentByte >> bitCounter) & 0x01;
if (currentMeasurement) {
inputs[i].bufferSum++;
}
if (inputs[i].oldestMeasurement) {
inputs[i].bufferSum--;
}
}
}
///////////////////////////
// UPDATE BUFFER INDEX
///////////////////////////
void updateBufferIndex() {
bitCounter++;
if (bitCounter == 8) {
bitCounter = 0;
byteCounter++;
if (byteCounter == BUFFER_LENGTH) {
byteCounter = 0;
}
}
}
///////////////////////////
// UPDATE INPUT STATES
///////////////////////////
void updateInputStates() {
inputChanged = false;
for (int i=0; i<NUM_INPUTS; i++) {
if (inputs[i].pressed) {
if (inputs[i].bufferSum < releaseThreshold) {
inputChanged = true;
inputs[i].pressed = false;
releaseKey(inputs[i].keyCode);
}
}
else if (!inputs[i].pressed) {
if (inputs[i].bufferSum > pressThreshold) { // input becomes pressed
inputChanged = true;
inputs[i].pressed = true;
pressKey(inputs[i].keyCode);
}
}
}
#ifdef DEBUG_CHANGE
if (inputChanged) {
Serial.println("change");
}
#endif
}
void pressKey(byte keyCode){
byte modifiers = 0;
UsbKeyboard.keyDown(keyCode);
}
void releaseKey(byte keyCode){
//CH note this currently ignores the key value - probably sends equivalent to "all keys up"
UsbKeyboard.keyUp(keyCode);
}
///////////////////////////
// ADD DELAY
///////////////////////////
void addDelay() {
unsigned long targetMoment = prevTime + loopTime;
if(targetMoment > prevTime){ //handle micros() overflow condition
while(micros() < targetMoment){
updateUsb();
}
}
prevTime = micros();
#ifdef DEBUG_TIMING
if (loopCounter == 0) {
int t = micros()-prevTime;
Serial.println(t);
}
loopCounter++;
loopCounter %= 999;
#endif
}