daily_automated

This commit is contained in:
topicchi
2023-03-17 11:59:21 +00:00
parent 252ecca9cf
commit e2f276193e
4496 changed files with 1178007 additions and 0 deletions

View 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
}

View 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

View 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

View 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);
}

View 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;
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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;
}
}
};

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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)