eliminate send_frame racecondition
[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 11
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 12000
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, LOW); //neue 12V MosFET Verstärkung invertiert Logik !
145   else
146     digitalWrite(RF_DATA_OUT_PIN, HIGH);
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, LOW); //neue 12V MosFET Verstärkung invertiert Logik !
161     else
162       digitalWrite(RF_DATA_OUT_PIN, HIGH);
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, LOW); //neue 12V MosFET Verstärkung invertiert Logik !
172     else
173       digitalWrite(RF_DATA_OUT_PIN, HIGH);
174     return;
175   }
176   stop_timer();
177   digitalWrite(RF_DATA_OUT_PIN, HIGH);
178
179   word_cnt++;
180   if(word_cnt < FRAME_LEN)
181     init_word(current_word);
182   else
183     frame_finished = 2;
184 }
185
186 //***********//
187
188
189 void send_frame(const word_t w)
190 {
191   if (frame_finished == 0)
192     for(;;)
193       if (frame_finished)
194       {
195         delay(10);
196         break;
197       }
198   word_cnt = 0;
199   frame_finished = 0;
200   init_word(w);      
201 }
202
203 void check_frame_done()
204 {
205   if (frame_finished==2)
206   {
207     Serial.println("Ok");
208     frame_finished=1;
209   }
210 }
211
212 //********************************************************************//
213
214 void printTemperature(DeviceAddress deviceAddress)
215 {
216   dallas_sensors.requestTemperatures();
217   float tempC = dallas_sensors.getTempC(deviceAddress);
218   //Serial.print("Temp C: ");
219   Serial.println(tempC TEMPC_OFFSET_ARDUINO_GENEREATED_HEAT);
220   //Serial.print(" Temp F: ");
221   //Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
222 }
223
224 //********************************************************************//
225
226 unsigned int light_level_mean_ = 0;
227 unsigned int light_sample_time_ = 0;
228
229 void updateLightLevel(unsigned int pin)
230 {
231   light_sample_time_++;
232   if (light_sample_time_ < PHOTO_SAMPLE_INTERVAL)
233     return;
234   light_sample_time_ = 0;
235   
236   unsigned int value = analogRead(pin);
237   if (value == light_level_mean_)
238     return;
239   
240   unsigned int diff = abs(value - light_level_mean_);
241   if (diff > 100)
242     light_level_mean_ = value;
243   else
244       light_level_mean_=(unsigned int) ( ((float) light_level_mean_) * 0.90 + ((float)value)*0.10 );
245 }
246
247 void printLightLevel()
248 {
249   //Serial.print("Photo: ");
250   Serial.println(light_level_mean_);
251 }
252
253 //********************************************************************//
254
255 unsigned long wm_start_=0;
256 bool wait_millis(unsigned long ms)
257 {
258   if (wm_start_ > 0)
259   {
260     if (millis() < wm_start_ || millis() > wm_start_+ ms)
261     {
262       wm_start_=0;
263       return false;
264     }
265     else
266       return true;
267   }
268   else
269   {
270     wm_start_=millis();
271     return true;
272   }
273 }
274
275 unsigned int flash_led_time_=0;
276 unsigned int flash_led_brightness_=255;
277 unsigned int flash_led_delay_=8;
278 void calculate_led_level(unsigned int pwm_pin)
279 {
280   if (flash_led_time_ == 0)
281     return;
282   if (wait_millis(flash_led_delay_))
283     return;
284   flash_led_time_--;
285   int c = abs(sin(float(flash_led_time_) / 100.0)) * flash_led_brightness_;
286   //int d = abs(sin(float(flash_led_time_) / 100.0)) * flash_led_brightness_;
287   analogWrite(BLUELED2_PWM_PIN, 255-c);
288   if (flash_led_brightness_ == 255)
289   {
290     if (flash_led_time_)
291       analogWrite(BLUELED_PWM_PIN, 255-c);
292     else
293       analogWrite(BLUELED_PWM_PIN, c);
294   }
295 }
296
297 void flash_led(unsigned int times, unsigned int brightness_divisor, unsigned int delay_divisor)
298 {
299   unsigned int new_flash_led_brightness = 255 / brightness_divisor;
300   unsigned int new_flash_led_delay = 8 / delay_divisor;
301   if (flash_led_time_ == 0 || new_flash_led_brightness > flash_led_brightness_)
302     flash_led_brightness_=new_flash_led_brightness;
303   if (flash_led_time_ == 0 || new_flash_led_delay < flash_led_delay_)
304     flash_led_delay_=new_flash_led_delay;
305   flash_led_time_ += 314*times;
306 }
307
308 //********************************************************************//
309
310 void setup()
311 {
312   pinMode(RF_DATA_OUT_PIN, OUTPUT);
313   digitalWrite(RF_DATA_OUT_PIN, HIGH);
314   pinMode(IR_MOVEMENT_PIN, INPUT);      // set pin to input
315   digitalWrite(IR_MOVEMENT_PIN, LOW);  // turn off pullup resistors  
316   pinMode(PANIC_BUTTON_PIN, INPUT);      // set pin to input
317   digitalWrite(PANIC_BUTTON_PIN, HIGH);  // turn on pullup resistors 
318   analogWrite(BLUELED_PWM_PIN,0);
319   analogWrite(BLUELED2_PWM_PIN,255); //pwm sink(-) instead of pwm + (better for mosfets)
320
321   Serial.begin(9600);
322   
323   onewire.reset();
324   onewire.reset_search();
325   dallas_sensors.begin();
326   //in case we change temp sensor:
327   if (!dallas_sensors.getAddress(onShieldTemp, 0)) 
328     Serial.println("Error: Unable to find address for Device 0"); 
329   dallas_sensors.setResolution(onShieldTemp, 9);  
330 }
331
332 unsigned int ir_time=IR_SAMPLE_DURATION;
333 unsigned int ir_count=0;
334 boolean pb_last_state=0;
335 boolean pb_state=0;
336 boolean pb_postth_state=0;
337 unsigned int pb_time=0;
338
339 void sensorEchoCommand(char command)
340 {
341   Serial.print("Sensor ");
342   Serial.print(command);
343   Serial.print(": ");
344 }
345
346 void loop()
347 {
348   ir_time--;
349   ir_count += (digitalRead(IR_MOVEMENT_PIN) == HIGH);
350
351   if (pb_time < PB_TRESHOLD)
352     pb_time++;
353   pb_state=(digitalRead(PANIC_BUTTON_PIN) == LOW);
354   
355   if (ir_time == 0)
356   {
357     if (ir_count >= IR_TRESHOLD)
358     {
359       flash_led(1,8,1);
360       Serial.println("movement");
361     }
362     ir_time=IR_SAMPLE_DURATION;
363     ir_count=0;
364   }
365   
366   if (pb_state == pb_last_state && pb_time >= PB_TRESHOLD)
367   {
368     if (pb_state && ! pb_postth_state)
369     {   
370       pb_postth_state=1;
371       Serial.println("PanicButton");
372       flash_led(7,1,2);
373     }
374     else if (!pb_state)
375       pb_postth_state=0;
376   }
377   else if (pb_state != pb_last_state)
378   {
379     pb_time=0;
380     pb_last_state=pb_state;
381   }
382   
383   updateLightLevel(PHOTO_ANALOGPIN);
384   calculate_led_level(BLUELED_PWM_PIN);
385   check_frame_done();
386   
387   if(Serial.available()) {
388     char command = Serial.read();
389     
390     if(command == 'A')
391       send_frame(words[A1_ON]);
392     else if(command == 'a')
393       send_frame(words[A1_OFF]);
394     else if(command == 'B')
395       send_frame(words[A2_ON]);
396     else if(command == 'b')
397       send_frame(words[A2_OFF]);
398
399     else if(command == 'C')
400       send_frame(words[B1_ON]);
401     else if(command == 'c')
402       send_frame(words[B1_OFF]);
403     else if(command == 'D')
404       send_frame(words[B2_ON]);
405     else if(command == 'd')
406       send_frame(words[B2_OFF]);
407
408     else if(command == 'E')
409       send_frame(words[C1_ON]);
410     else if(command == 'e')
411       send_frame(words[C1_OFF]);
412     else if(command == 'F')
413       send_frame(words[C2_ON]);
414     else if(command == 'f')
415       send_frame(words[C2_OFF]);
416
417     else if(command == 'G')
418       send_frame(words[D1_ON]);
419     else if(command == 'g')
420       send_frame(words[D1_OFF]);
421     else if(command == 'H')
422       send_frame(words[D2_ON]);
423     else if(command == 'h')
424       send_frame(words[D2_OFF]);
425     else if(command == 'T')
426     {
427       sensorEchoCommand(command);
428       printTemperature(onShieldTemp);
429     }
430     else if(command == 'P')
431     {
432       sensorEchoCommand(command);
433       printLightLevel();
434     }
435     else
436       Serial.println("Error: unknown command");
437   }
438 }