7 // define network constants
8 #define MAC_DAVID { 0x90, 0xA2, 0xDA, 0x0D, 0xF4, 0x63 }
9 #define MAC_PANIK { 0x90, 0xA2, 0xDA, 0x00, 0x9A, 0x94 }
10 #define MAC_PANIK2 { 0x90, 0xA2, 0xDA, 0x0E, 0xF3, 0x77 }
11 #define MAC_ADDRESS MAC_PANIK2
13 // include Arduino libraries
19 #include <EthernetUdp.h>
22 // include third party libraries
23 #include "WebServer.h"
25 // define SD and Ethernet select ports
27 #define ETHERNET_SELECT 10
29 // define machine variables
30 #define DEBOUNCE_TRESHOLD 10 // 10 milliseconds
31 #define ABORT_TRESHOLD 3000L // 3 seconds
32 #define PULSE_TRESHOLD 50 // 50 milliseconds
33 #define BLINK_TRESHOLD 100 // 100 milliseconds
36 #define RELAY_BUTTON_LEDS 5 // Button LED indicator
37 #define RELAY_GREEN_LEDS 6 // ``Non-Stop`` LED indicator
38 #define RELAY_RED_LEDS 8 // ``Studio 1`` LED indicator
39 #define RELAY_YELLOW_LEDS 7 // ``Studio 2`` LED indicator
41 #define RELAY_NONSTOP_OR_STUD 4 // Relay : Non-stop or Studio
42 #define RELAY_STUD1_OR_STUD2 9 // Relay : Studio 1 or Studio 2
45 #define BUTTON1 2 // ``Select`` button
46 #define BUTTON2 3 // ``Confirm`` button
47 #define NONSTOP_VIA_STUD1 14 // is nonstop coming out of studio 1
48 #define NONSTOP_VIA_STUD2 15 // is nonstop coming out of studio 2
57 typedef enum { RELAY_STATE_OPEN, RELAY_STATE_CLOSED } relayState_t;
60 /* define an array with led pins,
61 indexes in that array correspond to the values of possible selections
62 i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
64 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
67 /* activeSelection is the variable that holds the active output of the switch
68 it is declared as an attribute that keeps its value between arduino resets
70 int activeSelection = NONSTOP;
72 // variables and timers for blinking selection (selected but not confirmed)
73 int blinkingSelection = NONSTOP;
74 bool blinkingLedState = RELAY_STATE_CLOSED;
75 unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
78 // declaration of possible button states as enum type
79 typedef enum { nochange, pressed, released } buttonEvent_t;
81 // button event timers
82 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
84 // variables holding the state of each button
85 // these are used during the debouncing process
86 uint8_t button1State = LOW, button2State = LOW;
88 // variables holding the non-stop status from studios 1 & 2
89 bool nonstop_via_stud1, nonstop_via_stud2;
92 buttonEvent_t debounce( const uint8_t buttonPin,
94 unsigned long *buttonLastEventTime );
96 static uint8_t mac[] = MAC_ADDRESS;
99 // instanciate web server
100 WebServer webserver(PREFIX, 80);
103 // and EthernetUDP instance to send notifications
105 IPAddress udp_remote_ip(192, 168, 17, 224);
112 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
115 inline void notify_udp() // notify over UDP
118 char str_selection[20];
119 snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
121 Serial.println(F("Sending UDP... "));
122 Serial.println(str_selection);
124 Udp.beginPacket(udp_remote_ip, 1312);
125 Udp.write(str_selection);
131 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
134 server.httpSuccess("application/json");
136 if (type == WebServer::HEAD)
139 responseStatus response_status = NO_POST;
141 if (type == WebServer::POST)
145 char value[VALUELEN];
148 response_status = POST_ERROR;
150 while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
152 if (strcmp(name, "s") == 0) {
153 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
154 blinkingSelection = atoi(value);
155 activeSelection = atoi(value);
156 response_status = POST_OK;
163 server.println(F("{"));
165 server.print(" \"response\": ");
166 server.print(response_status);
168 server.print(",\n \"active\": ");
169 server.print(activeSelection);
171 server.print(",\n \"nonstop-via-stud1\": ");
172 server.print(nonstop_via_stud1);
173 server.print(",\n \"nonstop-via-stud2\": ");
174 server.println(nonstop_via_stud2);
176 server.println(F("}"));
183 blinkingSelection = activeSelection = NONSTOP;
185 // open serial communication for debugging
187 Serial.println(F("Startup"));
189 // disable SD and Ethernet ports before setup
190 pinMode(SD_SELECT, OUTPUT);
191 digitalWrite(SD_SELECT, HIGH); // disable SD card
192 pinMode(ETHERNET_SELECT, OUTPUT);
193 digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
195 // start SPI (because Ethernet shield needs it)
196 SPI.begin(); // start SPI
199 if (!(Ethernet.begin(mac) == 0)) // start network
200 Serial.println(Ethernet.localIP());
204 Serial.println(F("Network Error"));
209 if (! Udp.begin(1312)) {
211 Serial.println(F("Failed to initiate UDP"));
216 // set mode for used pins
217 pinMode(RELAY_RED_LEDS, OUTPUT);
218 digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
219 pinMode(RELAY_YELLOW_LEDS, OUTPUT);
220 digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
221 pinMode(RELAY_GREEN_LEDS, OUTPUT);
222 digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
223 pinMode(RELAY_BUTTON_LEDS, OUTPUT);
224 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
226 pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
227 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
228 pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
229 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
231 pinMode(BUTTON1, INPUT);
232 pinMode(BUTTON2, INPUT);
233 pinMode(NONSTOP_VIA_STUD1, INPUT);
234 pinMode(NONSTOP_VIA_STUD2, INPUT);
236 // configure web server pages
237 webserver.setDefaultCommand(&webCmd);
247 // update variables indicating if non-stop is selected in studios 1&2
248 nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
249 if (nonstop_via_stud1 == 0)
250 nonstop_via_stud1 = 1;
252 nonstop_via_stud1 = 0;
253 nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
254 if (nonstop_via_stud2 == 0)
255 nonstop_via_stud2 = 1;
257 nonstop_via_stud2 = 0;
259 // check if we have a HTTP request (and respond)
260 webserver.processConnection();
262 // handle button 1 (select button)
263 switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
269 Serial.println(F("Button 1 pressed"));
271 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
273 if (blinkingSelection > STUDIO2) {
274 blinkingSelection = NONSTOP;
276 blinkingStartTime = millis(),
277 blinkingAbortTime = millis();
278 blinkingLedState = RELAY_STATE_OPEN;
282 Serial.println(F("Button 1 released"));
287 // handle button 2 (confirm button)
288 switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
294 Serial.println(F("Button 2 pressed"));
296 blinkingAbortTime = 0; // disable blinking auto abort
300 Serial.println(F("Button 2 released"));
302 if (activeSelection != blinkingSelection)
304 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
305 activeSelection = blinkingSelection; // relay states must be changed now
307 Serial.print(F("Active Selection: "));
308 Serial.println(activeSelection);
315 // handle auto abort for blinking led (if any)
316 if ( (blinkingAbortTime != 0) &&
317 ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
318 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
319 blinkingAbortTime = 0;
320 blinkingSelection = activeSelection;
323 // handle blinking led (if selected is not current state)
324 if (activeSelection != blinkingSelection) {
325 if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
326 digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
327 digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
328 blinkingStartTime = millis();
329 blinkingLedState = !blinkingLedState;
333 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
336 digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
338 // update audio channel relays
339 if (activeSelection == NONSTOP)
341 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
342 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
344 else if (activeSelection == STUDIO1)
346 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
347 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
349 else if (activeSelection == STUDIO2)
351 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
352 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
356 buttonEvent_t debounce( const uint8_t buttonPin,
357 uint8_t *buttonState,
358 unsigned long *buttonLastEventTime )
360 uint8_t buttonLastState = *buttonState;
361 uint8_t buttonReading = digitalRead(buttonPin);
363 if ( (*buttonLastEventTime == 0) &&
364 (*buttonState != buttonReading) ) {
365 // something happened, start the debouncing process
366 *buttonLastEventTime = millis();
369 if (*buttonLastEventTime != 0) {
370 long buttonEventTimer = millis() - *buttonLastEventTime;
372 if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
373 (*buttonState == buttonReading) ) {
374 // noise or bouncing, abort
375 *buttonLastEventTime = 0;
378 if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
379 (buttonReading != *buttonState) ) {
380 // new button state was maintained
381 *buttonLastEventTime = 0;
382 *buttonState = buttonReading;
386 // debouncing finished, return button state
387 if (*buttonLastEventTime == 0) {
388 // comparing buttonState and buttonLastState tells whether the
389 // button is pressed or released
390 if ( (*buttonState == HIGH) &&
391 (buttonLastState == LOW) ) {
392 // button just pressed
393 buttonLastState = *buttonState;
396 if ( (*buttonState == LOW) &&
397 (buttonLastState == HIGH) ) {
398 // button just released
399 buttonLastState = *buttonState;