Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MagiQuest and 3.5ch Helicopters #26

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
588 changes: 545 additions & 43 deletions IRremote.cpp

Large diffs are not rendered by default.

104 changes: 95 additions & 9 deletions IRremote.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,90 @@
* 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)
*
* RCMM protocol added by Matthias Neeracher.
*/

#ifndef IRremote_h
#define IRremote_h
#include <inttypes.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
//#define TEST

// MagiQuest packet is both Wand ID and magnitude of swish and flick
union magiquest {
uint64_t llword;
uint8_t byte[8];
// uint16_t word[4];
uint32_t lword[2];
struct {
uint16_t magnitude;
uint32_t wand_id;
uint8_t padding;
uint8_t scrap;
} cmd ;
} ;

union helicopter {
uint32_t dword;
struct
{
uint8_t Throttle : 7; // 0..6 0 - 127
uint8_t Channel : 1; // 7 A=0, B=1
uint8_t Pitch : 7; // 8..14 0(forward) - 63(center) 127(back)
uint8_t Pspacer : 1; // 15 na
uint8_t Yaw : 7; // 16..22 127(left) - 63(center) - 0(right)
} symaR3;
struct
{
uint8_t Trim : 7; // 0..6 127(left) - 63(center) - 0(right)
uint8_t Tspacer : 1; // 7 na
uint8_t Throttle : 7; // 8..14 0 - 127
uint8_t Channel : 1; // 15 A=0, B=1
uint8_t Pitch : 7; // 16..22 0(forward) - 63(center) 127(back)
uint8_t Pspacer : 1; // 23 na
uint8_t Yaw : 7; // 24..30 127(left) - 63(center) - 0(right)
} symaR5;
struct
{
uint8_t cksum : 3; // 0..2
uint8_t Rbutton : 1; // 3 0-normally off, 1-depressed
uint8_t Lbutton : 1; // 4 0-normally off, 1-depressed
uint8_t Turbo : 1; // 5 1-off, 0-on
uint8_t Channel : 2; // 6,7 A=1, B=2, C=0
uint8_t Trim : 6; // 8..13 (left)63 - 31(center) - 0(right)
uint8_t Yaw : 5; // 14..18 31(left) - 15(center) - 0(right)
uint8_t Pitch : 6; // 19..24 0(foward) - 31(center) - 63(back)
uint8_t Throttle : 7; // 25..31 0 - 127
} uSeries;
struct
{
uint8_t Trim : 4; // 0..3 15(left) - 8(center) - 0(right)
uint8_t Trim_dir : 1; // 4 0= , 1=
uint8_t Yaw_dir : 1; // 5
uint8_t Fire : 1; // 6
uint8_t Yaw : 4; // 7..10 15(left) - 8(center) - 0(right)
uint8_t Pitch : 4; // 11..14 1(back) - 8(center) 15(forward)
uint8_t Throttle : 6; // 15..20 0 - 63
uint8_t Channel : 2; // 21..22 ?A=0, B=1
} fastlane;
};

// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, UNKNOWN
unsigned int panasonicAddress; // This is only used for decoding Panasonic data
unsigned long value; // Decoded value
int16_t decode_type; // NEC, SONY, RC5, UNKNOWN
uint16_t panasonicAddress; // This is only used for decoding Panasonic data
uint16_t magiquestMagnitude; // This is only used for MagiQuest
int32_t value; // Decoded value //mpf need to make unsigned.
union helicopter helicopter;
unsigned int parity;
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.
Expand All @@ -45,6 +110,12 @@ class decode_results {
#define JVC 8
#define SANYO 9
#define MITSUBISHI 10
#define MAGIQUEST 11
#define SYMA_R3 12
#define SYMA_R5 13
#define USERIES 14
#define FASTLANE 15
#define RCMM 16
#define UNKNOWN -1

// Decoded value for NEC when a repeat code is received
Expand All @@ -70,12 +141,19 @@ class IRrecv
long decodeRC6(decode_results *results);
long decodePanasonic(decode_results *results);
long decodeJVC(decode_results *results);
long decodeRCMM(decode_results *results);
long decodeHash(decode_results *results);
long decodeSyma(decode_results *results);
long decodeUseries(decode_results *results);
long decodeFastLane(decode_results *results);
long decodeMagiQuest(decode_results *results);
int compare(unsigned int oldval, unsigned int newval);

}
}
;

uint8_t UseriesChecksum(uint32_t val);

// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
Expand All @@ -99,20 +177,28 @@ class IRsend
void sendSharp(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.
void sendMagiQuest(unsigned long wand_id, unsigned magitude);
void sendSymaR5(unsigned long data);
void sendSymaR3(unsigned long data);
void sendUseries(unsigned long data);
void sendFastLane(unsigned long data);
void sendRCMM(unsigned long data, int nbits);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
void on(unsigned int freq);
void off(void);
}
;

// Some useful constants

#define USECPERTICK 50 // microseconds per clock interrupt tick
#define RAWBUF 100 // Length of raw duration buffer
#define USECPERTICK 25 // microseconds per clock interrupt tick
#define RAWBUF 112 // 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

#define MARK_EXCESS 50
#endif

148 changes: 144 additions & 4 deletions IRremoteInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
* 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 Paul Stoffregen <paul@pjrc.com> and Matthias Neeracher <neeracher@mac.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)
*
* RC-MM protocol added by Matthias Neeracher.
*/

#ifndef IRremoteint_h
Expand Down Expand Up @@ -65,6 +67,16 @@
#elif defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__)
#define IR_USE_TIMER1 // tx = pin 9

// Tested with ATtiny85, presumably works with ATtiny45, possibly with ATtiny25
// The attiny core uses Timer 0 for millis() etc., so using timer 1 is advisable
// for IR out. Pin 4 also conveniently is not used in any role for ISP.
// The Arduino-tiny core uses Timer 1 for millis(), so using timer 0 is advisable
// for IR out. Pin 0 is used by default for IR out in the Tinyspark IR shield, but
// is not usable for PWM waveforms where the frequency, not just the duty cycle,
// needs to be controlled.
#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define IR_USE_TIMER1_TINY // tx = pin 4 (OC1B)
// #define IR_USE_TIMER0 // tx = pin 1 (OC0B)
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
#else
//#define IR_USE_TIMER1 // tx = pin 9
Expand Down Expand Up @@ -163,9 +175,43 @@
#define JVC_ZERO_SPACE 550
#define JVC_RPT_LENGTH 60000

#define RCMM_HDR_MARK 417
#define RCMM_MARK 149 // Protocol says 167, but in practice we often seem to be short
#define RCMM_SPACE 277
#define RCMM_INCREMENT 167

#define SHARP_BITS 15
#define DISH_BITS 16

#define MAGIQUEST_PERIOD 1150
#define MAGIQUEST_MARK_ZERO 280
#define MAGIQUEST_SPACE_ZERO 850
#define MAGIQUEST_MARK_ONE 580
#define MAGIQUEST_SPACE_ONE 600

#define SYMA_UPDATE_PERIOD_CH_A 120 // 0
#define SYMA_UPDATE_PERIOD_CH_B 180 // 1
#define SYMA_HDR_MARK 2000
#define SYMA_HDR_SPACE 2000
#define SYMA_BIT_MARK 320
#define SYMA_ONE_SPACE 687
#define SYMA_ZERO_SPACE 300

#define USERIES_UPDATE_PERIOD_CH_A 150 // 1
#define USERIES_UPDATE_PERIOD_CH_B 110 // 2
#define USERIES_UPDATE_PERIOD_CH_C 190 // 0
#define USERIES_HDR_MARK 1600
#define USERIES_BIT_SPACE 400
#define USERIES_ONE_MARK 420
#define USERIES_ZERO_MARK 770

#define FASTLANE_UPDATE_PERIOD_CH_A 140 // 2
#define FASTLANE_UPDATE_PERIOD_CH_B 180 // 1
#define FASTLANE_UPDATE_PERIOD_CH_C 220 // 0
#define FASTLANE_HDR_MARK 2200
#define FASTLANE_ONE 1200
#define FASTLANE_ZERO 600

#define TOLERANCE 25 // percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
Expand Down Expand Up @@ -194,7 +240,7 @@ 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 long startTime; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
Expand All @@ -207,7 +253,7 @@ extern volatile irparams_t irparams;
#define MARK 0
#define SPACE 1

#define TOPBIT 0x80000000
#define TOPBIT 0x80000000

#define NEC_BITS 32
#define SONY_BITS 12
Expand All @@ -217,7 +263,12 @@ extern volatile irparams_t irparams;
#define MIN_RC6_SAMPLES 1
#define PANASONIC_BITS 48
#define JVC_BITS 16

#define RCMM_BITS 12
#define MAGIQUEST_BITS 56
#define SYMA_R5_BITS 32
#define SYMA_R3_BITS 24
#define USERIES_BITS 32
#define FASTLANE_BITS 23



Expand Down Expand Up @@ -300,6 +351,91 @@ extern volatile irparams_t irparams;
#endif


// defines for timer1 on ATtiny (8 bits), no phase-correct PWM
#elif defined(IR_USE_TIMER1_TINY)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (GTCCR |= _BV(COM1B1))
#define TIMER_DISABLE_PWM (GTCCR &= ~_BV(COM1B1))
#define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE1B))
#define TIMER_DISABLE_INTR (TIMSK &= ~_BV(OCIE1B))
#define TIMER_INTR_NAME TIMER1_COMPB_vect
#if SYSCLOCK <= 8000000
#define TIMER_CONFIG_KHZ(val) ({ \
const uint8_t pwmval = SYSCLOCK / 1000 / (val); \
TCCR1 = _BV(CS10); \
GTCCR = _BV(PWM1B); \
OCR1C = pwmval; \
OCR1B = pwmval / 3; \
})
#else
#define TIMER_CONFIG_KHZ(val) ({ \
const uint8_t pwmval = SYSCLOCK / 4000 / (val); \
TCCR1 = _BV(CS11) | _BV(CS10); \
GTCCR = _BV(PWM1B); \
OCR1C = pwmval; \
OCR1B = pwmval / 3; \
})
#endif
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000)
#if (TIMER_COUNT_TOP < 256)
#define TIMER_CONFIG_NORMAL() ({ \
TCCR1 = _BV(CTC1) | _BV(CS10); \
GTCCR = 0; \
OCR1C = TIMER_COUNT_TOP; \
OCR1B = TIMER_COUNT_TOP; \
TCNT1 = 0; \
})
#else
#define TIMER_CONFIG_NORMAL() ({ \
TCCR1 = _BV(CTC1) | _BV(CS12); \
GTCCR = 0; \
OCR1C = TIMER_COUNT_TOP / 8; \
OCR1B = TIMER_COUNT_TOP / 8; \
TCNT1 = 0; \
})
#endif
#define TIMER_PWM_PIN 4


// defines for timer0 (8 bits). Tested on ATtiny85, may also work on other
// processors, but most of them use Timer 0 to keep system time
#elif defined(IR_USE_TIMER0)
#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 = 0)
#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() ({ \
TCCR2A = _BV(WGM01); \
TCCR2B = _BV(CS00); \
OCR2A = TIMER_COUNT_TOP; \
TCNT2 = 0; \
})
#else
#define TIMER_CONFIG_NORMAL() ({ \
TCCR2A = _BV(WGM01); \
TCCR2B = _BV(CS01); \
OCR2A = TIMER_COUNT_TOP / 8; \
TCNT2 = 0; \
})
#endif
#if defined(CORE_OC0A_PIN)
#define TIMER_PWM_PIN CORE_OC0B_PIN
#else
#define TIMER_PWM_PIN 1 /* Attiny core */
#endif


// defines for timer3 (16 bits)
#elif defined(IR_USE_TIMER3)
#define TIMER_RESET
Expand Down Expand Up @@ -496,6 +632,10 @@ extern volatile irparams_t irparams;
#define BLINKLED 0
#define BLINKLED_ON() (PORTD |= B00000001)
#define BLINKLED_OFF() (PORTD &= B11111110)
#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define BLINKLED 4
#define BLINKLED_ON() (PORTB |= B00001000)
#define BLINKLED_OFF() (PORTB &= B11110110)
#else
#define BLINKLED 13
#define BLINKLED_ON() (PORTB |= B00100000)
Expand Down
Loading