2 #include <avr/interrupt.h>
5 #include <DallasTemperature.h>
8 //********************************************************************//
10 #define RF_DATA_OUT_PIN 13
11 #define IR_MOVEMENT_PIN 9
12 #define ONE_WIRE_PIN 8
13 #define PANIC_BUTTON_PIN 7
14 #define PANICLED_PWM_PIN 6
15 #define BLUELED_PWM_PIN 11
16 #define PHOTO_ANALOGPIN 0
17 //movement is reported if during IR_SAMPLE_DURATION at least IR_TRESHOLD ir signals are detectd
18 #define IR_SAMPLE_DURATION 12000
19 #define IR_TRESHOLD 8000
20 //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)
21 #define PB_TRESHOLD 1000
22 #define PHOTO_SAMPLE_INTERVAL 4000
23 #define IRREMOTE_SEND_PIN 3 //hardcoded in library
24 //WARNING IRremote Lib uses TCCR2
26 OneWire onewire(ONE_WIRE_PIN);
27 DallasTemperature dallas_sensors(&onewire);
28 DeviceAddress onShieldTemp = { 0x10, 0xE7, 0x77, 0xD3, 0x01, 0x08, 0x00, 0x3F };
30 #define TEMPC_OFFSET_ARDUINO_GENEREATED_HEAT
32 //********************************************************************//
33 // IR Codes, 32 bit, NEC
34 const int YAMAHA_CODE_BITS = 32;
35 const unsigned long int YAMAHA_CODE_BASE = 0x0000000005EA10000;
37 const char YAMAHA_POWER_TOGGLE =0xF8; //Power On/Off
38 const char YAMAHA_POWER_OFF =0x78; //Power Off !!!
39 const char YAMAHA_SLEEP =0xEA; //Toggle Sleep 120/90/60/30min or Off
41 const char YAMAHA_CD =0xA8; //Input CD
42 const char YAMAHA_TUNER =0x68; //Input Tuner
43 const char YAMAHA_TAPE =0x18; //Input Toggle Tape/CD
44 const char YAMAHA_DVD_SPDIF =0xE8; //Input Toggle DVD Auto / DVD Analog
45 const char YAMAHA_SAT_SPDIFF =0x2A; //Input Toggle Sat-DTV Auto / Sat-DTV Analog
46 const char YAMAHA_AUX =0xAA; //Input AUX (mode)
47 const char YAMAHA_VCR =0xF0; //Input VCR
48 const char YAMAHA_EXT51DEC =0xE1; //Input Ext. Decoder On/Off
50 const char YAMAHA_TUNER_PLUS =0x08; //Tuner Next Station 1-7 (of A1 - E7)
51 const char YAMAHA_TUNER_MINUS =0x88; //Tuner Prev Station 1-7 (of A1 - E7)
52 const char YAMAHA_TUNER_ABCDE =0x48; //Tuner Next Station Row A-E (of A1 - E7)
54 const char YAMAHA_MUTE =0x38;
55 const char YAMAHA_VOLUME_UP =0x58;
56 const char YAMAHA_VOLUME_DOWN =0xD8;
58 //const char YAMAHA_FRONT_LEVEL_P =0x01; //no function
59 //const char YAMAHA_FRONT_LEVEL_M =0x81; //no function
60 //const char YAMAHA_CENTRE_LEVEL_P =0x41; //no function
61 //const char YAMAHA_CENTRE_LEVEL_M =0xC1; //no function
62 //const char YAMAHA_REAR_LEVEL_P =0x7A; //no function
63 //const char YAMAHA_REAR_LEVEL_M =0xFA; //no function
64 const char YAMAHA_PLUS =0x4A; //unteres Steuerkreuz: Taste Rechts (Plus)
65 const char YAMAHA_MINUS =0xCA; //unteres Steuerkreuz: Taste Links (Minus)
66 const char YAMAHA_MENU =0x39; // Menu: Settings
67 const char YAMAHA_TEST =0xA1; // Test Sounds
68 const char YAMAHA_TIME_LEVEL =0x19; //Settings for Delay, Subwfs, Right Surround, Left Surround, Center
69 const char YAMAHA_TIME_LEVEL2 =0x61; //(also) Settings for Delay, Subwfs, Right Surround, Left Surround, Center
70 const char YAMAHA_TIME_LEVEL3 =0x99; //(also) Settings for Delay, Subwfs, Right Surround, Left Surround, Center
72 const char YAMAHA_EFFECT_TOGGLE =0x6A; //Effect Toggle On/Off
73 const char YAMAHA_PRG_DOWN =0x9A; //Effect/DSP Programm Toggle in down direction
74 const char YAMAHA_PRG_UP =0x1A; //Effect/DSP Programm Toggle in up direction
75 const char YAMAHA_EFFECT1 =0x31; //Effect TV Sports
76 const char YAMAHA_EFFECT2 =0x71; //Effect Rock Concert
77 const char YAMAHA_EFFECT3 =0xB1; //Effect Disco
78 const char YAMAHA_EFFECT4 =0xD1; //Mono Movie
79 const char YAMAHA_EFFECT5 =0x91; //Effect Toggle 70mm Sci-Fi / 70mm Spectacle
80 const char YAMAHA_EFFECT6 =0x51; //Effect Toggle 70mm General / 70mm Adventure
81 const char YAMAHA_P5 =0xFB; //P5 PRT (1 Main Bypass)? (1587674115)
83 //********************************************************************//
90 // offset is number of alphas (0.08ms)
92 const rf_bit_t zero_bit[] = { { 4, 1 },
98 const rf_bit_t one_bit[] = { { 12, 1 },
104 const rf_bit_t float_bit[] = { { 4, 1 },
110 const rf_bit_t sync_bit[] = { { 4, 1 },
114 typedef enum { ZERO = 0, ONE , FLOAT , SYNC } adbit_t;
115 typedef byte ad_bit_t;
117 typedef ad_bit_t word_t[WORD_LEN];
119 const rf_bit_t* bit_defs[] = { zero_bit, one_bit, float_bit, sync_bit };
125 const ad_bit_t* current_word;
126 byte volatile frame_finished = 1;
150 const word_t words[] = {
151 { ZERO, ZERO, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // A1_ON
152 { ZERO, ZERO, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // A1_OFF
153 { ZERO, ZERO, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // A2_ON
154 { ZERO, ZERO, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // A2_OFF
156 { FLOAT, ZERO, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // B1_ON
157 { FLOAT, ZERO, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // B1_OFF
158 { FLOAT, ZERO, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // B2_ON
159 { FLOAT, ZERO, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // B2_OFF
161 { ZERO, FLOAT, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // C1_ON
162 { ZERO, FLOAT, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // C1_OFF
163 { ZERO, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // C2_ON
164 { ZERO, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // C2_OFF
166 { FLOAT, FLOAT, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // D1_ON
167 { FLOAT, FLOAT, FLOAT, FLOAT, ZERO, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC }, // D1_OFF
168 { FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, FLOAT, SYNC }, // D2_ON
169 { FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, FLOAT, FLOAT, ZERO, SYNC } // D2_OFF
173 //********************************************************************//
182 TCCR2A = save_tccr2a; // normal mode
183 TCCR2B = save_tccr2b;
184 TIMSK2 = save_timsk2;
190 TCCR2A = 0; // prescaler 1:8, WGM = 4 (CTC)
191 TCCR2B = 1<<WGM12 | 1<<CS11; //
192 OCR2A = 159; // (1+159)*8 = 1280 -> 0.08ms @ 16 MHz -> 1*alpha
193 // OCR1A = 207; // (1+207)*8 = 1664 -> 0.104ms @ 16 MHz -> 1*alpha
194 TCNT2 = 0; // reseting timer
195 TIMSK2 = 1<<OCIE2A; // enable Interrupt
198 void stop_timer() // stop the timer
201 TCCR2B = 0; // no clock source
202 TIMSK2 = 0; // disable timer interrupt
205 void init_word(const word_t w)
212 if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
213 digitalWrite(RF_DATA_OUT_PIN, LOW); //neue 12V MosFET Verstรคrkung invertiert Logik !
215 digitalWrite(RF_DATA_OUT_PIN, HIGH);
220 ISR(TIMER2_COMPA_vect)
223 if(alpha_cnt < bit_defs[current_word[bit_cnt]][chunk_cnt].offset)
227 if(bit_defs[current_word[bit_cnt]][chunk_cnt].offset != 0) {
228 if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
229 digitalWrite(RF_DATA_OUT_PIN, LOW); //neue 12V MosFET Verstรคrkung invertiert Logik !
231 digitalWrite(RF_DATA_OUT_PIN, HIGH);
236 if(bit_cnt < WORD_LEN) {
239 if(bit_defs[current_word[bit_cnt]][chunk_cnt].state)
240 digitalWrite(RF_DATA_OUT_PIN, LOW); //neue 12V MosFET Verstรคrkung invertiert Logik !
242 digitalWrite(RF_DATA_OUT_PIN, HIGH);
246 digitalWrite(RF_DATA_OUT_PIN, HIGH);
249 if(word_cnt < FRAME_LEN)
250 init_word(current_word);
258 void send_frame(const word_t w)
260 if (frame_finished != 1)
261 for(;;) //wait until sending of previous frame finishes
272 void check_frame_done()
274 if (frame_finished==2)
276 Serial.println("Ok");
283 //********************************************************************//
285 void printTemperature(DeviceAddress deviceAddress)
287 dallas_sensors.requestTemperatures();
288 float tempC = dallas_sensors.getTempC(deviceAddress);
289 //Serial.print("Temp C: ");
290 Serial.println(tempC TEMPC_OFFSET_ARDUINO_GENEREATED_HEAT);
291 //Serial.print(" Temp F: ");
292 //Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
295 //********************************************************************//
297 unsigned int light_level_mean_ = 0;
298 unsigned int light_sample_time_ = 0;
300 void updateLightLevel(unsigned int pin)
302 light_sample_time_++;
303 if (light_sample_time_ < PHOTO_SAMPLE_INTERVAL)
305 light_sample_time_ = 0;
307 unsigned int value = analogRead(pin);
308 if (value == light_level_mean_)
311 unsigned int diff = abs(value - light_level_mean_);
313 light_level_mean_ = value;
315 light_level_mean_=(unsigned int) ( ((float) light_level_mean_) * 0.90 + ((float)value)*0.10 );
318 void printLightLevel()
320 Serial.println(light_level_mean_);
323 //********************************************************************//
325 unsigned long wm_start_[3]={0,0,0};
326 bool wait_millis(unsigned long *start_time, unsigned long ms)
330 else if (*start_time > 0)
332 if (millis() < *start_time || millis() > (*start_time) + ms)
342 *start_time=millis();
347 char flash_led_pins_[NUM_LEDS]={BLUELED_PWM_PIN,PANICLED_PWM_PIN};
348 unsigned int flash_led_time_[3]={0,0,0};
349 unsigned int flash_led_brightness_[3]={255,255,255};
350 unsigned int flash_led_delay_[3]={8,8,8};
351 unsigned int flash_led_initial_delay_[3]={0,0,0};
352 void calculate_led_level()
354 for (int ledid = 0; ledid < NUM_LEDS; ledid++)
356 if (flash_led_time_[ledid] == 0)
358 if (wait_millis(wm_start_ + ledid, flash_led_initial_delay_[ledid]))
360 flash_led_initial_delay_[ledid]=0;
361 if (wait_millis(wm_start_ + ledid, flash_led_delay_[ledid]))
363 flash_led_time_[ledid]--;
364 int c = abs(sin(float(flash_led_time_[ledid]) / 100.0)) * flash_led_brightness_[ledid];
365 //int d = abs(sin(float(flash_led_time_) / 100.0)) * flash_led_brightness_;
366 analogWrite(flash_led_pins_[ledid], 255-c);
370 ISR(TIMER1_COMPA_vect)
372 calculate_led_level();
374 // id: id of LED to flash (0,1)
375 // times: # of times the LED should flash
376 // brightness_divisor: 1: full brightness, 2: half brightness, ...
377 // delay_divisor: 1: slow... 8: fastest
378 // phase_divisor: 0.. same phase; 2.. pi/2 phase, 4.. pi phase, 6.. 3pi/2 phase
379 void flash_led(unsigned int id, unsigned int times, unsigned int brightness_divisor, unsigned int delay_divisor, unsigned int phase_divisor)
383 unsigned int new_flash_led_brightness = 255;
384 unsigned int new_flash_led_delay = 8;
387 analogWrite(flash_led_pins_[id],255); //off
390 if (brightness_divisor > 1) //guard against div by zero
391 new_flash_led_brightness /= brightness_divisor;
392 if (delay_divisor > 1) //guard against div by zero
393 new_flash_led_delay /= delay_divisor;
394 if (flash_led_time_[id] == 0 || new_flash_led_brightness > flash_led_brightness_[id])
395 flash_led_brightness_[id]=new_flash_led_brightness;
396 if (flash_led_time_[id] == 0 || new_flash_led_delay < flash_led_delay_[id])
397 flash_led_delay_[id]=new_flash_led_delay;
398 flash_led_time_[id] += 314*times;
399 flash_led_initial_delay_[id] = flash_led_delay_[id]*314*phase_divisor/8;
402 void start_led_timer()
405 TCCR1A = 0; // prescaler 1:8, WGM = 4 (CTC)
406 TCCR1B = 1<<WGM12 | 1<<CS11; //
407 OCR1A = 15999; // (1+15999) = 16000 -> 1ms @ 16 MHz
408 TCNT1 = 0; // reseting timer
409 TIMSK1 = 1<<OCIE1A; // enable Interrupt
412 void stop_led_timer() // stop the timer
415 TCCR1B = 0; // no clock source
416 TIMSK1 = 0; // disable timer interrupt
419 //********************************************************************//
421 void send_yamaha_ir_signal(char codebyte)
423 unsigned long int code = codebyte & 0xFF;
425 code |= (0xff ^ codebyte) & 0xFF;
426 code |= YAMAHA_CODE_BASE;
428 //irsend changes PWM Timer Frequency among other things
429 //.. doesn't go well with PWM output using the same timer
430 //.. thus we just set output to 255 so whatever frequency is used, led is off for the duration
431 //analogWrite(BLUELED_PWM_PIN,255); // switch led off
433 irsend.sendNEC(code,YAMAHA_CODE_BITS);
436 analogWrite(BLUELED_PWM_PIN,255); // switch off led again to be sure
437 //is actually not necessary, since we are not multitasking/using interrupts, but just to be sure in case this might change
439 Serial.println("Ok");
442 //********************************************************************//
446 pinMode(RF_DATA_OUT_PIN, OUTPUT);
447 digitalWrite(RF_DATA_OUT_PIN, HIGH);
448 pinMode(IR_MOVEMENT_PIN, INPUT); // set pin to input
449 digitalWrite(IR_MOVEMENT_PIN, LOW); // turn off pulldown resistors
450 pinMode(PANIC_BUTTON_PIN, INPUT); // set pin to input
451 digitalWrite(PANIC_BUTTON_PIN, LOW); // turn on pulldown resistors
452 analogWrite(PANICLED_PWM_PIN,255);
453 analogWrite(BLUELED_PWM_PIN,255); //pwm sink(-) instead of pwm + (better for mosfets)
454 pinMode(IRREMOTE_SEND_PIN, OUTPUT);
455 digitalWrite(IRREMOTE_SEND_PIN, HIGH);
460 onewire.reset_search();
461 dallas_sensors.begin();
462 //in case we change temp sensor:
463 if (!dallas_sensors.getAddress(onShieldTemp, 0))
464 Serial.println("Error: Unable to find address for Device 0");
465 dallas_sensors.setResolution(onShieldTemp, 9);
467 //save prev timer states:
469 save_tccr2a = TCCR2A; // normal mode
470 save_tccr2b = TCCR2B;
474 unsigned int ir_time=IR_SAMPLE_DURATION;
475 unsigned int ir_count=0;
476 boolean pb_last_state=0;
478 boolean pb_postth_state=0;
479 unsigned int pb_time=0;
481 void sensorEchoCommand(char command)
483 Serial.print("Sensor ");
484 Serial.print(command);
491 ir_count += (digitalRead(IR_MOVEMENT_PIN) == HIGH);
493 if (pb_time < PB_TRESHOLD)
495 pb_state=(digitalRead(PANIC_BUTTON_PIN) == HIGH);
499 if (ir_count >= IR_TRESHOLD)
501 flash_led(0, 1, 8, 1, 0 );
502 Serial.println("movement");
504 ir_time=IR_SAMPLE_DURATION;
508 if (pb_state == pb_last_state && pb_time >= PB_TRESHOLD)
510 if (pb_state && ! pb_postth_state)
513 Serial.println("PanicButton");
514 flash_led(0, 28, 1, 4, 0 );
515 flash_led(1, 28, 1, 4, 4 );
520 else if (pb_state != pb_last_state)
523 pb_last_state=pb_state;
526 updateLightLevel(PHOTO_ANALOGPIN);
527 //calculate_led_level();
530 if(Serial.available()) {
531 char command = Serial.read();
534 send_frame(words[A1_ON]);
535 else if(command == 'a')
536 send_frame(words[A1_OFF]);
537 else if(command == 'B')
538 send_frame(words[A2_ON]);
539 else if(command == 'b')
540 send_frame(words[A2_OFF]);
542 else if(command == 'C')
543 send_frame(words[B1_ON]);
544 else if(command == 'c')
545 send_frame(words[B1_OFF]);
546 else if(command == 'D')
547 send_frame(words[B2_ON]);
548 else if(command == 'd')
549 send_frame(words[B2_OFF]);
551 else if(command == 'E')
552 send_frame(words[C1_ON]);
553 else if(command == 'e')
554 send_frame(words[C1_OFF]);
555 else if(command == 'F')
556 send_frame(words[C2_ON]);
557 else if(command == 'f')
558 send_frame(words[C2_OFF]);
560 else if(command == 'G')
561 send_frame(words[D1_ON]);
562 else if(command == 'g')
563 send_frame(words[D1_OFF]);
564 else if(command == 'H')
565 send_frame(words[D2_ON]);
566 else if(command == 'h')
567 send_frame(words[D2_OFF]);
568 else if(command == 'T')
570 sensorEchoCommand(command);
571 printTemperature(onShieldTemp);
573 else if(command == 'P')
575 sensorEchoCommand(command);
578 else if (command == '^')
579 flash_led(1, 1, 2, 1, 0);
580 else if (command == '0')
581 send_yamaha_ir_signal(YAMAHA_POWER_OFF);
582 else if (command == '1')
583 send_yamaha_ir_signal(YAMAHA_POWER_TOGGLE);
584 else if (command == '2')
585 send_yamaha_ir_signal(YAMAHA_VOLUME_UP);
586 else if (command == '3')
587 send_yamaha_ir_signal(YAMAHA_VOLUME_DOWN);
588 else if (command == '4')
589 send_yamaha_ir_signal(YAMAHA_MUTE);
590 else if (command == '5')
591 send_yamaha_ir_signal(YAMAHA_CD);
592 else if (command == '6')
593 send_yamaha_ir_signal(YAMAHA_TUNER);
594 else if (command == '7')
595 send_yamaha_ir_signal(YAMAHA_DVD_SPDIF);
596 else if (command == '8')
597 send_yamaha_ir_signal(YAMAHA_MENU);
598 else if (command == '+')
599 send_yamaha_ir_signal(YAMAHA_PLUS);
600 else if (command == '-')
601 send_yamaha_ir_signal(YAMAHA_MINUS);
602 else if (command == 0xa7) // ยง
603 send_yamaha_ir_signal(YAMAHA_TEST);
604 else if (command == '$')
605 send_yamaha_ir_signal(YAMAHA_TIME_LEVEL);
606 else if (command == '%')
607 send_yamaha_ir_signal(YAMAHA_EFFECT_TOGGLE);
608 else if (command == '&')
609 send_yamaha_ir_signal(YAMAHA_PRG_DOWN);
610 else if (command == '/')
611 send_yamaha_ir_signal(YAMAHA_PRG_UP);
612 else if (command == '(')
613 send_yamaha_ir_signal(YAMAHA_TUNER_PLUS);
614 else if (command == '[')
615 send_yamaha_ir_signal(YAMAHA_TUNER_MINUS);
616 else if (command == ')')
617 send_yamaha_ir_signal(YAMAHA_TUNER_ABCDE);
618 else if (command == '9')
619 send_yamaha_ir_signal(YAMAHA_TAPE);
620 else if (command == '?')
621 send_yamaha_ir_signal(YAMAHA_VCR);
622 else if (command == '=')
623 send_yamaha_ir_signal(YAMAHA_EXT51DEC);
625 Serial.println("Error: unknown command");