From 6ee0dffb4c9fc40fc14cd2a3e6dadbc1226caccd Mon Sep 17 00:00:00 2001 From: Ken Shirriff Date: Fri, 22 Jan 2010 22:08:26 -0800 Subject: [PATCH] Initial commit from Irremote.zip --- IRremote.cpp | 601 +++++++++++++++++++++++++++++ IRremote.h | 94 +++++ IRremote.zip | Bin 0 -> 23732 bytes IRremoteInt.h | 111 ++++++ LICENSE.txt | 458 ++++++++++++++++++++++ examples/IRrecord/IRrecord.pde | 174 +++++++++ examples/IRrecvDemo/IRrecvDemo.pde | 28 ++ examples/IRrecvDump/IRrecvDump.pde | 74 ++++ examples/IRrelay/IRrelay.pde | 85 ++++ examples/IRsendDemo/IRsendDemo.pde | 26 ++ examples/IRtest/IRtest.pde | 190 +++++++++ keywords.txt | 37 ++ 12 files changed, 1878 insertions(+) create mode 100644 IRremote.cpp create mode 100644 IRremote.h create mode 100644 IRremote.zip create mode 100644 IRremoteInt.h create mode 100644 LICENSE.txt create mode 100644 examples/IRrecord/IRrecord.pde create mode 100644 examples/IRrecvDemo/IRrecvDemo.pde create mode 100644 examples/IRrecvDump/IRrecvDump.pde create mode 100644 examples/IRrelay/IRrelay.pde create mode 100644 examples/IRsendDemo/IRsendDemo.pde create mode 100644 examples/IRtest/IRtest.pde create mode 100644 keywords.txt diff --git a/IRremote.cpp b/IRremote.cpp new file mode 100644 index 0000000..bb6083e --- /dev/null +++ b/IRremote.cpp @@ -0,0 +1,601 @@ +/* + * IRremote + * Version 0.11 August, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#include "IRremote.h" +#include "IRremoteInt.h" + +// Provides ISR +#include + +volatile irparams_t irparams; + +// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging. +// To use them, set DEBUG in IRremoteInt.h +// Normally macros are used for efficiency +#ifdef DEBUG +int MATCH(int measured, int desired) { + Serial.print("Testing: "); + Serial.print(TICKS_LOW(desired), DEC); + Serial.print(" <= "); + Serial.print(measured, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired), DEC); + return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired); +} + +int MATCH_MARK(int measured_ticks, int desired_us) { + Serial.print("Testing mark "); + Serial.print(measured_ticks * USECPERTICK, DEC); + Serial.print(" vs "); + Serial.print(desired_us, DEC); + Serial.print(": "); + Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC); + Serial.print(" <= "); + Serial.print(measured_ticks, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC); + return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS); +} + +int MATCH_SPACE(int measured_ticks, int desired_us) { + Serial.print("Testing space "); + Serial.print(measured_ticks * USECPERTICK, DEC); + Serial.print(" vs "); + Serial.print(desired_us, DEC); + Serial.print(": "); + Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); + Serial.print(" <= "); + Serial.print(measured_ticks, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC); + return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS); +} +#endif + +void IRsend::sendNEC(unsigned long data, int nbits) +{ + enableIROut(38); + mark(NEC_HDR_MARK); + space(NEC_HDR_SPACE); + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + mark(NEC_BIT_MARK); + space(NEC_ONE_SPACE); + } + else { + mark(NEC_BIT_MARK); + space(NEC_ZERO_SPACE); + } + data <<= 1; + } + mark(NEC_BIT_MARK); + space(0); +} + +void IRsend::sendSony(unsigned long data, int nbits) { + enableIROut(40); + mark(SONY_HDR_MARK); + space(SONY_HDR_SPACE); + data = data << (32 - nbits); + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + mark(SONY_ONE_MARK); + space(SONY_HDR_SPACE); + } + else { + mark(SONY_ZERO_MARK); + space(SONY_HDR_SPACE); + } + data <<= 1; + } +} + +void IRsend::sendRaw(unsigned int buf[], int len, int hz) +{ + enableIROut(hz); + for (int i = 0; i < len; i++) { + if (i & 1) { + space(buf[i]); + } + else { + mark(buf[i]); + } + } + space(0); // Just to be sure +} + +// Note: first bit must be a one (start bit) +void IRsend::sendRC5(unsigned long data, int nbits) +{ + enableIROut(36); + data = data << (32 - nbits); + mark(RC5_T1); // First start bit + space(RC5_T1); // Second start bit + mark(RC5_T1); // Second start bit + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + space(RC5_T1); // 1 is space, then mark + mark(RC5_T1); + } + else { + mark(RC5_T1); + space(RC5_T1); + } + data <<= 1; + } + space(0); // Turn off at end +} + +// Caller needs to take care of flipping the toggle bit +void IRsend::sendRC6(unsigned long data, int nbits) +{ + enableIROut(36); + data = data << (32 - nbits); + mark(RC6_HDR_MARK); + space(RC6_HDR_SPACE); + mark(RC6_T1); // start bit + space(RC6_T1); + int t; + for (int i = 0; i < nbits; i++) { + if (i == 3) { + // double-wide trailer bit + t = 2 * RC6_T1; + } + else { + t = RC6_T1; + } + if (data & TOPBIT) { + mark(t); + space(t); + } + else { + space(t); + mark(t); + } + + data <<= 1; + } + space(0); // Turn off at end +} + +void IRsend::mark(int time) { + // Sends an IR mark for the specified number of microseconds. + // The mark output is modulated at the PWM frequency. + TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output + delayMicroseconds(time); +} + +/* Leave pin off for time (given in microseconds) */ +void IRsend::space(int time) { + // Sends an IR space for the specified number of microseconds. + // A space is no output, so the PWM output is disabled. + TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output + delayMicroseconds(time); +} + +void IRsend::enableIROut(int khz) { + // Enables IR output. The khz value controls the modulation frequency in kilohertz. + // The IR output will be on pin 3 (OC2B). + // This routine is designed for 36-40KHz; if you use it for other values, it's up to you + // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) + // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B + // controlling the duty cycle. + // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) + // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. + // A few hours staring at the ATmega documentation and this will all make sense. + // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. + + + // Disable the Timer2 Interrupt (which is used for receiving IR) + TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt + + pinMode(3, OUTPUT); + digitalWrite(3, LOW); // When not sending PWM, we want it low + + // COM2A = 00: disconnect OC2A + // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted + // WGM2 = 101: phase-correct PWM with OCRA as top + // CS2 = 000: no prescaling + TCCR2A = _BV(WGM20); + TCCR2B = _BV(WGM22) | _BV(CS20); + + // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. + OCR2A = SYSCLOCK / 2 / khz / 1000; + OCR2B = OCR2A / 3; // 33% duty cycle +} + +IRrecv::IRrecv(int recvpin) +{ + irparams.recvpin = recvpin; + irparams.blinkflag = 0; +} + +// initialization +void IRrecv::enableIRIn() { + // setup pulse clock timer interrupt + TCCR2A = 0; // normal mode + + //Prescale /8 (16M/8 = 0.5 microseconds per tick) + // Therefore, the timer interval can range from 0.5 to 128 microseconds + // depending on the reset value (255 to 0) + cbi(TCCR2B,CS22); + sbi(TCCR2B,CS21); + cbi(TCCR2B,CS20); + + //Timer2 Overflow Interrupt Enable + sbi(TIMSK2,TOIE2); + + RESET_TIMER2; + + sei(); // enable interrupts + + // initialize state machine variables + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; + + + // set pin modes + pinMode(irparams.recvpin, INPUT); +} + +// enable/disable blinking of pin 13 on IR processing +void IRrecv::blink13(int blinkflag) +{ + irparams.blinkflag = blinkflag; + if (blinkflag) + pinMode(BLINKLED, OUTPUT); +} + +// TIMER2 interrupt code to collect raw data. +// Widths of alternating SPACE, MARK are recorded in rawbuf. +// Recorded in ticks of 50 microseconds. +// rawlen counts the number of entries recorded so far. +// First entry is the SPACE between transmissions. +// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues. +// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts +ISR(TIMER2_OVF_vect) +{ + RESET_TIMER2; + + uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); + + irparams.timer++; // One more 50us tick + if (irparams.rawlen >= RAWBUF) { + // Buffer overflow + irparams.rcvstate = STATE_STOP; + } + switch(irparams.rcvstate) { + case STATE_IDLE: // In the middle of a gap + if (irdata == MARK) { + if (irparams.timer < GAP_TICKS) { + // Not big enough to be a gap. + irparams.timer = 0; + } + else { + // gap just ended, record duration and start recording transmission + irparams.rawlen = 0; + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_MARK; + } + } + break; + case STATE_MARK: // timing MARK + if (irdata == SPACE) { // MARK ended, record time + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_SPACE; + } + break; + case STATE_SPACE: // timing SPACE + if (irdata == MARK) { // SPACE just ended, record it + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_MARK; + } + else { // SPACE + if (irparams.timer > GAP_TICKS) { + // big SPACE, indicates gap between codes + // Mark current code as ready for processing + // Switch to STOP + // Don't reset timer; keep counting space width + irparams.rcvstate = STATE_STOP; + } + } + break; + case STATE_STOP: // waiting, measuring gap + if (irdata == MARK) { // reset gap timer + irparams.timer = 0; + } + break; + } + + if (irparams.blinkflag) { + if (irdata == MARK) { + PORTB |= B00100000; // turn pin 13 LED on + } + else { + PORTB &= B11011111; // turn pin 13 LED off + } + } +} + +void IRrecv::resume() { + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; +} + + + +// Decodes the received IR message +// Returns 0 if no data ready, 1 if data ready. +// Results of decoding are stored in results +int IRrecv::decode(decode_results *results) { + results->rawbuf = irparams.rawbuf; + results->rawlen = irparams.rawlen; + if (irparams.rcvstate != STATE_STOP) { + return ERR; + } +#ifdef DEBUG + Serial.println("Attempting NEC decode"); +#endif + if (decodeNEC(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting Sony decode"); +#endif + if (decodeSony(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting RC5 decode"); +#endif + if (decodeRC5(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting RC6 decode"); +#endif + if (decodeRC6(results)) { + return DECODED; + } + if (results->rawlen >= 6) { + // Only return raw buffer if at least 6 bits + results->decode_type = UNKNOWN; + results->bits = 0; + results->value = 0; + return DECODED; + } + // Throw away and start over + resume(); + return ERR; +} + +long IRrecv::decodeNEC(decode_results *results) { + long data = 0; + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) { + return ERR; + } + offset++; + // Check for repeat + if (irparams.rawlen == 4 && + MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) && + MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) { + results->bits = 0; + results->value = REPEAT; + results->decode_type = NEC; + return DECODED; + } + if (irparams.rawlen < 2 * NEC_BITS + 4) { + return ERR; + } + // Initial space + if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) { + return ERR; + } + offset++; + for (int i = 0; i < NEC_BITS; i++) { + if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) { + return ERR; + } + offset++; + if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) { + data = (data << 1) | 1; + } + else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) { + data <<= 1; + } + else { + return ERR; + } + offset++; + } + // Success + results->bits = NEC_BITS; + results->value = data; + results->decode_type = NEC; + return DECODED; +} + +long IRrecv::decodeSony(decode_results *results) { + long data = 0; + if (irparams.rawlen < 2 * SONY_BITS + 2) { + return ERR; + } + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) { + return ERR; + } + offset++; + + while (offset + 1 < irparams.rawlen) { + if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) { + break; + } + offset++; + if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) { + data = (data << 1) | 1; + } + else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) { + data <<= 1; + } + else { + return ERR; + } + offset++; + } + + // Success + results->bits = (offset - 1) / 2; + if (results->bits < 12) { + results->bits = 0; + return ERR; + } + results->value = data; + results->decode_type = SONY; + return DECODED; +} + +// Gets one undecoded level at a time from the raw buffer. +// The RC5/6 decoding is easier if the data is broken into time intervals. +// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1, +// successive calls to getRClevel will return MARK, MARK, SPACE. +// offset and used are updated to keep track of the current position. +// t1 is the time interval for a single bit in microseconds. +// Returns -1 for error (measured time interval is not a multiple of t1). +int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) { + if (*offset >= results->rawlen) { + // After end of recorded buffer, assume SPACE. + return SPACE; + } + int width = results->rawbuf[*offset]; + int val = ((*offset) % 2) ? MARK : SPACE; + int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS; + + int avail; + if (MATCH(width, t1 + correction)) { + avail = 1; + } + else if (MATCH(width, 2*t1 + correction)) { + avail = 2; + } + else if (MATCH(width, 3*t1 + correction)) { + avail = 3; + } + else { + return -1; + } + + (*used)++; + if (*used >= avail) { + *used = 0; + (*offset)++; + } +#ifdef DEBUG + if (val == MARK) { + Serial.println("MARK"); + } + else { + Serial.println("SPACE"); + } +#endif + return val; +} + +long IRrecv::decodeRC5(decode_results *results) { + if (irparams.rawlen < MIN_RC5_SAMPLES + 2) { + return ERR; + } + int offset = 1; // Skip gap space + long data = 0; + int used = 0; + // Get start bits + if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; + if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR; + if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; + int nbits; + for (nbits = 0; offset < irparams.rawlen; nbits++) { + int levelA = getRClevel(results, &offset, &used, RC5_T1); + int levelB = getRClevel(results, &offset, &used, RC5_T1); + if (levelA == SPACE && levelB == MARK) { + // 1 bit + data = (data << 1) | 1; + } + else if (levelA == MARK && levelB == SPACE) { + // zero bit + data <<= 1; + } + else { + return ERR; + } + } + + // Success + results->bits = nbits; + results->value = data; + results->decode_type = RC5; + return DECODED; +} + +long IRrecv::decodeRC6(decode_results *results) { + if (results->rawlen < MIN_RC6_SAMPLES) { + return ERR; + } + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) { + return ERR; + } + offset++; + if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) { + return ERR; + } + offset++; + long data = 0; + int used = 0; + // Get start bit (1) + if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR; + if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR; + int nbits; + for (nbits = 0; offset < results->rawlen; nbits++) { + int levelA, levelB; // Next two levels + levelA = getRClevel(results, &offset, &used, RC6_T1); + if (nbits == 3) { + // T bit is double wide; make sure second half matches + if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR; + } + levelB = getRClevel(results, &offset, &used, RC6_T1); + if (nbits == 3) { + // T bit is double wide; make sure second half matches + if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR; + } + if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5 + // 1 bit + data = (data << 1) | 1; + } + else if (levelA == SPACE && levelB == MARK) { + // zero bit + data <<= 1; + } + else { + return ERR; // Error + } + } + // Success + results->bits = nbits; + results->value = data; + results->decode_type = RC6; + return DECODED; +} diff --git a/IRremote.h b/IRremote.h new file mode 100644 index 0000000..35fb445 --- /dev/null +++ b/IRremote.h @@ -0,0 +1,94 @@ +/* + * IRremote + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#ifndef IRremote_h +#define IRremote_h + +// The following are compile-time library options. +// If you change them, recompile the library. +// If DEBUG is defined, a lot of debugging output will be printed during decoding. +// TEST must be defined for the IRtest unittests to work. It will make some +// methods virtual, which will be slightly slower, which is why it is optional. +// #define DEBUG +// #define TEST + +// Results returned from the decoder +class decode_results { +public: + int decode_type; // NEC, SONY, RC5, UNKNOWN + unsigned long value; // Decoded value + int bits; // Number of bits in decoded value + volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks + int rawlen; // Number of records in rawbuf. +}; + +// Values for decode_type +#define NEC 1 +#define SONY 2 +#define RC5 3 +#define RC6 4 +#define UNKNOWN -1 + +// Decoded value for NEC when a repeat code is received +#define REPEAT 0xffffffff + +// main class for receiving IR +class IRrecv +{ +public: + IRrecv(int recvpin); + void blink13(int blinkflag); + int decode(decode_results *results); + void enableIRIn(); + void resume(); +private: + // These are called by decode + int getRClevel(decode_results *results, int *offset, int *used, int t1); + long decodeNEC(decode_results *results); + long decodeSony(decode_results *results); + long decodeRC5(decode_results *results); + long decodeRC6(decode_results *results); +} +; + +// Only used for testing; can remove virtual for shorter code +#ifdef TEST +#define VIRTUAL virtual +#else +#define VIRTUAL +#endif + +class IRsend +{ +public: + IRsend() {} + void sendNEC(unsigned long data, int nbits); + void sendSony(unsigned long data, int nbits); + void sendRaw(unsigned int buf[], int len, int hz); + void sendRC5(unsigned long data, int nbits); + void sendRC6(unsigned long data, int nbits); + // private: + void enableIROut(int khz); + VIRTUAL void mark(int usec); + VIRTUAL void space(int usec); +} +; + +// Some useful constants + +#define USECPERTICK 50 // microseconds per clock interrupt tick +#define RAWBUF 76 // Length of raw duration buffer + +// Marks tend to be 100us too long, and spaces 100us too short +// when received due to sensor lag. +#define MARK_EXCESS 100 + +#endif diff --git a/IRremote.zip b/IRremote.zip new file mode 100644 index 0000000000000000000000000000000000000000..b462a8fd16a68183c3d2a266598d8e17894f9761 GIT binary patch literal 23732 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

-@l(=gtm?Lw?!{*1$ID6HRUjOn{CcyDM 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 Sz`^0&JQQzA;##`5@BRT(|B|f$ literal 0 HcmV?d00001 diff --git a/IRremoteInt.h b/IRremoteInt.h new file mode 100644 index 0000000..3824dbb --- /dev/null +++ b/IRremoteInt.h @@ -0,0 +1,111 @@ +/* + * IRremote + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#ifndef IRremoteint_h +#define IRremoteint_h + +#include + +#define CLKFUDGE 5 // fudge factor for clock interrupt overhead +#define CLK 256 // max value for clock (timer 2) +#define PRESCALE 8 // timer2 clock prescale +#define SYSCLOCK 16000000 // main Arduino clock +#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond + +#define ERR 0 +#define DECODED 1 + +#define BLINKLED 13 + +// defines for setting and clearing register bits +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +// clock timer reset value +#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE) +#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2 + +// pulse parameters in usec +#define NEC_HDR_MARK 9000 +#define NEC_HDR_SPACE 4500 +#define NEC_BIT_MARK 560 +#define NEC_ONE_SPACE 1600 +#define NEC_ZERO_SPACE 560 +#define NEC_RPT_SPACE 2250 + +#define SONY_HDR_MARK 2400 +#define SONY_HDR_SPACE 600 +#define SONY_ONE_MARK 1200 +#define SONY_ZERO_MARK 600 +#define SONY_RPT_LENGTH 45000 + +#define RC5_T1 889 +#define RC5_RPT_LENGTH 46000 + +#define RC6_HDR_MARK 2666 +#define RC6_HDR_SPACE 889 +#define RC6_T1 444 +#define RC6_RPT_LENGTH 46000 + +#define TOLERANCE 25 // percent tolerance in measurements +#define LTOL (1.0 - TOLERANCE/100.) +#define UTOL (1.0 + TOLERANCE/100.) + +#define _GAP 5000 // Minimum map between transmissions +#define GAP_TICKS (_GAP/USECPERTICK) + +#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK)) +#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1)) + +#ifndef DEBUG +#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us)) +#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS) +#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS) +// Debugging versions are in IRremote.cpp +#endif + +// receiver states +#define STATE_IDLE 2 +#define STATE_MARK 3 +#define STATE_SPACE 4 +#define STATE_STOP 5 + +// information for the interrupt handler +typedef struct { + uint8_t recvpin; // pin for IR data from detector + uint8_t rcvstate; // state machine + uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing + unsigned int timer; // state timer, counts 50uS ticks. + unsigned int rawbuf[RAWBUF]; // raw data + uint8_t rawlen; // counter of entries in rawbuf +} +irparams_t; + +// Defined in IRremote.cpp +extern volatile irparams_t irparams; + +// IR detector output is active low +#define MARK 0 +#define SPACE 1 + +#define TOPBIT 0x80000000 + +#define NEC_BITS 32 +#define SONY_BITS 12 +#define MIN_RC5_SAMPLES 11 +#define MIN_RC6_SAMPLES 1 + +#endif + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/IRrecord/IRrecord.pde b/examples/IRrecord/IRrecord.pde new file mode 100644 index 0000000..a1cf878 --- /dev/null +++ b/examples/IRrecord/IRrecord.pde @@ -0,0 +1,174 @@ +/* + * IRrecord: record and play back IR signals as a minimal + * An IR detector/demodulator must be connected to the input RECV_PIN. + * An IR LED must be connected to the output PWM pin 3. + * A button must be connected to the input BUTTON_PIN; this is the + * send button. + * A visible LED can be connected to STATUS_PIN to provide status. + * + * The logic is: + * If the button is pressed, send the IR code. + * If an IR code is received, record it. + * + * Version 0.11 September, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include + +int RECV_PIN = 11; +int BUTTON_PIN = 12; +int STATUS_PIN = 13; + +IRrecv irrecv(RECV_PIN); +IRsend irsend; + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver + pinMode(BUTTON_PIN, INPUT); + pinMode(STATUS_PIN, OUTPUT); +} + +// Storage for the recorded code +int codeType = -1; // The type of code +unsigned long codeValue; // The code value if not raw +unsigned int rawCodes[RAWBUF]; // The durations if raw +int codeLen; // The length of the code +int toggle = 0; // The RC5/6 toggle state + +// Stores the code for later playback +// Most of this code is just logging +void storeCode(decode_results *results) { + codeType = results->decode_type; + int count = results->rawlen; + if (codeType == UNKNOWN) { + Serial.println("Received unknown code, saving as raw"); + codeLen = results->rawlen - 1; + // To store raw codes: + // Drop first value (gap) + // Convert from ticks to microseconds + // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion + for (int i = 1; i <= codeLen; i++) { + if (i % 2) { + // Mark + rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS; + Serial.print(" m"); + } + else { + // Space + rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS; + Serial.print(" s"); + } + Serial.print(rawCodes[i - 1], DEC); + } + Serial.println(""); + } + else { + if (codeType == NEC) { + Serial.print("Received NEC: "); + if (results->value == REPEAT) { + // Don't record a NEC repeat value as that's useless. + Serial.println("repeat; ignoring."); + return; + } + } + else if (codeType == SONY) { + Serial.print("Received SONY: "); + } + else if (codeType == RC5) { + Serial.print("Received RC5: "); + } + else if (codeType == RC6) { + Serial.print("Received RC6: "); + } + else { + Serial.print("Unexpected codeType "); + Serial.print(codeType, DEC); + Serial.println(""); + } + Serial.println(results->value, HEX); + codeValue = results->value; + codeLen = results->bits; + } +} + +void sendCode(int repeat) { + if (codeType == NEC) { + if (repeat) { + irsend.sendNEC(REPEAT, codeLen); + Serial.println("Sent NEC repeat"); + } + else { + irsend.sendNEC(codeValue, codeLen); + Serial.print("Sent NEC "); + Serial.println(codeValue, HEX); + } + } + else if (codeType == SONY) { + irsend.sendSony(codeValue, codeLen); + Serial.print("Sent Sony "); + Serial.println(codeValue, HEX); + } + else if (codeType == RC5 || codeType == RC6) { + if (!repeat) { + // Flip the toggle bit for a new button press + toggle = 1 - toggle; + } + // Put the toggle bit into the code to send + codeValue = codeValue & ~(1 << (codeLen - 1)); + codeValue = codeValue | (toggle << (codeLen - 1)); + if (codeType == RC5) { + Serial.print("Sent RC5 "); + Serial.println(codeValue, HEX); + irsend.sendRC5(codeValue, codeLen); + } + else { + irsend.sendRC6(codeValue, codeLen); + Serial.print("Sent RC6 "); + Serial.println(codeValue, HEX); + } + } + else if (codeType == UNKNOWN /* i.e. raw */) { + // Assume 38 KHz + irsend.sendRaw(rawCodes, codeLen, 38); + Serial.println("Sent raw"); + } +} + +int lastButtonState; + +void loop() { + // If button pressed, send the code. + int buttonState = digitalRead(BUTTON_PIN); + if (lastButtonState == HIGH && buttonState == LOW) { + Serial.println("Released"); + irrecv.enableIRIn(); // Re-enable receiver + } + + if (buttonState) { + Serial.println("Pressed, sending"); + digitalWrite(STATUS_PIN, HIGH); + sendCode(lastButtonState == buttonState); + digitalWrite(STATUS_PIN, LOW); + delay(50); // Wait a bit between retransmissions + } + else if (irrecv.decode(&results)) { + digitalWrite(STATUS_PIN, HIGH); + storeCode(&results); + irrecv.resume(); // resume receiver + digitalWrite(STATUS_PIN, LOW); + } + lastButtonState = buttonState; +} + + + + + + + diff --git a/examples/IRrecvDemo/IRrecvDemo.pde b/examples/IRrecvDemo/IRrecvDemo.pde new file mode 100644 index 0000000..14982d8 --- /dev/null +++ b/examples/IRrecvDemo/IRrecvDemo.pde @@ -0,0 +1,28 @@ +/* + * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include + +int RECV_PIN = 11; + +IRrecv irrecv(RECV_PIN); + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +void loop() { + if (irrecv.decode(&results)) { + Serial.println(results.value, HEX); + irrecv.resume(); // Receive the next value + } +} diff --git a/examples/IRrecvDump/IRrecvDump.pde b/examples/IRrecvDump/IRrecvDump.pde new file mode 100644 index 0000000..ad3c599 --- /dev/null +++ b/examples/IRrecvDump/IRrecvDump.pde @@ -0,0 +1,74 @@ +/* + * IRremote: IRrecvDump - dump details of IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include + +int RECV_PIN = 11; + +IRrecv irrecv(RECV_PIN); + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +// Dumps out the decode_results structure. +// Call this after IRrecv::decode() +// void * to work around compiler issue +//void dump(void *v) { +// decode_results *results = (decode_results *)v +void dump(decode_results *results) { + int count = results->rawlen; + if (results->decode_type == UNKNOWN) { + Serial.println("Could not decode message"); + } + else { + if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); + } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); + } + Serial.print("Raw ("); + Serial.print(count, DEC); + Serial.print("): "); + + for (int i = 0; i < count; i++) { + if ((i % 2) == 1) { + Serial.print(results->rawbuf[i]*USECPERTICK, DEC); + } + else { + Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); + } + Serial.print(" "); + } + Serial.println(""); +} + + +void loop() { + if (irrecv.decode(&results)) { + Serial.println(results.value, HEX); + dump(&results); + irrecv.resume(); // Receive the next value + } +} diff --git a/examples/IRrelay/IRrelay.pde b/examples/IRrelay/IRrelay.pde new file mode 100644 index 0000000..f333133 --- /dev/null +++ b/examples/IRrelay/IRrelay.pde @@ -0,0 +1,85 @@ +/* + * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include + +int RECV_PIN = 11; +int RELAY_PIN = 4; + +IRrecv irrecv(RECV_PIN); +decode_results results; + +// Dumps out the decode_results structure. +// Call this after IRrecv::decode() +// void * to work around compiler issue +//void dump(void *v) { +// decode_results *results = (decode_results *)v +void dump(decode_results *results) { + int count = results->rawlen; + if (results->decode_type == UNKNOWN) { + Serial.println("Could not decode message"); + } + else { + if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); + } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); + } + Serial.print("Raw ("); + Serial.print(count, DEC); + Serial.print("): "); + + for (int i = 0; i < count; i++) { + if ((i % 2) == 1) { + Serial.print(results->rawbuf[i]*USECPERTICK, DEC); + } + else { + Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); + } + Serial.print(" "); + } + Serial.println(""); +} + +void setup() +{ + pinMode(RELAY_PIN, OUTPUT); + pinMode(13, OUTPUT); + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +int on = 0; +unsigned long last = millis(); + +void loop() { + if (irrecv.decode(&results)) { + // If it's been at least 1/4 second since the last + // IR received, toggle the relay + if (millis() - last > 250) { + on = !on; + digitalWrite(RELAY_PIN, on ? HIGH : LOW); + digitalWrite(13, on ? HIGH : LOW); + dump(&results); + } + last = millis(); + irrecv.resume(); // Receive the next value + } +} diff --git a/examples/IRsendDemo/IRsendDemo.pde b/examples/IRsendDemo/IRsendDemo.pde new file mode 100644 index 0000000..d864c82 --- /dev/null +++ b/examples/IRsendDemo/IRsendDemo.pde @@ -0,0 +1,26 @@ +/* + * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend + * An IR LED must be connected to Arduino PWM pin 3. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include + +IRsend irsend; + +void setup() +{ + Serial.begin(9600); +} + +void loop() { + if (Serial.read() != -1) { + for (int i = 0; i < 3; i++) { + irsend.sendSony(0xa90, 12); // Sony TV power code + delay(100); + } + } +} + diff --git a/examples/IRtest/IRtest.pde b/examples/IRtest/IRtest.pde new file mode 100644 index 0000000..b1cb522 --- /dev/null +++ b/examples/IRtest/IRtest.pde @@ -0,0 +1,190 @@ +/* + * IRremote: IRtest unittest + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + * + * Note: to run these tests, edit IRremote/IRremote.h to add "#define TEST" + * You must then recompile the library by removing IRremote.o and restarting + * the arduino IDE. + */ + +#include +#include + +// Dumps out the decode_results structure. +// Call this after IRrecv::decode() +// void * to work around compiler issue +//void dump(void *v) { +// decode_results *results = (decode_results *)v +void dump(decode_results *results) { + int count = results->rawlen; + if (results->decode_type == UNKNOWN) { + Serial.println("Could not decode message"); + } + else { + if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); + } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); + } + Serial.print("Raw ("); + Serial.print(count, DEC); + Serial.print("): "); + + for (int i = 0; i < count; i++) { + if ((i % 2) == 1) { + Serial.print(results->rawbuf[i]*USECPERTICK, DEC); + } + else { + Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); + } + Serial.print(" "); + } + Serial.println(""); +} + +IRrecv irrecv(0); +decode_results results; + +class IRsendDummy : +public IRsend +{ +public: + // For testing, just log the marks/spaces +#define SENDLOG_LEN 128 + int sendlog[SENDLOG_LEN]; + int sendlogcnt; + IRsendDummy() : + IRsend() { + } + void reset() { + sendlogcnt = 0; + } + void mark(int time) { + sendlog[sendlogcnt] = time; + if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; + } + void space(int time) { + sendlog[sendlogcnt] = -time; + if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; + } + // Copies the dummy buf into the interrupt buf + void useDummyBuf() { + int last = SPACE; + irparams.rcvstate = STATE_STOP; + irparams.rawlen = 1; // Skip the gap + for (int i = 0 ; i < sendlogcnt; i++) { + if (sendlog[i] < 0) { + if (last == MARK) { + // New space + irparams.rawbuf[irparams.rawlen++] = (-sendlog[i] - MARK_EXCESS) / USECPERTICK; + last = SPACE; + } + else { + // More space + irparams.rawbuf[irparams.rawlen - 1] += -sendlog[i] / USECPERTICK; + } + } + else if (sendlog[i] > 0) { + if (last == SPACE) { + // New mark + irparams.rawbuf[irparams.rawlen++] = (sendlog[i] + MARK_EXCESS) / USECPERTICK; + last = MARK; + } + else { + // More mark + irparams.rawbuf[irparams.rawlen - 1] += sendlog[i] / USECPERTICK; + } + } + } + if (irparams.rawlen % 2) { + irparams.rawlen--; // Remove trailing space + } + } +}; + +IRsendDummy irsenddummy; + +void verify(unsigned long val, int bits, int type) { + irsenddummy.useDummyBuf(); + irrecv.decode(&results); + Serial.print("Testing "); + Serial.print(val, HEX); + if (results.value == val && results.bits == bits && results.decode_type == type) { + Serial.println(": OK"); + } + else { + Serial.println(": Error"); + dump(&results); + } +} + +void testNEC(unsigned long val, int bits) { + irsenddummy.reset(); + irsenddummy.sendNEC(val, bits); + verify(val, bits, NEC); +} +void testSony(unsigned long val, int bits) { + irsenddummy.reset(); + irsenddummy.sendSony(val, bits); + verify(val, bits, SONY); +} +void testRC5(unsigned long val, int bits) { + irsenddummy.reset(); + irsenddummy.sendRC5(val, bits); + verify(val, bits, RC5); +} +void testRC6(unsigned long val, int bits) { + irsenddummy.reset(); + irsenddummy.sendRC6(val, bits); + verify(val, bits, RC6); +} + +void test() { + Serial.println("NEC tests"); + testNEC(0x00000000, 32); + testNEC(0xffffffff, 32); + testNEC(0xaaaaaaaa, 32); + testNEC(0x55555555, 32); + testNEC(0x12345678, 32); + Serial.println("Sony tests"); + testSony(0xfff, 12); + testSony(0x000, 12); + testSony(0xaaa, 12); + testSony(0x555, 12); + testSony(0x123, 12); + Serial.println("RC5 tests"); + testRC5(0xfff, 12); + testRC5(0x000, 12); + testRC5(0xaaa, 12); + testRC5(0x555, 12); + testRC5(0x123, 12); + Serial.println("RC6 tests"); + testRC6(0xfffff, 20); + testRC6(0x00000, 20); + testRC6(0xaaaaa, 20); + testRC6(0x55555, 20); + testRC6(0x12345, 20); +} + +void setup() +{ + Serial.begin(9600); + test(); +} + +void loop() { +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..7bf0f25 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For IRremote +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +decode_results KEYWORD1 +IRrecv KEYWORD1 +IRsend KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +blink13 KEYWORD2 +decode KEYWORD2 +enableIRIn KEYWORD2 +resume KEYWORD2 +enableIROut KEYWORD2 +sendNEC KEYWORD2 +sendSony KEYWORD2 +sendRaw KEYWORD2 +sendRC5 KEYWORD2 +sendRC6 KEYWORD2 +# +####################################### +# Constants (LITERAL1) +####################################### + +NEC LITERAL1 +SONY LITERAL1 +RC5 LITERAL1 +RC6 LITERAL1 +UNKNOWN LITERAL1 +REPEAT LITERAL1