+++ /dev/null
-// Panik Web Form Demo
-
-#define SERIAL_DEBUG
-#define ENABLE_UDP
-
-
-// define network constants
-#define MAC_DAVID { 0x90, 0xA2, 0xDA, 0x0D, 0xF4, 0x63 }
-#define MAC_PANIK { 0x90, 0xA2, 0xDA, 0x00, 0x9A, 0x94 }
-#define MAC_PANIK2 { 0x90, 0xA2, 0xDA, 0x0E, 0xF3, 0x77 }
-#define MAC_ADDRESS MAC_PANIK2
-
-// include Arduino libraries
-#include <Wire.h>
-#include <SPI.h>
-#include <SD.h>
-#include <Ethernet.h>
-#ifdef ENABLE_UDP
-#include <EthernetUdp.h>
-#endif
-
-// include third party libraries
-#include "WebServer.h"
-
-// define SD and Ethernet select ports
-#define SD_SELECT 4
-#define ETHERNET_SELECT 10
-
-// define machine variables
-#define DEBOUNCE_TRESHOLD 10 // 10 milliseconds
-#define ABORT_TRESHOLD 3000L // 3 seconds
-#define PULSE_TRESHOLD 50 // 50 milliseconds
-#define BLINK_TRESHOLD 100 // 100 milliseconds
-
-// output pins
-#define RELAY_BUTTON_LEDS 5 // Button LED indicator
-#define RELAY_GREEN_LEDS 6 // ``Non-Stop`` LED indicator
-#define RELAY_RED_LEDS 8 // ``Studio 1`` LED indicator
-#define RELAY_YELLOW_LEDS 7 // ``Studio 2`` LED indicator
-
-#define RELAY_NONSTOP_OR_STUD 4 // Relay : Non-stop or Studio
-#define RELAY_STUD1_OR_STUD2 9 // Relay : Studio 1 or Studio 2
-
-// input pins
-#define BUTTON1 2 // ``Select`` button
-#define BUTTON2 3 // ``Confirm`` button
-#define NONSTOP_VIA_STUD1 14 // is nonstop coming out of studio 1
-#define NONSTOP_VIA_STUD2 15 // is nonstop coming out of studio 2
-
-/* status */
-#define NONSTOP 0
-#define STUDIO1 1
-#define STUDIO2 2
-
-
-/* relay positions */
-typedef enum { RELAY_STATE_OPEN, RELAY_STATE_CLOSED } relayState_t;
-
-
-/* define an array with led pins,
- indexes in that array correspond to the values of possible selections
- i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
-*/
-const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
-
-
-/* activeSelection is the variable that holds the active output of the switch
- it is declared as an attribute that keeps its value between arduino resets
-*/
-int activeSelection = NONSTOP;
-
-// variables and timers for blinking selection (selected but not confirmed)
-int blinkingSelection = NONSTOP;
-bool blinkingLedState = RELAY_STATE_CLOSED;
-unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
-
-
-// declaration of possible button states as enum type
-typedef enum { nochange, pressed, released } buttonEvent_t;
-
-// button event timers
-unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
-
-// variables holding the state of each button
-// these are used during the debouncing process
-uint8_t button1State = LOW, button2State = LOW;
-
-// variables holding the non-stop status from studios 1 & 2
-bool nonstop_via_stud1, nonstop_via_stud2;
-
-// declare functions
-buttonEvent_t debounce( const uint8_t buttonPin,
- uint8_t *buttonState,
- unsigned long *buttonLastEventTime );
-
-static uint8_t mac[] = MAC_ADDRESS;
-#define PREFIX ""
-
-// instanciate web server
-WebServer webserver(PREFIX, 80);
-
-#ifdef ENABLE_UDP
-// and EthernetUDP instance to send notifications
-EthernetUDP Udp;
-IPAddress udp_remote_ip(192, 168, 17, 224);
-#endif
-
-
-#define NAMELEN 4
-#define VALUELEN 4
-
-typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
-
-
-inline void notify_udp() // notify over UDP
-{
-#ifdef ENABLE_UDP
- char str_selection[20];
- snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
- #ifdef SERIAL_DEBUG
- Serial.println(F("Sending UDP... "));
- Serial.println(str_selection);
- #endif
- Udp.beginPacket(udp_remote_ip, 1312);
- Udp.write(str_selection);
- Udp.endPacket();
-#endif
-}
-
-// web resource
-void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
-{
-
- server.httpSuccess("application/json");
-
- if (type == WebServer::HEAD)
- return;
-
- responseStatus response_status = NO_POST;
-
- if (type == WebServer::POST)
- {
- char name[NAMELEN];
- int name_len;
- char value[VALUELEN];
- int value_len;
-
- response_status = POST_ERROR;
-
- while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
- {
- if (strcmp(name, "s") == 0) {
- digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
- blinkingSelection = atoi(value);
- activeSelection = atoi(value);
- response_status = POST_OK;
-
- notify_udp();
- }
- }
- }
-
- server.println(F("{"));
-
- server.print(" \"response\": ");
- server.print(response_status);
-
- server.print(",\n \"active\": ");
- server.print(activeSelection);
-
- server.print(",\n \"nonstop-via-stud1\": ");
- server.print(nonstop_via_stud1);
- server.print(",\n \"nonstop-via-stud2\": ");
- server.println(nonstop_via_stud2);
-
- server.println(F("}"));
-}
-
-
-// setup function
-void setup()
-{
- blinkingSelection = activeSelection = NONSTOP;
-
- // open serial communication for debugging
- Serial.begin(9600);
- Serial.println(F("Startup"));
-
- // disable SD and Ethernet ports before setup
- pinMode(SD_SELECT, OUTPUT);
- digitalWrite(SD_SELECT, HIGH); // disable SD card
- pinMode(ETHERNET_SELECT, OUTPUT);
- digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
-
- // start SPI (because Ethernet shield needs it)
- SPI.begin(); // start SPI
-
- // start Ethernet
- if (!(Ethernet.begin(mac) == 0)) // start network
- Serial.println(Ethernet.localIP());
- else
- {
- #ifdef SERIAL_DEBUG
- Serial.println(F("Network Error"));
- #endif
- while (1) ;
- }
- #ifdef ENABLE_UDP
- if (! Udp.begin(1312)) {
- #ifdef SERIAL_DEBUG
- Serial.println(F("Failed to initiate UDP"));
- #endif
- }
- #endif
-
- // set mode for used pins
- pinMode(RELAY_RED_LEDS, OUTPUT);
- digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
- pinMode(RELAY_YELLOW_LEDS, OUTPUT);
- digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
- pinMode(RELAY_GREEN_LEDS, OUTPUT);
- digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
- pinMode(RELAY_BUTTON_LEDS, OUTPUT);
- digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
-
- pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
- digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
- pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
- digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
-
- pinMode(BUTTON1, INPUT);
- pinMode(BUTTON2, INPUT);
- pinMode(NONSTOP_VIA_STUD1, INPUT);
- pinMode(NONSTOP_VIA_STUD2, INPUT);
-
- // configure web server pages
- webserver.setDefaultCommand(&webCmd);
-
- // start web server
- webserver.begin();
-}
-
-
-// loop function
-void loop()
-{
- // update variables indicating if non-stop is selected in studios 1&2
- nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
- if (nonstop_via_stud1 == 0)
- nonstop_via_stud1 = 1;
- else
- nonstop_via_stud1 = 0;
- nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
- if (nonstop_via_stud2 == 0)
- nonstop_via_stud2 = 1;
- else
- nonstop_via_stud2 = 0;
-
- // check if we have a HTTP request (and respond)
- webserver.processConnection();
-
- // handle button 1 (select button)
- switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
- {
- case nochange:
- break;
- case pressed:
- #ifdef SERIAL_DEBUG
- Serial.println(F("Button 1 pressed"));
- #endif
- digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
- blinkingSelection++;
- if (blinkingSelection > STUDIO2) {
- blinkingSelection = NONSTOP;
- }
- blinkingStartTime = millis(),
- blinkingAbortTime = millis();
- blinkingLedState = RELAY_STATE_OPEN;
- break;
- case released:
- #ifdef SERIAL_DEBUG
- Serial.println(F("Button 1 released"));
- #endif
- break;
- }
-
- // handle button 2 (confirm button)
- switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
- {
- case nochange:
- break;
- case pressed:
- #ifdef SERIAL_DEBUG
- Serial.println(F("Button 2 pressed"));
- #endif
- blinkingAbortTime = 0; // disable blinking auto abort
- break;
- case released:
- #ifdef SERIAL_DEBUG
- Serial.println(F("Button 2 released"));
- #endif
- if (activeSelection != blinkingSelection)
- {
- digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
- activeSelection = blinkingSelection; // relay states must be changed now
- #ifdef SERIAL_DEBUG
- Serial.print(F("Active Selection: "));
- Serial.println(activeSelection);
- #endif
- notify_udp();
- break;
- }
- }
-
- // handle auto abort for blinking led (if any)
- if ( (blinkingAbortTime != 0) &&
- ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
- digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
- blinkingAbortTime = 0;
- blinkingSelection = activeSelection;
- }
-
- // handle blinking led (if selected is not current state)
- if (activeSelection != blinkingSelection) {
- if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
- digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
- digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
- blinkingStartTime = millis();
- blinkingLedState = !blinkingLedState;
- }
- }
- else {
- digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
- }
-
- digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
-
- // update audio channel relays
- if (activeSelection == NONSTOP)
- {
- digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
- digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
- }
- else if (activeSelection == STUDIO1)
- {
- digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
- digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
- }
- else if (activeSelection == STUDIO2)
- {
- digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
- digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
- }
-}
-
-buttonEvent_t debounce( const uint8_t buttonPin,
- uint8_t *buttonState,
- unsigned long *buttonLastEventTime )
-{
- uint8_t buttonLastState = *buttonState;
- uint8_t buttonReading = digitalRead(buttonPin);
-
- if ( (*buttonLastEventTime == 0) &&
- (*buttonState != buttonReading) ) {
- // something happened, start the debouncing process
- *buttonLastEventTime = millis();
- }
-
- if (*buttonLastEventTime != 0) {
- long buttonEventTimer = millis() - *buttonLastEventTime;
-
- if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
- (*buttonState == buttonReading) ) {
- // noise or bouncing, abort
- *buttonLastEventTime = 0;
- }
-
- if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
- (buttonReading != *buttonState) ) {
- // new button state was maintained
- *buttonLastEventTime = 0;
- *buttonState = buttonReading;
- }
- }
-
- // debouncing finished, return button state
- if (*buttonLastEventTime == 0) {
- // comparing buttonState and buttonLastState tells whether the
- // button is pressed or released
- if ( (*buttonState == HIGH) &&
- (buttonLastState == LOW) ) {
- // button just pressed
- buttonLastState = *buttonState;
- return pressed;
- }
- if ( (*buttonState == LOW) &&
- (buttonLastState == HIGH) ) {
- // button just released
- buttonLastState = *buttonState;
- return released;
- }
- }
- return nochange;
-}
--- /dev/null
+/*
+ * PanikSwitch
+ * Copyright (C) 2021-2021 Radio Panik
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define SERIAL_DEBUG
+#define ENABLE_UDP
+
+
+// define network constants
+#define MAC_DAVID { 0x90, 0xA2, 0xDA, 0x0D, 0xF4, 0x63 }
+#define MAC_PANIK { 0x90, 0xA2, 0xDA, 0x00, 0x9A, 0x94 }
+#define MAC_PANIK2 { 0x90, 0xA2, 0xDA, 0x0E, 0xF3, 0x77 }
+#define MAC_ADDRESS MAC_PANIK2
+
+// include Arduino libraries
+#include <Wire.h>
+#include <SPI.h>
+#include <Ethernet.h>
+#ifdef ENABLE_UDP
+#include <EthernetUdp.h>
+#endif
+
+// include third party libraries
+#include "WebServer.h"
+
+// define SD and Ethernet select ports
+#define SD_SELECT 4
+#define ETHERNET_SELECT 10
+
+// define machine variables
+#define DEBOUNCE_TRESHOLD 10 // 10 milliseconds
+#define ABORT_TRESHOLD 3000L // 3 seconds
+#define PULSE_TRESHOLD 50 // 50 milliseconds
+#define BLINK_TRESHOLD 100 // 100 milliseconds
+
+// output pins
+#define RELAY_BUTTON_LEDS 5 // Button LED indicator
+#define RELAY_GREEN_LEDS 6 // ``Non-Stop`` LED indicator
+#define RELAY_RED_LEDS 8 // ``Studio 1`` LED indicator
+#define RELAY_YELLOW_LEDS 7 // ``Studio 2`` LED indicator
+
+#define RELAY_NONSTOP_OR_STUD 4 // Relay : Non-stop or Studio
+#define RELAY_STUD1_OR_STUD2 9 // Relay : Studio 1 or Studio 2
+
+// input pins
+#define BUTTON1 2 // ``Select`` button
+#define BUTTON2 3 // ``Confirm`` button
+#define NONSTOP_VIA_STUD1 14 // is nonstop coming out of studio 1
+#define NONSTOP_VIA_STUD2 15 // is nonstop coming out of studio 2
+
+/* status */
+#define NONSTOP 0
+#define STUDIO1 1
+#define STUDIO2 2
+
+
+/* relay positions */
+typedef enum { RELAY_STATE_OPEN, RELAY_STATE_CLOSED } relayState_t;
+
+
+/* define an array with led pins,
+ indexes in that array correspond to the values of possible selections
+ i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
+*/
+const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
+
+
+/* activeSelection is the variable that holds the active output of the switch
+ it is declared as an attribute that keeps its value between arduino resets
+*/
+int activeSelection = NONSTOP;
+
+// variables and timers for blinking selection (selected but not confirmed)
+int blinkingSelection = NONSTOP;
+bool blinkingLedState = RELAY_STATE_CLOSED;
+unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
+
+
+// declaration of possible button states as enum type
+typedef enum { nochange, pressed, released } buttonEvent_t;
+
+// button event timers
+unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
+
+// variables holding the state of each button
+// these are used during the debouncing process
+uint8_t button1State = LOW, button2State = LOW;
+
+// variables holding the non-stop status from studios 1 & 2
+bool nonstop_via_stud1, nonstop_via_stud2;
+
+// declare functions
+buttonEvent_t debounce( const uint8_t buttonPin,
+ uint8_t *buttonState,
+ unsigned long *buttonLastEventTime );
+
+static uint8_t mac[] = MAC_ADDRESS;
+#define PREFIX ""
+
+// instanciate web server
+WebServer webserver(PREFIX, 80);
+
+#ifdef ENABLE_UDP
+// and EthernetUDP instance to send notifications
+EthernetUDP Udp;
+IPAddress udp_remote_ip(192, 168, 17, 246);
+#endif
+
+
+#define NAMELEN 4
+#define VALUELEN 4
+
+typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
+
+
+inline void notify_udp() // notify over UDP
+{
+#ifdef ENABLE_UDP
+ char str_selection[20];
+ snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Sending UDP... "));
+ Serial.println(str_selection);
+ #endif
+ Udp.beginPacket(udp_remote_ip, 1312);
+ Udp.write(str_selection);
+ Udp.endPacket();
+#endif
+}
+
+// web resource
+void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
+{
+
+ server.httpSuccess("application/json");
+
+ if (type == WebServer::HEAD)
+ return;
+
+ responseStatus response_status = NO_POST;
+
+ if (type == WebServer::POST)
+ {
+ char name[NAMELEN];
+ int name_len;
+ char value[VALUELEN];
+ int value_len;
+
+ response_status = POST_ERROR;
+
+ while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
+ {
+ if (strcmp(name, "s") == 0) {
+ digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
+ blinkingSelection = atoi(value);
+ activeSelection = atoi(value);
+ response_status = POST_OK;
+
+ notify_udp();
+ }
+ }
+ }
+
+ server.println(F("{"));
+
+ server.print(" \"response\": ");
+ server.print(response_status);
+
+ server.print(",\n \"active\": ");
+ server.print(activeSelection);
+
+ server.print(",\n \"nonstop-via-stud1\": ");
+ server.print(nonstop_via_stud1);
+ server.print(",\n \"nonstop-via-stud2\": ");
+ server.println(nonstop_via_stud2);
+
+ server.println(F("}"));
+}
+
+
+// setup function
+void setup()
+{
+ blinkingSelection = activeSelection = NONSTOP;
+
+ // open serial communication for debugging
+ Serial.begin(9600);
+ Serial.println(F("Startup"));
+
+ // disable SD and Ethernet ports before setup
+ pinMode(SD_SELECT, OUTPUT);
+ digitalWrite(SD_SELECT, HIGH); // disable SD card
+ pinMode(ETHERNET_SELECT, OUTPUT);
+ digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
+
+ // start SPI (because Ethernet shield needs it)
+ SPI.begin(); // start SPI
+
+ // start Ethernet
+ if (!(Ethernet.begin(mac) == 0)) // start network
+ Serial.println(Ethernet.localIP());
+ else
+ {
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Network Error"));
+ #endif
+ while (1) ;
+ }
+ #ifdef ENABLE_UDP
+ if (! Udp.begin(1312)) {
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Failed to initiate UDP"));
+ #endif
+ }
+ #endif
+
+ // set mode for used pins
+ pinMode(RELAY_RED_LEDS, OUTPUT);
+ digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
+ pinMode(RELAY_YELLOW_LEDS, OUTPUT);
+ digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
+ pinMode(RELAY_GREEN_LEDS, OUTPUT);
+ digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
+ pinMode(RELAY_BUTTON_LEDS, OUTPUT);
+ digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
+
+ pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
+ digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
+ pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
+ digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
+
+ pinMode(BUTTON1, INPUT);
+ pinMode(BUTTON2, INPUT);
+ pinMode(NONSTOP_VIA_STUD1, INPUT);
+ pinMode(NONSTOP_VIA_STUD2, INPUT);
+
+ // configure web server pages
+ webserver.setDefaultCommand(&webCmd);
+
+ // start web server
+ webserver.begin();
+}
+
+
+// loop function
+void loop()
+{
+ // update variables indicating if non-stop is selected in studios 1&2
+ nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
+ if (nonstop_via_stud1 == 0)
+ nonstop_via_stud1 = 1;
+ else
+ nonstop_via_stud1 = 0;
+ nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
+ if (nonstop_via_stud2 == 0)
+ nonstop_via_stud2 = 1;
+ else
+ nonstop_via_stud2 = 0;
+
+ // check if we have a HTTP request (and respond)
+ webserver.processConnection();
+
+ // handle button 1 (select button)
+ switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
+ {
+ case nochange:
+ break;
+ case pressed:
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Button 1 pressed"));
+ #endif
+ digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
+ blinkingSelection++;
+ if (blinkingSelection > STUDIO2) {
+ blinkingSelection = NONSTOP;
+ }
+ blinkingStartTime = millis(),
+ blinkingAbortTime = millis();
+ blinkingLedState = RELAY_STATE_OPEN;
+ break;
+ case released:
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Button 1 released"));
+ #endif
+ break;
+ }
+
+ // handle button 2 (confirm button)
+ switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
+ {
+ case nochange:
+ break;
+ case pressed:
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Button 2 pressed"));
+ #endif
+ blinkingAbortTime = 0; // disable blinking auto abort
+ break;
+ case released:
+ #ifdef SERIAL_DEBUG
+ Serial.println(F("Button 2 released"));
+ #endif
+ if (activeSelection != blinkingSelection)
+ {
+ digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
+ activeSelection = blinkingSelection; // relay states must be changed now
+ #ifdef SERIAL_DEBUG
+ Serial.print(F("Active Selection: "));
+ Serial.println(activeSelection);
+ #endif
+ notify_udp();
+ break;
+ }
+ }
+
+ // handle auto abort for blinking led (if any)
+ if ( (blinkingAbortTime != 0) &&
+ ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
+ digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
+ blinkingAbortTime = 0;
+ blinkingSelection = activeSelection;
+ }
+
+ // handle blinking led (if selected is not current state)
+ if (activeSelection != blinkingSelection) {
+ if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
+ digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
+ digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
+ blinkingStartTime = millis();
+ blinkingLedState = !blinkingLedState;
+ }
+ }
+ else {
+ digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
+ }
+
+ digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
+
+ // update audio channel relays
+ if (activeSelection == NONSTOP)
+ {
+ digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
+ digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
+ }
+ else if (activeSelection == STUDIO1)
+ {
+ digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
+ digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
+ }
+ else if (activeSelection == STUDIO2)
+ {
+ digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
+ digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
+ }
+}
+
+buttonEvent_t debounce( const uint8_t buttonPin,
+ uint8_t *buttonState,
+ unsigned long *buttonLastEventTime )
+{
+ uint8_t buttonLastState = *buttonState;
+ uint8_t buttonReading = digitalRead(buttonPin);
+
+ if ( (*buttonLastEventTime == 0) &&
+ (*buttonState != buttonReading) ) {
+ // something happened, start the debouncing process
+ *buttonLastEventTime = millis();
+ }
+
+ if (*buttonLastEventTime != 0) {
+ long buttonEventTimer = millis() - *buttonLastEventTime;
+
+ if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
+ (*buttonState == buttonReading) ) {
+ // noise or bouncing, abort
+ *buttonLastEventTime = 0;
+ }
+
+ if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
+ (buttonReading != *buttonState) ) {
+ // new button state was maintained
+ *buttonLastEventTime = 0;
+ *buttonState = buttonReading;
+ }
+ }
+
+ // debouncing finished, return button state
+ if (*buttonLastEventTime == 0) {
+ // comparing buttonState and buttonLastState tells whether the
+ // button is pressed or released
+ if ( (*buttonState == HIGH) &&
+ (buttonLastState == LOW) ) {
+ // button just pressed
+ buttonLastState = *buttonState;
+ return pressed;
+ }
+ if ( (*buttonState == LOW) &&
+ (buttonLastState == HIGH) ) {
+ // button just released
+ buttonLastState = *buttonState;
+ return released;
+ }
+ }
+ return nochange;
+}