5 // define network constants
6 #define MAC_DAVID { 0x90, 0xA2, 0xDA, 0x0D, 0xF4, 0x63 }
7 #define MAC_PANIK { 0x90, 0xA2, 0xDA, 0x00, 0x9A, 0x94 }
8 #define MAC_PANIK2 { 0x90, 0xA2, 0xDA, 0x0E, 0xF3, 0x77 }
9 #define MAC_ADDRESS MAC_PANIK2
11 // include Arduino libraries
16 #include <EthernetUdp.h>
18 // include third party libraries
19 #include "WebServer.h"
21 // include in-house libs
22 #include "PanikSwitch.h" // contains variable types for panik switch
24 // define SD and Ethernet select ports
26 #define ETHERNET_SELECT 10
28 // define machine variables
29 #define DEBOUNCE_TRESHOLD 10 // 10 milliseconds
30 #define ABORT_TRESHOLD 3000L // 3 seconds
31 #define PULSE_TRESHOLD 50 // 50 milliseconds
32 #define BLINK_TRESHOLD 100 // 100 milliseconds
35 #define RELAY_BUTTON_LEDS 5 // Button LED indicator
36 #define RELAY_GREEN_LEDS 6 // ``Non-Stop`` LED indicator
37 #define RELAY_RED_LEDS 8 // ``Studio 1`` LED indicator
38 #define RELAY_YELLOW_LEDS 7 // ``Studio 2`` LED indicator
40 #define RELAY_NONSTOP_OR_STUD 4 // Relay : Non-stop or Studio
41 #define RELAY_STUD1_OR_STUD2 9 // Relay : Studio 1 or Studio 2
44 #define BUTTON1 2 // ``Select`` button
45 #define BUTTON2 3 // ``Confirm`` button
46 #define NONSTOP_VIA_STUD1 14 // is nonstop coming out of studio 1
47 #define NONSTOP_VIA_STUD2 15 // is nonstop coming out of studio 2
51 /* define an array with led pins,
52 indexes in that array correspond to the values of possible selections
53 i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
55 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
58 /* activeSelection is the variable that holds the active output of the switch
59 it is declared as an attribute that keeps its value between arduino resets
61 switchSelection_t activeSelection __attribute__ ((section (".noinit")));
63 // variables and timers for blinking selection (selected but not confirmed)
64 switchSelection_t blinkingSelection = nonstop;
65 bool blinkingLedState = RELAY_STATE_CLOSED;
66 unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
69 // declaration of possible button states as enum type
70 typedef enum { nochange, pressed, released } buttonEvent_t;
72 // button event timers
73 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
75 // variables holding the state of each button
76 // these are used during the debouncing process
77 uint8_t button1State = LOW, button2State = LOW;
79 // variables holding the non-stop status from studios 1 & 2
80 bool nonstop_via_stud1, nonstop_via_stud2;
83 buttonEvent_t debounce( const uint8_t buttonPin,
85 unsigned long *buttonLastEventTime );
87 static uint8_t mac[] = MAC_ADDRESS;
90 // instanciate web server
91 WebServer webserver(PREFIX, 80);
93 // and EthernetUDP instance to send notifications
95 IPAddress udp_remote_ip(192, 168, 17, 224);
101 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
105 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
108 server.httpSuccess("application/json");
110 if (type == WebServer::HEAD)
113 responseStatus response_status = NO_POST;
115 if (type == WebServer::POST)
119 char value[VALUELEN];
122 response_status = POST_ERROR;
124 while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
126 if (strcmp(name, "s") == 0) {
127 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
128 blinkingSelection = static_cast<switchSelection_t>(atoi(value));
129 activeSelection = static_cast<switchSelection_t>(atoi(value));
130 response_status = POST_OK;
135 server.println(F("{"));
137 server.print(" \"response\": ");
138 server.print(response_status);
140 server.print(",\n \"active\": ");
141 server.print(activeSelection);
143 server.print(",\n \"nonstop-via-stud1\": ");
144 server.print(nonstop_via_stud1);
145 server.print(",\n \"nonstop-via-stud2\": ");
146 server.println(nonstop_via_stud2);
148 server.println(F("}"));
155 // make sure that activeSelection holds something valid
156 // if (!(activeSelection > nonstop) || !(activeSelection < _NbrSwitchSelections))
157 // activeSelection = nonstop;
158 blinkingSelection = activeSelection = nonstop;
160 // open serial communication for debugging
162 Serial.println(F("Startup"));
164 // disable SD and Ethernet ports before setup
165 pinMode(SD_SELECT, OUTPUT);
166 digitalWrite(SD_SELECT, HIGH); // disable SD card
167 pinMode(ETHERNET_SELECT, OUTPUT);
168 digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
170 // start SPI (because Ethernet shield needs it)
171 SPI.begin(); // start SPI
174 if (!(Ethernet.begin(mac) == 0)) // start network
175 Serial.println(Ethernet.localIP());
178 Serial.println(F("Network Error"));
181 if (! Udp.begin(1312)) {
182 Serial.println(F("Failed to initiate UDP"));
185 // set mode for used pins
186 pinMode(RELAY_RED_LEDS, OUTPUT);
187 digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
188 pinMode(RELAY_YELLOW_LEDS, OUTPUT);
189 digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
190 pinMode(RELAY_GREEN_LEDS, OUTPUT);
191 digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
192 pinMode(RELAY_BUTTON_LEDS, OUTPUT);
193 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
195 pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
196 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
197 pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
198 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
200 pinMode(BUTTON1, INPUT);
201 pinMode(BUTTON2, INPUT);
202 pinMode(NONSTOP_VIA_STUD1, INPUT);
203 pinMode(NONSTOP_VIA_STUD2, INPUT);
205 // configure web server pages
206 webserver.setDefaultCommand(&webCmd);
216 // update variables indicating if non-stop is selected in studios 1&2
217 nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
218 if (nonstop_via_stud1 == 0)
219 nonstop_via_stud1 = 1;
221 nonstop_via_stud1 = 0;
222 nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
223 if (nonstop_via_stud2 == 0)
224 nonstop_via_stud2 = 1;
226 nonstop_via_stud2 = 0;
228 // check if we have a HTTP request (and respond)
229 webserver.processConnection();
231 // handle button 1 (select button)
232 switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
237 //Serial.println(F("Button 1 pressed"));
238 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
240 blinkingStartTime = millis(),
241 blinkingAbortTime = millis();
242 blinkingLedState = RELAY_STATE_OPEN;
245 //Serial.println(F("Button 1 released"));
249 // handle button 2 (confirm button)
250 switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
255 //Serial.println(F("Button 2 pressed"));
256 blinkingAbortTime = 0; // disable blinking auto abort
259 //Serial.println(F("Button 2 released"));
260 if (activeSelection != blinkingSelection)
262 char str_selection[20];
263 digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
264 activeSelection = blinkingSelection; // relay states must be changed now
265 Serial.print(F("Active Selection: "));
266 Serial.println(activeSelection);
268 snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
269 Udp.beginPacket(udp_remote_ip, 1312);
270 Udp.write(str_selection);
276 // handle auto abort for blinking led (if any)
277 if ( (blinkingAbortTime != 0) &&
278 ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
279 digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
280 blinkingAbortTime = 0;
281 blinkingSelection = activeSelection;
284 // handle blinking led (if selected is not current state)
285 if (activeSelection != blinkingSelection) {
286 if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
287 digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
288 digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
289 blinkingStartTime = millis();
290 blinkingLedState = !blinkingLedState;
294 digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
297 digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
299 // update audio channel relays
300 if (activeSelection == nonstop)
302 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
303 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
305 else if (activeSelection == studio1)
307 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
308 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
310 else if (activeSelection == studio2)
312 digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
313 digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
317 buttonEvent_t debounce( const uint8_t buttonPin,
318 uint8_t *buttonState,
319 unsigned long *buttonLastEventTime )
321 uint8_t buttonLastState = *buttonState;
322 uint8_t buttonReading = digitalRead(buttonPin);
324 if ( (*buttonLastEventTime == 0) &&
325 (*buttonState != buttonReading) ) {
326 // something happened, start the debouncing process
327 *buttonLastEventTime = millis();
330 if (*buttonLastEventTime != 0) {
331 long buttonEventTimer = millis() - *buttonLastEventTime;
333 if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
334 (*buttonState == buttonReading) ) {
335 // noise or bouncing, abort
336 *buttonLastEventTime = 0;
339 if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
340 (buttonReading != *buttonState) ) {
341 // new button state was maintained
342 *buttonLastEventTime = 0;
343 *buttonState = buttonReading;
347 // debouncing finished, return button state
348 if (*buttonLastEventTime == 0) {
349 // comparing buttonState and buttonLastState tells whether the
350 // button is pressed or released
351 if ( (*buttonState == HIGH) &&
352 (buttonLastState == LOW) ) {
353 // button just pressed
354 buttonLastState = *buttonState;
357 if ( (*buttonState == LOW) &&
358 (buttonLastState == HIGH) ) {
359 // button just released
360 buttonLastState = *buttonState;