summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2015-06-03 15:06:17 +0200
committerPeter Wu <peter@lekensteyn.nl>2015-06-03 15:06:17 +0200
commit6228f52a5800124de4a43adb0c05ea5b4207c18f (patch)
treea3a16d507e64c810f11d1448a0b377a9d32c3636
parent401b609063e5248ad4a36f125dfe91076d3ad6cc (diff)
downloadcode-6228f52a5800124de4a43adb0c05ea5b4207c18f.tar.gz
Add libraries
HMC5883L: licensed under GPLv3 (converted CRLF to LF). IRremote: licensed under LGPL2.1 (unmodified).
-rw-r--r--Venus_Skeleton/libs/HMC5883L/HMC5883L.cpp160
-rw-r--r--Venus_Skeleton/libs/HMC5883L/HMC5883L.h75
-rw-r--r--Venus_Skeleton/libs/IRremote/IRremote.cpp1241
-rw-r--r--Venus_Skeleton/libs/IRremote/IRremote.h130
-rw-r--r--Venus_Skeleton/libs/IRremote/IRremoteInt.h525
5 files changed, 2131 insertions, 0 deletions
diff --git a/Venus_Skeleton/libs/HMC5883L/HMC5883L.cpp b/Venus_Skeleton/libs/HMC5883L/HMC5883L.cpp
new file mode 100644
index 0000000..68ebd02
--- /dev/null
+++ b/Venus_Skeleton/libs/HMC5883L/HMC5883L.cpp
@@ -0,0 +1,160 @@
+/*
+HMC5883L.cpp - Class file for the HMC5883L Triple Axis Magnetometer Arduino Library.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the version 3 GNU General Public License as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ WARNING: THE HMC5883L IS NOT IDENTICAL TO THE HMC5883!
+ Datasheet for HMC5883L:
+ http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/HMC5883L_3-Axis_Digital_Compass_IC.pdf
+
+*/
+#if ARDUINO >= 100
+ #include "Arduino.h"
+#else
+ #include "WProgram.h"
+#endif
+#include "HMC5883L.h"
+
+HMC5883L::HMC5883L()
+{
+ m_Scale = 1;
+}
+
+MagnetometerRaw HMC5883L::ReadRawAxis()
+{
+ uint8_t* buffer = Read(DataRegisterBegin, 6);
+ MagnetometerRaw raw = MagnetometerRaw();
+ raw.XAxis = (buffer[0] << 8) | buffer[1];
+ raw.ZAxis = (buffer[2] << 8) | buffer[3];
+ raw.YAxis = (buffer[4] << 8) | buffer[5];
+ return raw;
+}
+
+MagnetometerScaled HMC5883L::ReadScaledAxis()
+{
+ MagnetometerRaw raw = ReadRawAxis();
+ MagnetometerScaled scaled = MagnetometerScaled();
+ scaled.XAxis = raw.XAxis * m_Scale;
+ scaled.ZAxis = raw.ZAxis * m_Scale;
+ scaled.YAxis = raw.YAxis * m_Scale;
+ return scaled;
+}
+
+int HMC5883L::SetScale(float gauss)
+{
+ uint8_t regValue = 0x00;
+ if(gauss == 0.88)
+ {
+ regValue = 0x00;
+ m_Scale = 0.73;
+ }
+ else if(gauss == 1.3)
+ {
+ regValue = 0x01;
+ m_Scale = 0.92;
+ }
+ else if(gauss == 1.9)
+ {
+ regValue = 0x02;
+ m_Scale = 1.22;
+ }
+ else if(gauss == 2.5)
+ {
+ regValue = 0x03;
+ m_Scale = 1.52;
+ }
+ else if(gauss == 4.0)
+ {
+ regValue = 0x04;
+ m_Scale = 2.27;
+ }
+ else if(gauss == 4.7)
+ {
+ regValue = 0x05;
+ m_Scale = 2.56;
+ }
+ else if(gauss == 5.6)
+ {
+ regValue = 0x06;
+ m_Scale = 3.03;
+ }
+ else if(gauss == 8.1)
+ {
+ regValue = 0x07;
+ m_Scale = 4.35;
+ }
+ else
+ return ErrorCode_1_Num;
+
+ // Setting is in the top 3 bits of the register.
+ regValue = regValue << 5;
+ Write(ConfigurationRegisterB, regValue);
+}
+
+int HMC5883L::SetMeasurementMode(uint8_t mode)
+{
+ Write(ModeRegister, mode);
+ return 0;
+}
+
+void HMC5883L::Write(int address, int data)
+{
+ Wire.beginTransmission(HMC5883L_Address);
+ #if ARDUINO >= 100
+ Wire.write((uint8_t)address);
+ Wire.write((uint8_t)data);
+ #else
+ Wire.send(address);
+ Wire.send(data);
+ #endif
+
+ Wire.endTransmission();
+}
+
+uint8_t* HMC5883L::Read(int address, int length)
+{
+ Wire.beginTransmission(HMC5883L_Address);
+#if ARDUINO >= 100
+ Wire.write((uint8_t)address);
+#else
+ Wire.send(address);
+#endif
+ Wire.endTransmission();
+
+ Wire.beginTransmission(HMC5883L_Address);
+ Wire.requestFrom(HMC5883L_Address, length);
+
+ uint8_t buffer[length];
+ if(Wire.available() == length)
+ {
+ for(uint8_t i = 0; i < length; i++)
+ {
+ #if ARDUINO >= 100
+ buffer[i] = Wire.read();
+ #else
+ buffer[i] = Wire.receive();
+ #endif
+ }
+ }
+ Wire.endTransmission();
+
+ return buffer;
+}
+
+char* HMC5883L::GetErrorText(int errorCode)
+{
+ if (errorCode == ErrorCode_1_Num)
+ return ErrorCode_1;
+
+ return "Error not defined.";
+} \ No newline at end of file
diff --git a/Venus_Skeleton/libs/HMC5883L/HMC5883L.h b/Venus_Skeleton/libs/HMC5883L/HMC5883L.h
new file mode 100644
index 0000000..64ac68c
--- /dev/null
+++ b/Venus_Skeleton/libs/HMC5883L/HMC5883L.h
@@ -0,0 +1,75 @@
+/*
+HMC5883L.h - Header file for the HMC5883L Triple Axis Magnetometer Arduino Library.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the version 3 GNU General Public License as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ WARNING: THE HMC5883L IS NOT IDENTICAL TO THE HMC5883!
+ Datasheet for HMC5883L:
+ http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/HMC5883L_3-Axis_Digital_Compass_IC.pdf
+
+*/
+
+#ifndef HMC5883L_h
+#define HMC5883L_h
+
+#include <inttypes.h>
+#include "../Wire/Wire.h"
+
+#define HMC5883L_Address 0x1E
+#define ConfigurationRegisterA 0x00
+#define ConfigurationRegisterB 0x01
+#define ModeRegister 0x02
+#define DataRegisterBegin 0x03
+
+#define Measurement_Continuous 0x00
+#define Measurement_SingleShot 0x01
+#define Measurement_Idle 0x03
+
+#define ErrorCode_1 "Entered scale was not valid, valid gauss values are: 0.88, 1.3, 1.9, 2.5, 4.0, 4.7, 5.6, 8.1"
+#define ErrorCode_1_Num 1
+
+struct MagnetometerScaled
+{
+ float XAxis;
+ float YAxis;
+ float ZAxis;
+};
+
+struct MagnetometerRaw
+{
+ int XAxis;
+ int YAxis;
+ int ZAxis;
+};
+
+class HMC5883L
+{
+ public:
+ HMC5883L();
+
+ MagnetometerRaw ReadRawAxis();
+ MagnetometerScaled ReadScaledAxis();
+
+ int SetMeasurementMode(uint8_t mode);
+ int SetScale(float gauss);
+
+ char* GetErrorText(int errorCode);
+
+ protected:
+ void Write(int address, int byte);
+ uint8_t* Read(int address, int length);
+
+ private:
+ float m_Scale;
+};
+#endif \ No newline at end of file
diff --git a/Venus_Skeleton/libs/IRremote/IRremote.cpp b/Venus_Skeleton/libs/IRremote/IRremote.cpp
new file mode 100644
index 0000000..af5a3c8
--- /dev/null
+++ b/Venus_Skeleton/libs/IRremote/IRremote.cpp
@@ -0,0 +1,1241 @@
+/*
+ * IRremote
+ * Version 0.11 August, 2009
+ * Copyright 2009 Ken Shirriff
+ * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
+ *
+ * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers
+ * Modified by Mitra Ardron <mitra@mitra.biz>
+ * Added Sanyo and Mitsubishi controllers
+ * Modified Sony to spot the repeat codes that some Sony's send
+ *
+ * Interrupt code based on NECIRrcv by Joe Knapp
+ * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
+ * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
+ *
+ * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
+ * LG added by Darryl Smith (based on the JVC protocol)
+ * Whynter A/C ARC-110WD added by Francesco Meschia
+ */
+
+#include "IRremote.h"
+#include "IRremoteInt.h"
+
+// Provides ISR
+#include <avr/interrupt.h>
+
+volatile irparams_t irparams;
+
+// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.
+// To use them, set DEBUG in IRremoteInt.h
+// Normally macros are used for efficiency
+#ifdef DEBUG
+int MATCH(int measured, int desired) {
+ Serial.print("Testing: ");
+ Serial.print(TICKS_LOW(desired), DEC);
+ Serial.print(" <= ");
+ Serial.print(measured, DEC);
+ Serial.print(" <= ");
+ Serial.println(TICKS_HIGH(desired), DEC);
+ return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
+}
+
+int MATCH_MARK(int measured_ticks, int desired_us) {
+ Serial.print("Testing mark ");
+ Serial.print(measured_ticks * USECPERTICK, DEC);
+ Serial.print(" vs ");
+ Serial.print(desired_us, DEC);
+ Serial.print(": ");
+ Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
+ Serial.print(" <= ");
+ Serial.print(measured_ticks, DEC);
+ Serial.print(" <= ");
+ Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
+ return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
+}
+
+int MATCH_SPACE(int measured_ticks, int desired_us) {
+ Serial.print("Testing space ");
+ Serial.print(measured_ticks * USECPERTICK, DEC);
+ Serial.print(" vs ");
+ Serial.print(desired_us, DEC);
+ Serial.print(": ");
+ Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
+ Serial.print(" <= ");
+ Serial.print(measured_ticks, DEC);
+ Serial.print(" <= ");
+ Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
+ return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
+}
+#else
+int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
+int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us + MARK_EXCESS));}
+int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us - MARK_EXCESS));}
+// Debugging versions are in IRremote.cpp
+#endif
+
+void IRsend::sendNEC(unsigned long data, int nbits)
+{
+ enableIROut(38);
+ mark(NEC_HDR_MARK);
+ space(NEC_HDR_SPACE);
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ mark(NEC_BIT_MARK);
+ space(NEC_ONE_SPACE);
+ }
+ else {
+ mark(NEC_BIT_MARK);
+ space(NEC_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+ mark(NEC_BIT_MARK);
+ space(0);
+}
+
+void IRsend::sendWhynter(unsigned long data, int nbits) {
+ enableIROut(38);
+ mark(WHYNTER_ZERO_MARK);
+ space(WHYNTER_ZERO_SPACE);
+ mark(WHYNTER_HDR_MARK);
+ space(WHYNTER_HDR_SPACE);
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ mark(WHYNTER_ONE_MARK);
+ space(WHYNTER_ONE_SPACE);
+ }
+ else {
+ mark(WHYNTER_ZERO_MARK);
+ space(WHYNTER_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+ mark(WHYNTER_ZERO_MARK);
+ space(WHYNTER_ZERO_SPACE);
+}
+
+void IRsend::sendSony(unsigned long data, int nbits) {
+ enableIROut(40);
+ mark(SONY_HDR_MARK);
+ space(SONY_HDR_SPACE);
+ data = data << (32 - nbits);
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ mark(SONY_ONE_MARK);
+ space(SONY_HDR_SPACE);
+ }
+ else {
+ mark(SONY_ZERO_MARK);
+ space(SONY_HDR_SPACE);
+ }
+ data <<= 1;
+ }
+}
+
+void IRsend::sendRaw(unsigned int buf[], int len, int hz)
+{
+ enableIROut(hz);
+ for (int i = 0; i < len; i++) {
+ if (i & 1) {
+ space(buf[i]);
+ }
+ else {
+ mark(buf[i]);
+ }
+ }
+ space(0); // Just to be sure
+}
+
+// Note: first bit must be a one (start bit)
+void IRsend::sendRC5(unsigned long data, int nbits)
+{
+ enableIROut(36);
+ data = data << (32 - nbits);
+ mark(RC5_T1); // First start bit
+ space(RC5_T1); // Second start bit
+ mark(RC5_T1); // Second start bit
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ space(RC5_T1); // 1 is space, then mark
+ mark(RC5_T1);
+ }
+ else {
+ mark(RC5_T1);
+ space(RC5_T1);
+ }
+ data <<= 1;
+ }
+ space(0); // Turn off at end
+}
+
+// Caller needs to take care of flipping the toggle bit
+void IRsend::sendRC6(unsigned long data, int nbits)
+{
+ enableIROut(36);
+ data = data << (32 - nbits);
+ mark(RC6_HDR_MARK);
+ space(RC6_HDR_SPACE);
+ mark(RC6_T1); // start bit
+ space(RC6_T1);
+ int t;
+ for (int i = 0; i < nbits; i++) {
+ if (i == 3) {
+ // double-wide trailer bit
+ t = 2 * RC6_T1;
+ }
+ else {
+ t = RC6_T1;
+ }
+ if (data & TOPBIT) {
+ mark(t);
+ space(t);
+ }
+ else {
+ space(t);
+ mark(t);
+ }
+
+ data <<= 1;
+ }
+ space(0); // Turn off at end
+}
+void IRsend::sendPanasonic(unsigned int address, unsigned long data) {
+ enableIROut(35);
+ mark(PANASONIC_HDR_MARK);
+ space(PANASONIC_HDR_SPACE);
+
+ for(int i=0;i<16;i++)
+ {
+ mark(PANASONIC_BIT_MARK);
+ if (address & 0x8000) {
+ space(PANASONIC_ONE_SPACE);
+ } else {
+ space(PANASONIC_ZERO_SPACE);
+ }
+ address <<= 1;
+ }
+ for (int i=0; i < 32; i++) {
+ mark(PANASONIC_BIT_MARK);
+ if (data & TOPBIT) {
+ space(PANASONIC_ONE_SPACE);
+ } else {
+ space(PANASONIC_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+ mark(PANASONIC_BIT_MARK);
+ space(0);
+}
+void IRsend::sendJVC(unsigned long data, int nbits, int repeat)
+{
+ enableIROut(38);
+ data = data << (32 - nbits);
+ if (!repeat){
+ mark(JVC_HDR_MARK);
+ space(JVC_HDR_SPACE);
+ }
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ mark(JVC_BIT_MARK);
+ space(JVC_ONE_SPACE);
+ }
+ else {
+ mark(JVC_BIT_MARK);
+ space(JVC_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+ mark(JVC_BIT_MARK);
+ space(0);
+}
+
+void IRsend::sendSAMSUNG(unsigned long data, int nbits)
+{
+ enableIROut(38);
+ mark(SAMSUNG_HDR_MARK);
+ space(SAMSUNG_HDR_SPACE);
+ for (int i = 0; i < nbits; i++) {
+ if (data & TOPBIT) {
+ mark(SAMSUNG_BIT_MARK);
+ space(SAMSUNG_ONE_SPACE);
+ }
+ else {
+ mark(SAMSUNG_BIT_MARK);
+ space(SAMSUNG_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+ mark(SAMSUNG_BIT_MARK);
+ space(0);
+}
+
+void IRsend::mark(int time) {
+ // Sends an IR mark for the specified number of microseconds.
+ // The mark output is modulated at the PWM frequency.
+ TIMER_ENABLE_PWM; // Enable pin 3 PWM output
+ if (time > 0) delayMicroseconds(time);
+}
+
+/* Leave pin off for time (given in microseconds) */
+void IRsend::space(int time) {
+ // Sends an IR space for the specified number of microseconds.
+ // A space is no output, so the PWM output is disabled.
+ TIMER_DISABLE_PWM; // Disable pin 3 PWM output
+ if (time > 0) delayMicroseconds(time);
+}
+
+void IRsend::enableIROut(int khz) {
+ // Enables IR output. The khz value controls the modulation frequency in kilohertz.
+ // The IR output will be on pin 3 (OC2B).
+ // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
+ // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
+ // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
+ // controlling the duty cycle.
+ // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
+ // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
+ // A few hours staring at the ATmega documentation and this will all make sense.
+ // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
+
+
+ // Disable the Timer2 Interrupt (which is used for receiving IR)
+ TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
+
+ pinMode(TIMER_PWM_PIN, OUTPUT);
+ digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
+
+ // COM2A = 00: disconnect OC2A
+ // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
+ // WGM2 = 101: phase-correct PWM with OCRA as top
+ // CS2 = 000: no prescaling
+ // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
+ TIMER_CONFIG_KHZ(khz);
+}
+
+IRrecv::IRrecv(int recvpin)
+{
+ irparams.recvpin = recvpin;
+ irparams.blinkflag = 0;
+}
+
+// initialization
+void IRrecv::enableIRIn() {
+ 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);
+}
+
+// enable/disable blinking of pin 13 on IR processing
+void IRrecv::blink13(int blinkflag)
+{
+ irparams.blinkflag = blinkflag;
+ if (blinkflag)
+ pinMode(BLINKLED, OUTPUT);
+}
+
+// TIMER2 interrupt code to collect raw data.
+// Widths of alternating SPACE, MARK are recorded in rawbuf.
+// Recorded in ticks of 50 microseconds.
+// rawlen counts the number of entries recorded so far.
+// First entry is the SPACE between transmissions.
+// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
+// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
+ISR(TIMER_INTR_NAME)
+{
+ TIMER_RESET;
+
+ uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
+
+ irparams.timer++; // One more 50us tick
+ if (irparams.rawlen >= RAWBUF) {
+ // Buffer overflow
+ irparams.rcvstate = STATE_STOP;
+ }
+ switch(irparams.rcvstate) {
+ case STATE_IDLE: // In the middle of a gap
+ if (irdata == MARK) {
+ if (irparams.timer < GAP_TICKS) {
+ // Not big enough to be a gap.
+ irparams.timer = 0;
+ }
+ else {
+ // gap just ended, record duration and start recording transmission
+ irparams.rawlen = 0;
+ irparams.rawbuf[irparams.rawlen++] = irparams.timer;
+ irparams.timer = 0;
+ irparams.rcvstate = STATE_MARK;
+ }
+ }
+ break;
+ case STATE_MARK: // timing MARK
+ if (irdata == SPACE) { // MARK ended, record time
+ irparams.rawbuf[irparams.rawlen++] = irparams.timer;
+ irparams.timer = 0;
+ irparams.rcvstate = STATE_SPACE;
+ }
+ break;
+ case STATE_SPACE: // timing SPACE
+ if (irdata == MARK) { // SPACE just ended, record it
+ irparams.rawbuf[irparams.rawlen++] = irparams.timer;
+ irparams.timer = 0;
+ irparams.rcvstate = STATE_MARK;
+ }
+ else { // SPACE
+ if (irparams.timer > GAP_TICKS) {
+ // big SPACE, indicates gap between codes
+ // Mark current code as ready for processing
+ // Switch to STOP
+ // Don't reset timer; keep counting space width
+ irparams.rcvstate = STATE_STOP;
+ }
+ }
+ break;
+ case STATE_STOP: // waiting, measuring gap
+ if (irdata == MARK) { // reset gap timer
+ irparams.timer = 0;
+ }
+ break;
+ }
+
+ if (irparams.blinkflag) {
+ if (irdata == MARK) {
+ BLINKLED_ON(); // turn pin 13 LED on
+ }
+ else {
+ BLINKLED_OFF(); // turn pin 13 LED off
+ }
+ }
+}
+
+void IRrecv::resume() {
+ irparams.rcvstate = STATE_IDLE;
+ irparams.rawlen = 0;
+}
+
+
+
+// Decodes the received IR message
+// Returns 0 if no data ready, 1 if data ready.
+// Results of decoding are stored in results
+int IRrecv::decode(decode_results *results) {
+ results->rawbuf = irparams.rawbuf;
+ results->rawlen = irparams.rawlen;
+ if (irparams.rcvstate != STATE_STOP) {
+ return ERR;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting NEC decode");
+#endif
+ if (decodeNEC(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting Sony decode");
+#endif
+ if (decodeSony(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting Sanyo decode");
+#endif
+ if (decodeSanyo(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting Mitsubishi decode");
+#endif
+ if (decodeMitsubishi(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting RC5 decode");
+#endif
+ if (decodeRC5(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting RC6 decode");
+#endif
+ if (decodeRC6(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting Panasonic decode");
+#endif
+ if (decodePanasonic(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting LG decode");
+#endif
+ if (decodeLG(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting JVC decode");
+#endif
+ if (decodeJVC(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting SAMSUNG decode");
+#endif
+ if (decodeSAMSUNG(results)) {
+ return DECODED;
+ }
+#ifdef DEBUG
+ Serial.println("Attempting Whynter decode");
+#endif
+ if (decodeWhynter(results)) {
+ return DECODED;
+ }
+ // 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 DECODED;
+ }
+ // Throw away and start over
+ resume();
+ return ERR;
+}
+
+// NECs have a repeat only 4 items long
+long IRrecv::decodeNEC(decode_results *results) {
+ long data = 0;
+ int offset = 1; // Skip first space
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ // Check for repeat
+ if (irparams.rawlen == 4 &&
+ MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
+ MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
+ results->bits = 0;
+ results->value = REPEAT;
+ results->decode_type = NEC;
+ return DECODED;
+ }
+ if (irparams.rawlen < 2 * NEC_BITS + 4) {
+ return ERR;
+ }
+ // Initial space
+ if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+ for (int i = 0; i < NEC_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+ // Success
+ results->bits = NEC_BITS;
+ results->value = data;
+ results->decode_type = NEC;
+ return DECODED;
+}
+
+long IRrecv::decodeSony(decode_results *results) {
+ long data = 0;
+ if (irparams.rawlen < 2 * SONY_BITS + 2) {
+ return ERR;
+ }
+ int offset = 0; // Dont skip first space, check its size
+
+ // 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;
+ results->decode_type = SANYO;
+ return DECODED;
+ }
+ offset++;
+
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+
+ while (offset + 1 < irparams.rawlen) {
+ if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
+ break;
+ }
+ offset++;
+ if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+
+ // Success
+ results->bits = (offset - 1) / 2;
+ if (results->bits < 12) {
+ results->bits = 0;
+ return ERR;
+ }
+ results->value = data;
+ results->decode_type = SONY;
+ return DECODED;
+}
+
+long IRrecv::decodeWhynter(decode_results *results) {
+ long data = 0;
+
+ if (irparams.rawlen < 2 * WHYNTER_BITS + 6) {
+ return ERR;
+ }
+
+ int offset = 1; // skip initial space
+
+ // sequence begins with a bit mark and a zero space
+ if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (!MATCH_SPACE(results->rawbuf[offset], WHYNTER_ZERO_SPACE)) {
+ return ERR;
+ }
+ offset++;
+
+ // header mark and space
+ if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (!MATCH_SPACE(results->rawbuf[offset], WHYNTER_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+
+ // data bits
+ for (int i = 0; i < WHYNTER_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (MATCH_SPACE(results->rawbuf[offset], WHYNTER_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_SPACE(results->rawbuf[offset],WHYNTER_ZERO_SPACE)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+
+ // trailing mark
+ if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) {
+ return ERR;
+ }
+ // Success
+ results->bits = WHYNTER_BITS;
+ results->value = data;
+ results->decode_type = WHYNTER;
+ return DECODED;
+}
+
+
+// I think this is a Sanyo decoder - serial = SA 8650B
+// Looks like Sony except for timings, 48 chars of data and time/space different
+long IRrecv::decodeSanyo(decode_results *results) {
+ long data = 0;
+ if (irparams.rawlen < 2 * SANYO_BITS + 2) {
+ return ERR;
+ }
+ int offset = 0; // Skip first space
+ // Initial space
+ /* 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]);
+ */
+ if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) {
+ // Serial.print("IR Gap found: ");
+ results->bits = 0;
+ results->value = REPEAT;
+ results->decode_type = SANYO;
+ return DECODED;
+ }
+ offset++;
+
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+
+ // Skip Second Mark
+ if (!MATCH_MARK(results->rawbuf[offset], SANYO_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+
+ while (offset + 1 < irparams.rawlen) {
+ if (!MATCH_SPACE(results->rawbuf[offset], SANYO_HDR_SPACE)) {
+ break;
+ }
+ offset++;
+ if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+
+ // Success
+ results->bits = (offset - 1) / 2;
+ if (results->bits < 12) {
+ results->bits = 0;
+ return ERR;
+ }
+ results->value = data;
+ results->decode_type = SANYO;
+ return DECODED;
+}
+
+// Looks like Sony except for timings, 48 chars of data and time/space different
+long 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 ERR;
+ }
+ int offset = 0; // Skip first space
+ // Initial space
+ /* 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]);
+ */
+ /* 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 DECODED;
+ }
+ */
+ 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 ERR;
+ }
+ 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 {
+ // Serial.println("A"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
+ return ERR;
+ }
+ offset++;
+ if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) {
+ // Serial.println("B"); Serial.println(offset); Serial.println(results->rawbuf[offset]);
+ break;
+ }
+ offset++;
+ }
+
+ // Success
+ results->bits = (offset - 1) / 2;
+ if (results->bits < MITSUBISHI_BITS) {
+ results->bits = 0;
+ return ERR;
+ }
+ results->value = data;
+ results->decode_type = MITSUBISHI;
+ return DECODED;
+}
+
+
+// Gets one undecoded level at a time from the raw buffer.
+// The RC5/6 decoding is easier if the data is broken into time intervals.
+// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
+// successive calls to getRClevel will return MARK, MARK, SPACE.
+// offset and used are updated to keep track of the current position.
+// t1 is the time interval for a single bit in microseconds.
+// Returns -1 for error (measured time interval is not a multiple of t1).
+int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
+ if (*offset >= results->rawlen) {
+ // After end of recorded buffer, assume SPACE.
+ return SPACE;
+ }
+ int width = results->rawbuf[*offset];
+ int val = ((*offset) % 2) ? MARK : SPACE;
+ int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
+
+ int avail;
+ if (MATCH(width, t1 + correction)) {
+ avail = 1;
+ }
+ else if (MATCH(width, 2*t1 + correction)) {
+ avail = 2;
+ }
+ else if (MATCH(width, 3*t1 + correction)) {
+ avail = 3;
+ }
+ else {
+ return -1;
+ }
+
+ (*used)++;
+ if (*used >= avail) {
+ *used = 0;
+ (*offset)++;
+ }
+#ifdef DEBUG
+ if (val == MARK) {
+ Serial.println("MARK");
+ }
+ else {
+ Serial.println("SPACE");
+ }
+#endif
+ return val;
+}
+
+long IRrecv::decodeRC5(decode_results *results) {
+ if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
+ return ERR;
+ }
+ int offset = 1; // Skip gap space
+ long data = 0;
+ int used = 0;
+ // Get start bits
+ if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
+ if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
+ if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
+ int nbits;
+ for (nbits = 0; offset < irparams.rawlen; nbits++) {
+ int levelA = getRClevel(results, &offset, &used, RC5_T1);
+ int levelB = getRClevel(results, &offset, &used, RC5_T1);
+ if (levelA == SPACE && levelB == MARK) {
+ // 1 bit
+ data = (data << 1) | 1;
+ }
+ else if (levelA == MARK && levelB == SPACE) {
+ // zero bit
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ }
+
+ // Success
+ results->bits = nbits;
+ results->value = data;
+ results->decode_type = RC5;
+ return DECODED;
+}
+
+long IRrecv::decodeRC6(decode_results *results) {
+ if (results->rawlen < MIN_RC6_SAMPLES) {
+ return ERR;
+ }
+ int offset = 1; // Skip first space
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+ long data = 0;
+ int used = 0;
+ // Get start bit (1)
+ if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
+ if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
+ int nbits;
+ for (nbits = 0; offset < results->rawlen; nbits++) {
+ int levelA, levelB; // Next two levels
+ levelA = getRClevel(results, &offset, &used, RC6_T1);
+ if (nbits == 3) {
+ // T bit is double wide; make sure second half matches
+ if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
+ }
+ levelB = getRClevel(results, &offset, &used, RC6_T1);
+ if (nbits == 3) {
+ // T bit is double wide; make sure second half matches
+ if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
+ }
+ if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
+ // 1 bit
+ data = (data << 1) | 1;
+ }
+ else if (levelA == SPACE && levelB == MARK) {
+ // zero bit
+ data <<= 1;
+ }
+ else {
+ return ERR; // Error
+ }
+ }
+ // Success
+ results->bits = nbits;
+ results->value = data;
+ results->decode_type = RC6;
+ return DECODED;
+}
+long IRrecv::decodePanasonic(decode_results *results) {
+ unsigned long long data = 0;
+ int offset = 1;
+
+ if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (!MATCH_MARK(results->rawbuf[offset], PANASONIC_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+
+ // decode address
+ for (int i = 0; i < PANASONIC_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) {
+ return ERR;
+ }
+ if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ } else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) {
+ data <<= 1;
+ } else {
+ return ERR;
+ }
+ offset++;
+ }
+ results->value = (unsigned long)data;
+ results->panasonicAddress = (unsigned int)(data >> 32);
+ results->decode_type = PANASONIC;
+ results->bits = PANASONIC_BITS;
+ return DECODED;
+}
+
+long IRrecv::decodeLG(decode_results *results) {
+ long data = 0;
+ int offset = 1; // Skip first space
+
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], LG_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (irparams.rawlen < 2 * LG_BITS + 1 ) {
+ return ERR;
+ }
+ // Initial space
+ if (!MATCH_SPACE(results->rawbuf[offset], LG_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+ for (int i = 0; i < LG_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (MATCH_SPACE(results->rawbuf[offset], LG_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_SPACE(results->rawbuf[offset], LG_ZERO_SPACE)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+ //Stop bit
+ if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)){
+ return ERR;
+ }
+ // Success
+ results->bits = LG_BITS;
+ results->value = data;
+ results->decode_type = LG;
+ return DECODED;
+}
+
+
+long 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 DECODED;
+ }
+ // Initial mark
+ if (!MATCH_MARK(results->rawbuf[offset], JVC_HDR_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (irparams.rawlen < 2 * JVC_BITS + 1 ) {
+ return ERR;
+ }
+ // Initial space
+ if (!MATCH_SPACE(results->rawbuf[offset], JVC_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+ for (int i = 0; i < JVC_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+ //Stop bit
+ if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)){
+ return ERR;
+ }
+ // Success
+ results->bits = JVC_BITS;
+ results->value = data;
+ results->decode_type = JVC;
+ return DECODED;
+}
+
+// SAMSUNGs have a repeat only 4 items long
+long 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 ERR;
+ }
+ 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 DECODED;
+ }
+ if (irparams.rawlen < 2 * SAMSUNG_BITS + 4) {
+ return ERR;
+ }
+ // Initial space
+ if (!MATCH_SPACE(results->rawbuf[offset], SAMSUNG_HDR_SPACE)) {
+ return ERR;
+ }
+ offset++;
+ for (int i = 0; i < SAMSUNG_BITS; i++) {
+ if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_BIT_MARK)) {
+ return ERR;
+ }
+ offset++;
+ if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) {
+ data = (data << 1) | 1;
+ }
+ else if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) {
+ data <<= 1;
+ }
+ else {
+ return ERR;
+ }
+ offset++;
+ }
+ // Success
+ results->bits = SAMSUNG_BITS;
+ results->value = data;
+ results->decode_type = SAMSUNG;
+ return DECODED;
+}
+
+/* -----------------------------------------------------------------------
+ * 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. Hszh 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
+#define FNV_PRIME_32 16777619
+#define FNV_BASIS_32 2166136261
+
+/* 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.
+ */
+long IRrecv::decodeHash(decode_results *results) {
+ // Require at least 6 samples to prevent triggering on noise
+ if (results->rawlen < 6) {
+ return ERR;
+ }
+ long hash = FNV_BASIS_32;
+ 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 DECODED;
+}
+
+/* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand )
+
+The Dish send function needs to be repeated 4 times, and the Sharp 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 are the LIRC files that I found that seem to match the remote codes
+from the oscilloscope:
+
+Sharp LCD TV:
+http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
+
+DISH NETWORK (echostar 301):
+http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
+
+For the DISH codes, only send the last for characters of the hex.
+i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the
+linked LIRC file.
+*/
+
+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 (int i = 1 << (nbits-1); i > 0; i>>=1) {
+ if (data & i) {
+ 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;
+ }
+}
+
+// Sharp send compatible with data obtained through decodeSharp
+void IRsend::sendSharp(unsigned int address, unsigned int command) {
+ sendSharpRaw((address << 10) | (command << 2) | 2, 15);
+}
+
+void IRsend::sendDISH(unsigned long data, int nbits) {
+ enableIROut(56);
+ mark(DISH_HDR_MARK);
+ space(DISH_HDR_SPACE);
+ for (int i = 0; i < nbits; i++) {
+ if (data & DISH_TOP_BIT) {
+ mark(DISH_BIT_MARK);
+ space(DISH_ONE_SPACE);
+ }
+ else {
+ mark(DISH_BIT_MARK);
+ space(DISH_ZERO_SPACE);
+ }
+ data <<= 1;
+ }
+}
diff --git a/Venus_Skeleton/libs/IRremote/IRremote.h b/Venus_Skeleton/libs/IRremote/IRremote.h
new file mode 100644
index 0000000..e4b274e
--- /dev/null
+++ b/Venus_Skeleton/libs/IRremote/IRremote.h
@@ -0,0 +1,130 @@
+/*
+ * IRremote
+ * Version 0.1 July, 2009
+ * Copyright 2009 Ken Shirriff
+ * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
+ * 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
+
+// The following are compile-time library options.
+// If you change them, recompile the library.
+// If DEBUG is defined, a lot of debugging output will be printed during decoding.
+// TEST must be defined for the IRtest unittests to work. It will make some
+// methods virtual, which will be slightly slower, which is why it is optional.
+//#define DEBUG
+// #define TEST
+
+// Results returned from the decoder
+class decode_results {
+public:
+ int decode_type; // NEC, SONY, RC5, UNKNOWN
+ union { // This is used for decoding Panasonic and Sharp data
+ unsigned int panasonicAddress;
+ unsigned int sharpAddress;
+ };
+ unsigned long value; // Decoded value
+ int bits; // Number of bits in decoded value
+ volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
+ int rawlen; // Number of records in rawbuf.
+};
+
+// Values for decode_type
+#define NEC 1
+#define SONY 2
+#define RC5 3
+#define RC6 4
+#define DISH 5
+#define SHARP 6
+#define PANASONIC 7
+#define JVC 8
+#define SANYO 9
+#define MITSUBISHI 10
+#define SAMSUNG 11
+#define LG 12
+#define WHYNTER 13
+#define UNKNOWN -1
+
+// Decoded value for NEC when a repeat code is received
+#define REPEAT 0xffffffff
+
+// main class for receiving IR
+class IRrecv
+{
+public:
+ IRrecv(int recvpin);
+ void blink13(int blinkflag);
+ int decode(decode_results *results);
+ void enableIRIn();
+ void resume();
+private:
+ // These are called by decode
+ int getRClevel(decode_results *results, int *offset, int *used, int t1);
+ long decodeNEC(decode_results *results);
+ long decodeSony(decode_results *results);
+ long decodeSanyo(decode_results *results);
+ long decodeMitsubishi(decode_results *results);
+ long decodeRC5(decode_results *results);
+ long decodeRC6(decode_results *results);
+ long decodePanasonic(decode_results *results);
+ long decodeLG(decode_results *results);
+ long decodeJVC(decode_results *results);
+ long decodeSAMSUNG(decode_results *results);
+ long decodeWhynter(decode_results *results);
+ long decodeHash(decode_results *results);
+ int compare(unsigned int oldval, unsigned int newval);
+
+} ;
+
+// Only used for testing; can remove virtual for shorter code
+#ifdef TEST
+#define VIRTUAL virtual
+#else
+#define VIRTUAL
+#endif
+
+class IRsend
+{
+public:
+ IRsend() {}
+ void sendWhynter(unsigned long data, int nbits);
+ void sendNEC(unsigned long data, int nbits);
+ void sendSony(unsigned long data, int nbits);
+ // Neither Sanyo nor Mitsubishi send is implemented yet
+ // void sendSanyo(unsigned long data, int nbits);
+ // void sendMitsubishi(unsigned long data, int nbits);
+ void sendRaw(unsigned int buf[], int len, int hz);
+ void sendRC5(unsigned long data, int nbits);
+ void sendRC6(unsigned long data, int nbits);
+ void sendDISH(unsigned long data, int nbits);
+ void sendSharp(unsigned int address, unsigned int command);
+ void sendSharpRaw(unsigned long data, int nbits);
+ void sendPanasonic(unsigned int address, unsigned long data);
+ void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does.
+ // private:
+ void sendSAMSUNG(unsigned long data, int nbits);
+ void enableIROut(int khz);
+ VIRTUAL void mark(int usec);
+ VIRTUAL void space(int usec);
+} ;
+
+// Some useful constants
+
+#define USECPERTICK 50 // microseconds per clock interrupt tick
+#define RAWBUF 100 // Length of raw duration buffer
+
+// Marks tend to be 100us too long, and spaces 100us too short
+// when received due to sensor lag.
+#define MARK_EXCESS 100
+
+#endif
diff --git a/Venus_Skeleton/libs/IRremote/IRremoteInt.h b/Venus_Skeleton/libs/IRremote/IRremoteInt.h
new file mode 100644
index 0000000..53167c2
--- /dev/null
+++ b/Venus_Skeleton/libs/IRremote/IRremoteInt.h
@@ -0,0 +1,525 @@
+/*
+ * IRremote
+ * Version 0.1 July, 2009
+ * 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
+
+#if defined(ARDUINO) && ARDUINO >= 100
+#include <Arduino.h>
+#else
+#include <WProgram.h>
+#endif
+
+// define which timer to use
+//
+// Uncomment the timer you wish to use on your board. If you
+// are using another library which uses timer2, you have options
+// to switch IRremote to use a different timer.
+
+// 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
+#elif defined(__MK20DX128__)
+ #define IR_USE_TIMER_CMT // tx = pin 5
+
+// 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
+
+// Sanguino
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+ //#define IR_USE_TIMER1 // tx = pin 13
+ #define IR_USE_TIMER2 // tx = pin 14
+
+// Atmega8
+#elif defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__)
+ #define IR_USE_TIMER1 // tx = pin 9
+
+// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
+#else
+ //#define IR_USE_TIMER1 // tx = pin 9
+ #define IR_USE_TIMER2 // tx = pin 3
+#endif
+
+
+
+#ifdef F_CPU
+#define SYSCLOCK F_CPU // main Arduino clock
+#else
+#define SYSCLOCK 16000000 // main Arduino clock
+#endif
+
+#define ERR 0
+#define DECODED 1
+
+
+// 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 *50-100 for the Mark and *50+100 for the space
+// First MARK is the one after the long gap
+// pulse parameters in usec
+#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
+
+#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
+
+#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
+
+// SA 8650B
+#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
+
+// 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
+
+
+#define RC5_T1 889
+#define RC5_RPT_LENGTH 46000
+
+#define RC6_HDR_MARK 2666
+#define RC6_HDR_SPACE 889
+#define RC6_T1 444
+#define RC6_RPT_LENGTH 46000
+
+#define SHARP_BIT_MARK 245
+#define SHARP_ONE_SPACE 1805
+#define SHARP_ZERO_SPACE 795
+#define SHARP_GAP 600000
+#define SHARP_TOGGLE_MASK 0x3FF
+#define SHARP_RPT_SPACE 3000
+
+#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
+#define DISH_TOP_BIT 0x8000
+
+#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
+
+#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
+
+#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
+
+#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
+
+
+#define SHARP_BITS 15
+#define DISH_BITS 16
+
+#define TOLERANCE 25 // percent tolerance in measurements
+#define LTOL (1.0 - TOLERANCE/100.)
+#define UTOL (1.0 + TOLERANCE/100.)
+
+#define _GAP 5000 // Minimum map between transmissions
+#define GAP_TICKS (_GAP/USECPERTICK)
+
+#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
+#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
+
+// receiver states
+#define STATE_IDLE 2
+#define STATE_MARK 3
+#define STATE_SPACE 4
+#define STATE_STOP 5
+
+// information for the interrupt handler
+typedef struct {
+ uint8_t recvpin; // pin for IR data from detector
+ uint8_t rcvstate; // state machine
+ uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
+ unsigned int timer; // state timer, counts 50uS ticks.
+ unsigned int rawbuf[RAWBUF]; // raw data
+ uint8_t rawlen; // counter of entries in rawbuf
+}
+irparams_t;
+
+// Defined in IRremote.cpp
+extern volatile irparams_t irparams;
+
+// IR detector output is active low
+#define MARK 0
+#define SPACE 1
+
+#define TOPBIT 0x80000000
+
+#define NEC_BITS 32
+#define SONY_BITS 12
+#define SANYO_BITS 12
+#define MITSUBISHI_BITS 16
+#define MIN_RC5_SAMPLES 11
+#define MIN_RC6_SAMPLES 1
+#define PANASONIC_BITS 48
+#define JVC_BITS 16
+#define LG_BITS 28
+#define SAMSUNG_BITS 32
+#define WHYNTER_BITS 32
+
+
+
+
+// defines for 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 TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#define TIMER_PWM_PIN 9 /* Arduino Mega */
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+#define TIMER_PWM_PIN 14 /* Sanguino */
+#else
+#define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
+#endif
+
+
+// defines for 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_ATmega8P__) || defined(__AVR_ATmega8__)
+ #define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE1A))
+ #define TIMER_DISABLE_INTR (TIMSK = 0)
+#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 TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#define TIMER_PWM_PIN 11 /* Arduino Mega */
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+#define TIMER_PWM_PIN 13 /* Sanguino */
+#else
+#define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */
+#endif
+
+
+// defines for 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 TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#define TIMER_PWM_PIN 5 /* Arduino Mega */
+#else
+#error "Please add OC3A pin number here\n"
+#endif
+
+
+// defines for 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 TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */
+#elif defined(__AVR_ATmega32U4__)
+#define TIMER_PWM_PIN 13 /* Leonardo */
+#else
+#error "Please add OC4A pin number here\n"
+#endif
+
+
+// defines for 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 TIMER_PWM_PIN CORE_OC4A_PIN
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#define TIMER_PWM_PIN 6 /* Arduino Mega */
+#else
+#error "Please add OC4A pin number here\n"
+#endif
+
+
+// defines for 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 TIMER_PWM_PIN CORE_OC5A_PIN
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#define TIMER_PWM_PIN 46 /* Arduino Mega */
+#else
+#error "Please add OC5A pin number here\n"
+#endif
+
+
+// defines for special carrier modulator timer
+#elif defined(IR_USE_TIMER_CMT)
+#define TIMER_RESET ({ \
+ uint8_t tmp = CMT_MSC; \
+ CMT_CMD2 = 30; \
+})
+#define TIMER_ENABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_DSE|PORT_PCR_SRE
+#define TIMER_DISABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE
+#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)
+#if F_BUS == 48000000
+#define CMT_PPS_VAL 5
+#else
+#define CMT_PPS_VAL 2
+#endif
+#define TIMER_CONFIG_KHZ(val) ({ \
+ SIM_SCGC4 |= SIM_SCGC4_CMT; \
+ SIM_SOPT2 |= SIM_SOPT2_PTD7PAD; \
+ CMT_PPS = CMT_PPS_VAL; \
+ CMT_CGH1 = 2667 / val; \
+ CMT_CGL1 = 5333 / 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_VAL; \
+ CMT_CGH1 = 1; \
+ CMT_CGL1 = 1; \
+ CMT_CMD1 = 0; \
+ CMT_CMD2 = 30; \
+ CMT_CMD3 = 0; \
+ CMT_CMD4 = 19; \
+ CMT_OC = 0; \
+ CMT_MSC = 0x03; \
+})
+#define TIMER_PWM_PIN 5
+
+
+#else // unknown timer
+#error "Internal code configuration error, no known IR_USE_TIMER# defined\n"
+#endif
+
+
+// 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)
+#else
+#define BLINKLED 13
+#define BLINKLED_ON() (PORTB |= B00100000)
+#define BLINKLED_OFF() (PORTB &= B11011111)
+#endif
+
+#endif