Skip to content

Commit fc05a22

Browse files
authored
Add support for MagiQuest IR wands (Arduino-IRremote#703)
Co-authored-by: E. Stuart Hicks <ehicks@binarymagi.com>
1 parent 2fdb8bf commit fc05a22

File tree

7 files changed

+179
-2
lines changed

7 files changed

+179
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Whether you use the Adafruit Neopixel lib, or FastLED, interrupts get disabled o
2222
- You can use **multiple IR receiver** by just connecting the output pins of several IR receivers together. The IR receivers use an NPN transistor as output device with just a 30k resistor to VCC. This is almost "open collector" and allows connecting of several output pins.
2323

2424
# Supported IR Protocols
25-
Aiwa, BoseWave, Denon, Dish, JVC, Lego, LG, Mitsubishi, Panasonic, RC5, RC6, Samsung, Sanyo, Sharp, Sony, Whynter.
25+
Aiwa, BoseWave, Denon, Dish, JVC, Lego, LG, MagiQuest, Mitsubishi, Panasonic, RC5, RC6, Samsung, Sanyo, Sharp, Sony, Whynter.
2626

2727
## Handling unknown Protocols
2828
### Disclaimer

changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 2.5.0 2020/07
2+
- Added support for MagiQuest IR wands
3+
14
## 2.5.0 2020/06
25
- corrected keywords.txt.
36
- BoseWave protocol added PR #690.

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ sendSharpAltRaw KEYWORD2
3434
sendPanasonic KEYWORD2
3535
sendJVC KEYWORD2
3636
sendLG KEYWORD2
37+
sendMagiQuest KEYWORD2
3738

3839
#######################################
3940
# Constants (LITERAL1)
@@ -52,5 +53,6 @@ PANASONIC LITERAL1
5253
JVC LITERAL1
5354
LG LITERAL1
5455
AIWA_RC_T501 LITERAL1
56+
MAGIQUEST LITERAL1
5557
UNKNOWN LITERAL1
5658
REPEAT LITERAL1

src/IRremote.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
1818
// LG added by Darryl Smith (based on the JVC protocol)
1919
// Whynter A/C ARC-110WD added by Francesco Meschia
20+
// MagiQuest added by E. Stuart Hicks (based on code by mpflaga - https://github.com/mpflaga/Arduino-IRremote/)
2021
//******************************************************************************
2122
#ifndef IRremote_h
2223
#define IRremote_h
@@ -93,6 +94,9 @@
9394
#define DECODE_BOSEWAVE 1
9495
#define SEND_BOSEWAVE 1
9596

97+
#define DECODE_MAGIQUEST 1
98+
#define SEND_MAGIQUEST 1
99+
96100
#define DECODE_HASH 1 // special decoder for all protocols
97101

98102
/**
@@ -120,6 +124,7 @@ typedef enum {
120124
DENON,
121125
LEGO_PF,
122126
BOSEWAVE,
127+
MAGIQUEST,
123128
} decode_type_t;
124129

125130
/**
@@ -165,6 +170,7 @@ class decode_results {
165170
decode_type_t decode_type; ///< UNKNOWN, NEC, SONY, RC5, ...
166171
unsigned int address; ///< Used by Panasonic & Sharp [16-bits]
167172
unsigned long value; ///< Decoded value [max 32-bits]
173+
unsigned int magnitude; ///< Used by MagiQuest [16-bits]
168174
int bits; ///< Number of bits in decoded value
169175
volatile unsigned int *rawbuf; ///< Raw intervals in 50uS ticks
170176
unsigned int rawlen; ///< Number of records in rawbuf
@@ -321,6 +327,10 @@ class IRrecv {
321327
//......................................................................
322328
#if DECODE_BOSEWAVE
323329
bool decodeBoseWave(decode_results *results);
330+
#endif
331+
//......................................................................
332+
#if DECODE_MAGIQUEST
333+
bool decodeMagiQuest(decode_results *results);
324334
#endif
325335
};
326336

@@ -422,6 +432,10 @@ class IRsend {
422432
#if SEND_BOSEWAVE
423433
void sendBoseWave(unsigned char code);
424434
#endif
435+
//......................................................................
436+
#if SEND_MAGIQUEST
437+
void sendMagiQuest(unsigned long wand_id, unsigned int magnitude);
438+
#endif
425439

426440
/**
427441
* Parse the string given as Pronto Hex, and send it a number of times given

src/irRecv.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ int IRrecv::decode(decode_results *results) {
125125
if (decodeLegoPowerFunctions(results)) {return true ;}
126126
#endif
127127

128+
#if DECODE_MAGIQUEST
129+
DBG_PRINTLN("Attempting MagiQuest decode");
130+
if (decodeMagiQuest(results)) {return true ;}
131+
#endif
132+
128133
#if DECODE_HASH
129134
DBG_PRINTLN("Hash decode");
130135
// decodeHash returns a hash on any input.

src/ir_MagiQuest.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include "IRremote.h"
2+
#include <math.h>
3+
4+
// Based off the Magiquest fork of Arduino-IRremote by mpflaga
5+
// https://github.com/mpflaga/Arduino-IRremote/
6+
7+
//==============================================================================
8+
//
9+
//
10+
// M A G I Q U E S T
11+
//
12+
//
13+
//==============================================================================
14+
15+
// MagiQuest packet is both Wand ID and magnitude of swish and flick
16+
union magiquest_t {
17+
unsigned long long llword;
18+
unsigned char byte[8];
19+
struct {
20+
unsigned int magnitude;
21+
unsigned long wand_id;
22+
char padding;
23+
char scrap;// just to pad the struct out to 64 bits so we can union with llword
24+
} cmd;
25+
};
26+
27+
#define MAGIQUEST_BITS 50 // The number of bits in the command itself
28+
#define MAGIQUEST_PERIOD 1150 // Length of time a full MQ "bit" consumes (1100 - 1200 usec)
29+
/*
30+
* 0 = 25% mark & 75% space across 1 period
31+
* 1150 * 0.25 = 288 usec mark
32+
* 1150 - 288 = 862 usec space
33+
* 1 = 50% mark & 50% space across 1 period
34+
* 1150 * 0.5 = 575 usec mark
35+
* 1150 - 575 = 575 usec space
36+
*/
37+
#define MAGIQUEST_ONE_MARK 575
38+
#define MAGIQUEST_ONE_SPACE 575
39+
#define MAGIQUEST_ZERO_MARK 288
40+
#define MAGIQUEST_ZERO_SPACE 862
41+
42+
//+=============================================================================
43+
//
44+
#if SEND_MAGIQUEST
45+
void IRsend::sendMagiQuest(unsigned long wand_id, unsigned int magnitude) {
46+
magiquest_t data;
47+
48+
data.llword = 0;
49+
data.cmd.wand_id = wand_id;
50+
data.cmd.magnitude = magnitude;
51+
52+
// Set IR carrier frequency
53+
enableIROut(38);
54+
55+
// Data
56+
for (unsigned long long mask = (unsigned long long)pow(2, MAGIQUEST_BITS-1); mask > 0; mask >>= 1) {
57+
if (data.llword & mask) {
58+
DBG_PRINT("1");
59+
mark(MAGIQUEST_ONE_MARK);
60+
space(MAGIQUEST_ONE_SPACE);
61+
} else {
62+
DBG_PRINT("0");
63+
mark(MAGIQUEST_ZERO_MARK);
64+
space(MAGIQUEST_ZERO_SPACE);
65+
}
66+
}
67+
DBG_PRINTLN("");
68+
69+
// Footer
70+
mark(MAGIQUEST_ZERO_MARK);
71+
space(0); // Always end with the LED off
72+
}
73+
#endif
74+
75+
//+=============================================================================
76+
//
77+
#if DECODE_MAGIQUEST
78+
bool IRrecv::decodeMagiQuest(decode_results *results) {
79+
magiquest_t data; // Somewhere to build our code
80+
unsigned int offset = 1; // Skip the Gap reading
81+
82+
unsigned int mark_;
83+
unsigned int space_;
84+
unsigned int ratio_;
85+
86+
#if DEBUG
87+
char bitstring[MAGIQUEST_BITS*2];
88+
memset(bitstring, 0, sizeof(bitstring));
89+
#endif
90+
91+
// Check we have enough data
92+
if (irparams.rawlen < 2 * MAGIQUEST_BITS) {
93+
DBG_PRINT("Not enough bits to be a MagiQuest packet (");
94+
DBG_PRINT(irparams.rawlen);
95+
DBG_PRINT(" < ");
96+
DBG_PRINT(MAGIQUEST_BITS*2);
97+
DBG_PRINTLN(")");
98+
return false;
99+
}
100+
101+
// Read the bits in
102+
data.llword = 0;
103+
while (offset+1 < irparams.rawlen) {
104+
mark_ = results->rawbuf[offset++];
105+
space_ = results->rawbuf[offset++];
106+
ratio_ = space_ / mark_;
107+
108+
DBG_PRINT("mark=");
109+
DBG_PRINT(mark_ * MICROS_PER_TICK);
110+
DBG_PRINT(" space=");
111+
DBG_PRINT(space_ * MICROS_PER_TICK);
112+
DBG_PRINT(" ratio=");
113+
DBG_PRINTLN(ratio_);
114+
115+
if (MATCH_MARK(space_ + mark_, MAGIQUEST_PERIOD)) {
116+
if (ratio_ > 1) {
117+
// It's a 0
118+
data.llword <<= 1;
119+
#if DEBUG
120+
bitstring[(offset/2)-1] = '0';
121+
#endif
122+
} else {
123+
// It's a 1
124+
data.llword = (data.llword << 1) | 1;
125+
#if DEBUG
126+
bitstring[(offset/2)-1] = '1';
127+
#endif
128+
}
129+
} else {
130+
DBG_PRINTLN("MATCH_MARK failed");
131+
return false;
132+
}
133+
}
134+
#if DEBUG
135+
DBG_PRINTLN(bitstring);
136+
#endif
137+
138+
// Success
139+
results->decode_type = MAGIQUEST;
140+
results->bits = offset / 2;
141+
results->value = data.cmd.wand_id;
142+
results->magnitude = data.cmd.magnitude;
143+
144+
DBG_PRINT("MQ: bits=");
145+
DBG_PRINT(results->bits);
146+
DBG_PRINT(" value=");
147+
DBG_PRINT(results->value);
148+
DBG_PRINT(" magnitude=");
149+
DBG_PRINTLN(results->magnitude);
150+
151+
return true;
152+
}
153+
#endif

src/private/IRremoteBoardDefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
/**
8282
* Board dependent macro to turn BLINKLED off.
8383
*/
84-
#define BLINKLED_OFF() digitalWrite(BLINKLED, HIGH)
84+
#define BLINKLED_OFF() digitalWrite(BLINKLED, LOW)
8585

8686
/**
8787
* Define to use no carrier PWM, just simulate a receiver signal.

0 commit comments

Comments
 (0)