915f298fc97ff62c601dbc4beea8caececc6215b
[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   onewire.reset();
294   onewire.reset_search();
295   dallas_sensors.begin();
296   //in case we change temp sensor:
297   if (!dallas_sensors.getAddress(onShieldTemp, 0)) 
298     Serial.println("Error: Unable to find address for Device 0"); 
299   dallas_sensors.setResolution(onShieldTemp, 9);
300   
301   Serial.begin(9600);
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 echoCommand(char command)
312 {
313   Serial.print(command);
314   Serial.print(": ");
315 }
316
317 void loop()
318 {
319   ir_time--;
320   ir_count += (digitalRead(IR_MOVEMENT_PIN) == HIGH);
321
322   if (pb_time < PB_TRESHOLD)
323     pb_time++;
324   pb_state=(digitalRead(PANIC_BUTTON_PIN) == LOW);
325   
326   if (ir_time == 0)
327   {
328     if (ir_count >= IR_TRESHOLD)
329     {
330       flash_led(1);
331       Serial.println("movement");
332     }
333     ir_time=IR_SAMPLE_DURATION;
334     ir_count=0;
335   }
336   
337   if (pb_state == pb_last_state && pb_time >= PB_TRESHOLD)
338   {
339     if (pb_state && ! pb_postth_state)
340     {   
341       pb_postth_state=1;
342       Serial.println("PanicButton");
343       flash_led(4);
344     }
345     else if (!pb_state)
346       pb_postth_state=0;
347   }
348   else if (pb_state != pb_last_state)
349   {
350     pb_time=0;
351     pb_last_state=pb_state;
352   }
353   
354   updateLightLevel(PHOTO_ANALOGPIN);
355   calculate_led_level(BLUELED_PWM_PIN);
356   
357   if(Serial.available()) {
358     char command = Serial.read();
359     
360     if(command == 'A')
361       send_frame(words[A1_ON]);
362     else if(command == 'a')
363       send_frame(words[A1_OFF]);
364     else if(command == 'B')
365       send_frame(words[A2_ON]);
366     else if(command == 'b')
367       send_frame(words[A2_OFF]);
368
369     else if(command == 'C')
370       send_frame(words[B1_ON]);
371     else if(command == 'c')
372       send_frame(words[B1_OFF]);
373     else if(command == 'D')
374       send_frame(words[B2_ON]);
375     else if(command == 'd')
376       send_frame(words[B2_OFF]);
377
378     else if(command == 'E')
379       send_frame(words[C1_ON]);
380     else if(command == 'e')
381       send_frame(words[C1_OFF]);
382     else if(command == 'F')
383       send_frame(words[C2_ON]);
384     else if(command == 'f')
385       send_frame(words[C2_OFF]);
386
387     else if(command == 'G')
388       send_frame(words[D1_ON]);
389     else if(command == 'g')
390       send_frame(words[D1_OFF]);
391     else if(command == 'H')
392       send_frame(words[D2_ON]);
393     else if(command == 'h')
394       send_frame(words[D2_OFF]);
395     else if(command == 'T')
396     {
397       echoCommand(command);
398       printTemperature(onShieldTemp);
399     }
400     else if(command == 'P')
401     {
402       echoCommand(command);
403       printLightLevel();
404     }
405     else
406       Serial.println("Error: unknown command");
407   }
408 }