mirror of
https://github.com/Theaninova/Arduino-IRremote.git
synced 2025-12-12 17:36:15 +00:00
Initial commit from Irremote.zip
This commit is contained in:
601
IRremote.cpp
Normal file
601
IRremote.cpp
Normal file
@@ -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 <avr/interrupt.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user