#include "IRremote.h" //+============================================================================= // 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). // #if (DECODE_RC5 || DECODE_RC6) int getRClevel(decode_results *results, unsigned int *offset, int *used, int t1) { int width; int val; int correction; int avail; if (*offset >= results->rawlen) { return SPACE; // After end of recorded buffer, assume SPACE. } width = results->rawbuf[*offset]; val = ((*offset) % 2) ? MARK : SPACE; correction = (val == MARK) ? MARK_EXCESS_MICROS : - MARK_EXCESS_MICROS; 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)++; } DBG_PRINTLN((val == MARK) ? "MARK" : "SPACE"); return val; } #endif //============================================================================== // RRRR CCCC 55555 // R R C 5 // RRRR C 5555 // R R C 5 // R R CCCC 5555 // // NB: First bit must be a one (start bit) // #define MIN_RC5_SAMPLES 11 #define RC5_T1 889 #define RC5_RPT_LENGTH 46000 //+============================================================================= #if SEND_RC5 void IRsend::sendRC5(unsigned long data, int nbits) { // Set IR carrier frequency enableIROut(36); // Start mark(RC5_T1); space(RC5_T1); mark(RC5_T1); // Data - Biphase code MSB first for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { if (data & mask) { space(RC5_T1); // 1 is space, then mark mark(RC5_T1); } else { mark(RC5_T1); space(RC5_T1); } } space(0); // Always end with the LED off } void IRsend::sendRC5ext(uint8_t addr, uint8_t cmd, boolean toggle) { // Set IR carrier frequency enableIROut(36); uint8_t addressBits = 5; uint8_t commandBits = 7; // unsigned long nbits = addressBits + commandBits; // Start mark(RC5_T1); // Bit #6 of the command part, but inverted! uint8_t cmdBit6 = (1UL << (commandBits - 1)) & cmd; if (cmdBit6) { // Inverted (1 -> 0 = mark-to-space) mark(RC5_T1); space(RC5_T1); } else { space(RC5_T1); mark(RC5_T1); } commandBits--; // Toggle bit static int toggleBit = 1; if (toggle) { if (toggleBit == 0) { toggleBit = 1; } else { toggleBit = 0; } } if (toggleBit) { space(RC5_T1); mark(RC5_T1); } else { mark(RC5_T1); space(RC5_T1); } // Address for (uint8_t mask = 1UL << (addressBits - 1); mask; mask >>= 1) { if (addr & mask) { space(RC5_T1); // 1 is space, then mark mark(RC5_T1); } else { mark(RC5_T1); space(RC5_T1); } } // Command for (uint8_t mask = 1UL << (commandBits - 1); mask; mask >>= 1) { if (cmd & mask) { space(RC5_T1); // 1 is space, then mark mark(RC5_T1); } else { mark(RC5_T1); space(RC5_T1); } } space(0); // Always end with the LED off } #endif //+============================================================================= #if DECODE_RC5 bool IRrecv::decodeRC5() { int nbits; long data = 0; int used = 0; unsigned int offset = 1; // Skip gap space if (results.rawlen < MIN_RC5_SAMPLES + 2) { return false; } // Get start bits if (getRClevel(&results, &offset, &used, RC5_T1) != MARK) { return false; } if (getRClevel(&results, &offset, &used, RC5_T1) != SPACE) { return false; } if (getRClevel(&results, &offset, &used, RC5_T1) != MARK) { return false; } /* * Get data bits - MSB first */ for (nbits = 0; offset < results.rawlen; nbits++) { int levelA = getRClevel(&results, &offset, &used, RC5_T1); int levelB = getRClevel(&results, &offset, &used, RC5_T1); if ((levelA == SPACE) && (levelB == MARK)) { data = (data << 1) | 1; } else if ((levelA == MARK) && (levelB == SPACE)) { data = (data << 1) | 0; } else { return false; } } // Success results.bits = nbits; results.value = data; results.decode_type = RC5; return true; } bool IRrecv::decodeRC5(decode_results *aResults) { bool aReturnValue = decodeRC5(); *aResults = results; return aReturnValue; } #endif //+============================================================================= // RRRR CCCC 6666 // R R C 6 // RRRR C 6666 // R R C 6 6 // R R CCCC 666 // // NB : Caller needs to take care of flipping the toggle bit // #define MIN_RC6_SAMPLES 1 #define RC6_HEADER_MARK 2666 #define RC6_HEADER_SPACE 889 #define RC6_T1 444 #define RC6_RPT_LENGTH 46000 #if SEND_RC6 void IRsend::sendRC6(unsigned long data, int nbits) { // Set IR carrier frequency enableIROut(36); // Header mark(RC6_HEADER_MARK); space(RC6_HEADER_SPACE); // Start bit mark(RC6_T1); space(RC6_T1); // Data for (unsigned long i = 1, mask = 1UL << (nbits - 1); mask; i++, mask >>= 1) { // The fourth bit we send is a "double width trailer bit" int t = (i == 4) ? (RC6_T1 * 2) : (RC6_T1); if (data & mask) { mark(t); space(t); } else { space(t); mark(t); } } space(0); // Always end with the LED off } #endif //+============================================================================= #if DECODE_RC6 bool IRrecv::decodeRC6() { int nbits; long data = 0; int used = 0; unsigned int offset = 1; // Skip first space if (results.rawlen < MIN_RC6_SAMPLES) { return false; } // Initial mark if (!MATCH_MARK(results.rawbuf[offset], RC6_HEADER_MARK)) { return false; } offset++; if (!MATCH_SPACE(results.rawbuf[offset], RC6_HEADER_SPACE)) { return false; } offset++; // Get start bit (1) if (getRClevel(&results, &offset, &used, RC6_T1) != MARK) { return false; } if (getRClevel(&results, &offset, &used, RC6_T1) != SPACE) { return false; } 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 false; } } 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 false; } } if ((levelA == MARK) && (levelB == SPACE)) { data = (data << 1) | 1; // inverted compared to RC5 } else if ((levelA == SPACE) && (levelB == MARK)) { data = (data << 1) | 0; } else { return false; // Error } } // Success results.bits = nbits; results.value = data; results.decode_type = RC6; return true; } bool IRrecv::decodeRC6(decode_results *aResults) { bool aReturnValue = decodeRC6(); *aResults = results; return aReturnValue; } #endif