Hallo
This commit is contained in:
commit
d9714a88f1
198
IRremote/IRremote.cpp
Normal file
198
IRremote/IRremote.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
//******************************************************************************
|
||||||
|
// 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
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
// Defining IR_GLOBAL here allows us to declare the instantiation of global variables
|
||||||
|
#define IR_GLOBAL
|
||||||
|
# include "IRremote.h"
|
||||||
|
# include "IRremoteInt.h"
|
||||||
|
#undef IR_GLOBAL
|
||||||
|
|
||||||
|
#ifdef HAS_AVR_INTERRUPT_H
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
DBG_PRINT(F("Testing: "));
|
||||||
|
DBG_PRINT(TICKS_LOW(desired), DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(measured, DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(TICKS_HIGH(desired), DEC);
|
||||||
|
|
||||||
|
bool passed = ((measured >= TICKS_LOW(desired)) && (measured <= TICKS_HIGH(desired)));
|
||||||
|
if (passed)
|
||||||
|
DBG_PRINTLN(F("?; passed"));
|
||||||
|
else
|
||||||
|
DBG_PRINTLN(F("?; FAILED"));
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+========================================================
|
||||||
|
// Due to sensor lag, when received, Marks tend to be 100us too long
|
||||||
|
//
|
||||||
|
int MATCH_MARK (int measured_ticks, int desired_us)
|
||||||
|
{
|
||||||
|
DBG_PRINT(F("Testing mark (actual vs desired): "));
|
||||||
|
DBG_PRINT(measured_ticks * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F("us vs "));
|
||||||
|
DBG_PRINT(desired_us, DEC);
|
||||||
|
DBG_PRINT("us");
|
||||||
|
DBG_PRINT(": ");
|
||||||
|
DBG_PRINT(TICKS_LOW(desired_us + MARK_EXCESS) * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(measured_ticks * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(TICKS_HIGH(desired_us + MARK_EXCESS) * USECPERTICK, DEC);
|
||||||
|
|
||||||
|
bool passed = ((measured_ticks >= TICKS_LOW (desired_us + MARK_EXCESS))
|
||||||
|
&& (measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS)));
|
||||||
|
if (passed)
|
||||||
|
DBG_PRINTLN(F("?; passed"));
|
||||||
|
else
|
||||||
|
DBG_PRINTLN(F("?; FAILED"));
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+========================================================
|
||||||
|
// Due to sensor lag, when received, Spaces tend to be 100us too short
|
||||||
|
//
|
||||||
|
int MATCH_SPACE (int measured_ticks, int desired_us)
|
||||||
|
{
|
||||||
|
DBG_PRINT(F("Testing space (actual vs desired): "));
|
||||||
|
DBG_PRINT(measured_ticks * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F("us vs "));
|
||||||
|
DBG_PRINT(desired_us, DEC);
|
||||||
|
DBG_PRINT("us");
|
||||||
|
DBG_PRINT(": ");
|
||||||
|
DBG_PRINT(TICKS_LOW(desired_us - MARK_EXCESS) * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(measured_ticks * USECPERTICK, DEC);
|
||||||
|
DBG_PRINT(F(" <= "));
|
||||||
|
DBG_PRINT(TICKS_HIGH(desired_us - MARK_EXCESS) * USECPERTICK, DEC);
|
||||||
|
|
||||||
|
bool passed = ((measured_ticks >= TICKS_LOW (desired_us - MARK_EXCESS))
|
||||||
|
&& (measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS)));
|
||||||
|
if (passed)
|
||||||
|
DBG_PRINTLN(F("?; passed"));
|
||||||
|
else
|
||||||
|
DBG_PRINTLN(F("?; FAILED"));
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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 >= RAWBUF) irparams.rcvstate = STATE_OVERFLOW ; // Buffer overflow
|
||||||
|
|
||||||
|
switch(irparams.rcvstate) {
|
||||||
|
//......................................................................
|
||||||
|
case STATE_IDLE: // In the middle of a gap
|
||||||
|
if (irdata == MARK) {
|
||||||
|
if (irparams.timer < GAP_TICKS) { // Not big enough to be a gap.
|
||||||
|
irparams.timer = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Gap just ended; Record duration; Start recording transmission
|
||||||
|
irparams.overflow = false;
|
||||||
|
irparams.rawlen = 0;
|
||||||
|
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||||
|
irparams.timer = 0;
|
||||||
|
irparams.rcvstate = STATE_MARK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//......................................................................
|
||||||
|
case STATE_MARK: // Timing Mark
|
||||||
|
if (irdata == SPACE) { // Mark ended; Record time
|
||||||
|
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||||
|
irparams.timer = 0;
|
||||||
|
irparams.rcvstate = STATE_SPACE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//......................................................................
|
||||||
|
case STATE_SPACE: // Timing Space
|
||||||
|
if (irdata == MARK) { // Space just ended; Record time
|
||||||
|
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
|
||||||
|
irparams.timer = 0;
|
||||||
|
irparams.rcvstate = 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 = STATE_STOP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//......................................................................
|
||||||
|
case STATE_STOP: // Waiting; Measuring Gap
|
||||||
|
if (irdata == MARK) irparams.timer = 0 ; // Reset gap timer
|
||||||
|
break;
|
||||||
|
//......................................................................
|
||||||
|
case STATE_OVERFLOW: // Flag up a read overflow; Stop the State Machine
|
||||||
|
irparams.overflow = true;
|
||||||
|
irparams.rcvstate = STATE_STOP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
371
IRremote/IRremote.h
Normal file
371
IRremote/IRremote.h
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// 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
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#ifndef IRremote_h
|
||||||
|
#define IRremote_h
|
||||||
|
|
||||||
|
#define VERSION_IRREMOTE "2.4.0"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// The ISR header contains several useful macros the user may wish to use
|
||||||
|
//
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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_RC5 1
|
||||||
|
#define SEND_RC5 1
|
||||||
|
|
||||||
|
#define DECODE_RC6 1
|
||||||
|
#define SEND_RC6 1
|
||||||
|
|
||||||
|
#define DECODE_NEC 1
|
||||||
|
#define SEND_NEC 1
|
||||||
|
|
||||||
|
#define DECODE_SONY 1
|
||||||
|
#define SEND_SONY 1
|
||||||
|
|
||||||
|
#define DECODE_PANASONIC 1
|
||||||
|
#define SEND_PANASONIC 1
|
||||||
|
|
||||||
|
#define DECODE_JVC 1
|
||||||
|
#define SEND_JVC 1
|
||||||
|
|
||||||
|
#define DECODE_SAMSUNG 1
|
||||||
|
#define SEND_SAMSUNG 1
|
||||||
|
|
||||||
|
#define DECODE_WHYNTER 1
|
||||||
|
#define SEND_WHYNTER 1
|
||||||
|
|
||||||
|
#define DECODE_AIWA_RC_T501 1
|
||||||
|
#define SEND_AIWA_RC_T501 1
|
||||||
|
|
||||||
|
#define DECODE_LG 1
|
||||||
|
#define SEND_LG 1
|
||||||
|
|
||||||
|
#define DECODE_SANYO 1
|
||||||
|
#define SEND_SANYO 0 // NOT WRITTEN
|
||||||
|
|
||||||
|
#define DECODE_MITSUBISHI 1
|
||||||
|
#define SEND_MITSUBISHI 0 // NOT WRITTEN
|
||||||
|
|
||||||
|
#define DECODE_DISH 0 // NOT WRITTEN
|
||||||
|
#define SEND_DISH 1
|
||||||
|
|
||||||
|
#define DECODE_SHARP 0 // NOT WRITTEN
|
||||||
|
#define SEND_SHARP 1
|
||||||
|
|
||||||
|
#define DECODE_DENON 1
|
||||||
|
#define SEND_DENON 1
|
||||||
|
|
||||||
|
#define DECODE_PRONTO 0 // This function doe not logically make sense
|
||||||
|
#define SEND_PRONTO 1
|
||||||
|
|
||||||
|
#define DECODE_LEGO_PF 0 // NOT WRITTEN
|
||||||
|
#define SEND_LEGO_PF 1
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// When sending a Pronto code we request to send either the "once" code
|
||||||
|
// or the "repeat" code
|
||||||
|
// If the code requested does not exist we can request to fallback on the
|
||||||
|
// other code (the one we did not explicitly request)
|
||||||
|
//
|
||||||
|
// I would suggest that "fallback" will be the standard calling method
|
||||||
|
// The last paragraph on this page discusses the rationale of this idea:
|
||||||
|
// http://www.remotecentral.com/features/irdisp2.htm
|
||||||
|
//
|
||||||
|
#define PRONTO_ONCE false
|
||||||
|
#define PRONTO_REPEAT true
|
||||||
|
#define PRONTO_FALLBACK true
|
||||||
|
#define PRONTO_NOFALLBACK false
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// An enumerated list of all supported formats
|
||||||
|
// You do NOT need to remove entries from this list when disabling protocols!
|
||||||
|
//
|
||||||
|
typedef
|
||||||
|
enum {
|
||||||
|
UNKNOWN = -1,
|
||||||
|
UNUSED = 0,
|
||||||
|
RC5,
|
||||||
|
RC6,
|
||||||
|
NEC,
|
||||||
|
SONY,
|
||||||
|
PANASONIC,
|
||||||
|
JVC,
|
||||||
|
SAMSUNG,
|
||||||
|
WHYNTER,
|
||||||
|
AIWA_RC_T501,
|
||||||
|
LG,
|
||||||
|
SANYO,
|
||||||
|
MITSUBISHI,
|
||||||
|
DISH,
|
||||||
|
SHARP,
|
||||||
|
DENON,
|
||||||
|
PRONTO,
|
||||||
|
LEGO_PF,
|
||||||
|
}
|
||||||
|
decode_type_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Set DEBUG to 1 for lots of lovely debug output
|
||||||
|
//
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Debug directives
|
||||||
|
//
|
||||||
|
#if DEBUG
|
||||||
|
# define DBG_PRINT(...) Serial.print(__VA_ARGS__)
|
||||||
|
# define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define DBG_PRINT(...)
|
||||||
|
# define DBG_PRINTLN(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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) ;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Results returned from the decoder
|
||||||
|
//
|
||||||
|
class decode_results
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
decode_type_t decode_type; // UNKNOWN, NEC, SONY, RC5, ...
|
||||||
|
unsigned int address; // Used by Panasonic & Sharp [16-bits]
|
||||||
|
unsigned long value; // Decoded value [max 32-bits]
|
||||||
|
int bits; // Number of bits in decoded value
|
||||||
|
volatile unsigned int *rawbuf; // Raw intervals in 50uS ticks
|
||||||
|
int rawlen; // Number of records in rawbuf
|
||||||
|
int overflow; // true iff IR raw code too long
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Decoded value for NEC when a repeat code is received
|
||||||
|
//
|
||||||
|
#define REPEAT 0xFFFFFFFF
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Main class for receiving IR
|
||||||
|
//
|
||||||
|
class IRrecv
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IRrecv (int recvpin) ;
|
||||||
|
IRrecv (int recvpin, int blinkpin);
|
||||||
|
|
||||||
|
void blink13 (int blinkflag) ;
|
||||||
|
int decode (decode_results *results) ;
|
||||||
|
void enableIRIn ( ) ;
|
||||||
|
bool isIdle ( ) ;
|
||||||
|
void resume ( ) ;
|
||||||
|
|
||||||
|
private:
|
||||||
|
long decodeHash (decode_results *results) ;
|
||||||
|
int compare (unsigned int oldval, unsigned int newval) ;
|
||||||
|
|
||||||
|
//......................................................................
|
||||||
|
# if (DECODE_RC5 || DECODE_RC6)
|
||||||
|
// This helper function is shared by RC5 and RC6
|
||||||
|
int getRClevel (decode_results *results, int *offset, int *used, int t1) ;
|
||||||
|
# endif
|
||||||
|
# if DECODE_RC5
|
||||||
|
bool decodeRC5 (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
# if DECODE_RC6
|
||||||
|
bool decodeRC6 (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_NEC
|
||||||
|
bool decodeNEC (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_SONY
|
||||||
|
bool decodeSony (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_PANASONIC
|
||||||
|
bool decodePanasonic (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_JVC
|
||||||
|
bool decodeJVC (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_SAMSUNG
|
||||||
|
bool decodeSAMSUNG (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_WHYNTER
|
||||||
|
bool decodeWhynter (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_AIWA_RC_T501
|
||||||
|
bool decodeAiwaRCT501 (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_LG
|
||||||
|
bool decodeLG (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_SANYO
|
||||||
|
bool decodeSanyo (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_MITSUBISHI
|
||||||
|
bool decodeMitsubishi (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_DISH
|
||||||
|
bool decodeDish (decode_results *results) ; // NOT WRITTEN
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_SHARP
|
||||||
|
bool decodeSharp (decode_results *results) ; // NOT WRITTEN
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_DENON
|
||||||
|
bool decodeDenon (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if DECODE_LEGO_PF
|
||||||
|
bool decodeLegoPowerFunctions (decode_results *results) ;
|
||||||
|
# endif
|
||||||
|
} ;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Main class for sending IR
|
||||||
|
//
|
||||||
|
class IRsend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifdef USE_SOFT_CARRIER
|
||||||
|
|
||||||
|
IRsend(int pin = SEND_PIN)
|
||||||
|
{
|
||||||
|
sendPin = pin;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
IRsend()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void custom_delay_usec (unsigned long uSecs);
|
||||||
|
void enableIROut (int khz) ;
|
||||||
|
void mark (unsigned int usec) ;
|
||||||
|
void space (unsigned int usec) ;
|
||||||
|
void sendRaw (const unsigned int buf[], unsigned int len, unsigned int hz) ;
|
||||||
|
|
||||||
|
//......................................................................
|
||||||
|
# if SEND_RC5
|
||||||
|
void sendRC5 (unsigned long data, int nbits) ;
|
||||||
|
# endif
|
||||||
|
# if SEND_RC6
|
||||||
|
void sendRC6 (unsigned long data, int nbits) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if SEND_NEC
|
||||||
|
void sendNEC (unsigned long data, int nbits) ;
|
||||||
|
# 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) ;
|
||||||
|
# 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_DENON
|
||||||
|
void sendDenon (unsigned long data, int nbits) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if SEND_PRONTO
|
||||||
|
void sendPronto (char* code, bool repeat, bool fallback) ;
|
||||||
|
# endif
|
||||||
|
//......................................................................
|
||||||
|
# if SEND_LEGO_PF
|
||||||
|
void sendLegoPowerFunctions (uint16_t data, bool repeat = true) ;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#ifdef USE_SOFT_CARRIER
|
||||||
|
private:
|
||||||
|
int sendPin;
|
||||||
|
|
||||||
|
unsigned int periodTime;
|
||||||
|
unsigned int periodOnTime;
|
||||||
|
|
||||||
|
void sleepMicros(unsigned long us);
|
||||||
|
void sleepUntilMicros(unsigned long targetTime);
|
||||||
|
|
||||||
|
#else
|
||||||
|
const int sendPin = SEND_PIN;
|
||||||
|
#endif
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#endif
|
113
IRremote/IRremoteInt.h
Normal file
113
IRremote/IRremoteInt.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//******************************************************************************
|
||||||
|
// 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 right Arduino header
|
||||||
|
//
|
||||||
|
#if defined(ARDUINO) && (ARDUINO >= 100)
|
||||||
|
# include <Arduino.h>
|
||||||
|
#else
|
||||||
|
# if !defined(IRPRONTO)
|
||||||
|
# include <WProgram.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This handles definition and access to global variables
|
||||||
|
//
|
||||||
|
#ifdef IR_GLOBAL
|
||||||
|
# define EXTERN
|
||||||
|
#else
|
||||||
|
# define EXTERN extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Information for the Interrupt Service Routine
|
||||||
|
//
|
||||||
|
#define RAWBUF 101 // Maximum length of raw duration buffer
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct {
|
||||||
|
// The fields are ordered to reduce memory over caused by struct-padding
|
||||||
|
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
|
||||||
|
uint8_t rawlen; // counter of entries in rawbuf
|
||||||
|
unsigned int timer; // State timer, counts 50uS ticks.
|
||||||
|
unsigned int rawbuf[RAWBUF]; // raw data
|
||||||
|
uint8_t overflow; // Raw buffer overflow occurred
|
||||||
|
}
|
||||||
|
irparams_t;
|
||||||
|
|
||||||
|
// ISR State-Machine : Receiver States
|
||||||
|
#define STATE_IDLE 2
|
||||||
|
#define STATE_MARK 3
|
||||||
|
#define STATE_SPACE 4
|
||||||
|
#define STATE_STOP 5
|
||||||
|
#define STATE_OVERFLOW 6
|
||||||
|
|
||||||
|
// Allow all parts of the code access to the ISR data
|
||||||
|
// NB. The data can be changed by the ISR at any time, even mid-function
|
||||||
|
// Therefore we declare it as "volatile" to stop the compiler/CPU caching it
|
||||||
|
EXTERN volatile irparams_t 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
|
||||||
|
//
|
||||||
|
|
||||||
|
// Due to sensor lag, when received, Marks tend to be 100us too long and
|
||||||
|
// Spaces tend to be 100us too short
|
||||||
|
#define MARK_EXCESS 100
|
||||||
|
|
||||||
|
// Upper and Lower percentage tolerances in measurements
|
||||||
|
#define TOLERANCE 25
|
||||||
|
#define LTOL (1.0 - (TOLERANCE/100.))
|
||||||
|
#define UTOL (1.0 + (TOLERANCE/100.))
|
||||||
|
|
||||||
|
// Minimum gap between IR transmissions
|
||||||
|
#define _GAP 5000
|
||||||
|
#define GAP_TICKS (_GAP/USECPERTICK)
|
||||||
|
|
||||||
|
#define TICKS_LOW(us) ((int)(((us)*LTOL/USECPERTICK)))
|
||||||
|
#define TICKS_HIGH(us) ((int)(((us)*UTOL/USECPERTICK + 1)))
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// IR detector output is active low
|
||||||
|
//
|
||||||
|
#define MARK 0
|
||||||
|
#define SPACE 1
|
||||||
|
|
||||||
|
// All board specific stuff has been moved to its own file, included here.
|
||||||
|
#include "boarddefs.h"
|
||||||
|
|
||||||
|
#endif
|
653
IRremote/boarddefs.h
Normal file
653
IRremote/boarddefs.h
Normal file
@ -0,0 +1,653 @@
|
|||||||
|
//******************************************************************************
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// This file contains all board specific information. It was previously contained within
|
||||||
|
// IRremoteInt.h
|
||||||
|
|
||||||
|
// 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 boarddefs_h
|
||||||
|
#define boarddefs_h
|
||||||
|
|
||||||
|
// Define some defaults, that some boards may like to override
|
||||||
|
// (This is to avoid negative logic, ! DONT_... is just awkward.)
|
||||||
|
|
||||||
|
// This board has/needs the avr/interrupt.h
|
||||||
|
#define HAS_AVR_INTERRUPT_H
|
||||||
|
|
||||||
|
// Define if sending is supported
|
||||||
|
#define SENDING_SUPPORTED
|
||||||
|
|
||||||
|
// If defined, a standard enableIRIn function will be define.
|
||||||
|
// Undefine for boards supplying their own.
|
||||||
|
#define USE_DEFAULT_ENABLE_IR_IN
|
||||||
|
|
||||||
|
// Duty cycle in percent for sent signals. Presently takes effect only with USE_SOFT_CARRIER
|
||||||
|
#define DUTY_CYCLE 50
|
||||||
|
|
||||||
|
// If USE_SOFT_CARRIER, this amount (in micro seconds) is subtracted from the
|
||||||
|
// on-time of the pulses.
|
||||||
|
#define PULSE_CORRECTION 3
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Defines for blinking the LED
|
||||||
|
//
|
||||||
|
|
||||||
|
#if 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))
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_SAM) || 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_CARRIER
|
||||||
|
// Define to use spin wait instead of delayMicros()
|
||||||
|
//# define USE_SPIN_WAIT
|
||||||
|
# undef USE_DEFAULT_ENABLE_IR_IN
|
||||||
|
|
||||||
|
// The default pin used used for sending.
|
||||||
|
# define SEND_PIN 9
|
||||||
|
|
||||||
|
#elif defined(ESP32)
|
||||||
|
// No system LED on ESP32, disable blinking by NOT defining BLINKLED
|
||||||
|
|
||||||
|
// avr/interrupt.h is not present
|
||||||
|
# undef HAS_AVR_INTERRUPT_H
|
||||||
|
|
||||||
|
// Sending not implemented
|
||||||
|
# undef SENDING_SUPPORTED#
|
||||||
|
|
||||||
|
// Supply own enbleIRIn
|
||||||
|
# undef USE_DEFAULT_ENABLE_IR_IN
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define BLINKLED 13
|
||||||
|
# define BLINKLED_ON() (PORTB |= B00100000)
|
||||||
|
# define BLINKLED_OFF() (PORTB &= B11011111)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// CPU Frequency
|
||||||
|
//
|
||||||
|
#ifdef F_CPU
|
||||||
|
# define SYSCLOCK F_CPU // main Arduino clock
|
||||||
|
#else
|
||||||
|
# define SYSCLOCK 16000000 // main Arduino clock
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// microseconds per clock interrupt tick
|
||||||
|
#define USECPERTICK 50
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Arduino Mega
|
||||||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
//#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
|
||||||
|
|
||||||
|
// Teensy 1.0
|
||||||
|
#elif defined(__AVR_AT90USB162__)
|
||||||
|
#define IR_USE_TIMER1 // tx = pin 17
|
||||||
|
|
||||||
|
// Teensy 2.0
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
//#define IR_USE_TIMER1 // tx = pin 14
|
||||||
|
//#define IR_USE_TIMER3 // tx = pin 9
|
||||||
|
#define IR_USE_TIMER4_HS // tx = pin 10
|
||||||
|
|
||||||
|
// Teensy 3.0 / Teensy 3.1
|
||||||
|
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
#define IR_USE_TIMER_CMT // tx = pin 5
|
||||||
|
|
||||||
|
// Teensy-LC
|
||||||
|
#elif defined(__MKL26Z64__)
|
||||||
|
#define IR_USE_TIMER_TPM1 // tx = pin 16
|
||||||
|
|
||||||
|
// Teensy++ 1.0 & 2.0
|
||||||
|
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||||
|
//#define IR_USE_TIMER1 // tx = pin 25
|
||||||
|
#define IR_USE_TIMER2 // tx = pin 1
|
||||||
|
//#define IR_USE_TIMER3 // tx = pin 16
|
||||||
|
|
||||||
|
// MightyCore - ATmega1284
|
||||||
|
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||||
|
//#define IR_USE_TIMER1 // tx = pin 13
|
||||||
|
#define IR_USE_TIMER2 // tx = pin 14
|
||||||
|
//#define IR_USE_TIMER3 // tx = pin 6
|
||||||
|
|
||||||
|
// 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__)
|
||||||
|
//#define IR_USE_TIMER1 // tx = pin 13
|
||||||
|
#define IR_USE_TIMER2 // tx = pin 14
|
||||||
|
|
||||||
|
//MegaCore - ATmega64, ATmega128
|
||||||
|
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
|
||||||
|
#define IR_USE_TIMER1 // tx = pin 13
|
||||||
|
|
||||||
|
// MightyCore - ATmega8535, ATmega16, ATmega32
|
||||||
|
#elif defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
|
||||||
|
#define IR_USE_TIMER1 // tx = pin 13
|
||||||
|
|
||||||
|
// Atmega8
|
||||||
|
#elif defined(__AVR_ATmega8__)
|
||||||
|
#define IR_USE_TIMER1 // tx = pin 9
|
||||||
|
|
||||||
|
// ATtiny84
|
||||||
|
#elif defined(__AVR_ATtiny84__)
|
||||||
|
#define IR_USE_TIMER1 // tx = pin 6
|
||||||
|
|
||||||
|
//ATtiny85
|
||||||
|
#elif defined(__AVR_ATtiny85__)
|
||||||
|
#define IR_USE_TIMER_TINY0 // tx = pin 1
|
||||||
|
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#define IR_TIMER_USE_ESP32
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
|
||||||
|
#define TIMER_PRESCALER_DIV 64
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
|
||||||
|
// ATmega48, ATmega88, ATmega168, ATmega328
|
||||||
|
//#define IR_USE_TIMER1 // tx = pin 9
|
||||||
|
#define IR_USE_TIMER2 // tx = pin 3
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Defines for Timer
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Timer2 (8 bits)
|
||||||
|
//
|
||||||
|
#if defined(IR_USE_TIMER2)
|
||||||
|
|
||||||
|
#define TIMER_RESET
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK2 = 0)
|
||||||
|
#define TIMER_INTR_NAME TIMER2_COMPA_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR2A = _BV(WGM20); \
|
||||||
|
TCCR2B = _BV(WGM22) | _BV(CS20); \
|
||||||
|
OCR2A = pwmval; \
|
||||||
|
OCR2B = pwmval / 3; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if (TIMER_COUNT_TOP < 256)
|
||||||
|
# define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR2A = _BV(WGM21); \
|
||||||
|
TCCR2B = _BV(CS20); \
|
||||||
|
OCR2A = TIMER_COUNT_TOP; \
|
||||||
|
TCNT2 = 0; \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
# define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR2A = _BV(WGM21); \
|
||||||
|
TCCR2B = _BV(CS21); \
|
||||||
|
OCR2A = TIMER_COUNT_TOP / 8; \
|
||||||
|
TCNT2 = 0; \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC2B_PIN)
|
||||||
|
# define SEND_PIN CORE_OC2B_PIN // Teensy
|
||||||
|
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
# define 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 SEND_PIN 14 // MightyCore
|
||||||
|
#else
|
||||||
|
# define SEND_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc
|
||||||
|
#endif // ATmega48, ATmega88, ATmega168, ATmega328
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Timer1 (16 bits)
|
||||||
|
//
|
||||||
|
#elif defined(IR_USE_TIMER1)
|
||||||
|
|
||||||
|
#define TIMER_RESET
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1)))
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8535__) \
|
||||||
|
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
|
||||||
|
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
|
||||||
|
# define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE1A))
|
||||||
|
# define TIMER_DISABLE_INTR (TIMSK &= ~_BV(OCIE1A))
|
||||||
|
#else
|
||||||
|
# define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A))
|
||||||
|
# define TIMER_DISABLE_INTR (TIMSK1 = 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#define TIMER_INTR_NAME TIMER1_COMPA_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR1A = _BV(WGM11); \
|
||||||
|
TCCR1B = _BV(WGM13) | _BV(CS10); \
|
||||||
|
ICR1 = pwmval; \
|
||||||
|
OCR1A = pwmval / 3; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR1A = 0; \
|
||||||
|
TCCR1B = _BV(WGM12) | _BV(CS10); \
|
||||||
|
OCR1A = SYSCLOCK * USECPERTICK / 1000000; \
|
||||||
|
TCNT1 = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC1A_PIN)
|
||||||
|
# define SEND_PIN CORE_OC1A_PIN // Teensy
|
||||||
|
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
# define SEND_PIN 11 // Arduino Mega
|
||||||
|
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
|
||||||
|
# define SEND_PIN 13 // MegaCore
|
||||||
|
#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__)
|
||||||
|
# define SEND_PIN 13 // MightyCore
|
||||||
|
#elif defined(__AVR_ATtiny84__)
|
||||||
|
# define SEND_PIN 6
|
||||||
|
#else
|
||||||
|
# define SEND_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, etc
|
||||||
|
#endif // ATmega48, ATmega88, ATmega168, ATmega328
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Timer3 (16 bits)
|
||||||
|
//
|
||||||
|
#elif defined(IR_USE_TIMER3)
|
||||||
|
|
||||||
|
#define TIMER_RESET
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK3 = 0)
|
||||||
|
#define TIMER_INTR_NAME TIMER3_COMPA_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR3A = _BV(WGM31); \
|
||||||
|
TCCR3B = _BV(WGM33) | _BV(CS30); \
|
||||||
|
ICR3 = pwmval; \
|
||||||
|
OCR3A = pwmval / 3; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR3A = 0; \
|
||||||
|
TCCR3B = _BV(WGM32) | _BV(CS30); \
|
||||||
|
OCR3A = SYSCLOCK * USECPERTICK / 1000000; \
|
||||||
|
TCNT3 = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC3A_PIN)
|
||||||
|
# define SEND_PIN CORE_OC3A_PIN // Teensy
|
||||||
|
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
# define SEND_PIN 5 // Arduino Mega
|
||||||
|
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||||
|
# define SEND_PIN 6 // MightyCore
|
||||||
|
#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
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
|
||||||
|
#define TIMER_INTR_NAME TIMER4_OVF_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR4A = (1<<PWM4A); \
|
||||||
|
TCCR4B = _BV(CS40); \
|
||||||
|
TCCR4C = 0; \
|
||||||
|
TCCR4D = (1<<WGM40); \
|
||||||
|
TCCR4E = 0; \
|
||||||
|
TC4H = pwmval >> 8; \
|
||||||
|
OCR4C = pwmval; \
|
||||||
|
TC4H = (pwmval / 3) >> 8; \
|
||||||
|
OCR4A = (pwmval / 3) & 255; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR4A = 0; \
|
||||||
|
TCCR4B = _BV(CS40); \
|
||||||
|
TCCR4C = 0; \
|
||||||
|
TCCR4D = 0; \
|
||||||
|
TCCR4E = 0; \
|
||||||
|
TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \
|
||||||
|
OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \
|
||||||
|
TC4H = 0; \
|
||||||
|
TCNT4 = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC4A_PIN)
|
||||||
|
# define SEND_PIN CORE_OC4A_PIN // Teensy
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
# define 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
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
|
||||||
|
#define TIMER_INTR_NAME TIMER4_COMPA_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR4A = _BV(WGM41); \
|
||||||
|
TCCR4B = _BV(WGM43) | _BV(CS40); \
|
||||||
|
ICR4 = pwmval; \
|
||||||
|
OCR4A = pwmval / 3; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR4A = 0; \
|
||||||
|
TCCR4B = _BV(WGM42) | _BV(CS40); \
|
||||||
|
OCR4A = SYSCLOCK * USECPERTICK / 1000000; \
|
||||||
|
TCNT4 = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC4A_PIN)
|
||||||
|
# define SEND_PIN CORE_OC4A_PIN
|
||||||
|
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
# define 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
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK5 = 0)
|
||||||
|
#define TIMER_INTR_NAME TIMER5_COMPA_vect
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR5A = _BV(WGM51); \
|
||||||
|
TCCR5B = _BV(WGM53) | _BV(CS50); \
|
||||||
|
ICR5 = pwmval; \
|
||||||
|
OCR5A = pwmval / 3; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR5A = 0; \
|
||||||
|
TCCR5B = _BV(WGM52) | _BV(CS50); \
|
||||||
|
OCR5A = SYSCLOCK * USECPERTICK / 1000000; \
|
||||||
|
TCNT5 = 0; \
|
||||||
|
})
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#if defined(CORE_OC5A_PIN)
|
||||||
|
# define SEND_PIN CORE_OC5A_PIN
|
||||||
|
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
# define SEND_PIN 46 // Arduino Mega
|
||||||
|
#else
|
||||||
|
# error "Please add OC5A pin number here\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Special carrier modulator timer
|
||||||
|
//
|
||||||
|
#elif defined(IR_USE_TIMER_CMT)
|
||||||
|
|
||||||
|
#define TIMER_RESET ({ \
|
||||||
|
uint8_t tmp __attribute__((unused)) = CMT_MSC; \
|
||||||
|
CMT_CMD2 = 30; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_ENABLE_PWM do { \
|
||||||
|
CORE_PIN5_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE | PORT_PCR_SRE; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define TIMER_DISABLE_PWM do { \
|
||||||
|
CORE_PIN5_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_CMT)
|
||||||
|
#define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_CMT)
|
||||||
|
#define TIMER_INTR_NAME cmt_isr
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#ifdef ISR
|
||||||
|
# undef ISR
|
||||||
|
#endif
|
||||||
|
#define ISR(f) void f(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
|
||||||
|
|
||||||
|
//-----------------
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
SIM_SCGC4 |= SIM_SCGC4_CMT; \
|
||||||
|
SIM_SOPT2 |= SIM_SOPT2_PTD7PAD; \
|
||||||
|
CMT_PPS = CMT_PPS_DIV - 1; \
|
||||||
|
CMT_CGH1 = ((F_BUS / CMT_PPS_DIV / 3000) + ((val)/2)) / (val); \
|
||||||
|
CMT_CGL1 = ((F_BUS / CMT_PPS_DIV / 1500) + ((val)/2)) / (val); \
|
||||||
|
CMT_CMD1 = 0; \
|
||||||
|
CMT_CMD2 = 30; \
|
||||||
|
CMT_CMD3 = 0; \
|
||||||
|
CMT_CMD4 = 0; \
|
||||||
|
CMT_OC = 0x60; \
|
||||||
|
CMT_MSC = 0x01; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
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 SEND_PIN 5
|
||||||
|
|
||||||
|
// defines for TPM1 timer on Teensy-LC
|
||||||
|
#elif defined(IR_USE_TIMER_TPM1)
|
||||||
|
#define TIMER_RESET FTM1_SC |= FTM_SC_TOF;
|
||||||
|
#define TIMER_ENABLE_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE
|
||||||
|
#define TIMER_DISABLE_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE
|
||||||
|
#define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_FTM1)
|
||||||
|
#define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_FTM1)
|
||||||
|
#define TIMER_INTR_NAME ftm1_isr
|
||||||
|
#ifdef ISR
|
||||||
|
#undef ISR
|
||||||
|
#endif
|
||||||
|
#define ISR(f) void f(void)
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
SIM_SCGC6 |= SIM_SCGC6_TPM1; \
|
||||||
|
FTM1_SC = 0; \
|
||||||
|
FTM1_CNT = 0; \
|
||||||
|
FTM1_MOD = (F_PLL/2000) / val - 1; \
|
||||||
|
FTM1_C0V = (F_PLL/6000) / val - 1; \
|
||||||
|
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); \
|
||||||
|
})
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
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 SEND_PIN 16
|
||||||
|
|
||||||
|
// defines for timer_tiny0 (8 bits)
|
||||||
|
#elif defined(IR_USE_TIMER_TINY0)
|
||||||
|
#define TIMER_RESET
|
||||||
|
#define TIMER_ENABLE_PWM (TCCR0A |= _BV(COM0B1))
|
||||||
|
#define TIMER_DISABLE_PWM (TCCR0A &= ~(_BV(COM0B1)))
|
||||||
|
#define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE0A))
|
||||||
|
#define TIMER_DISABLE_INTR (TIMSK &= ~(_BV(OCIE0A)))
|
||||||
|
#define TIMER_INTR_NAME TIMER0_COMPA_vect
|
||||||
|
#define TIMER_CONFIG_KHZ(val) ({ \
|
||||||
|
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
|
||||||
|
TCCR0A = _BV(WGM00); \
|
||||||
|
TCCR0B = _BV(WGM02) | _BV(CS00); \
|
||||||
|
OCR0A = pwmval; \
|
||||||
|
OCR0B = pwmval / 3; \
|
||||||
|
})
|
||||||
|
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
|
||||||
|
#if (TIMER_COUNT_TOP < 256)
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR0A = _BV(WGM01); \
|
||||||
|
TCCR0B = _BV(CS00); \
|
||||||
|
OCR0A = TIMER_COUNT_TOP; \
|
||||||
|
TCNT0 = 0; \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define TIMER_CONFIG_NORMAL() ({ \
|
||||||
|
TCCR0A = _BV(WGM01); \
|
||||||
|
TCCR0B = _BV(CS01); \
|
||||||
|
OCR0A = TIMER_COUNT_TOP / 8; \
|
||||||
|
TCNT0 = 0; \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SEND_PIN 1 /* ATtiny85 */
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
// for that -- merlin
|
||||||
|
// As a warning, sending timing specific code from an ESP32 can be challenging if you need 100%
|
||||||
|
// reliability because the arduino code may be interrupted and cause your sent waveform to be the
|
||||||
|
// wrong length. This is specifically an issue for neopixels which require 800Khz resolution.
|
||||||
|
// IR may just work as is with the common code since it's lower frequency, but if not, the other
|
||||||
|
// way to do this on ESP32 is using the RMT built in driver like in this incomplete library below
|
||||||
|
// https://github.com/ExploreEmbedded/ESP32_RMT
|
||||||
|
#elif defined(IR_TIMER_USE_ESP32)
|
||||||
|
|
||||||
|
#define TIMER_RESET
|
||||||
|
|
||||||
|
#ifdef ISR
|
||||||
|
# undef ISR
|
||||||
|
#endif
|
||||||
|
#define ISR(f) void IRTimer()
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
|
||||||
|
// use timer 3 hardcoded at this time
|
||||||
|
|
||||||
|
#define TIMER_RESET
|
||||||
|
#define TIMER_ENABLE_PWM // Not presently used
|
||||||
|
#define TIMER_DISABLE_PWM
|
||||||
|
#define TIMER_ENABLE_INTR NVIC_EnableIRQ(TC3_IRQn) // Not presently used
|
||||||
|
#define TIMER_DISABLE_INTR NVIC_DisableIRQ(TC3_IRQn)
|
||||||
|
#define TIMER_INTR_NAME TC3_Handler // Not presently used
|
||||||
|
#define TIMER_CONFIG_KHZ(f)
|
||||||
|
|
||||||
|
#ifdef ISR
|
||||||
|
# undef ISR
|
||||||
|
#endif
|
||||||
|
#define ISR(f) void irs()
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Unknown Timer
|
||||||
|
//
|
||||||
|
#else
|
||||||
|
# error "Internal code configuration error, no known IR_USE_TIMER# defined\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Provide default definitions, portable but possibly slower than necessary.
|
||||||
|
#ifndef SENDPIN_ON
|
||||||
|
#define SENDPIN_ON(pin) digitalWrite(pin, HIGH)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SENDPIN_OFF
|
||||||
|
#define SENDPIN_OFF(pin) digitalWrite(pin, LOW)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ! boarddefs_h
|
81
IRremote/changelog.txt
Normal file
81
IRremote/changelog.txt
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
## 2.4.0 - 2017/08/10
|
||||||
|
- Cleanup of hardware dependencies. Merge in SAM support [PR #437](https://github.com/z3t0/Arduino-IRremote/pull/437)
|
||||||
|
|
||||||
|
## 2.3.3 - 2017/03/31
|
||||||
|
- Added ESP32 IR receive support [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/425)
|
||||||
|
|
||||||
|
## 2.2.3 - 2017/03/27
|
||||||
|
- Fix calculation of pause length in LEGO PF protocol [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/427)
|
||||||
|
|
||||||
|
## 2.2.2 - 2017/01/20
|
||||||
|
- Fixed naming bug [PR #398](https://github.com/z3t0/Arduino-IRremote/pull/398)
|
||||||
|
|
||||||
|
## 2.2.1 - 2016/07/27
|
||||||
|
- Added tests for Lego Power Functions Protocol [PR #336](https://github.com/z3t0/Arduino-IRremote/pull/336)
|
||||||
|
|
||||||
|
## 2.2.0 - 2016/06/28
|
||||||
|
- Added support for ATmega8535
|
||||||
|
- Added support for ATmega16
|
||||||
|
- Added support for ATmega32
|
||||||
|
- Added support for ATmega164
|
||||||
|
- Added support for ATmega324
|
||||||
|
- Added support for ATmega644
|
||||||
|
- Added support for ATmega1284
|
||||||
|
- Added support for ATmega64
|
||||||
|
- Added support for ATmega128
|
||||||
|
|
||||||
|
[PR](https://github.com/z3t0/Arduino-IRremote/pull/324)
|
||||||
|
|
||||||
|
## 2.1.1 - 2016/05/04
|
||||||
|
- Added Lego Power Functions Protocol [PR #309](https://github.com/z3t0/Arduino-IRremote/pull/309)
|
||||||
|
|
||||||
|
## 2.1.0 - 2016/02/20
|
||||||
|
- Improved Debugging [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258)
|
||||||
|
- Display TIME instead of TICKS [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258)
|
||||||
|
|
||||||
|
## 2.0.4 - 2016/02/20
|
||||||
|
- Add Panasonic and JVC to IRrecord example [PR](https://github.com/z3t0/Arduino-IRremote/pull/54)
|
||||||
|
|
||||||
|
## 2.0.3 - 2016/02/20
|
||||||
|
- Change IRSend Raw parameter to const [PR](https://github.com/z3t0/Arduino-IRremote/pull/227)
|
||||||
|
|
||||||
|
## 2.0.2 - 2015/12/02
|
||||||
|
- Added IRremoteInfo Sketch - [PR](https://github.com/z3t0/Arduino-IRremote/pull/241)
|
||||||
|
- Enforcing changelog.md
|
||||||
|
|
||||||
|
## 2.0.1 - 2015/07/26 - [Release](https://github.com/shirriff/Arduino-IRremote/releases/tag/BETA)
|
||||||
|
### Changes
|
||||||
|
- Updated README
|
||||||
|
- Updated Contributors
|
||||||
|
- Fixed #110 Mess
|
||||||
|
- Created Gitter Room
|
||||||
|
- Added Gitter Badge
|
||||||
|
- Standardised Code Base
|
||||||
|
- Clean Debug Output
|
||||||
|
- Optimized Send Loops
|
||||||
|
- Modularized Design
|
||||||
|
- Optimized and Updated Examples
|
||||||
|
- Improved Documentation
|
||||||
|
- Fixed and Improved many coding errors
|
||||||
|
- Fixed Aiwa RC-T501 Decoding
|
||||||
|
- Fixed Interrupt on ATmega8
|
||||||
|
- Switched to Stable Release of @PlatformIO
|
||||||
|
|
||||||
|
### Additions
|
||||||
|
- Added Aiwa RC-T501 Protocol
|
||||||
|
- Added Denon Protocol
|
||||||
|
- Added Pronto Support
|
||||||
|
- Added Library Properties
|
||||||
|
- Added Template For New Protocols
|
||||||
|
- Added this changelog
|
||||||
|
- Added Teensy LC Support
|
||||||
|
- Added ATtiny84 Support
|
||||||
|
- Added ATtiny85 Support
|
||||||
|
- Added isIdle method
|
||||||
|
|
||||||
|
### Deletions
|
||||||
|
- Removed (Fixed) #110
|
||||||
|
- Broke Teensy 3 / 3.1 Support
|
||||||
|
|
||||||
|
### Not Working
|
||||||
|
- Teensy 3 / 3.1 Support is in Development
|
39
IRremote/esp32.cpp
Normal file
39
IRremote/esp32.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifdef ESP32
|
||||||
|
|
||||||
|
// This file contains functions specific to the ESP32.
|
||||||
|
|
||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
// "Idiot check"
|
||||||
|
#ifdef USE_DEFAULT_ENABLE_IR_IN
|
||||||
|
#error Must undef USE_DEFAULT_ENABLE_IR_IN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hw_timer_t *timer;
|
||||||
|
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 = STATE_IDLE;
|
||||||
|
irparams.rawlen = 0;
|
||||||
|
|
||||||
|
// Set pin modes
|
||||||
|
pinMode(irparams.recvpin, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ESP32
|
513
IRremote/irPronto.cpp
Normal file
513
IRremote/irPronto.cpp
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
#define TEST 0
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
# define SEND_PRONTO 1
|
||||||
|
# define PRONTO_ONCE false
|
||||||
|
# define PRONTO_REPEAT true
|
||||||
|
# define PRONTO_FALLBACK true
|
||||||
|
# define PRONTO_NOFALLBACK false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SEND_PRONTO
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
#if TEST
|
||||||
|
# include <stdio.h>
|
||||||
|
void enableIROut (int freq) { printf("\nFreq = %d KHz\n", freq); }
|
||||||
|
void mark (int t) { printf("+%d," , t); }
|
||||||
|
void space (int t) { printf("-%d, ", t); }
|
||||||
|
#else
|
||||||
|
# include "IRremote.h"
|
||||||
|
#endif // TEST
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Check for a valid hex digit
|
||||||
|
//
|
||||||
|
bool ishex (char ch)
|
||||||
|
{
|
||||||
|
return ( ((ch >= '0') && (ch <= '9')) ||
|
||||||
|
((ch >= 'A') && (ch <= 'F')) ||
|
||||||
|
((ch >= 'a') && (ch <= 'f')) ) ? true : false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Check for a valid "blank" ... '\0' is a valid "blank"
|
||||||
|
//
|
||||||
|
bool isblank (char ch)
|
||||||
|
{
|
||||||
|
return ((ch == ' ') || (ch == '\t') || (ch == '\0')) ? true : false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Bypass spaces
|
||||||
|
//
|
||||||
|
bool byp (char** pcp)
|
||||||
|
{
|
||||||
|
while (isblank(**pcp)) (*pcp)++ ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Hex-to-Byte : Decode a hex digit
|
||||||
|
// We assume the character has already been validated
|
||||||
|
//
|
||||||
|
uint8_t htob (char ch)
|
||||||
|
{
|
||||||
|
if ((ch >= '0') && (ch <= '9')) return ch - '0' ;
|
||||||
|
if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ;
|
||||||
|
if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Hex-to-Word : Decode a block of 4 hex digits
|
||||||
|
// We assume the string has already been validated
|
||||||
|
// and the pointer being passed points at the start of a block of 4 hex digits
|
||||||
|
//
|
||||||
|
uint16_t htow (char* cp)
|
||||||
|
{
|
||||||
|
return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) |
|
||||||
|
(htob(cp[2]) << 4) | (htob(cp[3]) ) ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
//
|
||||||
|
bool sendPronto (char* s, bool repeat, bool fallback)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len;
|
||||||
|
int skip;
|
||||||
|
char* cp;
|
||||||
|
uint16_t freq; // Frequency in KHz
|
||||||
|
uint8_t usec; // pronto uSec/tick
|
||||||
|
uint8_t once;
|
||||||
|
uint8_t rpt;
|
||||||
|
|
||||||
|
// Validate the string
|
||||||
|
for (cp = s; *cp; cp += 4) {
|
||||||
|
byp(&cp);
|
||||||
|
if ( !ishex(cp[0]) || !ishex(cp[1]) ||
|
||||||
|
!ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will use cp to traverse the string
|
||||||
|
cp = s;
|
||||||
|
|
||||||
|
// Check mode = Oscillated/Learned
|
||||||
|
byp(&cp);
|
||||||
|
if (htow(cp) != 0000) return false;
|
||||||
|
cp += 4;
|
||||||
|
|
||||||
|
// Extract & set frequency
|
||||||
|
byp(&cp);
|
||||||
|
freq = (int)(1000000 / (htow(cp) * 0.241246)); // Rounding errors will occur, tolerance is +/- 10%
|
||||||
|
usec = (int)(((1.0 / freq) * 1000000) + 0.5); // Another rounding error, thank Cod for analogue electronics
|
||||||
|
freq /= 1000; // This will introduce a(nother) rounding error which we do not want in the usec calcualtion
|
||||||
|
cp += 4;
|
||||||
|
|
||||||
|
// Get length of "once" code
|
||||||
|
byp(&cp);
|
||||||
|
once = htow(cp);
|
||||||
|
cp += 4;
|
||||||
|
|
||||||
|
// Get length of "repeat" code
|
||||||
|
byp(&cp);
|
||||||
|
rpt = htow(cp);
|
||||||
|
cp += 4;
|
||||||
|
|
||||||
|
// Which code are we sending?
|
||||||
|
if (fallback) { // fallback on the "other" code if "this" code is not present
|
||||||
|
if (!repeat) { // requested 'once'
|
||||||
|
if (once) len = once * 2, skip = 0 ; // if once exists send it
|
||||||
|
else len = rpt * 2, skip = 0 ; // else send repeat code
|
||||||
|
} else { // requested 'repeat'
|
||||||
|
if (rpt) len = rpt * 2, skip = 0 ; // if rpt exists send it
|
||||||
|
else len = once * 2, skip = 0 ; // else send once code
|
||||||
|
}
|
||||||
|
} else { // Send what we asked for, do not fallback if the code is empty!
|
||||||
|
if (!repeat) len = once * 2, skip = 0 ; // 'once' starts at 0
|
||||||
|
else len = rpt * 2, skip = once ; // 'repeat' starts where 'once' ends
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip to start of code
|
||||||
|
for (i = 0; i < skip; i++, cp += 4) byp(&cp) ;
|
||||||
|
|
||||||
|
// Send code
|
||||||
|
enableIROut(freq);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
byp(&cp);
|
||||||
|
if (i & 1) space(htow(cp) * usec);
|
||||||
|
else mark (htow(cp) * usec);
|
||||||
|
cp += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if TEST
|
||||||
|
|
||||||
|
int main ( )
|
||||||
|
{
|
||||||
|
char prontoTest[] =
|
||||||
|
"0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100
|
||||||
|
"0010 0030 0010 0aa6"; // 104
|
||||||
|
|
||||||
|
sendPronto(prontoTest, PRONTO_ONCE, PRONTO_FALLBACK); // once code
|
||||||
|
sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_FALLBACK); // repeat code
|
||||||
|
sendPronto(prontoTest, PRONTO_ONCE, PRONTO_NOFALLBACK); // once code
|
||||||
|
sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_NOFALLBACK); // repeat code
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TEST
|
||||||
|
|
||||||
|
#endif // SEND_PRONTO
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//******************************************************************************
|
||||||
|
// Sources:
|
||||||
|
// http://www.remotecentral.com/features/irdisp2.htm
|
||||||
|
// http://www.hifi-remote.com/wiki/index.php?title=Working_With_Pronto_Hex
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define IRPRONTO
|
||||||
|
#include "IRremoteInt.h" // The Arduino IRremote library defines USECPERTICK
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Source: https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet
|
||||||
|
// -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
|
||||||
|
//
|
||||||
|
char prontoTest[] =
|
||||||
|
"0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60
|
||||||
|
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90
|
||||||
|
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100
|
||||||
|
"0010 0030 0010 0aa6"; // 104
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This is the longest code we can support
|
||||||
|
#define CODEMAX 200
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This is the data we pull out of the pronto code
|
||||||
|
typedef
|
||||||
|
struct {
|
||||||
|
int freq; // Carrier frequency (in Hz)
|
||||||
|
int usec; // uSec per tick (based on freq)
|
||||||
|
|
||||||
|
int codeLen; // Length of code
|
||||||
|
uint16_t code[CODEMAX]; // Code in hex
|
||||||
|
|
||||||
|
int onceLen; // Length of "once" transmit
|
||||||
|
uint16_t* once; // Pointer to start within 'code'
|
||||||
|
|
||||||
|
int rptLen; // Length of "repeat" transmit
|
||||||
|
uint16_t* rpt; // Pointer to start within 'code'
|
||||||
|
}
|
||||||
|
pronto_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// From what I have seen, the only time we go over 8-bits is the 'space'
|
||||||
|
// on the end which creates the lead-out/inter-code gap. Assuming I'm right,
|
||||||
|
// we can code this up as a special case and otherwise halve the size of our
|
||||||
|
// data!
|
||||||
|
// Ignoring the first four values (the config data) and the last value
|
||||||
|
// (the lead-out), if you find a protocol that uses values greater than 00fe
|
||||||
|
// we are going to have to revisit this code!
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// So, the 0th byte will be the carrier frequency in Khz (NOT Hz)
|
||||||
|
// " 1st " " " " length of the "once" code
|
||||||
|
// " 2nd " " " " length of the "repeat" code
|
||||||
|
//
|
||||||
|
// Thereafter, odd bytes will be Mark lengths as a multiple of USECPERTICK uS
|
||||||
|
// even " " " Space " " " " " " "
|
||||||
|
//
|
||||||
|
// Any occurence of "FF" in either a Mark or a Space will indicate
|
||||||
|
// "Use the 16-bit FF value" which will also be a multiple of USECPERTICK uS
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// As a point of comparison, the test code (prontoTest[]) is 520 bytes
|
||||||
|
// (yes, more than 0.5KB of our Arduino's precious 32KB) ... after conversion
|
||||||
|
// to pronto hex that goes down to ((520/5)*2) = 208 bytes ... once converted to
|
||||||
|
// our format we are down to ((208/2) -1 -1 +2) = 104 bytes
|
||||||
|
//
|
||||||
|
// In fariness this is still very memory-hungry
|
||||||
|
// ...As a rough guide:
|
||||||
|
// 10 codes cost 1K of memory (this will vary depending on the protocol).
|
||||||
|
//
|
||||||
|
// So if you're building a complex remote control, you will probably need to
|
||||||
|
// keep the codes on an external memory device (not in the Arduino sketch) and
|
||||||
|
// load them as you need them. Hmmm.
|
||||||
|
//
|
||||||
|
// This dictates that "Oscillated Pronto Codes" are probably NOT the way forward
|
||||||
|
//
|
||||||
|
// For example, prontoTest[] happens to be: A 48-bit IR code in Denon format
|
||||||
|
// So we know it starts with 80/40 (Denon header)
|
||||||
|
// and ends with 10/aa6 (Denon leadout)
|
||||||
|
// and all (48) bits in between are either 10/10 (Denon 0)
|
||||||
|
// or 10/30 (Denon 1)
|
||||||
|
// So we could easily store this data in 1-byte ("Denon")
|
||||||
|
// + 1-byte (Length=48)
|
||||||
|
// + 6-bytes (IR code)
|
||||||
|
// At 8-bytes per code, we can store 128 codes in 1KB or memory - that's a lot
|
||||||
|
// better than the 2 (two) we started off with!
|
||||||
|
//
|
||||||
|
// And serendipitously, by reducing the amount of data, our program will run
|
||||||
|
// a LOT faster!
|
||||||
|
//
|
||||||
|
// Again, I repeat, even after you have spent time converting the "Oscillated
|
||||||
|
// Pronto Codes" in to IRremote format, it will be a LOT more memory-hungry
|
||||||
|
// than using sendDenon() (or whichever) ...BUT these codes are easily
|
||||||
|
// available on the internet, so we'll support them!
|
||||||
|
//
|
||||||
|
typedef
|
||||||
|
struct {
|
||||||
|
uint16_t FF;
|
||||||
|
uint8_t code[CODEMAX];
|
||||||
|
}
|
||||||
|
irCode_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#define DEBUGF(...) printf(__VA_ARGS__)
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// String must be block of 4 hex digits separated with blanks
|
||||||
|
//
|
||||||
|
bool validate (char* cp, int* len)
|
||||||
|
{
|
||||||
|
for (*len = 0; *cp; (*len)++, cp += 4) {
|
||||||
|
byp(&cp);
|
||||||
|
if ( !ishex(cp[0]) || !ishex(cp[1]) ||
|
||||||
|
!ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Hex-to-Byte : Decode a hex digit
|
||||||
|
// We assume the character has already been validated
|
||||||
|
//
|
||||||
|
uint8_t htob (char ch)
|
||||||
|
{
|
||||||
|
if ((ch >= '0') && (ch <= '9')) return ch - '0' ;
|
||||||
|
if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ;
|
||||||
|
if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Hex-to-Word : Decode a block of 4 hex digits
|
||||||
|
// We assume the string has already been validated
|
||||||
|
// and the pointer being passed points at the start of a block of 4 hex digits
|
||||||
|
//
|
||||||
|
uint16_t htow (char* cp)
|
||||||
|
{
|
||||||
|
return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) |
|
||||||
|
(htob(cp[2]) << 4) | (htob(cp[3]) ) ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Convert the pronto string in to data
|
||||||
|
//
|
||||||
|
bool decode (char* s, pronto_t* p, irCode_t* ir)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
char* cp;
|
||||||
|
|
||||||
|
// Validate the Pronto string
|
||||||
|
if (!validate(s, &p->codeLen)) {
|
||||||
|
DEBUGF("Invalid pronto string\n");
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
DEBUGF("Found %d hex codes\n", p->codeLen);
|
||||||
|
|
||||||
|
// Allocate memory to store the decoded string
|
||||||
|
//if (!(p->code = malloc(p->len))) {
|
||||||
|
// DEBUGF("Memory allocation failed\n");
|
||||||
|
// return false ;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Check in case our code is too long
|
||||||
|
if (p->codeLen > CODEMAX) {
|
||||||
|
DEBUGF("Code too long, edit CODEMAX and recompile\n");
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the string
|
||||||
|
cp = s;
|
||||||
|
for (i = 0; i < p->codeLen; i++, cp += 4) {
|
||||||
|
byp(&cp);
|
||||||
|
p->code[i] = htow(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Announce our findings
|
||||||
|
DEBUGF("Input: |%s|\n", s);
|
||||||
|
DEBUGF("Found: |");
|
||||||
|
for (i = 0; i < p->codeLen; i++) DEBUGF("%04x ", p->code[i]) ;
|
||||||
|
DEBUGF("|\n");
|
||||||
|
|
||||||
|
DEBUGF("Form [%04X] : ", p->code[0]);
|
||||||
|
if (p->code[0] == 0x0000) DEBUGF("Oscillated (Learned)\n");
|
||||||
|
else if (p->code[0] == 0x0100) DEBUGF("Unmodulated\n");
|
||||||
|
else DEBUGF("Unknown\n");
|
||||||
|
if (p->code[0] != 0x0000) return false ; // Can only handle Oscillated
|
||||||
|
|
||||||
|
// Calculate the carrier frequency (+/- 10%) & uSecs per pulse
|
||||||
|
// Pronto uses a crystal which generates a timeabse of 0.241246
|
||||||
|
p->freq = (int)(1000000 / (p->code[1] * 0.241246));
|
||||||
|
p->usec = (int)(((1.0 / p->freq) * 1000000) + 0.5);
|
||||||
|
ir->code[0] = p->freq / 1000;
|
||||||
|
DEBUGF("Freq [%04X] : %d Hz (%d uS/pluse) -> %d KHz\n",
|
||||||
|
p->code[1], p->freq, p->usec, ir->code[0]);
|
||||||
|
|
||||||
|
// Set the length & start pointer for the "once" code
|
||||||
|
p->onceLen = p->code[2];
|
||||||
|
p->once = &p->code[4];
|
||||||
|
ir->code[1] = p->onceLen;
|
||||||
|
DEBUGF("Once [%04X] : %d\n", p->code[2], p->onceLen);
|
||||||
|
|
||||||
|
// Set the length & start pointer for the "repeat" code
|
||||||
|
p->rptLen = p->code[3];
|
||||||
|
p->rpt = &p->code[4 + p->onceLen];
|
||||||
|
ir->code[2] = p->rptLen;
|
||||||
|
DEBUGF("Rpt [%04X] : %d\n", p->code[3], p->rptLen);
|
||||||
|
|
||||||
|
// Check everything tallies
|
||||||
|
if (1 + 1 + 1 + 1 + (p->onceLen * 2) + (p->rptLen * 2) != p->codeLen) {
|
||||||
|
DEBUGF("Bad code length\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the IR data to our new format
|
||||||
|
ir->FF = p->code[p->codeLen - 1];
|
||||||
|
|
||||||
|
len = (p->onceLen * 2) + (p->rptLen * 2);
|
||||||
|
DEBUGF("Encoded: |");
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (p->code[i+4] == ir->FF) {
|
||||||
|
ir->code[i+3] = 0xFF;
|
||||||
|
} else if (p->code[i+4] > 0xFE) {
|
||||||
|
DEBUGF("\n%04X : Mark/Space overflow\n", p->code[i+4]);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
ir->code[i+3] = (p->code[i+4] * p->usec) / USECPERTICK;
|
||||||
|
}
|
||||||
|
DEBUGF("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]);
|
||||||
|
}
|
||||||
|
DEBUGF("|\n");
|
||||||
|
|
||||||
|
ir->FF = (ir->FF * p->usec) / USECPERTICK;
|
||||||
|
DEBUGF("FF -> %d\n", ir->FF);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
//
|
||||||
|
void irDump (irCode_t* ir)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
|
||||||
|
printf("uint8_t buttonName[%d] = {", len);
|
||||||
|
|
||||||
|
printf("%d,%d, ", (ir->FF >> 8), ir->FF & 0xFF);
|
||||||
|
printf("%d,%d,%d, ", ir->code[0], ir->code[1], ir->code[2]);
|
||||||
|
|
||||||
|
len = (ir->code[1] * 2) + (ir->code[2] * 2);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
printf("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("};\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
//
|
||||||
|
int main ( )
|
||||||
|
{
|
||||||
|
pronto_t pCode;
|
||||||
|
irCode_t irCode;
|
||||||
|
|
||||||
|
decode(prontoTest, &pCode, &irCode);
|
||||||
|
|
||||||
|
irDump(&irCode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //0
|
223
IRremote/irRecv.cpp
Normal file
223
IRremote/irRecv.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Decodes the received IR message
|
||||||
|
// Returns 0 if no data ready, 1 if data ready.
|
||||||
|
// Results of decoding are stored in results
|
||||||
|
//
|
||||||
|
int IRrecv::decode (decode_results *results)
|
||||||
|
{
|
||||||
|
results->rawbuf = irparams.rawbuf;
|
||||||
|
results->rawlen = irparams.rawlen;
|
||||||
|
|
||||||
|
results->overflow = irparams.overflow;
|
||||||
|
|
||||||
|
if (irparams.rcvstate != STATE_STOP) return false ;
|
||||||
|
|
||||||
|
#if DECODE_NEC
|
||||||
|
DBG_PRINTLN("Attempting NEC decode");
|
||||||
|
if (decodeNEC(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_SONY
|
||||||
|
DBG_PRINTLN("Attempting Sony decode");
|
||||||
|
if (decodeSony(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_SANYO
|
||||||
|
DBG_PRINTLN("Attempting Sanyo decode");
|
||||||
|
if (decodeSanyo(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_MITSUBISHI
|
||||||
|
DBG_PRINTLN("Attempting Mitsubishi decode");
|
||||||
|
if (decodeMitsubishi(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_RC5
|
||||||
|
DBG_PRINTLN("Attempting RC5 decode");
|
||||||
|
if (decodeRC5(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_RC6
|
||||||
|
DBG_PRINTLN("Attempting RC6 decode");
|
||||||
|
if (decodeRC6(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_PANASONIC
|
||||||
|
DBG_PRINTLN("Attempting Panasonic decode");
|
||||||
|
if (decodePanasonic(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_LG
|
||||||
|
DBG_PRINTLN("Attempting LG decode");
|
||||||
|
if (decodeLG(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_JVC
|
||||||
|
DBG_PRINTLN("Attempting JVC decode");
|
||||||
|
if (decodeJVC(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_SAMSUNG
|
||||||
|
DBG_PRINTLN("Attempting SAMSUNG decode");
|
||||||
|
if (decodeSAMSUNG(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_WHYNTER
|
||||||
|
DBG_PRINTLN("Attempting Whynter decode");
|
||||||
|
if (decodeWhynter(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_AIWA_RC_T501
|
||||||
|
DBG_PRINTLN("Attempting Aiwa RC-T501 decode");
|
||||||
|
if (decodeAiwaRCT501(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_DENON
|
||||||
|
DBG_PRINTLN("Attempting Denon decode");
|
||||||
|
if (decodeDenon(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DECODE_LEGO_PF
|
||||||
|
DBG_PRINTLN("Attempting Lego Power Functions");
|
||||||
|
if (decodeLegoPowerFunctions(results)) return true ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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(results)) return true ;
|
||||||
|
|
||||||
|
// 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 ( )
|
||||||
|
{
|
||||||
|
// Interrupt Service Routine - Fires every 50uS
|
||||||
|
cli();
|
||||||
|
// 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)
|
||||||
|
TIMER_CONFIG_NORMAL();
|
||||||
|
|
||||||
|
// Timer2 Overflow Interrupt Enable
|
||||||
|
TIMER_ENABLE_INTR;
|
||||||
|
|
||||||
|
TIMER_RESET;
|
||||||
|
|
||||||
|
sei(); // enable interrupts
|
||||||
|
|
||||||
|
// Initialize state machine variables
|
||||||
|
irparams.rcvstate = STATE_IDLE;
|
||||||
|
irparams.rawlen = 0;
|
||||||
|
|
||||||
|
// Set pin modes
|
||||||
|
pinMode(irparams.recvpin, INPUT);
|
||||||
|
}
|
||||||
|
#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 == STATE_IDLE || irparams.rcvstate == STATE_STOP) ? true : false;
|
||||||
|
}
|
||||||
|
//+=============================================================================
|
||||||
|
// Restart the ISR state machine
|
||||||
|
//
|
||||||
|
void IRrecv::resume ( )
|
||||||
|
{
|
||||||
|
irparams.rcvstate = STATE_IDLE;
|
||||||
|
irparams.rawlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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 < oldval * .8) return 0 ;
|
||||||
|
else if (oldval < newval * .8) return 2 ;
|
||||||
|
else return 1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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
|
||||||
|
|
||||||
|
long IRrecv::decodeHash (decode_results *results)
|
||||||
|
{
|
||||||
|
long hash = FNV_BASIS_32;
|
||||||
|
|
||||||
|
// Require at least 6 samples to prevent triggering on noise
|
||||||
|
if (results->rawlen < 6) return false ;
|
||||||
|
|
||||||
|
for (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;
|
||||||
|
}
|
139
IRremote/irSend.cpp
Normal file
139
IRremote/irSend.cpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
#ifdef SENDING_SUPPORTED
|
||||||
|
//+=============================================================================
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SOFT_CARRIER
|
||||||
|
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_CARRIER
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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_CARRIER
|
||||||
|
unsigned long start = micros();
|
||||||
|
unsigned long stop = start + time;
|
||||||
|
if (stop + periodTime < 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(periodOnTime);
|
||||||
|
SENDPIN_OFF(sendPin);
|
||||||
|
nextPeriodEnding += periodTime;
|
||||||
|
sleepUntilMicros(nextPeriodEnding);
|
||||||
|
now = micros();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
TIMER_ENABLE_PWM; // Enable pin 3 PWM output
|
||||||
|
if (time > 0) custom_delay_usec(time);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
TIMER_DISABLE_PWM; // Disable pin 3 PWM output
|
||||||
|
if (time > 0) IRsend::custom_delay_usec(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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_CARRIER
|
||||||
|
periodTime = (1000U + khz/2) / khz; // = 1000/khz + 1/2 = round(1000.0/khz)
|
||||||
|
periodOnTime = periodTime * DUTY_CYCLE / 100U - PULSE_CORRECTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Disable the Timer2 Interrupt (which is used for receiving IR)
|
||||||
|
TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
|
||||||
|
|
||||||
|
pinMode(sendPin, OUTPUT);
|
||||||
|
SENDPIN_OFF(sendPin); // When not sending, we want it low
|
||||||
|
|
||||||
|
// COM2A = 00: disconnect OC2A
|
||||||
|
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
|
||||||
|
// WGM2 = 101: phase-correct PWM with OCRA as top
|
||||||
|
// CS2 = 000: no prescaling
|
||||||
|
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
|
||||||
|
TIMER_CONFIG_KHZ(khz);
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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
|
105
IRremote/ir_Aiwa.cpp
Normal file
105
IRremote/ir_Aiwa.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 8800
|
||||||
|
#define AIWA_RC_T501_HDR_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_HDR_MARK);
|
||||||
|
space(AIWA_RC_T501_HDR_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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_AIWA_RC_T501
|
||||||
|
bool IRrecv::decodeAiwaRCT501 (decode_results *results)
|
||||||
|
{
|
||||||
|
int data = 0;
|
||||||
|
int offset = 1;
|
||||||
|
|
||||||
|
// Check SIZE
|
||||||
|
if (irparams.rawlen < 2 * (AIWA_RC_T501_SUM_BITS) + 4) return false ;
|
||||||
|
|
||||||
|
// Check HDR Mark/Space
|
||||||
|
if (!MATCH_MARK (results->rawbuf[offset++], AIWA_RC_T501_HDR_MARK )) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], AIWA_RC_T501_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
offset += 26; // skip pre-data - optional
|
||||||
|
while(offset < irparams.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;
|
||||||
|
}
|
||||||
|
#endif
|
94
IRremote/ir_Denon.cpp
Normal file
94
IRremote/ir_Denon.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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 BITS 14 // The number of bits in the command
|
||||||
|
|
||||||
|
#define HDR_MARK 300 // The length of the Header:Mark
|
||||||
|
#define HDR_SPACE 750 // The lenght of the Header:Space
|
||||||
|
|
||||||
|
#define BIT_MARK 300 // The length of a Bit:Mark
|
||||||
|
#define ONE_SPACE 1800 // The length of a Bit:Space for 1's
|
||||||
|
#define 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 (HDR_MARK);
|
||||||
|
space(HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark (BIT_MARK);
|
||||||
|
space(ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark (BIT_MARK);
|
||||||
|
space(ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
mark(BIT_MARK);
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
//
|
||||||
|
#if DECODE_DENON
|
||||||
|
bool IRrecv::decodeDenon (decode_results *results)
|
||||||
|
{
|
||||||
|
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 * BITS) + 1) return false ;
|
||||||
|
|
||||||
|
// Check initial Mark+Space match
|
||||||
|
if (!MATCH_MARK (results->rawbuf[offset++], HDR_MARK )) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
// Read the bits in
|
||||||
|
for (int i = 0; i < BITS; i++) {
|
||||||
|
// Each bit looks like: MARK + SPACE_1 -> 1
|
||||||
|
// or : MARK + SPACE_0 -> 0
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
// IR data is big-endian, so we shuffle it in from the right:
|
||||||
|
if (MATCH_SPACE(results->rawbuf[offset], ONE_SPACE)) data = (data << 1) | 1 ;
|
||||||
|
else if (MATCH_SPACE(results->rawbuf[offset], ZERO_SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = BITS;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = DENON;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
54
IRremote/ir_Dish.cpp
Normal file
54
IRremote/ir_Dish.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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 sned 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_HDR_MARK 400
|
||||||
|
#define DISH_HDR_SPACE 6100
|
||||||
|
#define DISH_BIT_MARK 400
|
||||||
|
#define DISH_ONE_SPACE 1700
|
||||||
|
#define DISH_ZERO_SPACE 2800
|
||||||
|
#define DISH_RPT_SPACE 6200
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_DISH
|
||||||
|
void IRsend::sendDISH (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(56);
|
||||||
|
|
||||||
|
mark(DISH_HDR_MARK);
|
||||||
|
space(DISH_HDR_SPACE);
|
||||||
|
|
||||||
|
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_HDR_MARK); //added 26th March 2016, by AnalysIR ( https://www.AnalysIR.com )
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
101
IRremote/ir_JVC.cpp
Normal file
101
IRremote/ir_JVC.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 8000
|
||||||
|
#define JVC_HDR_SPACE 4000
|
||||||
|
#define JVC_BIT_MARK 600
|
||||||
|
#define JVC_ONE_SPACE 1600
|
||||||
|
#define JVC_ZERO_SPACE 550
|
||||||
|
#define JVC_RPT_LENGTH 60000
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
#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_HDR_MARK);
|
||||||
|
space(JVC_HDR_SPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark(JVC_BIT_MARK);
|
||||||
|
space(JVC_ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark(JVC_BIT_MARK);
|
||||||
|
space(JVC_ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
mark(JVC_BIT_MARK);
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_JVC
|
||||||
|
bool IRrecv::decodeJVC (decode_results *results)
|
||||||
|
{
|
||||||
|
long data = 0;
|
||||||
|
int offset = 1; // Skip first space
|
||||||
|
|
||||||
|
// Check for repeat
|
||||||
|
if ( (irparams.rawlen - 1 == 33)
|
||||||
|
&& MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)
|
||||||
|
&& MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK)
|
||||||
|
) {
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
results->decode_type = JVC;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], JVC_HDR_MARK)) return false ;
|
||||||
|
|
||||||
|
if (irparams.rawlen < (2 * JVC_BITS) + 1 ) return false ;
|
||||||
|
|
||||||
|
// Initial space
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], JVC_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
for (int i = 0; i < JVC_BITS; i++) {
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], JVC_BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) data = (data << 1) | 1 ;
|
||||||
|
else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
80
IRremote/ir_LG.cpp
Normal file
80
IRremote/ir_LG.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// L GGGG
|
||||||
|
// L G
|
||||||
|
// L G GG
|
||||||
|
// L G G
|
||||||
|
// LLLLL GGG
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#define LG_BITS 28
|
||||||
|
|
||||||
|
#define LG_HDR_MARK 8000
|
||||||
|
#define LG_HDR_SPACE 4000
|
||||||
|
#define LG_BIT_MARK 600
|
||||||
|
#define LG_ONE_SPACE 1600
|
||||||
|
#define LG_ZERO_SPACE 550
|
||||||
|
#define LG_RPT_LENGTH 60000
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_LG
|
||||||
|
bool IRrecv::decodeLG (decode_results *results)
|
||||||
|
{
|
||||||
|
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_HDR_MARK)) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], LG_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
for (int i = 0; i < LG_BITS; i++) {
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], LG_BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_LG
|
||||||
|
void IRsend::sendLG (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(38);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(LG_HDR_MARK);
|
||||||
|
space(LG_HDR_SPACE);
|
||||||
|
mark(LG_BIT_MARK);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
46
IRremote/ir_Lego_PF.cpp
Normal file
46
IRremote/ir_Lego_PF.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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
|
115
IRremote/ir_Lego_PF_BitStreamEncoder.h
Normal file
115
IRremote/ir_Lego_PF_BitStreamEncoder.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
85
IRremote/ir_Mitsubishi.cpp
Normal file
85
IRremote/ir_Mitsubishi.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 250 // seen range 3500
|
||||||
|
#define MITSUBISHI_HDR_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 ssee 713 - not using ticks as get number wrapround
|
||||||
|
// #define MITSUBISHI_RPT_LENGTH 45000
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_MITSUBISHI
|
||||||
|
bool IRrecv::decodeMitsubishi (decode_results *results)
|
||||||
|
{
|
||||||
|
// Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2);
|
||||||
|
long data = 0;
|
||||||
|
if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) return false ;
|
||||||
|
int offset = 0; // 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[offset]);
|
||||||
|
Serial.println( "test against:");
|
||||||
|
Serial.println(results->rawbuf[offset]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Not seeing double keys from Mitsubishi
|
||||||
|
if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) {
|
||||||
|
// Serial.print("IR Gap found: ");
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
results->decode_type = MITSUBISHI;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// 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_HDR_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_HDR_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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
98
IRremote/ir_NEC.cpp
Normal file
98
IRremote/ir_NEC.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 9000
|
||||||
|
#define NEC_HDR_SPACE 4500
|
||||||
|
#define NEC_BIT_MARK 560
|
||||||
|
#define NEC_ONE_SPACE 1690
|
||||||
|
#define NEC_ZERO_SPACE 560
|
||||||
|
#define NEC_RPT_SPACE 2250
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_NEC
|
||||||
|
void IRsend::sendNEC (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(38);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(NEC_HDR_MARK);
|
||||||
|
space(NEC_HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark(NEC_BIT_MARK);
|
||||||
|
space(NEC_ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark(NEC_BIT_MARK);
|
||||||
|
space(NEC_ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
mark(NEC_BIT_MARK);
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// NECs have a repeat only 4 items long
|
||||||
|
//
|
||||||
|
#if DECODE_NEC
|
||||||
|
bool IRrecv::decodeNEC (decode_results *results)
|
||||||
|
{
|
||||||
|
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_HDR_MARK)) return false ;
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Check for repeat
|
||||||
|
if ( (irparams.rawlen == 4)
|
||||||
|
&& MATCH_SPACE(results->rawbuf[offset ], NEC_RPT_SPACE)
|
||||||
|
&& MATCH_MARK (results->rawbuf[offset+1], NEC_BIT_MARK )
|
||||||
|
) {
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
results->decode_type = NEC;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we have enough data
|
||||||
|
if (irparams.rawlen < (2 * NEC_BITS) + 4) return false ;
|
||||||
|
|
||||||
|
// Check header "space"
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) return false ;
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Build the data
|
||||||
|
for (int i = 0; i < NEC_BITS; i++) {
|
||||||
|
// Check data "mark"
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) return false ;
|
||||||
|
offset++;
|
||||||
|
// Suppend this bit
|
||||||
|
if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE )) data = (data << 1) | 1 ;
|
||||||
|
else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = NEC_BITS;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = NEC;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
78
IRremote/ir_Panasonic.cpp
Normal file
78
IRremote/ir_Panasonic.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 3502
|
||||||
|
#define PANASONIC_HDR_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(35);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(PANASONIC_HDR_MARK);
|
||||||
|
space(PANASONIC_HDR_SPACE);
|
||||||
|
|
||||||
|
// Address
|
||||||
|
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
|
||||||
|
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 (decode_results *results)
|
||||||
|
{
|
||||||
|
unsigned long long data = 0;
|
||||||
|
int offset = 1;
|
||||||
|
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_HDR_MARK )) return false ;
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
// decode address
|
||||||
|
for (int i = 0; i < PANASONIC_BITS; i++) {
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
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 = (unsigned long)data;
|
||||||
|
results->address = (unsigned int)(data >> 32);
|
||||||
|
results->decode_type = PANASONIC;
|
||||||
|
results->bits = PANASONIC_BITS;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
207
IRremote/ir_RC5_RC6.cpp
Normal file
207
IRremote/ir_RC5_RC6.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// Gets one undecoded level at a time from the raw buffer.
|
||||||
|
// The RC5/6 decoding is easier if the data is broken into time intervals.
|
||||||
|
// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
|
||||||
|
// successive calls to getRClevel will return MARK, MARK, SPACE.
|
||||||
|
// offset and used are updated to keep track of the current position.
|
||||||
|
// t1 is the time interval for a single bit in microseconds.
|
||||||
|
// Returns -1 for error (measured time interval is not a multiple of t1).
|
||||||
|
//
|
||||||
|
#if (DECODE_RC5 || DECODE_RC6)
|
||||||
|
int IRrecv::getRClevel (decode_results *results, int *offset, int *used, int t1)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int val;
|
||||||
|
int correction;
|
||||||
|
int avail;
|
||||||
|
|
||||||
|
if (*offset >= results->rawlen) return SPACE ; // After end of recorded buffer, assume SPACE.
|
||||||
|
width = results->rawbuf[*offset];
|
||||||
|
val = ((*offset) % 2) ? MARK : SPACE;
|
||||||
|
correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
|
||||||
|
|
||||||
|
if (MATCH(width, ( t1) + correction)) avail = 1 ;
|
||||||
|
else if (MATCH(width, (2*t1) + correction)) avail = 2 ;
|
||||||
|
else if (MATCH(width, (3*t1) + correction)) avail = 3 ;
|
||||||
|
else return -1 ;
|
||||||
|
|
||||||
|
(*used)++;
|
||||||
|
if (*used >= avail) {
|
||||||
|
*used = 0;
|
||||||
|
(*offset)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_PRINTLN( (val == MARK) ? "MARK" : "SPACE" );
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// RRRR CCCC 55555
|
||||||
|
// R R C 5
|
||||||
|
// RRRR C 5555
|
||||||
|
// R R C 5
|
||||||
|
// R R CCCC 5555
|
||||||
|
//
|
||||||
|
// NB: First bit must be a one (start bit)
|
||||||
|
//
|
||||||
|
#define MIN_RC5_SAMPLES 11
|
||||||
|
#define RC5_T1 889
|
||||||
|
#define RC5_RPT_LENGTH 46000
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_RC5
|
||||||
|
void IRsend::sendRC5 (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(36);
|
||||||
|
|
||||||
|
// Start
|
||||||
|
mark(RC5_T1);
|
||||||
|
space(RC5_T1);
|
||||||
|
mark(RC5_T1);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
space(RC5_T1); // 1 is space, then mark
|
||||||
|
mark(RC5_T1);
|
||||||
|
} else {
|
||||||
|
mark(RC5_T1);
|
||||||
|
space(RC5_T1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_RC5
|
||||||
|
bool IRrecv::decodeRC5 (decode_results *results)
|
||||||
|
{
|
||||||
|
int nbits;
|
||||||
|
long data = 0;
|
||||||
|
int used = 0;
|
||||||
|
int offset = 1; // Skip gap space
|
||||||
|
|
||||||
|
if (irparams.rawlen < MIN_RC5_SAMPLES + 2) return false ;
|
||||||
|
|
||||||
|
// Get start bits
|
||||||
|
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return false ;
|
||||||
|
if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return false ;
|
||||||
|
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return false ;
|
||||||
|
|
||||||
|
for (nbits = 0; offset < irparams.rawlen; nbits++) {
|
||||||
|
int levelA = getRClevel(results, &offset, &used, RC5_T1);
|
||||||
|
int levelB = getRClevel(results, &offset, &used, RC5_T1);
|
||||||
|
|
||||||
|
if ((levelA == SPACE) && (levelB == MARK )) data = (data << 1) | 1 ;
|
||||||
|
else if ((levelA == MARK ) && (levelB == SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = nbits;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = RC5;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// RRRR CCCC 6666
|
||||||
|
// R R C 6
|
||||||
|
// RRRR C 6666
|
||||||
|
// R R C 6 6
|
||||||
|
// R R CCCC 666
|
||||||
|
//
|
||||||
|
// NB : Caller needs to take care of flipping the toggle bit
|
||||||
|
//
|
||||||
|
#define MIN_RC6_SAMPLES 1
|
||||||
|
#define RC6_HDR_MARK 2666
|
||||||
|
#define RC6_HDR_SPACE 889
|
||||||
|
#define RC6_T1 444
|
||||||
|
#define RC6_RPT_LENGTH 46000
|
||||||
|
|
||||||
|
#if SEND_RC6
|
||||||
|
void IRsend::sendRC6 (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(36);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(RC6_HDR_MARK);
|
||||||
|
space(RC6_HDR_SPACE);
|
||||||
|
|
||||||
|
// Start bit
|
||||||
|
mark(RC6_T1);
|
||||||
|
space(RC6_T1);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long i = 1, mask = 1UL << (nbits - 1); mask; i++, mask >>= 1) {
|
||||||
|
// The fourth bit we send is a "double width trailer bit"
|
||||||
|
int t = (i == 4) ? (RC6_T1 * 2) : (RC6_T1) ;
|
||||||
|
if (data & mask) {
|
||||||
|
mark(t);
|
||||||
|
space(t);
|
||||||
|
} else {
|
||||||
|
space(t);
|
||||||
|
mark(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_RC6
|
||||||
|
bool IRrecv::decodeRC6 (decode_results *results)
|
||||||
|
{
|
||||||
|
int nbits;
|
||||||
|
long data = 0;
|
||||||
|
int used = 0;
|
||||||
|
int offset = 1; // Skip first space
|
||||||
|
|
||||||
|
if (results->rawlen < MIN_RC6_SAMPLES) return false ;
|
||||||
|
|
||||||
|
// Initial mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], RC6_HDR_MARK)) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], RC6_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
// Get start bit (1)
|
||||||
|
if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return false ;
|
||||||
|
if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return false ;
|
||||||
|
|
||||||
|
for (nbits = 0; offset < results->rawlen; nbits++) {
|
||||||
|
int levelA, levelB; // Next two levels
|
||||||
|
|
||||||
|
levelA = getRClevel(results, &offset, &used, RC6_T1);
|
||||||
|
if (nbits == 3) {
|
||||||
|
// T bit is double wide; make sure second half matches
|
||||||
|
if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
levelB = getRClevel(results, &offset, &used, RC6_T1);
|
||||||
|
if (nbits == 3) {
|
||||||
|
// T bit is double wide; make sure second half matches
|
||||||
|
if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((levelA == MARK ) && (levelB == SPACE)) data = (data << 1) | 1 ; // inverted compared to RC5
|
||||||
|
else if ((levelA == SPACE) && (levelB == MARK )) data = (data << 1) | 0 ; // ...
|
||||||
|
else return false ; // Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = nbits;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = RC6;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
92
IRremote/ir_Samsung.cpp
Normal file
92
IRremote/ir_Samsung.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 5000
|
||||||
|
#define SAMSUNG_HDR_SPACE 5000
|
||||||
|
#define SAMSUNG_BIT_MARK 560
|
||||||
|
#define SAMSUNG_ONE_SPACE 1600
|
||||||
|
#define SAMSUNG_ZERO_SPACE 560
|
||||||
|
#define SAMSUNG_RPT_SPACE 2250
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_SAMSUNG
|
||||||
|
void IRsend::sendSAMSUNG (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(38);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(SAMSUNG_HDR_MARK);
|
||||||
|
space(SAMSUNG_HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark(SAMSUNG_BIT_MARK);
|
||||||
|
space(SAMSUNG_ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark(SAMSUNG_BIT_MARK);
|
||||||
|
space(SAMSUNG_ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (decode_results *results)
|
||||||
|
{
|
||||||
|
long data = 0;
|
||||||
|
int offset = 1; // Skip first space
|
||||||
|
|
||||||
|
// Initial mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_HDR_MARK)) return false ;
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Check for repeat
|
||||||
|
if ( (irparams.rawlen == 4)
|
||||||
|
&& MATCH_SPACE(results->rawbuf[offset], SAMSUNG_RPT_SPACE)
|
||||||
|
&& MATCH_MARK(results->rawbuf[offset+1], SAMSUNG_BIT_MARK)
|
||||||
|
) {
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
results->decode_type = SAMSUNG;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (irparams.rawlen < (2 * SAMSUNG_BITS) + 4) return false ;
|
||||||
|
|
||||||
|
// Initial space
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], SAMSUNG_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
for (int i = 0; i < SAMSUNG_BITS; i++) {
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], SAMSUNG_BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) data = (data << 1) | 1 ;
|
||||||
|
else if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = SAMSUNG_BITS;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = SAMSUNG;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
76
IRremote/ir_Sanyo.cpp
Normal file
76
IRremote/ir_Sanyo.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 3500 // seen range 3500
|
||||||
|
#define SANYO_HDR_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 ssee 713 - not using ticks as get number wrapround
|
||||||
|
#define SANYO_RPT_LENGTH 45000
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_SANYO
|
||||||
|
bool IRrecv::decodeSanyo (decode_results *results)
|
||||||
|
{
|
||||||
|
long data = 0;
|
||||||
|
int offset = 0; // Skip first space <-- CHECK THIS!
|
||||||
|
|
||||||
|
if (irparams.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]);
|
||||||
|
Serial.println( "test against:");
|
||||||
|
Serial.println(results->rawbuf[offset]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initial space
|
||||||
|
if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) {
|
||||||
|
//Serial.print("IR Gap found: ");
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
results->decode_type = SANYO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Initial mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], SANYO_HDR_MARK)) return false ;
|
||||||
|
|
||||||
|
// Skip Second Mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], SANYO_HDR_MARK)) return false ;
|
||||||
|
|
||||||
|
while (offset + 1 < irparams.rawlen) {
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], SANYO_HDR_SPACE)) break ;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
71
IRremote/ir_Sharp.cpp
Normal file
71
IRremote/ir_Sharp.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_BIT_MARK 245
|
||||||
|
#define SHARP_ONE_SPACE 1805
|
||||||
|
#define SHARP_ZERO_SPACE 795
|
||||||
|
#define SHARP_GAP 600000
|
||||||
|
#define SHARP_RPT_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 behaviour of CD-S6470 remote control.
|
||||||
|
for (int n = 0; n < 3; n++) {
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark(SHARP_BIT_MARK);
|
||||||
|
space(SHARP_ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark(SHARP_BIT_MARK);
|
||||||
|
space(SHARP_ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark(SHARP_BIT_MARK);
|
||||||
|
space(SHARP_ZERO_SPACE);
|
||||||
|
delay(40);
|
||||||
|
|
||||||
|
data = data ^ SHARP_TOGGLE_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
#endif
|
95
IRremote/ir_Sony.cpp
Normal file
95
IRremote/ir_Sony.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 2400
|
||||||
|
#define SONY_HDR_SPACE 600
|
||||||
|
#define SONY_ONE_MARK 1200
|
||||||
|
#define SONY_ZERO_MARK 600
|
||||||
|
#define SONY_RPT_LENGTH 45000
|
||||||
|
#define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if SEND_SONY
|
||||||
|
void IRsend::sendSony (unsigned long data, int nbits)
|
||||||
|
{
|
||||||
|
// Set IR carrier frequency
|
||||||
|
enableIROut(40);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(SONY_HDR_MARK);
|
||||||
|
space(SONY_HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark(SONY_ONE_MARK);
|
||||||
|
space(SONY_HDR_SPACE);
|
||||||
|
} else {
|
||||||
|
mark(SONY_ZERO_MARK);
|
||||||
|
space(SONY_HDR_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will have ended with LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_SONY
|
||||||
|
bool IRrecv::decodeSony (decode_results *results)
|
||||||
|
{
|
||||||
|
long data = 0;
|
||||||
|
int offset = 0; // Dont skip first space, check its size
|
||||||
|
|
||||||
|
if (irparams.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] < SONY_DOUBLE_SPACE_USECS) {
|
||||||
|
// Serial.print("IR Gap found: ");
|
||||||
|
results->bits = 0;
|
||||||
|
results->value = REPEAT;
|
||||||
|
|
||||||
|
# ifdef DECODE_SANYO
|
||||||
|
results->decode_type = SANYO;
|
||||||
|
# else
|
||||||
|
results->decode_type = UNKNOWN;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Initial mark
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], SONY_HDR_MARK)) return false ;
|
||||||
|
|
||||||
|
while (offset + 1 < irparams.rawlen) {
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], SONY_HDR_SPACE)) break ;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
179
IRremote/ir_Template.cpp
Normal file
179
IRremote/ir_Template.cpp
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
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 *results) ;
|
||||||
|
#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"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// S H U Z U
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#define BITS 32 // The number of bits in the command
|
||||||
|
|
||||||
|
#define HDR_MARK 1000 // The length of the Header:Mark
|
||||||
|
#define HDR_SPACE 2000 // The lenght of the Header:Space
|
||||||
|
|
||||||
|
#define BIT_MARK 3000 // The length of a Bit:Mark
|
||||||
|
#define ONE_SPACE 4000 // The length of a Bit:Space for 1's
|
||||||
|
#define ZERO_SPACE 5000 // The length of a Bit:Space for 0's
|
||||||
|
|
||||||
|
#define 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 (HDR_MARK);
|
||||||
|
space(HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
mark (BIT_MARK);
|
||||||
|
space(ONE_SPACE);
|
||||||
|
} else {
|
||||||
|
mark (BIT_MARK);
|
||||||
|
space(ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
mark(BIT_MARK);
|
||||||
|
space(0); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
//
|
||||||
|
#if DECODE_SHUZU
|
||||||
|
bool IRrecv::decodeShuzu (decode_results *results)
|
||||||
|
{
|
||||||
|
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 * BITS) + 1) return false ;
|
||||||
|
|
||||||
|
// Check initial Mark+Space match
|
||||||
|
if (!MATCH_MARK (results->rawbuf[offset++], HDR_MARK )) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
// 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++], BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
// IR data is big-endian, so we shuffle it in from the right:
|
||||||
|
if (MATCH_SPACE(results->rawbuf[offset], ONE_SPACE)) data = (data << 1) | 1 ;
|
||||||
|
else if (MATCH_SPACE(results->rawbuf[offset], ZERO_SPACE)) data = (data << 1) | 0 ;
|
||||||
|
else return false ;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
results->bits = BITS;
|
||||||
|
results->value = data;
|
||||||
|
results->decode_type = SHUZU;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
91
IRremote/ir_Whynter.cpp
Normal file
91
IRremote/ir_Whynter.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.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_HDR_MARK 2850
|
||||||
|
#define WHYNTER_HDR_SPACE 2850
|
||||||
|
#define WHYNTER_BIT_MARK 750
|
||||||
|
#define WHYNTER_ONE_MARK 750
|
||||||
|
#define WHYNTER_ONE_SPACE 2150
|
||||||
|
#define WHYNTER_ZERO_MARK 750
|
||||||
|
#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_ZERO_MARK);
|
||||||
|
space(WHYNTER_ZERO_SPACE);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
mark(WHYNTER_HDR_MARK);
|
||||||
|
space(WHYNTER_HDR_SPACE);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
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_ZERO_MARK);
|
||||||
|
space(WHYNTER_ZERO_SPACE); // Always end with the LED off
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
#if DECODE_WHYNTER
|
||||||
|
bool IRrecv::decodeWhynter (decode_results *results)
|
||||||
|
{
|
||||||
|
long data = 0;
|
||||||
|
int offset = 1; // skip initial space
|
||||||
|
|
||||||
|
// Check we have the right amount of data
|
||||||
|
if (irparams.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 ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], WHYNTER_ZERO_SPACE)) return false ;
|
||||||
|
|
||||||
|
// header mark and space
|
||||||
|
if (!MATCH_MARK (results->rawbuf[offset++], WHYNTER_HDR_MARK )) return false ;
|
||||||
|
if (!MATCH_SPACE(results->rawbuf[offset++], WHYNTER_HDR_SPACE)) return false ;
|
||||||
|
|
||||||
|
// data bits
|
||||||
|
for (int i = 0; i < WHYNTER_BITS; i++) {
|
||||||
|
if (!MATCH_MARK(results->rawbuf[offset++], WHYNTER_BIT_MARK)) return false ;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
24
IRremote/library.json
Normal file
24
IRremote/library.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "IRremote",
|
||||||
|
"keywords": "infrared, ir, remote",
|
||||||
|
"description": "Send and receive infrared signals with multiple protocols",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/z3t0/Arduino-IRremote.git"
|
||||||
|
},
|
||||||
|
"version": "2.3.3",
|
||||||
|
"frameworks": "arduino",
|
||||||
|
"platforms": "atmelavr",
|
||||||
|
"authors" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name":"Rafi Khan",
|
||||||
|
"email":"zetoslab@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Ken Shirriff",
|
||||||
|
"email":"ken.shirriff@gmail.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
9
IRremote/library.properties
Normal file
9
IRremote/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=IRremote
|
||||||
|
version=2.2.3
|
||||||
|
author=shirriff
|
||||||
|
maintainer=shirriff
|
||||||
|
sentence=Send and receive infrared signals with multiple protocols
|
||||||
|
paragraph=Send and receive infrared signals with multiple protocols
|
||||||
|
category=Signal Input/Output
|
||||||
|
url=https://github.com/shirriff/Arduino-IRremote.git
|
||||||
|
architectures=*
|
102
IRremote/sam.cpp
Normal file
102
IRremote/sam.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Support routines for SAM processor boards
|
||||||
|
|
||||||
|
#include "IRremote.h"
|
||||||
|
#include "IRremoteInt.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
|
||||||
|
|
||||||
|
// "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;
|
||||||
|
|
||||||
|
TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
|
||||||
|
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||||
|
|
||||||
|
// Use the 16-bit timer
|
||||||
|
TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
|
||||||
|
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||||
|
|
||||||
|
// Use match mode so that the timer counter resets when the count matches the compare register
|
||||||
|
TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
|
||||||
|
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||||
|
|
||||||
|
// Set prescaler to 1024
|
||||||
|
//TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024;
|
||||||
|
TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV64;
|
||||||
|
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||||
|
|
||||||
|
setTimerFrequency(1000000 / USECPERTICK);
|
||||||
|
|
||||||
|
// Enable the compare interrupt
|
||||||
|
TC->INTENSET.reg = 0;
|
||||||
|
TC->INTENSET.bit.MC0 = 1;
|
||||||
|
|
||||||
|
NVIC_EnableIRQ(TC3_IRQn);
|
||||||
|
|
||||||
|
TC->CTRLA.reg |= TC_CTRLA_ENABLE;
|
||||||
|
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
|
||||||
|
}
|
||||||
|
|
||||||
|
//+=============================================================================
|
||||||
|
// 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 = STATE_IDLE;
|
||||||
|
irparams.rawlen = 0;
|
||||||
|
|
||||||
|
// Set pin modes
|
||||||
|
pinMode(irparams.recvpin, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irs(); // 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;
|
||||||
|
irs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
|
211
mecanum.ino
Normal file
211
mecanum.ino
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#include <boarddefs.h>
|
||||||
|
#include <IRremote.h>
|
||||||
|
#include <IRremoteInt.h>
|
||||||
|
#include <ir_Lego_PF_BitStreamEncoder.h>
|
||||||
|
#define IR 4
|
||||||
|
IRrecv irrecv(IR);
|
||||||
|
|
||||||
|
#define WHEEL_FRONT_LEFT_F A0
|
||||||
|
#define WHEEL_REAR_LEFT_R A1
|
||||||
|
#define WHEEL_REAR_RIGHT_F A2
|
||||||
|
#define WHEEL_FRONT_RIGHT_R A3
|
||||||
|
|
||||||
|
#define WHEEL_FRONT_LEFT_R 10
|
||||||
|
#define WHEEL_REAR_LEFT_F 9
|
||||||
|
#define WHEEL_FRONT_RIGHT_F 8
|
||||||
|
#define WHEEL_REAR_RIGHT_R 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4060792887 ^
|
||||||
|
* 4060752087 v
|
||||||
|
* 4060768407 <
|
||||||
|
* 4060784727 >
|
||||||
|
* 4060801047 enter
|
||||||
|
* 4060776567 menu
|
||||||
|
* 4060774527 aspect
|
||||||
|
* 4060745967 vol+
|
||||||
|
* 4060794927 vol-
|
||||||
|
* 4060803087 mute
|
||||||
|
* 4060750047 source
|
||||||
|
* 4060790847 video mode
|
||||||
|
* 4060786767 keystone +
|
||||||
|
* 4060778607 keystone -
|
||||||
|
* 4060782687 mouse +
|
||||||
|
* 4060766367 mouse -
|
||||||
|
* 4060748007 auto adj
|
||||||
|
* 4060743927 freeze
|
||||||
|
* 4060754127 blank
|
||||||
|
* 4060762287 zoom +
|
||||||
|
* 4060770447 zoom -
|
||||||
|
* 4060759227 info
|
||||||
|
* 4060780647 vga
|
||||||
|
* 4060742907 video
|
||||||
|
* 4060775547 s-video
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
irrecv.enableIRIn();
|
||||||
|
pinMode(WHEEL_REAR_RIGHT_R, OUTPUT);
|
||||||
|
pinMode(WHEEL_REAR_RIGHT_F, OUTPUT);
|
||||||
|
pinMode(WHEEL_REAR_LEFT_R, OUTPUT);
|
||||||
|
pinMode(WHEEL_REAR_LEFT_F, OUTPUT);
|
||||||
|
pinMode(WHEEL_FRONT_RIGHT_R, OUTPUT);
|
||||||
|
pinMode(WHEEL_FRONT_RIGHT_F, OUTPUT);
|
||||||
|
pinMode(WHEEL_FRONT_LEFT_R, OUTPUT);
|
||||||
|
pinMode(WHEEL_FRONT_LEFT_F, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void stop(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_R, HIGH);
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_F, HIGH);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_R, HIGH);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_F, HIGH);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_R, HIGH);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_F, HIGH);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_R, HIGH);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_F, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forward(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_F, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backward(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_R, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void strafe_l(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_R, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void strafe_r(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_F, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diag_l_f(){
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_F, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diag_r_r(){
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_R, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diag_r_f(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_F, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diag_l_r(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_R, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void turn_l(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_F, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void turn_r(){
|
||||||
|
digitalWrite(WHEEL_REAR_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_REAR_LEFT_R, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_RIGHT_F, LOW);
|
||||||
|
digitalWrite(WHEEL_FRONT_LEFT_R, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long getIRremote(){
|
||||||
|
static unsigned long lastValue = 0;
|
||||||
|
decode_results irResults;
|
||||||
|
if(irrecv.decode(&irResults) == 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(!(irResults.decode_type == NEC && irResults.value == REPEAT)){
|
||||||
|
lastValue = irResults.value;
|
||||||
|
}
|
||||||
|
irrecv.resume();
|
||||||
|
return lastValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
unsigned long remote = getIRremote();
|
||||||
|
static unsigned long modus;
|
||||||
|
if(remote){
|
||||||
|
Serial.println(remote);
|
||||||
|
modus = remote;
|
||||||
|
}
|
||||||
|
if(modus == 4060792887){
|
||||||
|
forward();
|
||||||
|
}else if(modus == 4060801047){
|
||||||
|
stop();
|
||||||
|
}else if(modus == 4060752087){
|
||||||
|
backward();
|
||||||
|
}else if(modus == 4060768407){
|
||||||
|
strafe_l();
|
||||||
|
}else if(modus == 4060784727){
|
||||||
|
strafe_r();
|
||||||
|
}else if(modus == 4060750047){
|
||||||
|
turn_l();
|
||||||
|
}else if(modus == 4060790847){
|
||||||
|
turn_r();
|
||||||
|
}else if(modus == 4060786767){
|
||||||
|
diag_l_f();
|
||||||
|
}else if(modus == 4060778607){
|
||||||
|
diag_r_r();
|
||||||
|
}else if(modus == 4060782687){
|
||||||
|
diag_r_f();
|
||||||
|
}else if(modus == 4060766367){
|
||||||
|
diag_l_r();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
stop();
|
||||||
|
forward();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
backward();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
strafe_l();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
strafe_r();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
diag_l_f();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
diag_l_r();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
diag_r_f();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
diag_r_r();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
turn_l();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
turn_r();
|
||||||
|
delay(1000);
|
||||||
|
stop();
|
||||||
|
*/
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user