Merge pull request #2 from jmontineri/master

Update to latest
This commit is contained in:
veroxzik
2019-06-28 23:20:34 -04:00
committed by GitHub
27 changed files with 795 additions and 783 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+173 -148
View File
@@ -1,213 +1,238 @@
//
//
//
//
//
//
#include "AirSensor.h"
#ifndef IR_SENSOR_MULTIPLEXED
int ir_sensor_pins[6] = {AIR_SENSOR_0_PIN, AIR_SENSOR_1_PIN, AIR_SENSOR_2_PIN, AIR_SENSOR_3_PIN, AIR_SENSOR_4_PIN, AIR_SENSOR_5_PIN};
#endif
// Sets the output pins to switch the charlieplexed array of LEDs.
// 0 is the bottom-most LED and 5 is the top-most
void AirSensor::changeLight(int light)
{
switch (light)
{
case 0:
pinMode(IR_A, OUTPUT);
pinMode(IR_B, OUTPUT);
pinMode(IR_C, INPUT);
switch (light)
{
case 0:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(IR_A, LOW);
digitalWrite(IR_B, HIGH);
digitalWrite(IR_C, LOW);
break;
case 1:
pinMode(IR_A, OUTPUT);
pinMode(IR_B, OUTPUT);
pinMode(IR_C, INPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 1:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, INPUT);
digitalWrite(IR_A, HIGH);
digitalWrite(IR_B, LOW);
digitalWrite(IR_C, LOW);
break;
case 2:
pinMode(IR_A, INPUT);
pinMode(IR_B, OUTPUT);
pinMode(IR_C, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 2:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(IR_A, LOW);
digitalWrite(IR_B, LOW);
digitalWrite(IR_C, HIGH);
break;
case 3:
pinMode(IR_A, INPUT);
pinMode(IR_B, OUTPUT);
pinMode(IR_C, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, LOW);
break;
case 3:
pinMode(LED_0, INPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(IR_A, LOW);
digitalWrite(IR_B, HIGH);
digitalWrite(IR_C, LOW);
break;
case 4:
pinMode(IR_A, OUTPUT);
pinMode(IR_B, INPUT);
pinMode(IR_C, OUTPUT);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
case 4:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(IR_A, LOW);
digitalWrite(IR_B, LOW);
digitalWrite(IR_C, HIGH);
break;
case 5:
pinMode(IR_A, OUTPUT);
pinMode(IR_B, INPUT);
pinMode(IR_C, OUTPUT);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
break;
case 5:
pinMode(LED_0, OUTPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(IR_A, HIGH);
digitalWrite(IR_B, LOW);
digitalWrite(IR_C, LOW);
break;
default:
turnOffLight();
break;
}
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, HIGH);
break;
default:
turnOffLight();
break;
}
}
// Sets all output pins to high-impedance to turn off all LEDs
void AirSensor::turnOffLight()
{
pinMode(IR_A, INPUT);
pinMode(IR_B, INPUT);
pinMode(IR_C, INPUT);
pinMode(LED_0, INPUT);
pinMode(LED_1, INPUT);
pinMode(LED_2, INPUT);
}
int AirSensor::getValue(int sensor, bool light)
{
// Turn on light corresponding to read sensor
if (light)
{
changeLight(sensor);
}
else
{
turnOffLight();
}
// Turn on light corresponding to read sensor
if (light)
{
changeLight(sensor);
}
else
{
turnOffLight();
}
#ifdef IR_SENSOR_MULTIPLEXED
// Set multiplexer to corresponding sensor
digitalWrite(MUX_A, bitRead(sensor, 0));
digitalWrite(MUX_B, bitRead(sensor, 1));
digitalWrite(MUX_C, bitRead(sensor, 2));
// Return sensor value
return analogRead(SENSOR_IN);
// Set multiplexer to corresponding sensor
digitalWrite(MUX_A, bitRead(sensor, 0));
digitalWrite(MUX_B, bitRead(sensor, 1));
digitalWrite(MUX_C, bitRead(sensor, 2));
// Return sensor value
#ifdef IR_SENSOR_ANALOG
return analogRead(SENSOR_IN);
#else
return analogRead(ir_sensor_pins[sensor]);
delay(1);
return digitalRead(SENSOR_IN);
#endif
#else
#ifdef IR_SENSOR_ANALOG
return analogRead(ir_sensor_pins[sensor]);
#else
delay(1);
return digitalRead(ir_sensor_pins[sensor]);
#endif
#endif
}
AirSensor::AirSensor(int requiredSamples, int skippedSamples) : thresholds{ 10000, 10000, 10000, 10000, 10000, 10000 }, calibrationSamples{ 0, 0, 0, 0, 0, 0 }, skippedSamples{ 0, 0, 0, 0, 0, 0 }, samplesToAcquire(requiredSamples), samplesToSkip(skippedSamples), calibrated{ 0, 0, 0, 0, 0, 0 }, allCalibrated(false)
{
// Load config values
EEPROM.get(12, deadzone);
EEPROM.get(16, alpha);
// Load config values
EEPROM.get(12, deadzone);
EEPROM.get(16, alpha);
#ifndef IR_SENSOR_ANALOG
// No calibration required in digital mode
for (int i = 0; i < 6; i++)
calibrated[i] = true;
allCalibrated = true;
#endif
}
// Check if all IR sensors are calibrated. If they are, set a flag to not need to re-check it
bool AirSensor::isCalibrated()
{
if (!allCalibrated)
{
for (int i = 0; i < 6; i++)
{
if (!calibrated[i])
return false;
}
allCalibrated = true;
}
return allCalibrated;
if (!allCalibrated)
{
for (int i = 0; i < 6; i++)
{
if (!calibrated[i])
return false;
}
allCalibrated = true;
}
return allCalibrated;
}
bool AirSensor::getSensorState(int sensor)
{
// Flash the LED and read the IR sensor
int value = getValue(sensor, true);
turnOffLight();
// Flash the LED and read the IR sensor
int value = getValue(sensor, true);
turnOffLight();
// If the sensor is calibrated, Store its current filtered value.
// We are using an exponential moving average to filter out environmental noise. Setting alpha to 1 disables it.
if (allCalibrated || calibrated[sensor]) {
sensorValues[sensor] = (float)value * alpha + sensorValues[sensor] * (1 - alpha);
return sensorValues[sensor] < thresholds[sensor];
}
else
{
// If it is not calibrated, perform calibration:
// Skip the first few samples. This might not be required, but improved performance in my case.
// This might be due to wiring mistakes I made - I'm leaving the code in either way as it can't hurt.
if (skippedSamples[sensor] > samplesToSkip)
{
// Keep the minimum value seen by the sensor
if (value < thresholds[sensor]) thresholds[sensor] = value;
// If we have enough samples:
if (++calibrationSamples[sensor] > samplesToAcquire)
{
// Consider the sensor calibrated. Finalize calibration for this sensor.
sensorValues[sensor] = value;
calibrated[sensor] = true;
thresholds[sensor] -= deadzone;
};
}
else
{
skippedSamples[sensor]++;
}
return false;
}
#ifdef IR_SENSOR_ANALOG
// If the sensor is calibrated, Store its current filtered value.
// We are using an exponential moving average to filter out environmental noise. Setting alpha to 1 disables it.
if (allCalibrated || calibrated[sensor]) {
sensorValues[sensor] = (float)value * alpha + sensorValues[sensor] * (1 - alpha);
return sensorValues[sensor] < thresholds[sensor];
}
else
{
// If it is not calibrated, perform calibration:
// Skip the first few samples. This might not be required, but improved performance in my case.
// This might be due to wiring mistakes I made - I'm leaving the code in either way as it can't hurt.
if (skippedSamples[sensor] > samplesToSkip)
{
// Keep the minimum value seen by the sensor
if (value < thresholds[sensor]) thresholds[sensor] = value;
// If we have enough samples:
if (++calibrationSamples[sensor] > samplesToAcquire)
{
// Consider the sensor calibrated. Finalize calibration for this sensor.
sensorValues[sensor] = value;
calibrated[sensor] = true;
thresholds[sensor] -= deadzone;
};
}
else
{
skippedSamples[sensor]++;
}
return false;
}
#else
return value == LOW ? true : false;
#endif
}
// Using data from air sensors, compute the height of the player's hand, from 0 (not present) to 1 (highest possible position).
float AirSensor::getHandPosition()
{
float total = 0;
float sensorsTriggered = 0;
for (int i = 0; i < 6; i++)
{
if (getSensorState(i))
{
sensorsTriggered++;
total += i + 1;
}
}
return sensorsTriggered == 0 ? 0 : (total / (sensorsTriggered)) / 6;
int highestTriggered = -1;
for (int i = 0; i < 6; i++)
{
if (getSensorState(i))
{
if ((i + 1) > highestTriggered)
highestTriggered = i + 1;
}
}
return highestTriggered == -1 ? 0 : ((float)highestTriggered / 6.0f);
}
void AirSensor::setDeadzone(int deadzone)
{
this->deadzone = deadzone;
EEPROM.put(12, deadzone);
this->deadzone = deadzone;
EEPROM.put(12, deadzone);
}
void AirSensor::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(16, alpha);
this->alpha = alpha;
EEPROM.put(16, alpha);
}
int AirSensor::getDeadzone()
{
return deadzone;
return deadzone;
}
float AirSensor::getAlpha()
{
return alpha;
return alpha;
}
void AirSensor::recalibrate()
{
for (int i = 0; i < 6; i++)
{
thresholds[i] = 0;
calibrationSamples[i] = 0;
skippedSamples[i] = 0;
sensorValues[i] = 0;
calibrated[i] = false;
}
allCalibrated = false;
for (int i = 0; i < 6; i++)
{
thresholds[i] = 0;
calibrationSamples[i] = 0;
skippedSamples[i] = 0;
sensorValues[i] = 0;
calibrated[i] = false;
}
allCalibrated = false;
}
+27 -30
View File
@@ -4,50 +4,47 @@
#define _AIRSENSOR_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#include "arduino.h"
#else
#include "WProgram.h"
#include "WProgram.h"
#endif
#include "PinConfig.h"
#include <EEPROM.h>
#ifndef IR_SENSOR_MULTIPLEXED
int ir_sensor_pins[6] = {AIR_SENSOR_0_PIN, AIR_SENSOR_1_PIN, AIR_SENSOR_2_PIN, AIR_SENSOR_3_PIN, AIR_SENSOR_4_PIN, AIR_SENSOR_5_PIN};
#endif
class AirSensor
{
private:
void changeLight(int light);
void turnOffLight();
private:
void changeLight(int light);
void turnOffLight();
int thresholds[6];
int calibrationSamples[6];
int skippedSamples[6];
float sensorValues[6];
int samplesToAcquire;
int samplesToSkip;
int thresholds[6];
int calibrationSamples[6];
int skippedSamples[6];
float sensorValues[6];
int samplesToAcquire;
int samplesToSkip;
bool calibrated[6];
bool allCalibrated;
bool calibrated[6];
bool allCalibrated;
uint16_t deadzone;
float alpha;
public:
AirSensor(int requiredSamples, int skippedSamples);
bool isCalibrated();
bool getSensorState(int sensor);
int getValue(int sensor, bool light);
float getHandPosition();
uint16_t deadzone;
float alpha;
public:
AirSensor(int requiredSamples, int skippedSamples);
bool isCalibrated();
bool getSensorState(int sensor);
int getValue(int sensor, bool light);
float getHandPosition();
void setDeadzone(int deadzone);
void setAlpha(float alpha);
int getDeadzone();
float getAlpha();
void recalibrate();
void setDeadzone(int deadzone);
void setAlpha(float alpha);
int getDeadzone();
float getAlpha();
void recalibrate();
};
#endif
+100 -100
View File
@@ -1,30 +1,30 @@
/*
CapacitiveSense.h - Capacitive Sensing Library for 'duino / Wiring
https://github.com/PaulStoffregen/CapacitiveSensor
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
http://playground.arduino.cc/Main/CapacitiveSensor
Copyright (c) 2009 Paul Bagder
Updates for other hardare by Paul Stoffregen, 2010-2016
Several modifications to better suit OpeNITHM by Jonathan Montineri, 2019
vim: set ts=4:
CapacitiveSense.h - Capacitive Sensing Library for 'duino / Wiring
https://github.com/PaulStoffregen/CapacitiveSensor
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
http://playground.arduino.cc/Main/CapacitiveSensor
Copyright (c) 2009 Paul Bagder
Updates for other hardare by Paul Stoffregen, 2010-2016
Several modifications to better suit OpeNITHM by Jonathan Montineri, 2019
vim: set ts=4:
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:
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 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.
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.
*/
#if ARDUINO >= 100
@@ -42,35 +42,35 @@
CapacitiveSensor::CapacitiveSensor(uint8_t sendPin, uint8_t receivePin1, uint8_t receivePin2)
{
// initialize this instance's variables
error = 1;
retVal = new unsigned int[2];
// initialize this instance's variables
error = 1;
retVal = new unsigned int[2];
loopTimingFactor = 310; // determined empirically - a hack
CS_Timeout_Millis = (200 * (float)loopTimingFactor * (float)F_CPU) / 16000000;
loopTimingFactor = 310; // determined empirically - a hack
CS_Timeout_Millis = (200 * (float)loopTimingFactor * (float)F_CPU) / 16000000;
// get pin mapping and port for send Pin - from PinMode function in core
// get pin mapping and port for send Pin - from PinMode function in core
#ifdef NUM_DIGITAL_PINS
if (sendPin >= NUM_DIGITAL_PINS) error = -1;
if (receivePin1 >= NUM_DIGITAL_PINS) error = -1;
if (receivePin2 >= NUM_DIGITAL_PINS) error = -1;
if (sendPin >= NUM_DIGITAL_PINS) error = -1;
if (receivePin1 >= NUM_DIGITAL_PINS) error = -1;
if (receivePin2 >= NUM_DIGITAL_PINS) error = -1;
#endif
pinMode(sendPin, OUTPUT); // sendpin to OUTPUT
pinMode(receivePin1, INPUT); // receivePins to INPUT
pinMode(receivePin2, INPUT);
pinMode(sendPin, OUTPUT); // sendpin to OUTPUT
pinMode(receivePin1, INPUT); // receivePins to INPUT
pinMode(receivePin2, INPUT);
// Get pin bitmask and registers
// Get pin bitmask and registers
sBit = PIN_TO_BITMASK(sendPin);
sReg = PIN_TO_BASEREG(sendPin);
sBit = PIN_TO_BITMASK(sendPin);
sReg = PIN_TO_BASEREG(sendPin);
r1Bit = PIN_TO_BITMASK(receivePin1);
r1Reg = PIN_TO_BASEREG(receivePin1);
r1Bit = PIN_TO_BITMASK(receivePin1);
r1Reg = PIN_TO_BASEREG(receivePin1);
r2Bit = PIN_TO_BITMASK(receivePin2);
r2Reg = PIN_TO_BASEREG(receivePin2);
r2Bit = PIN_TO_BITMASK(receivePin2);
r2Reg = PIN_TO_BASEREG(receivePin2);
}
// Public Methods //////////////////////////////////////////////////////////////
@@ -78,21 +78,21 @@ CapacitiveSensor::CapacitiveSensor(uint8_t sendPin, uint8_t receivePin1, uint8_t
unsigned int* CapacitiveSensor::sense(uint8_t samples)
{
total1 = 0;
total2 = 0;
total1 = 0;
total2 = 0;
// This code has very strict timing - disable interrupts
noInterrupts();
for (uint8_t i = 0; i < samples; i++) {
if (!SenseOneCycle()) return nullptr; // Poll capacitive sensors repeatedly
}
interrupts();
// This code has very strict timing - disable interrupts
//noInterrupts();
for (uint8_t i = 0; i < samples; i++) {
if (!SenseOneCycle()) return nullptr; // Poll capacitive sensors repeatedly
}
//interrupts();
retVal[0] = total1;
retVal[1] = total2;
retVal[0] = total1;
retVal[1] = total2;
// Return the pair of values for the 2 sensors that were polled
return retVal;
// Return the pair of values for the 2 sensors that were polled
return retVal;
}
// Private Methods /////////////////////////////////////////////////////////////
@@ -101,60 +101,60 @@ unsigned int* CapacitiveSensor::sense(uint8_t samples)
int CapacitiveSensor::SenseOneCycle(void)
{
DIRECT_WRITE_LOW(sReg, sBit); // sendPin Register low
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to input (pullups ar1e off)
DIRECT_MODE_OUTPUT(r1Reg, r1Bit); // receivePin to OUTPUT
DIRECT_WRITE_LOW(r1Reg, r1Bit); // pin is now LOW AND OUTPUT
delayMicroseconds(10);
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to input (pullups ar1e off)
DIRECT_WRITE_LOW(sReg, sBit); // sendPin Register low
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to input (pullups ar1e off)
DIRECT_MODE_OUTPUT(r1Reg, r1Bit); // receivePin to OUTPUT
DIRECT_WRITE_LOW(r1Reg, r1Bit); // pin is now LOW AND OUTPUT
delayMicroseconds(10);
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to input (pullups ar1e off)
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to input (pullups ar2e off)
DIRECT_MODE_OUTPUT(r2Reg, r2Bit); // receivePin to OUTPUT
DIRECT_WRITE_LOW(r2Reg, r2Bit); // pin is now LOW AND OUTPUT
delayMicroseconds(10);
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to input (pullups ar2e off)
DIRECT_WRITE_HIGH(sReg, sBit); // sendPin High
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to input (pullups ar2e off)
DIRECT_MODE_OUTPUT(r2Reg, r2Bit); // receivePin to OUTPUT
DIRECT_WRITE_LOW(r2Reg, r2Bit); // pin is now LOW AND OUTPUT
delayMicroseconds(10);
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to input (pullups ar2e off)
DIRECT_WRITE_HIGH(sReg, sBit); // sendPin High
while (total1 < CS_Timeout_Millis) { // while total is positive value
// Poll both pins at once
pin1State = DIRECT_READ(r1Reg, r1Bit);
pin2State = DIRECT_READ(r2Reg, r2Bit);
while (total1 < CS_Timeout_Millis) { // while total is positive value
// Poll both pins at once
pin1State = DIRECT_READ(r1Reg, r1Bit);
pin2State = DIRECT_READ(r2Reg, r2Bit);
total1 += !pin1State;
total2 += !pin2State;
total1 += !pin1State;
total2 += !pin2State;
// Break once both pins are high
if(pin1State && pin2State) break;
}
// Break once both pins are high
if (pin1State && pin2State) break;
}
if (total1 > CS_Timeout_Millis) {
return -2; // We timed out - should never happen with this implementation
}
if (total1 > CS_Timeout_Millis) {
return -2; // We timed out - should never happen with this implementation
}
// set receive pin HIGH briefly to charge up fully - because the while loop above will exit when pin is ~ 2.5V
DIRECT_WRITE_HIGH(r1Reg, r1Bit);
DIRECT_MODE_OUTPUT(r1Reg, r1Bit); // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
DIRECT_MODE_OUTPUT(r2Reg, r2Bit); // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
DIRECT_WRITE_HIGH(r1Reg, r1Bit);
DIRECT_WRITE_HIGH(r2Reg, r2Bit);
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to INPUT (pullup is off)
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to INPUT (pullup is off)
DIRECT_WRITE_LOW(sReg, sBit); // sendPin LOW
// set receive pin HIGH briefly to charge up fully - because the while loop above will exit when pin is ~ 2.5V
DIRECT_WRITE_HIGH(r1Reg, r1Bit);
DIRECT_MODE_OUTPUT(r1Reg, r1Bit); // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
DIRECT_MODE_OUTPUT(r2Reg, r2Bit); // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
DIRECT_WRITE_HIGH(r1Reg, r1Bit);
DIRECT_WRITE_HIGH(r2Reg, r2Bit);
DIRECT_MODE_INPUT(r1Reg, r1Bit); // receivePin to INPUT (pullup is off)
DIRECT_MODE_INPUT(r2Reg, r2Bit); // receivePin to INPUT (pullup is off)
DIRECT_WRITE_LOW(sReg, sBit); // sendPin LOW
// Same loop as above, but measuring capacitor discharge time instead
while ( (total1 < CS_Timeout_Millis) ) {
pin1State = DIRECT_READ(r1Reg, r1Bit);
pin2State = DIRECT_READ(r2Reg, r2Bit);
// Same loop as above, but measuring capacitor discharge time instead
while ( (total1 < CS_Timeout_Millis) ) {
pin1State = DIRECT_READ(r1Reg, r1Bit);
pin2State = DIRECT_READ(r2Reg, r2Bit);
total1 += pin1State;
total2 += pin2State;
total1 += pin1State;
total2 += pin2State;
if(!(pin1State || pin2State)) break;
}
if (!(pin1State || pin2State)) break;
}
if (total1 >= CS_Timeout_Millis) {
return -2;
} else {
return 1;
}
if (total1 >= CS_Timeout_Millis) {
return -2;
} else {
return 1;
}
}
+67 -67
View File
@@ -115,79 +115,79 @@
#include "portable.h"
#include "avr/pgmspace.h"
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
#define DIR_OFFSET_SS 0x01
#define DIR_OFFSET_SOC 0x04
#define EXT_PORT_OFFSET_SS 0x0A
#define EXT_PORT_OFFSET_SOC 0x50
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
#define DIR_OFFSET_SS 0x01
#define DIR_OFFSET_SOC 0x04
#define EXT_PORT_OFFSET_SS 0x0A
#define EXT_PORT_OFFSET_SOC 0x50
/* GPIO registers base address */
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
#define PIN_TO_BITMASK(pin) pin
#define IO_REG_TYPE uint32_t
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
#define PIN_TO_BITMASK(pin) pin
#define IO_REG_TYPE uint32_t
#define IO_REG_ASM
static inline __attribute__((always_inline))
IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
IO_REG_TYPE ret;
if (SS_GPIO == GPIO_TYPE(pin)) {
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
} else {
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
}
return ((ret >> GPIO_ID(pin)) & 0x01);
IO_REG_TYPE ret;
if (SS_GPIO == GPIO_TYPE(pin)) {
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
} else {
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
}
return ((ret >> GPIO_ID(pin)) & 0x01);
}
static inline __attribute__((always_inline))
void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
}
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
}
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
} else {
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
}
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
}
}
static inline __attribute__((always_inline))
void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
{
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
}
if (SS_GPIO == GPIO_TYPE(pin)) {
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
} else {
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
}
}
#define DIRECT_READ(base, pin) directRead(base, pin)
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
#define DIRECT_READ(base, pin) directRead(base, pin)
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
#endif
@@ -201,32 +201,32 @@ void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
// library interface description
class CapacitiveSensor
{
// user-accessible "public" interface
// user-accessible "public" interface
public:
// methods
CapacitiveSensor(uint8_t sendPin, uint8_t receivePin1, uint8_t receivePin2);
unsigned int* sense(uint8_t samples);
// library-accessible "private" interface
// methods
CapacitiveSensor(uint8_t sendPin, uint8_t receivePin1, uint8_t receivePin2);
unsigned int* sense(uint8_t samples);
// library-accessible "private" interface
private:
// variables
int error;
unsigned long leastTotal;
unsigned int loopTimingFactor;
unsigned long CS_Timeout_Millis;
unsigned int total1;
unsigned int total2;
unsigned int *retVal;
bool pin1State;
bool pin2State;
// variables
int error;
unsigned long leastTotal;
unsigned int loopTimingFactor;
unsigned long CS_Timeout_Millis;
unsigned int total1;
unsigned int total2;
unsigned int *retVal;
bool pin1State;
bool pin2State;
IO_REG_TYPE sBit; // send pin's ports and bitmask
volatile IO_REG_TYPE *sReg;
IO_REG_TYPE r1Bit; // receive 1 pin's ports and bitmask
volatile IO_REG_TYPE *r1Reg;
IO_REG_TYPE r2Bit; // receive 2 pin's ports and bitmask
volatile IO_REG_TYPE *r2Reg;
// methods
int SenseOneCycle(void);
IO_REG_TYPE sBit; // send pin's ports and bitmask
volatile IO_REG_TYPE *sReg;
IO_REG_TYPE r1Bit; // receive 1 pin's ports and bitmask
volatile IO_REG_TYPE *r1Reg;
IO_REG_TYPE r2Bit; // receive 2 pin's ports and bitmask
volatile IO_REG_TYPE *r2Reg;
// methods
int SenseOneCycle(void);
};
#endif
+186 -191
View File
@@ -1,13 +1,11 @@
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32u4__)
#include "USBOutput.h"
#define USB
#endif
#include "PinConfig.h"
#ifdef USB
#include "USBOutput.h"
#else
#include "SerialOutput.h"
#endif
#include "AirSensor.h"
#include "Touchboard.h"
#include <FastLED.h>
@@ -26,216 +24,213 @@ Touchboard *touchboard;
AirSensor *sensor;
Output *output;
char *command;
char command[32];
// Triggered when Touchboard determines a key was pressed
void onKeyPress(int key, bool wasHeld)
{
lightIntensity[key] = 1.0f;
output->sendKeyEvent(key, true, wasHeld);
keyStates[key] = true;
lightIntensity[key] = 1.0f;
output->sendKeyEvent(key, true, wasHeld);
keyStates[key] = true;
}
// Parse configuration command. For now, a serial terminal is required (like the monitor in Arduino IDE)
// Eventually I will make a config tool
void parseCommand()
{
char input1 = Serial.read();
char input2;
switch (input1)
{
case 't': // touchboard
while(!Serial.available());
input2 = Serial.read();
while(!Serial.available());
switch (input2)
{
case 't': // threshold
touchboard->setThreshold(Serial.parseInt());
break;
case 'd': // dead zone
touchboard->setDeadzone(Serial.parseInt());
break;
case 'a': // alpha
touchboard->setAlpha(Serial.parseFloat());
break;
case 'c': // calibrate
touchboard->calibrateKeys();
}
break;
case 'i': // ir sensors
while(!Serial.available());
input2 = Serial.read();
while(!Serial.available());
switch (input2)
{
case 'd': // dead zone
sensor->setDeadzone(Serial.parseInt());
break;
case 'a': // alpha
sensor->setAlpha(Serial.parseFloat());
break;
case 'c': // calibrate
sensor->recalibrate();
}
break;
case 'p': // pause
activated = false;
break;
case 'r': // resume
activated = true;
break;
case 'g': // print values
Serial.print("tt \t");
Serial.println(touchboard->getThreshold());
Serial.print("td \t");
Serial.println(touchboard->getDeadzone());
Serial.print("ta \t");
Serial.println(touchboard->getAlpha());
Serial.print("id \t");
Serial.println(sensor->getDeadzone());
Serial.print("ia \t");
Serial.println(sensor->getAlpha());
Serial.print("lor \t");
Serial.println(led_on.r);
Serial.print("log \t");
Serial.println(led_on.g);
Serial.print("lob \t");
Serial.println(led_on.b);
Serial.print("lfr \t");
Serial.println(led_off.r);
Serial.print("lfg \t");
Serial.println(led_off.g);
Serial.print("lfb \t");
Serial.println(led_off.b);
Serial.print(";");
break;
case 'a': // check if activated
Serial.println(activated);
Serial.print(";");
break;
case 'l': // change led color
while(!Serial.available());
input2 = Serial.read();
while(!Serial.available());
switch (input2)
{
case 'o': // on
while(!Serial.available());
switch ((char)Serial.read())
{
case 'r': // red
led_on.r = Serial.parseInt(); // for now this has to be expressed in decimal
break;
case 'g': // green
led_on.g = Serial.parseInt();
break;
case 'b': // blue
led_on.b = Serial.parseInt();
break;
case 'e': // everything
led_on = Serial.parseInt();
}
break;
case 'f': // off
while(!Serial.available());
switch ((char)Serial.read())
{
case 'r': // red
led_off.r = Serial.parseInt(); // for now this has to be expressed in decimal
break;
case 'g': // green
led_off.g = Serial.parseInt();
break;
case 'b': // blue
led_off.b = Serial.parseInt();
break;
case 'e': // everything
led_off = Serial.parseInt();
}
break;
}
break;
}
char input1 = Serial.read();
char input2;
switch (input1)
{
case 't': // touchboard
while (!Serial.available());
input2 = Serial.read();
switch (input2)
{
case 't': // threshold
touchboard->setThreshold(Serial.parseInt());
break;
case 'd': // dead zone
touchboard->setDeadzone(Serial.parseInt());
break;
case 'a': // alpha
touchboard->setAlpha(Serial.parseFloat());
break;
case 'c': // calibrate
touchboard->calibrateKeys();
}
break;
case 'i': // ir sensors
while (!Serial.available());
input2 = Serial.read();
switch (input2)
{
case 'd': // dead zone
sensor->setDeadzone(Serial.parseInt());
break;
case 'a': // alpha
sensor->setAlpha(Serial.parseFloat());
break;
case 'c': // calibrate
sensor->recalibrate();
}
break;
case 'p': // pause
activated = false;
break;
case 'r': // resume
activated = true;
break;
case 'g': // print values
Serial.print("tt \t");
Serial.println(touchboard->getThreshold());
Serial.print("td \t");
Serial.println(touchboard->getDeadzone());
Serial.print("ta \t");
Serial.println(touchboard->getAlpha());
Serial.print("id \t");
Serial.println(sensor->getDeadzone());
Serial.print("ia \t");
Serial.println(sensor->getAlpha());
Serial.print("lor \t");
Serial.println(led_on.r);
Serial.print("log \t");
Serial.println(led_on.g);
Serial.print("lob \t");
Serial.println(led_on.b);
Serial.print("lfr \t");
Serial.println(led_off.r);
Serial.print("lfg \t");
Serial.println(led_off.g);
Serial.print("lfb \t");
Serial.println(led_off.b);
Serial.print(";");
break;
case 'a': // check if activated
Serial.println(activated);
Serial.print(";");
break;
case 'l': // change led color
while (!Serial.available());
input2 = Serial.read();
switch (input2)
{
case 'o': // on
while (!Serial.available());
switch ((char)Serial.read())
{
case 'r': // red
led_on.r = Serial.parseInt(); // for now this has to be expressed in decimal
break;
case 'g': // green
led_on.g = Serial.parseInt();
break;
case 'b': // blue
led_on.b = Serial.parseInt();
break;
case 'e': // everything
led_on = Serial.parseInt();
}
break;
case 'f': // off
while (!Serial.available());
switch ((char)Serial.read())
{
case 'r': // red
led_off.r = Serial.parseInt(); // for now this has to be expressed in decimal
break;
case 'g': // green
led_off.g = Serial.parseInt();
break;
case 'b': // blue
led_off.b = Serial.parseInt();
break;
case 'e': // everything
led_off = Serial.parseInt();
}
break;
}
break;
}
}
void setup() {
Serial.begin(115200);
command = malloc(32);
Serial.begin(115200);
FastLED.addLeds<LED_TYPE, RGBPIN, LED_ORDER>(leds, 16);
FastLED.addLeds<LED_TYPE, RGBPIN, LED_ORDER>(leds, 16);
// Set LEDs blue
for (CRGB& led : leds)
{
led = 0x0000FF;
FastLED.show();
}
// Set LEDs blue
for (CRGB& led : leds)
{
led = 0x0000FF;
FastLED.show();
}
// Initialize and calibrate touch sensors
touchboard = new Touchboard(onKeyPress);
// Initialize and calibrate touch sensors
touchboard = new Touchboard(onKeyPress);
// Set LEDs red
for (CRGB& led : leds)
{
led = 0xFF0000;
FastLED.show();
}
// Set LEDs red
for (CRGB& led : leds)
{
led = 0xFF0000;
FastLED.show();
}
// Initialize air sensor - will automatically calibrate as it starts being read
sensor = new AirSensor(500, 50);
// Initialize air sensor - will automatically calibrate as it starts being read
sensor = new AirSensor(500, 50);
// Initialize relevant output method / USB or serial
#ifdef USB
output = new USBOutput();
#else
output = new SerialOutput();
#endif
// Initialize relevant output method / USB or serial
#ifdef USB
output = new USBOutput();
#else
output = new SerialOutput();
#endif
}
void loop() {
// Process config commands
if (Serial.available())
{
parseCommand();
}
// If currently paused through a config command, do not execute main loop
if (!activated) return;
// Process config commands
if (Serial.available())
{
parseCommand();
}
// Scan touch keyboard and update lights
touchboard->scan();
for (int i = 0; i < 16; i++)
{
if (lightIntensity[i] > 0.05f)
lightIntensity[i] -= 0.05f;
// If currently paused through a config command, do not execute main loop
if (!activated) return;
// If the key is currently being held, set its color to purple
if (touchboard->update(i))
{
leds[i].setRGB(min(led_on.r / 2 + led_on.r / 2 * lightIntensity[i], 255), min(led_on.g / 2 + led_on.g / 2 * lightIntensity[i], 255), min(led_on.b / 2 + led_on.b / 2 * lightIntensity[i], 255));
}
else
{
// If not, make it yellow and send the "key released" event if it was previously pressed
leds[i].setRGB(led_off.r/2, led_off.g/2, led_off.b/2);
if (keyStates[i])
{
output->sendKeyEvent(i, false, false);
keyStates[i] = false;
}
}
}
// Scan touch keyboard and update lights
touchboard->scan();
for (int i = 0; i < 16; i++)
{
if (lightIntensity[i] > 0.05f)
lightIntensity[i] -= 0.05f;
// Process air sensor hand position
const float newPosition = sensor->getHandPosition();
if (newPosition != sensorPosition)
{
output->sendSensorEvent(newPosition);
sensorPosition = newPosition;
}
// If the key is currently being held, set its color to purple
if (touchboard->update(i))
{
leds[i].setRGB(min(led_on.r / 2 + led_on.r / 2 * lightIntensity[i], 255), min(led_on.g / 2 + led_on.g / 2 * lightIntensity[i], 255), min(led_on.b / 2 + led_on.b / 2 * lightIntensity[i], 255));
}
else
{
// If not, make it yellow and send the "key released" event if it was previously pressed
leds[i].setRGB(led_off.r / 2, led_off.g / 2, led_off.b / 2);
if (keyStates[i])
{
output->sendKeyEvent(i, false, false);
keyStates[i] = false;
}
}
}
// Process air sensor hand position
const float newPosition = sensor->getHandPosition();
if (newPosition != sensorPosition)
{
output->sendSensorEvent(newPosition);
sensorPosition = newPosition;
}
// If the air sensor is calibrated, update lights. The lights will stay red as long as the air sensor is not calibrated.
if (sensor->isCalibrated())
FastLED.show();
}
// If the air sensor is calibrated, update lights. The lights will stay red as long as the air sensor is not calibrated.
if (sensor->isCalibrated())
FastLED.show();
}
+3 -10
View File
@@ -3,18 +3,11 @@
#ifndef _OUTPUT_h
#define _OUTPUT_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
class Output
{
public:
virtual void sendKeyEvent(int key, bool pressed, bool doublePressed);
virtual void sendSensorEvent(float position);
public:
virtual void sendKeyEvent(int key, bool pressed, bool doublePressed);
virtual void sendSensorEvent(float position);
};
#endif
+27 -19
View File
@@ -1,35 +1,43 @@
#pragma once
#ifndef _PINCONFIG_h
#define _PINCONFIG_h
#define IR_SENSOR_MULTIPLEXED
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32u4__)
#define USB
#endif
//#define IR_SENSOR_MULTIPLEXED
//#define IR_SENSOR_ANALOG // Uncomment if IR sensors are hooked up to analog pins
#define CALIBRATION_SAMPLES 500
// Multiplexer pin settings
#define MUX_A 9
#define MUX_B 8
#define MUX_C 7
#define MUX_0 20
#define MUX_1 19
#define MUX_2 18
// Sensor pin settings
#define IR_A 5
#define IR_B 4
#define IR_C 3
#define LED_0 0
#define LED_1 2
#define LED_2 3
#ifdef IR_SENSOR_MULTIPLEXED
#define SENSOR_IN A0
#define SENSOR_IN A0
#else
#define AIR_SENSOR_0_PIN 4
#define AIR_SENSOR_1_PIN 5
#define AIR_SENSOR_2_PIN 6
#define AIR_SENSOR_3_PIN 7
#define AIR_SENSOR_4_PIN 8
#define AIR_SENSOR_5_PIN 9
#define AIR_SENSOR_0_PIN 4
#define AIR_SENSOR_1_PIN 5
#define AIR_SENSOR_2_PIN 6
#define AIR_SENSOR_3_PIN 7
#define AIR_SENSOR_4_PIN 8
#define AIR_SENSOR_5_PIN 9
#endif
// Capsense pin settings
#define KEYBOARDPIN_1 10
#define KEYBOARDPIN_2 12
#define KEYBOARDPIN_COM 11
#define RECEIVE_1 21
#define RECEIVE_2 1
#define SEND 10
// Lighting pin settings
#define LED_TYPE WS2812B
#define LED_ORDER GRB
#define RGBPIN 2
#define RGBPIN 16
#endif
+13 -13
View File
@@ -1,6 +1,6 @@
//
//
//
//
//
//
#include "SerialOutput.h"
@@ -10,20 +10,20 @@
void SerialOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
builtPacket.data = 0;
builtPacket.keyEvent.isKeyboard = true;
builtPacket.keyEvent.isPressed = pressed;
builtPacket.keyEvent.isDoublePressed = doublePressed;
builtPacket.keyEvent.key = key;
builtPacket.data = 0;
builtPacket.keyEvent.isKeyboard = true;
builtPacket.keyEvent.isPressed = pressed;
builtPacket.keyEvent.isDoublePressed = doublePressed;
builtPacket.keyEvent.key = key;
Serial.write(builtPacket.data);
Serial.write(builtPacket.data);
}
void SerialOutput::sendSensorEvent(float position)
{
builtPacket.data = 0;
builtPacket.sensorEvent.isKeyboard = false;
builtPacket.sensorEvent.position = position * 127;
builtPacket.data = 0;
builtPacket.sensorEvent.isKeyboard = false;
builtPacket.sensorEvent.position = position * 127;
Serial.write(builtPacket.data);
Serial.write(builtPacket.data);
}
+20 -21
View File
@@ -4,39 +4,38 @@
#define _SERIALOUTPUT_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#include "arduino.h"
#else
#include "WProgram.h"
#include "WProgram.h"
#endif
#include "Output.h"
//All events can fit within one byte to save time sending over serial
union Packet
{
uint8_t data;
struct
{
bool isKeyboard : 1;
bool isPressed : 1;
bool isDoublePressed : 1;
unsigned int key : 5;
} keyEvent;
struct
{
bool isKeyboard : 1;
int position : 7;
} sensorEvent;
uint8_t data;
struct
{
bool isKeyboard : 1;
bool isPressed : 1;
bool isDoublePressed : 1;
unsigned int key : 5;
} keyEvent;
struct
{
bool isKeyboard : 1;
int position : 7;
} sensorEvent;
};
class SerialOutput : public Output
{
private:
Packet builtPacket = Packet();
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
private:
Packet builtPacket = Packet();
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
};
#endif
+82 -78
View File
@@ -2,123 +2,127 @@
void Touchboard::scan()
{
// For each key, set multiplexers and poll both capacitive sensors simultaneously
for (int i = 0; i < 8; i++)
{
digitalWrite(MUX_A, bitRead(i, 0));
digitalWrite(MUX_B, bitRead(i, 1));
digitalWrite(MUX_C, bitRead(i, 2));
// For each key, set multiplexers and poll both capacitive sensors simultaneously
for (int i = 0; i < 8; i++)
{
digitalWrite(MUX_0, bitRead(i, 0));
digitalWrite(MUX_1, bitRead(i, 1));
digitalWrite(MUX_2, bitRead(i, 2));
unsigned int* values = sensor.sense(3);
unsigned int* values = sensor.sense(3);
// Store the values received from the sensor poll into their respective positions
keys[i] = values[0];
keys[i + 8] = values[1];
}
// Store the values received from the sensor poll into their respective positions
keys[i] = values[0];
keys[i + 8] = values[1];
}
}
void Touchboard::calibrateKeys()
{
// Reset calibration data for all keys
for (int i = 0; i < 16; i++)
{
em_averages[i] = 0;
neutral_values[i] = 0;
key_states[i] = false;
keys[i] = false;
}
// Reset calibration data for all keys
for (int i = 0; i < 16; i++)
{
em_averages[i] = 0;
neutral_values[i] = 0;
key_states[i] = false;
keys[i] = false;
}
for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
// Repeatedly scan all keys
scan();
// Store the lowest read value as our baseline
for (int j = 0; j < 16; j++) {
if (keys[j] > neutral_values[j]) neutral_values[j] = keys[j];
}
}
// After calibration is complete, initialize the averages to the baseline values established previously
for (int i = 0; i < 16; i++) {
em_averages[i] = neutral_values[i];
}
for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
// Repeatedly scan all keys
scan();
// Store the lowest read value as our baseline
for (int j = 0; j < 16; j++) {
if (keys[j] > neutral_values[j]) neutral_values[j] = keys[j];
}
}
// After calibration is complete, initialize the averages to the baseline values established previously
for (int i = 0; i < 16; i++) {
em_averages[i] = neutral_values[i];
}
}
bool Touchboard::update(int key)
{
int read_value = keys[key];
float new_average = alpha * read_value + (1 - alpha) * em_averages[key];
if (read_value - neutral_values[key] < deadzone)
{
// If we are in the deadzone, ignore any touch events, set the key to be untouched and update the moving average.
if (key_states[key])
em_averages[key] = neutral_values[key];
else
em_averages[key] = new_average;
key_states[key] = false;
}
else
{
//If we are outside of the deadzone:
if (read_value > em_averages[key] + threshold)
{
// If we just detected a touch, make the key touched, discard the previous moving average and trigger the callback.
em_averages[key] = read_value;
onKeyPress(key, key_states[key]);
key_states[key] = true;
}
else
{
// Otherwise, just update the average.
em_averages[key] = new_average;
}
}
return key_states[key];
int read_value = keys[key];
float new_average = alpha * read_value + (1 - alpha) * em_averages[key];
if (read_value - neutral_values[key] < deadzone)
{
// If we are in the deadzone, ignore any touch events, set the key to be untouched and update the moving average.
if (key_states[key])
em_averages[key] = neutral_values[key];
else
em_averages[key] = new_average;
key_states[key] = false;
}
else
{
//If we are outside of the deadzone:
if (read_value > em_averages[key] + threshold)
{
// If we just detected a touch, make the key touched, discard the previous moving average and trigger the callback.
em_averages[key] = read_value;
onKeyPress(key, key_states[key]);
key_states[key] = true;
}
else
{
// Otherwise, just update the average.
em_averages[key] = new_average;
}
}
return key_states[key];
}
void Touchboard::setThreshold(uint16_t threshold)
{
this->threshold = threshold;
EEPROM.put(0, threshold);
this->threshold = threshold;
EEPROM.put(0, threshold);
}
void Touchboard::setDeadzone(uint16_t deadzone)
{
this->deadzone = deadzone;
EEPROM.put(4, deadzone);
this->deadzone = deadzone;
EEPROM.put(4, deadzone);
}
void Touchboard::setAlpha(float alpha)
{
this->alpha = alpha;
EEPROM.put(8, alpha);
this->alpha = alpha;
EEPROM.put(8, alpha);
}
int Touchboard::getThreshold()
{
return threshold;
return threshold;
}
int Touchboard::getDeadzone()
{
return deadzone;
return deadzone;
}
float Touchboard::getAlpha()
{
return alpha;
return alpha;
}
float Touchboard::getEmAverages(int key)
{
return em_averages[key];
}
Touchboard::Touchboard(void(*keyPressCallback)(int, bool)) :
sensor(CapacitiveSensor(KEYBOARDPIN_COM, KEYBOARDPIN_1, KEYBOARDPIN_2)),
onKeyPress(keyPressCallback)
sensor(CapacitiveSensor(SEND, RECEIVE_1, RECEIVE_2)),
onKeyPress(keyPressCallback)
{
EEPROM.get(0, threshold);
EEPROM.get(4, deadzone);
EEPROM.get(8, alpha);
EEPROM.get(0, threshold);
EEPROM.get(4, deadzone);
EEPROM.get(8, alpha);
pinMode(MUX_A, OUTPUT);
pinMode(MUX_B, OUTPUT);
pinMode(MUX_C, OUTPUT);
pinMode(MUX_0, OUTPUT);
pinMode(MUX_1, OUTPUT);
pinMode(MUX_2, OUTPUT);
calibrateKeys();
calibrateKeys();
}
+22 -30
View File
@@ -3,12 +3,6 @@
#ifndef _TOUCHBOARD_h
#define _TOUCHBOARD_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "PinConfig.h"
#include "CapacitiveSensor.h"
#include <EEPROM.h>
@@ -16,34 +10,32 @@
class Touchboard
{
private:
CapacitiveSensor sensor;
private:
CapacitiveSensor sensor;
uint16_t threshold;
uint16_t deadzone;
float alpha;
uint16_t threshold;
uint16_t deadzone;
float alpha;
float em_averages[16];
unsigned int keys[16];
int neutral_values[16];
void (*onKeyPress)(int, bool);
float em_averages[16];
unsigned int keys[16];
int neutral_values[16];
void (*onKeyPress)(int, bool);
public:
boolean key_states[16];
public:
boolean key_states[16];
Touchboard(void(*keyPressCallback)(int, bool));
void scan();
bool update(int key);
void setThreshold(uint16_t threshold);
void setDeadzone(uint16_t deadzone);
void setAlpha(float alpha);
int getThreshold();
int getDeadzone();
float getAlpha();
void calibrateKeys();
Touchboard(void(*keyPressCallback)(int, bool));
void scan();
bool update(int key);
void setThreshold(uint16_t threshold);
void setDeadzone(uint16_t deadzone);
void setAlpha(float alpha);
int getThreshold();
int getDeadzone();
float getAlpha();
float getEmAverages(int key);
void calibrateKeys();
};
#endif
+50 -49
View File
@@ -1,51 +1,52 @@
#ifdef USB
#include "USBOutput.h"
char bottomRow[] = {'a', 'z', 's', 'x', 'd', 'c', 'f', 'v', 'g', 'b', 'h', 'n', 'j', 'm', 'k', ','};
char topRow[] = {'1', 'q', '2', 'w', '3', 'e', '4', 'r', '5', 't', '6', 'y', '7', 'u', '8', 'i'};
void USBOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
if(pressed){
if(doublePressed){
NKROKeyboard.write(topRow[key]);
}
else{
NKROKeyboard.press(bottomRow[key]);
}
}
else{
NKROKeyboard.release(bottomRow[key]);
}
}
void USBOutput::sendSensorEvent(float position)
{
// Send hand up / hand down key
if(position > lastPosition){
NKROKeyboard.write(KEY_PAGE_UP);
}
if(position < lastPosition){
NKROKeyboard.write(KEY_PAGE_DOWN);
}
// Send hand seen / unseen key
if(position > 0.05f){
NKROKeyboard.press(KEY_HOME);
}
else{
NKROKeyboard.release(KEY_HOME);
}
// Send hand moved key
NKROKeyboard.write(KEY_END);
}
USBOutput::USBOutput(){
NKROKeyboard.begin();
lastPosition = 0;
}
#include "PinConfig.h"
#ifdef USB
#include "USBOutput.h"
char bottomRow[] = {'a', 'z', 's', 'x', 'd', 'c', 'f', 'v', 'g', 'b', 'h', 'n', 'j', 'm', 'k', ','};
char topRow[] = {'1', 'q', '2', 'w', '3', 'e', '4', 'r', '5', 't', '6', 'y', '7', 'u', '8', 'i'};
void USBOutput::sendKeyEvent(int key, bool pressed, bool doublePressed)
{
if (pressed) {
if (doublePressed) {
NKROKeyboard.write(topRow[key]);
}
else {
NKROKeyboard.press(bottomRow[key]);
}
}
else {
NKROKeyboard.release(bottomRow[key]);
}
}
void USBOutput::sendSensorEvent(float position)
{
// Send hand up / hand down key
if (position > lastPosition) {
NKROKeyboard.write(KEY_PAGE_UP);
}
if (position < lastPosition) {
NKROKeyboard.write(KEY_PAGE_DOWN);
}
// Send hand seen / unseen key
if (position > 0.05f) {
NKROKeyboard.press(KEY_HOME);
}
else {
NKROKeyboard.release(KEY_HOME);
}
// Send hand moved key
NKROKeyboard.write(KEY_END);
}
USBOutput::USBOutput() {
NKROKeyboard.begin();
lastPosition = 0;
}
#endif
+25 -27
View File
@@ -1,28 +1,26 @@
#define USBCON
#include <HID-Project.h>
// USBOutput.h
#ifndef _USBOUTPUT_h
#define _USBOUTPUT_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include "Output.h"
class USBOutput : public Output
{
private:
float lastPosition;
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
USBOutput();
};
#endif
// USBOutput.h
#ifndef _USBOUTPUT_h
#define _USBOUTPUT_h
#include "Output.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include <HID-Project.h>
class USBOutput : public Output
{
private:
float lastPosition;
public:
void sendKeyEvent(int key, bool pressed, bool doublePressed) override;
void sendSensorEvent(float position) override;
USBOutput();
};
#endif