]> git.0d.be Git - PanikSwitch.git/blob - FINAL2013V2.ino
put udp code behind ENABLE_UDP #define
[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 __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         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;
137       }
138     }
139   }
140
141   server.println(F("{"));
142
143   server.print(" \"response\": ");
144   server.print(response_status);
145
146   server.print(",\n \"active\": ");
147   server.print(activeSelection);
148
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);
153
154   server.println(F("}"));
155 }
156
157
158 // setup function
159 void setup()
160 {
161   // make sure that activeSelection holds something valid
162 //  if (!(activeSelection > nonstop) || !(activeSelection < _NbrSwitchSelections))
163 //    activeSelection = nonstop;
164   blinkingSelection = activeSelection = nonstop;
165
166   // open serial communication for debugging
167   Serial.begin(9600);
168   Serial.println(F("Startup"));
169
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
175
176   // start SPI (because Ethernet shield needs it)
177   SPI.begin();                                          // start SPI
178
179   // start Ethernet
180   if (!(Ethernet.begin(mac) == 0))                    // start network
181     Serial.println(Ethernet.localIP());
182   else
183   {
184     #ifdef SERIAL_DEBUG
185     Serial.println(F("Network Error"));
186     #endif
187     while (1) ;
188   }
189   #ifdef ENABLE_UDP
190   if (! Udp.begin(1312)) {
191     #ifdef SERIAL_DEBUG
192     Serial.println(F("Failed to initiate UDP"));
193     #endif
194   }
195   #endif
196
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);
206
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);
211
212   pinMode(BUTTON1, INPUT);
213   pinMode(BUTTON2, INPUT);
214   pinMode(NONSTOP_VIA_STUD1, INPUT);
215   pinMode(NONSTOP_VIA_STUD2, INPUT);
216
217   // configure web server pages
218   webserver.setDefaultCommand(&webCmd);
219
220   // start web server
221   webserver.begin();
222 }
223
224
225 // loop function
226 void loop()
227 {
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;
232   else
233     nonstop_via_stud1 = 0;
234   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
235   if (nonstop_via_stud2 == 0)
236     nonstop_via_stud2 = 1;
237   else
238     nonstop_via_stud2 = 0;
239
240   // check if we have a HTTP request (and respond)
241   webserver.processConnection();
242
243   // handle button 1 (select button)
244   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
245   {
246     case nochange:
247       break;
248     case pressed:
249       #ifdef SERIAL_DEBUG
250       Serial.println(F("Button 1 pressed"));
251       #endif
252       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
253       blinkingSelection++;
254       blinkingStartTime = millis(),
255       blinkingAbortTime = millis();
256       blinkingLedState = RELAY_STATE_OPEN;
257       break;
258     case released:
259       #ifdef SERIAL_DEBUG
260       Serial.println(F("Button 1 released"));
261       #endif
262       break;
263   }
264
265   // handle button 2 (confirm button)
266   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
267   {
268     case nochange:
269       break;
270     case pressed:
271       #ifdef SERIAL_DEBUG
272       Serial.println(F("Button 2 pressed"));
273       #endif
274       blinkingAbortTime = 0;        // disable blinking auto abort
275       break;
276     case released:
277       #ifdef SERIAL_DEBUG
278       Serial.println(F("Button 2 released"));
279       #endif
280       if (activeSelection != blinkingSelection)
281       {
282         char str_selection[20];
283         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
284         activeSelection = blinkingSelection;  // relay states must be changed now
285         #ifdef SERIAL_DEBUG
286         Serial.print(F("Active Selection: "));
287         Serial.println(activeSelection);
288         #endif
289         #ifdef ENABLE_UDP
290         // notify over UDP
291         snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
292         Udp.beginPacket(udp_remote_ip, 1312);
293         Udp.write(str_selection);
294         Udp.endPacket();
295         #endif
296         break;
297       }
298   }
299
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;
306   }
307
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;
315     }
316   }
317   else {
318     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
319   }
320
321   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
322
323   // update audio channel relays
324   if (activeSelection == nonstop)
325   {
326     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
327     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
328   }
329   else if (activeSelection == studio1)
330   {
331     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
332     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
333   }
334   else if (activeSelection == studio2)
335   {
336     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
337     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
338   }
339 }
340
341 buttonEvent_t debounce( const uint8_t buttonPin,
342                         uint8_t *buttonState,
343                         unsigned long *buttonLastEventTime )
344 {
345   uint8_t buttonLastState = *buttonState;
346   uint8_t buttonReading = digitalRead(buttonPin);
347
348   if ( (*buttonLastEventTime == 0) &&
349        (*buttonState != buttonReading) ) {
350     // something happened, start the debouncing process
351     *buttonLastEventTime = millis();
352   }
353
354   if (*buttonLastEventTime != 0) {
355     long buttonEventTimer = millis() - *buttonLastEventTime;
356
357     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
358          (*buttonState == buttonReading) ) {
359       // noise or bouncing, abort
360       *buttonLastEventTime = 0;
361     }
362
363     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
364          (buttonReading != *buttonState) ) {
365       // new button state was maintained
366       *buttonLastEventTime = 0;
367       *buttonState = buttonReading;
368     }
369   }
370
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;
379       return pressed;
380     }
381     if ( (*buttonState == LOW) &&
382          (buttonLastState == HIGH) ) {
383       // button just released
384       buttonLastState = *buttonState;
385       return released;
386     }
387   }
388   return nochange;
389 }