You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
6.3 KiB

/* IRLib_P04_RC6.h
* Part of IRLib Library for Arduino receiving, decoding, and sending
* infrared signals. See COPYRIGHT.txt and LICENSE.txt for more information.
*/
/*
* The RC6 protocol was invented by Phillips but is used by wide variety of manufacturers.
* Like the Phillips RC5 protocol it uses phased coding however the phase is backwards
* from RC5. With RC6 a space/mark pair indicates "0" and a mark/space indicates a "1".
* in the data. The protocol uses 36 kHz modulation however 38 kHz receivers can typically
* receive the codes okay.
* The protocol consists of a header followed by a "1" bit which is always on and we do not
* encode. This is followed by a 3 bit OEM code that is usually 0 or 6. This is followed by
* special trailer bit whose time is twice that of normal. It all but the 32-bit version,
* the trailer bit also serves as a toggle bit. The toggle bit changes if the button was
* pressed and released however remains the same if the button was held. You must toggle
* this bit yourself when sending data and account for it when interpreting decoded values.
* Next are the actual data bits. Varieties include 16, 20, 24, and 32 bit versions.
* Because we encode the 3 OEM bits and the toggle bit, our actual bit lengths are 20, 24,
* and 28 for the first three varieties. The 32-bit variety is different because it uses
* OEM bits of 011 followed by a 0 in what is traditionally the toggle bit.
* Because the 32-bit version is invariant in these first 4 bits, we do not encode them
* and presume they are always "0110". The 32-bit version uses the highest order of the
* data bits as a toggle bit. At this time the 16-bit version always uses OEM = 0 and
* other known varieties always use OEM = 6 but we will only make that presumption for the
* 32-bit version. Encoding the OEM bits allows for other OEM values to be used without
* modifying the library. If we ever encounter a 32-bit version with an OEM other than 6
* it will require a special modified encoder and decoder.
* Here is a description of known varieties:
* RC6-0-16: Original version by Phillips. 16 bits, we encode 20, toggle is 0x00010000
* RC6-6-20: Used by some Sky and Sky+ remotes. 20 bits, we encode 24, toggle is 0x00100000
* RC6-6-24: Also known as "Replay" protocol. 24 bits, we encode 28, toggle is 0x01000000
* RC6-6-32: Also known as "MCE" protocol. 32 bits, we encode 32, toggle is 0x00008000
*/
#ifndef IRLIB_PROTOCOL_04_H
#define IRLIB_PROTOCOL_04_H
#define IR_SEND_PROTOCOL_04 case 04: IRsendRC6::send(data,data2); break;
#define IR_DECODE_PROTOCOL_04 if(IRdecodeRC6::decode()) return true;
#ifdef IRLIB_HAVE_COMBO
#define PV_IR_DECODE_PROTOCOL_04 ,public virtual IRdecodeRC6
#define PV_IR_SEND_PROTOCOL_04 ,public virtual IRsendRC6
#else
#define PV_IR_DECODE_PROTOCOL_04 public virtual IRdecodeRC6
#define PV_IR_SEND_PROTOCOL_04 public virtual IRsendRC6
#endif
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#ifdef IRLIBSENDBASE_H
class IRsendRC6: public virtual IRsendBase {
public:
void send(uint32_t data, uint8_t nBits=16) {
if (nBits==0) nBits=16;
enableIROut(36);
uint64_t bigData = data;
if (nBits==32) {
bigData+=0xc00000000ull;//add OEM value
nBits=36;
};
bigData=bigData << (64 - nBits);
extent=0;
mark(RC6_HDR_MARK); space(RC6_HDR_SPACE);
mark(RC6_T1); space(RC6_T1);// start bit "1"
uint16_t t;
for (uint8_t i = 0; i < nBits; i++) {
if (i == 3) {
t = 2 * RC6_T1; // double-wide trailer bit
} else {
t = RC6_T1;
}
if (bigData & 0x8000000000000000ull) {
mark(t); space(t);//"1" is a Mark/space
} else {
space(t); mark(t);//"0" is a space/Mark
}
bigData <<= 1;
}
space(107000-extent); // Turn off at end
}
};
#endif //IRLIBSENDBASE_H
#ifdef IRLIBDECODEBASE_H
/* Note this decoder is a derived class from the IRdecodeRC base
* class rather than IRdecodeBase. The base class defines the
* method "getRClevel" which is common to both RC5 and RC6 protocols.
* It facilitates the decoding of phase encoded data.
*/
class IRdecodeRC6: public virtual IRdecodeRC {
public:
virtual bool decode(void) {
IRLIB_ATTEMPT_MESSAGE(F("RC6"));
resetDecoder();//This used to be in the receiver getResults.
//Legal lengths range from 24 through 76 we went one bigger just in case.
if( (recvGlobal.decodeLength < 23) || (recvGlobal.decodeLength > 77) )return RAW_COUNT_ERROR;
// Initial mark
if (!ignoreHeader) {
if (!MATCH(recvGlobal.decodeBuffer[1], RC6_HDR_MARK)) return HEADER_MARK_ERROR(RC6_HDR_MARK);
}
if (!MATCH(recvGlobal.decodeBuffer[2], RC6_HDR_SPACE)) return HEADER_SPACE_ERROR(RC6_HDR_SPACE);
offset=3;//Skip gap and header
data = 0;
used = 0;
// Get start bit (1)
if (getRClevel(&used, RC6_T1) != MARK) return DATA_MARK_ERROR(RC6_T1);
if (getRClevel(&used, RC6_T1) != SPACE) return DATA_SPACE_ERROR(RC6_T1);
for (nBits = 0; offset < recvGlobal.decodeLength; nBits++) {
RCLevel levelA, levelB; // Next two levels
levelA = getRClevel(&used, RC6_T1);
if (nBits == 3) {
// T bit is double wide; make sure second half matches
if (levelA != getRClevel(&used, RC6_T1)) return TRAILER_BIT_ERROR(RC6_T1);
}
levelB = getRClevel(&used, RC6_T1);
if (nBits == 3) {
// T bit is double wide; make sure second half matches
if (levelB != getRClevel(&used, RC6_T1)) return TRAILER_BIT_ERROR(RC6_T1);
}
if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
data = (data << 1) | 1; // 1 bit
} else if (levelA == SPACE && levelB == MARK) {
data <<= 1; // zero bit
} else {
return DATA_MARK_ERROR(RC6_T1);
}
}
// Success
if (nBits==36) {
nBits=32;//OEM & trailer bits are discarded on 32-bit version
} else {
//if ( (nBits!=20) || (nBits!=24) || (nBits!=28) ) return BIT_COUNT_ERROR;
}
bits = nBits;
value = data;
protocolNum = RC6;
return true;
}
};
#endif //IRLIBDECODEBASE_H
#define IRLIB_HAVE_COMBO
#endif //IRLIB_PROTOCOL_04_H