Firmware fixes #4
+173
-148
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user