New Sensor Events
[svn42.git] / rf433ctl / rf433ctl.pde
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <inttypes.h>
4 #include <OneWire.h>
5 #include <DallasTemperature.h>
6
7 //********************************************************************//
8
9 #define RF_DATA_OUT_PIN 13
10 #define IR_MOVEMENT_PIN 9
11 #define ONE_WIRE_PIN 8
12 #define PANIC_BUTTON_PIN 7
13 #define BLUELED_PWM_PIN 6
14 #define PHOTO_ANALOGPIN 0
15 //movement is reported if during IR_SAMPLE_DURATION at least IR_TRESHOLD ir signals are detectd
16 #define IR_SAMPLE_DURATION 20000
17 #define IR_TRESHOLD 13000
18 //duration PanicButton needs to be pressed before status change occurs (i.e. for two PanicButton Reports, the buttons needs to be pressed 1000 cycles, releases 1000 cycles and again pressed 1000 cycles)
19 #define PB_TRESHOLD 1000
20 #define PHOTO_SAMPLE_INTERVAL 4000
21
22 OneWire  onewire(ONE_WIRE_PIN);
23 DallasTemperature dallas_sensors(&onewire);
24 DeviceAddress onShieldTemp = { 0x10, 0xE7, 0x77, 0xD3, 0x01, 0x08, 0x00, 0x3F };
25 #define TEMPC_OFFSET_ARDUINO_GENEREATED_HEAT -4.0
26
27 typedef struct {
28   byte offset;
29   byte state;
30 } rf_bit_t;
31
32 // offset is number of alphas (0.08ms)
33
34 const rf_bit_t zero_bit[] = { {  4, 1 },
35                               { 16, 0 },
36                               { 20, 1 },
37                               { 32, 0 },
38                               {  0, 0 } };
39
40 const rf_bit_t one_bit[] = { { 12, 1 },
41                              { 16, 0 },
42                              { 28, 1 },
43                              { 32, 0 },
44                              {  0, 0 } };
45
46 const rf_bit_t float_bit[] = { {  4, 1 },
47                                { 16, 0 },
48                                { 28, 1 },
49                                { 32, 0 },
50                                {  0, 0 } };
51
52 const rf_bit_t sync_bit[] = { {   4, 1 },
53                               { 128, 0 },
54                               {   0, 0 } };
55
56 typedef enum { ZERO = 0, ONE , FLOAT , SYNC } adbit_t;
57 typedef byte ad_bit_t;
58 #define WORD_LEN 13
59 typedef ad_bit_t word_t[WORD_LEN];
60
61 const rf_bit_t* bit_defs[] = { zero_bit, one_bit, float_bit, sync_bit };
62
63 byte alpha_cnt = 0;
64 byte bit_cnt = 0;
65 byte chunk_cnt = 0;
66 byte word_cnt = 0;
67 const ad_bit_t* current_word;
68 byte volatile frame_finished = 1;
69
70 #define FRAME_LEN 8
71
72 #define A1_ON  0
73 #define A1_OFF 1
74 #define A2_ON  2
75 #define A2_OFF 3
76
77 #define B1_ON  4
78 #define B1_OFF 5
79 #define B2_ON  6
80 #define B2_OFF 7
81
82 #define C1_ON  8
83 #define C1_OFF 9
84 #define C2_ON  10
85 #define C2_OFF 11
86
87 #define D1_ON  12
88 #define D1_OFF 13
89 #define D2_ON  14
90 #define D2_OFF 15
91
92 const word_t words[]  = { 
93 { ZERO,  ZERO,  FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // A1_ON
94 { ZERO,  ZERO,  FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // A1_OFF
95 { ZERO,  ZERO,  FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // A2_ON
96 { ZERO,  ZERO,  FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // A2_OFF
97
98 { FLOAT, ZERO,  FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // B1_ON
99 { FLOAT, ZERO,  FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // B1_OFF
100 { FLOAT, ZERO,  FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // B2_ON
101 { FLOAT, ZERO,  FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // B2_OFF
102
103 { ZERO,  FLOAT, FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // C1_ON
104 { ZERO,  FLOAT, FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // C1_OFF
105 { ZERO,  FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // C2_ON
106 { ZERO,  FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // C2_OFF
107
108 { FLOAT, FLOAT, FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // D1_ON
109 { FLOAT, FLOAT, FLOAT, FLOAT, ZERO,  ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }, // D1_OFF
110 { FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // D2_ON
111 { FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO,  SYNC }  // D2_OFF
112 };
113
114
115 //********************************************************************//
116
117 void start_timer()
118 {
119   // timer 1: 2 ms
120   TCCR1A = 0;                    // prescaler 1:8, WGM = 4 (CTC)
121   TCCR1B = 1<<WGM12 | 1<<CS11;   // 
122   OCR1A = 159;        // (1+159)*8 = 1280 -> 0.08ms @ 16 MHz -> 1*alpha
123 //  OCR1A = 207;        // (1+207)*8 = 1664 -> 0.104ms @ 16 MHz -> 1*alpha
124   TCNT1 = 0;          // reseting timer
125   TIMSK1 = 1<<OCIE1A; // enable Interrupt
126 }
127
128 void stop_timer() // stop the timer
129 {
130   // timer1
131   TCCR1B = 0; // no clock source
132   TIMSK1 = 0; // disable timer interrupt
133 }
134
135 void init_word(const word_t w)
136 {
137   current_word = w;
138   alpha_cnt = 0;
139   chunk_cnt = 0;
140   bit_cnt = 0;
141
142   if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
143     digitalWrite(RF_DATA_OUT_PIN, HIGH);
144   else
145     digitalWrite(RF_DATA_OUT_PIN, LOW);
146
147   start_timer();
148 }
149
150 ISR(TIMER1_COMPA_vect)
151 {
152   alpha_cnt++;
153   if(alpha_cnt < bit_defs[current_word[bit_cnt]][chunk_cnt].offset)
154     return;
155
156   chunk_cnt++;
157   if(bit_defs[current_word[bit_cnt]][chunk_cnt].offset != 0) {
158     if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
159       digitalWrite(RF_DATA_OUT_PIN, HIGH);
160     else
161       digitalWrite(RF_DATA_OUT_PIN, LOW);
162     return;
163   }
164   
165   bit_cnt++;
166   if(bit_cnt < WORD_LEN) {
167     alpha_cnt = 0;
168     chunk_cnt = 0;
169     if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
170       digitalWrite(RF_DATA_OUT_PIN, HIGH);
171     else
172       digitalWrite(RF_DATA_OUT_PIN, LOW);
173     return;
174   }
175   stop_timer();
176   digitalWrite(RF_DATA_OUT_PIN, LOW);
177
178   word_cnt++;
179   if(word_cnt < FRAME_LEN)
180     init_word(current_word);
181
182   frame_finished = 1;
183 }
184
185 //***********//
186
187
188 void send_frame(const word_t w)
189 {
190   word_cnt = 0;
191   frame_finished = 0;
192   init_word(w);
193
194   for(;;)
195     if(frame_finished)
196       break;
197
198   Serial.println("Ok");
199 }
200
201 //********************************************************************//
202
203 void printTemperature(DeviceAddress deviceAddress)
204 {
205   dallas_sensors.requestTemperatures();
206   float tempC = dallas_sensors.getTempC(deviceAddress);
207   Serial.print("Temp C: ");
208   Serial.println(tempC TEMPC_OFFSET_ARDUINO_GENEREATED_HEAT);
209   //Serial.print(" Temp F: ");
210   //Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
211 }
212
213 //********************************************************************//
214
215 unsigned int light_level_mean_ = 0;
216 unsigned int light_sample_time_ = 0;
217
218 void updateLightLevel(unsigned int pin)
219 {
220   light_sample_time_++;
221   if (light_sample_time_ < PHOTO_SAMPLE_INTERVAL)
222     return;
223   light_sample_time_ = 0;
224   
225   unsigned int value = analogRead(pin);
226   if (value == light_level_mean_)
227     return;
228   
229   unsigned int diff = abs(value - light_level_mean_);
230   if (light_level_mean_ < 6 || diff > 250)
231     light_level_mean_ = value;
232   else
233       light_level_mean_=(unsigned int) ( ((float) light_level_mean_) * 0.98 + ((float)value)*0.02 );
234 }
235
236 void printLightLevel()
237 {
238   Serial.print("Photo: ");
239   Serial.println(light_level_mean_);
240 }
241
242 //********************************************************************//
243
244 unsigned long wm_start_=0;
245 bool wait_millis(unsigned long ms)
246 {
247   if (wm_start_ > 0)
248   {
249     if (millis() < wm_start_ || millis() > wm_start_+ ms)
250     {
251       wm_start_=0;
252       return false;
253     }
254     else
255       return true;
256   }
257   else
258   {
259     wm_start_=millis();
260     return true;
261   }
262 }
263
264 unsigned int flash_led_time_=0;
265 void calculate_led_level(unsigned int pwm_pin)
266 {
267   if (flash_led_time_ == 0)
268     return;
269   if (wait_millis(10))
270     return;
271   flash_led_time_--;
272   int c = abs(sin(float(flash_led_time_) / 100.0)) * 256;
273   analogWrite(pwm_pin,c);
274 }
275
276 void flash_led(int times)
277 {
278   flash_led_time_ += 314*times;
279 }
280
281 //********************************************************************//
282
283 void setup()
284 {
285   pinMode(RF_DATA_OUT_PIN, OUTPUT);
286   digitalWrite(RF_DATA_OUT_PIN, LOW);
287   pinMode(IR_MOVEMENT_PIN, INPUT);      // set pin to input
288   digitalWrite(IR_MOVEMENT_PIN, LOW);  // turn off pullup resistors  
289   pinMode(PANIC_BUTTON_PIN, INPUT);      // set pin to input
290   digitalWrite(PANIC_BUTTON_PIN, HIGH);  // turn on pullup resistors 
291   analogWrite(BLUELED_PWM_PIN,0);
292
293   Serial.begin(9600);
294   
295   onewire.reset();
296   onewire.reset_search();
297   dallas_sensors.begin();
298   //in case we change temp sensor:
299   if (!dallas_sensors.getAddress(onShieldTemp, 0)) 
300     Serial.println("Error: Unable to find address for Device 0"); 
301   dallas_sensors.setResolution(onShieldTemp, 9);  
302 }
303
304 unsigned int ir_time=IR_SAMPLE_DURATION;
305 unsigned int ir_count=0;
306 boolean pb_last_state=0;
307 boolean pb_state=0;
308 boolean pb_postth_state=0;
309 unsigned int pb_time=0;
310
311 void sensorEchoCommand(char command)
312 {
313   Serial.print("Sensor ");
314   Serial.print(command);
315   Serial.print(": ");
316 }
317
318 void loop()
319 {
320   ir_time--;
321   ir_count += (digitalRead(IR_MOVEMENT_PIN) == HIGH);
322
323   if (pb_time < PB_TRESHOLD)
324     pb_time++;
325   pb_state=(digitalRead(PANIC_BUTTON_PIN) == LOW);
326   
327   if (ir_time == 0)
328   {
329     if (ir_count >= IR_TRESHOLD)
330     {
331       flash_led(1);
332       Serial.println("movement");
333     }
334     ir_time=IR_SAMPLE_DURATION;
335     ir_count=0;
336   }
337   
338   if (pb_state == pb_last_state && pb_time >= PB_TRESHOLD)
339   {
340     if (pb_state && ! pb_postth_state)
341     {   
342       pb_postth_state=1;
343       Serial.println("PanicButton");
344       flash_led(4);
345     }
346     else if (!pb_state)
347       pb_postth_state=0;
348   }
349   else if (pb_state != pb_last_state)
350   {
351     pb_time=0;
352     pb_last_state=pb_state;
353   }
354   
355   updateLightLevel(PHOTO_ANALOGPIN);
356   calculate_led_level(BLUELED_PWM_PIN);
357   
358   if(Serial.available()) {
359     char command = Serial.read();
360     
361     if(command == 'A')
362       send_frame(words[A1_ON]);
363     else if(command == 'a')
364       send_frame(words[A1_OFF]);
365     else if(command == 'B')
366       send_frame(words[A2_ON]);
367     else if(command == 'b')
368       send_frame(words[A2_OFF]);
369
370     else if(command == 'C')
371       send_frame(words[B1_ON]);
372     else if(command == 'c')
373       send_frame(words[B1_OFF]);
374     else if(command == 'D')
375       send_frame(words[B2_ON]);
376     else if(command == 'd')
377       send_frame(words[B2_OFF]);
378
379     else if(command == 'E')
380       send_frame(words[C1_ON]);
381     else if(command == 'e')
382       send_frame(words[C1_OFF]);
383     else if(command == 'F')
384       send_frame(words[C2_ON]);
385     else if(command == 'f')
386       send_frame(words[C2_OFF]);
387
388     else if(command == 'G')
389       send_frame(words[D1_ON]);
390     else if(command == 'g')
391       send_frame(words[D1_OFF]);
392     else if(command == 'H')
393       send_frame(words[D2_ON]);
394     else if(command == 'h')
395       send_frame(words[D2_OFF]);
396     else if(command == 'T')
397     {
398       sensorEchoCommand(command);
399       printTemperature(onShieldTemp);
400     }
401     else if(command == 'P')
402     {
403       sensorEchoCommand(command);
404       printLightLevel();
405     }
406     else
407       Serial.println("Error: unknown command");
408   }
409 }