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