]> git.0d.be Git - PanikSwitch.git/blob - FINAL2013V2.ino
c9f3829e6d9a0a00e13d93daf013b8b09181430f
[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 // define SD and Ethernet select ports
26 #define  SD_SELECT            4
27 #define  ETHERNET_SELECT     10
28
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
34
35 // output pins
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
40
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
43
44 // input pins
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
49
50 /* status */
51 #define NONSTOP 0
52 #define STUDIO1 1
53 #define STUDIO2 2
54
55
56 /* relay positions */
57 typedef enum { RELAY_STATE_OPEN, RELAY_STATE_CLOSED } relayState_t;
58
59
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
63 */
64 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
65
66
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
69 */
70 int activeSelection = NONSTOP;
71
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;
76
77
78 // declaration of possible button states as enum type
79 typedef enum { nochange, pressed, released } buttonEvent_t;
80
81 // button event timers
82 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
83
84 // variables holding the state of each button
85 // these are used during the debouncing process
86 uint8_t button1State = LOW, button2State = LOW;
87
88 // variables holding the non-stop status from studios 1 & 2
89 bool nonstop_via_stud1, nonstop_via_stud2;
90
91 // declare functions
92 buttonEvent_t debounce( const uint8_t buttonPin,
93                         uint8_t *buttonState,
94                         unsigned long *buttonLastEventTime );
95
96 static uint8_t mac[] = MAC_ADDRESS;
97 #define PREFIX ""
98
99 // instanciate web server
100 WebServer webserver(PREFIX, 80);
101
102 #ifdef ENABLE_UDP
103 // and EthernetUDP instance to send notifications
104 EthernetUDP Udp;
105 IPAddress udp_remote_ip(192, 168, 17, 224);
106 #endif
107
108
109 #define NAMELEN 4
110 #define VALUELEN 4
111
112 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
113
114
115 inline void notify_udp()  // notify over UDP
116 {
117 #ifdef ENABLE_UDP
118   char str_selection[20];
119   snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
120   #ifdef SERIAL_DEBUG
121   Serial.println(F("Sending UDP... "));
122   Serial.println(str_selection);
123   #endif
124   Udp.beginPacket(udp_remote_ip, 1312);
125   Udp.write(str_selection);
126   Udp.endPacket();
127 #endif
128 }
129
130 // web resource
131 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
132 {
133
134   server.httpSuccess("application/json");
135
136   if (type == WebServer::HEAD)
137     return;
138
139   responseStatus response_status = NO_POST;
140
141   if (type == WebServer::POST)
142   {
143     char name[NAMELEN];
144     int  name_len;
145     char value[VALUELEN];
146     int value_len;
147
148     response_status = POST_ERROR;
149
150     while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
151     {
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;
157
158         notify_udp();
159       }
160     }
161   }
162
163   server.println(F("{"));
164
165   server.print(" \"response\": ");
166   server.print(response_status);
167
168   server.print(",\n \"active\": ");
169   server.print(activeSelection);
170
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);
175
176   server.println(F("}"));
177 }
178
179
180 // setup function
181 void setup()
182 {
183   blinkingSelection = activeSelection = NONSTOP;
184
185   // open serial communication for debugging
186   Serial.begin(9600);
187   Serial.println(F("Startup"));
188
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
194
195   // start SPI (because Ethernet shield needs it)
196   SPI.begin();                                          // start SPI
197
198   // start Ethernet
199   if (!(Ethernet.begin(mac) == 0))                    // start network
200     Serial.println(Ethernet.localIP());
201   else
202   {
203     #ifdef SERIAL_DEBUG
204     Serial.println(F("Network Error"));
205     #endif
206     while (1) ;
207   }
208   #ifdef ENABLE_UDP
209   if (! Udp.begin(1312)) {
210     #ifdef SERIAL_DEBUG
211     Serial.println(F("Failed to initiate UDP"));
212     #endif
213   }
214   #endif
215
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);
225
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);
230
231   pinMode(BUTTON1, INPUT);
232   pinMode(BUTTON2, INPUT);
233   pinMode(NONSTOP_VIA_STUD1, INPUT);
234   pinMode(NONSTOP_VIA_STUD2, INPUT);
235
236   // configure web server pages
237   webserver.setDefaultCommand(&webCmd);
238
239   // start web server
240   webserver.begin();
241 }
242
243
244 // loop function
245 void loop()
246 {
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;
251   else
252     nonstop_via_stud1 = 0;
253   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
254   if (nonstop_via_stud2 == 0)
255     nonstop_via_stud2 = 1;
256   else
257     nonstop_via_stud2 = 0;
258
259   // check if we have a HTTP request (and respond)
260   webserver.processConnection();
261
262   // handle button 1 (select button)
263   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
264   {
265     case nochange:
266       break;
267     case pressed:
268       #ifdef SERIAL_DEBUG
269       Serial.println(F("Button 1 pressed"));
270       #endif
271       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
272       blinkingSelection++;
273       if (blinkingSelection > STUDIO2) {
274         blinkingSelection = NONSTOP;
275       }
276       blinkingStartTime = millis(),
277       blinkingAbortTime = millis();
278       blinkingLedState = RELAY_STATE_OPEN;
279       break;
280     case released:
281       #ifdef SERIAL_DEBUG
282       Serial.println(F("Button 1 released"));
283       #endif
284       break;
285   }
286
287   // handle button 2 (confirm button)
288   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
289   {
290     case nochange:
291       break;
292     case pressed:
293       #ifdef SERIAL_DEBUG
294       Serial.println(F("Button 2 pressed"));
295       #endif
296       blinkingAbortTime = 0;        // disable blinking auto abort
297       break;
298     case released:
299       #ifdef SERIAL_DEBUG
300       Serial.println(F("Button 2 released"));
301       #endif
302       if (activeSelection != blinkingSelection)
303       {
304         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
305         activeSelection = blinkingSelection;  // relay states must be changed now
306         #ifdef SERIAL_DEBUG
307         Serial.print(F("Active Selection: "));
308         Serial.println(activeSelection);
309         #endif
310         notify_udp();
311         break;
312       }
313   }
314
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;
321   }
322
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;
330     }
331   }
332   else {
333     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
334   }
335
336   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
337
338   // update audio channel relays
339   if (activeSelection == NONSTOP)
340   {
341     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
342     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
343   }
344   else if (activeSelection == STUDIO1)
345   {
346     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
347     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
348   }
349   else if (activeSelection == STUDIO2)
350   {
351     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
352     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
353   }
354 }
355
356 buttonEvent_t debounce( const uint8_t buttonPin,
357                         uint8_t *buttonState,
358                         unsigned long *buttonLastEventTime )
359 {
360   uint8_t buttonLastState = *buttonState;
361   uint8_t buttonReading = digitalRead(buttonPin);
362
363   if ( (*buttonLastEventTime == 0) &&
364        (*buttonState != buttonReading) ) {
365     // something happened, start the debouncing process
366     *buttonLastEventTime = millis();
367   }
368
369   if (*buttonLastEventTime != 0) {
370     long buttonEventTimer = millis() - *buttonLastEventTime;
371
372     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
373          (*buttonState == buttonReading) ) {
374       // noise or bouncing, abort
375       *buttonLastEventTime = 0;
376     }
377
378     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
379          (buttonReading != *buttonState) ) {
380       // new button state was maintained
381       *buttonLastEventTime = 0;
382       *buttonState = buttonReading;
383     }
384   }
385
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;
394       return pressed;
395     }
396     if ( (*buttonState == LOW) &&
397          (buttonLastState == HIGH) ) {
398       // button just released
399       buttonLastState = *buttonState;
400       return released;
401     }
402   }
403   return nochange;
404 }