daily_automated
This commit is contained in:
205
trunk/Arduino/libraries/IRremote/src/IRremote.cpp
Normal file
205
trunk/Arduino/libraries/IRremote/src/IRremote.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
//******************************************************************************
|
||||
// IRremote
|
||||
// Version 2.0.1 June, 2015
|
||||
// Copyright 2009 Ken Shirriff
|
||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
//
|
||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
|
||||
// Modified by Mitra Ardron <mitra@mitra.biz>
|
||||
// Added Sanyo and Mitsubishi controllers
|
||||
// Modified Sony to spot the repeat codes that some Sony's send
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
// JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
// LG added by Darryl Smith (based on the JVC protocol)
|
||||
// Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
//******************************************************************************
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
struct irparams_struct irparams; // the irparams instance
|
||||
|
||||
//+=============================================================================
|
||||
// The match functions were (apparently) originally MACROs to improve code speed
|
||||
// (although this would have bloated the code) hence the names being CAPS
|
||||
// A later release implemented debug output and so they needed to be converted
|
||||
// to functions.
|
||||
// I tried to implement a dual-compile mode (DEBUG/non-DEBUG) but for some
|
||||
// reason, no matter what I did I could not get them to function as macros again.
|
||||
// I have found a *lot* of bugs in the Arduino compiler over the last few weeks,
|
||||
// and I am currently assuming that one of these bugs is my problem.
|
||||
// I may revisit this code at a later date and look at the assembler produced
|
||||
// in a hope of finding out what is going on, but for now they will remain as
|
||||
// functions even in non-DEBUG mode
|
||||
//
|
||||
int MATCH(int measured, int desired) {
|
||||
#if DEBUG
|
||||
Serial.print(F("Testing: "));
|
||||
Serial.print(TICKS_LOW(desired), DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(measured, DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(TICKS_HIGH(desired), DEC);
|
||||
#endif
|
||||
bool passed = ((measured >= TICKS_LOW(desired)) && (measured <= TICKS_HIGH(desired)));
|
||||
#if DEBUG
|
||||
if (passed) {
|
||||
Serial.println(F("?; passed"));
|
||||
} else {
|
||||
Serial.println(F("?; FAILED"));
|
||||
}
|
||||
#endif
|
||||
return passed;
|
||||
}
|
||||
|
||||
//+========================================================
|
||||
// Due to sensor lag, when received, Marks tend to be 100us too long
|
||||
//
|
||||
int MATCH_MARK(int measured_ticks, int desired_us) {
|
||||
#if DEBUG
|
||||
Serial.print(F("Testing mark (actual vs desired): "));
|
||||
Serial.print(measured_ticks * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F("us vs "));
|
||||
Serial.print(desired_us, DEC);
|
||||
Serial.print(F("us: "));
|
||||
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(measured_ticks * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(TICKS_HIGH(desired_us + MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC);
|
||||
#endif
|
||||
// compensate for marks exceeded by demodulator hardware
|
||||
bool passed = ((measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS_MICROS))
|
||||
&& (measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS_MICROS)));
|
||||
#if DEBUG
|
||||
if (passed) {
|
||||
Serial.println(F("?; passed"));
|
||||
} else {
|
||||
Serial.println(F("?; FAILED"));
|
||||
}
|
||||
#endif
|
||||
return passed;
|
||||
}
|
||||
|
||||
//+========================================================
|
||||
// Due to sensor lag, when received, Spaces tend to be 100us too short
|
||||
//
|
||||
int MATCH_SPACE(int measured_ticks, int desired_us) {
|
||||
#if DEBUG
|
||||
Serial.print(F("Testing space (actual vs desired): "));
|
||||
Serial.print(measured_ticks * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F("us vs "));
|
||||
Serial.print(desired_us, DEC);
|
||||
Serial.print(F("us: "));
|
||||
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(measured_ticks * MICROS_PER_TICK, DEC);
|
||||
Serial.print(F(" <= "));
|
||||
Serial.print(TICKS_HIGH(desired_us - MARK_EXCESS_MICROS) * MICROS_PER_TICK, DEC);
|
||||
#endif
|
||||
// compensate for marks exceeded and spaces shortened by demodulator hardware
|
||||
bool passed = ((measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS_MICROS))
|
||||
&& (measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS_MICROS)));
|
||||
#if DEBUG
|
||||
if (passed) {
|
||||
Serial.println(F("?; passed"));
|
||||
} else {
|
||||
Serial.println(F("?; FAILED"));
|
||||
}
|
||||
#endif
|
||||
return passed;
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Interrupt Service Routine - Fires every 50uS
|
||||
// TIMER2 interrupt code to collect raw data.
|
||||
// Widths of alternating SPACE, MARK are recorded in rawbuf.
|
||||
// Recorded in ticks of 50uS [microseconds, 0.000050 seconds]
|
||||
// 'rawlen' counts the number of entries recorded so far.
|
||||
// First entry is the SPACE between transmissions.
|
||||
// As soon as a the first [SPACE] entry 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; New logging starts
|
||||
//
|
||||
ISR (TIMER_INTR_NAME) {
|
||||
TIMER_RESET_INTR_PENDING; // reset timer interrupt flag if required (currently only for Teensy and ATmega4809)
|
||||
|
||||
// Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on]
|
||||
// digitalRead() is very slow. Optimisation is possible, but makes the code unportable
|
||||
uint8_t irdata = (uint8_t) digitalRead(irparams.recvpin);
|
||||
|
||||
irparams.timer++; // One more 50uS tick
|
||||
if (irparams.rawlen >= RAW_BUFFER_LENGTH) {
|
||||
// Flag up a read overflow; Stop the State Machine
|
||||
irparams.overflow = true;
|
||||
irparams.rcvstate = IR_REC_STATE_STOP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Due to a ESP32 compiler bug https://github.com/espressif/esp-idf/issues/1552 no switch statements are possible for ESP32
|
||||
* So we change the code to if / else if
|
||||
*/
|
||||
// switch (irparams.rcvstate) {
|
||||
//......................................................................
|
||||
if (irparams.rcvstate == IR_REC_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 gap duration; Start recording transmission
|
||||
// Initialize all state machine variables
|
||||
irparams.overflow = false;
|
||||
irparams.rawlen = 0;
|
||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||
irparams.timer = 0;
|
||||
irparams.rcvstate = IR_REC_STATE_MARK;
|
||||
}
|
||||
}
|
||||
} else if (irparams.rcvstate == IR_REC_STATE_MARK) { // Timing Mark
|
||||
if (irdata == SPACE) { // Mark ended; Record time
|
||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||
irparams.timer = 0;
|
||||
irparams.rcvstate = IR_REC_STATE_SPACE;
|
||||
}
|
||||
} else if (irparams.rcvstate == IR_REC_STATE_SPACE) { // Timing Space
|
||||
if (irdata == MARK) { // Space just ended; Record time
|
||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||
irparams.timer = 0;
|
||||
irparams.rcvstate = IR_REC_STATE_MARK;
|
||||
|
||||
} else if (irparams.timer > GAP_TICKS) { // Space
|
||||
// A long Space, indicates gap between codes
|
||||
// Flag the current code as ready for processing
|
||||
// Switch to STOP
|
||||
// Don't reset timer; keep counting Space width
|
||||
irparams.rcvstate = IR_REC_STATE_STOP;
|
||||
}
|
||||
} else if (irparams.rcvstate == IR_REC_STATE_STOP) { // Waiting; Measuring Gap
|
||||
if (irdata == MARK) {
|
||||
irparams.timer = 0; // Reset gap timer
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BLINKLED
|
||||
// If requested, flash LED while receiving IR data
|
||||
if (irparams.blinkflag) {
|
||||
if (irdata == MARK) {
|
||||
if (irparams.blinkpin) {
|
||||
digitalWrite(irparams.blinkpin, HIGH); // Turn user defined pin LED on
|
||||
} else {
|
||||
BLINKLED_ON(); // if no user defined LED pin, turn default LED pin for the hardware on
|
||||
}
|
||||
} else {
|
||||
if (irparams.blinkpin) {
|
||||
digitalWrite(irparams.blinkpin, LOW); // Turn user defined pin LED on
|
||||
} else {
|
||||
BLINKLED_OFF(); // if no user defined LED pin, turn default LED pin for the hardware on
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // BLINKLED
|
||||
}
|
||||
570
trunk/Arduino/libraries/IRremote/src/IRremote.h
Normal file
570
trunk/Arduino/libraries/IRremote/src/IRremote.h
Normal file
@@ -0,0 +1,570 @@
|
||||
/**
|
||||
* @file IRremote.h
|
||||
* @brief Public API to the library.
|
||||
*/
|
||||
|
||||
//******************************************************************************
|
||||
// IRremote
|
||||
// Version 2.0.1 June, 2015
|
||||
// Copyright 2009 Ken Shirriff
|
||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
// Edited by Mitra to add new controller SANYO
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
// JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
// LG added by Darryl Smith (based on the JVC protocol)
|
||||
// Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
// MagiQuest added by E. Stuart Hicks (based on code by mpflaga - https://github.com/mpflaga/Arduino-IRremote/)
|
||||
//******************************************************************************
|
||||
#ifndef IRremote_h
|
||||
#define IRremote_h
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#include "private/IRremoteInt.h"
|
||||
|
||||
/****************************************************
|
||||
* PROTOCOLS
|
||||
****************************************************/
|
||||
//------------------------------------------------------------------------------
|
||||
// Supported IR protocols
|
||||
// Each protocol you include costs memory and, during decode, costs time
|
||||
// Disable (set to 0) all the protocols you do not need/want!
|
||||
//
|
||||
#define DECODE_AIWA_RC_T501 1
|
||||
#define SEND_AIWA_RC_T501 1
|
||||
|
||||
#define DECODE_BOSEWAVE 1
|
||||
#define SEND_BOSEWAVE 1
|
||||
|
||||
#define DECODE_DENON 1
|
||||
#define SEND_DENON 1
|
||||
|
||||
#define DECODE_DISH 0 // NOT WRITTEN
|
||||
#define SEND_DISH 1
|
||||
|
||||
#define DECODE_JVC 1
|
||||
#define SEND_JVC 1
|
||||
|
||||
#define DECODE_LEGO_PF 0 // NOT WRITTEN
|
||||
#define SEND_LEGO_PF 1
|
||||
|
||||
#define DECODE_LG 1
|
||||
#define SEND_LG 1
|
||||
|
||||
#define DECODE_MAGIQUEST 1
|
||||
#define SEND_MAGIQUEST 1
|
||||
|
||||
#define DECODE_MITSUBISHI 1
|
||||
#define SEND_MITSUBISHI 0 // NOT WRITTEN
|
||||
|
||||
//#define USE_NEC_STANDARD // remove comment to have the standard NEC decoding (LSB first) available.
|
||||
#if defined(USE_NEC_STANDARD)
|
||||
#define DECODE_NEC_STANDARD 1
|
||||
#define DECODE_NEC 0
|
||||
#define LSB_FIRST_REQUIRED
|
||||
#else
|
||||
#define DECODE_NEC_STANDARD 0
|
||||
#define DECODE_NEC 1
|
||||
#endif
|
||||
#define SEND_NEC 1
|
||||
#define SEND_NEC_STANDARD 1
|
||||
|
||||
#define DECODE_PANASONIC 1
|
||||
#define SEND_PANASONIC 1
|
||||
|
||||
#define DECODE_RC5 1
|
||||
#define SEND_RC5 1
|
||||
|
||||
#define DECODE_RC6 1
|
||||
#define SEND_RC6 1
|
||||
|
||||
#define DECODE_SAMSUNG 1
|
||||
#define SEND_SAMSUNG 1
|
||||
|
||||
#define DECODE_SANYO 1
|
||||
#define SEND_SANYO 0 // NOT WRITTEN
|
||||
|
||||
#define DECODE_SHARP 1
|
||||
#define SEND_SHARP 1
|
||||
|
||||
#define DECODE_SHARP_ALT 1
|
||||
#define SEND_SHARP_ALT 1
|
||||
#if SEND_SHARP_ALT
|
||||
#define LSB_FIRST_REQUIRED
|
||||
#endif
|
||||
|
||||
#define DECODE_SONY 1
|
||||
#define SEND_SONY 1
|
||||
|
||||
#define DECODE_WHYNTER 1
|
||||
#define SEND_WHYNTER 1
|
||||
|
||||
#define DECODE_HASH 1 // special decoder for all protocols
|
||||
|
||||
/**
|
||||
* An enum consisting of all supported formats.
|
||||
* You do NOT need to remove entries from this list when disabling protocols!
|
||||
*/
|
||||
typedef enum {
|
||||
UNKNOWN = -1,
|
||||
UNUSED = 0,
|
||||
AIWA_RC_T501,
|
||||
BOSEWAVE,
|
||||
DENON,
|
||||
DISH,
|
||||
JVC,
|
||||
LEGO_PF,
|
||||
LG,
|
||||
MAGIQUEST,
|
||||
MITSUBISHI,
|
||||
NEC_STANDARD,
|
||||
NEC,
|
||||
PANASONIC,
|
||||
RC5,
|
||||
RC6,
|
||||
SAMSUNG,
|
||||
SANYO,
|
||||
SHARP,
|
||||
SHARP_ALT,
|
||||
SONY,
|
||||
WHYNTER,
|
||||
} decode_type_t;
|
||||
|
||||
/**
|
||||
* Comment this out for lots of lovely debug output.
|
||||
*/
|
||||
//#define DEBUG
|
||||
//------------------------------------------------------------------------------
|
||||
// Debug directives
|
||||
//
|
||||
#ifdef DEBUG
|
||||
# define DBG_PRINT(...) Serial.print(__VA_ARGS__)
|
||||
# define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
|
||||
#else
|
||||
/**
|
||||
* If DEBUG, print the arguments, otherwise do nothing.
|
||||
*/
|
||||
# define DBG_PRINT(...) void()
|
||||
/**
|
||||
* If DEBUG, print the arguments as a line, otherwise do nothing.
|
||||
*/
|
||||
# define DBG_PRINTLN(...) void()
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper macro for getting a macro definition as string
|
||||
//
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Mark & Space matching functions
|
||||
//
|
||||
int MATCH(int measured, int desired);
|
||||
int MATCH_MARK(int measured_ticks, int desired_us);
|
||||
int MATCH_SPACE(int measured_ticks, int desired_us);
|
||||
|
||||
/****************************************************
|
||||
* RECEIVING
|
||||
****************************************************/
|
||||
/**
|
||||
* Results returned from the decoder
|
||||
*/
|
||||
struct decode_results {
|
||||
decode_type_t decode_type; ///< UNKNOWN, NEC, SONY, RC5, ...
|
||||
unsigned int address; ///< Used by Panasonic & Sharp6 NEC_standard [16-bits]
|
||||
unsigned long value; ///< Decoded value / command [max 32-bits]
|
||||
int bits; ///< Number of bits in decoded value
|
||||
unsigned int magnitude; ///< Used by MagiQuest [16-bits]
|
||||
bool isRepeat; ///< True if repeat of value is detected
|
||||
|
||||
// next 3 values are copies of irparams values
|
||||
unsigned int *rawbuf; ///< Raw intervals in 50uS ticks
|
||||
unsigned int rawlen; ///< Number of records in rawbuf
|
||||
bool overflow; ///< true if IR raw code too long
|
||||
};
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
* Decoded value for NEC and others when a repeat code is received
|
||||
* Use Flag decode_results.isRepeat (see above) instead
|
||||
*/
|
||||
#define REPEAT 0xFFFFFFFF
|
||||
|
||||
/**
|
||||
* Main class for receiving IR
|
||||
*/
|
||||
class IRrecv {
|
||||
public:
|
||||
/**
|
||||
* Instantiate the IRrecv class. Multiple instantiation is not supported.
|
||||
* @param recvpin Arduino pin to use. No sanity check is made.
|
||||
*/
|
||||
IRrecv(int recvpin);
|
||||
/**
|
||||
* Instantiate the IRrecv class. Multiple instantiation is not supported.
|
||||
* @param recvpin Arduino pin to use, where a demodulating IR receiver is connected.
|
||||
* @param blinkpin pin to blink when receiving IR. Not supported by all hardware. No sanity check is made.
|
||||
*/
|
||||
IRrecv(int recvpin, int blinkpin);
|
||||
|
||||
/**
|
||||
* TODO: Why is this public???
|
||||
* @param blinkflag
|
||||
*/
|
||||
void blink13(int blinkflag);
|
||||
|
||||
/**
|
||||
* Attempt to decode the recently receive IR signal
|
||||
* @param results decode_results instance returning the decode, if any.
|
||||
* @return success of operation.
|
||||
*/
|
||||
bool decode(decode_results *aResults);__attribute__ ((deprecated ("You should use decode() without a parameter.")))
|
||||
; // deprecated
|
||||
bool decode();
|
||||
|
||||
/**
|
||||
* Enable IR reception.
|
||||
*/
|
||||
void enableIRIn();
|
||||
|
||||
/**
|
||||
* Disable IR reception.
|
||||
*/
|
||||
void disableIRIn();
|
||||
|
||||
/**
|
||||
* Returns status of reception
|
||||
* @return true if no reception is on-going.
|
||||
*/
|
||||
bool isIdle();
|
||||
|
||||
/**
|
||||
* Returns status of reception and copies IR-data to decode_results buffer if true.
|
||||
* @return true if data is available.
|
||||
*/
|
||||
bool available();
|
||||
|
||||
/**
|
||||
* Called to re-enable IR reception.
|
||||
*/
|
||||
void resume();
|
||||
|
||||
const char* getProtocolString();
|
||||
void printResultShort(Print * aSerial);
|
||||
|
||||
/**
|
||||
* Print the result (second argument) as Pronto Hex on the Stream supplied as argument.
|
||||
* @param stream The Stream on which to write, often Serial
|
||||
* @param results the decode_results as delivered from irrecv.decode.
|
||||
* @param frequency Modulation frequency in Hz. Often 38000Hz.
|
||||
*/
|
||||
void dumpPronto(Stream& stream, unsigned int frequency = 38000U);
|
||||
|
||||
unsigned long decodePulseDistanceData(uint8_t aNumberOfBits, uint8_t aStartOffset, unsigned int aBitMarkMicros,
|
||||
unsigned int aOneSpaceMicros, unsigned int aZeroSpaceMicros, bool aMSBfirst = true);
|
||||
|
||||
decode_results results; // the instance for decoding
|
||||
|
||||
private:
|
||||
#if DECODE_HASH
|
||||
bool decodeHash();
|
||||
bool decodeHash(decode_results *aResults);
|
||||
int compare(unsigned int oldval, unsigned int newval);
|
||||
#endif
|
||||
|
||||
//......................................................................
|
||||
#if DECODE_RC5
|
||||
/**
|
||||
* Try to decode the recently received IR signal as an RC5 signal-
|
||||
* @param results decode_results instance returning the decode, if any.
|
||||
* @return Success of the operation.
|
||||
*/
|
||||
bool decodeRC5();
|
||||
bool decodeRC5(decode_results *aResults);
|
||||
#endif
|
||||
#if DECODE_RC6
|
||||
bool decodeRC6();
|
||||
bool decodeRC6(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_NEC
|
||||
bool decodeNEC();
|
||||
bool decodeNEC(decode_results *aResults);
|
||||
#endif
|
||||
#if DECODE_NEC_STANDARD
|
||||
bool decodeNECStandard();
|
||||
#endif
|
||||
|
||||
//......................................................................
|
||||
#if DECODE_SONY
|
||||
bool decodeSony();
|
||||
bool decodeSony(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_PANASONIC
|
||||
bool decodePanasonic();
|
||||
bool decodePanasonic(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_JVC
|
||||
bool decodeJVC();
|
||||
bool decodeJVC(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_SAMSUNG
|
||||
bool decodeSAMSUNG();
|
||||
bool decodeSAMSUNG(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_WHYNTER
|
||||
bool decodeWhynter();
|
||||
bool decodeWhynter(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_AIWA_RC_T501
|
||||
bool decodeAiwaRCT501();
|
||||
bool decodeAiwaRCT501(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_LG
|
||||
bool decodeLG();
|
||||
bool decodeLG(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_SANYO
|
||||
bool decodeSanyo();
|
||||
bool decodeSanyo(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_MITSUBISHI
|
||||
bool decodeMitsubishi();
|
||||
bool decodeMitsubishi(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_DISH
|
||||
bool decodeDish () ; // NOT WRITTEN
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_SHARP
|
||||
bool decodeSharp();
|
||||
bool decodeSharp(decode_results *aResults);
|
||||
#endif
|
||||
#if DECODE_SHARP_ALT
|
||||
bool decodeSharpAlt();
|
||||
bool decodeSharpAlt(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_DENON
|
||||
bool decodeDenon();
|
||||
bool decodeDenon(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_LEGO_PF
|
||||
bool decodeLegoPowerFunctions (decode_results *aResults) ;
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_BOSEWAVE
|
||||
bool decodeBoseWave();
|
||||
bool decodeBoseWave(decode_results *aResults);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if DECODE_MAGIQUEST
|
||||
bool decodeMagiQuest();
|
||||
bool decodeMagiQuest(decode_results *aResults);
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************
|
||||
* SENDING
|
||||
****************************************************/
|
||||
/**
|
||||
* Define to use no carrier PWM, just simulate an active low receiver signal.
|
||||
*/
|
||||
//#define USE_NO_SEND_PWM
|
||||
/**
|
||||
* Define to use carrier PWM generation in software, instead of hardware PWM.
|
||||
*/
|
||||
//#define USE_SOFT_SEND_PWM
|
||||
/**
|
||||
* If USE_SOFT_SEND_PWM, this amount is subtracted from the on-time of the pulses.
|
||||
*/
|
||||
#ifndef PULSE_CORRECTION_MICROS
|
||||
#define PULSE_CORRECTION_MICROS 3
|
||||
#endif
|
||||
/**
|
||||
* If USE_SOFT_SEND_PWM, use spin wait instead of delayMicros().
|
||||
*/
|
||||
//#define USE_SPIN_WAIT
|
||||
/**
|
||||
* Main class for sending IR
|
||||
*/
|
||||
class IRsend {
|
||||
public:
|
||||
#if defined(USE_SOFT_SEND_PWM) || defined(USE_NO_SEND_PWM)
|
||||
IRsend(int pin = IR_SEND_PIN) {
|
||||
sendPin = pin;
|
||||
}
|
||||
#else
|
||||
IRsend() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void custom_delay_usec(unsigned long uSecs);
|
||||
void enableIROut(int khz);
|
||||
void sendPulseDistanceWidthData(unsigned int aOneMarkMicros, unsigned int aOneSpaceMicros, unsigned int aZeroMarkMicros,
|
||||
unsigned int aZeroSpaceMicros, unsigned long aData, uint8_t aNumberOfBits, bool aMSBfirst = true);
|
||||
void mark(unsigned int usec);
|
||||
void space(unsigned int usec);
|
||||
void sendRaw(const unsigned int buf[], unsigned int len, unsigned int hz);
|
||||
void sendRaw_P(const unsigned int buf[], unsigned int len, unsigned int hz);
|
||||
|
||||
//......................................................................
|
||||
#if SEND_RC5
|
||||
void sendRC5(unsigned long data, int nbits);
|
||||
void sendRC5ext(uint8_t addr, uint8_t cmd, boolean toggle);
|
||||
#endif
|
||||
#if SEND_RC6
|
||||
void sendRC6(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_NEC || SEND_NEC_STANDARD
|
||||
void sendNECRepeat();
|
||||
#endif
|
||||
#if SEND_NEC
|
||||
void sendNEC(unsigned long data, int nbits, bool repeat = false);
|
||||
#endif
|
||||
#if SEND_NEC_STANDARD
|
||||
void sendNECStandard(uint16_t aAddress, uint8_t aCommand, uint8_t aNumberOfRepeats = 0);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_SONY
|
||||
void sendSony(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_PANASONIC
|
||||
void sendPanasonic(unsigned int address, unsigned long data);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_JVC
|
||||
// JVC does NOT repeat by sending a separate code (like NEC does).
|
||||
// The JVC protocol repeats by skipping the header.
|
||||
// To send a JVC repeat signal, send the original code value
|
||||
// and set 'repeat' to true
|
||||
void sendJVC(unsigned long data, int nbits, bool repeat = false);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_SAMSUNG
|
||||
void sendSAMSUNG(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_WHYNTER
|
||||
void sendWhynter(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_AIWA_RC_T501
|
||||
void sendAiwaRCT501(int code);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_LG
|
||||
void sendLG(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_SANYO
|
||||
void sendSanyo ( ) ; // NOT WRITTEN
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_MISUBISHI
|
||||
void sendMitsubishi ( ) ; // NOT WRITTEN
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_DISH
|
||||
void sendDISH(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_SHARP
|
||||
void sendSharpRaw(unsigned long data, int nbits);
|
||||
void sendSharp(unsigned int address, unsigned int command);
|
||||
#endif
|
||||
#if SEND_SHARP_ALT
|
||||
void sendSharpAltRaw(unsigned int data, int nbits);
|
||||
void sendSharpAlt(uint8_t address, uint8_t command);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_DENON
|
||||
void sendDenon(unsigned long data, int nbits);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_LEGO_PF
|
||||
void sendLegoPowerFunctions(uint16_t data, bool repeat = true);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_BOSEWAVE
|
||||
void sendBoseWave(unsigned char code);
|
||||
#endif
|
||||
//......................................................................
|
||||
#if SEND_MAGIQUEST
|
||||
void sendMagiQuest(unsigned long wand_id, unsigned int magnitude);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse the string given as Pronto Hex, and send it a number of times given
|
||||
* as the second argument. Thereby the division of the Pronto Hex into
|
||||
* an intro-sequence and a repeat sequence is taken into account:
|
||||
* First the intro sequence is sent, then the repeat sequence is sent times-1 times.
|
||||
* However, if the intro sequence is empty, the repeat sequence is sent times times.
|
||||
* <a href="http://www.harctoolbox.org/Glossary.html#ProntoSemantics">Reference</a>.
|
||||
*
|
||||
* Note: Using this function is very wasteful for the memory consumption on
|
||||
* a small board.
|
||||
* Normally it is a much better ide to use a tool like e.g. IrScrutinizer
|
||||
* to transform Pronto type signals offline
|
||||
* to a more memory efficient format.
|
||||
*
|
||||
* @param prontoHexString C type string (null terminated) containing a Pronto Hex representation.
|
||||
* @param times Number of times to send the signal.
|
||||
*/
|
||||
void sendPronto(const char* prontoHexString, unsigned int times = 1U);
|
||||
|
||||
void sendPronto(const uint16_t* data, unsigned int length, unsigned int times = 1U);
|
||||
|
||||
#if HAS_FLASH_READ || defined(DOXYGEN)
|
||||
void sendPronto_PF(uint_farptr_t str, unsigned int times = 1U);
|
||||
|
||||
/**
|
||||
* Version of sendPronto that reads from PROGMEM, saving RAM memory.
|
||||
* @param pronto C type string (null terminated) containing a Pronto Hex representation.
|
||||
* @param times Number of times to send the signal.
|
||||
*/
|
||||
void sendPronto_PF(const char *str, unsigned int times = 1U);
|
||||
void sendPronto(const __FlashStringHelper *str, unsigned int times = 1U);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if (DECODE_RC5 || DECODE_RC6)
|
||||
/**
|
||||
* This helper function is shared by RC5 and RC6
|
||||
*/
|
||||
int getRClevel(decode_results *results, unsigned int *offset, int *used, int t1);
|
||||
#endif
|
||||
|
||||
#if defined(USE_SOFT_SEND_PWM) || defined(USE_NO_SEND_PWM)
|
||||
int sendPin;
|
||||
|
||||
# if defined(USE_SOFT_SEND_PWM)
|
||||
unsigned int periodTimeMicros;
|
||||
unsigned int periodOnTimeMicros;
|
||||
|
||||
void sleepMicros(unsigned long us);
|
||||
void sleepUntilMicros(unsigned long targetTime);
|
||||
# endif
|
||||
|
||||
#else
|
||||
const int sendPin = IR_SEND_PIN;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // IRremote_h
|
||||
47
trunk/Arduino/libraries/IRremote/src/esp32.cpp
Normal file
47
trunk/Arduino/libraries/IRremote/src/esp32.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifdef ESP32
|
||||
|
||||
// This file contains functions specific to the ESP32.
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
// "Idiot check"
|
||||
#ifdef USE_DEFAULT_ENABLE_IR_IN
|
||||
#error Must undef USE_DEFAULT_ENABLE_IR_IN
|
||||
#endif
|
||||
|
||||
hw_timer_t *timer;
|
||||
IRAM_ATTR void IRTimer(); // defined in IRremote.cpp, masqueraded as ISR(TIMER_INTR_NAME)
|
||||
|
||||
//+=============================================================================
|
||||
// initialization
|
||||
//
|
||||
void IRrecv::enableIRIn() {
|
||||
// Interrupt Service Routine - Fires every 50uS
|
||||
// ESP32 has a proper API to setup timers, no weird chip macros needed
|
||||
// simply call the readable API versions :)
|
||||
// 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up
|
||||
timer = timerBegin(1, 80, 1);
|
||||
timerAttachInterrupt(timer, &IRTimer, 1);
|
||||
// every 50ns, autoreload = true
|
||||
timerAlarmWrite(timer, 50, true);
|
||||
timerAlarmEnable(timer);
|
||||
|
||||
// Initialize state machine variables
|
||||
irparams.rcvstate = IR_REC_STATE_IDLE;
|
||||
irparams.rawlen = 0;
|
||||
|
||||
// Set pin modes
|
||||
pinMode(irparams.recvpin, INPUT);
|
||||
}
|
||||
|
||||
void IRrecv::disableIRIn() {
|
||||
timerEnd(timer);
|
||||
timerDetachInterrupt(timer);
|
||||
}
|
||||
|
||||
void IRsend::enableIROut(int khz) {
|
||||
ledcSetup(LED_CHANNEL, khz * 1000, 8); // 8 bit PWM resolution
|
||||
ledcAttachPin(IR_SEND_PIN, LED_CHANNEL); // bind pin to channel
|
||||
}
|
||||
|
||||
#endif // ESP32
|
||||
149
trunk/Arduino/libraries/IRremote/src/irPronto.cpp
Normal file
149
trunk/Arduino/libraries/IRremote/src/irPronto.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file irPronto.cpp
|
||||
* @brief In this file, the functions IRrecv::dumpPronto and
|
||||
* IRsend::sendPronto are defined.
|
||||
*/
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
// DO NOT EXPORT from this file
|
||||
static const uint16_t MICROSECONDS_T_MAX = 0xFFFFU;
|
||||
static const uint16_t learnedToken = 0x0000U;
|
||||
static const uint16_t learnedNonModulatedToken = 0x0100U;
|
||||
static const unsigned int bitsInHexadecimal = 4U;
|
||||
static const unsigned int digitsInProntoNumber = 4U;
|
||||
static const unsigned int numbersInPreamble = 4U;
|
||||
static const unsigned int hexMask = 0xFU;
|
||||
static const uint32_t referenceFrequency = 4145146UL;
|
||||
static const uint16_t fallbackFrequency = 64767U; // To use with frequency = 0;
|
||||
static const uint32_t microsecondsInSeconds = 1000000UL;
|
||||
static const unsigned int RESULT_JUNK_COUNT = 1U;
|
||||
|
||||
static unsigned int toFrequencyKHz(uint16_t code) {
|
||||
return ((referenceFrequency / code) + 500) / 1000;
|
||||
}
|
||||
|
||||
void IRsend::sendPronto(const uint16_t *data, unsigned int size, unsigned int times) {
|
||||
unsigned int timebase = (microsecondsInSeconds * data[1] + referenceFrequency / 2) / referenceFrequency;
|
||||
unsigned int khz;
|
||||
switch (data[0]) {
|
||||
case learnedToken: // normal, "learned"
|
||||
khz = toFrequencyKHz(data[1]);
|
||||
break;
|
||||
case learnedNonModulatedToken: // non-demodulated, "learned"
|
||||
khz = 0U;
|
||||
break;
|
||||
default:
|
||||
return; // There are other types, but they are not handled yet.
|
||||
}
|
||||
unsigned int intros = 2*data[2];
|
||||
unsigned int repeats = 2*data[3];
|
||||
if (numbersInPreamble + intros + repeats != size) // inconsistent sizes
|
||||
return;
|
||||
|
||||
unsigned int durations[intros + repeats];
|
||||
for (unsigned int i = 0; i < intros + repeats; i++) {
|
||||
uint32_t duration = ((uint32_t) data[i + numbersInPreamble]) * timebase;
|
||||
durations[i] = (unsigned int) ((duration <= MICROSECONDS_T_MAX) ? duration : MICROSECONDS_T_MAX);
|
||||
}
|
||||
|
||||
unsigned int numberRepeats = intros > 0 ? times - 1 : times;
|
||||
if (intros > 0) {
|
||||
sendRaw(durations, intros - 1, khz);
|
||||
}
|
||||
|
||||
if (numberRepeats == 0)
|
||||
return;
|
||||
|
||||
delay(durations[intros - 1] / 1000U);
|
||||
for (unsigned int i = 0; i < numberRepeats; i++) {
|
||||
sendRaw(durations + intros, repeats - 1, khz);
|
||||
if (i < numberRepeats - 1) { // skip last wait
|
||||
delay(durations[intros + repeats - 1] / 1000U);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IRsend::sendPronto(const char *str, unsigned int times) {
|
||||
size_t len = strlen(str)/(digitsInProntoNumber + 1) + 1;
|
||||
uint16_t data[len];
|
||||
const char *p = str;
|
||||
char *endptr[1];
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
long x = strtol(p, endptr, 16);
|
||||
if (x == 0 && i >= numbersInPreamble) {
|
||||
// Alignment error?, bail immediately (often right result).
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
data[i] = static_cast<uint16_t>(x); // If input is conforming, there can be no overflow!
|
||||
p = *endptr;
|
||||
}
|
||||
sendPronto(data, len, times);
|
||||
}
|
||||
|
||||
#if HAS_FLASH_READ
|
||||
void IRsend::sendPronto_PF(uint_farptr_t str, unsigned int times) {
|
||||
size_t len = strlen_PF(STRCPY_PF_CAST(str));
|
||||
char work[len + 1];
|
||||
strncpy_PF(work, STRCPY_PF_CAST(str), len);
|
||||
sendPronto(work, times);
|
||||
}
|
||||
|
||||
void IRsend::sendPronto_PF(const char *str, unsigned int times) {
|
||||
sendPronto_PF(reinterpret_cast<uint_farptr_t>(str), times); // to avoid infinite recursion
|
||||
};
|
||||
|
||||
void IRsend::sendPronto(const __FlashStringHelper *str, unsigned int times) {
|
||||
return sendPronto_PF(reinterpret_cast<uint_farptr_t>(str), times);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint16_t effectiveFrequency(uint16_t frequency) {
|
||||
return frequency > 0 ? frequency : fallbackFrequency;
|
||||
}
|
||||
|
||||
static uint16_t toTimebase(uint16_t frequency) {
|
||||
return microsecondsInSeconds / effectiveFrequency(frequency);
|
||||
}
|
||||
|
||||
static uint16_t toFrequencyCode(uint16_t frequency) {
|
||||
return referenceFrequency / effectiveFrequency(frequency);
|
||||
}
|
||||
|
||||
static char hexDigit(unsigned int x) {
|
||||
return (char) (x <= 9 ? ('0' + x) : ('A' + (x - 10)));
|
||||
}
|
||||
|
||||
static void dumpDigit(Stream& stream, unsigned int number) {
|
||||
stream.print(hexDigit(number));
|
||||
}
|
||||
|
||||
static void dumpNumber(Stream& stream, uint16_t number) {
|
||||
for (unsigned int i = 0; i < digitsInProntoNumber; i++) {
|
||||
unsigned int shifts = bitsInHexadecimal * (digitsInProntoNumber - 1 - i);
|
||||
dumpDigit(stream, (number >> shifts) & hexMask);
|
||||
}
|
||||
stream.print(' ');
|
||||
}
|
||||
|
||||
static void dumpDuration(Stream& stream, uint16_t duration, uint16_t timebase) {
|
||||
dumpNumber(stream, (duration * MICROS_PER_TICK + timebase / 2) / timebase);
|
||||
}
|
||||
|
||||
static void dumpSequence(Stream& stream, const volatile unsigned int *data, size_t length, uint16_t timebase) {
|
||||
for (unsigned int i = 0; i < length; i++)
|
||||
dumpDuration(stream, data[i], timebase);
|
||||
|
||||
dumpDuration(stream, _GAP, timebase);
|
||||
}
|
||||
|
||||
void IRrecv::dumpPronto(Stream& stream, unsigned int frequency) {
|
||||
dumpNumber(stream, frequency > 0 ? learnedToken : learnedNonModulatedToken);
|
||||
dumpNumber(stream, toFrequencyCode(frequency));
|
||||
dumpNumber(stream, (results.rawlen + 1) / 2);
|
||||
dumpNumber(stream, 0);
|
||||
unsigned int timebase = toTimebase(frequency);
|
||||
dumpSequence(stream, results.rawbuf + RESULT_JUNK_COUNT, results.rawlen - RESULT_JUNK_COUNT, timebase);
|
||||
}
|
||||
640
trunk/Arduino/libraries/IRremote/src/irReceive.cpp
Normal file
640
trunk/Arduino/libraries/IRremote/src/irReceive.cpp
Normal file
@@ -0,0 +1,640 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//+=============================================================================
|
||||
// Decodes the received IR message
|
||||
// Returns 0 if no data ready, 1 if data ready.
|
||||
// Results of decoding are stored in results
|
||||
//
|
||||
bool IRrecv::decode() {
|
||||
if (irparams.rcvstate != IR_REC_STATE_STOP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* First copy 3 values from irparams to internal results structure
|
||||
*/
|
||||
results.rawbuf = irparams.rawbuf;
|
||||
results.rawlen = irparams.rawlen;
|
||||
results.overflow = irparams.overflow;
|
||||
|
||||
// reset optional values
|
||||
results.address = 0;
|
||||
results.isRepeat = false;
|
||||
|
||||
#if DECODE_NEC_STANDARD
|
||||
DBG_PRINTLN("Attempting NEC_STANDARD decode");
|
||||
if (decodeNECStandard()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_NEC
|
||||
DBG_PRINTLN("Attempting NEC decode");
|
||||
if (decodeNEC()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SHARP
|
||||
DBG_PRINTLN("Attempting Sharp decode");
|
||||
if (decodeSharp()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SHARP_ALT
|
||||
DBG_PRINTLN("Attempting SharpAlt decode");
|
||||
if (decodeSharpAlt()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SONY
|
||||
DBG_PRINTLN("Attempting Sony decode");
|
||||
if (decodeSony()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SANYO
|
||||
DBG_PRINTLN("Attempting Sanyo decode");
|
||||
if (decodeSanyo()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_MITSUBISHI
|
||||
DBG_PRINTLN("Attempting Mitsubishi decode");
|
||||
if (decodeMitsubishi()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_RC5
|
||||
DBG_PRINTLN("Attempting RC5 decode");
|
||||
if (decodeRC5()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_RC6
|
||||
DBG_PRINTLN("Attempting RC6 decode");
|
||||
if (decodeRC6()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_PANASONIC
|
||||
DBG_PRINTLN("Attempting Panasonic decode");
|
||||
if (decodePanasonic()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_LG
|
||||
DBG_PRINTLN("Attempting LG decode");
|
||||
if (decodeLG()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_JVC
|
||||
DBG_PRINTLN("Attempting JVC decode");
|
||||
if (decodeJVC()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SAMSUNG
|
||||
DBG_PRINTLN("Attempting SAMSUNG decode");
|
||||
if (decodeSAMSUNG()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_WHYNTER
|
||||
DBG_PRINTLN("Attempting Whynter decode");
|
||||
if (decodeWhynter()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_AIWA_RC_T501
|
||||
DBG_PRINTLN("Attempting Aiwa RC-T501 decode");
|
||||
if (decodeAiwaRCT501()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_DENON
|
||||
DBG_PRINTLN("Attempting Denon decode");
|
||||
if (decodeDenon()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_LEGO_PF
|
||||
DBG_PRINTLN("Attempting Lego Power Functions");
|
||||
if (decodeLegoPowerFunctions()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_MAGIQUEST
|
||||
DBG_PRINTLN("Attempting MagiQuest decode");
|
||||
if (decodeMagiQuest()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_HASH
|
||||
DBG_PRINTLN("Hash decode");
|
||||
// decodeHash returns a hash on any input.
|
||||
// Thus, it needs to be last in the list.
|
||||
// If you add any decodes, add them before this.
|
||||
if (decodeHash()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throw away and start over
|
||||
resume();
|
||||
return false;
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
IRrecv::IRrecv(int recvpin) {
|
||||
irparams.recvpin = recvpin;
|
||||
irparams.blinkflag = 0;
|
||||
}
|
||||
|
||||
IRrecv::IRrecv(int recvpin, int blinkpin) {
|
||||
irparams.recvpin = recvpin;
|
||||
irparams.blinkpin = blinkpin;
|
||||
pinMode(blinkpin, OUTPUT);
|
||||
irparams.blinkflag = 0;
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// initialization
|
||||
//
|
||||
#ifdef USE_DEFAULT_ENABLE_IR_IN
|
||||
void IRrecv::enableIRIn() {
|
||||
// the interrupt Service Routine fires every 50 uS
|
||||
noInterrupts();
|
||||
// Setup pulse clock timer interrupt
|
||||
// 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)
|
||||
timerConfigForReceive();
|
||||
|
||||
// Timer2 Overflow Interrupt Enable
|
||||
TIMER_ENABLE_RECEIVE_INTR;
|
||||
|
||||
TIMER_RESET_INTR_PENDING;
|
||||
|
||||
interrupts();
|
||||
|
||||
// Initialize state machine state
|
||||
irparams.rcvstate = IR_REC_STATE_IDLE;
|
||||
// irparams.rawlen = 0; // not required
|
||||
|
||||
// Set pin modes
|
||||
pinMode(irparams.recvpin, INPUT);
|
||||
}
|
||||
|
||||
void IRrecv::disableIRIn() {
|
||||
TIMER_DISABLE_RECEIVE_INTR;
|
||||
}
|
||||
|
||||
#endif // USE_DEFAULT_ENABLE_IR_IN
|
||||
|
||||
//+=============================================================================
|
||||
// Enable/disable blinking of pin 13 on IR processing
|
||||
//
|
||||
void IRrecv::blink13(int blinkflag) {
|
||||
#ifdef BLINKLED
|
||||
irparams.blinkflag = blinkflag;
|
||||
if (blinkflag) {
|
||||
pinMode(BLINKLED, OUTPUT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Return if receiving new IR signals
|
||||
//
|
||||
bool IRrecv::isIdle() {
|
||||
return (irparams.rcvstate == IR_REC_STATE_IDLE || irparams.rcvstate == IR_REC_STATE_STOP) ? true : false;
|
||||
}
|
||||
|
||||
bool IRrecv::available() {
|
||||
if (irparams.rcvstate != IR_REC_STATE_STOP) {
|
||||
return false;
|
||||
}
|
||||
results.rawbuf = irparams.rawbuf;
|
||||
results.rawlen = irparams.rawlen;
|
||||
|
||||
results.overflow = irparams.overflow;
|
||||
if (!results.overflow) {
|
||||
return true;
|
||||
}
|
||||
resume(); //skip overflowed buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Restart the ISR state machine
|
||||
//
|
||||
void IRrecv::resume() {
|
||||
irparams.rcvstate = IR_REC_STATE_IDLE;
|
||||
// irparams.rawlen = 0; // not required
|
||||
}
|
||||
|
||||
# if DECODE_HASH
|
||||
//+=============================================================================
|
||||
// hashdecode - decode an arbitrary IR code.
|
||||
// Instead of decoding using a standard encoding scheme
|
||||
// (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
|
||||
//
|
||||
// The algorithm: look at the sequence of MARK signals, and see if each one
|
||||
// is shorter (0), the same length (1), or longer (2) than the previous.
|
||||
// Do the same with the SPACE signals. Hash the resulting sequence of 0's,
|
||||
// 1's, and 2's to a 32-bit value. This will give a unique value for each
|
||||
// different code (probably), for most code systems.
|
||||
//
|
||||
// http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
|
||||
//
|
||||
// Compare two tick values, returning 0 if newval is shorter,
|
||||
// 1 if newval is equal, and 2 if newval is longer
|
||||
// Use a tolerance of 20%
|
||||
//
|
||||
int IRrecv::compare(unsigned int oldval, unsigned int newval) {
|
||||
if (newval * 10 < oldval * 8) {
|
||||
return 0;
|
||||
}
|
||||
if (oldval * 10 < newval * 8) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each bit looks like: MARK + SPACE_1 -> 1
|
||||
* or : MARK + SPACE_0 -> 0
|
||||
* Data is read MSB first.
|
||||
*/
|
||||
unsigned long IRrecv::decodePulseDistanceData(uint8_t aNumberOfBits, uint8_t aStartOffset, unsigned int aBitMarkMicros,
|
||||
unsigned int aOneSpaceMicros, unsigned int aZeroSpaceMicros, bool aMSBfirst) {
|
||||
unsigned long aDecodedData = 0;
|
||||
|
||||
if (aMSBfirst) {
|
||||
for (uint8_t i = 0; i < aNumberOfBits; i++) {
|
||||
// Check for constant length mark
|
||||
if (!MATCH_MARK(results.rawbuf[aStartOffset], aBitMarkMicros)) {
|
||||
return false;
|
||||
}
|
||||
aStartOffset++;
|
||||
|
||||
// Check for variable length space indicating a 0 or 1
|
||||
if (MATCH_SPACE(results.rawbuf[aStartOffset], aOneSpaceMicros)) {
|
||||
aDecodedData = (aDecodedData << 1) | 1;
|
||||
} else if (MATCH_SPACE(results.rawbuf[aStartOffset], aZeroSpaceMicros)) {
|
||||
aDecodedData = (aDecodedData << 1) | 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
aStartOffset++;
|
||||
}
|
||||
}
|
||||
#if defined(LSB_FIRST_REQUIRED)
|
||||
else {
|
||||
for (unsigned long mask = 1UL; aNumberOfBits > 0; mask <<= 1, aNumberOfBits--) {
|
||||
// Check for constant length mark
|
||||
if (!MATCH_MARK(results.rawbuf[aStartOffset], aBitMarkMicros)) {
|
||||
return false;
|
||||
}
|
||||
aStartOffset++;
|
||||
|
||||
// Check for variable length space indicating a 0 or 1
|
||||
if (MATCH_SPACE(results.rawbuf[aStartOffset], aOneSpaceMicros)) {
|
||||
aDecodedData |= mask; // set the bit
|
||||
} else if (MATCH_SPACE(results.rawbuf[aStartOffset], aZeroSpaceMicros)) {
|
||||
// do not set the bit
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
aStartOffset++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return aDecodedData;
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
||||
// Converts the raw code values into a 32-bit hash code.
|
||||
// Hopefully this code is unique for each button.
|
||||
// This isn't a "real" decoding, just an arbitrary value.
|
||||
//
|
||||
#define FNV_PRIME_32 16777619
|
||||
#define FNV_BASIS_32 2166136261
|
||||
|
||||
bool IRrecv::decodeHash() {
|
||||
long hash = FNV_BASIS_32;
|
||||
|
||||
// Require at least 6 samples to prevent triggering on noise
|
||||
if (results.rawlen < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 1; (i + 2) < results.rawlen; i++) {
|
||||
int value = compare(results.rawbuf[i], results.rawbuf[i + 2]);
|
||||
// Add value into the hash
|
||||
hash = (hash * FNV_PRIME_32) ^ value;
|
||||
}
|
||||
|
||||
results.value = hash;
|
||||
results.bits = 32;
|
||||
results.decode_type = UNKNOWN;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeHash(decode_results *aResults) {
|
||||
bool aReturnValue = decodeHash();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif // defined(DECODE_HASH)
|
||||
|
||||
const char* IRrecv::getProtocolString() {
|
||||
switch (results.decode_type) {
|
||||
default:
|
||||
case UNKNOWN:
|
||||
return ("UNKNOWN");
|
||||
break;
|
||||
#if DECODE_AIWA_RC_T501
|
||||
case AIWA_RC_T501:
|
||||
return ("AIWA_RC_T501");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_BOSEWAVE
|
||||
case BOSEWAVE:
|
||||
return ("BOSEWAVE");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_DENON
|
||||
case DENON:
|
||||
return ("Denon");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_DISH
|
||||
case DISH:
|
||||
return("DISH");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_JVC
|
||||
case JVC:
|
||||
return ("JVC");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_LEGO_PF
|
||||
case LG:
|
||||
return("LEGO");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_LG
|
||||
case LG:
|
||||
return ("LG");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_MAGIQUEST
|
||||
case MAGIQUEST:
|
||||
return ("MAGIQUEST");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_MITSUBISHI
|
||||
case MITSUBISHI:
|
||||
return ("MITSUBISHI");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_NEC_STANDARD
|
||||
case NEC_STANDARD:
|
||||
return ("NEC_STANDARD");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_NEC
|
||||
case NEC:
|
||||
return("NEC");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_PANASONIC
|
||||
case PANASONIC:
|
||||
return ("PANASONIC");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_RC5
|
||||
case RC5:
|
||||
return ("RC5");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_RC6
|
||||
case RC6:
|
||||
return ("RC6");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_SAMSUNG
|
||||
case SAMSUNG:
|
||||
return ("SAMSUNG");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_SANYO
|
||||
case SANYO:
|
||||
return ("SANYO");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_SHARP
|
||||
case SHARP:
|
||||
return ("SHARP");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_SHARP_ALT
|
||||
case SHARP_ALT:
|
||||
return ("SHARP_ALT");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_SONY
|
||||
case SONY:
|
||||
return ("SONY");
|
||||
break;
|
||||
#endif
|
||||
#if DECODE_WHYNTER
|
||||
case WHYNTER:
|
||||
return ("WHYNTER");
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void IRrecv::printResultShort(Print * aSerial) {
|
||||
aSerial->print(F("Protocol="));
|
||||
aSerial->print(getProtocolString());
|
||||
aSerial->print(F(" Data=0x"));
|
||||
aSerial->print(results.value, HEX);
|
||||
if (results.isRepeat) {
|
||||
aSerial->print(F(" R"));
|
||||
}
|
||||
if (results.address != 0) {
|
||||
aSerial->print(F(" Address=0x"));
|
||||
aSerial->print(results.address, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DEPRECATED
|
||||
* With parameter aResults for backwards compatibility
|
||||
* Contains no new (since 5/2020) protocols.
|
||||
*/
|
||||
bool IRrecv::decode(decode_results *aResults) {
|
||||
if (irparams.rcvstate != IR_REC_STATE_STOP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* First copy 3 values from irparams to internal results structure
|
||||
*/
|
||||
results.rawbuf = irparams.rawbuf;
|
||||
results.rawlen = irparams.rawlen;
|
||||
results.overflow = irparams.overflow;
|
||||
|
||||
// reset optional values
|
||||
results.address = 0;
|
||||
results.isRepeat = false;
|
||||
|
||||
#if DECODE_NEC
|
||||
DBG_PRINTLN("Attempting NEC decode");
|
||||
if (decodeNEC(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SHARP
|
||||
DBG_PRINTLN("Attempting Sharp decode");
|
||||
if (decodeSharp(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SHARP_ALT
|
||||
DBG_PRINTLN("Attempting SharpAlt decode");
|
||||
if (decodeSharpAlt(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SONY
|
||||
DBG_PRINTLN("Attempting Sony decode");
|
||||
if (decodeSony(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SANYO
|
||||
DBG_PRINTLN("Attempting Sanyo decode");
|
||||
if (decodeSanyo(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_MITSUBISHI
|
||||
DBG_PRINTLN("Attempting Mitsubishi decode");
|
||||
if (decodeMitsubishi(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_RC5
|
||||
DBG_PRINTLN("Attempting RC5 decode");
|
||||
if (decodeRC5(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_RC6
|
||||
DBG_PRINTLN("Attempting RC6 decode");
|
||||
if (decodeRC6(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_PANASONIC
|
||||
DBG_PRINTLN("Attempting Panasonic decode");
|
||||
if (decodePanasonic(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_LG
|
||||
DBG_PRINTLN("Attempting LG decode");
|
||||
if (decodeLG(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_JVC
|
||||
DBG_PRINTLN("Attempting JVC decode");
|
||||
if (decodeJVC(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_SAMSUNG
|
||||
DBG_PRINTLN("Attempting SAMSUNG decode");
|
||||
if (decodeSAMSUNG(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_WHYNTER
|
||||
DBG_PRINTLN("Attempting Whynter decode");
|
||||
if (decodeWhynter(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_AIWA_RC_T501
|
||||
DBG_PRINTLN("Attempting Aiwa RC-T501 decode");
|
||||
if (decodeAiwaRCT501(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_DENON
|
||||
DBG_PRINTLN("Attempting Denon decode");
|
||||
if (decodeDenon(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DECODE_LEGO_PF
|
||||
DBG_PRINTLN("Attempting Lego Power Functions");
|
||||
if (decodeLegoPowerFunctions(aResults)) {
|
||||
return true ;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DECODE_HASH)
|
||||
DBG_PRINTLN("Hash decode");
|
||||
// decodeHash returns a hash on any input.
|
||||
// Thus, it needs to be last in the list.
|
||||
// If you add any decodes, add them before this.
|
||||
if (decodeHash(aResults)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throw away and start over
|
||||
resume();
|
||||
return false;
|
||||
}
|
||||
206
trunk/Arduino/libraries/IRremote/src/irSend.cpp
Normal file
206
trunk/Arduino/libraries/IRremote/src/irSend.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
#ifdef SENDING_SUPPORTED // from IRremoteBoardDefs.h
|
||||
//+=============================================================================
|
||||
void IRsend::sendRaw(const unsigned int buf[], unsigned int len, unsigned int hz) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(hz);
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
if (i & 1) {
|
||||
space(buf[i]);
|
||||
} else {
|
||||
mark(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
|
||||
void IRsend::sendRaw_P(const unsigned int buf[], unsigned int len, unsigned int hz) {
|
||||
#if !defined(__AVR__)
|
||||
sendRaw(buf,len,hz); // Let the function work for non AVR platforms
|
||||
#else
|
||||
// Set IR carrier frequency
|
||||
enableIROut(hz);
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
uint16_t duration = pgm_read_word_near(buf + sizeof(uint16_t) * i);
|
||||
if (i & 1) {
|
||||
space(duration);
|
||||
} else {
|
||||
mark(duration);
|
||||
}
|
||||
}
|
||||
space(0); // Always end with the LED off
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef USE_SOFT_SEND_PWM
|
||||
void inline IRsend::sleepMicros(unsigned long us) {
|
||||
#ifdef USE_SPIN_WAIT
|
||||
sleepUntilMicros(micros() + us);
|
||||
#else
|
||||
if (us > 0U) { // Is this necessary? (Official docu https://www.arduino.cc/en/Reference/DelayMicroseconds does not tell.)
|
||||
delayMicroseconds((unsigned int) us);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void inline IRsend::sleepUntilMicros(unsigned long targetTime) {
|
||||
#ifdef USE_SPIN_WAIT
|
||||
while (micros() < targetTime)
|
||||
;
|
||||
#else
|
||||
unsigned long now = micros();
|
||||
if (now < targetTime) {
|
||||
sleepMicros(targetTime - now);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // USE_SOFT_SEND_PWM
|
||||
|
||||
//+=============================================================================
|
||||
// Sends PulseDistance data from MSB to LSB
|
||||
//
|
||||
void IRsend::sendPulseDistanceWidthData(unsigned int aOneMarkMicros, unsigned int aOneSpaceMicros, unsigned int aZeroMarkMicros,
|
||||
unsigned int aZeroSpaceMicros, unsigned long aData, uint8_t aNumberOfBits, bool aMSBfirst) {
|
||||
|
||||
if (aMSBfirst) { // Send the MSB first.
|
||||
// send data from MSB to LSB until mask bit is shifted out
|
||||
for (unsigned long mask = 1UL << (aNumberOfBits - 1); mask; mask >>= 1) {
|
||||
if (aData & mask) {
|
||||
DBG_PRINT("1");
|
||||
mark(aOneMarkMicros);
|
||||
space(aOneSpaceMicros);
|
||||
} else {
|
||||
DBG_PRINT("0");
|
||||
mark(aZeroMarkMicros);
|
||||
space(aZeroSpaceMicros);
|
||||
}
|
||||
}
|
||||
DBG_PRINTLN("");
|
||||
}
|
||||
#if defined(LSB_FIRST_REQUIRED)
|
||||
else { // Send the Least Significant Bit (LSB) first / MSB last.
|
||||
for (uint16_t bit = 0; bit < aNumberOfBits; bit++, aData >>= 1)
|
||||
if (aData & 1) { // Send a 1
|
||||
DBG_PRINT("1");
|
||||
mark(aOneMarkMicros);
|
||||
space(aOneSpaceMicros);
|
||||
} else { // Send a 0
|
||||
DBG_PRINT("0");
|
||||
mark(aZeroMarkMicros);
|
||||
space(aZeroSpaceMicros);
|
||||
}
|
||||
DBG_PRINTLN("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Sends an IR mark for the specified number of microseconds.
|
||||
// The mark output is modulated at the PWM frequency.
|
||||
//
|
||||
|
||||
void IRsend::mark(unsigned int time) {
|
||||
#ifdef USE_SOFT_SEND_PWM
|
||||
unsigned long start = micros();
|
||||
unsigned long stop = start + time;
|
||||
if (stop + periodTimeMicros < start) {
|
||||
// Counter wrap-around, happens very seldomly, but CAN happen.
|
||||
// Just give up instead of possibly damaging the hardware.
|
||||
return;
|
||||
}
|
||||
unsigned long nextPeriodEnding = start;
|
||||
unsigned long now = micros();
|
||||
while (now < stop) {
|
||||
SENDPIN_ON(sendPin);
|
||||
sleepMicros (periodOnTimeMicros);
|
||||
SENDPIN_OFF(sendPin);
|
||||
nextPeriodEnding += periodTimeMicros;
|
||||
sleepUntilMicros(nextPeriodEnding);
|
||||
now = micros();
|
||||
}
|
||||
#elif defined(USE_NO_SEND_PWM)
|
||||
digitalWrite(sendPin, LOW); // Set output to active low.
|
||||
#else
|
||||
TIMER_ENABLE_SEND_PWM; // Enable pin 3 PWM output
|
||||
#endif
|
||||
if (time > 0) {
|
||||
custom_delay_usec(time);
|
||||
}
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// Leave pin off for time (given in microseconds)
|
||||
// Sends an IR space for the specified number of microseconds.
|
||||
// A space is no output, so the PWM output is disabled.
|
||||
//
|
||||
void IRsend::space(unsigned int time) {
|
||||
#if defined(USE_NO_SEND_PWM)
|
||||
digitalWrite(sendPin, HIGH); // Set output to inactive high.
|
||||
#else
|
||||
TIMER_DISABLE_SEND_PWM; // Disable pin 3 PWM output
|
||||
#endif
|
||||
if (time > 0) {
|
||||
IRsend::custom_delay_usec(time);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_DEFAULT_ENABLE_IR_OUT
|
||||
//+=============================================================================
|
||||
// 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.
|
||||
//
|
||||
void IRsend::enableIROut(int khz) {
|
||||
#ifdef USE_SOFT_SEND_PWM
|
||||
periodTimeMicros = (1000U + khz / 2) / khz; // = 1000/khz + 1/2 = round(1000.0/khz)
|
||||
periodOnTimeMicros = periodTimeMicros * IR_SEND_DUTY_CYCLE / 100U - PULSE_CORRECTION_MICROS;
|
||||
#endif
|
||||
|
||||
#if defined(USE_NO_SEND_PWM)
|
||||
pinMode(sendPin, OUTPUT);
|
||||
digitalWrite(sendPin, HIGH); // Set output to inactive high.
|
||||
#else
|
||||
// Disable the Timer2 Interrupt (which is used for receiving IR)
|
||||
TIMER_DISABLE_RECEIVE_INTR; //Timer2 Overflow Interrupt
|
||||
|
||||
pinMode(sendPin, OUTPUT);
|
||||
|
||||
SENDPIN_OFF(sendPin); // When not sending, we want it low
|
||||
|
||||
timerConfigForSend(khz);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
// Custom delay function that circumvents Arduino's delayMicroseconds limit
|
||||
|
||||
void IRsend::custom_delay_usec(unsigned long uSecs) {
|
||||
if (uSecs > 4) {
|
||||
unsigned long start = micros();
|
||||
unsigned long endMicros = start + uSecs - 4;
|
||||
if (endMicros < start) { // Check if overflow
|
||||
while (micros() > start) {
|
||||
} // wait until overflow
|
||||
}
|
||||
while (micros() < endMicros) {
|
||||
} // normal wait
|
||||
}
|
||||
//else {
|
||||
// __asm__("nop\n\t"); // must have or compiler optimizes out
|
||||
//}
|
||||
}
|
||||
|
||||
#endif // SENDING_SUPPORTED
|
||||
129
trunk/Arduino/libraries/IRremote/src/ir_Aiwa.cpp
Normal file
129
trunk/Arduino/libraries/IRremote/src/ir_Aiwa.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// AAA IIIII W W AAA
|
||||
// A A I W W A A
|
||||
// AAAAA I W W W AAAAA
|
||||
// A A I W W W A A
|
||||
// A A IIIII WWW A A
|
||||
//==============================================================================
|
||||
|
||||
// Based off the RC-T501 RCU
|
||||
// Lirc file http://lirc.sourceforge.net/remotes/aiwa/RC-T501
|
||||
|
||||
#define AIWA_RC_T501_HZ 38
|
||||
#define AIWA_RC_T501_BITS 15
|
||||
#define AIWA_RC_T501_PRE_BITS 26
|
||||
#define AIWA_RC_T501_POST_BITS 1
|
||||
#define AIWA_RC_T501_SUM_BITS (AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_BITS + AIWA_RC_T501_POST_BITS)
|
||||
#define AIWA_RC_T501_HEADER_MARK 8800
|
||||
#define AIWA_RC_T501_HEADER_SPACE 4500
|
||||
#define AIWA_RC_T501_BIT_MARK 500
|
||||
#define AIWA_RC_T501_ONE_SPACE 600
|
||||
#define AIWA_RC_T501_ZERO_SPACE 1700
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_AIWA_RC_T501
|
||||
void IRsend::sendAiwaRCT501(int code) {
|
||||
unsigned long pre = 0x0227EEC0; // 26-bits
|
||||
|
||||
// Set IR carrier frequency
|
||||
enableIROut(AIWA_RC_T501_HZ);
|
||||
|
||||
// Header
|
||||
mark(AIWA_RC_T501_HEADER_MARK);
|
||||
space(AIWA_RC_T501_HEADER_SPACE);
|
||||
|
||||
// Send "pre" data
|
||||
for (unsigned long mask = 1UL << (26 - 1); mask; mask >>= 1) {
|
||||
mark(AIWA_RC_T501_BIT_MARK);
|
||||
if (pre & mask)
|
||||
space(AIWA_RC_T501_ONE_SPACE);
|
||||
else
|
||||
space(AIWA_RC_T501_ZERO_SPACE);
|
||||
}
|
||||
|
||||
//-v- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK!
|
||||
// it only send 15bits and ignores the top bit
|
||||
// then uses TOPBIT which is 0x80000000 to check the bit code
|
||||
// I suspect TOPBIT should be changed to 0x00008000
|
||||
|
||||
// Skip first code bit
|
||||
code <<= 1;
|
||||
// Send code
|
||||
for (int i = 0; i < 15; i++) {
|
||||
mark(AIWA_RC_T501_BIT_MARK);
|
||||
if (code & 0x80000000)
|
||||
space(AIWA_RC_T501_ONE_SPACE);
|
||||
else
|
||||
space(AIWA_RC_T501_ZERO_SPACE);
|
||||
code <<= 1;
|
||||
}
|
||||
|
||||
//-^- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK!
|
||||
|
||||
// POST-DATA, 1 bit, 0x0
|
||||
mark(AIWA_RC_T501_BIT_MARK);
|
||||
space(AIWA_RC_T501_ZERO_SPACE);
|
||||
|
||||
mark(AIWA_RC_T501_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_AIWA_RC_T501
|
||||
bool IRrecv::decodeAiwaRCT501() {
|
||||
int data = 0;
|
||||
unsigned int offset = 1;
|
||||
|
||||
// Check SIZE
|
||||
if (results.rawlen < 2 * (AIWA_RC_T501_SUM_BITS) + 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check HDR Mark/Space
|
||||
if (!MATCH_MARK(results.rawbuf[offset], AIWA_RC_T501_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], AIWA_RC_T501_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
offset += 26; // skip pre-data - optional
|
||||
while (offset < results.rawlen - 4) {
|
||||
if (MATCH_MARK(results.rawbuf[offset], AIWA_RC_T501_BIT_MARK)) {
|
||||
offset++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ONE & ZERO
|
||||
if (MATCH_SPACE(results.rawbuf[offset], AIWA_RC_T501_ONE_SPACE)) {
|
||||
data = (data << 1) | 1;
|
||||
} else if (MATCH_SPACE(results.rawbuf[offset], AIWA_RC_T501_ZERO_SPACE)) {
|
||||
data = (data << 1) | 0;
|
||||
} else {
|
||||
break; // End of one & zero detected
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
results.bits = (offset - 1) / 2;
|
||||
if (results.bits < 42) {
|
||||
return false;
|
||||
}
|
||||
|
||||
results.value = data;
|
||||
results.decode_type = AIWA_RC_T501;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeAiwaRCT501(decode_results *aResults) {
|
||||
bool aReturnValue = decodeAiwaRCT501();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
222
trunk/Arduino/libraries/IRremote/src/ir_BoseWave.cpp
Normal file
222
trunk/Arduino/libraries/IRremote/src/ir_BoseWave.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// BBBB OOO SSSS EEEEE
|
||||
// B B O O S E
|
||||
// BB B O O SSS EEEE
|
||||
// B B O O S E
|
||||
// BBBB OOO SSSS EEEEE
|
||||
//==============================================================================
|
||||
//
|
||||
// Bose Wave Radio CD Remote Control
|
||||
// |-------------------------------------|
|
||||
// | On/Off Sleep VolUp |
|
||||
// | Play/Pause Stop VolDown |
|
||||
// | FM AM Aux |
|
||||
// | Tune Down Tune Up Mute |
|
||||
// | 1 2 3 |
|
||||
// | 4 5 6 |
|
||||
// |-------------------------------------|
|
||||
//
|
||||
// Support for Bose Wave Radio CD provided by https://github.com/uvotguy.
|
||||
//
|
||||
// This protocol was reverse engineered by capturing IR signals from a working
|
||||
// remote. Multiple signals were captured on my oscilloscope, and the timing
|
||||
// values were averaged.
|
||||
//
|
||||
// IR codes are 8 bits. Transmission starts with a header: a mark and a space.
|
||||
// The header is followed by an 8-bit command, where a bit is a mark and a short
|
||||
// space (1) or a long space (0). The command is followed by the complement of
|
||||
// the command (8 bits). A transmission ends with a short mark.
|
||||
//
|
||||
// As seen on my trusty oscilloscope, there is no repeat code. Instead, when I
|
||||
// press and hold a button on my remote, it sends a command, makes a 51.2ms space,
|
||||
// and resends the command, etc, etc.
|
||||
//
|
||||
// It may be worth noting that these values do NOT match those in the LIRC
|
||||
// remote database (http://lirc.sourceforge.net/remotes/bose/).
|
||||
|
||||
#define CMD_ON_OFF 0xff
|
||||
#define CMD_MUTE 0xfe
|
||||
#define CMD_VOL_UP 0xfd
|
||||
#define CMD_VOL_DOWN 0xfc
|
||||
#define CMD_PRESET_6 0xfb
|
||||
#define CMD_SLEEP 0xfa
|
||||
#define CMD_FM 0xf9
|
||||
#define CMD_AUX 0xf8
|
||||
#define CMD_AM 0xf7
|
||||
#define CMD_PLAY_PAUSE 0xf6
|
||||
#define CMD_STOP 0xf5
|
||||
#define CMD_TUNE_UP 0xf4
|
||||
#define CMD_TUNE_DOWN 0xf3
|
||||
#define CMD_PRESET_1 0xf2
|
||||
#define CMD_PRESET_2 0xf1
|
||||
#define CMD_PRESET_3 0xf0
|
||||
#define CMD_PRESET_4 0xef
|
||||
#define CMD_PRESET_5 0xee
|
||||
|
||||
#define BOSEWAVE_BITS 8
|
||||
#define BOSEWAVE_HEADER_MARK 1061
|
||||
#define BOSEWAVE_HEADER_SPACE 1456
|
||||
#define BOSEWAVE_BIT_MARK 534
|
||||
#define BOSEWAVE_ONE_SPACE 468
|
||||
#define BOSEWAVE_ZERO_SPACE 1447
|
||||
#define BOSEWAVE_END_MARK 614
|
||||
#define BOSEWAVE_REPEAT_SPACE 51200
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_BOSEWAVE
|
||||
unsigned int rawSignal[35];
|
||||
void IRsend::sendBoseWave(unsigned char code) {
|
||||
|
||||
int index = 0;
|
||||
// Header
|
||||
rawSignal[index++] = BOSEWAVE_HEADER_MARK;
|
||||
rawSignal[index++] = BOSEWAVE_HEADER_SPACE;
|
||||
|
||||
// 8 bit command
|
||||
for (unsigned char mask = 0x80; mask; mask >>= 1) {
|
||||
rawSignal[index++] = BOSEWAVE_BIT_MARK;
|
||||
if (code & mask) {
|
||||
rawSignal[index++] = BOSEWAVE_ONE_SPACE;
|
||||
} else {
|
||||
rawSignal[index++] = BOSEWAVE_ZERO_SPACE;
|
||||
}
|
||||
}
|
||||
|
||||
// 8 bit command complement
|
||||
for (unsigned char mask = 0x80; mask; mask >>= 1) {
|
||||
rawSignal[index++] = BOSEWAVE_BIT_MARK;
|
||||
if (code & mask) {
|
||||
rawSignal[index++] = BOSEWAVE_ZERO_SPACE;
|
||||
} else {
|
||||
rawSignal[index++] = BOSEWAVE_ONE_SPACE;
|
||||
}
|
||||
}
|
||||
// End transmission
|
||||
rawSignal[index++] = BOSEWAVE_END_MARK;
|
||||
|
||||
// Transmit
|
||||
this->sendRaw(rawSignal, 35, 38);
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_BOSEWAVE
|
||||
bool IRrecv::decodeBoseWave() {
|
||||
unsigned char command = 0; // Decoded command
|
||||
unsigned char complement = 0; // Decoded command complement
|
||||
|
||||
int index = 0; // Index in to results array
|
||||
|
||||
DBG_PRINTLN("Decoding Bose Wave ...");
|
||||
|
||||
// Check we have enough data
|
||||
if (irparams.rawlen < (2 * BOSEWAVE_BITS * 2) + 3) {
|
||||
DBG_PRINT("\tInvalid data length found: ");
|
||||
DBG_PRINTLN(results.rawlen);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check header "mark"
|
||||
index = 1;
|
||||
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_HEADER_MARK)) {
|
||||
DBG_PRINT("\tInvalid Header Mark. Expecting ");
|
||||
DBG_PRINT(BOSEWAVE_HEADER_MARK);
|
||||
DBG_PRINT(". Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Check header "space"
|
||||
if (!MATCH_SPACE(results.rawbuf[index], BOSEWAVE_HEADER_SPACE)) {
|
||||
DBG_PRINT("\tInvalid Header Space. Expecting ");
|
||||
DBG_PRINT(BOSEWAVE_HEADER_SPACE);
|
||||
DBG_PRINT(". Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Decode the data bits
|
||||
for (int ii = 7; ii >= 0; ii--) {
|
||||
// Check bit "mark". Mark is always the same length.
|
||||
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_BIT_MARK)) {
|
||||
DBG_PRINT("\tInvalid command Mark. Expecting ");
|
||||
DBG_PRINT(BOSEWAVE_BIT_MARK);
|
||||
DBG_PRINT(". Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Check bit "space"
|
||||
if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ONE_SPACE)) {
|
||||
command |= (0x01 << ii);
|
||||
} else if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ZERO_SPACE)) {
|
||||
// Nothing to do for zeroes.
|
||||
} else {
|
||||
DBG_PRINT("\tInvalid command Space. Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// Decode the command complement bits. We decode it here as the complement
|
||||
// of the complement (0=1 and 1=0) so we can easily compare it to the command.
|
||||
for (int ii = 7; ii >= 0; ii--) {
|
||||
// Check bit "mark". Mark is always the same length.
|
||||
if (!MATCH_MARK(results.rawbuf[index], BOSEWAVE_BIT_MARK)) {
|
||||
DBG_PRINT("\tInvalid complement Mark. Expecting ");
|
||||
DBG_PRINT(BOSEWAVE_BIT_MARK);
|
||||
DBG_PRINT(". Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Check bit "space"
|
||||
if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ONE_SPACE)) {
|
||||
// Nothing to do.
|
||||
} else if (MATCH_SPACE(results.rawbuf[index], BOSEWAVE_ZERO_SPACE)) {
|
||||
complement |= (0x01 << ii);
|
||||
} else {
|
||||
DBG_PRINT("\tInvalid complement Space. Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (command != complement) {
|
||||
DBG_PRINT("\tComplement is not correct. Command=0x");
|
||||
DBG_PRINT(command, HEX);
|
||||
DBG_PRINT(" Complement=0x");
|
||||
DBG_PRINTLN(complement, HEX);
|
||||
return false;
|
||||
} else {
|
||||
DBG_PRINTLN("\tValid command");
|
||||
}
|
||||
|
||||
// Check end "mark"
|
||||
if (MATCH_MARK(results.rawbuf[index], BOSEWAVE_END_MARK) == 0) {
|
||||
DBG_PRINT("\tInvalid end Mark. Got ");
|
||||
DBG_PRINTLN(results.rawbuf[index] * MICROS_PER_TICK);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = BOSEWAVE_BITS;
|
||||
results.value = command;
|
||||
results.decode_type = BOSEWAVE;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeBoseWave(decode_results *aResults) {
|
||||
bool aReturnValue = decodeBoseWave();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
114
trunk/Arduino/libraries/IRremote/src/ir_Denon.cpp
Normal file
114
trunk/Arduino/libraries/IRremote/src/ir_Denon.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
// Reverse Engineered by looking at RAW dumps generated by IRremote
|
||||
|
||||
// I have since discovered that Denon publish all their IR codes:
|
||||
// https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet
|
||||
// -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
|
||||
|
||||
// Having looked at the official Denon Pronto sheet and reverse engineered
|
||||
// the timing values from it, it is obvious that Denon have a range of
|
||||
// different timings and protocols ...the values here work for my AVR-3801 Amp!
|
||||
|
||||
//==============================================================================
|
||||
// DDDD EEEEE N N OOO N N
|
||||
// D D E NN N O O NN N
|
||||
// D D EEE N N N O O N N N
|
||||
// D D E N NN O O N NN
|
||||
// DDDD EEEEE N N OOO N N
|
||||
//==============================================================================
|
||||
|
||||
#define DENON_BITS 14 // The number of bits in the command
|
||||
|
||||
#define DENON_HEADER_MARK 300 // The length of the Header:Mark
|
||||
#define DENON_HEADER_SPACE 750 // The lenght of the Header:Space
|
||||
|
||||
#define DENON_BIT_MARK 300 // The length of a Bit:Mark
|
||||
#define DENON_ONE_SPACE 1800 // The length of a Bit:Space for 1's
|
||||
#define DENON_ZERO_SPACE 750 // The length of a Bit:Space for 0's
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if SEND_DENON
|
||||
void IRsend::sendDenon(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Header
|
||||
mark(DENON_HEADER_MARK);
|
||||
space(DENON_HEADER_SPACE);
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(DENON_BIT_MARK, DENON_ONE_SPACE, DENON_BIT_MARK, DENON_ZERO_SPACE, data, nbits);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark(DENON_BIT_MARK);
|
||||
// space(DENON_ONE_SPACE);
|
||||
// } else {
|
||||
// mark(DENON_BIT_MARK);
|
||||
// space(DENON_ZERO_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Footer
|
||||
mark(DENON_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if DECODE_DENON
|
||||
bool IRrecv::decodeDenon() {
|
||||
unsigned long data = 0; // Somewhere to build our code
|
||||
int offset = 1; // Skip the gap reading
|
||||
|
||||
// Check we have the right amount of data
|
||||
if (irparams.rawlen != 1 + 2 + (2 * DENON_BITS) + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check initial Mark+Space match
|
||||
if (!MATCH_MARK(results.rawbuf[offset], DENON_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], DENON_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Read the bits in
|
||||
data = decodePulseDistanceData(DENON_BITS, offset, DENON_BIT_MARK, DENON_ONE_SPACE, DENON_ZERO_SPACE);
|
||||
// for (int i = 0; i < DENON_BITS; i++) {
|
||||
// // Each bit looks like: MARK + SPACE_1 -> 1
|
||||
// // or : MARK + SPACE_0 -> 0
|
||||
// if (!MATCH_MARK(results.rawbuf[offset], DENON_BIT_MARK)) {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
//
|
||||
// // IR data is big-endian, so we shuffle it in from the right:
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], DENON_ONE_SPACE)) {
|
||||
// data = (data << 1) | 1;
|
||||
// } else if (MATCH_SPACE(results.rawbuf[offset], DENON_ZERO_SPACE)) {
|
||||
// data = (data << 1) | 0;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
// }
|
||||
|
||||
// Success
|
||||
results.bits = DENON_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = DENON;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeDenon(decode_results *aResults) {
|
||||
bool aReturnValue = decodeDenon();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
55
trunk/Arduino/libraries/IRremote/src/ir_Dish.cpp
Normal file
55
trunk/Arduino/libraries/IRremote/src/ir_Dish.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// DDDD IIIII SSSS H H
|
||||
// D D I S H H
|
||||
// D D I SSS HHHHH
|
||||
// D D I S H H
|
||||
// DDDD IIIII SSSS H H
|
||||
//==============================================================================
|
||||
|
||||
// Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
|
||||
//
|
||||
// The send function needs to be repeated 4 times
|
||||
//
|
||||
// Only send the last for characters of the hex.
|
||||
// I.E. Use 0x1C10 instead of 0x0000000000001C10 as listed in the LIRC file.
|
||||
//
|
||||
// Here is the LIRC file I found that seems to match the remote codes from the
|
||||
// oscilloscope:
|
||||
// DISH NETWORK (echostar 301):
|
||||
// http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
|
||||
|
||||
#define DISH_BITS 16
|
||||
#define DISH_HEADER_MARK 400
|
||||
#define DISH_HEADER_SPACE 6100
|
||||
#define DISH_BIT_MARK 400
|
||||
#define DISH_ONE_SPACE 1700
|
||||
#define DISH_ZERO_SPACE 2800
|
||||
#define DISH_REPEAT_SPACE 6200
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_DISH
|
||||
void IRsend::sendDISH(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(56);
|
||||
|
||||
mark(DISH_HEADER_MARK);
|
||||
space(DISH_HEADER_SPACE);
|
||||
|
||||
sendPulseDistanceWidthData(DISH_BIT_MARK, DISH_ONE_SPACE, DISH_BIT_MARK, DISH_ZERO_SPACE, data, nbits);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark(DISH_BIT_MARK);
|
||||
// space(DISH_ONE_SPACE);
|
||||
// } else {
|
||||
// mark(DISH_BIT_MARK);
|
||||
// space(DISH_ZERO_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
mark(DISH_HEADER_MARK); //added 26th March 2016, by AnalysIR ( https://www.AnalysIR.com )
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
99
trunk/Arduino/libraries/IRremote/src/ir_JVC.cpp
Normal file
99
trunk/Arduino/libraries/IRremote/src/ir_JVC.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// JJJJJ V V CCCC
|
||||
// J V V C
|
||||
// J V V C
|
||||
// J J V V C
|
||||
// J V CCCC
|
||||
//==============================================================================
|
||||
|
||||
#define JVC_BITS 16
|
||||
#define JVC_HEADER_MARK 8400
|
||||
#define JVC_HEADER_SPACE 4200
|
||||
#define JVC_BIT_MARK 600
|
||||
#define JVC_ONE_SPACE 1600
|
||||
#define JVC_ZERO_SPACE 550
|
||||
#define JVC_REPEAT_SPACE 50000
|
||||
|
||||
//+=============================================================================
|
||||
// JVC does NOT repeat by sending a separate code (like NEC does).
|
||||
// The JVC protocol repeats by skipping the header.
|
||||
// To send a JVC repeat signal, send the original code value
|
||||
// and set 'repeat' to true
|
||||
//
|
||||
// JVC commands sometimes need to be sent two or three times with 40 to 60 ms pause in between.
|
||||
//
|
||||
#if SEND_JVC
|
||||
void IRsend::sendJVC(unsigned long data, int nbits, bool repeat) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Only send the Header if this is NOT a repeat command
|
||||
if (!repeat) {
|
||||
mark(JVC_HEADER_MARK);
|
||||
space(JVC_HEADER_SPACE);
|
||||
}
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(JVC_BIT_MARK, JVC_ONE_SPACE, JVC_BIT_MARK, JVC_ZERO_SPACE, data, nbits);
|
||||
|
||||
// Footer
|
||||
mark(JVC_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_JVC
|
||||
bool IRrecv::decodeJVC() {
|
||||
long data = 0;
|
||||
int offset = 1; // Skip first space
|
||||
|
||||
// Check for repeat
|
||||
if ((results.rawlen - 1 == 33) && MATCH_MARK(results.rawbuf[offset], JVC_BIT_MARK)
|
||||
&& MATCH_MARK(results.rawbuf[results.rawlen - 1], JVC_BIT_MARK)) {
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = JVC;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initial mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], JVC_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (results.rawlen < (2 * JVC_BITS) + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initial space
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], JVC_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(JVC_BITS, offset, JVC_BIT_MARK, JVC_ONE_SPACE, JVC_ZERO_SPACE);
|
||||
|
||||
// Stop bit
|
||||
if (!MATCH_MARK(results.rawbuf[offset], JVC_BIT_MARK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = JVC_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = JVC;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeJVC(decode_results *aResults) {
|
||||
bool aReturnValue = decodeJVC();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
102
trunk/Arduino/libraries/IRremote/src/ir_LG.cpp
Normal file
102
trunk/Arduino/libraries/IRremote/src/ir_LG.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// L GGGG
|
||||
// L G
|
||||
// L G GG
|
||||
// L G G
|
||||
// LLLLL GGG
|
||||
//==============================================================================
|
||||
|
||||
#define LG_BITS 28
|
||||
|
||||
#define LG_HEADER_MARK 8400
|
||||
#define LG_HEADER_SPACE 4200
|
||||
#define LG_BIT_MARK 600
|
||||
#define LG_ONE_SPACE 1600
|
||||
#define LG_ZERO_SPACE 550
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_LG
|
||||
bool IRrecv::decodeLG() {
|
||||
long data = 0;
|
||||
int offset = 1; // Skip first space
|
||||
|
||||
// Check we have the right amount of data
|
||||
if (irparams.rawlen < (2 * LG_BITS) + 1)
|
||||
return false;
|
||||
|
||||
// Initial mark/space
|
||||
if (!MATCH_MARK(results.rawbuf[offset], LG_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], LG_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(LG_BITS, offset, LG_BIT_MARK, LG_ONE_SPACE, LG_ZERO_SPACE);
|
||||
// for (int i = 0; i < LG_BITS; i++) {
|
||||
// if (!MATCH_MARK(results.rawbuf[offset], LG_BIT_MARK)) {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
//
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], LG_ONE_SPACE)) {
|
||||
// data = (data << 1) | 1;
|
||||
// } else if (MATCH_SPACE(results.rawbuf[offset], LG_ZERO_SPACE)) {
|
||||
// data = (data << 1) | 0;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
// }
|
||||
|
||||
// Stop bit
|
||||
if (!MATCH_MARK(results.rawbuf[offset], LG_BIT_MARK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = LG_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = LG;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeLG(decode_results *aResults) {
|
||||
bool aReturnValue = decodeLG();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_LG
|
||||
void IRsend::sendLG(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Header
|
||||
mark(LG_HEADER_MARK);
|
||||
space(LG_HEADER_SPACE);
|
||||
// mark(LG_BIT_MARK);
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(LG_BIT_MARK, LG_ONE_SPACE, LG_BIT_MARK, LG_ZERO_SPACE, data, nbits);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// space(LG_ONE_SPACE);
|
||||
// mark(LG_BIT_MARK);
|
||||
// } else {
|
||||
// space(LG_ZERO_SPACE);
|
||||
// mark(LG_BIT_MARK);
|
||||
// }
|
||||
// }
|
||||
|
||||
mark(LG_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
44
trunk/Arduino/libraries/IRremote/src/ir_Lego_PF.cpp
Normal file
44
trunk/Arduino/libraries/IRremote/src/ir_Lego_PF.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "IRremote.h"
|
||||
#include "ir_Lego_PF_BitStreamEncoder.h"
|
||||
|
||||
//==============================================================================
|
||||
// L EEEEEE EEEE OOOO
|
||||
// L E E O O
|
||||
// L EEEE E EEE O O
|
||||
// L E E E O O LEGO Power Functions
|
||||
// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel
|
||||
//==============================================================================
|
||||
|
||||
// Supported Devices
|
||||
// LEGO® Power Functions IR Receiver 8884
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if SEND_LEGO_PF
|
||||
|
||||
#if DEBUG
|
||||
namespace {
|
||||
void logFunctionParameters(uint16_t data, bool repeat) {
|
||||
DBG_PRINT("sendLegoPowerFunctions(data=");
|
||||
DBG_PRINT(data);
|
||||
DBG_PRINT(", repeat=");
|
||||
DBG_PRINTLN(repeat?"true)" : "false)");
|
||||
}
|
||||
} // anonymous namespace
|
||||
#endif // DEBUG
|
||||
|
||||
void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat) {
|
||||
#if DEBUG
|
||||
::logFunctionParameters(data, repeat);
|
||||
#endif // DEBUG
|
||||
|
||||
enableIROut(38);
|
||||
static LegoPfBitStreamEncoder bitStreamEncoder;
|
||||
bitStreamEncoder.reset(data, repeat);
|
||||
do {
|
||||
mark(bitStreamEncoder.getMarkDuration());
|
||||
space(bitStreamEncoder.getPauseDuration());
|
||||
} while (bitStreamEncoder.next());
|
||||
}
|
||||
|
||||
#endif // SEND_LEGO_PF
|
||||
@@ -0,0 +1,117 @@
|
||||
//==============================================================================
|
||||
// L EEEEEE EEEE OOOO
|
||||
// L E E O O
|
||||
// L EEEE E EEE O O
|
||||
// L E E E O O LEGO Power Functions
|
||||
// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016, 2017 Philipp Henkel
|
||||
//==============================================================================
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
|
||||
class LegoPfBitStreamEncoder {
|
||||
private:
|
||||
uint16_t data;
|
||||
bool repeatMessage;
|
||||
uint8_t messageBitIdx;
|
||||
uint8_t repeatCount;
|
||||
uint16_t messageLength;
|
||||
|
||||
public:
|
||||
// HIGH data bit = IR mark + high pause
|
||||
// LOW data bit = IR mark + low pause
|
||||
static const uint16_t LOW_BIT_DURATION = 421;
|
||||
static const uint16_t HIGH_BIT_DURATION = 711;
|
||||
static const uint16_t START_BIT_DURATION = 1184;
|
||||
static const uint16_t STOP_BIT_DURATION = 1184;
|
||||
static const uint8_t IR_MARK_DURATION = 158;
|
||||
static const uint16_t HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION;
|
||||
static const uint16_t LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION;
|
||||
static const uint16_t START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION;
|
||||
static const uint16_t STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION;
|
||||
static const uint8_t MESSAGE_BITS = 18;
|
||||
static const uint16_t MAX_MESSAGE_LENGTH = 16000;
|
||||
|
||||
void reset(uint16_t data, bool repeatMessage) {
|
||||
this->data = data;
|
||||
this->repeatMessage = repeatMessage;
|
||||
messageBitIdx = 0;
|
||||
repeatCount = 0;
|
||||
messageLength = getMessageLength();
|
||||
}
|
||||
|
||||
int getChannelId() const {
|
||||
return 1 + ((data >> 12) & 0x3);
|
||||
}
|
||||
|
||||
uint16_t getMessageLength() const {
|
||||
// Sum up all marks
|
||||
uint16_t length = MESSAGE_BITS * IR_MARK_DURATION;
|
||||
|
||||
// Sum up all pauses
|
||||
length += START_PAUSE_DURATION;
|
||||
for (unsigned long mask = 1UL << 15; mask; mask >>= 1) {
|
||||
if (data & mask) {
|
||||
length += HIGH_PAUSE_DURATION;
|
||||
} else {
|
||||
length += LOW_PAUSE_DURATION;
|
||||
}
|
||||
}
|
||||
length += STOP_PAUSE_DURATION;
|
||||
return length;
|
||||
}
|
||||
|
||||
boolean next() {
|
||||
messageBitIdx++;
|
||||
if (messageBitIdx >= MESSAGE_BITS) {
|
||||
repeatCount++;
|
||||
messageBitIdx = 0;
|
||||
}
|
||||
if (repeatCount >= 1 && !repeatMessage) {
|
||||
return false;
|
||||
} else if (repeatCount >= 5) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t getMarkDuration() const {
|
||||
return IR_MARK_DURATION;
|
||||
}
|
||||
|
||||
uint32_t getPauseDuration() const {
|
||||
if (messageBitIdx == 0)
|
||||
return START_PAUSE_DURATION;
|
||||
else if (messageBitIdx < MESSAGE_BITS - 1) {
|
||||
return getDataBitPause();
|
||||
} else {
|
||||
return getStopPause();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t getDataBitPause() const {
|
||||
const int pos = MESSAGE_BITS - 2 - messageBitIdx;
|
||||
const bool isHigh = data & (1 << pos);
|
||||
return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION;
|
||||
}
|
||||
|
||||
uint32_t getStopPause() const {
|
||||
if (repeatMessage) {
|
||||
return getRepeatStopPause();
|
||||
} else {
|
||||
return STOP_PAUSE_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getRepeatStopPause() const {
|
||||
if (repeatCount == 0 || repeatCount == 1) {
|
||||
return STOP_PAUSE_DURATION + (uint32_t) 5 * MAX_MESSAGE_LENGTH - messageLength;
|
||||
} else if (repeatCount == 2 || repeatCount == 3) {
|
||||
return STOP_PAUSE_DURATION + (uint32_t) (6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength;
|
||||
} else {
|
||||
return STOP_PAUSE_DURATION;
|
||||
}
|
||||
}
|
||||
};
|
||||
158
trunk/Arduino/libraries/IRremote/src/ir_MagiQuest.cpp
Normal file
158
trunk/Arduino/libraries/IRremote/src/ir_MagiQuest.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
// Based off the Magiquest fork of Arduino-IRremote by mpflaga
|
||||
// https://github.com/mpflaga/Arduino-IRremote/
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
//
|
||||
// M A G I Q U E S T
|
||||
//
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
// MagiQuest packet is both Wand ID and magnitude of swish and flick
|
||||
union magiquest_t {
|
||||
unsigned long long llword;
|
||||
struct {
|
||||
unsigned int magnitude;
|
||||
unsigned long wand_id;
|
||||
char padding;
|
||||
char scrap; // just to pad the struct out to 64 bits so we can union with llword
|
||||
} cmd;
|
||||
};
|
||||
|
||||
#define MAGIQUEST_BITS 50 // The number of bits in the command itself
|
||||
#define MAGIQUEST_PERIOD 1150 // Length of time a full MQ "bit" consumes (1100 - 1200 usec)
|
||||
/*
|
||||
* 0 = 25% mark & 75% space across 1 period
|
||||
* 1150 * 0.25 = 288 usec mark
|
||||
* 1150 - 288 = 862 usec space
|
||||
* 1 = 50% mark & 50% space across 1 period
|
||||
* 1150 * 0.5 = 575 usec mark
|
||||
* 1150 - 575 = 575 usec space
|
||||
*/
|
||||
#define MAGIQUEST_ONE_MARK 575
|
||||
#define MAGIQUEST_ONE_SPACE 575
|
||||
#define MAGIQUEST_ZERO_MARK 288
|
||||
#define MAGIQUEST_ZERO_SPACE 862
|
||||
|
||||
#define MAGIQUEST_MASK (1ULL << (MAGIQUEST_BITS-1))
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if SEND_MAGIQUEST
|
||||
void IRsend::sendMagiQuest(unsigned long wand_id, unsigned int magnitude) {
|
||||
magiquest_t data;
|
||||
|
||||
data.llword = 0;
|
||||
data.cmd.wand_id = wand_id;
|
||||
data.cmd.magnitude = magnitude;
|
||||
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Data
|
||||
for (unsigned long long mask = MAGIQUEST_MASK; mask > 0; mask >>= 1) {
|
||||
if (data.llword & mask) {
|
||||
DBG_PRINT("1");
|
||||
mark(MAGIQUEST_ONE_MARK);
|
||||
space(MAGIQUEST_ONE_SPACE);
|
||||
} else {
|
||||
DBG_PRINT("0");
|
||||
mark(MAGIQUEST_ZERO_MARK);
|
||||
space(MAGIQUEST_ZERO_SPACE);
|
||||
}
|
||||
}
|
||||
DBG_PRINTLN("");
|
||||
|
||||
// Footer
|
||||
mark(MAGIQUEST_ZERO_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if DECODE_MAGIQUEST
|
||||
bool IRrecv::decodeMagiQuest() {
|
||||
magiquest_t data; // Somewhere to build our code
|
||||
unsigned int offset = 1; // Skip the gap reading
|
||||
|
||||
unsigned int mark_;
|
||||
unsigned int space_;
|
||||
unsigned int ratio_;
|
||||
|
||||
#if DEBUG
|
||||
char bitstring[MAGIQUEST_BITS*2];
|
||||
memset(bitstring, 0, sizeof(bitstring));
|
||||
#endif
|
||||
|
||||
// Check we have enough data
|
||||
if (results.rawlen < 2 * MAGIQUEST_BITS) {
|
||||
DBG_PRINT("Not enough bits to be a MagiQuest packet (");
|
||||
DBG_PRINT(irparams.rawlen);
|
||||
DBG_PRINT(" < ");
|
||||
DBG_PRINT(MAGIQUEST_BITS*2);
|
||||
DBG_PRINTLN(")");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the bits in
|
||||
data.llword = 0;
|
||||
while (offset + 1 < results.rawlen) {
|
||||
mark_ = results.rawbuf[offset++];
|
||||
space_ = results.rawbuf[offset++];
|
||||
ratio_ = space_ / mark_;
|
||||
|
||||
DBG_PRINT("mark=");
|
||||
DBG_PRINT(mark_ * MICROS_PER_TICK);
|
||||
DBG_PRINT(" space=");
|
||||
DBG_PRINT(space_ * MICROS_PER_TICK);
|
||||
DBG_PRINT(" ratio=");
|
||||
DBG_PRINTLN(ratio_);
|
||||
|
||||
if (MATCH_MARK(space_ + mark_, MAGIQUEST_PERIOD)) {
|
||||
if (ratio_ > 1) {
|
||||
// It's a 0
|
||||
data.llword <<= 1;
|
||||
#if DEBUG
|
||||
bitstring[(offset/2)-1] = '0';
|
||||
#endif
|
||||
} else {
|
||||
// It's a 1
|
||||
data.llword = (data.llword << 1) | 1;
|
||||
#if DEBUG
|
||||
bitstring[(offset/2)-1] = '1';
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
DBG_PRINTLN("MATCH_MARK failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
DBG_PRINTLN(bitstring);
|
||||
#endif
|
||||
|
||||
// Success
|
||||
results.decode_type = MAGIQUEST;
|
||||
results.bits = offset / 2;
|
||||
results.value = data.cmd.wand_id;
|
||||
results.magnitude = data.cmd.magnitude;
|
||||
|
||||
DBG_PRINT("MQ: bits=");
|
||||
DBG_PRINT(results.bits);
|
||||
DBG_PRINT(" value=");
|
||||
DBG_PRINT(results.value);
|
||||
DBG_PRINT(" magnitude=");
|
||||
DBG_PRINTLN(results.magnitude);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeMagiQuest(decode_results *aResults) {
|
||||
bool aReturnValue = decodeMagiQuest();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
92
trunk/Arduino/libraries/IRremote/src/ir_Mitsubishi.cpp
Normal file
92
trunk/Arduino/libraries/IRremote/src/ir_Mitsubishi.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII
|
||||
// M M M I T S U U B B I S H H I
|
||||
// M M M I T SSS U U BBBB I SSS HHHHH I
|
||||
// M M I T S U U B B I S H H I
|
||||
// M M IIIII T SSSS UUU BBBBB IIIII SSSS H H IIIII
|
||||
//==============================================================================
|
||||
|
||||
// Looks like Sony except for timings, 48 chars of data and time/space different
|
||||
|
||||
#define MITSUBISHI_BITS 16
|
||||
|
||||
// Mitsubishi RM 75501
|
||||
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
|
||||
// #define MITSUBISHI_HEADER_MARK 250 // seen range 3500
|
||||
#define MITSUBISHI_HEADER_SPACE 350 // 7*50+100
|
||||
#define MITSUBISHI_ONE_MARK 1950 // 41*50-100
|
||||
#define MITSUBISHI_ZERO_MARK 750 // 17*50-100
|
||||
// #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually see 713 - not using ticks as get number wrap around
|
||||
// #define MITSUBISHI_RPT_LENGTH 45000
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_MITSUBISHI
|
||||
bool IRrecv::decodeMitsubishi() {
|
||||
// Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2);
|
||||
long data = 0;
|
||||
if (results.rawlen < 2 * MITSUBISHI_BITS + 2)
|
||||
return false;
|
||||
unsigned int offset = 1; // Skip first space
|
||||
// Initial space
|
||||
|
||||
#if 0
|
||||
// Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay
|
||||
Serial.print("IR Gap: ");
|
||||
Serial.println( results.rawbuf[0]);
|
||||
Serial.println( "test against:");
|
||||
Serial.println(results.rawbuf[0]);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Not seeing double keys from Mitsubishi
|
||||
if (results.rawbuf[0] < MITSUBISHI_DOUBLE_SPACE_USECS) {
|
||||
// Serial.print("IR Gap found: ");
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.decode_type = MITSUBISHI;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Typical
|
||||
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7
|
||||
|
||||
// Initial Space
|
||||
if (!MATCH_MARK(results.rawbuf[offset], MITSUBISHI_HEADER_SPACE))
|
||||
return false;
|
||||
offset++;
|
||||
|
||||
while (offset + 1 < irparams.rawlen) {
|
||||
if (MATCH_MARK(results.rawbuf[offset], MITSUBISHI_ONE_MARK))
|
||||
data = (data << 1) | 1;
|
||||
else if (MATCH_MARK(results.rawbuf[offset], MITSUBISHI_ZERO_MARK))
|
||||
data <<= 1;
|
||||
else
|
||||
return false;
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], MITSUBISHI_HEADER_SPACE))
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = (offset - 1) / 2;
|
||||
if (results.bits < MITSUBISHI_BITS) {
|
||||
results.bits = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
results.value = data;
|
||||
results.decode_type = MITSUBISHI;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeMitsubishi(decode_results *aResults) {
|
||||
bool aReturnValue = decodeMitsubishi();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
212
trunk/Arduino/libraries/IRremote/src/ir_NEC.cpp
Normal file
212
trunk/Arduino/libraries/IRremote/src/ir_NEC.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* ir_NEC.cpp
|
||||
*
|
||||
* Contains functions for receiving and sending NEC IR Protocol in "raw" and standard format with 16 bit Address 8bit Data
|
||||
*
|
||||
* This file is part of Arduino-RobotCar https://github.com/z3t0/Arduino-IRremote.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*/
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// N N EEEEE CCCC
|
||||
// NN N E C
|
||||
// N N N EEE C
|
||||
// N NN E C
|
||||
// N N EEEEE CCCC
|
||||
//==============================================================================
|
||||
|
||||
#define NEC_BITS 32
|
||||
#define NEC_HEADER_MARK 9000
|
||||
#define NEC_HEADER_SPACE 4500
|
||||
#define NEC_BIT_MARK 560
|
||||
#define NEC_ONE_SPACE 1690
|
||||
#define NEC_ZERO_SPACE 560
|
||||
#define NEC_REPEAT_SPACE 2250
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_NEC || SEND_NEC_STANDARD
|
||||
/*
|
||||
* Send repeat
|
||||
* Repeat commands should be sent in a 110 ms raster.
|
||||
*/
|
||||
void IRsend::sendNECRepeat() {
|
||||
enableIROut(38);
|
||||
mark(NEC_HEADER_MARK);
|
||||
space(NEC_REPEAT_SPACE);
|
||||
mark(NEC_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_NEC
|
||||
/*
|
||||
* Repeat commands should be sent in a 110 ms raster.
|
||||
* https://www.sbprojects.net/knowledge/ir/nec.php
|
||||
*/
|
||||
void IRsend::sendNEC(unsigned long data, int nbits, bool repeat) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
if (data == REPEAT || repeat) {
|
||||
sendNECRepeat();
|
||||
return;
|
||||
}
|
||||
|
||||
// Header
|
||||
mark(NEC_HEADER_MARK);
|
||||
space(NEC_HEADER_SPACE);
|
||||
// Data
|
||||
sendPulseDistanceWidthData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE, data, nbits);
|
||||
|
||||
// Footer
|
||||
mark(NEC_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_NEC_STANDARD
|
||||
/*
|
||||
* Repeat commands should be sent in a 110 ms raster.
|
||||
* https://www.sbprojects.net/knowledge/ir/nec.php
|
||||
*/
|
||||
void IRsend::sendNECStandard(uint16_t aAddress, uint8_t aCommand, uint8_t aNumberOfRepeats) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
unsigned long tStartMillis = millis();
|
||||
// Header
|
||||
mark(NEC_HEADER_MARK);
|
||||
space(NEC_HEADER_SPACE);
|
||||
// Address 16 bit LSB first
|
||||
sendPulseDistanceWidthData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE, aAddress, 16, false);
|
||||
|
||||
// send 8 command bits and then 8 inverted command bits LSB first
|
||||
uint16_t tCommand = ((~aCommand) << 8) | aCommand;
|
||||
// Command 16 bit LSB first
|
||||
sendPulseDistanceWidthData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE, tCommand, 16, false);
|
||||
mark(NEC_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
|
||||
for (uint8_t i = 0; i < aNumberOfRepeats; ++i) {
|
||||
// send repeat in a 110 ms raster
|
||||
delay((tStartMillis + 110) - millis());
|
||||
tStartMillis = millis();
|
||||
// send repeat
|
||||
sendNECRepeat();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//+=============================================================================
|
||||
// NECs have a repeat only 4 items long
|
||||
//
|
||||
#if DECODE_NEC
|
||||
bool IRrecv::decodeNEC() {
|
||||
long data = 0; // We decode in to here; Start with nothing
|
||||
int offset = 1; // Index in to results; Skip first entry!?
|
||||
|
||||
// Check header "mark"
|
||||
if (!MATCH_MARK(results.rawbuf[offset], NEC_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Check for repeat
|
||||
if ((results.rawlen == 4) && MATCH_SPACE(results.rawbuf[offset], NEC_REPEAT_SPACE)
|
||||
&& MATCH_MARK(results.rawbuf[offset + 1], NEC_BIT_MARK)) {
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = NEC;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check we have enough data
|
||||
if (results.rawlen < (2 * NEC_BITS) + 4) {
|
||||
return false;
|
||||
}
|
||||
// Check header "space"
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], NEC_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(NEC_BITS, offset, NEC_BIT_MARK, NEC_ONE_SPACE, NEC_ZERO_SPACE);
|
||||
|
||||
// Success
|
||||
results.bits = NEC_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = NEC;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeNEC(decode_results *aResults) {
|
||||
bool aReturnValue = decodeNEC();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
// NECs have a repeat only 4 items long
|
||||
//
|
||||
#if DECODE_NEC_STANDARD
|
||||
bool IRrecv::decodeNECStandard() {
|
||||
long data = 0; // We decode in to here; Start with nothing
|
||||
int offset = 1; // Index in to results; Skip first entry!?
|
||||
|
||||
// Check header "mark"
|
||||
if (!MATCH_MARK(results.rawbuf[offset], NEC_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Check for repeat
|
||||
if ((results.rawlen == 4) && MATCH_SPACE(results.rawbuf[offset], NEC_REPEAT_SPACE)
|
||||
&& MATCH_MARK(results.rawbuf[offset + 1], NEC_BIT_MARK)) {
|
||||
results.isRepeat = true;
|
||||
results.bits = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check we have enough data
|
||||
if (results.rawlen < (2 * NEC_BITS) + 4) {
|
||||
return false;
|
||||
}
|
||||
// Check header "space"
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], NEC_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(NEC_BITS, offset, NEC_BIT_MARK, NEC_ONE_SPACE, NEC_ZERO_SPACE, false);
|
||||
|
||||
// Success
|
||||
uint16_t tCommand = data >> 16;
|
||||
uint8_t tCommandNotInverted = tCommand & 0xFF;
|
||||
uint8_t tCommandInverted = tCommand >> 8;
|
||||
// plausi check for command
|
||||
if ((tCommandNotInverted ^ tCommandInverted) != 0xFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
results.isRepeat = false;
|
||||
results.value = tCommandNotInverted;
|
||||
results.bits = NEC_BITS;
|
||||
results.address = data & 0xFFFF; // first 16 bit
|
||||
results.decode_type = NEC_STANDARD;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
108
trunk/Arduino/libraries/IRremote/src/ir_Panasonic.cpp
Normal file
108
trunk/Arduino/libraries/IRremote/src/ir_Panasonic.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// PPPP AAA N N AAA SSSS OOO N N IIIII CCCC
|
||||
// P P A A NN N A A S O O NN N I C
|
||||
// PPPP AAAAA N N N AAAAA SSS O O N N N I C
|
||||
// P A A N NN A A S O O N NN I C
|
||||
// P A A N N A A SSSS OOO N N IIIII CCCC
|
||||
//==============================================================================
|
||||
|
||||
#define PANASONIC_BITS 48
|
||||
#define PANASONIC_ADDRESS_BITS 16
|
||||
#define PANASONIC_DATA_BITS 32
|
||||
#define PANASONIC_HEADER_MARK 3502
|
||||
#define PANASONIC_HEADER_SPACE 1750
|
||||
#define PANASONIC_BIT_MARK 502
|
||||
#define PANASONIC_ONE_SPACE 1244
|
||||
#define PANASONIC_ZERO_SPACE 400
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_PANASONIC
|
||||
void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(37); // 36.7kHz is the correct frequency
|
||||
|
||||
// Header
|
||||
mark(PANASONIC_HEADER_MARK);
|
||||
space(PANASONIC_HEADER_SPACE);
|
||||
|
||||
// Address
|
||||
sendPulseDistanceWidthData(PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE, PANASONIC_BIT_MARK, PANASONIC_ZERO_SPACE, address,
|
||||
PANASONIC_ADDRESS_BITS);
|
||||
// for (unsigned long mask = 1UL << (16 - 1); mask; mask >>= 1) {
|
||||
// mark(PANASONIC_BIT_MARK);
|
||||
// if (address & mask)
|
||||
// space(PANASONIC_ONE_SPACE);
|
||||
// else
|
||||
// space(PANASONIC_ZERO_SPACE);
|
||||
// }
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE, PANASONIC_BIT_MARK,
|
||||
PANASONIC_ZERO_SPACE, data, PANASONIC_DATA_BITS);
|
||||
// for (unsigned long mask = 1UL << (32 - 1); mask; mask >>= 1) {
|
||||
// mark(PANASONIC_BIT_MARK);
|
||||
// if (data & mask)
|
||||
// space(PANASONIC_ONE_SPACE);
|
||||
// else
|
||||
// space(PANASONIC_ZERO_SPACE);
|
||||
// }
|
||||
|
||||
// Footer
|
||||
mark(PANASONIC_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_PANASONIC
|
||||
bool IRrecv::decodePanasonic() {
|
||||
unsigned long address = 0;
|
||||
unsigned long data = 0;
|
||||
int offset = 1;
|
||||
|
||||
if (!MATCH_MARK(results.rawbuf[offset], PANASONIC_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
if (!MATCH_MARK(results.rawbuf[offset], PANASONIC_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
address = decodePulseDistanceData(PANASONIC_ADDRESS_BITS, offset, PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE,
|
||||
PANASONIC_ZERO_SPACE);
|
||||
data = decodePulseDistanceData(PANASONIC_DATA_BITS, offset + PANASONIC_ADDRESS_BITS, PANASONIC_BIT_MARK,
|
||||
PANASONIC_ONE_SPACE, PANASONIC_ZERO_SPACE);
|
||||
// // decode address
|
||||
// for (int i = 0; i < PANASONIC_BITS; i++) {
|
||||
// if (!MATCH_MARK(results.rawbuf[offset], PANASONIC_BIT_MARK)) {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
//
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], PANASONIC_ONE_SPACE)) {
|
||||
// data = (data << 1) | 1;
|
||||
// } else if (MATCH_SPACE(results.rawbuf[offset], PANASONIC_ZERO_SPACE)) {
|
||||
// data = (data << 1) | 0;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
// }
|
||||
|
||||
results.value = data;
|
||||
results.address = address;
|
||||
results.decode_type = PANASONIC;
|
||||
results.bits = PANASONIC_BITS;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodePanasonic(decode_results *aResults) {
|
||||
bool aReturnValue = decodePanasonic();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
320
trunk/Arduino/libraries/IRremote/src/ir_RC5_RC6.cpp
Normal file
320
trunk/Arduino/libraries/IRremote/src/ir_RC5_RC6.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#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
|
||||
85
trunk/Arduino/libraries/IRremote/src/ir_Samsung.cpp
Normal file
85
trunk/Arduino/libraries/IRremote/src/ir_Samsung.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSSS AAA MMM SSSS U U N N GGGG
|
||||
// S A A M M M S U U NN N G
|
||||
// SSS AAAAA M M M SSS U U N N N G GG
|
||||
// S A A M M S U U N NN G G
|
||||
// SSSS A A M M SSSS UUU N N GGG
|
||||
//==============================================================================
|
||||
|
||||
#define SAMSUNG_BITS 32
|
||||
#define SAMSUNG_HEADER_MARK 4500
|
||||
#define SAMSUNG_HEADER_SPACE 4500
|
||||
#define SAMSUNG_BIT_MARK 560
|
||||
#define SAMSUNG_ONE_SPACE 1600
|
||||
#define SAMSUNG_ZERO_SPACE 560
|
||||
#define SAMSUNG_REPEAT_SPACE 2250
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_SAMSUNG
|
||||
void IRsend::sendSAMSUNG(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Header
|
||||
mark(SAMSUNG_HEADER_MARK);
|
||||
space(SAMSUNG_HEADER_SPACE);
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, SAMSUNG_BIT_MARK, SAMSUNG_ZERO_SPACE, data, nbits);
|
||||
|
||||
// Footer
|
||||
mark(SAMSUNG_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
// SAMSUNGs have a repeat only 4 items long
|
||||
//
|
||||
#if DECODE_SAMSUNG
|
||||
bool IRrecv::decodeSAMSUNG() {
|
||||
long data = 0;
|
||||
int offset = 1; // Skip first space
|
||||
|
||||
// Initial mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SAMSUNG_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Check for repeat
|
||||
if ((irparams.rawlen == 4) && MATCH_SPACE(results.rawbuf[offset], SAMSUNG_REPEAT_SPACE)
|
||||
&& MATCH_MARK(results.rawbuf[offset + 1], SAMSUNG_BIT_MARK)) {
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = SAMSUNG;
|
||||
return true;
|
||||
}
|
||||
if (irparams.rawlen < (2 * SAMSUNG_BITS) + 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initial space
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], SAMSUNG_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(SAMSUNG_BITS, offset, SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, SAMSUNG_ZERO_SPACE);
|
||||
|
||||
// Success
|
||||
results.bits = SAMSUNG_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = SAMSUNG;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeSAMSUNG(decode_results *aResults) {
|
||||
bool aReturnValue = decodeSAMSUNG();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
95
trunk/Arduino/libraries/IRremote/src/ir_Sanyo.cpp
Normal file
95
trunk/Arduino/libraries/IRremote/src/ir_Sanyo.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSSS AAA N N Y Y OOO
|
||||
// S A A NN N Y Y O O
|
||||
// SSS AAAAA N N N Y O O
|
||||
// S A A N NN Y O O
|
||||
// SSSS A A N N Y OOO
|
||||
//==============================================================================
|
||||
|
||||
// I think this is a Sanyo decoder: Serial = SA 8650B
|
||||
// Looks like Sony except for timings, 48 chars of data and time/space different
|
||||
|
||||
#define SANYO_BITS 12
|
||||
#define SANYO_HEADER_MARK 3500 // seen range 3500
|
||||
#define SANYO_HEADER_SPACE 950 // seen 950
|
||||
#define SANYO_ONE_MARK 2400 // seen 2400
|
||||
#define SANYO_ZERO_MARK 700 // seen 700
|
||||
#define SANYO_DOUBLE_SPACE_USECS 800 // usually see 713 - not using ticks as get number wrap around
|
||||
#define SANYO_RPT_LENGTH 45000
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_SANYO
|
||||
bool IRrecv::decodeSanyo() {
|
||||
long data = 0;
|
||||
unsigned int offset = 0; // Skip first space <-- CHECK THIS!
|
||||
|
||||
if (results.rawlen < (2 * SANYO_BITS) + 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay
|
||||
Serial.print("IR Gap: ");
|
||||
Serial.println( results.rawbuf[offset] * MICROS_PER_TICK);
|
||||
Serial.println( "test against:");
|
||||
Serial.println(SANYO_DOUBLE_SPACE_USECS);
|
||||
#endif
|
||||
|
||||
// Initial space
|
||||
if ((results.rawbuf[offset] * MICROS_PER_TICK) < SANYO_DOUBLE_SPACE_USECS) {
|
||||
//Serial.print("IR Gap found: ");
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = SANYO;
|
||||
return true;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Initial mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SANYO_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Skip Second Mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SANYO_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
while (offset + 1 < irparams.rawlen) {
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], SANYO_HEADER_SPACE)) {
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (MATCH_MARK(results.rawbuf[offset], SANYO_ONE_MARK)) {
|
||||
data = (data << 1) | 1;
|
||||
} else if (MATCH_MARK(results.rawbuf[offset], SANYO_ZERO_MARK)) {
|
||||
data = (data << 1) | 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = (offset - 1) / 2;
|
||||
if (results.bits < 12) {
|
||||
results.bits = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
results.value = data;
|
||||
results.decode_type = SANYO;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeSanyo(decode_results *aResults) {
|
||||
bool aReturnValue = decodeSanyo();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
180
trunk/Arduino/libraries/IRremote/src/ir_Sharp.cpp
Normal file
180
trunk/Arduino/libraries/IRremote/src/ir_Sharp.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSSS H H AAA RRRR PPPP
|
||||
// S H H A A R R P P
|
||||
// SSS HHHHH AAAAA RRRR PPPP
|
||||
// S H H A A R R P
|
||||
// SSSS H H A A R R P
|
||||
//==============================================================================
|
||||
|
||||
// Sharp and DISH support by Todd Treece: http://unionbridge.org/design/ircommand
|
||||
//
|
||||
// The send function has the necessary repeat built in because of the need to
|
||||
// invert the signal.
|
||||
//
|
||||
// Sharp protocol documentation:
|
||||
// http://www.sbprojects.com/knowledge/ir/sharp.htm
|
||||
//
|
||||
// Here is the LIRC file I found that seems to match the remote codes from the
|
||||
// oscilloscope:
|
||||
// Sharp LCD TV:
|
||||
// http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
|
||||
|
||||
#define SHARP_BITS 15
|
||||
#define SHARP_ONE_SPACE 1805
|
||||
//#define SHARP_ONE_SPACE 1850
|
||||
|
||||
#define SHARP_ADDR_BITS 5
|
||||
#define SHARP_DATA_BITS 8
|
||||
#define SHARP_BIT_MARK_SEND 250
|
||||
#define SHARP_BIT_MARK_RECV 150
|
||||
|
||||
#define SHARP_ZERO_SPACE 795
|
||||
#define SHARP_GAP 600000
|
||||
#define SHARP_REPEAT_SPACE 3000
|
||||
|
||||
#define SHARP_TOGGLE_MASK 0x3FF
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_SHARP
|
||||
void IRsend::sendSharpRaw(unsigned long data, int nbits) {
|
||||
enableIROut(38);
|
||||
|
||||
// Sending codes in bursts of 3 (normal, inverted, normal) makes transmission
|
||||
// much more reliable. That's the exact behavior of CD-S6470 remote control.
|
||||
for (int n = 0; n < 3; n++) {
|
||||
sendPulseDistanceWidthData(SHARP_BIT_MARK_SEND, SHARP_ONE_SPACE, SHARP_BIT_MARK_SEND, SHARP_ZERO_SPACE, data, nbits);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark (SHARP_BIT_MARK_SEND);
|
||||
// space(SHARP_ONE_SPACE);
|
||||
// } else {
|
||||
// mark (SHARP_BIT_MARK_SEND);
|
||||
// space(SHARP_ZERO_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
mark(SHARP_BIT_MARK_SEND);
|
||||
space(SHARP_ZERO_SPACE);
|
||||
delay(40);
|
||||
|
||||
data = data ^ SHARP_TOGGLE_MASK;
|
||||
}
|
||||
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
// Sharp send compatible with data obtained through decodeSharp()
|
||||
// ^^^^^^^^^^^^^ FUNCTION MISSING!
|
||||
//
|
||||
#if SEND_SHARP
|
||||
void IRsend::sendSharp(unsigned int address, unsigned int command) {
|
||||
sendSharpRaw((address << 10) | (command << 2) | 2, SHARP_BITS);
|
||||
/*
|
||||
* Use this code instead of the line above to be code compatible to the decoded values from decodeSharp
|
||||
*/
|
||||
// //Change address to big-endian (five bits swap place)
|
||||
// address = (address & 0x10) >> 4 | (address & 0x01) << 4 | (address & 0x08) >> 2 | (address & 0x02) << 2 | (address & 0x04) ;
|
||||
// //Change command to big-endian (eight bit swap place)
|
||||
// command = (command & 0xF0) >> 4 | (command & 0x0F) << 4;
|
||||
// command = (command & 0xCC) >> 2 | (command & 0x33) << 2;
|
||||
// command = (command & 0xAA) >> 1 | (command & 0x55) << 1;
|
||||
// sendSharpRaw((address << 10) | (command << 2) | 0, SHARP_BITS);
|
||||
}
|
||||
|
||||
#endif // SEND_SHARP
|
||||
|
||||
//+=============================================================================
|
||||
// Sharp decode function written based on Sharp protocol documentation:
|
||||
// http://www.sbprojects.com/knowledge/ir/sharp.htm
|
||||
// Tesded on a DENON AVR-1804 reciever
|
||||
|
||||
#if DECODE_SHARP
|
||||
bool IRrecv::decodeSharp() {
|
||||
unsigned long addr = 0; // Somewhere to build our address
|
||||
unsigned long data = 0; // Somewhere to build our data
|
||||
unsigned long lastData = 0; // Somewhere to store last data
|
||||
int offset = 1; //skip long space
|
||||
int loops = 1; //number of bursts
|
||||
|
||||
// Check we have the right amount of data
|
||||
// Either one burst or three where second is inverted
|
||||
// The setting #define _GAP 5000 in IRremoteInt.h will give one burst and possibly three calls to this function
|
||||
if (irparams.rawlen == (SHARP_BITS + 1) * 2)
|
||||
loops = 1;
|
||||
else if (irparams.rawlen == (SHARP_BITS + 1) * 2 * 3)
|
||||
loops = 3;
|
||||
else
|
||||
return false;
|
||||
|
||||
// Check the first mark to see if it fits the SHARP_BIT_MARK_RECV length
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SHARP_BIT_MARK_RECV))
|
||||
return false;
|
||||
//check the first pause and see if it fits the SHARP_ONE_SPACE or SHARP_ZERO_SPACE length
|
||||
if (!(MATCH_SPACE(results.rawbuf[offset + 1], SHARP_ONE_SPACE) || MATCH_SPACE(results.rawbuf[offset + 1], SHARP_ZERO_SPACE)))
|
||||
return false;
|
||||
|
||||
// Read the bits in
|
||||
for (int j = 0; j < loops; j++) {
|
||||
data = 0;
|
||||
addr = 0;
|
||||
addr = decodePulseDistanceData(SHARP_ADDR_BITS, offset, SHARP_BIT_MARK_SEND, SHARP_ONE_SPACE, SHARP_ZERO_SPACE);
|
||||
// for (int i = 0; i < SHARP_ADDR_BITS; i++) {
|
||||
// // Each bit looks like: SHARP_BIT_MARK_RECV + SHARP_ONE_SPACE -> 1
|
||||
// // or : SHARP_BIT_MARK_RECV + SHARP_ZERO_SPACE -> 0
|
||||
// if (!MATCH_MARK(results.rawbuf[offset++], SHARP_BIT_MARK_RECV))
|
||||
// return false;
|
||||
// // IR data is big-endian, so we shuffle it in from the right:
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], SHARP_ONE_SPACE))
|
||||
// addr += 1 << i;
|
||||
// else if (MATCH_SPACE(results.rawbuf[offset], SHARP_ZERO_SPACE))
|
||||
// addr = addr;
|
||||
// else
|
||||
// return false;
|
||||
// offset++;
|
||||
// }
|
||||
data = decodePulseDistanceData( SHARP_DATA_BITS, offset + SHARP_ADDR_BITS, SHARP_BIT_MARK_SEND, SHARP_ONE_SPACE,
|
||||
SHARP_ZERO_SPACE);
|
||||
// for (int i = 0; i < SHARP_DATA_BITS; i++) {
|
||||
// // Each bit looks like: SHARP_BIT_MARK_RECV + SHARP_ONE_SPACE -> 1
|
||||
// // or : SHARP_BIT_MARK_RECV + SHARP_ZERO_SPACE -> 0
|
||||
// if (!MATCH_MARK(results.rawbuf[offset++], SHARP_BIT_MARK_RECV))
|
||||
// return false;
|
||||
// // IR data is big-endian, so we shuffle it in from the right:
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], SHARP_ONE_SPACE))
|
||||
// data += 1 << i;
|
||||
// else if (MATCH_SPACE(results.rawbuf[offset], SHARP_ZERO_SPACE))
|
||||
// data = data;
|
||||
// else
|
||||
// return false;
|
||||
// offset++;
|
||||
// //Serial.print(i);
|
||||
// //Serial.print(":");
|
||||
// //Serial.println(data, HEX);
|
||||
// }
|
||||
//skip exp bit (mark+pause), chk bit (mark+pause), mark and long pause before next burst
|
||||
offset += 6;
|
||||
|
||||
//Check if last burst data is equal to this burst (lastData already inverted)
|
||||
if (lastData != 0 && data != lastData)
|
||||
return false;
|
||||
//save current burst of data but invert (XOR) the last 10 bits (8 data bits + exp bit + chk bit)
|
||||
lastData = data ^ 0xFF;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = SHARP_BITS;
|
||||
results.value = data;
|
||||
results.address = addr;
|
||||
results.decode_type = SHARP;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeSharp(decode_results *aResults) {
|
||||
bool aReturnValue = decodeSharp();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
128
trunk/Arduino/libraries/IRremote/src/ir_Sharp_alt.cpp
Normal file
128
trunk/Arduino/libraries/IRremote/src/ir_Sharp_alt.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
//-*- mode: C; c-basic-offset: 8; tab-width: 8; indent-tabs-mode: t; -*-
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSSS H H AAA RRRR PPPP AAA L TTTTT
|
||||
// S H H A A R R P P A A L T
|
||||
// SSS HHHHH AAAAA RRRR PPPP AAAAA L T
|
||||
// S H H A A R R P A A L T
|
||||
// SSSS H H A A R R P A A LLLLL T
|
||||
//==============================================================================
|
||||
|
||||
// This is an alternative protocol to that in ir_Sharp.cpp. It was tested with
|
||||
// the original Sharp GA538WJSA remote control. LIRC file with codes for this
|
||||
// remote control: http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
|
||||
//
|
||||
// Author: Sergiy Kolesnikov
|
||||
//
|
||||
|
||||
#define SHARP_ALT_RAWLEN 32
|
||||
#define SHARP_ALT_ADDRESS_BITS 5
|
||||
#define SHARP_ALT_COMMAND_BITS 8
|
||||
#define SHARP_ALT_BIT_MARK 150
|
||||
#define SHARP_ALT_SEND_BIT_MARK 300
|
||||
#define SHARP_ALT_ONE_SPACE 1750
|
||||
#define SHARP_ALT_ZERO_SPACE 700
|
||||
#define SHARP_ALT_REPEAT_SPACE 50000
|
||||
#define SHARP_ALT_SEND_REPEAT_SPACE 44000
|
||||
#define SHARP_ALT_TOGGLE_MASK 0x3FF
|
||||
#define SHARP_ALT_SEND_INVERT_MASK 0x7FE0
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_SHARP_ALT
|
||||
void IRsend::sendSharpAltRaw(unsigned int data, int nbits) {
|
||||
enableIROut(38);
|
||||
|
||||
for (int n = 0; n < 3; n++) {
|
||||
// From LSB to MSB
|
||||
sendPulseDistanceWidthData(SHARP_ALT_SEND_BIT_MARK, SHARP_ALT_ONE_SPACE, SHARP_ALT_SEND_BIT_MARK, SHARP_ALT_ZERO_SPACE,
|
||||
data, nbits, false);
|
||||
// unsigned long mask = 1UL;
|
||||
// for (int i = 0; i < nbits; i++) {
|
||||
// if (data & mask) {
|
||||
// mark(SHARP_ALT_SEND_BIT_MARK);
|
||||
// space(SHARP_ALT_ONE_SPACE);
|
||||
// } else {
|
||||
// mark(SHARP_ALT_SEND_BIT_MARK);
|
||||
// space(SHARP_ALT_ZERO_SPACE);
|
||||
// }
|
||||
// mask <<= 1;
|
||||
// }
|
||||
mark(SHARP_ALT_BIT_MARK);
|
||||
space(SHARP_ALT_SEND_REPEAT_SPACE);
|
||||
data = data ^ SHARP_ALT_SEND_INVERT_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
void IRsend::sendSharpAlt(uint8_t address, uint8_t command) {
|
||||
// 1 = The expansion and the check bits (01).
|
||||
unsigned int data = (1 << SHARP_ALT_COMMAND_BITS) | command;
|
||||
data = (data << SHARP_ALT_ADDRESS_BITS) | address;
|
||||
|
||||
// (+2) is for the expansion and the check bits 0b01.
|
||||
sendSharpAltRaw(data, SHARP_ALT_ADDRESS_BITS + SHARP_ALT_COMMAND_BITS + 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_SHARP_ALT
|
||||
bool IRrecv::decodeSharpAlt() {
|
||||
static boolean is_first_repeat = true;
|
||||
|
||||
// Check we have enough data.
|
||||
if (results.rawlen < (SHARP_ALT_RAWLEN))
|
||||
return false;
|
||||
|
||||
// Check stop mark.
|
||||
if (!MATCH_MARK(results.rawbuf[SHARP_ALT_RAWLEN - 1], SHARP_ALT_BIT_MARK))
|
||||
return false;
|
||||
|
||||
// Check the "check bit." If this bit is not 0 than it is an inverted
|
||||
// frame, which we ignore.
|
||||
if (!MATCH_SPACE(results.rawbuf[SHARP_ALT_RAWLEN - 2], SHARP_ALT_ZERO_SPACE))
|
||||
return false;
|
||||
|
||||
// Check for repeat.
|
||||
long initial_space = ((long) results.rawbuf[0]) * MICROS_PER_TICK;
|
||||
if (initial_space <= SHARP_ALT_REPEAT_SPACE) {
|
||||
if (!is_first_repeat) {
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = SHARP;
|
||||
return true;
|
||||
} else {
|
||||
// Ignore the first repeat that always comes after the
|
||||
// inverted frame (even if the button was pressed only once).
|
||||
is_first_repeat = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode bits. SHARP_ALT_RAWLEN-6 because index starts with 0 (-1) and we
|
||||
// omit the timings for the stop mark (-1), the check bit (-2), and the
|
||||
// expansion bit (-2).
|
||||
uint16_t bits = 0;
|
||||
for (uint8_t i = SHARP_ALT_RAWLEN - 6; i > 1; i -= 2) {
|
||||
if (MATCH_SPACE(results.rawbuf[i], SHARP_ALT_ONE_SPACE)) {
|
||||
bits = (bits << 1) | 1;
|
||||
} else if (MATCH_SPACE(results.rawbuf[i], SHARP_ALT_ZERO_SPACE)) {
|
||||
bits = (bits << 1) | 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
results.bits = SHARP_ALT_ADDRESS_BITS + SHARP_ALT_COMMAND_BITS;
|
||||
results.address = (bits & (1 << (SHARP_ALT_ADDRESS_BITS))) - 1;
|
||||
results.value = bits >> SHARP_ALT_ADDRESS_BITS; // command
|
||||
results.decode_type = SHARP_ALT;
|
||||
is_first_repeat = true;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeSharpAlt(decode_results *aResults) {
|
||||
bool aReturnValue = decodeSharpAlt();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
105
trunk/Arduino/libraries/IRremote/src/ir_Sony.cpp
Normal file
105
trunk/Arduino/libraries/IRremote/src/ir_Sony.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// SSSS OOO N N Y Y
|
||||
// S O O NN N Y Y
|
||||
// SSS O O N N N Y
|
||||
// S O O N NN Y
|
||||
// SSSS OOO N N Y
|
||||
//==============================================================================
|
||||
|
||||
#define SONY_BITS 12
|
||||
#define SONY_HEADER_MARK 2400
|
||||
#define SONY_HEADER_SPACE 600
|
||||
#define SONY_ONE_MARK 1200
|
||||
#define SONY_ZERO_MARK 600
|
||||
#define SONY_RPT_LENGTH 45000
|
||||
#define SONY_DOUBLE_SPACE_USECS 500 // usually see 713 - not using ticks as get number wrap around
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_SONY
|
||||
void IRsend::sendSony(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(40);
|
||||
|
||||
// Header
|
||||
mark(SONY_HEADER_MARK);
|
||||
space(SONY_HEADER_SPACE);
|
||||
|
||||
sendPulseDistanceWidthData(SONY_ONE_MARK, SONY_HEADER_SPACE, SONY_ZERO_MARK, SONY_HEADER_SPACE, data, nbits);
|
||||
// // Data - Pulse width coding
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark(SONY_ONE_MARK);
|
||||
// space(SONY_HEADER_SPACE);
|
||||
// } else {
|
||||
// mark(SONY_ZERO_MARK);
|
||||
// space(SONY_HEADER_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_SONY
|
||||
bool IRrecv::decodeSony() {
|
||||
long data = 0;
|
||||
unsigned int offset = 0; // Dont skip first space, check its size
|
||||
|
||||
if (results.rawlen < (2 * SONY_BITS) + 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some Sony's deliver repeats fast after first
|
||||
// unfortunately can't spot difference from of repeat from two fast clicks
|
||||
if (results.rawbuf[offset] * MICROS_PER_TICK < SONY_DOUBLE_SPACE_USECS) {
|
||||
DBG_PRINTLN("IR Gap found");
|
||||
results.bits = 0;
|
||||
results.value = REPEAT;
|
||||
results.isRepeat = true;
|
||||
results.decode_type = UNKNOWN;
|
||||
return true;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Initial mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SONY_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
while (offset + 1 < results.rawlen) {
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], SONY_HEADER_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 = (data << 1) | 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = (offset - 1) / 2;
|
||||
if (results.bits < 12) {
|
||||
results.bits = 0;
|
||||
return false;
|
||||
}
|
||||
results.value = data;
|
||||
results.decode_type = SONY;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeSony(decode_results *aResults) {
|
||||
bool aReturnValue = decodeSony();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
197
trunk/Arduino/libraries/IRremote/src/ir_Template.cpp
Normal file
197
trunk/Arduino/libraries/IRremote/src/ir_Template.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
Assuming the protocol we are adding is for the (imaginary) manufacturer: Shuzu
|
||||
|
||||
Our fantasy protocol is a standard protocol, so we can use this standard
|
||||
template without too much work. Some protocols are quite unique and will require
|
||||
considerably more work in this file! It is way beyond the scope of this text to
|
||||
explain how to reverse engineer "unusual" IR protocols. But, unless you own an
|
||||
oscilloscope, the starting point is probably to use the rawDump.ino sketch and
|
||||
try to spot the pattern!
|
||||
|
||||
Before you start, make sure the IR library is working OK:
|
||||
# Open up the Arduino IDE
|
||||
# Load up the rawDump.ino example sketch
|
||||
# Run it
|
||||
|
||||
Now we can start to add our new protocol...
|
||||
|
||||
1. Copy this file to : ir_Shuzu.cpp
|
||||
|
||||
2. Replace all occurrences of "Shuzu" with the name of your protocol.
|
||||
|
||||
3. Tweak the #defines to suit your protocol.
|
||||
|
||||
4. If you're lucky, tweaking the #defines will make the default send() function
|
||||
work.
|
||||
|
||||
5. Again, if you're lucky, tweaking the #defines will have made the default
|
||||
decode() function work.
|
||||
|
||||
You have written the code to support your new protocol!
|
||||
|
||||
Now you must do a few things to add it to the IRremote system:
|
||||
|
||||
1. Open IRremote.h and make the following changes:
|
||||
REMEMEBER to change occurences of "SHUZU" with the name of your protocol
|
||||
|
||||
A. At the top, in the section "Supported Protocols", add:
|
||||
#define DECODE_SHUZU 1
|
||||
#define SEND_SHUZU 1
|
||||
|
||||
B. In the section "enumerated list of all supported formats", add:
|
||||
SHUZU,
|
||||
to the end of the list (notice there is a comma after the protocol name)
|
||||
|
||||
C. Further down in "Main class for receiving IR", add:
|
||||
//......................................................................
|
||||
#if DECODE_SHUZU
|
||||
bool decodeShuzu (decode_results *aResults) ;
|
||||
#endif
|
||||
|
||||
D. Further down in "Main class for sending IR", add:
|
||||
//......................................................................
|
||||
#if SEND_SHUZU
|
||||
void sendShuzu (unsigned long data, int nbits) ;
|
||||
#endif
|
||||
|
||||
E. Save your changes and close the file
|
||||
|
||||
2. Now open irRecv.cpp and make the following change:
|
||||
|
||||
A. In the function IRrecv::decode(), add:
|
||||
#ifdef DECODE_NEC
|
||||
DBG_PRINTLN("Attempting Shuzu decode");
|
||||
if (decodeShuzu(results)) return true ;
|
||||
#endif
|
||||
|
||||
B. Save your changes and close the file
|
||||
|
||||
You will probably want to add your new protocol to the example sketch
|
||||
|
||||
3. Open MyDocuments\Arduino\libraries\IRremote\examples\IRrecvDumpV2.ino
|
||||
|
||||
A. In the encoding() function, add:
|
||||
case SHUZU: Serial.print("SHUZU"); break ;
|
||||
|
||||
Now open the Arduino IDE, load up the rawDump.ino sketch, and run it.
|
||||
Hopefully it will compile and upload.
|
||||
If it doesn't, you've done something wrong. Check your work.
|
||||
If you can't get it to work - seek help from somewhere.
|
||||
|
||||
If you get this far, I will assume you have successfully added your new protocol
|
||||
There is one last thing to do.
|
||||
|
||||
1. Delete this giant instructional comment.
|
||||
|
||||
2. Send a copy of your work to us so we can include it in the library and
|
||||
others may benefit from your hard work and maybe even write a song about how
|
||||
great you are for helping them! :)
|
||||
|
||||
Regards,
|
||||
BlueChip
|
||||
*/
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
//
|
||||
// S H U Z U
|
||||
//
|
||||
//
|
||||
//==============================================================================
|
||||
|
||||
#define SHUZU_BITS 32 // The number of bits in the command
|
||||
|
||||
#define SHUZU_HEADER_MARK 1000 // The length of the Header:Mark
|
||||
#define SHUZU_HEADER_SPACE 2000 // The lenght of the Header:Space
|
||||
|
||||
#define SHUZU_BIT_MARK 3000 // The length of a Bit:Mark
|
||||
#define SHUZU_ONE_SPACE 4000 // The length of a Bit:Space for 1's
|
||||
#define SHUZU_ZERO_SPACE 5000 // The length of a Bit:Space for 0's
|
||||
|
||||
#define SHUZU_OTHER 1234 // Other things you may need to define
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if SEND_SHUZU
|
||||
void IRsend::sendShuzu(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Header
|
||||
mark(SHUZU_HEADER_MARK);
|
||||
space(SHUZU_HEADER_SPACE);
|
||||
|
||||
// Data
|
||||
sendPulseDistanceData(data, nbits, SHUZU_BIT_MARK, SHUZU_ONE_SPACE,SHUZU_BIT_MARK, SHUZU_ZERO_SPACE);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark(SHUZU_BIT_MARK);
|
||||
// space(SHUZU_ONE_SPACE);
|
||||
// } else {
|
||||
// mark(SHUZU_BIT_MARK);
|
||||
// space(SHUZU_ZERO_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Footer
|
||||
mark(SHUZU_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
//
|
||||
#if DECODE_SHUZU
|
||||
bool IRrecv::decodeShuzu() {
|
||||
unsigned long data = 0; // Somewhere to build our code
|
||||
int offset = 1; // Skip the gap reading
|
||||
|
||||
// Check we have the right amount of data
|
||||
if (results.rawlen != 1 + 2 + (2 * SHUZU_BITS) + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check initial Mark+Space match
|
||||
if (!MATCH_MARK(results.rawbuf[offset], SHUZU_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], SHUZU_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(results, SHUZU_BITS, offset, SHUZU_BIT_MARK, SHUZU_ONE_SPACE, SHUZU_ZERO_SPACE);
|
||||
// // Read the bits in
|
||||
// for (int i = 0; i < SHUZU_BITS; i++) {
|
||||
// // Each bit looks like: MARK + SPACE_1 -> 1
|
||||
// // or : MARK + SPACE_0 -> 0
|
||||
// if (!MATCH_MARK(results.rawbuf[offset], SHUZU_BIT_MARK)) {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
//
|
||||
// // IR data is big-endian, so we shuffle it in from the right:
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], SHUZU_ONE_SPACE)) {
|
||||
// data = (data << 1) | 1;
|
||||
// } else if (MATCH_SPACE(results.rawbuf[offset], SHUZU_ZERO_SPACE)) {
|
||||
// data = (data << 1) | 0;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
// }
|
||||
|
||||
// Success
|
||||
results.bits = SHUZU_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = SHUZU;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeShuzu(decode_results *aResults) {
|
||||
bool aReturnValue = decodeShuzu();
|
||||
}
|
||||
#endif
|
||||
118
trunk/Arduino/libraries/IRremote/src/ir_Whynter.cpp
Normal file
118
trunk/Arduino/libraries/IRremote/src/ir_Whynter.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include "IRremote.h"
|
||||
|
||||
//==============================================================================
|
||||
// W W H H Y Y N N TTTTT EEEEE RRRRR
|
||||
// W W H H Y Y NN N T E R R
|
||||
// W W W HHHHH Y N N N T EEE RRRR
|
||||
// W W W H H Y N NN T E R R
|
||||
// WWW H H Y N N T EEEEE R R
|
||||
//==============================================================================
|
||||
|
||||
#define WHYNTER_BITS 32
|
||||
#define WHYNTER_HEADER_MARK 2850
|
||||
#define WHYNTER_HEADER_SPACE 2850
|
||||
#define WHYNTER_BIT_MARK 750
|
||||
#define WHYNTER_ONE_SPACE 2150
|
||||
#define WHYNTER_ZERO_SPACE 750
|
||||
|
||||
//+=============================================================================
|
||||
#if SEND_WHYNTER
|
||||
void IRsend::sendWhynter(unsigned long data, int nbits) {
|
||||
// Set IR carrier frequency
|
||||
enableIROut(38);
|
||||
|
||||
// Start
|
||||
mark(WHYNTER_BIT_MARK);
|
||||
space(WHYNTER_ZERO_SPACE);
|
||||
|
||||
// Header
|
||||
mark(WHYNTER_HEADER_MARK);
|
||||
space(WHYNTER_HEADER_SPACE);
|
||||
|
||||
// Data
|
||||
sendPulseDistanceWidthData(WHYNTER_BIT_MARK, WHYNTER_ONE_SPACE, WHYNTER_BIT_MARK, WHYNTER_ZERO_SPACE, data, nbits);
|
||||
// for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||
// if (data & mask) {
|
||||
// mark(WHYNTER_ONE_MARK);
|
||||
// space(WHYNTER_ONE_SPACE);
|
||||
// } else {
|
||||
// mark(WHYNTER_ZERO_MARK);
|
||||
// space(WHYNTER_ZERO_SPACE);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Footer
|
||||
mark(WHYNTER_BIT_MARK);
|
||||
space(0); // Always end with the LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
#if DECODE_WHYNTER
|
||||
bool IRrecv::decodeWhynter() {
|
||||
long data = 0;
|
||||
int offset = 1; // skip initial space
|
||||
|
||||
// Check we have the right amount of data
|
||||
if (results.rawlen < (2 * WHYNTER_BITS) + 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sequence begins with a bit mark and a zero space
|
||||
if (!MATCH_MARK(results.rawbuf[offset], WHYNTER_BIT_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], WHYNTER_ZERO_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// header mark and space
|
||||
if (!MATCH_MARK(results.rawbuf[offset], WHYNTER_HEADER_MARK)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
if (!MATCH_SPACE(results.rawbuf[offset], WHYNTER_HEADER_SPACE)) {
|
||||
return false;
|
||||
}
|
||||
offset++;
|
||||
|
||||
data = decodePulseDistanceData(WHYNTER_BITS, offset, WHYNTER_BIT_MARK, WHYNTER_ONE_SPACE, WHYNTER_ZERO_SPACE);
|
||||
// // data bits
|
||||
// for (int i = 0; i < WHYNTER_BITS; i++) {
|
||||
// if (!MATCH_MARK(results.rawbuf[offset], WHYNTER_BIT_MARK)) {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
//
|
||||
// if (MATCH_SPACE(results.rawbuf[offset], WHYNTER_ONE_SPACE)) {
|
||||
// data = (data << 1) | 1;
|
||||
// } else if (MATCH_SPACE(results.rawbuf[offset], WHYNTER_ZERO_SPACE)) {
|
||||
// data = (data << 1) | 0;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// offset++;
|
||||
// }
|
||||
|
||||
// trailing mark
|
||||
if (!MATCH_MARK(results.rawbuf[offset], WHYNTER_BIT_MARK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
results.bits = WHYNTER_BITS;
|
||||
results.value = data;
|
||||
results.decode_type = WHYNTER;
|
||||
return true;
|
||||
}
|
||||
bool IRrecv::decodeWhynter(decode_results *aResults) {
|
||||
bool aReturnValue = decodeWhynter();
|
||||
*aResults = results;
|
||||
return aReturnValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
60
trunk/Arduino/libraries/IRremote/src/nRF5.cpp
Normal file
60
trunk/Arduino/libraries/IRremote/src/nRF5.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#if defined (NRF5) || defined (ARDUINO_ARCH_NRF52840)
|
||||
|
||||
// This file contains functions specific to the nRF5.
|
||||
// It uses Timer2 so you cannot use the Adafruit_Microbit display driver
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
// "Idiot check"
|
||||
#ifdef USE_DEFAULT_ENABLE_IR_IN
|
||||
#error Must undef USE_DEFAULT_ENABLE_IR_IN
|
||||
#endif
|
||||
|
||||
void IRTimer(); // defined in IRremote.cpp, masqueraded as ISR(TIMER_INTR_NAME)
|
||||
|
||||
//+=============================================================================
|
||||
// initialization
|
||||
//
|
||||
void IRrecv::enableIRIn() {
|
||||
// Interrupt Service Routine - Fires every 50uS
|
||||
NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode
|
||||
NRF_TIMER2->TASKS_CLEAR = 1; // clear the task first to be usable for later
|
||||
NRF_TIMER2->PRESCALER = 4; // f TIMER = 16 MHz / (2 ^ PRESCALER ) : 4 -> 1 MHz, 1 uS
|
||||
NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; //Set counter to 16 bit resolution
|
||||
NRF_TIMER2->CC[0] = 50; //Set value for TIMER2 compare register 0, to trigger every 50 uS
|
||||
NRF_TIMER2->CC[1] = 0; //Set value for TIMER2 compare register 1
|
||||
|
||||
// Enable interrupt on Timer 2, for CC[0] compare match events
|
||||
NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
|
||||
NVIC_EnableIRQ (TIMER2_IRQn);
|
||||
|
||||
NRF_TIMER2->TASKS_START = 1; // Start TIMER2
|
||||
|
||||
// timerAttachInterrupt(timer, &IRTimer, 1);
|
||||
|
||||
// Initialize state machine variables
|
||||
irparams.rcvstate = IR_REC_STATE_IDLE;
|
||||
irparams.rawlen = 0;
|
||||
|
||||
// Set pin modes
|
||||
pinMode(irparams.recvpin, INPUT);
|
||||
}
|
||||
|
||||
void timer_pal(void) {
|
||||
if ((NRF_TIMER2->EVENTS_COMPARE[0] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk) != 0)) {
|
||||
NRF_TIMER2->EVENTS_COMPARE[0] = 0; //Clear compare register 0 event
|
||||
IRTimer(); // call the IR-receive function
|
||||
NRF_TIMER2->CC[0] += 50;
|
||||
}
|
||||
}
|
||||
|
||||
/** TIMTER2 peripheral interrupt handler. This interrupt handler is called whenever there it a TIMER2 interrupt
|
||||
* Don't mess with this line. really.
|
||||
*/
|
||||
extern "C" {
|
||||
void TIMER2_IRQHandler(void) {
|
||||
timer_pal();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NRF5
|
||||
958
trunk/Arduino/libraries/IRremote/src/private/IRremoteBoardDefs.h
Normal file
958
trunk/Arduino/libraries/IRremote/src/private/IRremoteBoardDefs.h
Normal file
@@ -0,0 +1,958 @@
|
||||
/**
|
||||
* @file IRremoteBoardDefs.h
|
||||
*
|
||||
* @brief All board specific information should be contained in this file.
|
||||
* It defines a number of macros, depending on the board, as determined by
|
||||
* pre-proccesor symbols.
|
||||
* It was previously contained within IRremoteInt.h.
|
||||
*/
|
||||
// IRremote
|
||||
// Version 2.0.1 June, 2015
|
||||
// Copyright 2009 Ken Shirriff
|
||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
// JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
// Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
// Sparkfun Pro Micro support by Alastair McCormack
|
||||
//******************************************************************************
|
||||
#ifndef IRremoteBoardDefs_h
|
||||
#define IRremoteBoardDefs_h
|
||||
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
#include <avr/pgmspace.h>
|
||||
#define HAS_FLASH_READ 1
|
||||
#define STRCPY_PF_CAST(x) (x)
|
||||
#else
|
||||
#define HAS_FLASH_READ 0
|
||||
#endif
|
||||
|
||||
// Define some defaults, that some boards may like to override
|
||||
// (This is to avoid negative logic, ! DONT_... is just awkward.)
|
||||
|
||||
/**
|
||||
* Defined if the standard enableIRIn function should be used.
|
||||
* Undefine for boards supplying their own.
|
||||
*/
|
||||
#define USE_DEFAULT_ENABLE_IR_IN
|
||||
|
||||
/**
|
||||
* Define if the current board supports sending.
|
||||
* Currently not used.
|
||||
*/
|
||||
#define SENDING_SUPPORTED
|
||||
|
||||
/**
|
||||
* Defined if the standard enableIROut function should be used.
|
||||
* Undefine for boards supplying their own.
|
||||
*/
|
||||
#define USE_DEFAULT_ENABLE_IR_OUT
|
||||
|
||||
/**
|
||||
* Duty cycle in percent for sent signals.
|
||||
*/
|
||||
#if ! defined(IR_SEND_DUTY_CYCLE)
|
||||
#define IR_SEND_DUTY_CYCLE 30 // 30 saves power and is compatible to the old existing code
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This first #ifdef statement contains defines for blinking the LED,
|
||||
// as well as all other board specific information, with the exception of
|
||||
// timers and the sending pin (IR_SEND_PIN).
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* If defined, denotes pin number of LED that should be blinked during IR reception.
|
||||
* Leave undefined to disable blinking.
|
||||
*/
|
||||
#define BLINKLED LED_BUILTIN
|
||||
|
||||
/**
|
||||
* Board dependent macro to turn BLINKLED on.
|
||||
*/
|
||||
#define BLINKLED_ON() digitalWrite(BLINKLED, HIGH)
|
||||
|
||||
/**
|
||||
* Board dependent macro to turn BLINKLED off.
|
||||
*/
|
||||
#define BLINKLED_OFF() digitalWrite(BLINKLED, LOW)
|
||||
|
||||
#elif ! defined(ARDUINO)
|
||||
// Assume that we compile a test version, to be executed on the host, not on a board.
|
||||
|
||||
// Do not define anything.
|
||||
|
||||
#elif defined(CORE_LED0_PIN)
|
||||
#define BLINKLED CORE_LED0_PIN
|
||||
#define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH))
|
||||
#define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW))
|
||||
|
||||
// Sparkfun Pro Micro is __AVR_ATmega32U4__ but has different external circuit
|
||||
#elif defined(ARDUINO_AVR_PROMICRO)
|
||||
// We have no built in LED -> reuse RX LED
|
||||
#define BLINKLED LED_BUILTIN_RX
|
||||
#define BLINKLED_ON() RXLED1
|
||||
#define BLINKLED_OFF() RXLED0
|
||||
|
||||
// Arduino Leonardo
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define BLINKLED LED_BUILTIN
|
||||
#define BLINKLED_ON() (PORTC |= B10000000)
|
||||
#define BLINKLED_OFF() (PORTC &= B01111111)
|
||||
|
||||
// Arduino Uno, Nano etc (previously default clause)
|
||||
#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__)
|
||||
#define BLINKLED LED_BUILTIN
|
||||
#define BLINKLED_ON() (PORTB |= B00100000)
|
||||
#define BLINKLED_OFF() (PORTB &= B11011111)
|
||||
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define BLINKLED 13
|
||||
#define BLINKLED_ON() (PORTB |= B10000000)
|
||||
#define BLINKLED_OFF() (PORTB &= B01111111)
|
||||
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#define BLINKLED 0
|
||||
#define BLINKLED_ON() (PORTD |= B00000001)
|
||||
#define BLINKLED_OFF() (PORTD &= B11111110)
|
||||
|
||||
// Nano Every, Uno WiFi Rev2, nRF5 BBC MicroBit, Nano33_BLE
|
||||
#elif defined(__AVR_ATmega4809__) || defined(NRF5) || defined (ARDUINO_ARCH_NRF52840)
|
||||
#define BLINKLED LED_BUILTIN
|
||||
#define BLINKLED_ON() (digitalWrite(BLINKLED, HIGH))
|
||||
#define BLINKLED_OFF() (digitalWrite(BLINKLED, LOW))
|
||||
|
||||
// Arduino Zero
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define BLINKLED LED_BUILTIN
|
||||
#define BLINKLED_ON() (digitalWrite(LED_BUILTIN, HIGH))
|
||||
#define BLINKLED_OFF() (digitalWrite(LED_BUILTIN, LOW))
|
||||
|
||||
#define USE_SOFT_SEND_PWM
|
||||
// Define to use spin wait instead of delayMicros()
|
||||
//#define USE_SPIN_WAIT
|
||||
// Supply own enableIRIn()
|
||||
#undef USE_DEFAULT_ENABLE_IR_IN
|
||||
|
||||
#elif defined(ESP32)
|
||||
// No system LED on ESP32, disable blinking by NOT defining BLINKLED
|
||||
|
||||
// Supply own enableIRIn() and enableIROut()
|
||||
#undef USE_DEFAULT_ENABLE_IR_IN
|
||||
#undef USE_DEFAULT_ENABLE_IR_OUT
|
||||
|
||||
#else
|
||||
#warning No blinking definition found. Check IRremoteBoardDefs.h.
|
||||
#ifdef LED_BUILTIN
|
||||
#define BLINKLED LED_BUILTIN
|
||||
#define BLINKLED_ON() digitalWrite(BLINKLED, HIGH)
|
||||
#define BLINKLED_OFF() digitalWrite(BLINKLED, LOW)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// microseconds per clock interrupt tick
|
||||
#if ! defined(MICROS_PER_TICK)
|
||||
#define MICROS_PER_TICK 50
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Define which timer to use
|
||||
//
|
||||
// Uncomment the timer you wish to use on your board.
|
||||
// If you are using another library which uses timer2, you have options to
|
||||
// switch IRremote to use a different timer.
|
||||
//
|
||||
|
||||
#ifndef ARDUINO
|
||||
// Assume that we compile a test version, to be executed on the host,
|
||||
// not on a board.
|
||||
|
||||
// Do not define any timer.
|
||||
|
||||
/*********************
|
||||
* ARDUINO Boards
|
||||
*********************/
|
||||
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
|
||||
// ATmega48, ATmega88, ATmega168, ATmega328
|
||||
#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__) // old default clause
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER2)
|
||||
//#define IR_USE_TIMER1 // tx = pin 9
|
||||
#define IR_USE_TIMER2 // tx = pin 3
|
||||
# endif
|
||||
|
||||
// Arduino Mega
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER2) && !defined(IR_USE_TIMER3) && !defined(IR_USE_TIMER4) && !defined(IR_USE_TIMER5)
|
||||
//#define IR_USE_TIMER1 // tx = pin 11
|
||||
#define IR_USE_TIMER2 // tx = pin 9
|
||||
//#define IR_USE_TIMER3 // tx = pin 5
|
||||
//#define IR_USE_TIMER4 // tx = pin 6
|
||||
//#define IR_USE_TIMER5 // tx = pin 46
|
||||
# endif
|
||||
|
||||
// Leonardo
|
||||
#elif defined(__AVR_ATmega32U4__) && ! defined(TEENSYDUINO) && ! defined(ARDUINO_AVR_PROMICRO)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER3) && !defined(IR_USE_TIMER4_HS)
|
||||
//#define IR_USE_TIMER1 // tx = pin 9
|
||||
#define IR_USE_TIMER3 // tx = pin 5
|
||||
//#define IR_USE_TIMER4_HS // tx = pin 13
|
||||
# endif
|
||||
|
||||
// Nano Every, Uno WiFi Rev2
|
||||
#elif defined(__AVR_ATmega4809__)
|
||||
# if !defined(IR_USE_TIMER_4809_1) && !defined(IR_USE_TIMER_4809_2)
|
||||
#define IR_USE_TIMER_4809_1 // tx = pin 24
|
||||
//#define IR_USE_TIMER_4809_2 // TODO tx = pin 21
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* Plain AVR CPU's
|
||||
*********************/
|
||||
// ATmega8u2, ATmega16U2, ATmega32U2
|
||||
#elif defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin C6
|
||||
#endif
|
||||
|
||||
// Atmega8
|
||||
#elif defined(__AVR_ATmega8__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin 9
|
||||
# endif
|
||||
|
||||
|
||||
// ATtiny84
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin 6
|
||||
# endif
|
||||
|
||||
//ATtiny85
|
||||
#elif defined(__AVR_ATtiny85__)
|
||||
# if !defined(IR_USE_TIMER_TINY0)
|
||||
#define IR_USE_TIMER_TINY0 // tx = pin 1
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* SPARKFUN Boards
|
||||
*********************/
|
||||
// Sparkfun Pro Micro
|
||||
#elif defined(ARDUINO_AVR_PROMICRO)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER3) && !defined(IR_USE_TIMER4_HS)
|
||||
//#define IR_USE_TIMER1 // tx = pin 9
|
||||
#define IR_USE_TIMER3 // tx = pin 5
|
||||
//#define IR_USE_TIMER4_HS // tx = pin 13
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* TEENSY Boards
|
||||
*********************/
|
||||
// Teensy 1.0
|
||||
#elif defined(__AVR_AT90USB162__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin 17
|
||||
# endif
|
||||
|
||||
// Teensy 2.0
|
||||
#elif defined(__AVR_ATmega32U4__) && defined(TEENSYDUINO)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER3) && !defined(IR_USE_TIMER4_HS)
|
||||
//#define IR_USE_TIMER1 // tx = pin 14 (Teensy 2.0 - physical pin: B5)
|
||||
#define IR_USE_TIMER3 // tx = pin 9 (Teensy 2.0 - physical pin: C6)
|
||||
//#define IR_USE_TIMER4_HS // tx = pin 10 (Teensy 2.0 - physical pin: C7)
|
||||
# endif
|
||||
|
||||
// Teensy 3.0 / Teensy 3.1
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
# if !defined(IR_USE_TIMER_CMT)
|
||||
#define IR_USE_TIMER_CMT // tx = pin 5
|
||||
# endif
|
||||
|
||||
// Teensy-LC
|
||||
#elif defined(__MKL26Z64__)
|
||||
# if !defined(IR_USE_TIMER_TPM1)
|
||||
#define IR_USE_TIMER_TPM1 // tx = pin 16
|
||||
# endif
|
||||
|
||||
// Teensy++ 1.0 & 2.0
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER2) && !defined(IR_USE_TIMER3)
|
||||
//#define IR_USE_TIMER1 // tx = pin 25
|
||||
#define IR_USE_TIMER2 // tx = pin 1
|
||||
//#define IR_USE_TIMER3 // tx = pin 16
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* CPU's with MegaCore
|
||||
*********************/
|
||||
// MegaCore - ATmega64, ATmega128
|
||||
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin 13
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* CPU's with MajorCore
|
||||
*********************/
|
||||
#elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER3)
|
||||
#define IR_USE_TIMER1 // tx = pin 13
|
||||
//#define IR_USE_TIMER3 // tx = pin 12 - ATmega162 only
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* CPU's with MightyCore
|
||||
*********************/
|
||||
// MightyCore - ATmega1284
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER2) && !defined(IR_USE_TIMER3)
|
||||
//#define IR_USE_TIMER1 // tx = pin 13
|
||||
#define IR_USE_TIMER2 // tx = pin 14
|
||||
//#define IR_USE_TIMER3 // tx = pin 6
|
||||
# endif
|
||||
|
||||
// MightyCore - ATmega164, ATmega324, ATmega644
|
||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
|
||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
|
||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
|
||||
|| defined(__AVR_ATmega164P__)
|
||||
# if !defined(IR_USE_TIMER1) && !defined(IR_USE_TIMER2)
|
||||
//#define IR_USE_TIMER1 // tx = pin 13
|
||||
#define IR_USE_TIMER2 // tx = pin 14
|
||||
# endif
|
||||
|
||||
// MightyCore - ATmega8535, ATmega16, ATmega32
|
||||
#elif defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
|
||||
# if !defined(IR_USE_TIMER1)
|
||||
#define IR_USE_TIMER1 // tx = pin 13
|
||||
# endif
|
||||
|
||||
/*********************
|
||||
* OTHER CPU's
|
||||
*********************/
|
||||
#elif defined(ESP32)
|
||||
# if !defined(IR_USE_TIMER_ESP32)
|
||||
#define IR_USE_TIMER_ESP32
|
||||
# endif
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
#define TIMER_PRESCALER_DIV 64
|
||||
|
||||
#elif defined(NRF5) // nRF5 BBC MicroBit
|
||||
// It uses Timer2 so you cannot use the Adafruit_Microbit display driver
|
||||
// Sending not implemented
|
||||
#undef SENDING_SUPPORTED
|
||||
|
||||
// Supply own enbleIRIn
|
||||
#undef USE_DEFAULT_ENABLE_IR_IN
|
||||
|
||||
#else
|
||||
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
|
||||
// ATmega48, ATmega88, ATmega168, ATmega328
|
||||
#define IR_USE_TIMER1 // tx = pin 9
|
||||
#warning Board could not be identified from pre-processor symbols. By Default, TIMER1 has been selected for use with IRremote. Please extend IRremoteBoardDefs.h.
|
||||
#endif
|
||||
|
||||
// Provide default definitions, portable but possibly slower than necessary.
|
||||
// digitalWrite is supposed to be slow. If this is an issue, define faster,
|
||||
// board-dependent versions of these macros SENDPIN_ON(pin) and SENDPIN_OFF(pin).
|
||||
// Portable, possibly slow, default definitions are given at the end of this file.
|
||||
// If defining new versions, feel free to ignore the pin argument if it
|
||||
// is not configurable on the current board.
|
||||
|
||||
#ifndef SENDPIN_ON
|
||||
/** Board dependent macro to turn on the pin given as argument. */
|
||||
#define SENDPIN_ON(pin) digitalWrite(pin, HIGH)
|
||||
#endif
|
||||
|
||||
#ifndef SENDPIN_OFF
|
||||
/**
|
||||
* Board dependent macro to turn off the pin given as argument.
|
||||
*/
|
||||
#define SENDPIN_OFF(pin) digitalWrite(pin, LOW)
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CPU Frequency
|
||||
//
|
||||
#if !defined(SYSCLOCK) && defined(ARDUINO) // allow for processor specific code to define SYSCLOCK
|
||||
#ifndef F_CPU
|
||||
#error SYSCLOCK or F_CPU cannot be determined. Define it for your board in IRremoteBoardDefs.h.
|
||||
#endif // ! F_CPU
|
||||
/**
|
||||
* Clock frequency to be used for timing.
|
||||
*/
|
||||
#define SYSCLOCK F_CPU // main Arduino clock
|
||||
#endif // ! SYSCLOCK
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines for Timer
|
||||
|
||||
// We define static board specific functions here, but they are only used in a few files.
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
//---------------------------------------------------------
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* If applicable, pin number for sending IR. Note that in most cases, this is not
|
||||
* used and ignored if set. Instead, the sending pin is determined by the timer
|
||||
* deployed.
|
||||
*/
|
||||
#define IR_SEND_PIN
|
||||
|
||||
/**
|
||||
* Interrupt service routine. Called as interrupt routine to collect read IR data.
|
||||
*/
|
||||
#define ISR
|
||||
|
||||
#elif ! defined(ARDUINO)
|
||||
// Assume that we compile a test version, to be executed on the host,
|
||||
// not on a board.
|
||||
// Do nothing.
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void do_not_use__(void)
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer2 (8 bits)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER2)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR2A |= _BV(COM2B1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR2A &= ~(_BV(COM2B1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK2 = _BV(OCIE2A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK2 = 0)
|
||||
#define TIMER_INTR_NAME TIMER2_COMPA_vect
|
||||
// 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
|
||||
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
/*
|
||||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
*/
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint16_t pwmval = (SYSCLOCK / 2000) / (frequency);
|
||||
TCCR2A = _BV(WGM20);
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20);
|
||||
OCR2A = pwmval;
|
||||
OCR2B = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
#define TIMER_COUNT_TOP (SYSCLOCK * MICROS_PER_TICK / 1000000)
|
||||
/*
|
||||
* timerConfigForReceive() is used exclusively by IRrecv::enableIRIn()
|
||||
* It generates an interrupt each 50 (MICROS_PER_TICK) us.
|
||||
*/
|
||||
static void timerConfigForReceive() {
|
||||
#if (TIMER_COUNT_TOP < 256)
|
||||
TCCR2A = _BV(WGM21);
|
||||
TCCR2B = _BV(CS20);
|
||||
OCR2A = TIMER_COUNT_TOP;
|
||||
TCNT2 = 0;
|
||||
#else
|
||||
TCCR2A = _BV(WGM21);
|
||||
TCCR2B = _BV(CS21);
|
||||
OCR2A = TIMER_COUNT_TOP / 8;
|
||||
TCNT2 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC2B_PIN)
|
||||
#define IR_SEND_PIN CORE_OC2B_PIN // Teensy
|
||||
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define IR_SEND_PIN 9 // Arduino Mega
|
||||
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
|
||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
|
||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
|
||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
|
||||
|| defined(__AVR_ATmega164P__)
|
||||
#define IR_SEND_PIN 14 // MightyCore, MegaCore
|
||||
|
||||
#else
|
||||
#define IR_SEND_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc
|
||||
#endif // defined(CORE_OC2B_PIN)
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer1 (16 bits)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER1)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR1A |= _BV(COM1A1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR1A &= ~(_BV(COM1A1)))
|
||||
|
||||
//-----------------
|
||||
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8515__) \
|
||||
|| defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) \
|
||||
|| defined(__AVR_ATmega32__) || defined(__AVR_ATmega64__) \
|
||||
|| defined(__AVR_ATmega128__) || defined(__AVR_ATmega162__)
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK |= _BV(OCIE1A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK &= ~_BV(OCIE1A))
|
||||
#else
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK1 = _BV(OCIE1A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK1 = 0)
|
||||
#endif
|
||||
|
||||
//-----------------
|
||||
#define TIMER_INTR_NAME TIMER1_COMPA_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR1A = _BV(WGM11);
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
ICR1 = pwmval;
|
||||
OCR1A = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCCR1A = 0;
|
||||
TCCR1B = _BV(WGM12) | _BV(CS10);
|
||||
OCR1A = SYSCLOCK * MICROS_PER_TICK / 1000000;
|
||||
TCNT1 = 0;
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC1A_PIN)
|
||||
#define IR_SEND_PIN CORE_OC1A_PIN // Teensy
|
||||
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define IR_SEND_PIN 11 // Arduino Mega
|
||||
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
|
||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
|
||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
|
||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
|
||||
|| defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \
|
||||
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \
|
||||
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \
|
||||
|| defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \
|
||||
|| defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
|
||||
#define IR_SEND_PIN 13 // MightyCore, MegaCore, MajorCore
|
||||
|
||||
#elif defined(__AVR_ATtiny84__)
|
||||
# define IR_SEND_PIN 6
|
||||
|
||||
#else
|
||||
#define IR_SEND_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, Sparkfun Pro Micro, Leonardo etc.
|
||||
#endif // defined(CORE_OC1A_PIN)
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer3 (16 bits)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER3)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR3A |= _BV(COM3A1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR3A &= ~(_BV(COM3A1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK3 = _BV(OCIE3A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK3 = 0)
|
||||
#define TIMER_INTR_NAME TIMER3_COMPA_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR3A = _BV(WGM31);
|
||||
TCCR3B = _BV(WGM33) | _BV(CS30);
|
||||
ICR3 = pwmval;
|
||||
OCR3A = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCCR3A = 0;
|
||||
TCCR3B = _BV(WGM32) | _BV(CS30);
|
||||
OCR3A = SYSCLOCK * MICROS_PER_TICK / 1000000;
|
||||
TCNT3 = 0;
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC3A_PIN)
|
||||
#define IR_SEND_PIN CORE_OC3A_PIN // Teensy
|
||||
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) \
|
||||
|| defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_PROMICRO)
|
||||
#define IR_SEND_PIN 5 // Arduino Mega, Arduino Leonardo, Sparkfun Pro Micro
|
||||
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||
#define IR_SEND_PIN 6 // MightyCore, MegaCore
|
||||
|
||||
#else
|
||||
#error "Please add OC3A pin number here\n"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer4 (10 bits, high speed option)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER4_HS)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR4A |= _BV(COM4A0)) // Use complimentary O̅C̅4̅A̅ output on pin 5
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR4A &= ~(_BV(COM4A0))) // (Pro Micro does not map PC7 (32/ICP3/CLK0/OC4A)
|
||||
// of ATmega32U4 )
|
||||
#else
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR4A |= _BV(COM4A1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
||||
#endif
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK4 = _BV(TOIE4))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK4 = 0)
|
||||
#define TIMER_INTR_NAME TIMER4_OVF_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR4A = (1 << PWM4A);
|
||||
TCCR4B = _BV(CS40);
|
||||
TCCR4C = 0;
|
||||
TCCR4D = (1 << WGM40);
|
||||
TCCR4E = 0;
|
||||
TC4H = pwmval >> 8;
|
||||
OCR4C = pwmval;
|
||||
TC4H = (pwmval * IR_SEND_DUTY_CYCLE / 100) >> 8;
|
||||
OCR4A = (pwmval * IR_SEND_DUTY_CYCLE / 100) & 255;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCCR4A = 0;
|
||||
TCCR4B = _BV(CS40);
|
||||
TCCR4C = 0;
|
||||
TCCR4D = 0;
|
||||
TCCR4E = 0;
|
||||
TC4H = (SYSCLOCK * MICROS_PER_TICK / 1000000) >> 8;
|
||||
OCR4C = (SYSCLOCK * MICROS_PER_TICK / 1000000) & 255;
|
||||
TC4H = 0;
|
||||
TCNT4 = 0;
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC4A_PIN)
|
||||
#define IR_SEND_PIN CORE_OC4A_PIN // Teensy
|
||||
#elif defined(ARDUINO_AVR_PROMICRO)
|
||||
#define IR_SEND_PIN 5 // Sparkfun Pro Micro
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define IR_SEND_PIN 13 // Leonardo
|
||||
#else
|
||||
#error "Please add OC4A pin number here\n"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer4 (16 bits)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER4)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR4A |= _BV(COM4A1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK4 = _BV(OCIE4A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK4 = 0)
|
||||
#define TIMER_INTR_NAME TIMER4_COMPA_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR4A = _BV(WGM41);
|
||||
TCCR4B = _BV(WGM43) | _BV(CS40);
|
||||
ICR4 = pwmval;
|
||||
OCR4A = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCCR4A = 0;
|
||||
TCCR4B = _BV(WGM42) | _BV(CS40);
|
||||
OCR4A = SYSCLOCK * MICROS_PER_TICK / 1000000;
|
||||
TCNT4 = 0;
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC4A_PIN)
|
||||
#define IR_SEND_PIN CORE_OC4A_PIN
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define IR_SEND_PIN 6 // Arduino Mega
|
||||
#else
|
||||
#error "Please add OC4A pin number here\n"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Timer5 (16 bits)
|
||||
//
|
||||
#elif defined(IR_USE_TIMER5)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR5A |= _BV(COM5A1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR5A &= ~(_BV(COM5A1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK5 = _BV(OCIE5A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK5 = 0)
|
||||
#define TIMER_INTR_NAME TIMER5_COMPA_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR5A = _BV(WGM51);
|
||||
TCCR5B = _BV(WGM53) | _BV(CS50);
|
||||
ICR5 = pwmval;
|
||||
OCR5A = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCCR5A = 0;
|
||||
TCCR5B = _BV(WGM52) | _BV(CS50);
|
||||
OCR5A = SYSCLOCK * MICROS_PER_TICK / 1000000;
|
||||
TCNT5 = 0;
|
||||
}
|
||||
|
||||
//-----------------
|
||||
#if defined(CORE_OC5A_PIN)
|
||||
#define IR_SEND_PIN CORE_OC5A_PIN
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define IR_SEND_PIN 46 // Arduino Mega
|
||||
#else
|
||||
#error "Please add OC5A pin number here\n"
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Special carrier modulator timer for Teensy 3.0 / Teensy 3.1
|
||||
//
|
||||
#elif defined(IR_USE_TIMER_CMT)
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING ({ \
|
||||
uint8_t tmp __attribute__((unused)) = CMT_MSC; \
|
||||
CMT_CMD2 = 30; \
|
||||
})
|
||||
|
||||
#define TIMER_ENABLE_SEND_PWM do { \
|
||||
CORE_PIN5_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE | PORT_PCR_SRE; \
|
||||
} while(0)
|
||||
|
||||
#define TIMER_DISABLE_SEND_PWM do { \
|
||||
CORE_PIN5_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE; \
|
||||
} while(0)
|
||||
|
||||
#define TIMER_ENABLE_RECEIVE_INTR NVIC_ENABLE_IRQ(IRQ_CMT)
|
||||
#define TIMER_DISABLE_RECEIVE_INTR NVIC_DISABLE_IRQ(IRQ_CMT)
|
||||
#define TIMER_INTR_NAME cmt_isr
|
||||
|
||||
//-----------------
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void do_not_use__(void)
|
||||
|
||||
//-----------------
|
||||
#define CMT_PPS_DIV ((F_BUS + 7999999) / 8000000)
|
||||
#if F_BUS < 8000000
|
||||
#error IRremote requires at least 8 MHz on Teensy 3.x
|
||||
#endif
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
SIM_SCGC4 |= SIM_SCGC4_CMT;
|
||||
SIM_SOPT2 |= SIM_SOPT2_PTD7PAD;
|
||||
CMT_PPS = CMT_PPS_DIV - 1;
|
||||
CMT_CGH1 = ((F_BUS / CMT_PPS_DIV / 3000) + ((frequency) / 2)) / (frequency);
|
||||
CMT_CGL1 = ((F_BUS / CMT_PPS_DIV / 1500) + ((frequency) / 2)) / (frequency);
|
||||
CMT_CMD1 = 0;
|
||||
CMT_CMD2 = 30;
|
||||
CMT_CMD3 = 0;
|
||||
CMT_CMD4 = 0;
|
||||
CMT_OC = 0x60;
|
||||
CMT_MSC = 0x01;
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
SIM_SCGC4 |= SIM_SCGC4_CMT;
|
||||
CMT_PPS = CMT_PPS_DIV - 1;
|
||||
CMT_CGH1 = 1;
|
||||
CMT_CGL1 = 1;
|
||||
CMT_CMD1 = 0;
|
||||
CMT_CMD2 = 30;
|
||||
CMT_CMD3 = 0;
|
||||
CMT_CMD4 = (F_BUS / 160000 + CMT_PPS_DIV / 2) / CMT_PPS_DIV - 31;
|
||||
CMT_OC = 0;
|
||||
CMT_MSC = 0x03;
|
||||
}
|
||||
|
||||
#define IR_SEND_PIN 5
|
||||
|
||||
// defines for TPM1 timer on Teensy-LC
|
||||
#elif defined(IR_USE_TIMER_TPM1)
|
||||
#define TIMER_RESET_INTR_PENDING FTM1_SC |= FTM_SC_TOF;
|
||||
#define TIMER_ENABLE_SEND_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE
|
||||
#define TIMER_DISABLE_SEND_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE
|
||||
#define TIMER_ENABLE_RECEIVE_INTR NVIC_ENABLE_IRQ(IRQ_FTM1)
|
||||
#define TIMER_DISABLE_RECEIVE_INTR NVIC_DISABLE_IRQ(IRQ_FTM1)
|
||||
#define TIMER_INTR_NAME ftm1_isr
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void do_not_use__(void)
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
SIM_SCGC6 |= SIM_SCGC6_TPM1;
|
||||
FTM1_SC = 0;
|
||||
FTM1_CNT = 0;
|
||||
FTM1_MOD = (F_PLL / 2000) / frequency - 1;
|
||||
FTM1_C0V = (F_PLL / 6000) / frequency - 1;
|
||||
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0);
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
SIM_SCGC6 |= SIM_SCGC6_TPM1;
|
||||
FTM1_SC = 0;
|
||||
FTM1_CNT = 0;
|
||||
FTM1_MOD = (F_PLL / 40000) - 1;
|
||||
FTM1_C0V = 0;
|
||||
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0) | FTM_SC_TOF | FTM_SC_TOIE;
|
||||
}
|
||||
#define IR_SEND_PIN 16
|
||||
|
||||
// defines for timer_tiny0 (8 bits)
|
||||
#elif defined(IR_USE_TIMER_TINY0)
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR0A |= _BV(COM0B1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR0A &= ~(_BV(COM0B1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK |= _BV(OCIE0A))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK &= ~(_BV(OCIE0A)))
|
||||
#define TIMER_INTR_NAME TIMER0_COMPA_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint16_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR0A = _BV(WGM00);
|
||||
TCCR0B = _BV(WGM02) | _BV(CS00);
|
||||
OCR0A = pwmval;
|
||||
OCR0B = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
#define TIMER_COUNT_TOP (SYSCLOCK * MICROS_PER_TICK / 1000000)
|
||||
static void timerConfigForReceive() {
|
||||
#if (TIMER_COUNT_TOP < 256)
|
||||
TCCR0A = _BV(WGM01);
|
||||
TCCR0B = _BV(CS00);
|
||||
OCR0A = TIMER_COUNT_TOP;
|
||||
TCNT0 = 0;
|
||||
#else
|
||||
TCCR0A = _BV(WGM01);
|
||||
TCCR0B = _BV(CS01);
|
||||
OCR0A = TIMER_COUNT_TOP / 8;
|
||||
TCNT0 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define IR_SEND_PIN 1
|
||||
|
||||
// work in progress- defines for timer_tiny1 (8 bits)
|
||||
#elif defined(IR_USE_TIMER_TINY1)
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM (TCCR1 |= _BV(CTC1))
|
||||
#define TIMER_DISABLE_SEND_PWM (TCCR0A &= ~(_BV(COM0B1)))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TIMSK |= _BV(OCIE1B))
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TIMSK &= ~(_BV(OCIE1B)))
|
||||
#define TIMER_INTR_NAME TIMER1_COMPB_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint16_t pwmval = SYSCLOCK / 2000 / (frequency);
|
||||
TCCR0A = _BV(WGM00);
|
||||
TCCR0B = _BV(WGM02) | _BV(CS00);
|
||||
OCR0A = pwmval;
|
||||
OCR0B = pwmval * IR_SEND_DUTY_CYCLE / 100;
|
||||
}
|
||||
|
||||
#define IR_SEND_PIN 1
|
||||
|
||||
#elif defined(IR_USE_TIMER_4809_1)
|
||||
// ATmega4809 TCB0
|
||||
#define TIMER_RESET_INTR_PENDING TCB0.INTFLAGS = TCB_CAPT_bm
|
||||
#define TIMER_ENABLE_SEND_PWM (TCB0.CTRLB |= TCB_CCMPEN_bm)
|
||||
#define TIMER_DISABLE_SEND_PWM (TCB0.CTRLB &= ~(TCB_CCMPEN_bm))
|
||||
#define TIMER_ENABLE_RECEIVE_INTR (TCB0.INTCTRL = TCB_CAPT_bm)
|
||||
#define TIMER_DISABLE_RECEIVE_INTR (TCB0.INTCTRL &= ~(TCB_CAPT_bm))
|
||||
#define TIMER_INTR_NAME TCB0_INT_vect
|
||||
|
||||
static void timerConfigForSend(uint16_t frequency) {
|
||||
const uint32_t pwmval = (SYSCLOCK / 2000) / (frequency);
|
||||
TCB0.CTRLB = TCB_CNTMODE_PWM8_gc;
|
||||
TCB0.CCMPL = pwmval;
|
||||
TCB0.CCMPH = (pwmval * IR_SEND_DUTY_CYCLE) / 100;
|
||||
TCB0.CTRLA = (TCB_CLKSEL_CLKDIV2_gc) | (TCB_ENABLE_bm);
|
||||
}
|
||||
|
||||
static void timerConfigForReceive() {
|
||||
TCB0.CTRLB = (TCB_CNTMODE_INT_gc);
|
||||
TCB0.CCMP = ((SYSCLOCK * MICROS_PER_TICK) / 1000000);
|
||||
TCB0.INTCTRL = TCB_CAPT_bm;
|
||||
TCB0.CTRLA = (TCB_CLKSEL_CLKDIV1_gc) | (TCB_ENABLE_bm);
|
||||
}
|
||||
|
||||
#define IR_SEND_PIN 6 /* Nano Every, Uno WiFi Rev2 */
|
||||
//---------------------------------------------------------
|
||||
// ESP32 (ESP8266 should likely be added here too)
|
||||
//
|
||||
|
||||
// ESP32 has it own timer API and does not use these macros, but to avoid ifdef'ing
|
||||
// them out in the common code, they are defined to no-op. This allows the code to compile
|
||||
// (which it wouldn't otherwise) but irsend will not work until ESP32 specific code is written
|
||||
//
|
||||
// The timer code is in the esp32.cpp file
|
||||
//
|
||||
// An IRremote version for ESP8266 and ESP32 is available at https://github.com/crankyoldgit/IRremoteESP8266
|
||||
#elif defined(IR_USE_TIMER_ESP32)
|
||||
|
||||
#if ! defined(IR_SEND_PIN)
|
||||
#define IR_SEND_PIN 4 // can use any pin, no timer restrictions
|
||||
#endif
|
||||
|
||||
#if ! defined(LED_CHANNEL)
|
||||
#define LED_CHANNEL 0 // The channel used for PWM 0 to 7 are high speed PWM channels
|
||||
#endif
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM ledcWrite(LED_CHANNEL, IR_SEND_DUTY_CYCLE) // we must use channel here not pin number
|
||||
#define TIMER_DISABLE_SEND_PWM ledcWrite(LED_CHANNEL, 0)
|
||||
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void IRAM_ATTR IRTimer()
|
||||
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
// use timer 3 hardcoded at this time
|
||||
|
||||
#define IR_SEND_PIN 9
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
#define TIMER_ENABLE_SEND_PWM // Not presently used
|
||||
#define TIMER_DISABLE_SEND_PWM
|
||||
#define TIMER_ENABLE_RECEIVE_INTR NVIC_EnableIRQ(TC3_IRQn) // Not presently used
|
||||
#define TIMER_DISABLE_RECEIVE_INTR NVIC_DisableIRQ(TC3_IRQn)
|
||||
#define TIMER_INTR_NAME TC3_Handler // Not presently used
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
static void timerConfigForSend(uint16_t frequency __attribute__((unused))) {}
|
||||
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void IRTimer(void)
|
||||
|
||||
#elif defined(NRF5) || defined (ARDUINO_ARCH_NRF52840)
|
||||
// The default pin used used for sending. 3, A0 - left pad
|
||||
#define IR_SEND_PIN 3 // dummy since sending not yet supported
|
||||
|
||||
#define TIMER_RESET_INTR_PENDING
|
||||
|
||||
#ifdef ISR
|
||||
#undef ISR
|
||||
#endif
|
||||
#define ISR(f) void IRTimer(void)
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Unknown Timer
|
||||
//
|
||||
#else
|
||||
#error "Internal code configuration error, no known IR_USE_TIMER* defined\n"
|
||||
#endif
|
||||
|
||||
#endif // ! IRremoteBoardDefs_h
|
||||
117
trunk/Arduino/libraries/IRremote/src/private/IRremoteInt.h
Normal file
117
trunk/Arduino/libraries/IRremote/src/private/IRremoteInt.h
Normal file
@@ -0,0 +1,117 @@
|
||||
//******************************************************************************
|
||||
// IRremoteint.h
|
||||
// IRremote
|
||||
// Version 2.0.1 June, 2015
|
||||
// Copyright 2009 Ken Shirriff
|
||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
|
||||
//
|
||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
|
||||
//
|
||||
// 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/
|
||||
//
|
||||
// JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
|
||||
// Whynter A/C ARC-110WD added by Francesco Meschia
|
||||
//******************************************************************************
|
||||
|
||||
#ifndef IRremoteint_h
|
||||
#define IRremoteint_h
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Include the Arduino header
|
||||
//
|
||||
#include <Arduino.h>
|
||||
|
||||
// All board specific stuff have been moved to its own file, included here.
|
||||
#include "IRremoteBoardDefs.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Information for the Interrupt Service Routine
|
||||
//
|
||||
#if ! defined(RAW_BUFFER_LENGTH)
|
||||
#define RAW_BUFFER_LENGTH 101 ///< Maximum length of raw duration buffer. Must be odd.
|
||||
#endif
|
||||
|
||||
// ISR State-Machine : Receiver States
|
||||
#define IR_REC_STATE_IDLE 0
|
||||
#define IR_REC_STATE_MARK 1
|
||||
#define IR_REC_STATE_SPACE 2
|
||||
#define IR_REC_STATE_STOP 3
|
||||
|
||||
/**
|
||||
* This struct is used for the ISR (interrupt service routine)
|
||||
* and is copied once only in state STATE_STOP, so only rcvstate needs to be volatile.
|
||||
*/
|
||||
struct irparams_struct {
|
||||
// The fields are ordered to reduce memory over caused by struct-padding
|
||||
volatile uint8_t rcvstate; ///< State Machine state
|
||||
uint8_t recvpin; ///< Pin connected to IR data from detector
|
||||
uint8_t blinkpin;
|
||||
uint8_t blinkflag; ///< true -> enable blinking of pin on IR processing
|
||||
unsigned int rawlen; ///< counter of entries in rawbuf
|
||||
unsigned int timer; ///< State timer, counts 50uS ticks.
|
||||
unsigned int rawbuf[RAW_BUFFER_LENGTH]; ///< raw data
|
||||
uint8_t overflow; ///< Raw buffer overflow occurred
|
||||
};
|
||||
|
||||
extern struct irparams_struct irparams;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines for setting and clearing register bits
|
||||
//
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Pulse parms are ((X*50)-100) for the Mark and ((X*50)+100) for the Space.
|
||||
// First MARK is the one after the long gap
|
||||
// Pulse parameters in uSec
|
||||
//
|
||||
|
||||
/**
|
||||
* When received, marks tend to be too long and
|
||||
* spaces tend to be too short.
|
||||
* To compensate for this, MARK_EXCESS_MICROS is subtracted from all marks,
|
||||
* and added to all spaces.
|
||||
*/
|
||||
#define MARK_EXCESS_MICROS 100
|
||||
|
||||
/** Relative tolerance (in percent) for some comparisons on measured data. */
|
||||
#define TOLERANCE 25
|
||||
|
||||
/** Lower tolerance for comparison of measured data */
|
||||
//#define LTOL (1.0 - (TOLERANCE/100.))
|
||||
#define LTOL (100 - TOLERANCE)
|
||||
/** Upper tolerance for comparison of measured data */
|
||||
//#define UTOL (1.0 + (TOLERANCE/100.))
|
||||
#define UTOL (100 + TOLERANCE)
|
||||
|
||||
/** Minimum gap between IR transmissions, in microseconds */
|
||||
#define _GAP 5000
|
||||
|
||||
/** Minimum gap between IR transmissions, in MICROS_PER_TICK */
|
||||
#define GAP_TICKS (_GAP/MICROS_PER_TICK)
|
||||
|
||||
//#define TICKS_LOW(us) ((int)(((us)*LTOL/MICROS_PER_TICK)))
|
||||
//#define TICKS_HIGH(us) ((int)(((us)*UTOL/MICROS_PER_TICK + 1)))
|
||||
#if MICROS_PER_TICK == 50 && TOLERANCE == 25 // Defaults
|
||||
#define TICKS_LOW(us) ((int) ((us)/67 )) // (us) / ((MICROS_PER_TICK:50 / LTOL:75 ) * 100)
|
||||
#define TICKS_HIGH(us) ((int) ((us)/40 + 1)) // (us) / ((MICROS_PER_TICK:50 / UTOL:125) * 100) + 1
|
||||
#else
|
||||
#define TICKS_LOW(us) ((int) ((long) (us) * LTOL / (MICROS_PER_TICK * 100) ))
|
||||
#define TICKS_HIGH(us) ((int) ((long) (us) * UTOL / (MICROS_PER_TICK * 100) + 1))
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IR detector output is active low
|
||||
//
|
||||
#define MARK 0 ///< Sensor output for a mark ("flash")
|
||||
#define SPACE 1 ///< Sensor output for a space ("gap")
|
||||
|
||||
#endif
|
||||
100
trunk/Arduino/libraries/IRremote/src/sam.cpp
Normal file
100
trunk/Arduino/libraries/IRremote/src/sam.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
// Support routines for SAM processor boards
|
||||
|
||||
#include "IRremote.h"
|
||||
|
||||
// "Idiot check"
|
||||
#ifdef USE_DEFAULT_ENABLE_IR_IN
|
||||
#error Must undef USE_DEFAULT_ENABLE_IR_IN
|
||||
#endif
|
||||
|
||||
//+=============================================================================
|
||||
// ATSAMD Timer setup & IRQ functions
|
||||
//
|
||||
|
||||
// following based on setup from GitHub jdneo/timerInterrupt.ino
|
||||
|
||||
static void setTimerFrequency(int frequencyHz) {
|
||||
int compareValue = (SYSCLOCK / (TIMER_PRESCALER_DIV * frequencyHz)) - 1;
|
||||
//Serial.println(compareValue);
|
||||
TcCount16* TC = (TcCount16*) TC3;
|
||||
// Make sure the count is in a proportional position to where it was
|
||||
// to prevent any jitter or disconnect when changing the compare value.
|
||||
TC->COUNT.reg = map(TC->COUNT.reg, 0, TC->CC[0].reg, 0, compareValue);
|
||||
TC->CC[0].reg = compareValue;
|
||||
//Serial.print("COUNT.reg ");
|
||||
//Serial.println(TC->COUNT.reg);
|
||||
//Serial.print("CC[0].reg ");
|
||||
//Serial.println(TC->CC[0].reg);
|
||||
while (TC->STATUS.bit.SYNCBUSY == 1)
|
||||
;
|
||||
}
|
||||
|
||||
static void startTimer() {
|
||||
REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3);
|
||||
while (GCLK->STATUS.bit.SYNCBUSY == 1)
|
||||
; // wait for sync
|
||||
|
||||
TcCount16* TC = (TcCount16*) TC3;
|
||||
|
||||
// The TC should be disabled before the TC is reset in order to avoid undefined behavior.
|
||||
TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
|
||||
// When write-synchronization is ongoing for a register, any subsequent write attempts to this register will be discarded, and an error will be reported.
|
||||
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||
// Reset TCx
|
||||
TC->CTRLA.reg = TC_CTRLA_SWRST;
|
||||
// When writing a ‘1’ to the CTRLA.SWRST bit it will immediately read as ‘1’.
|
||||
// CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
|
||||
while (TC->CTRLA.bit.SWRST)
|
||||
;
|
||||
|
||||
// Use the 16-bit timer
|
||||
// Use match mode so that the timer counter resets when the count matches the compare register
|
||||
// Set prescaler to 64
|
||||
TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV64 | TC_CTRLA_ENABLE;
|
||||
|
||||
setTimerFrequency(1000000 / MICROS_PER_TICK);
|
||||
|
||||
// Enable the compare interrupt
|
||||
TC->INTENSET.reg = 0;
|
||||
TC->INTENSET.bit.MC0 = 1;
|
||||
|
||||
NVIC_EnableIRQ (TC3_IRQn);
|
||||
|
||||
}
|
||||
|
||||
//+=============================================================================
|
||||
// initialization
|
||||
//
|
||||
|
||||
void IRrecv::enableIRIn() {
|
||||
// Interrupt Service Routine - Fires every 50uS
|
||||
//Serial.println("Starting timer");
|
||||
startTimer();
|
||||
//Serial.println("Started timer");
|
||||
|
||||
// Initialize state machine variables
|
||||
irparams.rcvstate = IR_REC_STATE_IDLE;
|
||||
irparams.rawlen = 0;
|
||||
|
||||
// Set pin modes
|
||||
pinMode(irparams.recvpin, INPUT);
|
||||
}
|
||||
|
||||
void IRrecv::disableIRIn() {
|
||||
TC3->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
|
||||
}
|
||||
|
||||
void IRTimer(); // Defined in IRRemote as ISR(TIMER_INTR_NAME)
|
||||
|
||||
void TC3_Handler(void) {
|
||||
TcCount16* TC = (TcCount16*) TC3;
|
||||
// If this interrupt is due to the compare register matching the timer count
|
||||
// we toggle the LED.
|
||||
if (TC->INTFLAG.bit.MC0 == 1) {
|
||||
TC->INTFLAG.bit.MC0 = 1;
|
||||
IRTimer();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(ARDUINO_ARCH_SAMD)
|
||||
Reference in New Issue
Block a user