experimenting with diff led light levels
[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 15000
17 #define IR_TRESHOLD 10000
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 unsigned int flash_led_brightness_=256;
266 unsigned int flash_led_delay_=8;
267 void calculate_led_level(unsigned int pwm_pin)
268 {
269   if (flash_led_time_ == 0)
270     return;
271   if (wait_millis(flash_led_delay_))
272     return;
273   flash_led_time_--;
274   int c = abs(sin(float(flash_led_time_) / 100.0)) * flash_led_brightness_;
275   analogWrite(pwm_pin,c);
276 }
277
278 void flash_led(unsigned int times, unsigned int brightness_divisor, unsigned int delay_divisor)
279 {
280   flash_led_time_ += 314*times;
281   unsigned int new_flash_led_brightness=256/brightness_divisor;
282   unsigned int new_flash_led_delay = flash_led_delay_ / delay_divisor;
283   if (flash_led_time_ == 0 || new_flash_led_brightness > flash_led_brightness_)
284     flash_led_brightness_=new_flash_led_brightness;
285   if (flash_led_time_ == 0 || new_flash_led_delay < flash_led_delay_)
286     flash_led_delay_=new_flash_led_delay;
287 }
288
289 //********************************************************************//
290
291 void setup()
292 {
293   pinMode(RF_DATA_OUT_PIN, OUTPUT);
294   digitalWrite(RF_DATA_OUT_PIN, LOW);
295   pinMode(IR_MOVEMENT_PIN, INPUT);      // set pin to input
296   digitalWrite(IR_MOVEMENT_PIN, LOW);  // turn off pullup resistors  
297   pinMode(PANIC_BUTTON_PIN, INPUT);      // set pin to input
298   digitalWrite(PANIC_BUTTON_PIN, HIGH);  // turn on pullup resistors 
299   analogWrite(BLUELED_PWM_PIN,0);
300
301   Serial.begin(9600);
302   
303   onewire.reset();
304   onewire.reset_search();
305   dallas_sensors.begin();
306   //in case we change temp sensor:
307   if (!dallas_sensors.getAddress(onShieldTemp, 0)) 
308     Serial.println("Error: Unable to find address for Device 0"); 
309   dallas_sensors.setResolution(onShieldTemp, 9);  
310 }
311
312 unsigned int ir_time=IR_SAMPLE_DURATION;
313 unsigned int ir_count=0;
314 boolean pb_last_state=0;
315 boolean pb_state=0;
316 boolean pb_postth_state=0;
317 unsigned int pb_time=0;
318
319 void sensorEchoCommand(char command)
320 {
321   Serial.print("Sensor ");
322   Serial.print(command);
323   Serial.print(": ");
324 }
325
326 void loop()
327 {
328   ir_time--;
329   ir_count += (digitalRead(IR_MOVEMENT_PIN) == HIGH);
330
331   if (pb_time < PB_TRESHOLD)
332     pb_time++;
333   pb_state=(digitalRead(PANIC_BUTTON_PIN) == LOW);
334   
335   if (ir_time == 0)
336   {
337     if (ir_count >= IR_TRESHOLD)
338     {
339       flash_led(1,2,1);
340       Serial.println("movement");
341     }
342     ir_time=IR_SAMPLE_DURATION;
343     ir_count=0;
344   }
345   
346   if (pb_state == pb_last_state && pb_time >= PB_TRESHOLD)
347   {
348     if (pb_state && ! pb_postth_state)
349     {   
350       pb_postth_state=1;
351       Serial.println("PanicButton");
352       flash_led(7,1,2);
353     }
354     else if (!pb_state)
355       pb_postth_state=0;
356   }
357   else if (pb_state != pb_last_state)
358   {
359     pb_time=0;
360     pb_last_state=pb_state;
361   }
362   
363   updateLightLevel(PHOTO_ANALOGPIN);
364   calculate_led_level(BLUELED_PWM_PIN);
365   
366   if(Serial.available()) {
367     char command = Serial.read();
368     
369     if(command == 'A')
370       send_frame(words[A1_ON]);
371     else if(command == 'a')
372       send_frame(words[A1_OFF]);
373     else if(command == 'B')
374       send_frame(words[A2_ON]);
375     else if(command == 'b')
376       send_frame(words[A2_OFF]);
377
378     else if(command == 'C')
379       send_frame(words[B1_ON]);
380     else if(command == 'c')
381       send_frame(words[B1_OFF]);
382     else if(command == 'D')
383       send_frame(words[B2_ON]);
384     else if(command == 'd')
385       send_frame(words[B2_OFF]);
386
387     else if(command == 'E')
388       send_frame(words[C1_ON]);
389     else if(command == 'e')
390       send_frame(words[C1_OFF]);
391     else if(command == 'F')
392       send_frame(words[C2_ON]);
393     else if(command == 'f')
394       send_frame(words[C2_OFF]);
395
396     else if(command == 'G')
397       send_frame(words[D1_ON]);
398     else if(command == 'g')
399       send_frame(words[D1_OFF]);
400     else if(command == 'H')
401       send_frame(words[D2_ON]);
402     else if(command == 'h')
403       send_frame(words[D2_OFF]);
404     else if(command == 'T')
405     {
406       sensorEchoCommand(command);
407       printTemperature(onShieldTemp);
408     }
409     else if(command == 'P')
410     {
411       sensorEchoCommand(command);
412       printLightLevel();
413     }
414     else
415       Serial.println("Error: unknown command");
416   }
417 }