#include "HECB.h" #include // RadioHead library #include // Required for RadioHead, though not used directly RH_ASK rf_driver(4000, RF_PORTD, RF_PORTD); // 2000 bps, DATA pin on 17 /*** INPUTS ***/ #define SENS_F_O IN_1 #define SENS_F_C IN_2 #define SENS_R_O IN_3 #define SENS_R_C IN_4 const int8_t SENSORS[] = {SENS_F_O, SENS_F_C, SENS_R_O, SENS_R_C}; #define NUM_SENSORS 4 #define SENSOR_DEBOUNCE_DELAY 20 bool lastSensorStates[NUM_SENSORS] = {HIGH, HIGH, HIGH, HIGH}; bool currentSensorStates[NUM_SENSORS] = {HIGH, HIGH, HIGH, HIGH}; bool sensorFallingEdges[NUM_SENSORS] = {false, false, false, false}; uint32_t lastSensorDebounceTimes[NUM_SENSORS] = {0, 0, 0, 0}; void checkSensors() { //Serial.print(' '); for (uint8_t i = 0; i < NUM_SENSORS; i++) { bool reading = digitalRead(SENSORS[i]); if (reading != lastSensorStates[i]) { lastSensorDebounceTimes[i] = millis(); } if ((millis() - lastSensorDebounceTimes[i]) > SENSOR_DEBOUNCE_DELAY) { if (reading != currentSensorStates[i]) { currentSensorStates[i] = reading; } } lastSensorStates[i] = reading; //Serial.print(currentSensorStates[i] ? '-':'T'); } //Serial.print(' '); } bool checkSensor(int8_t ch) { return !currentSensorStates[ch-1]; } //#define REPEAT_INTERVAL 100 #define NUM_BUTTONS 5 #define DEBOUNCE_DELAY 100 const uint8_t BUTTON_PINS[NUM_BUTTONS] = {BTN1, BTN2, BTN3, BTN4, BTN5}; bool lastButtonStates[NUM_BUTTONS] = {HIGH, HIGH, HIGH, HIGH, HIGH}; bool currentButtonStates[NUM_BUTTONS] = {HIGH, HIGH, HIGH, HIGH, HIGH}; bool buttonFallingEdges[NUM_BUTTONS] = {false, false, false, false, false}; uint32_t lastDebounceTimes[NUM_BUTTONS] = {0, 0, 0, 0, 0}; uint32_t lastRepeatTimes[NUM_BUTTONS] = {0, 0, 0, 0, 0}; void checkButtons() { for (uint8_t i = 0; i < NUM_BUTTONS; i++) { bool reading = digitalRead(BUTTON_PINS[i]); if (reading != lastButtonStates[i]) { lastDebounceTimes[i] = millis(); } if ((millis() - lastDebounceTimes[i]) > DEBOUNCE_DELAY) { if (reading != currentButtonStates[i]) { currentButtonStates[i] = reading; if (currentButtonStates[i] == LOW) { buttonFallingEdges[i] = true; } } } lastButtonStates[i] = reading; //Serial.print(currentButtonStates[i] ? '-':'T'); } //Serial.println(); } /*** OUTPUTS ***/ #define CMD_OFF 0 #define CMD_F_O 1 #define CMD_F_C 2 #define CMD_R_O 3 #define CMD_R_C 4 int8_t lastcmd = 0; int8_t currentcmd = 0; uint32_t lastt = 0; #define SWITCH_COOLDOWN 300 void setOutputsRaw(int8_t cmd) { if (cmd == CMD_OFF) { digitalWrite(RELAY_2A, LOW); digitalWrite(RELAY_2B, LOW); digitalWrite(RELAY_3A, LOW); digitalWrite(RELAY_3B, LOW); } else { digitalWrite(RELAY_2A, (cmd == CMD_F_O || cmd == CMD_R_O) ? HIGH : LOW); digitalWrite(RELAY_2B, (cmd == CMD_F_C || cmd == CMD_R_C) ? HIGH : LOW); digitalWrite(RELAY_3A, (cmd == CMD_R_O || cmd == CMD_R_C) ? HIGH : LOW); digitalWrite(RELAY_3B, (cmd == CMD_F_O || cmd == CMD_F_C) ? HIGH : LOW); } } void setOutputs(int8_t cmd) { // if requesting to shut off if (cmd == CMD_OFF) { // go ahead and turn off currentcmd = CMD_OFF; } // if we're past cooldown if ((millis() - lastt) > SWITCH_COOLDOWN) { // accept new commands currentcmd = cmd; // if not past cooldown and trying a new command } else if (cmd != currentcmd) { // we shut down currentcmd = CMD_OFF; } // if we're not off if (currentcmd != CMD_OFF) { // reset cooldown timer lastt = millis(); } //Serial.print("CMD_"); //Serial.print(currentcmd); //Serial.print(" "); setOutputsRaw(currentcmd); } /*** FSM ***/ uint32_t timer; int8_t channel; int8_t state; #define STATE_OFF 0 #define STATE_JOG 1 #define STATE_RUN 2 #define JOG_DEBOUNCE 160 // handle state transitions void changeState(int8_t newState, int8_t newChannel=0) { switch(newState) { case STATE_JOG: timer = millis() + JOG_DEBOUNCE; break; case STATE_RUN: if (state != newState || channel != newChannel) timer = millis() + ((channel%2) ? 9000 : 16000); break; case STATE_OFF: break; } if (state != newState || channel != newChannel) { Serial.print("STATE: "); Serial.print(newState); Serial.print(":"); Serial.print(newChannel); Serial.print(" "); Serial.println(); } state = newState; channel = newChannel; } void runFSM() { // if any button is pressed, cancel any command, run the output manually. bool overridden = false; for (int8_t i=0; i<4; i++) { if (currentButtonStates[i]){ buttonFallingEdges[i] = false; continue; } if (!digitalRead(53)) { changeState(STATE_OFF); setOutputs(checkSensor(i+1) ? CMD_OFF:i+1); } else if (!digitalRead(51)) { if (buttonFallingEdges[i]) { if (state == STATE_RUN) { changeState(STATE_OFF); } else { changeState(STATE_RUN, i+1); } } } else { changeState(STATE_OFF); setOutputs(i+1); } buttonFallingEdges[i] = false; overridden = true; } //if (digitalRead(53) && digitalRead(51)) overridden = true; if (!overridden) { // check for automatic state transitions switch(state) { case STATE_JOG: if (millis() > timer) changeState(STATE_OFF); case STATE_RUN: if (millis() > timer) changeState(STATE_OFF); if (checkSensor(channel)) changeState(STATE_OFF); break; } // go to outputs switch(state) { case STATE_JOG: setOutputs(channel); break; case STATE_RUN: setOutputs(channel); break; case STATE_OFF: setOutputs(CMD_OFF); break; } } } /*#define NUM_CMDS 8 #define DEBOUNCE_RF 500 bool lastCmdStates[NUM_CMDS] = {LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; bool currentCmdStates[NUM_CMDS] = {LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; bool cmdRisingEdges[NUM_CMDS] = {0,0,0,0,0,0,0,0}; uint32_t lastCmdDebounceTimes[NUM_BUTTONS] = {0, 0, 0, 0, 0}; void checkButtons() { for (uint8_t i = 0; i < NUM_CMDS; i++) { if (reading != lastCmdStates[i]) { lastCmdDebounceTimes[i] = millis(); } if ((millis() - lastCmdDebounceTimes[i]) > DEBOUNCE_DELAY) { cmdRisingEdges[i] = false; if (reading != currentCmdStates[i]) { currentCmdStates[i] = reading; if (currentCmdStates[i]) { cmdRisingEdges[i] = true; } } } lastCmdStates[i] = reading; Serial.print(currentButtonStates[i] ? '-':'T'); } //Serial.println(); }*/ #define DEBOUNCE_RF 300 bool cmdFirstSeen[8] = {0,0,0,0,0,0,0,0}; uint32_t cmdValidTil[8] = {0,0,0,0,0,0,0,0}; //{-10000,-10000,-10000,-10000,-10000,-10000,-10000,-10000}; uint32_t cmdSeenThisScan[8] = {0,0,0,0,0,0,0,0}; //{-10000,-10000,-10000,-10000,-10000,-10000,-10000,-10000}; //bool currentCmdState[8] = {0,0,0,0,0,0,0,0}; //bool currentCmdState[8] = {0,0,0,0,0,0,0,0}; void checkRFTransmissions() { uint8_t buf[RH_ASK_MAX_MESSAGE_LEN]; // Buffer for incoming message uint8_t buflen = sizeof(buf); if (rf_driver.recv(buf, &buflen)) { // Check if a message is received buf[buflen] = '\0'; Serial.print("COMMAND: "); Serial.println((char*)buf); // check if command is correct length if (buflen != 7) return; // length if (buf[0]!='h') return; if (buf[1]!='e') return; if (buf[2]!='c') return; if (buf[3]!='b') return; if ((buf[4]+buf[5]) != buf[6]) return; // checksum if (buf[5] < 49 || buf[5] > 52) return; // valid channel if (buf[4] != 'J' && buf[4] != 'R') return; // valid command int8_t cmd_no = (buf[4] == 'J' ? 0:4) + buf[5]-49; if (cmdValidTil[cmd_no] < millis()) { cmdFirstSeen[cmd_no] = true; } cmdSeenThisScan[cmd_no] = true; cmdValidTil[cmd_no] = millis() + DEBOUNCE_RF; } for (uint8_t i=0;i<8;i++) { if (cmdSeenThisScan[i] && i<4) { changeState(STATE_JOG, i+1); } else if (cmdFirstSeen[i]) { if (state == STATE_RUN) { changeState(STATE_OFF); } else { changeState(STATE_RUN, i-4+1); } } cmdFirstSeen[i] = false; cmdSeenThisScan[i] = false; } /*if (buf[4] == 'J') changeState(STATE_JOG, buf[5]-48); if (buf[4] == 'R') { if (state == STATE_RUN) { if (channel == buf[5]-48) { if (lastTimeOfCmd[cmd_no] > lastTimeOfCmd+DEBOUNCE_RF) { changeState(STATE_OFF); } } else { changeState(STATE_OFF); } } else { if (lastTimeOfCmd[cmd_no] > lastTimeOfCmd+DEBOUNCE_RF) { changeState(STATE_RUN, buf[5]-48); lastTimeOfCmd[cmd_no] = millis(); } }*/ /*// if running if (state == STATE_RUN) { // if running and a different channel, just shut off if (channel != buf[5]-48){ changeState(STATE_OFF); // if running and the same channel, and we are past the time of the button being pressed } else if (millis() > rf_runt) { changeState(STATE_OFF); } else { changeState(STATE_RUN, buf[5]-48); rf_runt = millis() + DEBOUNCE_RF; } } else { changeState(STATE_RUN, buf[5]-48); rf_runt = millis() + DEBOUNCE_RF; }*/ //} //} } void setup() { Serial.begin(115200); Serial.println("Good Morning!"); if (!rf_driver.init()) { Serial.println("RF Receiver initialization failed!"); } setupHECB(); } void loop() { checkButtons(); checkSensors(); checkRFTransmissions(); runFSM(); // check if both traps are closed /*if(!checkSensor(CMD_F_C) || !checkSensor(CMD_R_C)) { digitalWrite(RELAY_4A, HIGH); } else { digitalWrite(RELAY_4A, LOW); }*/ //Serial.println("loop"); //Serial.println(); //delay(5); }