├── IRremote.cpp ├── IRremote.h ├── IRremoteInt.h ├── LICENSE.txt ├── examples ├── IRrecord │ └── IRrecord.ino ├── IRrecvDemo │ └── IRrecvDemo.ino ├── IRrecvDump │ └── IRrecvDump.ino ├── IRrelay │ └── IRrelay.ino ├── IRsendDemo │ └── IRsendDemo.ino ├── IRsendDemoHelicopter │ └── IRsendDemoHelicopter.ino ├── IRsendDemoMagi │ └── IRsendDemoMagi.ino ├── IRtest │ └── IRtest.ino ├── IRtest2 │ └── IRtest2.ino └── JVCPanasonicSendDemo │ └── JVCPanasonicSendDemo.ino ├── keywords.txt └── readme /IRremote.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote 3 | * Version 0.11 August, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 6 | * 7 | * Modified by Paul Stoffregen to support other boards and timers 8 | * Modified by Mitra Ardron 9 | * Added Sanyo and Mitsubishi controllers 10 | * Modified Sony to spot the repeat codes that some Sony's send 11 | * 12 | * Interrupt code based on NECIRrcv by Joe Knapp 13 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 14 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 15 | * 16 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 17 | */ 18 | 19 | #include "IRremote.h" 20 | #include "IRremoteInt.h" 21 | 22 | // Provides ISR 23 | #include 24 | #include 25 | 26 | #if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 27 | #define IS_AVTINY 28 | #define ENABLE_MagiQuest 29 | // add others as to fit in Tiny 30 | #else 31 | #define ENABLE_MagiQuest 32 | #define ENABLE_NEC 33 | #define ENABLE_SONY 34 | #define ENABLE_Sanyo 35 | #define ENABLE_Mitsubishi 36 | #define ENABLE_Panasonic 37 | #define ENABLE_RC5 38 | #define ENABLE_RC6 39 | #define ENABLE_SymaR3 40 | #define ENABLE_SymaR5 41 | #define ENABLE_Useries 42 | #define ENABLE_FastLane 43 | #define ENABLE_JVC 44 | #define ENABLE_RCMM 45 | #endif 46 | 47 | #define MIN(x,y) (x < y ? x : y) 48 | #define UINT16_MAX 0xFFFFUL 49 | 50 | volatile irparams_t irparams; 51 | 52 | #if SYSCLOCK != 8000000L && SYSCLOCK != 16000000L 53 | // 54 | // Built-in delayMicroseconds only works for 16MHz and 8MHz. 55 | // 56 | #define USE_CYCLE_BASED_TIMINGS 57 | void IRsend::mark(int time) { 58 | // Sends an IR mark for the specified number of microseconds. 59 | // The mark output is modulated at the PWM frequency. 60 | TIMER_ENABLE_PWM; // Enable pin 3 PWM output 61 | } 62 | 63 | /* Leave pin off for time (given in microseconds) */ 64 | void IRsend::space(int time) { 65 | // Sends an IR space for the specified number of microseconds. 66 | // A space is no output, so the PWM output is disabled. 67 | TIMER_DISABLE_PWM; // Disable pin 3 PWM output 68 | } 69 | #define US_TO_ITER(x) uint16_t(((x)*(SYSCLOCK/1000))/4000) 70 | #define mark(x) do { this->mark ((x)); _delay_loop_2(US_TO_ITER(x)); } while (0) 71 | #define space(x) do { this->space ((x)); _delay_loop_2(US_TO_ITER(x)); } while (0) 72 | 73 | void IRsend::on(unsigned int freq) { 74 | // Sends an IR mark 75 | // The mark output is modulated at the PWM frequency. 76 | enableIROut(freq); 77 | TIMER_ENABLE_PWM; // Enable pin 3 PWM output 78 | } 79 | void IRsend::off() { 80 | // Sends an IR mark 81 | // The mark output is modulated at the PWM frequency. 82 | TIMER_DISABLE_PWM; // Enable pin 3 PWM output 83 | } 84 | 85 | 86 | 87 | #endif 88 | 89 | // These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging. 90 | // To use them, set DEBUG in IRremoteInt.h 91 | // Normally macros are used for efficiency 92 | #ifdef DEBUG 93 | int MATCH(int measured, int desired) { 94 | Serial.print("Testing: "); 95 | Serial.print(TICKS_LOW(desired), DEC); 96 | Serial.print(" <= "); 97 | Serial.print(measured, DEC); 98 | Serial.print(" <= "); 99 | Serial.println(TICKS_HIGH(desired), DEC); 100 | return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired); 101 | } 102 | 103 | int MATCH_MARK(int measured_ticks, int desired_us) { 104 | Serial.print("Testing mark "); 105 | Serial.print(measured_ticks * USECPERTICK, DEC); 106 | Serial.print(" vs "); 107 | Serial.print(desired_us, DEC); 108 | Serial.print(": "); 109 | Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC); 110 | Serial.print(" <= "); 111 | Serial.print(measured_ticks, DEC); 112 | Serial.print(" <= "); 113 | Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC); 114 | return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS); 115 | } 116 | 117 | int MATCH_SPACE(int measured_ticks, int desired_us) { 118 | Serial.print("Testing space "); 119 | Serial.print(measured_ticks * USECPERTICK, DEC); 120 | Serial.print(" vs "); 121 | Serial.print(desired_us, DEC); 122 | Serial.print(": "); 123 | Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); 124 | Serial.print(" <= "); 125 | Serial.print(measured_ticks, DEC); 126 | Serial.print(" <= "); 127 | Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC); 128 | return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS); 129 | } 130 | #endif 131 | 132 | void IRsend::sendNEC(unsigned long data, int nbits) 133 | { 134 | enableIROut(38); 135 | mark(NEC_HDR_MARK); 136 | space(NEC_HDR_SPACE); 137 | for (int i = 0; i < nbits; i++) { 138 | if (data & TOPBIT) { 139 | mark(NEC_BIT_MARK); 140 | space(NEC_ONE_SPACE); 141 | } 142 | else { 143 | mark(NEC_BIT_MARK); 144 | space(NEC_ZERO_SPACE); 145 | } 146 | data <<= 1; 147 | } 148 | mark(NEC_BIT_MARK); 149 | space(0); 150 | } 151 | 152 | void IRsend::sendSony(unsigned long data, int nbits) { 153 | enableIROut(40); 154 | mark(SONY_HDR_MARK); 155 | space(SONY_HDR_SPACE); 156 | data = data << (32 - nbits); 157 | for (int i = 0; i < nbits; i++) { 158 | if (data & TOPBIT) { 159 | mark(SONY_ONE_MARK); 160 | space(SONY_HDR_SPACE); 161 | } 162 | else { 163 | mark(SONY_ZERO_MARK); 164 | space(SONY_HDR_SPACE); 165 | } 166 | data <<= 1; 167 | } 168 | } 169 | 170 | void IRsend::sendRaw(unsigned int buf[], int len, int hz) 171 | { 172 | enableIROut(hz); 173 | for (int i = 0; i < len; i++) { 174 | if (i & 1) { 175 | space(buf[i]); 176 | } 177 | else { 178 | mark(buf[i]); 179 | } 180 | } 181 | space(0); // Just to be sure 182 | } 183 | 184 | // Note: first bit must be a one (start bit) 185 | void IRsend::sendRC5(unsigned long data, int nbits) 186 | { 187 | enableIROut(36); 188 | data = data << (32 - nbits); 189 | mark(RC5_T1); // First start bit 190 | space(RC5_T1); // Second start bit 191 | mark(RC5_T1); // Second start bit 192 | for (int i = 0; i < nbits; i++) { 193 | if (data & TOPBIT) { 194 | space(RC5_T1); // 1 is space, then mark 195 | mark(RC5_T1); 196 | } 197 | else { 198 | mark(RC5_T1); 199 | space(RC5_T1); 200 | } 201 | data <<= 1; 202 | } 203 | space(0); // Turn off at end 204 | } 205 | 206 | // Caller needs to take care of flipping the toggle bit 207 | void IRsend::sendRC6(unsigned long data, int nbits) 208 | { 209 | enableIROut(36); 210 | data = data << (32 - nbits); 211 | mark(RC6_HDR_MARK); 212 | space(RC6_HDR_SPACE); 213 | mark(RC6_T1); // start bit 214 | space(RC6_T1); 215 | int t; 216 | for (int i = 0; i < nbits; i++) { 217 | if (i == 3) { 218 | // double-wide trailer bit 219 | t = 2 * RC6_T1; 220 | } 221 | else { 222 | t = RC6_T1; 223 | } 224 | if (data & TOPBIT) { 225 | mark(t); 226 | space(t); 227 | } 228 | else { 229 | space(t); 230 | mark(t); 231 | } 232 | 233 | data <<= 1; 234 | } 235 | space(0); // Turn off at end 236 | } 237 | void IRsend::sendPanasonic(unsigned int address, unsigned long data) { 238 | enableIROut(35); 239 | mark(PANASONIC_HDR_MARK); 240 | space(PANASONIC_HDR_SPACE); 241 | 242 | for(int i=0;i<16;i++) 243 | { 244 | mark(PANASONIC_BIT_MARK); 245 | if (address & 0x8000) { 246 | space(PANASONIC_ONE_SPACE); 247 | } else { 248 | space(PANASONIC_ZERO_SPACE); 249 | } 250 | address <<= 1; 251 | } 252 | for (int i=0; i < 32; i++) { 253 | mark(PANASONIC_BIT_MARK); 254 | if (data & TOPBIT) { 255 | space(PANASONIC_ONE_SPACE); 256 | } else { 257 | space(PANASONIC_ZERO_SPACE); 258 | } 259 | data <<= 1; 260 | } 261 | mark(PANASONIC_BIT_MARK); 262 | space(0); 263 | } 264 | void IRsend::sendJVC(unsigned long data, int nbits, int repeat) 265 | { 266 | enableIROut(38); 267 | data = data << (32 - nbits); 268 | if (!repeat){ 269 | mark(JVC_HDR_MARK); 270 | space(JVC_HDR_SPACE); 271 | } 272 | for (int i = 0; i < nbits; i++) { 273 | if (data & TOPBIT) { 274 | mark(JVC_BIT_MARK); 275 | space(JVC_ONE_SPACE); 276 | } 277 | else { 278 | mark(JVC_BIT_MARK); 279 | space(JVC_ZERO_SPACE); 280 | } 281 | data <<= 1; 282 | } 283 | mark(JVC_BIT_MARK); 284 | space(0); 285 | } 286 | 287 | // Caller needs to take care of flipping the toggle bit 288 | void IRsend::sendRCMM(unsigned long data, int nbits) 289 | { 290 | enableIROut(36); 291 | data = data << (32 - nbits); 292 | mark(RCMM_HDR_MARK); 293 | space(RCMM_SPACE); 294 | for (int i = 0; i < nbits; i += 2) { 295 | mark(RCMM_MARK); 296 | space(RCMM_SPACE+(data >> 30)*RCMM_INCREMENT); 297 | data <<= 2; 298 | } 299 | mark(RCMM_MARK); 300 | space(0); 301 | } 302 | 303 | void IRsend::sendMagiQuest(uint32_t wand_id, uint16_t magnitude) 304 | { 305 | magiquest data; 306 | //data.cmd.scrap = 0x00; 307 | data.cmd.padding = 0x00; 308 | data.cmd.magnitude = magnitude; 309 | data.cmd.wand_id = wand_id; 310 | 311 | enableIROut(38); 312 | for (uint16_t i = 0; i < 56; i++) { 313 | data.llword <<= 1; 314 | if (((int8_t) data.byte[6]) < 0) { // if negative then MSBit is one. 315 | mark(MAGIQUEST_MARK_ONE); 316 | space(MAGIQUEST_SPACE_ONE); 317 | } 318 | else { 319 | mark(MAGIQUEST_MARK_ZERO); 320 | space(MAGIQUEST_SPACE_ZERO); 321 | } 322 | } 323 | } 324 | void IRsend::sendSymaR5(uint32_t data) 325 | { 326 | enableIROut(38); 327 | mark(SYMA_HDR_MARK); // SYMA_HDR_MARK 328 | space(SYMA_HDR_SPACE); // SYMA_HDR_SPACE 329 | for (uint8_t i = 0; i < SYMA_R5_BITS+1; i++) { 330 | mark(SYMA_BIT_MARK); // SYMA_BIT_MARK 331 | if (((int32_t)data) < 0) { // if negative then MSBit is one. 332 | space(SYMA_ONE_SPACE); // SYMA_ONE_SPACE 333 | } 334 | else { 335 | space(SYMA_ZERO_SPACE); // SYMA_ZERO_SPACE 336 | } 337 | data <<= 1; 338 | } 339 | } 340 | void IRsend::sendSymaR3(uint32_t data) 341 | { 342 | enableIROut(38); 343 | mark(SYMA_HDR_MARK); 344 | space(SYMA_HDR_SPACE); 345 | data <<= 8; 346 | for (uint8_t i = 0; i < SYMA_R3_BITS+1; i++) { 347 | mark(SYMA_BIT_MARK); 348 | if (((int32_t)data) < 0) { // if negative then MSBit is one. 349 | space(SYMA_ONE_SPACE); 350 | } 351 | else { 352 | space(SYMA_ZERO_SPACE); 353 | } 354 | data <<= 1; 355 | } 356 | } 357 | void IRsend::sendUseries(uint32_t data) 358 | { 359 | enableIROut(38); 360 | mark(USERIES_HDR_MARK); 361 | for (int16_t i = 0; i < USERIES_BITS+1; i++) { 362 | space(USERIES_BIT_SPACE); 363 | if (((int32_t)data) < 0) { // if negative then MSBit is one. 364 | mark(USERIES_ZERO_MARK); 365 | } 366 | else { 367 | mark(USERIES_ONE_MARK); 368 | } 369 | data <<= 1; 370 | } 371 | space(0); // Just to be sure 372 | } 373 | void IRsend::sendFastLane(uint32_t data) 374 | { 375 | enableIROut(38); 376 | mark(FASTLANE_HDR_MARK); 377 | data <<= (32 - FASTLANE_BITS); // upshift to start point of data. 378 | for (int16_t i = 0; i < FASTLANE_BITS+1; i++) { 379 | if (i%2) { 380 | if (((int32_t)data) < 0) { // if negative then MSBit is one. 381 | mark(FASTLANE_ONE); 382 | } 383 | else { 384 | mark(FASTLANE_ZERO); 385 | } 386 | } else { 387 | if (((int32_t)data) < 0) { // if negative then MSBit is one. 388 | space(FASTLANE_ONE); 389 | } 390 | else { 391 | space(FASTLANE_ZERO); 392 | } 393 | } 394 | data <<= 1; 395 | } 396 | space(0); // Just to be sure 397 | } 398 | 399 | #ifndef USE_CYCLE_BASED_TIMINGS 400 | void IRsend::mark(int16_t time) { 401 | // Sends an IR mark for the specified number of microseconds. 402 | // The mark output is modulated at the PWM frequency. 403 | TIMER_ENABLE_PWM; // Enable pin 3 PWM output 404 | if (time > 0) delayMicroseconds(time); 405 | } 406 | 407 | /* Leave pin off for time (given in microseconds) */ 408 | void IRsend::space(int time) { 409 | // Sends an IR space for the specified number of microseconds. 410 | // A space is no output, so the PWM output is disabled. 411 | TIMER_DISABLE_PWM; // Disable pin 3 PWM output 412 | if (time > 0) delayMicroseconds(time); 413 | } 414 | #endif 415 | 416 | void IRsend::enableIROut(int khz) { 417 | // Enables IR output. The khz value controls the modulation frequency in kilohertz. 418 | // The IR output will be on pin 3 (OC2B). 419 | // This routine is designed for 36-40KHz; if you use it for other values, it's up to you 420 | // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) 421 | // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B 422 | // controlling the duty cycle. 423 | // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) 424 | // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. 425 | // A few hours staring at the ATmega documentation and this will all make sense. 426 | // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. 427 | 428 | 429 | // Disable the Timer2 Interrupt (which is used for receiving IR) 430 | TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt 431 | 432 | pinMode(TIMER_PWM_PIN, OUTPUT); 433 | digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low 434 | 435 | // COM2A = 00: disconnect OC2A 436 | // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted 437 | // WGM2 = 101: phase-correct PWM with OCRA as top 438 | // CS2 = 000: no prescaling 439 | // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. 440 | TIMER_CONFIG_KHZ(khz); 441 | } 442 | 443 | IRrecv::IRrecv(int recvpin) 444 | { 445 | irparams.recvpin = recvpin; 446 | irparams.blinkflag = 0; 447 | } 448 | 449 | // initialization 450 | void IRrecv::enableIRIn() { 451 | cli(); 452 | if (digitalPinToPCICR(irparams.recvpin)) 453 | { 454 | *digitalPinToPCICR(irparams.recvpin) |= _BV(digitalPinToPCICRbit(irparams.recvpin)); 455 | *digitalPinToPCMSK(irparams.recvpin) |= _BV(digitalPinToPCMSKbit(irparams.recvpin)); 456 | } 457 | 458 | // initialize state machine variables 459 | irparams.rcvstate = STATE_IDLE; 460 | irparams.rawlen = 0; 461 | irparams.startTime = micros(); 462 | sei(); // enable interrupts 463 | 464 | // set pin modes 465 | pinMode(irparams.recvpin, INPUT); 466 | } 467 | 468 | // enable/disable blinking of pin 13 on IR processing 469 | void IRrecv::blink13(int blinkflag) 470 | { 471 | irparams.blinkflag = blinkflag; 472 | if (blinkflag) 473 | pinMode(BLINKLED, OUTPUT); 474 | } 475 | 476 | // TIMER2 interrupt code to collect raw data. 477 | // Widths of alternating SPACE, MARK are recorded in rawbuf. 478 | // Recorded in ticks of 50 microseconds. 479 | // rawlen counts the number of entries recorded so far. 480 | // First entry is the SPACE between transmissions. 481 | // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues. 482 | // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts 483 | void handle_interrupt() 484 | { 485 | uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); 486 | uint32_t now = micros(); 487 | uint32_t elapsed; 488 | if (now < irparams.startTime) 489 | elapsed = now+1+(0xFFFFFFFF-irparams.startTime); 490 | else 491 | elapsed = now-irparams.startTime; 492 | elapsed /= USECPERTICK; 493 | if (irparams.rawlen >= RAWBUF) { 494 | // Buffer overflow 495 | irparams.rcvstate = STATE_STOP; 496 | } 497 | switch(irparams.rcvstate) { 498 | case STATE_IDLE: // In the middle of a gap 499 | if (irdata == MARK) { 500 | if (elapsed < GAP_TICKS) { 501 | // Not big enough to be a gap. 502 | irparams.startTime = now; 503 | } else { 504 | // gap just ended, record duration and start recording transmission 505 | irparams.rawlen = 0; 506 | irparams.rawbuf[irparams.rawlen++] = MIN(elapsed, UINT16_MAX); 507 | irparams.startTime = now; 508 | irparams.rcvstate = STATE_MARK; 509 | } 510 | } 511 | break; 512 | case STATE_MARK: // timing MARK 513 | if (irdata == SPACE) { // MARK ended, record time 514 | irparams.rawbuf[irparams.rawlen++] = MIN(elapsed, UINT16_MAX); 515 | irparams.startTime = now; 516 | irparams.rcvstate = STATE_SPACE; 517 | } 518 | break; 519 | case STATE_SPACE: // timing SPACE 520 | if (irdata == MARK) { // SPACE just ended, record it 521 | irparams.rawbuf[irparams.rawlen++] = MIN(elapsed, UINT16_MAX); 522 | irparams.startTime = now; 523 | irparams.rcvstate = STATE_MARK; 524 | } 525 | else { // SPACE 526 | if (elapsed > GAP_TICKS) { 527 | // big SPACE, indicates gap between codes 528 | // Mark current code as ready for processing 529 | // Switch to STOP 530 | // Don't reset timer; keep counting space width 531 | irparams.rcvstate = STATE_STOP; 532 | } 533 | } 534 | break; 535 | case STATE_STOP: // waiting, measuring gap 536 | if (irdata == MARK) { // reset gap timer 537 | irparams.startTime = now; 538 | } 539 | break; 540 | } 541 | 542 | if (irparams.blinkflag) { 543 | if (irdata == MARK) { 544 | BLINKLED_ON(); // turn pin 13 LED on 545 | } 546 | else { 547 | BLINKLED_OFF(); // turn pin 13 LED off 548 | } 549 | } 550 | } 551 | 552 | void IRrecv::resume() { 553 | irparams.rcvstate = STATE_IDLE; 554 | irparams.rawlen = 0; 555 | } 556 | 557 | #if defined(PCINT0_vect) 558 | ISR(PCINT0_vect) 559 | { 560 | handle_interrupt(); 561 | } 562 | #endif 563 | 564 | #if defined(PCINT1_vect) 565 | ISR(PCINT1_vect) 566 | { 567 | handle_interrupt(); 568 | } 569 | #endif 570 | 571 | #if defined(PCINT2_vect) 572 | ISR(PCINT2_vect) 573 | { 574 | handle_interrupt(); 575 | } 576 | #endif 577 | 578 | #if defined(PCINT3_vect) 579 | ISR(PCINT3_vect) 580 | { 581 | handle_interrupt(); 582 | } 583 | #endif 584 | 585 | 586 | // Decodes the received IR message 587 | // Returns 0 if no data ready, 1 if data ready. 588 | // Results of decoding are stored in results 589 | int IRrecv::decode(decode_results *results) { 590 | cli(); 591 | handle_interrupt(); 592 | sei(); 593 | results->rawbuf = irparams.rawbuf; 594 | results->rawlen = irparams.rawlen; 595 | if (irparams.rcvstate != STATE_STOP) { 596 | return ERR; 597 | } 598 | #ifdef ENABLE_MagiQuest 599 | #ifdef DEBUG 600 | Serial.println("Attempting MagiQuest decode"); 601 | #endif 602 | if (decodeMagiQuest(results)) { 603 | return DECODED; 604 | } 605 | #endif //ENABLE_MagiQuest 606 | 607 | #ifndef ENABLE_NEC 608 | #ifdef DEBUG 609 | Serial.println("Attempting NEC decode"); 610 | #endif 611 | if (decodeNEC(results)) { 612 | return DECODED; 613 | } 614 | #endif //ENABLE_NEC 615 | 616 | #ifdef ENABLE_SONY 617 | #ifdef DEBUG 618 | Serial.println("Attempting Sony decode"); 619 | #endif 620 | if (decodeSony(results)) { 621 | return DECODED; 622 | } 623 | #endif //ENABLE_SONY 624 | 625 | #ifdef ENABLE_Sanyo 626 | #ifdef DEBUG 627 | Serial.println("Attempting Sanyo decode"); 628 | #endif 629 | if (decodeSanyo(results)) { 630 | return DECODED; 631 | } 632 | #endif //ENABLE_Sanyo 633 | 634 | #ifdef ENABLE_Mitsubishi 635 | #ifdef DEBUG 636 | Serial.println("Attempting Mitsubishi decode"); 637 | #endif 638 | if (decodeMitsubishi(results)) { 639 | return DECODED; 640 | } 641 | #endif //ENABLE_Mitsubishi 642 | 643 | #ifdef ENABLE_Panasonic 644 | #ifdef DEBUG 645 | Serial.println("Attempting Panasonic decode"); 646 | #endif 647 | if (decodePanasonic(results)) { 648 | return DECODED; 649 | } 650 | #endif //ENABLE_Panasonic 651 | 652 | #ifdef ENABLE_RC5 653 | #ifdef DEBUG 654 | Serial.println("Attempting RC5 decode"); 655 | #endif 656 | if (decodeRC5(results)) { 657 | return DECODED; 658 | } 659 | #endif //ENABLE_RC5 660 | 661 | #ifdef ENABLE_RC6 662 | #ifdef DEBUG 663 | Serial.println("Attempting RC6 decode"); 664 | #endif 665 | if (decodeRC6(results)) { 666 | return DECODED; 667 | } 668 | #endif //ENABLE_RC6 669 | 670 | #ifdef ENABLE_Syma 671 | #ifdef DEBUG 672 | Serial.println("Attempting Syma decode"); 673 | #endif 674 | if (decodeSyma(results)) { 675 | return DECODED; 676 | } 677 | #endif //ENABLE_Syma 678 | 679 | #ifdef ENABLE_Useries 680 | #ifdef DEBUG 681 | Serial.println("Attempting Useries decode"); 682 | #endif 683 | if (decodeUseries(results)) { 684 | return DECODED; 685 | } 686 | #endif //ENABLE_Useries 687 | 688 | #ifdef ENABLE_FastLane 689 | #ifdef DEBUG 690 | Serial.println("Attempting FastLane decode"); 691 | #endif 692 | if (decodeFastLane(results)) { 693 | return DECODED; 694 | } 695 | #endif //ENABLE_FastLane 696 | 697 | #ifdef ENABLE_JVC 698 | #ifdef DEBUG 699 | Serial.println("Attempting JVC decode"); 700 | #endif 701 | if (decodeJVC(results)) { 702 | return DECODED; 703 | } 704 | #endif //ENABLE_JVC 705 | 706 | #ifdef ENABLE_RCMM 707 | #ifdef DEBUG 708 | Serial.println("Attempting RCMM decode"); 709 | #endif 710 | if (decodeRCMM(results)) { 711 | return DECODED; 712 | } 713 | #endif //ENABLE_RCMM 714 | 715 | #ifndef IS_AVTINY 716 | // decodeHash returns a hash on any input. 717 | // Thus, it needs to be last in the list. 718 | // If you add any decodes, add them before this. 719 | if (decodeHash(results)) { 720 | return DECODED; 721 | } 722 | #endif //IS_AVTINY 723 | // Throw away and start over 724 | resume(); 725 | return ERR; 726 | } 727 | 728 | // NECs have a repeat only 4 items long 729 | long IRrecv::decodeNEC(decode_results *results) { 730 | long data = 0; 731 | int offset = 1; // Skip first space 732 | // Initial mark 733 | if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) { 734 | return ERR; 735 | } 736 | offset++; 737 | // Check for repeat 738 | if (irparams.rawlen == 4 && 739 | MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) && 740 | MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) { 741 | results->bits = 0; 742 | results->value = REPEAT; 743 | results->decode_type = NEC; 744 | return DECODED; 745 | } 746 | if (irparams.rawlen < 2 * NEC_BITS + 4) { 747 | return ERR; 748 | } 749 | // Initial space 750 | if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) { 751 | return ERR; 752 | } 753 | offset++; 754 | for (int i = 0; i < NEC_BITS; i++) { 755 | if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) { 756 | return ERR; 757 | } 758 | offset++; 759 | if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) { 760 | data = (data << 1) | 1; 761 | } 762 | else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) { 763 | data <<= 1; 764 | } 765 | else { 766 | return ERR; 767 | } 768 | offset++; 769 | } 770 | // Success 771 | results->bits = NEC_BITS; 772 | results->value = data; 773 | results->decode_type = NEC; 774 | return DECODED; 775 | } 776 | 777 | long IRrecv::decodeSony(decode_results *results) { 778 | long data = 0; 779 | if (irparams.rawlen < 2 * SONY_BITS + 2) { 780 | return ERR; 781 | } 782 | int offset = 0; // Dont skip first space, check its size 783 | 784 | // Some Sony's deliver repeats fast after first 785 | // unfortunately can't spot difference from of repeat from two fast clicks 786 | if (results->rawbuf[offset] < SONY_DOUBLE_SPACE_USECS) { 787 | // Serial.print("IR Gap found: "); 788 | results->bits = 0; 789 | results->value = REPEAT; 790 | results->decode_type = SANYO; 791 | return DECODED; 792 | } 793 | offset++; 794 | 795 | // Initial mark 796 | if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) { 797 | return ERR; 798 | } 799 | offset++; 800 | 801 | while (offset + 1 < irparams.rawlen) { 802 | if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) { 803 | break; 804 | } 805 | offset++; 806 | if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) { 807 | data = (data << 1) | 1; 808 | } 809 | else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) { 810 | data <<= 1; 811 | } 812 | else { 813 | return ERR; 814 | } 815 | offset++; 816 | } 817 | 818 | // Success 819 | results->bits = (offset - 1) / 2; 820 | if (results->bits < 12) { 821 | results->bits = 0; 822 | return ERR; 823 | } 824 | results->value = data; 825 | results->decode_type = SONY; 826 | return DECODED; 827 | } 828 | 829 | // I think this is a Sanyo decoder - serial = SA 8650B 830 | // Looks like Sony except for timings, 48 chars of data and time/space different 831 | long IRrecv::decodeSanyo(decode_results *results) { 832 | long data = 0; 833 | if (irparams.rawlen < 2 * SANYO_BITS + 2) { 834 | return ERR; 835 | } 836 | int offset = 0; // Skip first space 837 | // Initial space 838 | /* Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay 839 | Serial.print("IR Gap: "); 840 | Serial.println( results->rawbuf[offset]); 841 | Serial.println( "test against:"); 842 | Serial.println(results->rawbuf[offset]); 843 | */ 844 | if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) { 845 | // Serial.print("IR Gap found: "); 846 | results->bits = 0; 847 | results->value = REPEAT; 848 | results->decode_type = SANYO; 849 | return DECODED; 850 | } 851 | offset++; 852 | 853 | // Initial mark 854 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) { 855 | return ERR; 856 | } 857 | offset++; 858 | 859 | // Skip Second Mark 860 | if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) { 861 | return ERR; 862 | } 863 | offset++; 864 | 865 | while (offset + 1 < irparams.rawlen) { 866 | if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) { 867 | break; 868 | } 869 | offset++; 870 | if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) { 871 | data = (data << 1) | 1; 872 | } 873 | else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) { 874 | data <<= 1; 875 | } 876 | else { 877 | return ERR; 878 | } 879 | offset++; 880 | } 881 | 882 | // Success 883 | results->bits = (offset - 1) / 2; 884 | if (results->bits < 12) { 885 | results->bits = 0; 886 | return ERR; 887 | } 888 | results->value = data; 889 | results->decode_type = SANYO; 890 | return DECODED; 891 | } 892 | 893 | // Looks like Sony except for timings, 48 chars of data and time/space different 894 | long IRrecv::decodeMitsubishi(decode_results *results) { 895 | // Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2); 896 | long data = 0; 897 | if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) { 898 | return ERR; 899 | } 900 | int offset = 0; // Skip first space 901 | // Initial space 902 | /* Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay 903 | Serial.print("IR Gap: "); 904 | Serial.println( results->rawbuf[offset]); 905 | Serial.println( "test against:"); 906 | Serial.println(results->rawbuf[offset]); 907 | */ 908 | /* Not seeing double keys from Mitsubishi 909 | if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) { 910 | // Serial.print("IR Gap found: "); 911 | results->bits = 0; 912 | results->value = REPEAT; 913 | results->decode_type = MITSUBISHI; 914 | return DECODED; 915 | } 916 | */ 917 | offset++; 918 | 919 | // Typical 920 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 921 | 922 | // Initial Space 923 | if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) { 924 | return ERR; 925 | } 926 | offset++; 927 | while (offset + 1 < irparams.rawlen) { 928 | if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) { 929 | data = (data << 1) | 1; 930 | } 931 | else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) { 932 | data <<= 1; 933 | } 934 | else { 935 | // Serial.println("A"); Serial.println(offset); Serial.println(results->rawbuf[offset]); 936 | return ERR; 937 | } 938 | offset++; 939 | if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) { 940 | // Serial.println("B"); Serial.println(offset); Serial.println(results->rawbuf[offset]); 941 | break; 942 | } 943 | offset++; 944 | } 945 | 946 | // Success 947 | results->bits = (offset - 1) / 2; 948 | if (results->bits < MITSUBISHI_BITS) { 949 | results->bits = 0; 950 | return ERR; 951 | } 952 | results->value = data; 953 | results->decode_type = MITSUBISHI; 954 | return DECODED; 955 | } 956 | 957 | 958 | // Gets one undecoded level at a time from the raw buffer. 959 | // The RC5/6 decoding is easier if the data is broken into time intervals. 960 | // E.g. if the buffer has MARK for 2 time intervals and SPACE for 1, 961 | // successive calls to getRClevel will return MARK, MARK, SPACE. 962 | // offset and used are updated to keep track of the current position. 963 | // t1 is the time interval for a single bit in microseconds. 964 | // Returns -1 for error (measured time interval is not a multiple of t1). 965 | int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) { 966 | if (*offset >= results->rawlen) { 967 | // After end of recorded buffer, assume SPACE. 968 | return SPACE; 969 | } 970 | int width = results->rawbuf[*offset]; 971 | int val = ((*offset) % 2) ? MARK : SPACE; 972 | int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS; 973 | 974 | int avail; 975 | if (MATCH(width, t1 + correction)) { 976 | avail = 1; 977 | } 978 | if (((avail < 0) || (val == MARK)) && MATCH(width, 2*t1 + correction)) { 979 | avail = 2; 980 | } 981 | if (((avail < 0) || (val == MARK)) && MATCH(width, 3*t1 + correction)) { 982 | avail = 3; 983 | } 984 | if (avail < 0) { 985 | return -1; 986 | } 987 | 988 | (*used)++; 989 | if (*used >= avail) { 990 | *used = 0; 991 | (*offset)++; 992 | } 993 | #ifdef DEBUG 994 | if (val == MARK) { 995 | Serial.println("MARK"); 996 | } 997 | else { 998 | Serial.println("SPACE"); 999 | } 1000 | #endif 1001 | return val; 1002 | } 1003 | 1004 | long IRrecv::decodeRC5(decode_results *results) { 1005 | if (irparams.rawlen < MIN_RC5_SAMPLES + 2) { 1006 | return ERR; 1007 | } 1008 | int offset = 1; // Skip gap space 1009 | long data = 0; 1010 | int used = 0; 1011 | // Get start bits 1012 | if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; 1013 | if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR; 1014 | if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; 1015 | int nbits; 1016 | for (nbits = 0; offset < irparams.rawlen; nbits++) { 1017 | int levelA = getRClevel(results, &offset, &used, RC5_T1); 1018 | int levelB = getRClevel(results, &offset, &used, RC5_T1); 1019 | if (levelA == SPACE && levelB == MARK) { 1020 | // 1 bit 1021 | data = (data << 1) | 1; 1022 | } 1023 | else if (levelA == MARK && levelB == SPACE) { 1024 | // zero bit 1025 | data <<= 1; 1026 | } 1027 | else { 1028 | return ERR; 1029 | } 1030 | } 1031 | 1032 | // Success 1033 | results->bits = nbits; 1034 | results->value = data; 1035 | results->decode_type = RC5; 1036 | return DECODED; 1037 | } 1038 | 1039 | long IRrecv::decodeRC6(decode_results *results) { 1040 | if (results->rawlen < MIN_RC6_SAMPLES) { 1041 | return ERR; 1042 | } 1043 | int offset = 1; // Skip first space 1044 | // Initial mark 1045 | if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) { 1046 | return ERR; 1047 | } 1048 | offset++; 1049 | if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) { 1050 | return ERR; 1051 | } 1052 | offset++; 1053 | long data = 0; 1054 | int used = 0; 1055 | // Get start bit (1) 1056 | if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR; 1057 | if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR; 1058 | int nbits; 1059 | for (nbits = 0; offset < results->rawlen; nbits++) { 1060 | int levelA, levelB; // Next two levels 1061 | levelA = getRClevel(results, &offset, &used, RC6_T1); 1062 | if (nbits == 3) { 1063 | // T bit is double wide; make sure second half matches 1064 | if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR; 1065 | } 1066 | levelB = getRClevel(results, &offset, &used, RC6_T1); 1067 | if (nbits == 3) { 1068 | // T bit is double wide; make sure second half matches 1069 | if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR; 1070 | } 1071 | if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5 1072 | // 1 bit 1073 | data = (data << 1) | 1; 1074 | } 1075 | else if (levelA == SPACE && levelB == MARK) { 1076 | // zero bit 1077 | data <<= 1; 1078 | } 1079 | else { 1080 | return ERR; // Error 1081 | } 1082 | } 1083 | // Success 1084 | results->bits = nbits; 1085 | results->value = data; 1086 | results->decode_type = RC6; 1087 | return DECODED; 1088 | } 1089 | long IRrecv::decodePanasonic(decode_results *results) { 1090 | unsigned long long data = 0; 1091 | int offset = 1; 1092 | 1093 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) { 1094 | return ERR; 1095 | } 1096 | offset++; 1097 | if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) { 1098 | return ERR; 1099 | } 1100 | offset++; 1101 | 1102 | // decode address 1103 | for (int i = 0; i < PANASONIC_BITS; i++) { 1104 | if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) { 1105 | return ERR; 1106 | } 1107 | if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE)) { 1108 | data = (data << 1) | 1; 1109 | } else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) { 1110 | data <<= 1; 1111 | } else { 1112 | return ERR; 1113 | } 1114 | offset++; 1115 | } 1116 | results->value = (unsigned long)data; 1117 | results->panasonicAddress = (unsigned int)(data >> 32); 1118 | results->decode_type = PANASONIC; 1119 | results->bits = PANASONIC_BITS; 1120 | return DECODED; 1121 | } 1122 | int32_t IRrecv::decodeSyma(decode_results *results) { 1123 | uint32_t data = 0; 1124 | int16_t offset = 1; 1125 | uint8_t syma_len; 1126 | 1127 | if (irparams.rawlen == 2 * (SYMA_R5_BITS + 2)) { 1128 | syma_len = SYMA_R5_BITS; 1129 | } 1130 | else if (irparams.rawlen == 2 * (SYMA_R3_BITS + 2)) { 1131 | syma_len = SYMA_R3_BITS; 1132 | } 1133 | else { 1134 | return ERR; 1135 | } 1136 | if (!MATCH_MARK(results->rawbuf[offset], SYMA_HDR_MARK)) { 1137 | return ERR; 1138 | } 1139 | offset++; 1140 | if (!MATCH_MARK(results->rawbuf[offset], SYMA_HDR_SPACE)) { 1141 | return ERR; 1142 | } 1143 | offset++; 1144 | for (uint8_t i = 0; i < syma_len; i++) { 1145 | if (!MATCH_MARK(results->rawbuf[offset++], SYMA_BIT_MARK)) { 1146 | return ERR; 1147 | } 1148 | if (MATCH_SPACE(results->rawbuf[offset], SYMA_ONE_SPACE)) { 1149 | data = (data << 1) | 1; 1150 | } else if (MATCH_SPACE(results->rawbuf[offset], SYMA_ZERO_SPACE)) { 1151 | data <<= 1; 1152 | } else { 1153 | return ERR; 1154 | } 1155 | offset++; 1156 | } 1157 | results->value = data; 1158 | if (syma_len == SYMA_R5_BITS) { 1159 | results->decode_type = SYMA_R5; 1160 | } 1161 | else if (syma_len == SYMA_R3_BITS) { 1162 | results->decode_type = SYMA_R3; 1163 | } 1164 | results->bits = syma_len; 1165 | results->helicopter.dword = data; 1166 | return DECODED; 1167 | } 1168 | int32_t IRrecv::decodeUseries(decode_results *results) { 1169 | uint32_t data = 0; 1170 | int16_t offset = 1; 1171 | if (irparams.rawlen < 2 * (USERIES_BITS + 2)) { 1172 | return ERR; 1173 | } 1174 | if (!MATCH_MARK(results->rawbuf[offset], USERIES_HDR_MARK)) { 1175 | return ERR; 1176 | } 1177 | offset++; 1178 | for (int16_t i = 0; i < USERIES_BITS; i++) { 1179 | if (!MATCH_SPACE(results->rawbuf[offset++], USERIES_BIT_SPACE)) { 1180 | return ERR; 1181 | } 1182 | if (MATCH_MARK(results->rawbuf[offset],USERIES_ONE_MARK)) { 1183 | data <<= 1; 1184 | } else if (MATCH_MARK(results->rawbuf[offset],USERIES_ZERO_MARK)) { 1185 | data = (data << 1) | 1; 1186 | } else { 1187 | return ERR; 1188 | } 1189 | offset++; 1190 | } 1191 | results->value = data; 1192 | results->helicopter.dword = data; 1193 | results->parity = UseriesChecksum(data); 1194 | results->decode_type = USERIES; 1195 | results->bits = USERIES_BITS; 1196 | return DECODED; 1197 | } 1198 | int32_t IRrecv::decodeFastLane(decode_results *results) { 1199 | helicopter data; 1200 | data.dword = 0; 1201 | int16_t offset = 1; 1202 | if (irparams.rawlen < (FASTLANE_BITS + 2)) { 1203 | return ERR; 1204 | } 1205 | if (!MATCH_MARK(results->rawbuf[offset], FASTLANE_HDR_MARK)) { 1206 | return ERR; 1207 | } 1208 | offset++; 1209 | for (int16_t i = 0; i < FASTLANE_BITS; i++) { 1210 | if (MATCH_MARK(results->rawbuf[offset],FASTLANE_ZERO)) { 1211 | data.dword <<= 1; 1212 | } else if (MATCH_MARK(results->rawbuf[offset],FASTLANE_ONE)) { 1213 | data.dword = (data.dword << 1) | 1; 1214 | } else { 1215 | return ERR; 1216 | } 1217 | offset++; 1218 | } 1219 | results->value = data.dword; 1220 | results->helicopter.dword = data.dword; 1221 | results->decode_type = FASTLANE; 1222 | results->bits = FASTLANE_BITS; 1223 | return DECODED; 1224 | } 1225 | long IRrecv::decodeJVC(decode_results *results) { 1226 | long data = 0; 1227 | int offset = 1; // Skip first space 1228 | // Check for repeat 1229 | if (irparams.rawlen - 1 == 33 && 1230 | MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) && 1231 | MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK)) { 1232 | results->bits = 0; 1233 | results->value = REPEAT; 1234 | results->decode_type = JVC; 1235 | return DECODED; 1236 | } 1237 | // Initial mark 1238 | if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) { 1239 | return ERR; 1240 | } 1241 | offset++; 1242 | if (irparams.rawlen < 2 * JVC_BITS + 1 ) { 1243 | return ERR; 1244 | } 1245 | // Initial space 1246 | if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) { 1247 | return ERR; 1248 | } 1249 | offset++; 1250 | for (int i = 0; i < JVC_BITS; i++) { 1251 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) { 1252 | return ERR; 1253 | } 1254 | offset++; 1255 | if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) { 1256 | data = (data << 1) | 1; 1257 | } 1258 | else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) { 1259 | data <<= 1; 1260 | } 1261 | else { 1262 | return ERR; 1263 | } 1264 | offset++; 1265 | } 1266 | //Stop bit 1267 | if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)){ 1268 | return ERR; 1269 | } 1270 | // Success 1271 | results->bits = JVC_BITS; 1272 | results->value = data; 1273 | results->decode_type = JVC; 1274 | return DECODED; 1275 | } 1276 | 1277 | long IRrecv::decodeRCMM(decode_results *results) { 1278 | long data = 0; 1279 | if (irparams.rawlen < RCMM_BITS + 4) { 1280 | return ERR; 1281 | } 1282 | int offset = 1; // Skip first space 1283 | // Initial mark 1284 | if (!MATCH_MARK(results->rawbuf[offset], RCMM_HDR_MARK)) { 1285 | return ERR; 1286 | } 1287 | offset++; 1288 | if (!MATCH_SPACE(results->rawbuf[offset], RCMM_SPACE)) { 1289 | return ERR; 1290 | } 1291 | offset++; 1292 | 1293 | while (offset + 1 < irparams.rawlen) { 1294 | if (!MATCH_MARK(results->rawbuf[offset], RCMM_MARK)) { 1295 | return ERR; 1296 | } 1297 | offset++; 1298 | if (MATCH_SPACE(results->rawbuf[offset], RCMM_SPACE)) { 1299 | data = (data << 2) | 0; 1300 | } 1301 | else if (MATCH_SPACE(results->rawbuf[offset], RCMM_SPACE+RCMM_INCREMENT)) { 1302 | data = (data << 2) | 1; 1303 | } 1304 | else if (MATCH_SPACE(results->rawbuf[offset], RCMM_SPACE+2*RCMM_INCREMENT)) { 1305 | data = (data << 2) | 2; 1306 | } 1307 | else if (MATCH_SPACE(results->rawbuf[offset], RCMM_SPACE+3*RCMM_INCREMENT)) { 1308 | data = (data << 2) | 3; 1309 | } 1310 | else { 1311 | return ERR; 1312 | } 1313 | offset++; 1314 | } 1315 | if (!MATCH_MARK(results->rawbuf[offset], RCMM_MARK)) { 1316 | return ERR; 1317 | } 1318 | 1319 | // Success 1320 | results->bits = (offset - 3); 1321 | if (results->bits < RCMM_BITS) { 1322 | results->bits = 0; 1323 | return ERR; 1324 | } 1325 | results->value = data; 1326 | results->decode_type = RCMM; 1327 | return DECODED; 1328 | } 1329 | 1330 | int32_t IRrecv::decodeMagiQuest(decode_results *results) { 1331 | magiquest data; 1332 | data.llword = 0; 1333 | 1334 | int16_t offset = 1; 1335 | uint16_t mark_; 1336 | uint16_t space_; 1337 | uint8_t multiple_; 1338 | 1339 | if (irparams.rawlen < 2 * MAGIQUEST_BITS) { 1340 | return ERR; 1341 | } 1342 | 1343 | while (offset + 1 < irparams.rawlen) { 1344 | mark_ = results->rawbuf[offset]; 1345 | space_ = results->rawbuf[offset+1]; 1346 | multiple_ = space_ / mark_; 1347 | // it is either 25% + 75% or 50% + 50% 1348 | 1349 | #ifdef DEBUG 1350 | Serial.print("mark="); 1351 | Serial.print(mark_ * USECPERTICK); 1352 | Serial.print(" space="); 1353 | Serial.print(space_ * USECPERTICK); 1354 | Serial.print(" mult="); 1355 | Serial.print(multiple_); 1356 | Serial.print(" "); 1357 | #endif 1358 | if (MATCH_MARK(space_ + mark_, MAGIQUEST_PERIOD)) { 1359 | if (multiple_ > 1) { 1360 | #ifdef DEBUG 1361 | Serial.print("0-MPF "); 1362 | MATCH_MARK(results->rawbuf[offset], MAGIQUEST_MARK_ZERO); 1363 | #endif 1364 | data.llword <<= 1; 1365 | } else { 1366 | #ifdef DEBUG 1367 | Serial.print("1-MPF "); 1368 | MATCH_MARK(results->rawbuf[offset], MAGIQUEST_MARK_ONE); 1369 | #endif 1370 | data.llword = (data.llword << 1) | 1; 1371 | } 1372 | } else { 1373 | return ERR; 1374 | } 1375 | offset++; 1376 | offset++; 1377 | } 1378 | // Success 1379 | results->bits = (offset + 1) / 2; 1380 | if (results->bits < 12) { 1381 | results->bits = 0; 1382 | return ERR; 1383 | } 1384 | results->magiquestMagnitude = data.cmd.magnitude; 1385 | results->value = data.cmd.wand_id; 1386 | results->decode_type = MAGIQUEST; 1387 | return DECODED; 1388 | } 1389 | 1390 | /* ----------------------------------------------------------------------- 1391 | * hashdecode - decode an arbitrary IR code. 1392 | * Instead of decoding using a standard encoding scheme 1393 | * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value. 1394 | * 1395 | * The algorithm: look at the sequence of MARK signals, and see if each one 1396 | * is shorter (0), the same length (1), or longer (2) than the previous. 1397 | * Do the same with the SPACE signals. Hszh the resulting sequence of 0's, 1398 | * 1's, and 2's to a 32-bit value. This will give a unique value for each 1399 | * different code (probably), for most code systems. 1400 | * 1401 | * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html 1402 | */ 1403 | 1404 | // Compare two tick values, returning 0 if newval is shorter, 1405 | // 1 if newval is equal, and 2 if newval is longer 1406 | // Use a tolerance of 20% 1407 | int IRrecv::compare(unsigned int oldval, unsigned int newval) { 1408 | if (newval < oldval * .8) { 1409 | return 0; 1410 | } 1411 | else if (oldval < newval * .8) { 1412 | return 2; 1413 | } 1414 | else { 1415 | return 1; 1416 | } 1417 | } 1418 | 1419 | // Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param 1420 | #define FNV_PRIME_32 16777619 1421 | #define FNV_BASIS_32 2166136261 1422 | 1423 | /* Converts the raw code values into a 32-bit hash code. 1424 | * Hopefully this code is unique for each button. 1425 | * This isn't a "real" decoding, just an arbitrary value. 1426 | */ 1427 | long IRrecv::decodeHash(decode_results *results) { 1428 | // Require at least 6 samples to prevent triggering on noise 1429 | if (results->rawlen < 6) { 1430 | return ERR; 1431 | } 1432 | long hash = FNV_BASIS_32; 1433 | for (int i = 1; i+2 < results->rawlen; i++) { 1434 | int value = compare(results->rawbuf[i], results->rawbuf[i+2]); 1435 | // Add value into the hash 1436 | hash = (hash * FNV_PRIME_32) ^ value; 1437 | } 1438 | results->value = hash; 1439 | results->bits = 32; 1440 | results->decode_type = UNKNOWN; 1441 | return DECODED; 1442 | } 1443 | 1444 | /* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand ) 1445 | 1446 | The Dish send function needs to be repeated 4 times, and the Sharp function 1447 | has the necessary repeat built in because of the need to invert the signal. 1448 | 1449 | Sharp protocol documentation: 1450 | http://www.sbprojects.com/knowledge/ir/sharp.htm 1451 | 1452 | Here are the LIRC files that I found that seem to match the remote codes 1453 | from the oscilloscope: 1454 | 1455 | Sharp LCD TV: 1456 | http://lirc.sourceforge.net/remotes/sharp/GA538WJSA 1457 | 1458 | DISH NETWORK (echostar 301): 1459 | http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx 1460 | 1461 | For the DISH codes, only send the last for characters of the hex. 1462 | i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the 1463 | linked LIRC file. 1464 | */ 1465 | 1466 | void IRsend::sendSharp(unsigned long data, int nbits) { 1467 | unsigned long invertdata = data ^ SHARP_TOGGLE_MASK; 1468 | enableIROut(38); 1469 | for (int i = 0; i < nbits; i++) { 1470 | if (data & 0x4000) { 1471 | mark(SHARP_BIT_MARK); 1472 | space(SHARP_ONE_SPACE); 1473 | } 1474 | else { 1475 | mark(SHARP_BIT_MARK); 1476 | space(SHARP_ZERO_SPACE); 1477 | } 1478 | data <<= 1; 1479 | } 1480 | 1481 | mark(SHARP_BIT_MARK); 1482 | space(SHARP_ZERO_SPACE); 1483 | delay(46); 1484 | for (int i = 0; i < nbits; i++) { 1485 | if (invertdata & 0x4000) { 1486 | mark(SHARP_BIT_MARK); 1487 | space(SHARP_ONE_SPACE); 1488 | } 1489 | else { 1490 | mark(SHARP_BIT_MARK); 1491 | space(SHARP_ZERO_SPACE); 1492 | } 1493 | invertdata <<= 1; 1494 | } 1495 | mark(SHARP_BIT_MARK); 1496 | space(SHARP_ZERO_SPACE); 1497 | delay(46); 1498 | } 1499 | 1500 | void IRsend::sendDISH(unsigned long data, int nbits) 1501 | { 1502 | enableIROut(56); 1503 | mark(DISH_HDR_MARK); 1504 | space(DISH_HDR_SPACE); 1505 | for (int i = 0; i < nbits; i++) { 1506 | if (data & DISH_TOP_BIT) { 1507 | mark(DISH_BIT_MARK); 1508 | space(DISH_ONE_SPACE); 1509 | } 1510 | else { 1511 | mark(DISH_BIT_MARK); 1512 | space(DISH_ZERO_SPACE); 1513 | } 1514 | data <<= 1; 1515 | } 1516 | } 1517 | uint8_t UseriesChecksum(uint32_t val) 1518 | { 1519 | const uint8_t map[8] = { 0, 1, 3, 2, 6, 7, 5, 4 }; 1520 | uint32_t x = val & 0xFFFFFFF8; 1521 | uint32_t p = x; 1522 | while ((x >>= 7) != 0) { 1523 | p ^= x; 1524 | } 1525 | p = (p ^ (p >> 1) ^ (p >> 2) ^ (p >> 4)) & 7; 1526 | return(map[p]); 1527 | } 1528 | -------------------------------------------------------------------------------- /IRremote.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote 3 | * Version 0.1 July, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com 6 | * Edited by Mitra to add new controller SANYO 7 | * 8 | * Interrupt code based on NECIRrcv by Joe Knapp 9 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 10 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 11 | * 12 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 13 | * 14 | * RCMM protocol added by Matthias Neeracher. 15 | */ 16 | 17 | #ifndef IRremote_h 18 | #define IRremote_h 19 | #include 20 | 21 | // The following are compile-time library options. 22 | // If you change them, recompile the library. 23 | // If DEBUG is defined, a lot of debugging output will be printed during decoding. 24 | // TEST must be defined for the IRtest unittests to work. It will make some 25 | // methods virtual, which will be slightly slower, which is why it is optional. 26 | // #define DEBUG 27 | //#define TEST 28 | 29 | // MagiQuest packet is both Wand ID and magnitude of swish and flick 30 | union magiquest { 31 | uint64_t llword; 32 | uint8_t byte[8]; 33 | // uint16_t word[4]; 34 | uint32_t lword[2]; 35 | struct { 36 | uint16_t magnitude; 37 | uint32_t wand_id; 38 | uint8_t padding; 39 | uint8_t scrap; 40 | } cmd ; 41 | } ; 42 | 43 | union helicopter { 44 | uint32_t dword; 45 | struct 46 | { 47 | uint8_t Throttle : 7; // 0..6 0 - 127 48 | uint8_t Channel : 1; // 7 A=0, B=1 49 | uint8_t Pitch : 7; // 8..14 0(forward) - 63(center) 127(back) 50 | uint8_t Pspacer : 1; // 15 na 51 | uint8_t Yaw : 7; // 16..22 127(left) - 63(center) - 0(right) 52 | } symaR3; 53 | struct 54 | { 55 | uint8_t Trim : 7; // 0..6 127(left) - 63(center) - 0(right) 56 | uint8_t Tspacer : 1; // 7 na 57 | uint8_t Throttle : 7; // 8..14 0 - 127 58 | uint8_t Channel : 1; // 15 A=0, B=1 59 | uint8_t Pitch : 7; // 16..22 0(forward) - 63(center) 127(back) 60 | uint8_t Pspacer : 1; // 23 na 61 | uint8_t Yaw : 7; // 24..30 127(left) - 63(center) - 0(right) 62 | } symaR5; 63 | struct 64 | { 65 | uint8_t cksum : 3; // 0..2 66 | uint8_t Rbutton : 1; // 3 0-normally off, 1-depressed 67 | uint8_t Lbutton : 1; // 4 0-normally off, 1-depressed 68 | uint8_t Turbo : 1; // 5 1-off, 0-on 69 | uint8_t Channel : 2; // 6,7 A=1, B=2, C=0 70 | uint8_t Trim : 6; // 8..13 (left)63 - 31(center) - 0(right) 71 | uint8_t Yaw : 5; // 14..18 31(left) - 15(center) - 0(right) 72 | uint8_t Pitch : 6; // 19..24 0(foward) - 31(center) - 63(back) 73 | uint8_t Throttle : 7; // 25..31 0 - 127 74 | } uSeries; 75 | struct 76 | { 77 | uint8_t Trim : 4; // 0..3 15(left) - 8(center) - 0(right) 78 | uint8_t Trim_dir : 1; // 4 0= , 1= 79 | uint8_t Yaw_dir : 1; // 5 80 | uint8_t Fire : 1; // 6 81 | uint8_t Yaw : 4; // 7..10 15(left) - 8(center) - 0(right) 82 | uint8_t Pitch : 4; // 11..14 1(back) - 8(center) 15(forward) 83 | uint8_t Throttle : 6; // 15..20 0 - 63 84 | uint8_t Channel : 2; // 21..22 ?A=0, B=1 85 | } fastlane; 86 | }; 87 | 88 | // Results returned from the decoder 89 | class decode_results { 90 | public: 91 | int16_t decode_type; // NEC, SONY, RC5, UNKNOWN 92 | uint16_t panasonicAddress; // This is only used for decoding Panasonic data 93 | uint16_t magiquestMagnitude; // This is only used for MagiQuest 94 | int32_t value; // Decoded value //mpf need to make unsigned. 95 | union helicopter helicopter; 96 | unsigned int parity; 97 | int bits; // Number of bits in decoded value 98 | volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks 99 | int rawlen; // Number of records in rawbuf. 100 | }; 101 | 102 | // Values for decode_type 103 | #define NEC 1 104 | #define SONY 2 105 | #define RC5 3 106 | #define RC6 4 107 | #define DISH 5 108 | #define SHARP 6 109 | #define PANASONIC 7 110 | #define JVC 8 111 | #define SANYO 9 112 | #define MITSUBISHI 10 113 | #define MAGIQUEST 11 114 | #define SYMA_R3 12 115 | #define SYMA_R5 13 116 | #define USERIES 14 117 | #define FASTLANE 15 118 | #define RCMM 16 119 | #define UNKNOWN -1 120 | 121 | // Decoded value for NEC when a repeat code is received 122 | #define REPEAT 0xffffffff 123 | 124 | // main class for receiving IR 125 | class IRrecv 126 | { 127 | public: 128 | IRrecv(int recvpin); 129 | void blink13(int blinkflag); 130 | int decode(decode_results *results); 131 | void enableIRIn(); 132 | void resume(); 133 | private: 134 | // These are called by decode 135 | int getRClevel(decode_results *results, int *offset, int *used, int t1); 136 | long decodeNEC(decode_results *results); 137 | long decodeSony(decode_results *results); 138 | long decodeSanyo(decode_results *results); 139 | long decodeMitsubishi(decode_results *results); 140 | long decodeRC5(decode_results *results); 141 | long decodeRC6(decode_results *results); 142 | long decodePanasonic(decode_results *results); 143 | long decodeJVC(decode_results *results); 144 | long decodeRCMM(decode_results *results); 145 | long decodeHash(decode_results *results); 146 | long decodeSyma(decode_results *results); 147 | long decodeUseries(decode_results *results); 148 | long decodeFastLane(decode_results *results); 149 | long decodeMagiQuest(decode_results *results); 150 | int compare(unsigned int oldval, unsigned int newval); 151 | 152 | } 153 | ; 154 | 155 | uint8_t UseriesChecksum(uint32_t val); 156 | 157 | // Only used for testing; can remove virtual for shorter code 158 | #ifdef TEST 159 | #define VIRTUAL virtual 160 | #else 161 | #define VIRTUAL 162 | #endif 163 | 164 | class IRsend 165 | { 166 | public: 167 | IRsend() {} 168 | void sendNEC(unsigned long data, int nbits); 169 | void sendSony(unsigned long data, int nbits); 170 | // Neither Sanyo nor Mitsubishi send is implemented yet 171 | // void sendSanyo(unsigned long data, int nbits); 172 | // void sendMitsubishi(unsigned long data, int nbits); 173 | void sendRaw(unsigned int buf[], int len, int hz); 174 | void sendRC5(unsigned long data, int nbits); 175 | void sendRC6(unsigned long data, int nbits); 176 | void sendDISH(unsigned long data, int nbits); 177 | void sendSharp(unsigned long data, int nbits); 178 | void sendPanasonic(unsigned int address, unsigned long data); 179 | void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does. 180 | void sendMagiQuest(unsigned long wand_id, unsigned magitude); 181 | void sendSymaR5(unsigned long data); 182 | void sendSymaR3(unsigned long data); 183 | void sendUseries(unsigned long data); 184 | void sendFastLane(unsigned long data); 185 | void sendRCMM(unsigned long data, int nbits); 186 | // private: 187 | void enableIROut(int khz); 188 | VIRTUAL void mark(int usec); 189 | VIRTUAL void space(int usec); 190 | void on(unsigned int freq); 191 | void off(void); 192 | } 193 | ; 194 | 195 | // Some useful constants 196 | 197 | #define USECPERTICK 25 // microseconds per clock interrupt tick 198 | #define RAWBUF 112 // Length of raw duration buffer 199 | 200 | // Marks tend to be 100us too long, and spaces 100us too short 201 | // when received due to sensor lag. 202 | #define MARK_EXCESS 50 203 | #endif 204 | 205 | -------------------------------------------------------------------------------- /IRremoteInt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote 3 | * Version 0.1 July, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 6 | * 7 | * Modified by Paul Stoffregen and Matthias Neeracher to support other boards and timers 8 | * 9 | * Interrupt code based on NECIRrcv by Joe Knapp 10 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 11 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 12 | * 13 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 14 | * 15 | * RC-MM protocol added by Matthias Neeracher. 16 | */ 17 | 18 | #ifndef IRremoteint_h 19 | #define IRremoteint_h 20 | 21 | #if defined(ARDUINO) && ARDUINO >= 100 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | // define which timer to use 28 | // 29 | // Uncomment the timer you wish to use on your board. If you 30 | // are using another library which uses timer2, you have options 31 | // to switch IRremote to use a different timer. 32 | 33 | // Arduino Mega 34 | #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 35 | //#define IR_USE_TIMER1 // tx = pin 11 36 | #define IR_USE_TIMER2 // tx = pin 9 37 | //#define IR_USE_TIMER3 // tx = pin 5 38 | //#define IR_USE_TIMER4 // tx = pin 6 39 | //#define IR_USE_TIMER5 // tx = pin 46 40 | 41 | // Teensy 1.0 42 | #elif defined(__AVR_AT90USB162__) 43 | #define IR_USE_TIMER1 // tx = pin 17 44 | 45 | // Teensy 2.0 46 | #elif defined(__AVR_ATmega32U4__) 47 | //#define IR_USE_TIMER1 // tx = pin 14 48 | //#define IR_USE_TIMER3 // tx = pin 9 49 | #define IR_USE_TIMER4_HS // tx = pin 10 50 | 51 | // Teensy 3.0 52 | #elif defined(__MK20DX128__) 53 | #define IR_USE_TIMER_CMT // tx = pin 5 54 | 55 | // Teensy++ 1.0 & 2.0 56 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 57 | //#define IR_USE_TIMER1 // tx = pin 25 58 | #define IR_USE_TIMER2 // tx = pin 1 59 | //#define IR_USE_TIMER3 // tx = pin 16 60 | 61 | // Sanguino 62 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 63 | //#define IR_USE_TIMER1 // tx = pin 13 64 | #define IR_USE_TIMER2 // tx = pin 14 65 | 66 | // Atmega8 67 | #elif defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__) 68 | #define IR_USE_TIMER1 // tx = pin 9 69 | 70 | // Tested with ATtiny85, presumably works with ATtiny45, possibly with ATtiny25 71 | // The attiny core uses Timer 0 for millis() etc., so using timer 1 is advisable 72 | // for IR out. Pin 4 also conveniently is not used in any role for ISP. 73 | // The Arduino-tiny core uses Timer 1 for millis(), so using timer 0 is advisable 74 | // for IR out. Pin 0 is used by default for IR out in the Tinyspark IR shield, but 75 | // is not usable for PWM waveforms where the frequency, not just the duty cycle, 76 | // needs to be controlled. 77 | #elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 78 | #define IR_USE_TIMER1_TINY // tx = pin 4 (OC1B) 79 | // #define IR_USE_TIMER0 // tx = pin 1 (OC0B) 80 | // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc 81 | #else 82 | //#define IR_USE_TIMER1 // tx = pin 9 83 | #define IR_USE_TIMER2 // tx = pin 3 84 | #endif 85 | 86 | 87 | 88 | #ifdef F_CPU 89 | #define SYSCLOCK F_CPU // main Arduino clock 90 | #else 91 | #define SYSCLOCK 16000000 // main Arduino clock 92 | #endif 93 | 94 | #define ERR 0 95 | #define DECODED 1 96 | 97 | 98 | // defines for setting and clearing register bits 99 | #ifndef cbi 100 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 101 | #endif 102 | #ifndef sbi 103 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 104 | #endif 105 | 106 | // Pulse parms are *50-100 for the Mark and *50+100 for the space 107 | // First MARK is the one after the long gap 108 | // pulse parameters in usec 109 | #define NEC_HDR_MARK 9000 110 | #define NEC_HDR_SPACE 4500 111 | #define NEC_BIT_MARK 560 112 | #define NEC_ONE_SPACE 1600 113 | #define NEC_ZERO_SPACE 560 114 | #define NEC_RPT_SPACE 2250 115 | 116 | #define SONY_HDR_MARK 2400 117 | #define SONY_HDR_SPACE 600 118 | #define SONY_ONE_MARK 1200 119 | #define SONY_ZERO_MARK 600 120 | #define SONY_RPT_LENGTH 45000 121 | #define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround 122 | 123 | // SA 8650B 124 | #define SANYO_HDR_MARK 3500 // seen range 3500 125 | #define SANYO_HDR_SPACE 950 // seen 950 126 | #define SANYO_ONE_MARK 2400 // seen 2400 127 | #define SANYO_ZERO_MARK 700 // seen 700 128 | #define SANYO_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround 129 | #define SANYO_RPT_LENGTH 45000 130 | 131 | // Mitsubishi RM 75501 132 | // 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 133 | 134 | // #define MITSUBISHI_HDR_MARK 250 // seen range 3500 135 | #define MITSUBISHI_HDR_SPACE 350 // 7*50+100 136 | #define MITSUBISHI_ONE_MARK 1950 // 41*50-100 137 | #define MITSUBISHI_ZERO_MARK 750 // 17*50-100 138 | // #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround 139 | // #define MITSUBISHI_RPT_LENGTH 45000 140 | 141 | 142 | #define RC5_T1 889 143 | #define RC5_RPT_LENGTH 46000 144 | 145 | #define RC6_HDR_MARK 2666 146 | #define RC6_HDR_SPACE 889 147 | #define RC6_T1 444 148 | #define RC6_RPT_LENGTH 46000 149 | 150 | #define SHARP_BIT_MARK 245 151 | #define SHARP_ONE_SPACE 1805 152 | #define SHARP_ZERO_SPACE 795 153 | #define SHARP_GAP 600000 154 | #define SHARP_TOGGLE_MASK 0x3FF 155 | #define SHARP_RPT_SPACE 3000 156 | 157 | #define DISH_HDR_MARK 400 158 | #define DISH_HDR_SPACE 6100 159 | #define DISH_BIT_MARK 400 160 | #define DISH_ONE_SPACE 1700 161 | #define DISH_ZERO_SPACE 2800 162 | #define DISH_RPT_SPACE 6200 163 | #define DISH_TOP_BIT 0x8000 164 | 165 | #define PANASONIC_HDR_MARK 3502 166 | #define PANASONIC_HDR_SPACE 1750 167 | #define PANASONIC_BIT_MARK 502 168 | #define PANASONIC_ONE_SPACE 1244 169 | #define PANASONIC_ZERO_SPACE 400 170 | 171 | #define JVC_HDR_MARK 8000 172 | #define JVC_HDR_SPACE 4000 173 | #define JVC_BIT_MARK 600 174 | #define JVC_ONE_SPACE 1600 175 | #define JVC_ZERO_SPACE 550 176 | #define JVC_RPT_LENGTH 60000 177 | 178 | #define RCMM_HDR_MARK 417 179 | #define RCMM_MARK 149 // Protocol says 167, but in practice we often seem to be short 180 | #define RCMM_SPACE 277 181 | #define RCMM_INCREMENT 167 182 | 183 | #define SHARP_BITS 15 184 | #define DISH_BITS 16 185 | 186 | #define MAGIQUEST_PERIOD 1150 187 | #define MAGIQUEST_MARK_ZERO 280 188 | #define MAGIQUEST_SPACE_ZERO 850 189 | #define MAGIQUEST_MARK_ONE 580 190 | #define MAGIQUEST_SPACE_ONE 600 191 | 192 | #define SYMA_UPDATE_PERIOD_CH_A 120 // 0 193 | #define SYMA_UPDATE_PERIOD_CH_B 180 // 1 194 | #define SYMA_HDR_MARK 2000 195 | #define SYMA_HDR_SPACE 2000 196 | #define SYMA_BIT_MARK 320 197 | #define SYMA_ONE_SPACE 687 198 | #define SYMA_ZERO_SPACE 300 199 | 200 | #define USERIES_UPDATE_PERIOD_CH_A 150 // 1 201 | #define USERIES_UPDATE_PERIOD_CH_B 110 // 2 202 | #define USERIES_UPDATE_PERIOD_CH_C 190 // 0 203 | #define USERIES_HDR_MARK 1600 204 | #define USERIES_BIT_SPACE 400 205 | #define USERIES_ONE_MARK 420 206 | #define USERIES_ZERO_MARK 770 207 | 208 | #define FASTLANE_UPDATE_PERIOD_CH_A 140 // 2 209 | #define FASTLANE_UPDATE_PERIOD_CH_B 180 // 1 210 | #define FASTLANE_UPDATE_PERIOD_CH_C 220 // 0 211 | #define FASTLANE_HDR_MARK 2200 212 | #define FASTLANE_ONE 1200 213 | #define FASTLANE_ZERO 600 214 | 215 | #define TOLERANCE 25 // percent tolerance in measurements 216 | #define LTOL (1.0 - TOLERANCE/100.) 217 | #define UTOL (1.0 + TOLERANCE/100.) 218 | 219 | #define _GAP 5000 // Minimum map between transmissions 220 | #define GAP_TICKS (_GAP/USECPERTICK) 221 | 222 | #define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK)) 223 | #define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1)) 224 | 225 | #ifndef DEBUG 226 | int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);} 227 | int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us + MARK_EXCESS));} 228 | int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us - MARK_EXCESS));} 229 | // Debugging versions are in IRremote.cpp 230 | #endif 231 | 232 | // receiver states 233 | #define STATE_IDLE 2 234 | #define STATE_MARK 3 235 | #define STATE_SPACE 4 236 | #define STATE_STOP 5 237 | 238 | // information for the interrupt handler 239 | typedef struct { 240 | uint8_t recvpin; // pin for IR data from detector 241 | uint8_t rcvstate; // state machine 242 | uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing 243 | unsigned long startTime; // state timer, counts 50uS ticks. 244 | unsigned int rawbuf[RAWBUF]; // raw data 245 | uint8_t rawlen; // counter of entries in rawbuf 246 | } 247 | irparams_t; 248 | 249 | // Defined in IRremote.cpp 250 | extern volatile irparams_t irparams; 251 | 252 | // IR detector output is active low 253 | #define MARK 0 254 | #define SPACE 1 255 | 256 | #define TOPBIT 0x80000000 257 | 258 | #define NEC_BITS 32 259 | #define SONY_BITS 12 260 | #define SANYO_BITS 12 261 | #define MITSUBISHI_BITS 16 262 | #define MIN_RC5_SAMPLES 11 263 | #define MIN_RC6_SAMPLES 1 264 | #define PANASONIC_BITS 48 265 | #define JVC_BITS 16 266 | #define RCMM_BITS 12 267 | #define MAGIQUEST_BITS 56 268 | #define SYMA_R5_BITS 32 269 | #define SYMA_R3_BITS 24 270 | #define USERIES_BITS 32 271 | #define FASTLANE_BITS 23 272 | 273 | 274 | 275 | // defines for timer2 (8 bits) 276 | #if defined(IR_USE_TIMER2) 277 | #define TIMER_RESET 278 | #define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1)) 279 | #define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1))) 280 | #define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A)) 281 | #define TIMER_DISABLE_INTR (TIMSK2 = 0) 282 | #define TIMER_INTR_NAME TIMER2_COMPA_vect 283 | #define TIMER_CONFIG_KHZ(val) ({ \ 284 | const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ 285 | TCCR2A = _BV(WGM20); \ 286 | TCCR2B = _BV(WGM22) | _BV(CS20); \ 287 | OCR2A = pwmval; \ 288 | OCR2B = pwmval / 3; \ 289 | }) 290 | #define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) 291 | #if (TIMER_COUNT_TOP < 256) 292 | #define TIMER_CONFIG_NORMAL() ({ \ 293 | TCCR2A = _BV(WGM21); \ 294 | TCCR2B = _BV(CS20); \ 295 | OCR2A = TIMER_COUNT_TOP; \ 296 | TCNT2 = 0; \ 297 | }) 298 | #else 299 | #define TIMER_CONFIG_NORMAL() ({ \ 300 | TCCR2A = _BV(WGM21); \ 301 | TCCR2B = _BV(CS21); \ 302 | OCR2A = TIMER_COUNT_TOP / 8; \ 303 | TCNT2 = 0; \ 304 | }) 305 | #endif 306 | #if defined(CORE_OC2B_PIN) 307 | #define TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */ 308 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 309 | #define TIMER_PWM_PIN 9 /* Arduino Mega */ 310 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 311 | #define TIMER_PWM_PIN 14 /* Sanguino */ 312 | #else 313 | #define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ 314 | #endif 315 | 316 | 317 | // defines for timer1 (16 bits) 318 | #elif defined(IR_USE_TIMER1) 319 | #define TIMER_RESET 320 | #define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1)) 321 | #define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1))) 322 | #if defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__) 323 | #define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE1A)) 324 | #define TIMER_DISABLE_INTR (TIMSK = 0) 325 | #else 326 | #define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A)) 327 | #define TIMER_DISABLE_INTR (TIMSK1 = 0) 328 | #endif 329 | #define TIMER_INTR_NAME TIMER1_COMPA_vect 330 | #define TIMER_CONFIG_KHZ(val) ({ \ 331 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 332 | TCCR1A = _BV(WGM11); \ 333 | TCCR1B = _BV(WGM13) | _BV(CS10); \ 334 | ICR1 = pwmval; \ 335 | OCR1A = pwmval / 3; \ 336 | }) 337 | #define TIMER_CONFIG_NORMAL() ({ \ 338 | TCCR1A = 0; \ 339 | TCCR1B = _BV(WGM12) | _BV(CS10); \ 340 | OCR1A = SYSCLOCK * USECPERTICK / 1000000; \ 341 | TCNT1 = 0; \ 342 | }) 343 | #if defined(CORE_OC1A_PIN) 344 | #define TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */ 345 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 346 | #define TIMER_PWM_PIN 11 /* Arduino Mega */ 347 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 348 | #define TIMER_PWM_PIN 13 /* Sanguino */ 349 | #else 350 | #define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ 351 | #endif 352 | 353 | 354 | // defines for timer1 on ATtiny (8 bits), no phase-correct PWM 355 | #elif defined(IR_USE_TIMER1_TINY) 356 | #define TIMER_RESET 357 | #define TIMER_ENABLE_PWM (GTCCR |= _BV(COM1B1)) 358 | #define TIMER_DISABLE_PWM (GTCCR &= ~_BV(COM1B1)) 359 | #define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE1B)) 360 | #define TIMER_DISABLE_INTR (TIMSK &= ~_BV(OCIE1B)) 361 | #define TIMER_INTR_NAME TIMER1_COMPB_vect 362 | #if SYSCLOCK <= 8000000 363 | #define TIMER_CONFIG_KHZ(val) ({ \ 364 | const uint8_t pwmval = SYSCLOCK / 1000 / (val); \ 365 | TCCR1 = _BV(CS10); \ 366 | GTCCR = _BV(PWM1B); \ 367 | OCR1C = pwmval; \ 368 | OCR1B = pwmval / 3; \ 369 | }) 370 | #else 371 | #define TIMER_CONFIG_KHZ(val) ({ \ 372 | const uint8_t pwmval = SYSCLOCK / 4000 / (val); \ 373 | TCCR1 = _BV(CS11) | _BV(CS10); \ 374 | GTCCR = _BV(PWM1B); \ 375 | OCR1C = pwmval; \ 376 | OCR1B = pwmval / 3; \ 377 | }) 378 | #endif 379 | #define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) 380 | #if (TIMER_COUNT_TOP < 256) 381 | #define TIMER_CONFIG_NORMAL() ({ \ 382 | TCCR1 = _BV(CTC1) | _BV(CS10); \ 383 | GTCCR = 0; \ 384 | OCR1C = TIMER_COUNT_TOP; \ 385 | OCR1B = TIMER_COUNT_TOP; \ 386 | TCNT1 = 0; \ 387 | }) 388 | #else 389 | #define TIMER_CONFIG_NORMAL() ({ \ 390 | TCCR1 = _BV(CTC1) | _BV(CS12); \ 391 | GTCCR = 0; \ 392 | OCR1C = TIMER_COUNT_TOP / 8; \ 393 | OCR1B = TIMER_COUNT_TOP / 8; \ 394 | TCNT1 = 0; \ 395 | }) 396 | #endif 397 | #define TIMER_PWM_PIN 4 398 | 399 | 400 | // defines for timer0 (8 bits). Tested on ATtiny85, may also work on other 401 | // processors, but most of them use Timer 0 to keep system time 402 | #elif defined(IR_USE_TIMER0) 403 | #define TIMER_RESET 404 | #define TIMER_ENABLE_PWM (TCCR0A |= _BV(COM0B1)) 405 | #define TIMER_DISABLE_PWM (TCCR0A &= ~(_BV(COM0B1))) 406 | #define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE0A)) 407 | #define TIMER_DISABLE_INTR (TIMSK = 0) 408 | #define TIMER_INTR_NAME TIMER0_COMPA_vect 409 | #define TIMER_CONFIG_KHZ(val) ({ \ 410 | const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ 411 | TCCR0A = _BV(WGM00); \ 412 | TCCR0B = _BV(WGM02) | _BV(CS00); \ 413 | OCR0A = pwmval; \ 414 | OCR0B = pwmval / 3; \ 415 | }) 416 | #define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) 417 | #if (TIMER_COUNT_TOP < 256) 418 | #define TIMER_CONFIG_NORMAL() ({ \ 419 | TCCR2A = _BV(WGM01); \ 420 | TCCR2B = _BV(CS00); \ 421 | OCR2A = TIMER_COUNT_TOP; \ 422 | TCNT2 = 0; \ 423 | }) 424 | #else 425 | #define TIMER_CONFIG_NORMAL() ({ \ 426 | TCCR2A = _BV(WGM01); \ 427 | TCCR2B = _BV(CS01); \ 428 | OCR2A = TIMER_COUNT_TOP / 8; \ 429 | TCNT2 = 0; \ 430 | }) 431 | #endif 432 | #if defined(CORE_OC0A_PIN) 433 | #define TIMER_PWM_PIN CORE_OC0B_PIN 434 | #else 435 | #define TIMER_PWM_PIN 1 /* Attiny core */ 436 | #endif 437 | 438 | 439 | // defines for timer3 (16 bits) 440 | #elif defined(IR_USE_TIMER3) 441 | #define TIMER_RESET 442 | #define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1)) 443 | #define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1))) 444 | #define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A)) 445 | #define TIMER_DISABLE_INTR (TIMSK3 = 0) 446 | #define TIMER_INTR_NAME TIMER3_COMPA_vect 447 | #define TIMER_CONFIG_KHZ(val) ({ \ 448 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 449 | TCCR3A = _BV(WGM31); \ 450 | TCCR3B = _BV(WGM33) | _BV(CS30); \ 451 | ICR3 = pwmval; \ 452 | OCR3A = pwmval / 3; \ 453 | }) 454 | #define TIMER_CONFIG_NORMAL() ({ \ 455 | TCCR3A = 0; \ 456 | TCCR3B = _BV(WGM32) | _BV(CS30); \ 457 | OCR3A = SYSCLOCK * USECPERTICK / 1000000; \ 458 | TCNT3 = 0; \ 459 | }) 460 | #if defined(CORE_OC3A_PIN) 461 | #define TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */ 462 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 463 | #define TIMER_PWM_PIN 5 /* Arduino Mega */ 464 | #else 465 | #error "Please add OC3A pin number here\n" 466 | #endif 467 | 468 | 469 | // defines for timer4 (10 bits, high speed option) 470 | #elif defined(IR_USE_TIMER4_HS) 471 | #define TIMER_RESET 472 | #define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) 473 | #define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) 474 | #define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4)) 475 | #define TIMER_DISABLE_INTR (TIMSK4 = 0) 476 | #define TIMER_INTR_NAME TIMER4_OVF_vect 477 | #define TIMER_CONFIG_KHZ(val) ({ \ 478 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 479 | TCCR4A = (1<> 8; \ 485 | OCR4C = pwmval; \ 486 | TC4H = (pwmval / 3) >> 8; \ 487 | OCR4A = (pwmval / 3) & 255; \ 488 | }) 489 | #define TIMER_CONFIG_NORMAL() ({ \ 490 | TCCR4A = 0; \ 491 | TCCR4B = _BV(CS40); \ 492 | TCCR4C = 0; \ 493 | TCCR4D = 0; \ 494 | TCCR4E = 0; \ 495 | TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \ 496 | OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \ 497 | TC4H = 0; \ 498 | TCNT4 = 0; \ 499 | }) 500 | #if defined(CORE_OC4A_PIN) 501 | #define TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */ 502 | #elif defined(__AVR_ATmega32U4__) 503 | #define TIMER_PWM_PIN 13 /* Leonardo */ 504 | #else 505 | #error "Please add OC4A pin number here\n" 506 | #endif 507 | 508 | 509 | // defines for timer4 (16 bits) 510 | #elif defined(IR_USE_TIMER4) 511 | #define TIMER_RESET 512 | #define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) 513 | #define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) 514 | #define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A)) 515 | #define TIMER_DISABLE_INTR (TIMSK4 = 0) 516 | #define TIMER_INTR_NAME TIMER4_COMPA_vect 517 | #define TIMER_CONFIG_KHZ(val) ({ \ 518 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 519 | TCCR4A = _BV(WGM41); \ 520 | TCCR4B = _BV(WGM43) | _BV(CS40); \ 521 | ICR4 = pwmval; \ 522 | OCR4A = pwmval / 3; \ 523 | }) 524 | #define TIMER_CONFIG_NORMAL() ({ \ 525 | TCCR4A = 0; \ 526 | TCCR4B = _BV(WGM42) | _BV(CS40); \ 527 | OCR4A = SYSCLOCK * USECPERTICK / 1000000; \ 528 | TCNT4 = 0; \ 529 | }) 530 | #if defined(CORE_OC4A_PIN) 531 | #define TIMER_PWM_PIN CORE_OC4A_PIN 532 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 533 | #define TIMER_PWM_PIN 6 /* Arduino Mega */ 534 | #else 535 | #error "Please add OC4A pin number here\n" 536 | #endif 537 | 538 | 539 | // defines for timer5 (16 bits) 540 | #elif defined(IR_USE_TIMER5) 541 | #define TIMER_RESET 542 | #define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1)) 543 | #define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1))) 544 | #define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A)) 545 | #define TIMER_DISABLE_INTR (TIMSK5 = 0) 546 | #define TIMER_INTR_NAME TIMER5_COMPA_vect 547 | #define TIMER_CONFIG_KHZ(val) ({ \ 548 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 549 | TCCR5A = _BV(WGM51); \ 550 | TCCR5B = _BV(WGM53) | _BV(CS50); \ 551 | ICR5 = pwmval; \ 552 | OCR5A = pwmval / 3; \ 553 | }) 554 | #define TIMER_CONFIG_NORMAL() ({ \ 555 | TCCR5A = 0; \ 556 | TCCR5B = _BV(WGM52) | _BV(CS50); \ 557 | OCR5A = SYSCLOCK * USECPERTICK / 1000000; \ 558 | TCNT5 = 0; \ 559 | }) 560 | #if defined(CORE_OC5A_PIN) 561 | #define TIMER_PWM_PIN CORE_OC5A_PIN 562 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 563 | #define TIMER_PWM_PIN 46 /* Arduino Mega */ 564 | #else 565 | #error "Please add OC5A pin number here\n" 566 | #endif 567 | 568 | 569 | // defines for special carrier modulator timer 570 | #elif defined(IR_USE_TIMER_CMT) 571 | #define TIMER_RESET ({ \ 572 | uint8_t tmp = CMT_MSC; \ 573 | CMT_CMD2 = 30; \ 574 | }) 575 | #define TIMER_ENABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_DSE|PORT_PCR_SRE 576 | #define TIMER_DISABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE 577 | #define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_CMT) 578 | #define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_CMT) 579 | #define TIMER_INTR_NAME cmt_isr 580 | #ifdef ISR 581 | #undef ISR 582 | #endif 583 | #define ISR(f) void f(void) 584 | #if F_BUS == 48000000 585 | #define CMT_PPS_VAL 5 586 | #else 587 | #define CMT_PPS_VAL 2 588 | #endif 589 | #define TIMER_CONFIG_KHZ(val) ({ \ 590 | SIM_SCGC4 |= SIM_SCGC4_CMT; \ 591 | SIM_SOPT2 |= SIM_SOPT2_PTD7PAD; \ 592 | CMT_PPS = CMT_PPS_VAL; \ 593 | CMT_CGH1 = 2667 / val; \ 594 | CMT_CGL1 = 5333 / val; \ 595 | CMT_CMD1 = 0; \ 596 | CMT_CMD2 = 30; \ 597 | CMT_CMD3 = 0; \ 598 | CMT_CMD4 = 0; \ 599 | CMT_OC = 0x60; \ 600 | CMT_MSC = 0x01; \ 601 | }) 602 | #define TIMER_CONFIG_NORMAL() ({ \ 603 | SIM_SCGC4 |= SIM_SCGC4_CMT; \ 604 | CMT_PPS = CMT_PPS_VAL; \ 605 | CMT_CGH1 = 1; \ 606 | CMT_CGL1 = 1; \ 607 | CMT_CMD1 = 0; \ 608 | CMT_CMD2 = 30; \ 609 | CMT_CMD3 = 0; \ 610 | CMT_CMD4 = 19; \ 611 | CMT_OC = 0; \ 612 | CMT_MSC = 0x03; \ 613 | }) 614 | #define TIMER_PWM_PIN 5 615 | 616 | 617 | #else // unknown timer 618 | #error "Internal code configuration error, no known IR_USE_TIMER# defined\n" 619 | #endif 620 | 621 | 622 | // defines for blinking the LED 623 | #if defined(CORE_LED0_PIN) 624 | #define BLINKLED CORE_LED0_PIN 625 | #define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH)) 626 | #define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW)) 627 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 628 | #define BLINKLED 13 629 | #define BLINKLED_ON() (PORTB |= B10000000) 630 | #define BLINKLED_OFF() (PORTB &= B01111111) 631 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 632 | #define BLINKLED 0 633 | #define BLINKLED_ON() (PORTD |= B00000001) 634 | #define BLINKLED_OFF() (PORTD &= B11111110) 635 | #elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 636 | #define BLINKLED 4 637 | #define BLINKLED_ON() (PORTB |= B00001000) 638 | #define BLINKLED_OFF() (PORTB &= B11110110) 639 | #else 640 | #define BLINKLED 13 641 | #define BLINKLED_ON() (PORTB |= B00100000) 642 | #define BLINKLED_OFF() (PORTB &= B11011111) 643 | #endif 644 | 645 | #endif 646 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 2.1, February 1999 4 | 5 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | [This is the first released version of the Lesser GPL. It also counts 11 | as the successor of the GNU Library Public License, version 2, hence 12 | the version number 2.1.] 13 | 14 | Preamble 15 | 16 | The licenses for most software are designed to take away your 17 | freedom to share and change it. By contrast, the GNU General Public 18 | Licenses are intended to guarantee your freedom to share and change 19 | free software--to make sure the software is free for all its users. 20 | 21 | This license, the Lesser General Public License, applies to some 22 | specially designated software packages--typically libraries--of the 23 | Free Software Foundation and other authors who decide to use it. You 24 | can use it too, but we suggest you first think carefully about whether 25 | this license or the ordinary General Public License is the better 26 | strategy to use in any particular case, based on the explanations below. 27 | 28 | When we speak of free software, we are referring to freedom of use, 29 | not price. Our General Public Licenses are designed to make sure that 30 | you have the freedom to distribute copies of free software (and charge 31 | for this service if you wish); that you receive source code or can get 32 | it if you want it; that you can change the software and use pieces of 33 | it in new free programs; and that you are informed that you can do 34 | these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid 37 | distributors to deny you these rights or to ask you to surrender these 38 | rights. These restrictions translate to certain responsibilities for 39 | you if you distribute copies of the library or if you modify it. 40 | 41 | For example, if you distribute copies of the library, whether gratis 42 | or for a fee, you must give the recipients all the rights that we gave 43 | you. You must make sure that they, too, receive or can get the source 44 | code. If you link other code with the library, you must provide 45 | complete object files to the recipients, so that they can relink them 46 | with the library after making changes to the library and recompiling 47 | it. And you must show them these terms so they know their rights. 48 | 49 | We protect your rights with a two-step method: (1) we copyright the 50 | library, and (2) we offer you this license, which gives you legal 51 | permission to copy, distribute and/or modify the library. 52 | 53 | To protect each distributor, we want to make it very clear that 54 | there is no warranty for the free library. Also, if the library is 55 | modified by someone else and passed on, the recipients should know 56 | that what they have is not the original version, so that the original 57 | author's reputation will not be affected by problems that might be 58 | introduced by others. 59 | 60 | Finally, software patents pose a constant threat to the existence of 61 | any free program. We wish to make sure that a company cannot 62 | effectively restrict the users of a free program by obtaining a 63 | restrictive license from a patent holder. Therefore, we insist that 64 | any patent license obtained for a version of the library must be 65 | consistent with the full freedom of use specified in this license. 66 | 67 | Most GNU software, including some libraries, is covered by the 68 | ordinary GNU General Public License. This license, the GNU Lesser 69 | General Public License, applies to certain designated libraries, and 70 | is quite different from the ordinary General Public License. We use 71 | this license for certain libraries in order to permit linking those 72 | libraries into non-free programs. 73 | 74 | When a program is linked with a library, whether statically or using 75 | a shared library, the combination of the two is legally speaking a 76 | combined work, a derivative of the original library. The ordinary 77 | General Public License therefore permits such linking only if the 78 | entire combination fits its criteria of freedom. The Lesser General 79 | Public License permits more lax criteria for linking other code with 80 | the library. 81 | 82 | We call this license the "Lesser" General Public License because it 83 | does Less to protect the user's freedom than the ordinary General 84 | Public License. It also provides other free software developers Less 85 | of an advantage over competing non-free programs. These disadvantages 86 | are the reason we use the ordinary General Public License for many 87 | libraries. However, the Lesser license provides advantages in certain 88 | special circumstances. 89 | 90 | For example, on rare occasions, there may be a special need to 91 | encourage the widest possible use of a certain library, so that it becomes 92 | a de-facto standard. To achieve this, non-free programs must be 93 | allowed to use the library. A more frequent case is that a free 94 | library does the same job as widely used non-free libraries. In this 95 | case, there is little to gain by limiting the free library to free 96 | software only, so we use the Lesser General Public License. 97 | 98 | In other cases, permission to use a particular library in non-free 99 | programs enables a greater number of people to use a large body of 100 | free software. For example, permission to use the GNU C Library in 101 | non-free programs enables many more people to use the whole GNU 102 | operating system, as well as its variant, the GNU/Linux operating 103 | system. 104 | 105 | Although the Lesser General Public License is Less protective of the 106 | users' freedom, it does ensure that the user of a program that is 107 | linked with the Library has the freedom and the wherewithal to run 108 | that program using a modified version of the Library. 109 | 110 | The precise terms and conditions for copying, distribution and 111 | modification follow. Pay close attention to the difference between a 112 | "work based on the library" and a "work that uses the library". The 113 | former contains code derived from the library, whereas the latter must 114 | be combined with the library in order to run. 115 | 116 | GNU LESSER GENERAL PUBLIC LICENSE 117 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 118 | 119 | 0. This License Agreement applies to any software library or other 120 | program which contains a notice placed by the copyright holder or 121 | other authorized party saying it may be distributed under the terms of 122 | this Lesser General Public License (also called "this License"). 123 | Each licensee is addressed as "you". 124 | 125 | A "library" means a collection of software functions and/or data 126 | prepared so as to be conveniently linked with application programs 127 | (which use some of those functions and data) to form executables. 128 | 129 | The "Library", below, refers to any such software library or work 130 | which has been distributed under these terms. A "work based on the 131 | Library" means either the Library or any derivative work under 132 | copyright law: that is to say, a work containing the Library or a 133 | portion of it, either verbatim or with modifications and/or translated 134 | straightforwardly into another language. (Hereinafter, translation is 135 | included without limitation in the term "modification".) 136 | 137 | "Source code" for a work means the preferred form of the work for 138 | making modifications to it. For a library, complete source code means 139 | all the source code for all modules it contains, plus any associated 140 | interface definition files, plus the scripts used to control compilation 141 | and installation of the library. 142 | 143 | Activities other than copying, distribution and modification are not 144 | covered by this License; they are outside its scope. The act of 145 | running a program using the Library is not restricted, and output from 146 | such a program is covered only if its contents constitute a work based 147 | on the Library (independent of the use of the Library in a tool for 148 | writing it). Whether that is true depends on what the Library does 149 | and what the program that uses the Library does. 150 | 151 | 1. You may copy and distribute verbatim copies of the Library's 152 | complete source code as you receive it, in any medium, provided that 153 | you conspicuously and appropriately publish on each copy an 154 | appropriate copyright notice and disclaimer of warranty; keep intact 155 | all the notices that refer to this License and to the absence of any 156 | warranty; and distribute a copy of this License along with the 157 | Library. 158 | 159 | You may charge a fee for the physical act of transferring a copy, 160 | and you may at your option offer warranty protection in exchange for a 161 | fee. 162 | 163 | 2. You may modify your copy or copies of the Library or any portion 164 | of it, thus forming a work based on the Library, and copy and 165 | distribute such modifications or work under the terms of Section 1 166 | above, provided that you also meet all of these conditions: 167 | 168 | a) The modified work must itself be a software library. 169 | 170 | b) You must cause the files modified to carry prominent notices 171 | stating that you changed the files and the date of any change. 172 | 173 | c) You must cause the whole of the work to be licensed at no 174 | charge to all third parties under the terms of this License. 175 | 176 | d) If a facility in the modified Library refers to a function or a 177 | table of data to be supplied by an application program that uses 178 | the facility, other than as an argument passed when the facility 179 | is invoked, then you must make a good faith effort to ensure that, 180 | in the event an application does not supply such function or 181 | table, the facility still operates, and performs whatever part of 182 | its purpose remains meaningful. 183 | 184 | (For example, a function in a library to compute square roots has 185 | a purpose that is entirely well-defined independent of the 186 | application. Therefore, Subsection 2d requires that any 187 | application-supplied function or table used by this function must 188 | be optional: if the application does not supply it, the square 189 | root function must still compute square roots.) 190 | 191 | These requirements apply to the modified work as a whole. If 192 | identifiable sections of that work are not derived from the Library, 193 | and can be reasonably considered independent and separate works in 194 | themselves, then this License, and its terms, do not apply to those 195 | sections when you distribute them as separate works. But when you 196 | distribute the same sections as part of a whole which is a work based 197 | on the Library, the distribution of the whole must be on the terms of 198 | this License, whose permissions for other licensees extend to the 199 | entire whole, and thus to each and every part regardless of who wrote 200 | it. 201 | 202 | Thus, it is not the intent of this section to claim rights or contest 203 | your rights to work written entirely by you; rather, the intent is to 204 | exercise the right to control the distribution of derivative or 205 | collective works based on the Library. 206 | 207 | In addition, mere aggregation of another work not based on the Library 208 | with the Library (or with a work based on the Library) on a volume of 209 | a storage or distribution medium does not bring the other work under 210 | the scope of this License. 211 | 212 | 3. You may opt to apply the terms of the ordinary GNU General Public 213 | License instead of this License to a given copy of the Library. To do 214 | this, you must alter all the notices that refer to this License, so 215 | that they refer to the ordinary GNU General Public License, version 2, 216 | instead of to this License. (If a newer version than version 2 of the 217 | ordinary GNU General Public License has appeared, then you can specify 218 | that version instead if you wish.) Do not make any other change in 219 | these notices. 220 | 221 | Once this change is made in a given copy, it is irreversible for 222 | that copy, so the ordinary GNU General Public License applies to all 223 | subsequent copies and derivative works made from that copy. 224 | 225 | This option is useful when you wish to copy part of the code of 226 | the Library into a program that is not a library. 227 | 228 | 4. You may copy and distribute the Library (or a portion or 229 | derivative of it, under Section 2) in object code or executable form 230 | under the terms of Sections 1 and 2 above provided that you accompany 231 | it with the complete corresponding machine-readable source code, which 232 | must be distributed under the terms of Sections 1 and 2 above on a 233 | medium customarily used for software interchange. 234 | 235 | If distribution of object code is made by offering access to copy 236 | from a designated place, then offering equivalent access to copy the 237 | source code from the same place satisfies the requirement to 238 | distribute the source code, even though third parties are not 239 | compelled to copy the source along with the object code. 240 | 241 | 5. A program that contains no derivative of any portion of the 242 | Library, but is designed to work with the Library by being compiled or 243 | linked with it, is called a "work that uses the Library". Such a 244 | work, in isolation, is not a derivative work of the Library, and 245 | therefore falls outside the scope of this License. 246 | 247 | However, linking a "work that uses the Library" with the Library 248 | creates an executable that is a derivative of the Library (because it 249 | contains portions of the Library), rather than a "work that uses the 250 | library". The executable is therefore covered by this License. 251 | Section 6 states terms for distribution of such executables. 252 | 253 | When a "work that uses the Library" uses material from a header file 254 | that is part of the Library, the object code for the work may be a 255 | derivative work of the Library even though the source code is not. 256 | Whether this is true is especially significant if the work can be 257 | linked without the Library, or if the work is itself a library. The 258 | threshold for this to be true is not precisely defined by law. 259 | 260 | If such an object file uses only numerical parameters, data 261 | structure layouts and accessors, and small macros and small inline 262 | functions (ten lines or less in length), then the use of the object 263 | file is unrestricted, regardless of whether it is legally a derivative 264 | work. (Executables containing this object code plus portions of the 265 | Library will still fall under Section 6.) 266 | 267 | Otherwise, if the work is a derivative of the Library, you may 268 | distribute the object code for the work under the terms of Section 6. 269 | Any executables containing that work also fall under Section 6, 270 | whether or not they are linked directly with the Library itself. 271 | 272 | 6. As an exception to the Sections above, you may also combine or 273 | link a "work that uses the Library" with the Library to produce a 274 | work containing portions of the Library, and distribute that work 275 | under terms of your choice, provided that the terms permit 276 | modification of the work for the customer's own use and reverse 277 | engineering for debugging such modifications. 278 | 279 | You must give prominent notice with each copy of the work that the 280 | Library is used in it and that the Library and its use are covered by 281 | this License. You must supply a copy of this License. If the work 282 | during execution displays copyright notices, you must include the 283 | copyright notice for the Library among them, as well as a reference 284 | directing the user to the copy of this License. Also, you must do one 285 | of these things: 286 | 287 | a) Accompany the work with the complete corresponding 288 | machine-readable source code for the Library including whatever 289 | changes were used in the work (which must be distributed under 290 | Sections 1 and 2 above); and, if the work is an executable linked 291 | with the Library, with the complete machine-readable "work that 292 | uses the Library", as object code and/or source code, so that the 293 | user can modify the Library and then relink to produce a modified 294 | executable containing the modified Library. (It is understood 295 | that the user who changes the contents of definitions files in the 296 | Library will not necessarily be able to recompile the application 297 | to use the modified definitions.) 298 | 299 | b) Use a suitable shared library mechanism for linking with the 300 | Library. A suitable mechanism is one that (1) uses at run time a 301 | copy of the library already present on the user's computer system, 302 | rather than copying library functions into the executable, and (2) 303 | will operate properly with a modified version of the library, if 304 | the user installs one, as long as the modified version is 305 | interface-compatible with the version that the work was made with. 306 | 307 | c) Accompany the work with a written offer, valid for at 308 | least three years, to give the same user the materials 309 | specified in Subsection 6a, above, for a charge no more 310 | than the cost of performing this distribution. 311 | 312 | d) If distribution of the work is made by offering access to copy 313 | from a designated place, offer equivalent access to copy the above 314 | specified materials from the same place. 315 | 316 | e) Verify that the user has already received a copy of these 317 | materials or that you have already sent this user a copy. 318 | 319 | For an executable, the required form of the "work that uses the 320 | Library" must include any data and utility programs needed for 321 | reproducing the executable from it. However, as a special exception, 322 | the materials to be distributed need not include anything that is 323 | normally distributed (in either source or binary form) with the major 324 | components (compiler, kernel, and so on) of the operating system on 325 | which the executable runs, unless that component itself accompanies 326 | the executable. 327 | 328 | It may happen that this requirement contradicts the license 329 | restrictions of other proprietary libraries that do not normally 330 | accompany the operating system. Such a contradiction means you cannot 331 | use both them and the Library together in an executable that you 332 | distribute. 333 | 334 | 7. You may place library facilities that are a work based on the 335 | Library side-by-side in a single library together with other library 336 | facilities not covered by this License, and distribute such a combined 337 | library, provided that the separate distribution of the work based on 338 | the Library and of the other library facilities is otherwise 339 | permitted, and provided that you do these two things: 340 | 341 | a) Accompany the combined library with a copy of the same work 342 | based on the Library, uncombined with any other library 343 | facilities. This must be distributed under the terms of the 344 | Sections above. 345 | 346 | b) Give prominent notice with the combined library of the fact 347 | that part of it is a work based on the Library, and explaining 348 | where to find the accompanying uncombined form of the same work. 349 | 350 | 8. You may not copy, modify, sublicense, link with, or distribute 351 | the Library except as expressly provided under this License. Any 352 | attempt otherwise to copy, modify, sublicense, link with, or 353 | distribute the Library is void, and will automatically terminate your 354 | rights under this License. However, parties who have received copies, 355 | or rights, from you under this License will not have their licenses 356 | terminated so long as such parties remain in full compliance. 357 | 358 | 9. You are not required to accept this License, since you have not 359 | signed it. However, nothing else grants you permission to modify or 360 | distribute the Library or its derivative works. These actions are 361 | prohibited by law if you do not accept this License. Therefore, by 362 | modifying or distributing the Library (or any work based on the 363 | Library), you indicate your acceptance of this License to do so, and 364 | all its terms and conditions for copying, distributing or modifying 365 | the Library or works based on it. 366 | 367 | 10. Each time you redistribute the Library (or any work based on the 368 | Library), the recipient automatically receives a license from the 369 | original licensor to copy, distribute, link with or modify the Library 370 | subject to these terms and conditions. You may not impose any further 371 | restrictions on the recipients' exercise of the rights granted herein. 372 | You are not responsible for enforcing compliance by third parties with 373 | this License. 374 | 375 | 11. If, as a consequence of a court judgment or allegation of patent 376 | infringement or for any other reason (not limited to patent issues), 377 | conditions are imposed on you (whether by court order, agreement or 378 | otherwise) that contradict the conditions of this License, they do not 379 | excuse you from the conditions of this License. If you cannot 380 | distribute so as to satisfy simultaneously your obligations under this 381 | License and any other pertinent obligations, then as a consequence you 382 | may not distribute the Library at all. For example, if a patent 383 | license would not permit royalty-free redistribution of the Library by 384 | all those who receive copies directly or indirectly through you, then 385 | the only way you could satisfy both it and this License would be to 386 | refrain entirely from distribution of the Library. 387 | 388 | If any portion of this section is held invalid or unenforceable under any 389 | particular circumstance, the balance of the section is intended to apply, 390 | and the section as a whole is intended to apply in other circumstances. 391 | 392 | It is not the purpose of this section to induce you to infringe any 393 | patents or other property right claims or to contest validity of any 394 | such claims; this section has the sole purpose of protecting the 395 | integrity of the free software distribution system which is 396 | implemented by public license practices. Many people have made 397 | generous contributions to the wide range of software distributed 398 | through that system in reliance on consistent application of that 399 | system; it is up to the author/donor to decide if he or she is willing 400 | to distribute software through any other system and a licensee cannot 401 | impose that choice. 402 | 403 | This section is intended to make thoroughly clear what is believed to 404 | be a consequence of the rest of this License. 405 | 406 | 12. If the distribution and/or use of the Library is restricted in 407 | certain countries either by patents or by copyrighted interfaces, the 408 | original copyright holder who places the Library under this License may add 409 | an explicit geographical distribution limitation excluding those countries, 410 | so that distribution is permitted only in or among countries not thus 411 | excluded. In such case, this License incorporates the limitation as if 412 | written in the body of this License. 413 | 414 | 13. The Free Software Foundation may publish revised and/or new 415 | versions of the Lesser General Public License from time to time. 416 | Such new versions will be similar in spirit to the present version, 417 | but may differ in detail to address new problems or concerns. 418 | 419 | Each version is given a distinguishing version number. If the Library 420 | specifies a version number of this License which applies to it and 421 | "any later version", you have the option of following the terms and 422 | conditions either of that version or of any later version published by 423 | the Free Software Foundation. If the Library does not specify a 424 | license version number, you may choose any version ever published by 425 | the Free Software Foundation. 426 | 427 | 14. If you wish to incorporate parts of the Library into other free 428 | programs whose distribution conditions are incompatible with these, 429 | write to the author to ask for permission. For software which is 430 | copyrighted by the Free Software Foundation, write to the Free 431 | Software Foundation; we sometimes make exceptions for this. Our 432 | decision will be guided by the two goals of preserving the free status 433 | of all derivatives of our free software and of promoting the sharing 434 | and reuse of software generally. 435 | 436 | NO WARRANTY 437 | 438 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 439 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 440 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 441 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 442 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 443 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 444 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 445 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 446 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 447 | 448 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 449 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 450 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 451 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 452 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 453 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 454 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 455 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 456 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 457 | DAMAGES. 458 | 459 | -------------------------------------------------------------------------------- /examples/IRrecord/IRrecord.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRrecord: record and play back IR signals as a minimal 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * An IR LED must be connected to the output PWM pin 3. 5 | * A button must be connected to the input BUTTON_PIN; this is the 6 | * send button. 7 | * A visible LED can be connected to STATUS_PIN to provide status. 8 | * 9 | * The logic is: 10 | * If the button is pressed, send the IR code. 11 | * If an IR code is received, record it. 12 | * 13 | * Version 0.11 September, 2009 14 | * Copyright 2009 Ken Shirriff 15 | * http://arcfn.com 16 | */ 17 | 18 | #include 19 | 20 | int RECV_PIN = 11; 21 | int BUTTON_PIN = 12; 22 | int STATUS_PIN = 13; 23 | 24 | IRrecv irrecv(RECV_PIN); 25 | IRsend irsend; 26 | 27 | decode_results results; 28 | 29 | void setup() 30 | { 31 | Serial.begin(9600); 32 | irrecv.enableIRIn(); // Start the receiver 33 | pinMode(BUTTON_PIN, INPUT); 34 | pinMode(STATUS_PIN, OUTPUT); 35 | } 36 | 37 | // Storage for the recorded code 38 | int codeType = -1; // The type of code 39 | unsigned long codeValue; // The code value if not raw 40 | unsigned int rawCodes[RAWBUF]; // The durations if raw 41 | int codeLen; // The length of the code 42 | int toggle = 0; // The RC5/6 toggle state 43 | 44 | // Stores the code for later playback 45 | // Most of this code is just logging 46 | void storeCode(decode_results *results) { 47 | codeType = results->decode_type; 48 | int count = results->rawlen; 49 | if (codeType == UNKNOWN) { 50 | Serial.println("Received unknown code, saving as raw"); 51 | codeLen = results->rawlen - 1; 52 | // To store raw codes: 53 | // Drop first value (gap) 54 | // Convert from ticks to microseconds 55 | // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion 56 | for (int i = 1; i <= codeLen; i++) { 57 | if (i % 2) { 58 | // Mark 59 | rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS; 60 | Serial.print(" m"); 61 | } 62 | else { 63 | // Space 64 | rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS; 65 | Serial.print(" s"); 66 | } 67 | Serial.print(rawCodes[i - 1], DEC); 68 | } 69 | Serial.println(""); 70 | } 71 | else { 72 | if (codeType == NEC) { 73 | Serial.print("Received NEC: "); 74 | if (results->value == REPEAT) { 75 | // Don't record a NEC repeat value as that's useless. 76 | Serial.println("repeat; ignoring."); 77 | return; 78 | } 79 | } 80 | else if (codeType == SONY) { 81 | Serial.print("Received SONY: "); 82 | } 83 | else if (codeType == RC5) { 84 | Serial.print("Received RC5: "); 85 | } 86 | else if (codeType == RC6) { 87 | Serial.print("Received RC6: "); 88 | } 89 | else if (codeType == MAGIQUEST) { 90 | Serial.print("Received MAGIQUEST: "); 91 | } 92 | else { 93 | Serial.print("Unexpected codeType "); 94 | Serial.print(codeType, DEC); 95 | Serial.println(""); 96 | } 97 | Serial.println(results->value, HEX); 98 | codeValue = results->value; 99 | codeLen = results->bits; 100 | } 101 | } 102 | 103 | void sendCode(int repeat) { 104 | if (codeType == NEC) { 105 | if (repeat) { 106 | irsend.sendNEC(REPEAT, codeLen); 107 | Serial.println("Sent NEC repeat"); 108 | } 109 | else { 110 | irsend.sendNEC(codeValue, codeLen); 111 | Serial.print("Sent NEC "); 112 | Serial.println(codeValue, HEX); 113 | } 114 | } 115 | else if (codeType == SONY) { 116 | irsend.sendSony(codeValue, codeLen); 117 | Serial.print("Sent Sony "); 118 | Serial.println(codeValue, HEX); 119 | } 120 | else if (codeType == RC5 || codeType == RC6) { 121 | if (!repeat) { 122 | // Flip the toggle bit for a new button press 123 | toggle = 1 - toggle; 124 | } 125 | // Put the toggle bit into the code to send 126 | codeValue = codeValue & ~(1 << (codeLen - 1)); 127 | codeValue = codeValue | (toggle << (codeLen - 1)); 128 | if (codeType == RC5) { 129 | Serial.print("Sent RC5 "); 130 | Serial.println(codeValue, HEX); 131 | irsend.sendRC5(codeValue, codeLen); 132 | } 133 | else { 134 | irsend.sendRC6(codeValue, codeLen); 135 | Serial.print("Sent RC6 "); 136 | Serial.println(codeValue, HEX); 137 | } 138 | } 139 | else if (codeType == RCMM) { 140 | irsend.sendRCMM(codeValue, codeLen); 141 | Serial.print("Sent RCMM "); 142 | Serial.println(codeValue, HEX); 143 | } 144 | else if (codeType == MAGIQUEST) { 145 | irsend.sendSony(codeValue, codeLen); 146 | Serial.print("Sent MAGIQUEST "); 147 | Serial.println(codeValue, HEX); 148 | } 149 | else if (codeType == UNKNOWN /* i.e. raw */) { 150 | // Assume 38 KHz 151 | irsend.sendRaw(rawCodes, codeLen, 38); 152 | Serial.println("Sent raw"); 153 | } 154 | } 155 | 156 | int lastButtonState; 157 | 158 | void loop() { 159 | // If button pressed, send the code. 160 | int buttonState = digitalRead(BUTTON_PIN); 161 | if (lastButtonState == HIGH && buttonState == LOW) { 162 | Serial.println("Released"); 163 | irrecv.enableIRIn(); // Re-enable receiver 164 | } 165 | 166 | if (buttonState) { 167 | Serial.println("Pressed, sending"); 168 | digitalWrite(STATUS_PIN, HIGH); 169 | sendCode(lastButtonState == buttonState); 170 | digitalWrite(STATUS_PIN, LOW); 171 | delay(50); // Wait a bit between retransmissions 172 | } 173 | else if (irrecv.decode(&results)) { 174 | digitalWrite(STATUS_PIN, HIGH); 175 | storeCode(&results); 176 | irrecv.resume(); // resume receiver 177 | digitalWrite(STATUS_PIN, LOW); 178 | } 179 | lastButtonState = buttonState; 180 | } 181 | -------------------------------------------------------------------------------- /examples/IRrecvDemo/IRrecvDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | int RECV_PIN = 11; 12 | 13 | IRrecv irrecv(RECV_PIN); 14 | 15 | decode_results results; 16 | 17 | void setup() 18 | { 19 | Serial.begin(9600); 20 | irrecv.enableIRIn(); // Start the receiver 21 | } 22 | 23 | void loop() { 24 | if (irrecv.decode(&results)) { 25 | Serial.println(results.value, HEX); 26 | irrecv.resume(); // Receive the next value 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/IRrecvDump/IRrecvDump.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRrecvDump - dump details of IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 8 | * RCMM protocol added by Matthias Neeracher 9 | */ 10 | 11 | #include 12 | 13 | #if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 14 | #define IS_AVTINY 15 | int RECV_PIN = 2; 16 | #define ENABLE_MagiQuest 17 | // add others as to fit in Tiny 18 | #else 19 | int RECV_PIN = 11; 20 | #define ENABLE_MagiQuest 21 | #define ENABLE_NEC 22 | #define ENABLE_SONY 23 | #define ENABLE_Sanyo 24 | #define ENABLE_Mitsubishi 25 | #define ENABLE_Panasonic 26 | #define ENABLE_RC5 27 | #define ENABLE_RC6 28 | #define ENABLE_SymaR3 29 | #define ENABLE_SymaR5 30 | #define ENABLE_Useries 31 | #define ENABLE_FastLane 32 | #define ENABLE_JVC 33 | #define ENABLE_RCMM 34 | #endif 35 | 36 | 37 | IRrecv irrecv(RECV_PIN); 38 | 39 | decode_results results; 40 | 41 | void setup() 42 | { 43 | Serial.begin(9600); 44 | Serial.println("starting..."); 45 | irrecv.enableIRIn(); // Start the receiver 46 | #ifdef IS_AVTINY 47 | pinMode(1, OUTPUT); //LED on Model A 48 | 49 | 50 | for (int i = 0; i < 5; i++) { 51 | digitalWrite(1, HIGH); 52 | delay(125); // wait for a second 53 | digitalWrite(1, LOW); 54 | delay(125); // wait for a second 55 | } 56 | 57 | #endif //IS_AVTINY 58 | } 59 | 60 | // Dumps out the decode_results structure. 61 | // Call this after IRrecv::decode() 62 | // void * to work around compiler issue 63 | //void dump(void *v) { 64 | // decode_results *results = (decode_results *)v 65 | void dump(decode_results *results) { 66 | 67 | int count = results->rawlen; 68 | 69 | //#ifndef IS_AVTINY 70 | if (results->decode_type == UNKNOWN) { 71 | Serial.print("Unknown encoding: "); 72 | } 73 | //#endif //IS_AVTINY 74 | 75 | #ifdef ENABLE_NEC 76 | else if (results->decode_type == NEC) { 77 | Serial.print("Decoded NEC: "); 78 | } 79 | else if (results->decode_type == SONY) { 80 | Serial.print("Decoded SONY: "); 81 | } 82 | #endif //ENABLE_NEC 83 | 84 | #ifdef ENABLE_MagiQuest 85 | else if (results->decode_type == MAGIQUEST) { 86 | #ifndef IS_AVTINY 87 | Serial.print("Decoded MAGIQUEST - Magnitude="); 88 | Serial.print(results->magiquestMagnitude, HEX); 89 | Serial.print(", wand_id="); 90 | #endif //IS_AVTINY 91 | if (results->value == 0x4FAB881) { 92 | for (int i = 0; i < 2; i++) { 93 | digitalWrite(1, HIGH); 94 | delay(250); // wait for a second 95 | digitalWrite(1, LOW); 96 | delay(125); // wait for a second 97 | } 98 | } 99 | } 100 | #endif //ENABLE_MagiQuest 101 | 102 | #ifdef ENABLE_RC5 103 | else if (results->decode_type == RC5) { 104 | Serial.print("Decoded RC5: "); 105 | } 106 | else if (results->decode_type == RC6) { 107 | Serial.print("Decoded RC6: "); 108 | } 109 | #endif //ENABLE_RC5 110 | 111 | #ifdef ENABLE_Panasonic 112 | else if (results->decode_type == PANASONIC) { 113 | Serial.print("Decoded PANASONIC - Address: "); 114 | Serial.print(results->panasonicAddress,HEX); 115 | Serial.print(", Value: "); 116 | for (int i = 0; i < 3; i++) { 117 | digitalWrite(1, HIGH); 118 | delay(250); // wait for a second 119 | digitalWrite(1, LOW); 120 | delay(125); // wait for a second 121 | } 122 | } 123 | #endif //ENABLE_Panasonic 124 | 125 | #ifdef ENABLE_Syma 126 | else if (results->decode_type == SYMA_R5) { 127 | Serial.print("Decoded SYMA_R5 - "); 128 | Serial.print(" C="); Serial.print(results->helicopter.symaR5.Channel); 129 | Serial.print("("); Serial.write(results->helicopter.symaR5.Channel + 0x41); Serial.print(")"); 130 | Serial.print(" T="); Serial.print(results->helicopter.symaR5.Throttle,DEC); 131 | Serial.print(" P="); Serial.print(results->helicopter.symaR5.Pitch,DEC); 132 | Serial.print(" Y="); Serial.print(results->helicopter.symaR5.Yaw,DEC); 133 | Serial.print(" t="); Serial.print(results->helicopter.symaR5.Trim,DEC); 134 | } 135 | #endif //ENABLE_Syma 136 | 137 | #ifdef ENABLE_Syma 138 | else if (results->decode_type == SYMA_R3) { 139 | Serial.print("Decoded SYMA_R3 - "); 140 | Serial.print(" C="); Serial.print(results->helicopter.symaR3.Channel); 141 | Serial.print("("); Serial.write(results->helicopter.symaR3.Channel + 0x41); Serial.print(")"); 142 | Serial.print(" T="); Serial.print(results->helicopter.symaR3.Throttle,DEC); 143 | Serial.print(" P="); Serial.print(results->helicopter.symaR3.Pitch,DEC); 144 | Serial.print(" Y="); Serial.print(results->helicopter.symaR3.Yaw,DEC); 145 | } 146 | #endif //ENABLE_Syma 147 | 148 | #ifdef ENABLE_Useries 149 | else if (results->decode_type == USERIES) { 150 | // temp variables to hold Channel from propietary format. 151 | uint8_t Channel = results->helicopter.uSeries.Channel; 152 | 153 | //convert Channel to easy A,B,C 154 | switch (Channel) { 155 | case 1: 156 | case 2: 157 | Channel--; 158 | break; 159 | case 0: 160 | Channel = 2; 161 | break; 162 | } // ~case 163 | 164 | Serial.print("Decoded Useries - "); 165 | Serial.print(" C="); Serial.print(results->helicopter.uSeries.Channel,DEC); 166 | Serial.print("("); Serial.write(Channel + 0x41); Serial.print(")"); 167 | Serial.print(" T="); Serial.print(results->helicopter.uSeries.Throttle,DEC); 168 | Serial.print(" P="); Serial.print(results->helicopter.uSeries.Pitch,DEC); 169 | Serial.print(" Y="); Serial.print(results->helicopter.uSeries.Yaw,DEC); 170 | Serial.print(" t="); Serial.print(results->helicopter.uSeries.Trim,DEC); 171 | Serial.print(" Turbo="); Serial.print(results->helicopter.uSeries.Turbo,DEC); 172 | Serial.print(" Lbutton="); Serial.print(results->helicopter.uSeries.Lbutton,DEC); 173 | Serial.print(" Rbutton="); Serial.print(results->helicopter.uSeries.Rbutton,DEC); 174 | Serial.print(" Leftover="); Serial.print(results->helicopter.uSeries.cksum,DEC); 175 | Serial.print(" Parity="); Serial.print(results->parity,DEC); 176 | } 177 | #endif //ENABLE_Useries 178 | 179 | #ifdef ENABLE_FastLane 180 | else if (results->decode_type == FASTLANE) { 181 | // temp variables to hold FastLane's unsigned integers from propietary magnitude and direction bits. 182 | uint8_t Yaw; 183 | uint8_t Trim; 184 | uint8_t Channel; 185 | 186 | //convert Yaw's direction bit to unsigned integers, for easy scaling 187 | if (results->helicopter.fastlane.Yaw_dir) { 188 | Yaw = 16 - results->helicopter.fastlane.Yaw; 189 | } else { 190 | Yaw = 16 + results->helicopter.fastlane.Yaw; 191 | } 192 | 193 | //convert Trim's direction bit to unsigned integers, for easy scaling 194 | if (results->helicopter.fastlane.Trim_dir) { 195 | Trim = 16 - results->helicopter.fastlane.Trim; 196 | } else { 197 | Trim = 16 + results->helicopter.fastlane.Trim; 198 | } 199 | 200 | //convert Channel to easy A,B,C 201 | Channel = ((results->helicopter.fastlane.Channel >> 1) & 0x55) | ((results->helicopter.fastlane.Channel << 1) & 0xaa); 202 | 203 | Serial.print("Decoded FastLane - "); 204 | Serial.print(millis()); Serial.print("ms "); 205 | Serial.print(" C="); Serial.print(results->helicopter.fastlane.Channel,DEC); 206 | Serial.print("("); Serial.write(Channel + 0x41); Serial.print(")"); 207 | Serial.print(" T="); Serial.print(results->helicopter.fastlane.Throttle,DEC); 208 | Serial.print(" P="); Serial.print(results->helicopter.fastlane.Pitch,DEC); 209 | Serial.print(" Yd="); Serial.print(results->helicopter.fastlane.Yaw_dir,DEC); 210 | Serial.print(" Y="); Serial.print(results->helicopter.fastlane.Yaw,DEC); 211 | Serial.print("(u"); Serial.print(Yaw,DEC);Serial.print(")"); 212 | Serial.print(" td="); Serial.print(results->helicopter.fastlane.Trim_dir,DEC); 213 | Serial.print(" t="); Serial.print(results->helicopter.fastlane.Trim,DEC); 214 | Serial.print("(u"); Serial.print(Trim,DEC); Serial.print(")"); 215 | Serial.print(" F="); Serial.print(results->helicopter.fastlane.Fire,DEC); 216 | 217 | } 218 | #endif //ENABLE_FastLane 219 | 220 | #ifdef ENABLE_JVC 221 | else if (results->decode_type == JVC) { 222 | Serial.print("Decoded JVC: "); 223 | } 224 | #endif //ENABLE_JVC 225 | 226 | #ifdef ENABLE_RCMM 227 | else if (results->decode_type == RCMM) { 228 | Serial.print("Decoded RCMM: "); 229 | } 230 | Serial.print(" value="); 231 | Serial.print(results->value, HEX); 232 | Serial.print(" ("); 233 | Serial.print(results->bits, DEC); 234 | Serial.println(" bits)"); 235 | Serial.print("Raw ("); 236 | Serial.print(count, DEC); 237 | Serial.print("): "); 238 | 239 | for (int i = 0; i < count; i++) { 240 | if ((i % 2) == 1) { 241 | Serial.print(results->rawbuf[i]*USECPERTICK, DEC); 242 | } 243 | else { 244 | Serial.print(-(long)results->rawbuf[i]*USECPERTICK, DEC); 245 | } 246 | Serial.print(" "); 247 | } 248 | Serial.println(""); 249 | #endif //ENABLE_RCMM 250 | } 251 | 252 | 253 | void loop() { 254 | if (irrecv.decode(&results)) { 255 | Serial.println(results.value, HEX); 256 | dump(&results); 257 | irrecv.resume(); // Receive the next value 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /examples/IRrelay/IRrelay.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv 3 | * An IR detector/demodulator must be connected to the input RECV_PIN. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | int RECV_PIN = 11; 12 | int RELAY_PIN = 4; 13 | 14 | IRrecv irrecv(RECV_PIN); 15 | decode_results results; 16 | 17 | // Dumps out the decode_results structure. 18 | // Call this after IRrecv::decode() 19 | // void * to work around compiler issue 20 | //void dump(void *v) { 21 | // decode_results *results = (decode_results *)v 22 | void dump(decode_results *results) { 23 | int count = results->rawlen; 24 | if (results->decode_type == UNKNOWN) { 25 | Serial.println("Could not decode message"); 26 | } 27 | else { 28 | if (results->decode_type == NEC) { 29 | Serial.print("Decoded NEC: "); 30 | } 31 | else if (results->decode_type == SONY) { 32 | Serial.print("Decoded SONY: "); 33 | } 34 | else if (results->decode_type == RC5) { 35 | Serial.print("Decoded RC5: "); 36 | } 37 | else if (results->decode_type == RC6) { 38 | Serial.print("Decoded RC6: "); 39 | } 40 | else if (results->decode_type == RCMM) { 41 | Serial.print("Decoded RCMM: "); 42 | } 43 | else if (results->decode_type == MAGIQUEST) { 44 | Serial.print("Decoded MAGIQUEST: "); 45 | } 46 | Serial.print(results->value, HEX); 47 | Serial.print(" ("); 48 | Serial.print(results->bits, DEC); 49 | Serial.println(" bits)"); 50 | } 51 | Serial.print("Raw ("); 52 | Serial.print(count, DEC); 53 | Serial.print("): "); 54 | 55 | for (int i = 0; i < count; i++) { 56 | if ((i % 2) == 1) { 57 | Serial.print(results->rawbuf[i]*USECPERTICK, DEC); 58 | } 59 | else { 60 | Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); 61 | } 62 | Serial.print(" "); 63 | } 64 | Serial.println(""); 65 | } 66 | 67 | void setup() 68 | { 69 | pinMode(RELAY_PIN, OUTPUT); 70 | pinMode(13, OUTPUT); 71 | Serial.begin(9600); 72 | irrecv.enableIRIn(); // Start the receiver 73 | } 74 | 75 | int on = 0; 76 | unsigned long last = millis(); 77 | 78 | void loop() { 79 | if (irrecv.decode(&results)) { 80 | // If it's been at least 1/4 second since the last 81 | // IR received, toggle the relay 82 | if (millis() - last > 250) { 83 | on = !on; 84 | digitalWrite(RELAY_PIN, on ? HIGH : LOW); 85 | digitalWrite(13, on ? HIGH : LOW); 86 | dump(&results); 87 | } 88 | last = millis(); 89 | irrecv.resume(); // Receive the next value 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/IRsendDemo/IRsendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | IRsend irsend; 12 | 13 | void setup() 14 | { 15 | Serial.begin(9600); 16 | } 17 | 18 | void loop() { 19 | if (Serial.read() != -1) { 20 | for (int i = 0; i < 3; i++) { 21 | irsend.sendSony(0xa90, 12); // Sony TV power code 22 | delay(40); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/IRsendDemoHelicopter/IRsendDemoHelicopter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemoHelicopter - demonstrates sending IR codes Remote Controlled Helicopters 3 | * This code is a proof concept by emulating each of the three 3.5ch IR helicopters Remote transmitter. 4 | * Both the real helicopter or IRrecvDump.ino should recieve signals, decode and either display or react correspondingly. 5 | * Major components of the software layout is: 6 | * 1) Setup 7 | * of Arduino Pins. 8 | * Model and Channel for selected device. 9 | * 2) Reading of Throttle and other Analog inputs. 10 | * 3) Convert the input from the common console to model specific formats. 11 | * 4) transmitting the corresponding formatted signal 12 | * 13 | * Much of the common console's signals are converted to the corresponding formats 14 | * Which have been done in easy to read subroutines. 15 | * This allows individual users to hack out un-wanted devices, and or alter the console interface. 16 | 17 | * a few items worth noting. 18 | * The remotes begin transmitting only when the throttle is above a minimum threshold. 19 | * Each model and selected channel auto resends the IR signal, as to constantly update the helicopter. 20 | * Each model's auto resend period is different based on channel as to provide a work-a-round for collisions. 21 | * This is a poor mans pseudo fall back. But works by brut force. 22 | * Each model of helicoptor's receiver has a unique HOLD time. 23 | * As to remember the last received IR signal, until the hold time expires. 24 | * When the throttle goes below the mininum each model will keep sending the IR (equivalent of OFF) for specified period. 25 | * This ensure prompt shut down. Otherwise it would be possible to drop throttle and not send the Zero Throttle. 26 | * Causing the Helicopter to remain with last value until hold time expires. 27 | * 28 | * Where the below code emulates the above behavior of each transmitter remote as found to behave. 29 | * 30 | * Hardware Requirements: 31 | * An IR LED must be connected to Arduino PWM pin 3. 32 | * Four Potentiometers connected to Analog inputs are used for Throttle, Pitch, Yaw and Trim 33 | * Some Helicoptors have buttons for weapons and such, which the require digital inputs. 34 | * The analog and digital inputs are defined below. See Used Pins section. 35 | * Selection of Model and Channel can be accomplished one of three possible ways, based on selecting appropiate #if(1). 36 | * 1st method is just to hard code. 37 | * 2nd method is to prompt from Serial Monitor Port 38 | * 3rd method is to determine based off of Digital IO pins. 39 | 40 | * Version 0.1 Feb, 2013 41 | * Copyright 2012 42 | */ 43 | 44 | #include 45 | 46 | // enable Serial Debug Prints 47 | #define DEBUG 48 | 49 | //Used Pins 50 | // note pin 3 is used by output LED 51 | // avoid pin 11 as it may used by input LED 52 | #define analogInThrottle A0 53 | #define analogInPitch A1 54 | #define analogInYaw A2 55 | #define analogInTrim A3 // may not be used with SymaR3 56 | #define DigitalInLbutton 5 57 | #define DigitalInRbutton 4 58 | #define DigitalInTurbo 2 59 | // optionally used Pins 60 | #define DigitalInModel0 9 61 | #define DigitalInModel1 8 62 | #define DigitalInChannel0 7 63 | #define DigitalInChannel1 6 // Useries only 64 | 65 | //list of different models 66 | #define _SYMAR5 0 67 | #define _SYMAR3 1 68 | #define _USERIES 2 69 | #define _FASTLANE 3 70 | 71 | // selected model to use when hard code selection method is defined below 72 | #define _JAMMED_MODEL _SYMAR5 73 | #define _JAMMED_CHANNEL 0 74 | 75 | // Throttle time to keep sending off. 76 | // As helicoptor will keep last known value for a timeout before quitting. 77 | #define THROTTLE_HOLD_TIME_SYMA 500 78 | #define THROTTLE_HOLD_TIME_FASTLANE 500 79 | #define THROTTLE_HOLD_TIME_USERIES 3000 80 | 81 | // some reason can not include IRremoteInt.h without being in DEBUG mode. 82 | // So these are defined here, again. 83 | #define SYMA_UPDATE_PERIOD_CH_A 120 // 0 84 | #define SYMA_UPDATE_PERIOD_CH_B 180 // 1 85 | #define USERIES_UPDATE_PERIOD_CH_A 150 // 1 86 | #define USERIES_UPDATE_PERIOD_CH_B 110 // 2 87 | #define USERIES_UPDATE_PERIOD_CH_C 190 // 0 88 | #define FASTLANE_UPDATE_PERIOD_CH_A 140 // 2 89 | #define FASTLANE_UPDATE_PERIOD_CH_B 180 // 1 90 | #define FASTLANE_UPDATE_PERIOD_CH_C 220 // 0 91 | 92 | //Global attributes 93 | IRsend irsend; 94 | int8_t model; 95 | int8_t channel; 96 | int32_t current_millis; 97 | int32_t prev_millis; 98 | int32_t last_throttle_millis; 99 | int32_t throttle_hold_time; 100 | int32_t update_period; 101 | union helicopter helicopter; 102 | 103 | void setup() 104 | { 105 | Serial.begin(9600); 106 | // update rate is fast, so 9600 may need to be bumped up, 107 | // depending on what else you do or added more debug. 108 | 109 | pinMode(analogInThrottle, INPUT); 110 | pinMode(analogInPitch, INPUT); 111 | pinMode(analogInYaw, INPUT); 112 | pinMode(analogInTrim, INPUT); 113 | pinMode(DigitalInLbutton, INPUT_PULLUP); 114 | pinMode(DigitalInRbutton, INPUT_PULLUP); 115 | pinMode(DigitalInTurbo, INPUT_PULLUP); 116 | 117 | while (!Serial) { 118 | ; // wait for serial port to connect. Needed for Leonardo only 119 | } 120 | 121 | // This is alot of prep. Just make Model and Channel selectable. 122 | #if (1) 123 | // just jam the values 124 | model = _JAMMED_MODEL; 125 | Serial.print(F("Model = ")); 126 | Serial.println(model, DEC); 127 | channel = _JAMMED_CHANNEL; 128 | #elif (0) 129 | // select based on input pins. 130 | pinMode(DigitalInModel0, INPUT_PULLUP); 131 | pinMode(DigitalInModel1, INPUT_PULLUP); 132 | model = digitalRead(DigitalInModel1) << 1 || digitalRead(DigitalInModel0); 133 | 134 | pinMode(DigitalInChannel0, INPUT_PULLUP); 135 | pinMode(DigitalInChannel1, INPUT_PULLUP); 136 | channel = digitalRead(DigitalInChannel1) << 1 || digitalRead(DigitalInChannel0); 137 | #else 138 | // select based on serial input, with rule checks 139 | model = -1; 140 | channel = -1; 141 | Serial.println(F("To begin.")); 142 | while (model < 0) { 143 | Serial.println(F("Enter Model of Helicopter?")); 144 | Serial.println(F("0 = SymaR5")); 145 | Serial.println(F("1 = SymaR3")); 146 | Serial.println(F("2 = Useries")); 147 | Serial.println(F("3 = FastLane")); 148 | while (!Serial.available()) { 149 | // wait for Serial input 150 | }; 151 | model = Serial.read() - 0x30; // substract ASCII offset for zero 152 | if (model > _USERIES) model = -1; 153 | } 154 | Serial.print(F("Model = ")); 155 | Serial.println(model, DEC); 156 | 157 | while (channel < 0) { 158 | Serial.println(F("Enter Model of Helicopter?")); 159 | Serial.print(F("A, B")); 160 | if (model == _USERIES) { // accomidate U-Series third channel 161 | Serial.println(F(", C")); 162 | } else { 163 | Serial.println(); 164 | } 165 | while (!Serial.available()) { 166 | // wait for Serial input 167 | }; 168 | channel = (toupper(Serial.read()) - 0x41) ; // substract ASCII offset for "A" or "a" 169 | } // while channel 170 | #endif 171 | 172 | #ifdef DEBUG 173 | Serial.print(F("Channel = ")); 174 | Serial.println(channel, DEC); 175 | Serial.print(F("update_period = ")); 176 | Serial.println(update_period, DEC); 177 | #endif 178 | 179 | // determine varianaces based on Model and Channel 180 | switch (model) { 181 | case _SYMAR5: 182 | case _SYMAR3: 183 | throttle_hold_time = THROTTLE_HOLD_TIME_SYMA; 184 | switch (channel) { 185 | case 0: 186 | update_period = SYMA_UPDATE_PERIOD_CH_A; 187 | break; 188 | case 1: 189 | update_period = SYMA_UPDATE_PERIOD_CH_B; 190 | break; 191 | } 192 | break; //_SYMARx 193 | 194 | case _USERIES: 195 | throttle_hold_time = THROTTLE_HOLD_TIME_USERIES; 196 | switch (channel) { 197 | case 0: 198 | update_period = USERIES_UPDATE_PERIOD_CH_A; 199 | channel = 1; 200 | break; 201 | case 1: 202 | update_period = USERIES_UPDATE_PERIOD_CH_B; 203 | channel = 2; 204 | break; 205 | case 2: 206 | update_period = USERIES_UPDATE_PERIOD_CH_C; 207 | channel = 0; 208 | break; 209 | } 210 | break; //_USERIES 211 | 212 | case _FASTLANE: 213 | throttle_hold_time = THROTTLE_HOLD_TIME_FASTLANE; 214 | switch (channel) { 215 | case 0: 216 | update_period = FASTLANE_UPDATE_PERIOD_CH_A; 217 | channel = 0; 218 | break; 219 | case 1: 220 | update_period = FASTLANE_UPDATE_PERIOD_CH_B; 221 | channel = 2; 222 | break; 223 | case 2: 224 | update_period = FASTLANE_UPDATE_PERIOD_CH_C; 225 | channel = 1; 226 | break; 227 | } 228 | break; //_FASTLANE 229 | } 230 | 231 | // prime periodic update 232 | prev_millis = millis(); 233 | last_throttle_millis = current_millis - throttle_hold_time; 234 | 235 | } // setup() 236 | 237 | void loop() { 238 | uint16_t throttle; 239 | uint16_t pitch; 240 | uint16_t yaw; 241 | uint16_t trim; 242 | 243 | current_millis = millis(); 244 | 245 | // check if next interval to transmit IR signal 246 | if (current_millis - prev_millis >= update_period) { 247 | prev_millis += update_period; // mark time for next interval. 248 | helicopter.dword = 0; // blank out un-defined bits. 249 | 250 | // read throttle 251 | throttle = analogRead(analogInThrottle); 252 | 253 | // is the throttle on or just off, if so begin transmitting 254 | if ((throttle > (1023*0.05)) || ((current_millis - last_throttle_millis) < throttle_hold_time) ) { 255 | if (throttle > (1023*0.05)) { 256 | last_throttle_millis = current_millis; // mark time for throttle timeout 257 | } 258 | #ifdef DEBUG 259 | Serial.print(current_millis, DEC); Serial.print(F("ms")); 260 | #endif 261 | 262 | // read rest of controls 263 | pitch = analogRead(analogInPitch); 264 | yaw = analogRead(analogInYaw); 265 | trim = analogRead(analogInTrim); 266 | 267 | // Ready message by mapping into unions bit structure 268 | switch (model) { 269 | case _SYMAR5: 270 | tx_SymaR5(channel, throttle, pitch, yaw, trim); 271 | break; // _SYMAR5 272 | 273 | case _SYMAR3: 274 | tx_SymaR3(channel, throttle, pitch, yaw, trim); 275 | break; // _SYMAR3 276 | 277 | case _USERIES: 278 | tx_uSeries(channel, throttle, pitch, yaw, trim); 279 | break; // _USERIES 280 | 281 | case _FASTLANE: 282 | tx_FastLane(channel, throttle, pitch, yaw, trim); 283 | break; // _USERIES 284 | } 285 | 286 | #ifdef DEBUG 287 | Serial.print(F(" +0x")); Serial.print(helicopter.dword, HEX); 288 | Serial.println(); 289 | #endif 290 | } // ~if throttle 291 | } // ~if timer service 292 | } // ~loop() 293 | 294 | void tx_SymaR5(uint8_t channel, uint16_t throttle, uint16_t pitch, uint16_t yaw, uint16_t trim) { 295 | helicopter.symaR5.Channel = channel; 296 | 297 | // rescale analog input to desired scale for model 298 | helicopter.symaR5.Throttle = map(throttle, 0, 1023, 0, 127); 299 | helicopter.symaR5.Pitch = map(pitch, 0, 1023, 0, 127); 300 | helicopter.symaR5.Yaw = map(yaw, 0, 1023, 127, 0); 301 | helicopter.symaR5.Trim = map(trim, 0, 1023, 127, 0); 302 | 303 | // send the IR 304 | irsend.sendSymaR5(helicopter.dword); 305 | 306 | #ifdef DEBUG 307 | Serial.print(F(" C=")); Serial.print(helicopter.symaR5.Channel,DEC); 308 | Serial.print(F(" T=")); Serial.print(helicopter.symaR5.Throttle,DEC); 309 | Serial.print(F(" P=")); Serial.print(helicopter.symaR5.Pitch,DEC); 310 | Serial.print(F(" Y=")); Serial.print(helicopter.symaR5.Yaw,DEC); 311 | Serial.print(F(" t=")); Serial.print(helicopter.symaR5.Trim,DEC); 312 | #endif 313 | } 314 | 315 | void tx_SymaR3(uint8_t channel, uint16_t throttle, uint16_t pitch, uint16_t yaw, uint16_t trim) { 316 | helicopter.symaR3.Channel = channel; 317 | 318 | // rescale analog input to desired scale for model 319 | helicopter.symaR3.Throttle = map(throttle, 0, 1023, 0, 127); 320 | helicopter.symaR3.Pitch = map(pitch, 0, 1023, 0, 127); 321 | helicopter.symaR3.Yaw = map(yaw, 0, 1023, 127, 0); 322 | 323 | // send the IR 324 | irsend.sendSymaR3(helicopter.dword); 325 | 326 | #ifdef DEBUG 327 | Serial.print(F(" C=")); Serial.print(helicopter.symaR3.Channel,DEC); 328 | Serial.print(F(" T=")); Serial.print(helicopter.symaR3.Throttle,DEC); 329 | Serial.print(F(" P=")); Serial.print(helicopter.symaR3.Pitch,DEC); 330 | Serial.print(F(" Y=")); Serial.print(helicopter.symaR3.Yaw,DEC); 331 | #endif 332 | } 333 | 334 | void tx_uSeries(uint8_t channel, uint16_t throttle, uint16_t pitch, uint16_t yaw, uint16_t trim) { 335 | helicopter.uSeries.Channel = channel; 336 | 337 | // rescale analog input to desired scale for model 338 | helicopter.uSeries.Throttle = map(throttle, 0, 1023, 0, 127); 339 | helicopter.uSeries.Pitch = map(pitch, 0, 1023, 0, 63); 340 | helicopter.uSeries.Yaw = map(yaw, 0, 1023, 31, 0); 341 | helicopter.uSeries.Trim = map(trim, 0, 1023, 63, 0); 342 | 343 | // read the buttons 344 | helicopter.uSeries.Turbo = ~digitalRead(DigitalInTurbo); 345 | helicopter.uSeries.Lbutton = ~digitalRead(DigitalInLbutton); 346 | helicopter.uSeries.Rbutton = ~digitalRead(DigitalInRbutton); 347 | 348 | // add in calculated parity checksum 349 | helicopter.uSeries.cksum = UseriesChecksum(helicopter.dword); 350 | 351 | // send the IR 352 | irsend.sendUseries(helicopter.dword); 353 | 354 | #ifdef DEBUG 355 | delay(40);//ms 356 | Serial.print(F(" C=")); Serial.print(helicopter.uSeries.Channel,DEC); 357 | Serial.print(F(" T=")); Serial.print(helicopter.uSeries.Throttle,DEC); 358 | Serial.print(F(" P=")); Serial.print(helicopter.uSeries.Pitch,DEC); 359 | Serial.print(F(" Y=")); Serial.print(helicopter.uSeries.Yaw,DEC); 360 | Serial.print(F(" t=")); Serial.print(helicopter.uSeries.Trim,DEC); 361 | Serial.print(F(" L=")); Serial.print(helicopter.uSeries.Lbutton,DEC); 362 | Serial.print(F(" R=")); Serial.print(helicopter.uSeries.Rbutton,DEC); 363 | Serial.print(F(" Turbo=")); Serial.print(helicopter.uSeries.Turbo,DEC); 364 | Serial.print(F(" cksum=")); Serial.print(helicopter.uSeries.cksum,DEC); 365 | Serial.flush(); 366 | #endif 367 | } 368 | 369 | void tx_FastLane(uint8_t channel, uint16_t throttle, uint16_t pitch, uint16_t yaw, uint16_t trim) { 370 | helicopter.fastlane.Channel = channel; 371 | 372 | // rescale analog input to desired scale for model 373 | helicopter.fastlane.Throttle = map(throttle, 0, 1023, 0, 63); 374 | helicopter.fastlane.Pitch = map(pitch, 0, 1023, 0, 15); 375 | 376 | // convert scaler analog input for Yaw to two component: direction bit and magnitude. 377 | #define YAW_SIZE 32 // input bit size of analog after mapping 378 | yaw = map(yaw, 0, 1023, (YAW_SIZE-1), 0); 379 | helicopter.fastlane.Yaw_dir = (yaw & (YAW_SIZE/2))>0?0:1; 380 | yaw = yaw & ~(YAW_SIZE/2); // strip off MSB, leaving the magnitude 381 | if (helicopter.fastlane.Yaw_dir == 0) { 382 | helicopter.fastlane.Yaw = yaw; // if not reverse direction simply use magnitude. 383 | } 384 | else { 385 | helicopter.fastlane.Yaw = (YAW_SIZE/2) - yaw; //otherwise convert to reverse direction 386 | } 387 | 388 | // convert scaler analog input for Trim to two component: direction bit and magnitude. 389 | #define TRIM_SIZE 32 // input bit size of analog after mapping 390 | trim = map(trim, 0, 1023, (TRIM_SIZE - 1), 0); 391 | helicopter.fastlane.Trim_dir = (trim & (TRIM_SIZE/2))>0?0:1; 392 | trim = trim & ~(TRIM_SIZE/2); // strip off MSB, leaving the magnitude 393 | if (helicopter.fastlane.Trim_dir == 0) { 394 | helicopter.fastlane.Trim = trim; // if not reverse direction simply use magnitude. 395 | } 396 | else { 397 | helicopter.fastlane.Trim = (TRIM_SIZE/2) - trim;//otherwise convert to reverse direction 398 | } 399 | // read the buttons 400 | helicopter.fastlane.Fire = ~digitalRead(DigitalInTurbo); 401 | 402 | // send the IR 403 | irsend.sendFastLane(helicopter.dword); 404 | 405 | #ifdef DEBUG 406 | delay(40);//ms 407 | Serial.print(F(" C=")); Serial.print(helicopter.fastlane.Channel,DEC); 408 | Serial.print(F(" T=")); Serial.print(helicopter.fastlane.Throttle,DEC); 409 | Serial.print(F(" P=")); Serial.print(helicopter.fastlane.Pitch,DEC); 410 | Serial.print(F(" Yd=")); Serial.print(helicopter.fastlane.Yaw_dir,DEC); 411 | Serial.print(F(" Y=")); Serial.print(helicopter.fastlane.Yaw,DEC); 412 | Serial.print(F(" td=")); Serial.print(helicopter.fastlane.Trim_dir,DEC); 413 | Serial.print(F(" t=")); Serial.print(helicopter.fastlane.Trim,DEC); 414 | Serial.print(F(" F=")); Serial.print(helicopter.fastlane.Fire,DEC); 415 | Serial.flush(); 416 | #endif 417 | } -------------------------------------------------------------------------------- /examples/IRsendDemoMagi/IRsendDemoMagi.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | */ 8 | 9 | #include 10 | 11 | IRsend irsend; 12 | 13 | void setup() 14 | { 15 | Serial.begin(115200); 16 | } 17 | 18 | void loop() { 19 | if (Serial.read() != -1) { 20 | delay(500); 21 | irsend.sendMagiQuest(0x19D1DD01, 0xB6); 22 | delay(3000); 23 | irsend.sendMagiQuest(0x18C04B01, 0xEEEE); 24 | delay(3000); 25 | irsend.sendMagiQuest(0x4FAB881, 0xB6); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/IRtest/IRtest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRtest unittest 3 | * Version 0.1 July, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * http://arcfn.com 6 | * 7 | * Note: to run these tests, edit IRremote/IRremote.h to add "#define TEST" 8 | * You must then recompile the library by removing IRremote.o and restarting 9 | * the arduino IDE. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | // Dumps out the decode_results structure. 16 | // Call this after IRrecv::decode() 17 | // void * to work around compiler issue 18 | //void dump(void *v) { 19 | // decode_results *results = (decode_results *)v 20 | void dump(decode_results *results) { 21 | int count = results->rawlen; 22 | if (results->decode_type == UNKNOWN) { 23 | Serial.println("Could not decode message"); 24 | } 25 | else { 26 | if (results->decode_type == NEC) { 27 | Serial.print("Decoded NEC: "); 28 | } 29 | else if (results->decode_type == SONY) { 30 | Serial.print("Decoded SONY: "); 31 | } 32 | else if (results->decode_type == RC5) { 33 | Serial.print("Decoded RC5: "); 34 | } 35 | else if (results->decode_type == RC6) { 36 | Serial.print("Decoded RC6: "); 37 | } 38 | else if (results->decode_type == RCMM) { 39 | Serial.print("Decoded RCMM: "); 40 | } 41 | Serial.print(results->value, HEX); 42 | Serial.print(" ("); 43 | Serial.print(results->bits, DEC); 44 | Serial.println(" bits)"); 45 | } 46 | Serial.print("Raw ("); 47 | Serial.print(count, DEC); 48 | Serial.print("): "); 49 | 50 | for (int i = 0; i < count; i++) { 51 | if ((i % 2) == 1) { 52 | Serial.print(results->rawbuf[i]*USECPERTICK, DEC); 53 | } 54 | else { 55 | Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); 56 | } 57 | Serial.print(" "); 58 | } 59 | Serial.println(""); 60 | } 61 | 62 | IRrecv irrecv(0); 63 | decode_results results; 64 | 65 | class IRsendDummy : 66 | public IRsend 67 | { 68 | public: 69 | // For testing, just log the marks/spaces 70 | #define SENDLOG_LEN 128 71 | int sendlog[SENDLOG_LEN]; 72 | int sendlogcnt; 73 | IRsendDummy() : 74 | IRsend() { 75 | } 76 | void reset() { 77 | sendlogcnt = 0; 78 | } 79 | void mark(int time) { 80 | sendlog[sendlogcnt] = time; 81 | if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; 82 | } 83 | void space(int time) { 84 | sendlog[sendlogcnt] = -time; 85 | if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; 86 | } 87 | // Copies the dummy buf into the interrupt buf 88 | void useDummyBuf() { 89 | int last = SPACE; 90 | irparams.rcvstate = STATE_STOP; 91 | irparams.rawlen = 1; // Skip the gap 92 | for (int i = 0 ; i < sendlogcnt; i++) { 93 | if (sendlog[i] < 0) { 94 | if (last == MARK) { 95 | // New space 96 | irparams.rawbuf[irparams.rawlen++] = (-sendlog[i] - MARK_EXCESS) / USECPERTICK; 97 | last = SPACE; 98 | } 99 | else { 100 | // More space 101 | irparams.rawbuf[irparams.rawlen - 1] += -sendlog[i] / USECPERTICK; 102 | } 103 | } 104 | else if (sendlog[i] > 0) { 105 | if (last == SPACE) { 106 | // New mark 107 | irparams.rawbuf[irparams.rawlen++] = (sendlog[i] + MARK_EXCESS) / USECPERTICK; 108 | last = MARK; 109 | } 110 | else { 111 | // More mark 112 | irparams.rawbuf[irparams.rawlen - 1] += sendlog[i] / USECPERTICK; 113 | } 114 | } 115 | } 116 | if (irparams.rawlen % 2) { 117 | irparams.rawlen--; // Remove trailing space 118 | } 119 | } 120 | }; 121 | 122 | IRsendDummy irsenddummy; 123 | 124 | void verify(unsigned long val, int bits, int type) { 125 | irsenddummy.useDummyBuf(); 126 | irrecv.decode(&results); 127 | Serial.print("Testing "); 128 | Serial.print(val, HEX); 129 | if (results.value == val && results.bits == bits && results.decode_type == type) { 130 | Serial.println(": OK"); 131 | } 132 | else { 133 | Serial.println(": Error"); 134 | dump(&results); 135 | } 136 | } 137 | 138 | void testNEC(unsigned long val, int bits) { 139 | irsenddummy.reset(); 140 | irsenddummy.sendNEC(val, bits); 141 | verify(val, bits, NEC); 142 | } 143 | void testSony(unsigned long val, int bits) { 144 | irsenddummy.reset(); 145 | irsenddummy.sendSony(val, bits); 146 | verify(val, bits, SONY); 147 | } 148 | void testRC5(unsigned long val, int bits) { 149 | irsenddummy.reset(); 150 | irsenddummy.sendRC5(val, bits); 151 | verify(val, bits, RC5); 152 | } 153 | void testRC6(unsigned long val, int bits) { 154 | irsenddummy.reset(); 155 | irsenddummy.sendRC6(val, bits); 156 | verify(val, bits, RC6); 157 | } 158 | void testRCMM(unsigned long val, int bits) { 159 | irsenddummy.reset(); 160 | irsenddummy.sendRCMM(val, bits); 161 | verify(val, bits, RCMM); 162 | } 163 | 164 | void test() { 165 | Serial.println("NEC tests"); 166 | testNEC(0x00000000, 32); 167 | testNEC(0xffffffff, 32); 168 | testNEC(0xaaaaaaaa, 32); 169 | testNEC(0x55555555, 32); 170 | testNEC(0x12345678, 32); 171 | Serial.println("Sony tests"); 172 | testSony(0xfff, 12); 173 | testSony(0x000, 12); 174 | testSony(0xaaa, 12); 175 | testSony(0x555, 12); 176 | testSony(0x123, 12); 177 | Serial.println("RC5 tests"); 178 | testRC5(0xfff, 12); 179 | testRC5(0x000, 12); 180 | testRC5(0xaaa, 12); 181 | testRC5(0x555, 12); 182 | testRC5(0x123, 12); 183 | Serial.println("RC6 tests"); 184 | testRC6(0xfffff, 20); 185 | testRC6(0x00000, 20); 186 | testRC6(0xaaaaa, 20); 187 | testRC6(0x55555, 20); 188 | testRC6(0x12345, 20); 189 | Serial.println("RCMM tests"); 190 | testNEC(0x00000000, 32); 191 | testNEC(0xffffffff, 32); 192 | testNEC(0xaaaaaaaa, 32); 193 | testNEC(0x55555555, 32); 194 | testNEC(0x12345678, 32); 195 | } 196 | 197 | void setup() 198 | { 199 | Serial.begin(9600); 200 | test(); 201 | } 202 | 203 | void loop() { 204 | } 205 | -------------------------------------------------------------------------------- /examples/IRtest2/IRtest2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Test send/receive functions of IRremote, using a pair of Arduinos. 3 | * 4 | * Arduino #1 should have an IR LED connected to the send pin (3). 5 | * Arduino #2 should have an IR detector/demodulator connected to the 6 | * receive pin (11) and a visible LED connected to pin 3. 7 | * 8 | * The cycle: 9 | * Arduino #1 will wait 2 seconds, then run through the tests. 10 | * It repeats this forever. 11 | * Arduino #2 will wait for at least one second of no signal 12 | * (to synchronize with #1). It will then wait for the same test 13 | * signals. It will log all the status to the serial port. It will 14 | * also indicate status through the LED, which will flash each time a test 15 | * is completed. If there is an error, it will light up for 5 seconds. 16 | * 17 | * The test passes if the LED flashes 19 times, pauses, and then repeats. 18 | * The test fails if the LED lights for 5 seconds. 19 | * 20 | * The test software automatically decides which board is the sender and which is 21 | * the receiver by looking for an input on the send pin, which will indicate 22 | * the sender. You should hook the serial port to the receiver for debugging. 23 | * 24 | * Copyright 2010 Ken Shirriff 25 | * http://arcfn.com 26 | */ 27 | 28 | #include 29 | 30 | int RECV_PIN = 11; 31 | int LED_PIN = 3; 32 | 33 | IRrecv irrecv(RECV_PIN); 34 | IRsend irsend; 35 | 36 | decode_results results; 37 | 38 | #define RECEIVER 1 39 | #define SENDER 2 40 | #define ERROR 3 41 | 42 | int mode; 43 | 44 | void setup() 45 | { 46 | Serial.begin(9600); 47 | // Check RECV_PIN to decide if we're RECEIVER or SENDER 48 | if (digitalRead(RECV_PIN) == HIGH) { 49 | mode = RECEIVER; 50 | irrecv.enableIRIn(); 51 | pinMode(LED_PIN, OUTPUT); 52 | digitalWrite(LED_PIN, LOW); 53 | Serial.println("Receiver mode"); 54 | } 55 | else { 56 | mode = SENDER; 57 | Serial.println("Sender mode"); 58 | } 59 | } 60 | 61 | // Wait for the gap between tests, to synchronize with 62 | // the sender. 63 | // Specifically, wait for a signal followed by a gap of at last gap ms. 64 | void waitForGap(int gap) { 65 | Serial.println("Waiting for gap"); 66 | while (1) { 67 | while (digitalRead(RECV_PIN) == LOW) { 68 | } 69 | unsigned long time = millis(); 70 | while (digitalRead(RECV_PIN) == HIGH) { 71 | if (millis() - time > gap) { 72 | return; 73 | } 74 | } 75 | } 76 | } 77 | 78 | // Dumps out the decode_results structure. 79 | // Call this after IRrecv::decode() 80 | void dump(decode_results *results) { 81 | int count = results->rawlen; 82 | if (results->decode_type == UNKNOWN) { 83 | Serial.println("Could not decode message"); 84 | } 85 | else { 86 | if (results->decode_type == NEC) { 87 | Serial.print("Decoded NEC: "); 88 | } 89 | else if (results->decode_type == SONY) { 90 | Serial.print("Decoded SONY: "); 91 | } 92 | else if (results->decode_type == RC5) { 93 | Serial.print("Decoded RC5: "); 94 | } 95 | else if (results->decode_type == RC6) { 96 | Serial.print("Decoded RC6: "); 97 | } 98 | else if (results->decode_type == MAGIQUEST) { 99 | Serial.print("Decoded MAGIQUEST: "); 100 | } 101 | Serial.print(results->value, HEX); 102 | Serial.print(" ("); 103 | Serial.print(results->bits, DEC); 104 | Serial.println(" bits)"); 105 | } 106 | Serial.print("Raw ("); 107 | Serial.print(count, DEC); 108 | Serial.print("): "); 109 | 110 | for (int i = 0; i < count; i++) { 111 | if ((i % 2) == 1) { 112 | Serial.print(results->rawbuf[i]*USECPERTICK, DEC); 113 | } 114 | else { 115 | Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); 116 | } 117 | Serial.print(" "); 118 | } 119 | Serial.println(""); 120 | } 121 | 122 | 123 | // Test send or receive. 124 | // If mode is SENDER, send a code of the specified type, value, and bits 125 | // If mode is RECEIVER, receive a code and verify that it is of the 126 | // specified type, value, and bits. For success, the LED is flashed; 127 | // for failure, the mode is set to ERROR. 128 | // The motivation behind this method is that the sender and the receiver 129 | // can do the same test calls, and the mode variable indicates whether 130 | // to send or receive. 131 | void test(char *label, int type, unsigned long value, int bits) { 132 | if (mode == SENDER) { 133 | Serial.println(label); 134 | if (type == NEC) { 135 | irsend.sendNEC(value, bits); 136 | } 137 | else if (type == SONY) { 138 | irsend.sendSony(value, bits); 139 | } 140 | else if (type == RC5) { 141 | irsend.sendRC5(value, bits); 142 | } 143 | else if (type == RC6) { 144 | irsend.sendRC6(value, bits); 145 | } 146 | else if (type == MAGIQUEST) { 147 | irsend.sendMagiQuest(value, bits); 148 | } 149 | else { 150 | Serial.print(label); 151 | Serial.println("Bad type!"); 152 | } 153 | delay(200); 154 | } 155 | else if (mode == RECEIVER) { 156 | irrecv.resume(); // Receive the next value 157 | unsigned long max_time = millis() + 30000; 158 | Serial.print(label); 159 | 160 | // Wait for decode or timeout 161 | while (!irrecv.decode(&results)) { 162 | if (millis() > max_time) { 163 | Serial.println("Timeout receiving data"); 164 | mode = ERROR; 165 | return; 166 | } 167 | } 168 | if (type == results.decode_type && value == results.value && bits == results.bits) { 169 | Serial.println (": OK"); 170 | digitalWrite(LED_PIN, HIGH); 171 | delay(20); 172 | digitalWrite(LED_PIN, LOW); 173 | } 174 | else { 175 | Serial.println(": BAD"); 176 | dump(&results); 177 | mode = ERROR; 178 | } 179 | } 180 | } 181 | 182 | // Test raw send or receive. This is similar to the test method, 183 | // except it send/receives raw data. 184 | void testRaw(char *label, unsigned int *rawbuf, int rawlen) { 185 | if (mode == SENDER) { 186 | Serial.println(label); 187 | irsend.sendRaw(rawbuf, rawlen, 38 /* kHz */); 188 | delay(200); 189 | } 190 | else if (mode == RECEIVER ) { 191 | irrecv.resume(); // Receive the next value 192 | unsigned long max_time = millis() + 30000; 193 | Serial.print(label); 194 | 195 | // Wait for decode or timeout 196 | while (!irrecv.decode(&results)) { 197 | if (millis() > max_time) { 198 | Serial.println("Timeout receiving data"); 199 | mode = ERROR; 200 | return; 201 | } 202 | } 203 | 204 | // Received length has extra first element for gap 205 | if (rawlen != results.rawlen - 1) { 206 | Serial.print("Bad raw length "); 207 | Serial.println(results.rawlen, DEC); 208 | mode = ERROR; 209 | return; 210 | } 211 | for (int i = 0; i < rawlen; i++) { 212 | long got = results.rawbuf[i+1] * USECPERTICK; 213 | // Adjust for extra duration of marks 214 | if (i % 2 == 0) { 215 | got -= MARK_EXCESS; 216 | } 217 | else { 218 | got += MARK_EXCESS; 219 | } 220 | // See if close enough, within 25% 221 | if (rawbuf[i] * 1.25 < got || got * 1.25 < rawbuf[i]) { 222 | Serial.println(": BAD"); 223 | dump(&results); 224 | mode = ERROR; 225 | return; 226 | } 227 | 228 | } 229 | Serial.println (": OK"); 230 | digitalWrite(LED_PIN, HIGH); 231 | delay(20); 232 | digitalWrite(LED_PIN, LOW); 233 | } 234 | } 235 | 236 | // This is the raw data corresponding to NEC 0x12345678 237 | unsigned int sendbuf[] = { /* NEC format */ 238 | 9000, 4500, 239 | 560, 560, 560, 560, 560, 560, 560, 1690, /* 1 */ 240 | 560, 560, 560, 560, 560, 1690, 560, 560, /* 2 */ 241 | 560, 560, 560, 560, 560, 1690, 560, 1690, /* 3 */ 242 | 560, 560, 560, 1690, 560, 560, 560, 560, /* 4 */ 243 | 560, 560, 560, 1690, 560, 560, 560, 1690, /* 5 */ 244 | 560, 560, 560, 1690, 560, 1690, 560, 560, /* 6 */ 245 | 560, 560, 560, 1690, 560, 1690, 560, 1690, /* 7 */ 246 | 560, 1690, 560, 560, 560, 560, 560, 560, /* 8 */ 247 | 560}; 248 | 249 | void loop() { 250 | if (mode == SENDER) { 251 | delay(2000); // Delay for more than gap to give receiver a better chance to sync. 252 | } 253 | else if (mode == RECEIVER) { 254 | waitForGap(1000); 255 | } 256 | else if (mode == ERROR) { 257 | // Light up for 5 seconds for error 258 | digitalWrite(LED_PIN, HIGH); 259 | delay(5000); 260 | digitalWrite(LED_PIN, LOW); 261 | mode = RECEIVER; // Try again 262 | return; 263 | } 264 | 265 | // The test suite. 266 | test("SONY1", SONY, 0x123, 12); 267 | test("SONY2", SONY, 0x000, 12); 268 | test("SONY3", SONY, 0xfff, 12); 269 | test("SONY4", SONY, 0x12345, 20); 270 | test("SONY5", SONY, 0x00000, 20); 271 | test("SONY6", SONY, 0xfffff, 20); 272 | test("NEC1", NEC, 0x12345678, 32); 273 | test("NEC2", NEC, 0x00000000, 32); 274 | test("NEC3", NEC, 0xffffffff, 32); 275 | test("NEC4", NEC, REPEAT, 32); 276 | test("RC51", RC5, 0x12345678, 32); 277 | test("RC52", RC5, 0x0, 32); 278 | test("RC53", RC5, 0xffffffff, 32); 279 | test("RC61", RC6, 0x12345678, 32); 280 | test("RC62", RC6, 0x0, 32); 281 | test("RC63", RC6, 0xffffffff, 32); 282 | test("MAGIQUEST", MAGIQUEST, 0x12345678, 56); 283 | 284 | // Tests of raw sending and receiving. 285 | // First test sending raw and receiving raw. 286 | // Then test sending raw and receiving decoded NEC 287 | // Then test sending NEC and receiving raw 288 | testRaw("RAW1", sendbuf, 67); 289 | if (mode == SENDER) { 290 | testRaw("RAW2", sendbuf, 67); 291 | test("RAW3", NEC, 0x12345678, 32); 292 | } 293 | else { 294 | test("RAW2", NEC, 0x12345678, 32); 295 | testRaw("RAW3", sendbuf, 67); 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend 3 | * An IR LED must be connected to Arduino PWM pin 3. 4 | * Version 0.1 July, 2009 5 | * Copyright 2009 Ken Shirriff 6 | * http://arcfn.com 7 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 8 | */ 9 | #include 10 | 11 | #define PanasonicAddress 0x4004 // Panasonic address (Pre data) 12 | #define PanasonicPower 0x100BCBD // Panasonic Power button 13 | 14 | #define JVCPower 0xC5E8 15 | 16 | IRsend irsend; 17 | 18 | void setup() 19 | { 20 | } 21 | 22 | void loop() { 23 | irsend.sendPanasonic(PanasonicAddress,PanasonicPower); // This should turn your TV on and off 24 | 25 | irsend.sendJVC(JVCPower, 16,0); // hex value, 16 bits, no repeat 26 | delayMicroseconds(50); // see http://www.sbprojects.com/knowledge/ir/jvc.php for information 27 | irsend.sendJVC(JVCPower, 16,1); // hex value, 16 bits, repeat 28 | delayMicroseconds(50); 29 | } 30 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For IRremote 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | decode_results KEYWORD1 10 | IRrecv KEYWORD1 11 | IRsend KEYWORD1 12 | magiquest KEYWORD1 13 | helicopter KEYWORD1 14 | 15 | ####################################### 16 | # Methods and Functions (KEYWORD2) 17 | ####################################### 18 | 19 | blink13 KEYWORD2 20 | decode KEYWORD2 21 | enableIRIn KEYWORD2 22 | resume KEYWORD2 23 | enableIROut KEYWORD2 24 | sendNEC KEYWORD2 25 | sendSony KEYWORD2 26 | sendSanyo KEYWORD2 27 | sendMitsubishi KEYWORD2 28 | sendRaw KEYWORD2 29 | sendRC5 KEYWORD2 30 | sendRC6 KEYWORD2 31 | sendDISH KEYWORD2 32 | sendSharp KEYWORD2 33 | sendPanasonic KEYWORD2 34 | sendJVC KEYWORD2 35 | sendMagiQuest KEYWORD2 36 | sendSymaR5 KEYWORD2 37 | sendSymaR3 KEYWORD2 38 | sendUseries KEYWORD2 39 | sendFastLane KEYWORD2 40 | sendRCMM KEYWORD2 41 | 42 | 43 | # 44 | ####################################### 45 | # Constants (LITERAL1) 46 | ####################################### 47 | 48 | NEC LITERAL1 49 | SONY LITERAL1 50 | SANYO LITERAL1 51 | MITSUBISHI LITERAL1 52 | RC5 LITERAL1 53 | RC6 LITERAL1 54 | DISH LITERAL1 55 | SHARP LITERAL1 56 | PANASONIC LITERAL1 57 | JVC LITERAL1 58 | MAGIQUEST LITERAL1 59 | SYMA_R3 LITERAL1 60 | SYMA_R5 LITERAL1 61 | USERIES LITERAL1 62 | FASTLANE LITERAL1 63 | RCMM LITERAL1 64 | UNKNOWN LITERAL1 65 | REPEAT LITERAL1 -------------------------------------------------------------------------------- /readme: -------------------------------------------------------------------------------- 1 | This is the IRremote library for the Arduino. 2 | 3 | To download from github (http://github.com/shirriff/Arduino-IRremote), click on the "Downloads" link in the upper right, click "Download as zip", and get a zip file. Unzip it and rename the directory shirriff-Arduino-IRremote-nnn to IRremote 4 | 5 | To install, move the downloaded IRremote directory to: 6 | arduino-1.x/libraries/IRremote 7 | where arduino-1.x is your Arduino installation directory 8 | 9 | After installation you should have files such as: 10 | arduino-1.x/libraries/IRremote/IRremote.cpp 11 | 12 | For details on the library see the Wiki on github or the blog post http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 13 | 14 | Copyright 2009-2012 Ken Shirriff 15 | --------------------------------------------------------------------------------