#define Program_Name "OLED Menu"
#define Program_Version "v0.1"
#include <Wire.h>
#include "SSD1306AsciiWire.h"
#include "OneButton.h"
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
const int SDApin = 41;
const int SCLpin = 42;
const int DIO1 = 39;
const int soundPin = 38;
const int pinTrapA = 4;
const int pinTrapB = 5;
const int pinTrapC = 10;
const int pinTrapD = 11;
const int pinTrapE = -1;
const int pinTrapF = -1;
const int pinTrapG = -1;
const int pinTrapH = -1;
const int pinDblA = 6;
const int pinDblB = -1;
const int pinDblC = -1;
const int pinDblD = -1;
const int pinPgmA = 7;
const int pinPgmB = 8;
const int pinPgmC = -1;
uint8_t shot = 0xFF;
uint8_t shotA = 0xFF;
uint8_t shotB = 0xFF;
unsigned long idleDelayMs = 1000;
unsigned long resetDelayMs = 100;
unsigned long armingDelayMs = 500;
unsigned long manualArmingDelayMs = 100;
unsigned long delayArmingDelayMs = 1000;
unsigned long voiceArmingDelayMs = 100;
unsigned long fireDelayMs = 0;
unsigned long manualFireDelayMs = 0;
unsigned long delayFireDelayMs = 3000;
unsigned long voiceFireDelayMs = 100;
//Flag set by various trigger methods - then conditioned in the main function
volatile bool pullState = false;
volatile bool voicePull = false;
volatile bool manualPull = false;
SSD1306AsciiWire oled;
//Physical interface buttons
OneButton trapA = OneButton(pinTrapA, true, true);
OneButton trapB = OneButton(pinTrapB, true, true);
OneButton trapC = OneButton(pinTrapC, true, true);
OneButton trapD = OneButton(pinTrapD, true, true);
OneButton dblA = OneButton(pinDblA, true, true);
OneButton pgmA = OneButton(pinPgmA, true, true);
OneButton pgmB = OneButton(pinPgmB, true, true);
//Non-human interfaces treated as buttons
OneButton ifDIO1 = OneButton(DIO1, false, false);
enum deviceState : uint8_t {
IDLE,
READY,
ARMED,
FIRE_DELAY,
FIRING,
FIRED,
RESET_DELAY,
PROGRAM_MODE
};
enum shotMode : uint8_t {
TARGET,
SPORTING,
SKEET_AM
};
enum resetMode : uint8_t {
ONESHOT,
REPEAT
};
enum pairMode : uint8_t {
SINGLE,
TRUE,
REPORT,
FOLLOWING
};
enum triggerMode : uint8_t {
MANUAL,
VOICE,
DELAY
};
deviceState currState = deviceState::IDLE;
shotMode currShotMode = shotMode::TARGET;
resetMode currResetMode = resetMode::ONESHOT;
pairMode currPairMode = pairMode::SINGLE;
triggerMode currTriggerMode = triggerMode::MANUAL;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32-S3!");
Wire.begin(SDApin, SCLpin, I2C_ADDRESS);
//Wire.setClock(400000L);
Wire.setClock(3400000L);
#if RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0
pinMode(soundPin, INPUT); //This needs to be debounced sub-milisecond so OneButton cannot be used
oled.setFont(System5x7);
oled.clear();
displayHeader();
setupInputs();
}
void loop() {
btnHandle(); //Read button states & trigger callbacks
setShots(); //set/reset shot variable
setPullState();
displayState(); //Update the display for our current modedeviceState
displayMode(); //draw the shotmode section of the screen
fsm(); //FSM - running deviceState
delay(10); // this speeds up the simulation
}
void fsm() {
static unsigned long fsmMillis = millis();
//static unsigned long armMillis = millis();
//static unsigned long fireDelay = millis();
switch (currState) {
case (deviceState::IDLE):
if (millis() - fsmMillis > idleDelayMs) {
currState = deviceState::READY;
fsmMillis = millis();
}
break;
case (deviceState::READY):
if (shot != 0xFF ) {
currState = deviceState::ARMED;
fsmMillis = millis();
}
break;
case deviceState::ARMED:
if (shot != 0xFF && pullState) {
currState = deviceState::FIRE_DELAY;
fsmMillis = millis();
}
else if (shot == 0xFF) {
currState = deviceState::READY;
fsmMillis = millis();
}
break; //end of deviceState::ARMED
case (deviceState::FIRE_DELAY):
if (millis() - fsmMillis >= fireDelayMs) {
currState = deviceState::FIRING;
fsmMillis = millis();
}
break;
case (deviceState::FIRING):
sendPacket();
currState = deviceState::FIRED;
fsmMillis = millis();
break;
case (deviceState::FIRED):
currState = deviceState::RESET_DELAY;
fsmMillis = millis();
break;
case (deviceState::RESET_DELAY):
if (millis() - fsmMillis >= resetDelayMs) {
switch (currResetMode) {
case (resetMode::ONESHOT):
currState = deviceState::READY;
fsmMillis = millis();
break;
case (resetMode::REPEAT):
currState = deviceState::ARMED;
fsmMillis = millis();
break;
default:
Serial.println("'Default' Switch Case reached - fsm() deviceState::FIRED");
break;
} //end of switch (currREsetMode)
}
break; //end of case (deviceState::RESET_DELAY):
default:
break;
} //end of switch (currState):
}
void setShots() { //set shots based on mode(s) and shotA/B values
static int pairCnt = 0;
switch (currShotMode) {
case (shotMode::TARGET):
if (currState == deviceState::ARMED || currState == deviceState::READY) {
shot = shotA;
}
else if (currState == deviceState::FIRED) {
resetShots();
setPullState();
}
break; //end of case shotMode::TARGET
case (shotMode::SPORTING):
switch (currPairMode){
case (pairMode::SINGLE):
if (currState == deviceState::ARMED || currState == deviceState::READY) {
shot = shotA;
}
else if (currState == deviceState::FIRED) {
resetShots();
setPullState();
}
break;
case (pairMode::TRUE):
if (currState == deviceState::ARMED || currState == deviceState::READY) {
shot = shotA & shotB;
}
else if (currState == deviceState::FIRED) {
resetShots();
setPullState();
}
break;
case (pairMode::REPORT):
if (currState == deviceState::ARMED || currState == deviceState::READY) {
if (pairCnt == 0) {
shot = shotA;
}
else if (pairCnt == 1) {
shot = shotB;
}
}
else if (currState == deviceState::FIRED) {
if (pairCnt == 0) {
voicePull = false;
resetShots();
setPullState();
pairCnt = 1;
}
else if (pairCnt == 1) {
voicePull = false;
resetShots();
setPullState();
pairCnt = 0;
}
}
break;
case (pairMode::FOLLOWING):
shot = shotA;
break;
default:
break;
}
break; //end of case shotMode::SPORTING
default:
break;
} //end of switch(currShotMode)
}
void resetShots() { //reset shots to starting value (low active switches)
if (currResetMode == resetMode::ONESHOT) {
shot = 0xFF;
shotA = 0xFF;
shotB = 0xFF;
Serial.println("resetShots(); resetMode::ONESHOT");
}
else if (currResetMode == resetMode::REPEAT) {
shot = 0xFF;
Serial.println("resetShots(); resetMode::REPEAT");
}
}
void setPullState() {
if (shot == 0xFF) {
pullState = false;
voicePull = false;
manualPull = false;
}
switch (currShotMode) {
case (shotMode::TARGET):
switch (currTriggerMode) {
case (triggerMode::MANUAL):
if (shot != 0xFF) {
pullState = true;
}
break;
case (triggerMode::DELAY):
if (shot != 0xFF) {
pullState = true;
}
break;
case (triggerMode::VOICE):
if (shot != 0xFF) {
pullState = voicePull;
}
break;
default:
break;
}
break;
case (shotMode::SPORTING):
switch (currTriggerMode) {
case (triggerMode::MANUAL):
if (shot != 0xFF) {
pullState = manualPull;
}
break;
case (triggerMode::DELAY):
if (shot != 0xFF) {
pullState = manualPull;
}
break;
case (triggerMode::VOICE):
if (shot != 0xFF) {
pullState = voicePull;
}
break;
default:
break;
}
break;
default:
Serial.println("Default case Error - setPullState / shotMode");
break;
}
}
void displayHeader() {
oled.clear(0,oled.displayWidth(),0,0);
oled.print(Program_Name);
oled.print(" ");
oled.print(Program_Version);
}
void displayClear() {
oled.clear(0,oled.displayWidth(),2,7);
}
void displayState() {
static uint8_t prevState = 0;
static uint8_t rowNum = 1;
if (currState != prevState) {
//displayClear();
oled.setCursor(0,rowNum);
oled.clearToEOL();
oled.setCursor(leftTextPos(2),rowNum);
oled.print("---");
oled.setCursor(rightTextPos(5), rowNum);
oled.print("---");
switch (currState) {
case deviceState::IDLE:
oled.setCursor(centerTextPos(4), rowNum);
oled.print("IDLE");
break;
case deviceState::READY:
oled.setCursor(centerTextPos(5), rowNum);
oled.print("READY");
break;
case deviceState::ARMED:
oled.setCursor(centerTextPos(5), rowNum);
oled.print("ARMED");
break;
case deviceState::FIRE_DELAY:
oled.setCursor(centerTextPos(10), rowNum);
oled.print("FIRE DELAY");
break;
case deviceState::FIRING:
oled.setCursor(centerTextPos(6), rowNum);
oled.print("FIRING");
break;
case deviceState::FIRED:
oled.setCursor(centerTextPos(5), rowNum);
oled.print("FIRED");
break;
case deviceState::RESET_DELAY:
oled.setCursor(centerTextPos(9), rowNum);
oled.print("RESETTING");
break;
case deviceState::PROGRAM_MODE:
oled.setCursor(centerTextPos(8), rowNum);
oled.print("PGM MODE");
break;
default:
Serial.println("'Default' Switch Case reached - displayState()");
break;
}
prevState = currState;
}
}
uint8_t centerTextPos (uint8_t numChars) {
static uint8_t cursorPos = 0;
cursorPos = (oled.displayWidth() / 2) - (oled.fieldWidth(numChars)/2);
return cursorPos;
}
uint8_t leftTextPos (uint8_t numChars) {
static uint8_t cursorPos = 0;
cursorPos = oled.fieldWidth(numChars);
return cursorPos;
}
uint8_t rightTextPos (uint8_t numChars) {
static uint8_t cursorPos = 0;
cursorPos = oled.displayWidth() - oled.fieldWidth(numChars);
return cursorPos;
}
uint8_t leftOfCenterTextPos (uint8_t numChars) {
static uint8_t cursorPos = 0;
cursorPos = (oled.displayWidth()/2) - (oled.fieldWidth(numChars+1) );
return cursorPos;
}
uint8_t rightOfCenterTextPos (uint8_t numChars) {
static uint8_t cursorPos = 0;
cursorPos = (oled.displayWidth()/2) + (oled.fieldWidth(1));
return cursorPos;
}
void leftOfCenterTextClear (uint8_t rowNum) {
oled.clear(0,(oled.displayWidth()/2) - oled.fieldWidth(1)/2,rowNum, rowNum);
}
void rightOfCenterTextClear (uint8_t rowNum) {
oled.clear((oled.displayWidth()/2) + oled.fieldWidth(1)/2, oled.displayWidth(), rowNum, rowNum);
}
void clearTextRow (uint8_t rowNum) {
oled.clear(0,oled.displayWidth(), rowNum, rowNum);
}
void displayMode() {
static uint8_t prevState = 0xFF;
static uint8_t prevShotMode = 0xFF;
static uint8_t prevResetMode = 0xFF;
static uint8_t prevTriggerMode = 0xFF;
static uint8_t prevPairMode = 0xFF;
static uint8_t prevShot = 0x00;
static uint8_t prevShotA = 0x00;
static uint8_t prevShotB = 0x00;
static uint16_t isChanged = 0x0000;
if (currState != prevState)
{bitSet(isChanged, 0);}
if (currShotMode != prevShotMode)
{bitSet(isChanged, 1);}
if (currResetMode != prevResetMode)
{bitSet(isChanged, 2);}
if (currTriggerMode != prevTriggerMode)
{bitSet(isChanged, 3);}
if (currPairMode != prevPairMode)
{bitSet(isChanged, 4);}
if (shot != prevShot)
{bitSet(isChanged, 5);}
if (shotA != prevShotA)
{bitSet(isChanged, 6);}
if (shotB != prevShotB)
{bitSet(isChanged, 7);}
if (isChanged != 0x0000) {
//displayClear();
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
displayModeSeparator();
if (bitRead(isChanged,1) == 1) {displayShotMode(2);}
if (bitRead(isChanged,2) == 1) {displayResetMode(2);}
if (bitRead(isChanged,3) == 1) {displayTriggerMode(3);}
if (bitRead(isChanged,4) == 1) {displayPairMode(3);}
if (bitRead(isChanged,5) == 1) {displayShotHeader(5);}
if (bitRead(isChanged,6) == 1) {displayShot1(6);}
if (bitRead(isChanged,7) == 1) {displayShot2(7);}
prevState = currState;
prevShotMode = currShotMode;
prevResetMode = currResetMode;
prevTriggerMode = currTriggerMode;
prevPairMode = currPairMode;
prevShot = shot;
prevShotA = shotA;
prevShotB = shotB;
isChanged = 0x000;
}
}
}
void displayModeSeparator() {
for (int row = 2; row < 5; row++) {
oled.setCursor(centerTextPos(1),row);
oled.print("-");
}
}
void displayShotMode(uint8_t rowNum) {
String modeText = shotModeText();
leftOfCenterTextClear(rowNum);
oled.setCursor(leftOfCenterTextPos(modeText.length()),rowNum);
oled.print(modeText);
}
void displayResetMode(uint8_t rowNum) {
String modeText = resetModeText();
rightOfCenterTextClear(rowNum);
oled.setCursor(rightOfCenterTextPos(modeText.length()),rowNum);
oled.print(modeText);
}
void displayTriggerMode(uint8_t rowNum) {
String modeText = triggerModeText();
leftOfCenterTextClear(rowNum);
oled.setCursor(leftOfCenterTextPos(modeText.length()),rowNum);
oled.print(modeText);
}
void displayPairMode(uint8_t rowNum) {
String modeText = pairModeText();
rightOfCenterTextClear(rowNum);
oled.setCursor(rightOfCenterTextPos(modeText.length()),rowNum);
oled.print(modeText);
}
void displayShotHeader(uint8_t rowNum) {
oled.setCursor(centerTextPos(15),rowNum);
oled.print("A B C D E F G H");
}
void displayShot1(uint8_t rowNum) {
clearTextRow(rowNum);
oled.setCursor(centerTextPos(15),rowNum);
for (int i=0; i<8; i++) {
if(bitRead(shotA, i) == 0) {
oled.print("X ");
}
else {
oled.print(" ");
}
}
}
void displayShot2(uint8_t rowNum) {
clearTextRow(rowNum);
oled.setCursor(centerTextPos(15),rowNum);
for (int i=0; i<8; i++) {
if(bitRead(shotB, i) == 0) {
oled.print("X ");
}
else {
oled.print(" ");
}
}
}
String shotModeText () {
static String modeText = "";
switch (currShotMode) {
case (shotMode::TARGET):
modeText = "TARGET";
break;
case (shotMode::SPORTING):
modeText = "SPORTING";
break;
case (shotMode::SKEET_AM):
modeText = "USA SKEET";
break;
default:
break;
}
return modeText;
}
String resetModeText () {
static String modeText = "";
switch (currResetMode) {
case (resetMode::ONESHOT):
modeText = "ONE SHOT";
break;
case (resetMode::REPEAT):
modeText = "REPEAT";
break;
default:
Serial.println("'Default' Switch Case reached - resetModeText()");
break;
}
return modeText;
}
String triggerModeText () {
static String modeText = "";
switch (currTriggerMode) {
case (triggerMode::MANUAL):
modeText = "MANUAL";
break;
case (triggerMode::DELAY):
modeText = "DELAY";
break;
case (triggerMode::VOICE):
modeText = "VOICE";
break;
default:
break;
}
return modeText;
}
String pairModeText () {
static String modeText = "";
switch (currPairMode) {
case (pairMode::SINGLE):
modeText = "SINGLE";
break;
case (pairMode::TRUE):
modeText = "TRUE";
break;
case (pairMode::REPORT):
modeText = "REPORT";
break;
case (pairMode::FOLLOWING):
modeText = "FOLLOW";
break;
default:
modeText = "";
break;
}
return modeText;
}
void sendPacket() {
Serial.print("Packet Tx: ");
for (int i=0; i<8; i++) {
if(bitRead(shot, i) == 0) {
Serial.print("X");
}
else {
Serial.print("-");
}
}
Serial.println();
//shot = 0xFF;
}
void rxPacket() {
//if (currState == deviceState::FIRED || currState == deviceState::ARMING_DELAY || currState == deviceState::ARMED) {
Serial.println("ACK");
// }
}
/*
* Trap Buttons
*/
void trapAClick() {
static uint8_t switchBit = 0;
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (currPairMode == pairMode::SINGLE) {
if (shotA != 0xFF) {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
else if (bitRead(shotA, switchBit) == 0) {
shotA = 0xFF;
bitSet(shotA, switchBit);
}
else {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
}
if (currPairMode != pairMode::SINGLE) {
if (shotA != 0xFF && shotB != 0xFF) {
shotA = 0xFF;
shotB = 0xFF;
bitClear(shotA,switchBit);
}
else if (shotA != 0xFF) {
bitClear(shotB,switchBit);
}
else if (shotB != 0xFF) {
bitClear(shotA,switchBit);
}
else if (shotA == 0xFF && shotB == 0xFF) {
bitClear(shotA,switchBit);
}
}
}
Serial.println("trapAClick");
debugShots();
}
void trapBClick() {
static uint8_t switchBit = 1;
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (currPairMode == pairMode::SINGLE) {
if (shotA != 0xFF) {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
else if (bitRead(shotA, switchBit) == 0) {
shotA = 0xFF;
bitSet(shotA, switchBit);
}
else {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
}
if (currPairMode != pairMode::SINGLE) {
if (shotA != 0xFF && shotB != 0xFF) {
shotA = 0xFF;
shotB = 0xFF;
bitClear(shotA,switchBit);
}
else if (shotA != 0xFF) {
bitClear(shotB,switchBit);
}
else if (shotB != 0xFF) {
bitClear(shotA,switchBit);
}
else if (shotA == 0xFF && shotB == 0xFF) {
bitClear(shotA,switchBit);
}
}
}
Serial.println("trapBClick");
debugShots();
}
void trapCClick() {
static uint8_t switchBit = 2;
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (currPairMode == pairMode::SINGLE) {
if (shotA != 0xFF) {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
else if (bitRead(shotA, switchBit) == 0) {
shotA = 0xFF;
bitSet(shotA, switchBit);
}
else {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
}
if (currPairMode != pairMode::SINGLE) {
if (shotA != 0xFF && shotB != 0xFF) {
shotA = 0xFF;
shotB = 0xFF;
bitClear(shotA,switchBit);
}
else if (shotA != 0xFF) {
bitClear(shotB,switchBit);
}
else if (shotB != 0xFF) {
bitClear(shotA,switchBit);
}
else if (shotA == 0xFF && shotB == 0xFF) {
bitClear(shotA,switchBit);
}
}
}
Serial.println("trapCClick");
debugShots();
}
void trapDClick() {
static uint8_t switchBit = 3;
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (currPairMode == pairMode::SINGLE) {
if (shotA != 0xFF) {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
else if (bitRead(shotA, switchBit) == 0) {
shotA = 0xFF;
bitSet(shotA, switchBit);
}
else {
shotA = 0xFF;
bitClear(shotA,switchBit);
}
}
if (currPairMode != pairMode::SINGLE) {
if (shotA != 0xFF && shotB != 0xFF) {
shotA = 0xFF;
shotB = 0xFF;
bitClear(shotA,switchBit);
}
else if (shotA != 0xFF) {
bitClear(shotB,switchBit);
}
else if (shotB != 0xFF) {
bitClear(shotA,switchBit);
}
else if (shotA == 0xFF && shotB == 0xFF) {
bitClear(shotA,switchBit);
}
}
}
Serial.println("trapDClick");
debugShots();
}
void dblAClick() {
if (currShotMode == shotMode::TARGET) {
if (currState == deviceState::READY || currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (shotA == 0xFF) {
bitClear(shotA,0);
bitClear(shotA,1);
}
else if (bitRead(shotA,0) == 0 && bitRead(shotA,1) == 0) {
shotA = 0xFF;
}
else if (bitRead(shotA,0) == 0 || bitRead(shotA,1) == 0) {
shotA = 0xFF;
bitClear(shotA,0);
bitClear(shotA,1);
}
else if (bitRead(shotA,0) == 1 && bitRead(shotA,1) == 1) {
shotA = 0xFF;
}
}
}
if (currShotMode == shotMode::SPORTING) {
if (currTriggerMode == triggerMode::MANUAL || currTriggerMode == triggerMode::DELAY) {
manualPull = true;
}
}
}
/*
* Control Button handlers
*/
void dblADoubleClick() { //change currPairMode
if (currShotMode == shotMode::SPORTING) {
switch (currPairMode) {
case pairMode::SINGLE:
currPairMode = pairMode::TRUE;
break;
case pairMode::TRUE:
if (currTriggerMode == triggerMode::VOICE) {
currPairMode = pairMode::REPORT;
}
else {
currPairMode = pairMode::FOLLOWING;
}
break;
case pairMode::REPORT:
currPairMode = pairMode::FOLLOWING;
break;
case pairMode::FOLLOWING:
currPairMode = pairMode::SINGLE;
break;
default:
Serial.println("'Default' Switch Case reached - dblAClick()");
break;
}
shot = 0xFF;
shotA = 0xFF;
shotB = 0xFF;
}
}
void dblALongPress() { //Clear current shot setup
if (currState == deviceState::ARMED || currState == deviceState::FIRE_DELAY) {
if (currShotMode == shotMode::TARGET || currShotMode == shotMode::SPORTING) {
shot = 0xFF;
shotA = 0xFF;
shotB = 0xFF;
}
}
}
void pgmAClick() { //Change fireDelayMs
static unsigned long delayMs = fireDelayMs;
delayMs = fireDelayMs;
switch (delayMs) {
case 0:
delayMs = 100;
break;
case 100:
delayMs = 200;
break;
case 200:
delayMs = 300;
break;
case 300:
delayMs = 500;
break;
case 500:
delayMs = 1000;
break;
case 1000:
delayMs = 1500;
break;
case 1500:
delayMs = 2000;
break;
case 2000:
delayMs = 3000;
break;
case 3000:
delayMs = 4000;
break;
case 4000:
delayMs = 5000;
break;
case 5000:
delayMs = 6000;
break;
case 6000:
delayMs = 0;
break;
default:
delayMs = 1000;
break;
}
switch (currTriggerMode) {
case (triggerMode::MANUAL):
manualFireDelayMs = delayMs;
break;
case (triggerMode::DELAY):
delayFireDelayMs = delayMs;
break;
case (triggerMode::VOICE):
voiceFireDelayMs = delayMs;
break;
default:
break;
}
fireDelayMs = delayMs;
}
void pgmADoubleClick() { //currTriggerMode & default resetMode/pairMode/fireDelayMs
switch (currTriggerMode) {
case (triggerMode::MANUAL):
currTriggerMode = triggerMode::DELAY;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
fireDelayMs = delayFireDelayMs;
break;
case (triggerMode::DELAY):
currTriggerMode = triggerMode::VOICE;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
fireDelayMs = voiceFireDelayMs;
break;
case (triggerMode::VOICE):
currTriggerMode = triggerMode::MANUAL;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
fireDelayMs = manualFireDelayMs;
break;
default:
break;
}
shot = 0xFF;
shotA = 0xFF;
shotB = 0xFF;
}
void pgmALongPress () { //currState in/out of deviceState::PGM_MODE
switch (currState) {
case deviceState::PROGRAM_MODE:
currState = deviceState::IDLE;
break;
case deviceState::READY:
currState = deviceState::PROGRAM_MODE;
break;
case deviceState::ARMED:
currState = deviceState::PROGRAM_MODE;
break;
case deviceState::IDLE:
currState = deviceState::PROGRAM_MODE;
break;
default:
Serial.println("'Default' Switch Case reached - pgmBLongPress()");
break;
}
}
void pgmBClick() {
}
void pgmBDoubleClick() { //currResetMode
switch (currShotMode) {
case (shotMode::TARGET): //In TARGET mode - ONESHOT reset, unless we are in VOICE trigger
if (currTriggerMode == triggerMode::VOICE) {
switch (currResetMode) {
case resetMode::ONESHOT:
currResetMode = resetMode::REPEAT;
break;
case resetMode::REPEAT:
currResetMode = resetMode::ONESHOT;
break;
default:
Serial.println("'Default' Switch Case reached - pgmBDoubleClick() - shotMode::TARGET");
break;
}
}
else {
currResetMode = resetMode::ONESHOT;
}
break;
case (shotMode::SPORTING): //In Sporting Mode - all resetMode allowed
switch (currResetMode) {
case resetMode::ONESHOT:
currResetMode = resetMode::REPEAT;
break;
case resetMode::REPEAT:
currResetMode = resetMode::ONESHOT;
break;
default:
Serial.println("'Default' Switch Case reached - pgmBDoubleClick() - shotMode::TARGET");
break;
}
break;
case (shotMode::SKEET_AM): //In SKEET_AM Mode - ONESHOT only as the sequence is handled differently
currResetMode = resetMode::ONESHOT;
break;
default:
Serial.println("'Default' Switch Case reached - pgmBDoubleClick()");
break;
}
}
void pgmBLongPress () { //change shotMode
switch (currShotMode) {
case shotMode::TARGET:
currShotMode = shotMode::SPORTING;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
break;
case shotMode::SPORTING:
currShotMode = shotMode::TARGET;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
break;
//To be addressed later
case shotMode::SKEET_AM:
currShotMode = shotMode::TARGET;
currResetMode = resetMode::ONESHOT;
currPairMode = pairMode::SINGLE;
break;
default:
Serial.println("'Default' Switch Case reached - pgmBLongPress()");
break;
}
shot = 0xFF;
}
void soundClick() {
if (currTriggerMode == triggerMode::VOICE) {
switch (currState) {
case (deviceState::ARMED):
voicePull = true;
Serial.println("PULL! deviceState::ARMED");
break;
case (deviceState::FIRE_DELAY):
voicePull = true;
Serial.println("PULL! deviceState::FIRE_DELAY)");
break;
default:
break;
}
}
}
void checkSound() {
static int buttonState = 1;
static int lastButtonState = 0;
static int currentButtonState = 0;
static unsigned long lastDebounceTime = 0;
static unsigned long debounceDelay = 250; // ~400 Works for a puuuull - but not closing the bolt
currentButtonState = digitalRead(soundPin);
if (currentButtonState != lastButtonState) {
lastDebounceTime = micros();
}
if ((micros() - lastDebounceTime) > debounceDelay) {
if (currentButtonState != buttonState) {
buttonState = currentButtonState;
if (buttonState == LOW) {
soundClick();
}
}
}
lastButtonState = currentButtonState;
}
void btnHandle() {
trapA.tick();
trapB.tick();
trapC.tick();
trapD.tick();
dblA.tick();
pgmA.tick();
pgmB.tick();
ifDIO1.tick();
checkSound(); //not a OneButton tick() - but our own micros() based debounce & call to soundClick()
}
void setupInputs() {
trapA.attachClick(trapAClick);
trapB.attachClick(trapBClick);
trapC.attachClick(trapCClick);
trapD.attachClick(trapDClick);
dblA.attachClick(dblAClick);
//Control Buttons
dblA.attachDoubleClick(dblADoubleClick);
dblA.attachLongPressStop(dblALongPress);
pgmA.attachClick(pgmAClick);
pgmA.attachDoubleClick(pgmADoubleClick);
pgmA.attachLongPressStop(pgmALongPress);
pgmB.attachClick(pgmBClick);
pgmB.attachLongPressStop(pgmBLongPress);
pgmB.attachDoubleClick(pgmBDoubleClick);
//Radio
ifDIO1.attachClick(rxPacket);
}
void debugShots() {
/*
Serial.print("shotA: ");
Serial.print(shotA);
Serial.print(" shotB: ");
Serial.print(shotB);
Serial.print(" shot: ");
Serial.println(shot);
*/
}