From 514ab9740b8711dba113eae84aa6834264f7f770 Mon Sep 17 00:00:00 2001 From: veroxzik Date: Thu, 18 Apr 2019 23:17:19 -0400 Subject: [PATCH] Updates to match PCB Changed pin names to match schematic and PCB per mickabrig7 Changed default pins numbers to match PCB Added ability to use digitalRead for IR sensors Changes tabs to 2 spaces (consistent with Arduino standard) Fixes build for 32U4 based processors (SerialOutput.h/.cpp is untested) --- Firmware/AirSensor.cpp | 321 +++++++++++++++-------------- Firmware/AirSensor.h | 53 +++-- Firmware/CapacitiveSensor.cpp | 154 +++++++------- Firmware/CapacitiveSensor.h | 70 +++---- Firmware/OpeNITHM.ino | 374 +++++++++++++++++----------------- Firmware/Output.h | 11 +- Firmware/PinConfig.h | 42 ++-- Firmware/SerialOutput.cpp | 20 +- Firmware/SerialOutput.h | 37 ++-- Firmware/Touchboard.cpp | 160 ++++++++------- Firmware/Touchboard.h | 48 ++--- Firmware/USBOutput.cpp | 100 ++++----- Firmware/USBOutput.h | 52 +++-- 13 files changed, 726 insertions(+), 716 deletions(-) diff --git a/Firmware/AirSensor.cpp b/Firmware/AirSensor.cpp index 881d949..083cf2f 100644 --- a/Firmware/AirSensor.cpp +++ b/Firmware/AirSensor.cpp @@ -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; } diff --git a/Firmware/AirSensor.h b/Firmware/AirSensor.h index 8caf847..91b5783 100644 --- a/Firmware/AirSensor.h +++ b/Firmware/AirSensor.h @@ -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 -#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(); + 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; + 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(); + 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 - diff --git a/Firmware/CapacitiveSensor.cpp b/Firmware/CapacitiveSensor.cpp index 3f7fb55..8f6c35d 100644 --- a/Firmware/CapacitiveSensor.cpp +++ b/Firmware/CapacitiveSensor.cpp @@ -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; + } } diff --git a/Firmware/CapacitiveSensor.h b/Firmware/CapacitiveSensor.h index 8112244..e34ecae 100644 --- a/Firmware/CapacitiveSensor.h +++ b/Firmware/CapacitiveSensor.h @@ -115,18 +115,18 @@ #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)) @@ -146,7 +146,7 @@ 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)); + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); } else { MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); } @@ -157,7 +157,7 @@ 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)); + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); } else { MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); } @@ -183,11 +183,11 @@ void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE 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 @@ -204,29 +204,29 @@ class CapacitiveSensor // user-accessible "public" interface public: // methods - CapacitiveSensor(uint8_t sendPin, uint8_t receivePin1, uint8_t receivePin2); - unsigned int* sense(uint8_t samples); + 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; + 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; + 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); + int SenseOneCycle(void); }; #endif diff --git a/Firmware/OpeNITHM.ino b/Firmware/OpeNITHM.ino index 8328569..5cb57fc 100644 --- a/Firmware/OpeNITHM.ino +++ b/Firmware/OpeNITHM.ino @@ -1,5 +1,4 @@ #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32u4__) -#include "USBOutput.h" #define USB #endif @@ -8,9 +7,11 @@ #else #include "SerialOutput.h" #endif + #include "AirSensor.h" #include "Touchboard.h" #include +#include "PinConfig.h" CRGB leds[16]; @@ -26,216 +27,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()); + char 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()); + char 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()); + char 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(leds, 16); - FastLED.addLeds(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(); -} \ No newline at end of file + // 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(); + +} diff --git a/Firmware/Output.h b/Firmware/Output.h index 76cd6a5..1d05145 100644 --- a/Firmware/Output.h +++ b/Firmware/Output.h @@ -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); + virtual void sendKeyEvent(int key, bool pressed, bool doublePressed); + virtual void sendSensorEvent(float position); }; #endif - diff --git a/Firmware/PinConfig.h b/Firmware/PinConfig.h index e6ac858..6e73000 100644 --- a/Firmware/PinConfig.h +++ b/Firmware/PinConfig.h @@ -1,35 +1,39 @@ -#pragma once +#ifndef _PINCONFIG_h +#define _PINCONFIG_h -#define IR_SENSOR_MULTIPLEXED +//#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 diff --git a/Firmware/SerialOutput.cpp b/Firmware/SerialOutput.cpp index a1606f4..0752f2f 100644 --- a/Firmware/SerialOutput.cpp +++ b/Firmware/SerialOutput.cpp @@ -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); } diff --git a/Firmware/SerialOutput.h b/Firmware/SerialOutput.h index cdac7b7..84193bb 100644 --- a/Firmware/SerialOutput.h +++ b/Firmware/SerialOutput.h @@ -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(); + Packet builtPacket = Packet(); public: - void sendKeyEvent(int key, bool pressed, bool doublePressed) override; - void sendSensorEvent(float position) override; + void sendKeyEvent(int key, bool pressed, bool doublePressed) override; + void sendSensorEvent(float position) override; }; #endif - diff --git a/Firmware/Touchboard.cpp b/Firmware/Touchboard.cpp index efdd212..5aaff08 100644 --- a/Firmware/Touchboard.cpp +++ b/Firmware/Touchboard.cpp @@ -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(); } - diff --git a/Firmware/Touchboard.h b/Firmware/Touchboard.h index f2a5fff..83143e7 100644 --- a/Firmware/Touchboard.h +++ b/Firmware/Touchboard.h @@ -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 @@ -17,33 +11,31 @@ class Touchboard { private: - CapacitiveSensor sensor; + 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]; + 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 - diff --git a/Firmware/USBOutput.cpp b/Firmware/USBOutput.cpp index 572c423..1469f90 100644 --- a/Firmware/USBOutput.cpp +++ b/Firmware/USBOutput.cpp @@ -1,51 +1,51 @@ -#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; -} +#ifdef USB -#endif +#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 \ No newline at end of file diff --git a/Firmware/USBOutput.h b/Firmware/USBOutput.h index 1388954..3094419 100644 --- a/Firmware/USBOutput.h +++ b/Firmware/USBOutput.h @@ -1,28 +1,26 @@ -#define USBCON -#include - -// 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 + +class USBOutput : public Output +{ +private: + float lastPosition; +public: + void sendKeyEvent(int key, bool pressed, bool doublePressed) override; + void sendSensorEvent(float position) override; + USBOutput(); +}; + +#endif