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 // include in-house libs
26 #include "PanikSwitch.h" // contains variable types for panik switch
28 // define SD and Ethernet select ports
30 #define ETHERNET_SELECT 10
32 // define machine variables
33 #define DEBOUNCE_TRESHOLD 10 // 10 milliseconds
34 #define ABORT_TRESHOLD 3000L // 3 seconds
35 #define PULSE_TRESHOLD 50 // 50 milliseconds
36 #define BLINK_TRESHOLD 100 // 100 milliseconds
39 #define RELAY_BUTTON_LEDS 5 // Button LED indicator
40 #define RELAY_GREEN_LEDS 6 // ``Non-Stop`` LED indicator
41 #define RELAY_RED_LEDS 8 // ``Studio 1`` LED indicator
42 #define RELAY_YELLOW_LEDS 7 // ``Studio 2`` LED indicator
44 #define RELAY_NONSTOP_OR_STUD 4 // Relay : Non-stop or Studio
45 #define RELAY_STUD1_OR_STUD2 9 // Relay : Studio 1 or Studio 2
48 #define BUTTON1 2 // ``Select`` button
49 #define BUTTON2 3 // ``Confirm`` button
50 #define NONSTOP_VIA_STUD1 14 // is nonstop coming out of studio 1
51 #define NONSTOP_VIA_STUD2 15 // is nonstop coming out of studio 2
55 /* define an array with led pins,
56 indexes in that array correspond to the values of possible selections
57 i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
59 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
62 /* activeSelection is the variable that holds the active output of the switch
63 it is declared as an attribute that keeps its value between arduino resets
65 switchSelection_t activeSelection __attribute__ ((section (".noinit")));
67 // variables and timers for blinking selection (selected but not confirmed)
68 switchSelection_t blinkingSelection = nonstop;
69 bool blinkingLedState = RELAY_STATE_CLOSED;
70 unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
73 // declaration of possible button states as enum type
74 typedef enum { nochange, pressed, released } buttonEvent_t;
76 // button event timers
77 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
79 // variables holding the state of each button
80 // these are used during the debouncing process
81 uint8_t button1State = LOW, button2State = LOW;
83 // variables holding the non-stop status from studios 1 & 2
84 bool nonstop_via_stud1, nonstop_via_stud2;
87 buttonEvent_t debounce( const uint8_t buttonPin,
89 unsigned long *buttonLastEventTime );
91 static uint8_t mac[] = MAC_ADDRESS;
94 // instanciate web server
95 WebServer webserver(PREFIX, 80);
98 // and EthernetUDP instance to send notifications
100 IPAddress udp_remote_ip(192, 168, 17, 224);
107 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
111 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
114 server.httpSuccess("application/json");
116 if (type == WebServer::HEAD)
119 responseStatus response_status = NO_POST;
121 if (type == WebServer::POST)
125 char value[VALUELEN];
128 response_status = POST_ERROR;
130 while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
132 if (strcmp(name, "s") == 0) {
133 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
134 blinkingSelection = static_cast<switchSelection_t>(atoi(value));
135 activeSelection = static_cast<switchSelection_t>(atoi(value));
136 response_status = POST_OK;
141 server.println(F("{"));
143 server.print(" \"response\": ");
144 server.print(response_status);
146 server.print(",\n \"active\": ");
147 server.print(activeSelection);
149 server.print(",\n \"nonstop-via-stud1\": ");
150 server.print(nonstop_via_stud1);
151 server.print(",\n \"nonstop-via-stud2\": ");
152 server.println(nonstop_via_stud2);
154 server.println(F("}"));
161 // make sure that activeSelection holds something valid
162 // if (!(activeSelection > nonstop) || !(activeSelection < _NbrSwitchSelections))
163 // activeSelection = nonstop;
164 blinkingSelection = activeSelection = nonstop;
166 // open serial communication for debugging
168 Serial.println(F("Startup"));
170 // disable SD and Ethernet ports before setup
171 pinMode(SD_SELECT, OUTPUT);
172 digitalWrite(SD_SELECT, HIGH); // disable SD card
173 pinMode(ETHERNET_SELECT, OUTPUT);
174 digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
176 // start SPI (because Ethernet shield needs it)
177 SPI.begin(); // start SPI
180 if (!(Ethernet.begin(mac) == 0)) // start network
181 Serial.println(Ethernet.localIP());
185 Serial.println(F("Network Error"));
190 if (! Udp.begin(1312)) {
192 Serial.println(F("Failed to initiate UDP"));
197 // set mode for used pins
198 pinMode(RELAY_RED_LEDS, OUTPUT);
199 digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
200 pinMode(RELAY_YELLOW_LEDS, OUTPUT);
201 digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
202 pinMode(RELAY_GREEN_LEDS, OUTPUT);
203 digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
204 pinMode(RELAY_BUTTON_LEDS, OUTPUT);
205 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
207 pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
208 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
209 pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
210 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
212 pinMode(BUTTON1, INPUT);
213 pinMode(BUTTON2, INPUT);
214 pinMode(NONSTOP_VIA_STUD1, INPUT);
215 pinMode(NONSTOP_VIA_STUD2, INPUT);
217 // configure web server pages
218 webserver.setDefaultCommand(&webCmd);
228 // update variables indicating if non-stop is selected in studios 1&2
229 nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
230 if (nonstop_via_stud1 == 0)
231 nonstop_via_stud1 = 1;
233 nonstop_via_stud1 = 0;
234 nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
235 if (nonstop_via_stud2 == 0)
236 nonstop_via_stud2 = 1;
238 nonstop_via_stud2 = 0;
240 // check if we have a HTTP request (and respond)
241 webserver.processConnection();
243 // handle button 1 (select button)
244 switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
250 Serial.println(F("Button 1 pressed"));
252 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
254 blinkingStartTime = millis(),
255 blinkingAbortTime = millis();
256 blinkingLedState = RELAY_STATE_OPEN;
260 Serial.println(F("Button 1 released"));
265 // handle button 2 (confirm button)
266 switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
272 Serial.println(F("Button 2 pressed"));
274 blinkingAbortTime = 0; // disable blinking auto abort
278 Serial.println(F("Button 2 released"));
280 if (activeSelection != blinkingSelection)
282 char str_selection[20];
283 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
284 activeSelection = blinkingSelection; // relay states must be changed now
286 Serial.print(F("Active Selection: "));
287 Serial.println(activeSelection);
291 snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
292 Udp.beginPacket(udp_remote_ip, 1312);
293 Udp.write(str_selection);
300 // handle auto abort for blinking led (if any)
301 if ( (blinkingAbortTime != 0) &&
302 ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
303 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
304 blinkingAbortTime = 0;
305 blinkingSelection = activeSelection;
308 // handle blinking led (if selected is not current state)
309 if (activeSelection != blinkingSelection) {
310 if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
311 digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
312 digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
313 blinkingStartTime = millis();
314 blinkingLedState = !blinkingLedState;
318 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
321 digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
323 // update audio channel relays
324 if (activeSelection == nonstop)
326 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
327 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
329 else if (activeSelection == studio1)
331 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
332 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
334 else if (activeSelection == studio2)
336 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
337 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
341 buttonEvent_t debounce( const uint8_t buttonPin,
342 uint8_t *buttonState,
343 unsigned long *buttonLastEventTime )
345 uint8_t buttonLastState = *buttonState;
346 uint8_t buttonReading = digitalRead(buttonPin);
348 if ( (*buttonLastEventTime == 0) &&
349 (*buttonState != buttonReading) ) {
350 // something happened, start the debouncing process
351 *buttonLastEventTime = millis();
354 if (*buttonLastEventTime != 0) {
355 long buttonEventTimer = millis() - *buttonLastEventTime;
357 if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
358 (*buttonState == buttonReading) ) {
359 // noise or bouncing, abort
360 *buttonLastEventTime = 0;
363 if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
364 (buttonReading != *buttonState) ) {
365 // new button state was maintained
366 *buttonLastEventTime = 0;
367 *buttonState = buttonReading;
371 // debouncing finished, return button state
372 if (*buttonLastEventTime == 0) {
373 // comparing buttonState and buttonLastState tells whether the
374 // button is pressed or released
375 if ( (*buttonState == HIGH) &&
376 (buttonLastState == LOW) ) {
377 // button just pressed
378 buttonLastState = *buttonState;
381 if ( (*buttonState == LOW) &&
382 (buttonLastState == HIGH) ) {
383 // button just released
384 buttonLastState = *buttonState;