]> git.0d.be Git - PanikSwitch.git/blob - FINAL2013V2.ino
always enable nonstop on boot
[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         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   blinkingSelection = activeSelection = nonstop;
162
163   // open serial communication for debugging
164   Serial.begin(9600);
165   Serial.println(F("Startup"));
166
167   // disable SD and Ethernet ports before setup
168   pinMode(SD_SELECT, OUTPUT);
169   digitalWrite(SD_SELECT, HIGH);                  // disable SD card
170   pinMode(ETHERNET_SELECT, OUTPUT);
171   digitalWrite(ETHERNET_SELECT, HIGH);           // disable Ethernet
172
173   // start SPI (because Ethernet shield needs it)
174   SPI.begin();                                          // start SPI
175
176   // start Ethernet
177   if (!(Ethernet.begin(mac) == 0))                    // start network
178     Serial.println(Ethernet.localIP());
179   else
180   {
181     #ifdef SERIAL_DEBUG
182     Serial.println(F("Network Error"));
183     #endif
184     while (1) ;
185   }
186   #ifdef ENABLE_UDP
187   if (! Udp.begin(1312)) {
188     #ifdef SERIAL_DEBUG
189     Serial.println(F("Failed to initiate UDP"));
190     #endif
191   }
192   #endif
193
194   // set mode for used pins
195   pinMode(RELAY_RED_LEDS, OUTPUT);
196   digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
197   pinMode(RELAY_YELLOW_LEDS, OUTPUT);
198   digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
199   pinMode(RELAY_GREEN_LEDS, OUTPUT);
200   digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
201   pinMode(RELAY_BUTTON_LEDS, OUTPUT);
202   digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
203
204   pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
205   digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
206   pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
207   digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
208
209   pinMode(BUTTON1, INPUT);
210   pinMode(BUTTON2, INPUT);
211   pinMode(NONSTOP_VIA_STUD1, INPUT);
212   pinMode(NONSTOP_VIA_STUD2, INPUT);
213
214   // configure web server pages
215   webserver.setDefaultCommand(&webCmd);
216
217   // start web server
218   webserver.begin();
219 }
220
221
222 // loop function
223 void loop()
224 {
225   // update variables indicating if non-stop is selected in studios 1&2
226   nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
227   if (nonstop_via_stud1 == 0)
228     nonstop_via_stud1 = 1;
229   else
230     nonstop_via_stud1 = 0;
231   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
232   if (nonstop_via_stud2 == 0)
233     nonstop_via_stud2 = 1;
234   else
235     nonstop_via_stud2 = 0;
236
237   // check if we have a HTTP request (and respond)
238   webserver.processConnection();
239
240   // handle button 1 (select button)
241   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
242   {
243     case nochange:
244       break;
245     case pressed:
246       #ifdef SERIAL_DEBUG
247       Serial.println(F("Button 1 pressed"));
248       #endif
249       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
250       blinkingSelection++;
251       blinkingStartTime = millis(),
252       blinkingAbortTime = millis();
253       blinkingLedState = RELAY_STATE_OPEN;
254       break;
255     case released:
256       #ifdef SERIAL_DEBUG
257       Serial.println(F("Button 1 released"));
258       #endif
259       break;
260   }
261
262   // handle button 2 (confirm button)
263   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
264   {
265     case nochange:
266       break;
267     case pressed:
268       #ifdef SERIAL_DEBUG
269       Serial.println(F("Button 2 pressed"));
270       #endif
271       blinkingAbortTime = 0;        // disable blinking auto abort
272       break;
273     case released:
274       #ifdef SERIAL_DEBUG
275       Serial.println(F("Button 2 released"));
276       #endif
277       if (activeSelection != blinkingSelection)
278       {
279         char str_selection[20];
280         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
281         activeSelection = blinkingSelection;  // relay states must be changed now
282         #ifdef SERIAL_DEBUG
283         Serial.print(F("Active Selection: "));
284         Serial.println(activeSelection);
285         #endif
286         #ifdef ENABLE_UDP
287         // notify over UDP
288         snprintf(str_selection, 19, "{\"active\": %d}", activeSelection);
289         Udp.beginPacket(udp_remote_ip, 1312);
290         Udp.write(str_selection);
291         Udp.endPacket();
292         #endif
293         break;
294       }
295   }
296
297   // handle auto abort for blinking led (if any)
298   if ( (blinkingAbortTime != 0) &&
299        ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
300     digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
301     blinkingAbortTime = 0;
302     blinkingSelection = activeSelection;
303   }
304
305   // handle blinking led (if selected is not current state)
306   if (activeSelection != blinkingSelection) {
307     if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
308       digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
309       digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
310       blinkingStartTime = millis();
311       blinkingLedState = !blinkingLedState;
312     }
313   }
314   else {
315     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
316   }
317
318   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
319
320   // update audio channel relays
321   if (activeSelection == nonstop)
322   {
323     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
324     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
325   }
326   else if (activeSelection == studio1)
327   {
328     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
329     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
330   }
331   else if (activeSelection == studio2)
332   {
333     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
334     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
335   }
336 }
337
338 buttonEvent_t debounce( const uint8_t buttonPin,
339                         uint8_t *buttonState,
340                         unsigned long *buttonLastEventTime )
341 {
342   uint8_t buttonLastState = *buttonState;
343   uint8_t buttonReading = digitalRead(buttonPin);
344
345   if ( (*buttonLastEventTime == 0) &&
346        (*buttonState != buttonReading) ) {
347     // something happened, start the debouncing process
348     *buttonLastEventTime = millis();
349   }
350
351   if (*buttonLastEventTime != 0) {
352     long buttonEventTimer = millis() - *buttonLastEventTime;
353
354     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
355          (*buttonState == buttonReading) ) {
356       // noise or bouncing, abort
357       *buttonLastEventTime = 0;
358     }
359
360     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
361          (buttonReading != *buttonState) ) {
362       // new button state was maintained
363       *buttonLastEventTime = 0;
364       *buttonState = buttonReading;
365     }
366   }
367
368   // debouncing finished, return button state
369   if (*buttonLastEventTime == 0) {
370     // comparing buttonState and buttonLastState tells whether the
371     // button is pressed or released
372     if ( (*buttonState == HIGH) &&
373          (buttonLastState == LOW) ) {
374       // button just pressed
375       buttonLastState = *buttonState;
376       return pressed;
377     }
378     if ( (*buttonState == LOW) &&
379          (buttonLastState == HIGH) ) {
380       // button just released
381       buttonLastState = *buttonState;
382       return released;
383     }
384   }
385   return nochange;
386 }