Mikanum/IRremote/ir_RC5_RC6.cpp
2023-01-19 08:45:51 +01:00

208 lines
5.7 KiB
C++

#include "IRremote.h"
#include "IRremoteInt.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 IRrecv::getRClevel (decode_results *results, 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 : - MARK_EXCESS;
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
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
}
#endif
//+=============================================================================
#if DECODE_RC5
bool IRrecv::decodeRC5 (decode_results *results)
{
int nbits;
long data = 0;
int used = 0;
int offset = 1; // Skip gap space
if (irparams.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 ;
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 )) 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;
}
#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_HDR_MARK 2666
#define RC6_HDR_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_HDR_MARK);
space(RC6_HDR_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 (decode_results *results)
{
int nbits;
long data = 0;
int used = 0;
int offset = 1; // Skip first space
if (results->rawlen < MIN_RC6_SAMPLES) return false ;
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset++], RC6_HDR_MARK)) return false ;
if (!MATCH_SPACE(results->rawbuf[offset++], RC6_HDR_SPACE)) return false ;
// 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;
}
#endif