IRremote
ir_MagiQuest.hpp
Go to the documentation of this file.
1 /*
2  * ir_MagiQuest.hpp
3  *
4  * Contains functions for receiving and sending MagiQuest Protocol
5  * Based off the Magiquest fork of Arduino-IRremote by mpflaga https://github.com/mpflaga/Arduino-IRremote/
6  *
7  * RESULT:
8  * The 31 bit wand ID is available in decodedRawData.
9  * The lower 16 bit of the ID is available in address.
10  * The magnitude is available in command.
11  *
12  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
13  *
14  ************************************************************************************
15  * MIT License
16  *
17  * Copyright (c) 2017-2023 E. Stuart Hicks <ehicks@binarymagi.com>, Armin Joachimsmeyer
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a copy
20  * of this software and associated documentation files (the "Software"), to deal
21  * in the Software without restriction, including without limitation the rights
22  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23  * copies of the Software, and to permit persons to whom the Software is furnished
24  * to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice shall be included in all
27  * copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
30  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
31  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
32  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
33  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
34  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35  *
36  ************************************************************************************
37  */
38 #ifndef _IR_MAGIQUEST_HPP
39 #define _IR_MAGIQUEST_HPP
40 
41 #if defined(DEBUG) && !defined(LOCAL_DEBUG)
42 #define LOCAL_DEBUG
43 #else
44 //#define LOCAL_DEBUG // This enables debug output only for this file
45 #endif
46 //
47 //==============================================================================
48 //
49 // M M AA GGG III QQQ U U EEEE SSS TTTTTT
50 // MM MM A A G I Q Q U U E S TT
51 // M M M AAAA G GG I Q Q U U EEE SSS TT
52 // M M A A G G I Q QQ U U E S TT
53 // M M A A GGG III QQQQ UUU EEEE SSSS TT
54 // Q
55 //==============================================================================
56 /*
57  * https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp
58  * https://github.com/Arduino-IRremote/Arduino-IRremote/discussions/1027#discussioncomment-3636857
59  * https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1015#issuecomment-1222247231
60 
61  Protocol=MagiQuest Address=0xFF00 Command=0x176 Raw-Data=0x6BCDFF00 56 bits MSB first
62  + 250,- 800 + 250,- 850 + 250,- 850 + 250,- 850 // 8 zero start bits
63  + 250,- 850 + 300,- 800 + 250,- 850 + 250,- 850
64 
65  // 31 ID bits
66  + 550,- 600 + 550,- 550 + 350,- 800 + 600,- 600 // 110 1 6
67  + 200,- 950 + 550,- 600 + 550,- 600 + 550,- 600 // 011 1 B - 1(from above)011 => B
68  + 550,- 600 + 250,- 900 + 300,- 850 + 550,- 600 // 100 1 C
69  + 550,- 600 + 300,- 850 + 550,- 600 + 550,- 600
70  + 550,- 600 + 550,- 600 + 550,- 600 + 550,- 600
71  + 550,- 600 + 550,- 600 + 550,- 600 + 300,- 800
72  + 350,- 850 + 300,- 850 + 300,- 850 + 300,- 850
73  + 300,- 850 + 300,- 850 + 300,- 850 + 550,- 600 // 000 1 - 3 LSB ID bits 000 + 1 MSB magnitude bit 1
74 
75  // 8 bit magnitude
76  + 300,- 850 + 550,- 600 + 550,- 600 + 550,- 600
77  + 300,- 850 + 550,- 600 + 550,- 600 + 250,- 900
78 
79  // Checksum (+ sum of the 5 bytes before == 0)
80  + 250,- 900 + 300,- 900 + 250,- 850 + 550,- 600
81  + 600,- 550 + 300,- 900 + 250,- 850 + 550
82  */
83 // MSB first, 8 start bits (zero), 31 wand id bits, 9 magnitude bits 8 checksum bits and no stop bit => 56 bits
84 #define MAGIQUEST_CHECKSUM_BITS 8 // magiquest_t.cmd.checksum
85 #define MAGIQUEST_MAGNITUDE_BITS 9 // magiquest_t.cmd.magnitude
86 #define MAGIQUEST_WAND_ID_BITS 31 // magiquest_t.cmd.wand_id -> wand-id is handled as 32 bit and always even
87 #define MAGIQUEST_START_BITS 8 // magiquest_t.cmd.StartBits
88 
89 #define MAGIQUEST_PERIOD 1150 // Time for a full MagiQuest "bit" (1100 - 1200 usec)
90 
91 #define MAGIQUEST_DATA_BITS (MAGIQUEST_CHECKSUM_BITS + MAGIQUEST_MAGNITUDE_BITS + MAGIQUEST_WAND_ID_BITS) // 48 Size of the command without the start bits
92 #define MAGIQUEST_BITS (MAGIQUEST_CHECKSUM_BITS + MAGIQUEST_MAGNITUDE_BITS + MAGIQUEST_WAND_ID_BITS + MAGIQUEST_START_BITS) // 56 Size of the command with the start bits
93 
94 /*
95  * 0 = 25% mark & 75% space across 1 period
96  * 1150 * 0.25 = 288 usec mark
97  * 1150 - 288 = 862 usec space
98  * 1 = 50% mark & 50% space across 1 period
99  * 1150 * 0.5 = 575 usec mark
100  * 1150 - 575 = 575 usec space
101  */
102 #define MAGIQUEST_UNIT (MAGIQUEST_PERIOD / 4) // 287.5
103 
104 #define MAGIQUEST_ONE_MARK (2 * MAGIQUEST_UNIT) // 576
105 #define MAGIQUEST_ONE_SPACE (2 * MAGIQUEST_UNIT) // 576
106 #define MAGIQUEST_ZERO_MARK MAGIQUEST_UNIT // 287.5
107 #define MAGIQUEST_ZERO_SPACE (3 * MAGIQUEST_UNIT) // 864
108 
109 // assume 110 as repeat period
112 //+=============================================================================
113 //
118 void IRsend::sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude) {
119 
120  // Set IR carrier frequency
121  enableIROut(38);
122 
123  aMagnitude &= 0x1FF; // we have 9 bit
124  LongUnion tWandId;
125  tWandId.ULong = aWandId << 1;
126  uint8_t tChecksum = (tWandId.Bytes[0]) + tWandId.Bytes[1] + tWandId.Bytes[2] + tWandId.Bytes[3];
127  tChecksum += aMagnitude + (aMagnitude >> 8);
128  tChecksum = ~tChecksum + 1;
129 
130  // 8 start bits
132  // 48 bit data
133  sendPulseDistanceWidthData(&MagiQuestProtocolConstants, aWandId, MAGIQUEST_WAND_ID_BITS); // send only 31 bit, do not send MSB here
136 #if defined(LOCAL_DEBUG)
137  // must be after sending, in order not to destroy the send timing
138  Serial.print(F("MagiQuest checksum=0x"));
139  Serial.println(tChecksum, HEX);
140 #endif
141 }
142 
143 //+=============================================================================
144 //
145 /*
146  * decodes a 56 bit result, which is not really compatible with standard decoder layout
147  * magnitude is stored in command
148  * 31 bit wand_id is stored in decodedRawData
149  * lower 16 bit of wand_id is stored in address
150  */
152 
153  // Check we have the right amount of data, magnitude and ID bits and 8 start bits + 0 stop bit
154  if (decodedIRData.rawlen != (2 * MAGIQUEST_BITS)) {
155  IR_DEBUG_PRINT(F("MagiQuest: "));
156  IR_DEBUG_PRINT(F("Data length="));
158  IR_DEBUG_PRINTLN(F(" is not 112"));
159  return false;
160  }
161 
162  /*
163  * Check for 8 zero header bits
164  */
166 #if defined(LOCAL_DEBUG)
167  Serial.print(F("MagiQuest: "));
168  Serial.println(F("Start bit decode failed"));
169 #endif
170  return false;
171  }
172  if (decodedIRData.decodedRawData != 0) {
173 #if defined(LOCAL_DEBUG)
174  Serial.print(F("MagiQuest: "));
175  Serial.print(F("Not 8 leading zero start bits received, RawData=0x"));
176  Serial.println(decodedIRData.decodedRawData, HEX);
177 #endif
178  return false;
179  }
180 
181  /*
182  * Decode the 31 bit ID
183  */
185 #if defined(LOCAL_DEBUG)
186  Serial.print(F("MagiQuest: "));
187  Serial.println(F("ID decode failed"));
188 #endif
189  return false;
190  }
191  LongUnion tDecodedRawData;
192 #if defined(LOCAL_DEBUG)
193  Serial.print(F("31 bit WandId=0x"));
194  Serial.println(decodedIRData.decodedRawData, HEX);
195 #endif
196  uint32_t tWandId = decodedIRData.decodedRawData; // save tWandId for later use
197  tDecodedRawData.ULong = decodedIRData.decodedRawData << 1; // shift for checksum computation
198  uint8_t tChecksum = tDecodedRawData.Bytes[0] + tDecodedRawData.Bytes[1] + tDecodedRawData.Bytes[2] + tDecodedRawData.Bytes[3];
199 #if defined(LOCAL_DEBUG)
200  Serial.print(F("31 bit WandId=0x"));
201  Serial.print(decodedIRData.decodedRawData, HEX);
202  Serial.print(F(" shifted=0x"));
203  Serial.println(tDecodedRawData.ULong, HEX);
204 #endif
205  /*
206  * Decode the 9 bit Magnitude + 8 bit checksum
207  */
210 #if defined(LOCAL_DEBUG)
211  Serial.print(F("MagiQuest: "));
212  Serial.println(F("Magnitude + checksum decode failed"));
213 #endif
214  return false;
215  }
216 
217 #if defined(LOCAL_DEBUG)
218  Serial.print(F("Magnitude + checksum=0x"));
219  Serial.println(decodedIRData.decodedRawData, HEX);
220 #endif
221  tDecodedRawData.ULong = decodedIRData.decodedRawData;
222  decodedIRData.command = tDecodedRawData.UBytes[1] | tDecodedRawData.UBytes[2] << 8; // Values observed are 0x102,01,04,37,05,38,2D| 02,06,04|03,103,12,18,0E|09
223 
224  tChecksum += tDecodedRawData.UBytes[2] /* only one bit */+ tDecodedRawData.UBytes[1] + tDecodedRawData.UBytes[0];
225  if (tChecksum != 0) {
227 #if defined(LOCAL_DEBUG)
228  Serial.print(F("Checksum 0x"));
229  Serial.print(tChecksum, HEX);
230  Serial.println(F(" is not 0"));
231 #endif
232  }
233 
234  // Success
235  decodedIRData.decodedRawData = tWandId; // 31 bit wand_id
236  decodedIRData.address = tWandId; // lower 16 bit of wand_id
237  decodedIRData.extra = tWandId >> 16; // upper 15 bit of wand_id
238 
242 
243  return true;
244 }
245 #if defined(LOCAL_DEBUG)
246 #undef LOCAL_DEBUG
247 #endif
248 #endif // _IR_MAGIQUEST_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:109
LongUnion
Union to specify parts / manifestations of a 32 bit Long without casts and shifts.
Definition: LongUnion.h:59
IRsend::sendMagiQuest
void sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude)
Definition: ir_MagiQuest.hpp:118
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:145
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:118
MAGIQUEST_ONE_SPACE
#define MAGIQUEST_ONE_SPACE
Definition: ir_MagiQuest.hpp:105
IRData::rawlen
uint_fast8_t rawlen
counter of entries in rawbuf
Definition: IRProtocol.h:123
LongUnion::UBytes
uint8_t UBytes[4]
Definition: LongUnion.h:91
IRData::decodedRawData
IRRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send functions.
Definition: IRProtocol.h:112
IR_DEBUG_PRINT
#define IR_DEBUG_PRINT(...)
If DEBUG, print the arguments, otherwise do nothing.
Definition: IRremoteInt.h:137
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:69
MagiQuestProtocolConstants
struct PulseDistanceWidthProtocolConstants MagiQuestProtocolConstants
Definition: ir_MagiQuest.hpp:110
IRrecv::decodePulseDistanceWidthData
bool decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, uint_fast8_t aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:845
MAGIQUEST_ZERO_MARK
#define MAGIQUEST_ZERO_MARK
Definition: ir_MagiQuest.hpp:106
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:93
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:132
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:321
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRProtocol.h:119
MAGIQUEST_ZERO_SPACE
#define MAGIQUEST_ZERO_SPACE
Definition: ir_MagiQuest.hpp:107
MAGIQUEST_CHECKSUM_BITS
#define MAGIQUEST_CHECKSUM_BITS
Definition: ir_MagiQuest.hpp:84
MAGIQUEST_ONE_MARK
#define MAGIQUEST_ONE_MARK
Definition: ir_MagiQuest.hpp:104
MAGIQUEST_MAGNITUDE_BITS
#define MAGIQUEST_MAGNITUDE_BITS
Definition: ir_MagiQuest.hpp:85
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:110
LongUnion::ULong
uint32_t ULong
Definition: LongUnion.h:95
MAGIQUEST_WAND_ID_BITS
#define MAGIQUEST_WAND_ID_BITS
Definition: ir_MagiQuest.hpp:86
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:99
IRData::extra
uint16_t extra
Contains upper 16 bit of Magiquest WandID, Kaseikyo unknown vendor ID and Distance protocol (HeaderMa...
Definition: IRProtocol.h:111
IRrecv::decodeMagiQuest
bool decodeMagiQuest()
Definition: ir_MagiQuest.hpp:151
LongUnion::Bytes
int8_t Bytes[4]
Definition: LongUnion.h:92
MAGIQUEST_START_BITS
#define MAGIQUEST_START_BITS
Definition: ir_MagiQuest.hpp:87
IRsend::sendPulseDistanceWidthData
void sendPulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits)
Sends PulseDistance data The output always ends with a space Each additional call costs 16 bytes prog...
Definition: IRSend.hpp:832
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:141
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:108
MAGIQUEST_BITS
#define MAGIQUEST_BITS
Definition: ir_MagiQuest.hpp:92
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1205