webserver: update with latest upstream code
[PanikSwitch.git] / FINAL2013V2.ino
1 // Panik Web Form Demo
2
3
4
5 // define network constants
6 #define MAC_DAVID { 0x90, 0xA2, 0xDA, 0x0D, 0xF4, 0x63 }
7 #define MAC_PANIK { 0x90, 0xA2, 0xDA, 0x00, 0x9A, 0x94 }
8 #define MAC_PANIK2 { 0x90, 0xA2, 0xDA, 0x0E, 0xF3, 0x77 }
9 #define MAC_ADDRESS MAC_PANIK
10
11
12 // include Arduino libraries
13 #include <Wire.h>
14 #include <SPI.h>
15 #include <SD.h>
16 #include <Ethernet.h>
17
18 // include third party libraries
19 #include "WebServer.h"
20
21 // include in-house libs
22 #include "PanikSwitch.h"    // contains variable types for panik switch
23
24 // define SD and Ethernet select ports
25 #define  SD_SELECT            4
26 #define  ETHERNET_SELECT     10
27
28 // define machine variables
29 #define DEBOUNCE_TRESHOLD     10   // 10 milliseconds
30 #define ABORT_TRESHOLD     3000L   // 3 seconds
31 #define PULSE_TRESHOLD        50   // 50 milliseconds
32 #define BLINK_TRESHOLD       100   // 100 milliseconds
33
34 // output pins
35 #define RELAY_BUTTON_LEDS        5   // Button LED indicator
36 #define RELAY_GREEN_LEDS         6   // ``Non-Stop`` LED indicator
37 #define RELAY_RED_LEDS           8   // ``Studio 1`` LED indicator
38 #define RELAY_YELLOW_LEDS        7   // ``Studio 2`` LED indicator
39
40 #define RELAY_NONSTOP_OR_STUD    4   // Relay : Non-stop or Studio
41 #define RELAY_STUD1_OR_STUD2     9   // Relay : Studio 1 or Studio 2
42
43 // input pins
44 #define BUTTON1                  2   // ``Select`` button
45 #define BUTTON2                  3   // ``Confirm`` button
46 #define NONSTOP_VIA_STUD1       14   // is nonstop coming out of studio 1
47 #define NONSTOP_VIA_STUD2       15   // is nonstop coming out of studio 2
48
49
50
51 /* define an array with led pins,
52    indexes in that array correspond to the values of possible selections
53    i.e.: RELAY_GREEN_LEDS: nonstop, RELAY_RED_LEDS: studio1, RELAY_YELLOW_LEDS: studio2
54 */
55 const int ledsArray[] = { RELAY_GREEN_LEDS, RELAY_RED_LEDS, RELAY_YELLOW_LEDS };
56
57
58 /* activeSelection is the variable that holds the active output of the switch
59    it is declared as an attribute that keeps its value between arduino resets
60 */
61 switchSelection_t activeSelection __attribute__ ((section (".noinit")));
62
63 // variables and timers for blinking selection (selected but not confirmed)
64 switchSelection_t blinkingSelection = nonstop;
65 bool blinkingLedState = RELAY_STATE_CLOSED;
66 unsigned long blinkingStartTime = 0, blinkingAbortTime = 0;
67
68
69 // declaration of possible button states as enum type
70 typedef enum { nochange, pressed, released } buttonEvent_t;
71
72 // button event timers
73 unsigned long button1LastEventTime = 0, button2LastEventTime = 0;
74
75 // variables holding the state of each button
76 // these are used during the debouncing process
77 uint8_t button1State = LOW, button2State = LOW;
78
79 // variables holding the non-stop status from studios 1 & 2
80 bool nonstop_via_stud1, nonstop_via_stud2;
81
82 // declare functions
83 buttonEvent_t debounce( const uint8_t buttonPin,
84                         uint8_t *buttonState,
85                         unsigned long *buttonLastEventTime );
86
87 static uint8_t mac[] = MAC_ADDRESS;
88 #define PREFIX ""
89
90 // instanciate web server
91 WebServer webserver(PREFIX, 80);
92
93 #define NAMELEN 4
94 #define VALUELEN 4
95
96 typedef enum responseStatus { NO_POST, POST_OK, POST_ERROR };
97
98
99 // web resource
100 void webCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
101 {
102
103   server.httpSuccess("application/json");
104
105   if (type == WebServer::HEAD)
106     return;
107
108   responseStatus response_status = NO_POST;
109
110   if (type == WebServer::POST)
111   {
112     return;
113     char name[NAMELEN];
114     int  name_len;
115     char value[VALUELEN];
116     int value_len;
117
118     response_status = POST_ERROR;
119
120     while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
121     {
122       if (strcmp(name, "s") == 0) {
123         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
124         blinkingSelection = static_cast<switchSelection_t>(atoi(value));
125         activeSelection = static_cast<switchSelection_t>(atoi(value));
126         response_status = POST_OK;
127       }
128     }
129   }
130
131   server.println(F("{"));
132
133   server.print(" \"response\": ");
134   server.print(response_status);
135
136   server.print(",\n \"active\": ");
137   server.print(activeSelection);
138
139   server.print(",\n \"nonstop-via-stud1\": ");
140   server.print(nonstop_via_stud1);
141   server.print(",\n \"nonstop-via-stud2\": ");
142   server.println(nonstop_via_stud2);
143
144   server.println(F("}"));
145 }
146
147
148 // setup function
149 void setup()
150 {
151   // make sure that activeSelection holds something valid
152 //  if (!(activeSelection > nonstop) || !(activeSelection < _NbrSwitchSelections))
153 //    activeSelection = nonstop;
154   blinkingSelection = activeSelection = nonstop;
155
156   // open serial communication for debugging
157   Serial.begin(9600);
158   Serial.println(F("Startup"));
159
160   // disable SD and Ethernet ports before setup
161   pinMode(SD_SELECT, OUTPUT);
162   digitalWrite(SD_SELECT, HIGH);                  // disable SD card
163   pinMode(ETHERNET_SELECT, OUTPUT);
164   digitalWrite(ETHERNET_SELECT, HIGH);           // disable Ethernet
165
166   // start SPI (because Ethernet shield needs it)
167   SPI.begin();                                          // start SPI
168
169   // start Ethernet
170   if (!(Ethernet.begin(mac) == 0))                    // start network
171     Serial.println(Ethernet.localIP());
172   else
173   {
174     Serial.println(F("Network Error"));
175     while (1) ;
176   }
177
178   // set mode for used pins
179   pinMode(RELAY_RED_LEDS, OUTPUT);
180   digitalWrite(RELAY_RED_LEDS, RELAY_STATE_CLOSED);
181   pinMode(RELAY_YELLOW_LEDS, OUTPUT);
182   digitalWrite(RELAY_YELLOW_LEDS, RELAY_STATE_CLOSED);
183   pinMode(RELAY_GREEN_LEDS, OUTPUT);
184   digitalWrite(RELAY_GREEN_LEDS, RELAY_STATE_CLOSED);
185   pinMode(RELAY_BUTTON_LEDS, OUTPUT);
186   digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
187
188   pinMode(RELAY_NONSTOP_OR_STUD, OUTPUT);
189   digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
190   pinMode(RELAY_STUD1_OR_STUD2, OUTPUT);
191   digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
192
193   pinMode(BUTTON1, INPUT);
194   pinMode(BUTTON2, INPUT);
195   pinMode(NONSTOP_VIA_STUD1, INPUT);
196   pinMode(NONSTOP_VIA_STUD2, INPUT);
197
198   // configure web server pages
199   webserver.setDefaultCommand(&webCmd);
200
201   // start web server
202   webserver.begin();
203 }
204
205
206 // loop function
207 void loop()
208 {
209   // update variables indicating if non-stop is selected in studios 1&2
210   nonstop_via_stud1 = digitalRead(NONSTOP_VIA_STUD1);
211   if (nonstop_via_stud1 == 0)
212     nonstop_via_stud1 = 1;
213   else
214     nonstop_via_stud1 = 0;
215   nonstop_via_stud2 = digitalRead(NONSTOP_VIA_STUD2);
216   if (nonstop_via_stud2 == 0)
217     nonstop_via_stud2 = 1;
218   else
219     nonstop_via_stud2 = 0;
220
221   // check if we have a HTTP request (and respond)
222   webserver.processConnection();
223
224   // handle button 1 (select button)
225   switch ( debounce(BUTTON1, &button1State, &button1LastEventTime) )
226   {
227     case nochange:
228       break;
229     case pressed:
230       //Serial.println(F("Button 1 pressed"));
231       digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
232       blinkingSelection++;
233       blinkingStartTime = millis(),
234       blinkingAbortTime = millis();
235       blinkingLedState = RELAY_STATE_OPEN;
236       break;
237     case released:
238       //Serial.println(F("Button 1 released"));
239       break;
240   }
241
242   // handle button 2 (confirm button)
243   switch ( debounce(BUTTON2, &button2State, &button2LastEventTime) )
244   {
245     case nochange:
246       break;
247     case pressed:
248       //Serial.println(F("Button 2 pressed"));
249       blinkingAbortTime = 0;        // disable blinking auto abort
250       break;
251     case released:
252       //Serial.println(F("Button 2 released"));
253       if (activeSelection != blinkingSelection)
254       {
255         digitalWrite(ledsArray[activeSelection], RELAY_STATE_CLOSED);
256         activeSelection = blinkingSelection;  // relay states must be changed now
257         Serial.print(F("Active Selection: "));
258         Serial.println(activeSelection);
259         break;
260       }
261   }
262
263   // handle auto abort for blinking led (if any)
264   if ( (blinkingAbortTime != 0) &&
265        ((millis() - blinkingAbortTime) >= ABORT_TRESHOLD) ) {
266     digitalWrite(ledsArray[blinkingSelection], RELAY_STATE_CLOSED);
267     blinkingAbortTime = 0;
268     blinkingSelection = activeSelection;
269   }
270
271   // handle blinking led (if selected is not current state)
272   if (activeSelection != blinkingSelection) {
273     if ((millis() - blinkingStartTime) >= BLINK_TRESHOLD) {
274       digitalWrite(ledsArray[blinkingSelection], blinkingLedState);
275       digitalWrite(RELAY_BUTTON_LEDS, !blinkingLedState);
276       blinkingStartTime = millis();
277       blinkingLedState = !blinkingLedState;
278     }
279   }
280   else {
281     digitalWrite(RELAY_BUTTON_LEDS, RELAY_STATE_CLOSED);
282   }
283
284   digitalWrite(ledsArray[activeSelection], RELAY_STATE_OPEN);
285
286   // update audio channel relays
287   if (activeSelection == nonstop)
288   {
289     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_CLOSED);
290     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
291   }
292   else if (activeSelection == studio1)
293   {
294     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
295     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_CLOSED);
296   }
297   else if (activeSelection == studio2)
298   {
299     digitalWrite(RELAY_NONSTOP_OR_STUD, RELAY_STATE_OPEN);
300     digitalWrite(RELAY_STUD1_OR_STUD2, RELAY_STATE_OPEN);
301   }
302 }
303
304 buttonEvent_t debounce( const uint8_t buttonPin,
305                         uint8_t *buttonState,
306                         unsigned long *buttonLastEventTime )
307 {
308   uint8_t buttonLastState = *buttonState;
309   uint8_t buttonReading = digitalRead(buttonPin);
310
311   if ( (*buttonLastEventTime == 0) &&
312        (*buttonState != buttonReading) ) {
313     // something happened, start the debouncing process
314     *buttonLastEventTime = millis();
315   }
316
317   if (*buttonLastEventTime != 0) {
318     long buttonEventTimer = millis() - *buttonLastEventTime;
319
320     if ( (buttonEventTimer < DEBOUNCE_TRESHOLD) &&
321          (*buttonState == buttonReading) ) {
322       // noise or bouncing, abort
323       *buttonLastEventTime = 0;
324     }
325
326     if ( (buttonEventTimer >= DEBOUNCE_TRESHOLD) &&
327          (buttonReading != *buttonState) ) {
328       // new button state was maintained
329       *buttonLastEventTime = 0;
330       *buttonState = buttonReading;
331     }
332   }
333
334   // debouncing finished, return button state
335   if (*buttonLastEventTime == 0) {
336     // comparing buttonState and buttonLastState tells whether the
337     // button is pressed or released
338     if ( (*buttonState == HIGH) &&
339          (buttonLastState == LOW) ) {
340       // button just pressed
341       buttonLastState = *buttonState;
342       return pressed;
343     }
344     if ( (*buttonState == LOW) &&
345          (buttonLastState == HIGH) ) {
346       // button just released
347       buttonLastState = *buttonState;
348       return released;
349     }
350   }
351   return nochange;
352 }
353