]> git.0d.be Git - PanikSwitch.git/blob - FINAL2013V2.ino
also send udp notification when setting over HTTP
[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 // web resource
111 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
112 {
113
114   server.httpSuccess("application/json");
115
116   if (type == WebServer::HEAD)
117     return;
118
119   responseStatus response_status = NO_POST;
120
121   if (type == WebServer::POST)
122   {
123     char name[NAMELEN];
124     int  name_len;
125     char value[VALUELEN];
126     int value_len;
127
128     response_status = POST_ERROR;
129
130     while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
131     {
132       if (strcmp(name, "s") == 0) {
133         char str_selection[20];
134
135         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
136         blinkingSelection = static_cast<switchSelection_t>(atoi(value));
137         activeSelection = static_cast<switchSelection_t>(atoi(value));
138         response_status = POST_OK;
139
140         #ifdef ENABLE_UDP
141         // notify over UDP
142         snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
143         #ifdef SERIAL_DEBUG
144         Serial.println(F("Sending UDP... "));
145         Serial.println(str_selection);
146         #endif
147         Udp.beginPacket(udp_remote_ip, 1312);
148         Udp.write(str_selection);
149         Udp.endPacket();
150         #endif
151
152       }
153     }
154   }
155
156   server.println(F("{"));
157
158   server.print(" \"response\": ");
159   server.print(response_status);
160
161   server.print(",\n \"active\": ");
162   server.print(activeSelection);
163
164   server.print(",\n \"nonstop-via-stud1\": ");
165   server.print(nonstop_via_stud1);
166   server.print(",\n \"nonstop-via-stud2\": ");
167   server.println(nonstop_via_stud2);
168
169   server.println(F("}"));
170 }
171
172
173 // setup function
174 void setup()
175 {
176   blinkingSelection = activeSelection = nonstop;
177
178   // open serial communication for debugging
179   Serial.begin(9600);
180   Serial.println(F("Startup"));
181
182   // disable SD and Ethernet ports before setup
183   pinMode(SD_SELECT, OUTPUT);
184   digitalWrite(SD_SELECT, HIGH);                  // disable SD card
185   pinMode(ETHERNET_SELECT, OUTPUT);
186   digitalWrite(ETHERNET_SELECT, HIGH);           // disable Ethernet
187
188   // start SPI (because Ethernet shield needs it)
189   SPI.begin();                                          // start SPI
190
191   // start Ethernet
192   if (!(Ethernet.begin(mac) == 0))                    // start network
193     Serial.println(Ethernet.localIP());
194   else
195   {
196     #ifdef SERIAL_DEBUG
197     Serial.println(F("Network Error"));
198     #endif
199     while (1) ;
200   }
201   #ifdef ENABLE_UDP
202   if (! Udp.begin(1312)) {
203     #ifdef SERIAL_DEBUG
204     Serial.println(F("Failed to initiate UDP"));
205     #endif
206   }
207   #endif
208
209   // set mode for used pins
210   pinMode(RELAY_RED_LEDS, OUTPUT);
211   digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
212   pinMode(RELAY_YELLOW_LEDS, OUTPUT);
213   digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
214   pinMode(RELAY_GREEN_LEDS, OUTPUT);
215   digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
216   pinMode(RELAY_BUTTON_LEDS, OUTPUT);
217   digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
218
219   pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
220   digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
221   pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
222   digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
223
224   pinMode(BUTTON1, INPUT);
225   pinMode(BUTTON2, INPUT);
226   pinMode(NONSTOP_VIA_STUD1, INPUT);
227   pinMode(NONSTOP_VIA_STUD2, INPUT);
228
229   // configure web server pages
230   webserver.setDefaultCommand(&webCmd);
231
232   // start web server
233   webserver.begin();
234 }
235
236
237 // loop function
238 void loop()
239 {
240   // update variables indicating if non-stop is selected in studios 1&2
241   nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
242   if (nonstop_via_stud1 == 0)
243     nonstop_via_stud1 = 1;
244   else
245     nonstop_via_stud1 = 0;
246   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
247   if (nonstop_via_stud2 == 0)
248     nonstop_via_stud2 = 1;
249   else
250     nonstop_via_stud2 = 0;
251
252   // check if we have a HTTP request (and respond)
253   webserver.processConnection();
254
255   // handle button 1 (select button)
256   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
257   {
258     case nochange:
259       break;
260     case pressed:
261       #ifdef SERIAL_DEBUG
262       Serial.println(F("Button 1 pressed"));
263       #endif
264       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
265       blinkingSelection++;
266       blinkingStartTime = millis(),
267       blinkingAbortTime = millis();
268       blinkingLedState = RELAY_STATE_OPEN;
269       break;
270     case released:
271       #ifdef SERIAL_DEBUG
272       Serial.println(F("Button 1 released"));
273       #endif
274       break;
275   }
276
277   // handle button 2 (confirm button)
278   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
279   {
280     case nochange:
281       break;
282     case pressed:
283       #ifdef SERIAL_DEBUG
284       Serial.println(F("Button 2 pressed"));
285       #endif
286       blinkingAbortTime = 0;        // disable blinking auto abort
287       break;
288     case released:
289       #ifdef SERIAL_DEBUG
290       Serial.println(F("Button 2 released"));
291       #endif
292       if (activeSelection != blinkingSelection)
293       {
294         char str_selection[20];
295         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
296         activeSelection = blinkingSelection;  // relay states must be changed now
297         #ifdef SERIAL_DEBUG
298         Serial.print(F("Active Selection: "));
299         Serial.println(activeSelection);
300         #endif
301         #ifdef ENABLE_UDP
302         // notify over UDP
303         snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
304         #ifdef SERIAL_DEBUG
305         Serial.println(F("Sending UDP... "));
306         Serial.println(str_selection);
307         #endif
308         Udp.beginPacket(udp_remote_ip, 1312);
309         Udp.write(str_selection);
310         Udp.endPacket();
311         #endif
312         break;
313       }
314   }
315
316   // handle auto abort for blinking led (if any)
317   if ( (blinkingAbortTime != 0) &&
318        ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
319     digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
320     blinkingAbortTime = 0;
321     blinkingSelection = activeSelection;
322   }
323
324   // handle blinking led (if selected is not current state)
325   if (activeSelection != blinkingSelection) {
326     if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
327       digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
328       digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
329       blinkingStartTime = millis();
330       blinkingLedState = !blinkingLedState;
331     }
332   }
333   else {
334     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
335   }
336
337   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
338
339   // update audio channel relays
340   if (activeSelection == nonstop)
341   {
342     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
343     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
344   }
345   else if (activeSelection == studio1)
346   {
347     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
348     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
349   }
350   else if (activeSelection == studio2)
351   {
352     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
353     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
354   }
355 }
356
357 buttonEvent_t debounce( const uint8_t buttonPin,
358                         uint8_t *buttonState,
359                         unsigned long *buttonLastEventTime )
360 {
361   uint8_t buttonLastState = *buttonState;
362   uint8_t buttonReading = digitalRead(buttonPin);
363
364   if ( (*buttonLastEventTime == 0) &&
365        (*buttonState != buttonReading) ) {
366     // something happened, start the debouncing process
367     *buttonLastEventTime = millis();
368   }
369
370   if (*buttonLastEventTime != 0) {
371     long buttonEventTimer = millis() - *buttonLastEventTime;
372
373     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
374          (*buttonState == buttonReading) ) {
375       // noise or bouncing, abort
376       *buttonLastEventTime = 0;
377     }
378
379     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
380          (buttonReading != *buttonState) ) {
381       // new button state was maintained
382       *buttonLastEventTime = 0;
383       *buttonState = buttonReading;
384     }
385   }
386
387   // debouncing finished, return button state
388   if (*buttonLastEventTime == 0) {
389     // comparing buttonState and buttonLastState tells whether the
390     // button is pressed or released
391     if ( (*buttonState == HIGH) &&
392          (buttonLastState == LOW) ) {
393       // button just pressed
394       buttonLastState = *buttonState;
395       return pressed;
396     }
397     if ( (*buttonState == LOW) &&
398          (buttonLastState == HIGH) ) {
399       // button just released
400       buttonLastState = *buttonState;
401       return released;
402     }
403   }
404   return nochange;
405 }