]> git.0d.be Git - PanikSwitch.git/blob - FINAL2013V2.ino
53e3ae9012149215e4d207f662afe70857adbe15
[PanikSwitch.git] / FINAL2013V2.ino
1 // Panik Web Form Demo
2
3 #define SERIAL_DEBUG
4 #define ENABLE_UDP
5
6
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
12
13 // include Arduino libraries
14 #include <Wire.h>
15 #include <SPI.h>
16 #include <SD.h>
17 #include <Ethernet.h>
18 #ifdef ENABLE_UDP
19 #include <EthernetUdp.h>
20 #endif
21
22 // include third party libraries
23 #include "WebServer.h"
24
25 // include in-house libs
26 #include "PanikSwitch.h"    // contains variable types for panik switch
27
28 // define SD and Ethernet select ports
29 #define  SD_SELECT            4
30 #define  ETHERNET_SELECT     10
31
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
37
38 // output pins
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
43
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
46
47 // input pins
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
52
53
54
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
58 */
59 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
60
61
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
64 */
65 switchSelection_t activeSelection = 0;  // __attribute__ ((section (".noinit")));
66
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;
71
72
73 // declaration of possible button states as enum type
74 typedef enum { nochange, pressed, released } buttonEvent_t;
75
76 // button event timers
77 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
78
79 // variables holding the state of each button
80 // these are used during the debouncing process
81 uint8_t button1State = LOW, button2State = LOW;
82
83 // variables holding the non-stop status from studios 1 & 2
84 bool nonstop_via_stud1, nonstop_via_stud2;
85
86 // declare functions
87 buttonEvent_t debounce( const uint8_t buttonPin,
88                         uint8_t *buttonState,
89                         unsigned long *buttonLastEventTime );
90
91 static uint8_t mac[] = MAC_ADDRESS;
92 #define PREFIX ""
93
94 // instanciate web server
95 WebServer webserver(PREFIX, 80);
96
97 #ifdef ENABLE_UDP
98 // and EthernetUDP instance to send notifications
99 EthernetUDP Udp;
100 IPAddress udp_remote_ip(192, 168, 17, 224);
101 #endif
102
103
104 #define NAMELEN 4
105 #define VALUELEN 4
106
107 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
108
109
110 inline void notify_udp()  // notify over UDP
111 {
112 #ifdef ENABLE_UDP
113   char str_selection[20];
114   snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
115   #ifdef SERIAL_DEBUG
116   Serial.println(F("Sending UDP... "));
117   Serial.println(str_selection);
118   #endif
119   Udp.beginPacket(udp_remote_ip, 1312);
120   Udp.write(str_selection);
121   Udp.endPacket();
122 #endif
123 }
124
125 // web resource
126 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
127 {
128
129   server.httpSuccess("application/json");
130
131   if (type == WebServer::HEAD)
132     return;
133
134   responseStatus response_status = NO_POST;
135
136   if (type == WebServer::POST)
137   {
138     char name[NAMELEN];
139     int  name_len;
140     char value[VALUELEN];
141     int value_len;
142
143     response_status = POST_ERROR;
144
145     while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
146     {
147       if (strcmp(name, "s") == 0) {
148         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
149         blinkingSelection = static_cast<switchSelection_t>(atoi(value));
150         activeSelection = static_cast<switchSelection_t>(atoi(value));
151         response_status = POST_OK;
152
153         notify_udp();
154       }
155     }
156   }
157
158   server.println(F("{"));
159
160   server.print(" \"response\": ");
161   server.print(response_status);
162
163   server.print(",\n \"active\": ");
164   server.print(activeSelection);
165
166   server.print(",\n \"nonstop-via-stud1\": ");
167   server.print(nonstop_via_stud1);
168   server.print(",\n \"nonstop-via-stud2\": ");
169   server.println(nonstop_via_stud2);
170
171   server.println(F("}"));
172 }
173
174
175 // setup function
176 void setup()
177 {
178   blinkingSelection = activeSelection = nonstop;
179
180   // open serial communication for debugging
181   Serial.begin(9600);
182   Serial.println(F("Startup"));
183
184   // disable SD and Ethernet ports before setup
185   pinMode(SD_SELECT, OUTPUT);
186   digitalWrite(SD_SELECT, HIGH);                  // disable SD card
187   pinMode(ETHERNET_SELECT, OUTPUT);
188   digitalWrite(ETHERNET_SELECT, HIGH);           // disable Ethernet
189
190   // start SPI (because Ethernet shield needs it)
191   SPI.begin();                                          // start SPI
192
193   // start Ethernet
194   if (!(Ethernet.begin(mac) == 0))                    // start network
195     Serial.println(Ethernet.localIP());
196   else
197   {
198     #ifdef SERIAL_DEBUG
199     Serial.println(F("Network Error"));
200     #endif
201     while (1) ;
202   }
203   #ifdef ENABLE_UDP
204   if (! Udp.begin(1312)) {
205     #ifdef SERIAL_DEBUG
206     Serial.println(F("Failed to initiate UDP"));
207     #endif
208   }
209   #endif
210
211   // set mode for used pins
212   pinMode(RELAY_RED_LEDS, OUTPUT);
213   digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
214   pinMode(RELAY_YELLOW_LEDS, OUTPUT);
215   digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
216   pinMode(RELAY_GREEN_LEDS, OUTPUT);
217   digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
218   pinMode(RELAY_BUTTON_LEDS, OUTPUT);
219   digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
220
221   pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
222   digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
223   pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
224   digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
225
226   pinMode(BUTTON1, INPUT);
227   pinMode(BUTTON2, INPUT);
228   pinMode(NONSTOP_VIA_STUD1, INPUT);
229   pinMode(NONSTOP_VIA_STUD2, INPUT);
230
231   // configure web server pages
232   webserver.setDefaultCommand(&webCmd);
233
234   // start web server
235   webserver.begin();
236 }
237
238
239 // loop function
240 void loop()
241 {
242   // update variables indicating if non-stop is selected in studios 1&2
243   nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
244   if (nonstop_via_stud1 == 0)
245     nonstop_via_stud1 = 1;
246   else
247     nonstop_via_stud1 = 0;
248   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
249   if (nonstop_via_stud2 == 0)
250     nonstop_via_stud2 = 1;
251   else
252     nonstop_via_stud2 = 0;
253
254   // check if we have a HTTP request (and respond)
255   webserver.processConnection();
256
257   // handle button 1 (select button)
258   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
259   {
260     case nochange:
261       break;
262     case pressed:
263       #ifdef SERIAL_DEBUG
264       Serial.println(F("Button 1 pressed"));
265       #endif
266       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
267       blinkingSelection++;
268       blinkingStartTime = millis(),
269       blinkingAbortTime = millis();
270       blinkingLedState = RELAY_STATE_OPEN;
271       break;
272     case released:
273       #ifdef SERIAL_DEBUG
274       Serial.println(F("Button 1 released"));
275       #endif
276       break;
277   }
278
279   // handle button 2 (confirm button)
280   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
281   {
282     case nochange:
283       break;
284     case pressed:
285       #ifdef SERIAL_DEBUG
286       Serial.println(F("Button 2 pressed"));
287       #endif
288       blinkingAbortTime = 0;        // disable blinking auto abort
289       break;
290     case released:
291       #ifdef SERIAL_DEBUG
292       Serial.println(F("Button 2 released"));
293       #endif
294       if (activeSelection != blinkingSelection)
295       {
296         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
297         activeSelection = blinkingSelection;  // relay states must be changed now
298         #ifdef SERIAL_DEBUG
299         Serial.print(F("Active Selection: "));
300         Serial.println(activeSelection);
301         #endif
302         notify_udp();
303         break;
304       }
305   }
306
307   // handle auto abort for blinking led (if any)
308   if ( (blinkingAbortTime != 0) &&
309        ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
310     digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
311     blinkingAbortTime = 0;
312     blinkingSelection = activeSelection;
313   }
314
315   // handle blinking led (if selected is not current state)
316   if (activeSelection != blinkingSelection) {
317     if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
318       digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
319       digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
320       blinkingStartTime = millis();
321       blinkingLedState = !blinkingLedState;
322     }
323   }
324   else {
325     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
326   }
327
328   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
329
330   // update audio channel relays
331   if (activeSelection == nonstop)
332   {
333     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
334     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
335   }
336   else if (activeSelection == studio1)
337   {
338     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
339     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
340   }
341   else if (activeSelection == studio2)
342   {
343     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
344     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
345   }
346 }
347
348 buttonEvent_t debounce( const uint8_t buttonPin,
349                         uint8_t *buttonState,
350                         unsigned long *buttonLastEventTime )
351 {
352   uint8_t buttonLastState = *buttonState;
353   uint8_t buttonReading = digitalRead(buttonPin);
354
355   if ( (*buttonLastEventTime == 0) &&
356        (*buttonState != buttonReading) ) {
357     // something happened, start the debouncing process
358     *buttonLastEventTime = millis();
359   }
360
361   if (*buttonLastEventTime != 0) {
362     long buttonEventTimer = millis() - *buttonLastEventTime;
363
364     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
365          (*buttonState == buttonReading) ) {
366       // noise or bouncing, abort
367       *buttonLastEventTime = 0;
368     }
369
370     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
371          (buttonReading != *buttonState) ) {
372       // new button state was maintained
373       *buttonLastEventTime = 0;
374       *buttonState = buttonReading;
375     }
376   }
377
378   // debouncing finished, return button state
379   if (*buttonLastEventTime == 0) {
380     // comparing buttonState and buttonLastState tells whether the
381     // button is pressed or released
382     if ( (*buttonState == HIGH) &&
383          (buttonLastState == LOW) ) {
384       // button just pressed
385       buttonLastState = *buttonState;
386       return pressed;
387     }
388     if ( (*buttonState == LOW) &&
389          (buttonLastState == HIGH) ) {
390       // button just released
391       buttonLastState = *buttonState;
392       return released;
393     }
394   }
395   return nochange;
396 }