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