X-Git-Url: https://git.realraum.at/?p=svn42.git;a=blobdiff_plain;f=rf433ctl%2FIRremote%2FIRremote.cpp;fp=rf433ctl%2FIRremote%2FIRremote.cpp;h=0000000000000000000000000000000000000000;hp=b632723066e9aa1e331332eb3d28057657a300e4;hb=ff9137d257207a3a4b03c4f453cc1b7ce1e3cf17;hpb=a34e51d757fe52cb19de2937ae1b211894167524 diff --git a/rf433ctl/IRremote/IRremote.cpp b/rf433ctl/IRremote/IRremote.cpp deleted file mode 100644 index b632723..0000000 --- a/rf433ctl/IRremote/IRremote.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* - * 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, HIGH); // When not sending PWM, we want it low (invertiert angeschlossen) - - // 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 / 4; // 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; -}