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-2024 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  // No stop bit!
84  */
85 // MSB first, 8 start bits (zero), 31 wand id bits, 9 magnitude bits 8 checksum bits and no stop bit => 56 bits
86 #define MAGIQUEST_CHECKSUM_BITS 8 // magiquest_t.cmd.checksum
87 #define MAGIQUEST_MAGNITUDE_BITS 9 // magiquest_t.cmd.magnitude
88 #define MAGIQUEST_WAND_ID_BITS 31 // magiquest_t.cmd.wand_id -> wand-id is handled as 32 bit and always even
89 #define MAGIQUEST_START_BITS 8 // magiquest_t.cmd.StartBits
90 
91 #define MAGIQUEST_PERIOD 1150 // Time for a full MagiQuest "bit" (1100 - 1200 usec)
92 
93 #define MAGIQUEST_DATA_BITS (MAGIQUEST_CHECKSUM_BITS + MAGIQUEST_MAGNITUDE_BITS + MAGIQUEST_WAND_ID_BITS) // 48 Size of the command without the start bits
94 #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
95 
96 /*
97  * 0 = 25% mark & 75% space across 1 period
98  * 1150 * 0.25 = 288 usec mark
99  * 1150 - 288 = 862 usec space
100  * 1 = 50% mark & 50% space across 1 period
101  * 1150 * 0.5 = 575 usec mark
102  * 1150 - 575 = 575 usec space
103  */
104 #define MAGIQUEST_UNIT (MAGIQUEST_PERIOD / 4) // 287.5
105 
106 #define MAGIQUEST_ONE_MARK (2 * MAGIQUEST_UNIT) // 576
107 #define MAGIQUEST_ONE_SPACE (2 * MAGIQUEST_UNIT) // 576
108 #define MAGIQUEST_ZERO_MARK MAGIQUEST_UNIT // 287.5
109 #define MAGIQUEST_ZERO_SPACE (3 * MAGIQUEST_UNIT) // 864
110 
111 // assume 110 as repeat period
114  NULL };
115 //+=============================================================================
116 //
121 void IRsend::sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude) {
122 
123  // Set IR carrier frequency
124  enableIROut(38);
125 
126  aMagnitude &= 0x1FF; // we have 9 bit
127  LongUnion tWandId;
128  tWandId.ULong = aWandId << 1;
129  uint8_t tChecksum = (tWandId.Bytes[0]) + tWandId.Bytes[1] + tWandId.Bytes[2] + tWandId.Bytes[3];
130  tChecksum += aMagnitude + (aMagnitude >> 8);
131  tChecksum = ~tChecksum + 1;
132 
133  // 8 start bits
135  // 48 bit data
136  sendPulseDistanceWidthData(&MagiQuestProtocolConstants, aWandId, MAGIQUEST_WAND_ID_BITS); // send only 31 bit, do not send MSB here
139 #if defined(LOCAL_DEBUG)
140  // must be after sending, in order not to destroy the send timing
141  Serial.print(F("MagiQuest checksum=0x"));
142  Serial.println(tChecksum, HEX);
143 #endif
144 }
145 
146 //+=============================================================================
147 //
148 /*
149  * decodes a 56 bit result, which is not really compatible with standard decoder layout
150  * magnitude is stored in command
151  * 31 bit wand_id is stored in decodedRawData
152  * lower 16 bit of wand_id is stored in address
153  */
155 
156  // Check we have the right amount of data, magnitude and ID bits and 8 start bits + 0 stop bit
157  if (decodedIRData.rawlen != (2 * MAGIQUEST_BITS)) {
158  IR_DEBUG_PRINT(F("MagiQuest: "));
159  IR_DEBUG_PRINT(F("Data length="));
161  IR_DEBUG_PRINTLN(F(" is not 112"));
162  return false;
163  }
164 
165  /*
166  * Check for 8 zero header bits
167  */
169 #if defined(LOCAL_DEBUG)
170  Serial.print(F("MagiQuest: "));
171  Serial.println(F("Start bit decode failed"));
172 #endif
173  return false;
174  }
175  if (decodedIRData.decodedRawData != 0) {
176 #if defined(LOCAL_DEBUG)
177  Serial.print(F("MagiQuest: "));
178  Serial.print(F("Not 8 leading zero start bits received, RawData=0x"));
179  Serial.println(decodedIRData.decodedRawData, HEX);
180 #endif
181  return false;
182  }
183 
184  /*
185  * Decode the 31 bit ID
186  */
188 #if defined(LOCAL_DEBUG)
189  Serial.print(F("MagiQuest: "));
190  Serial.println(F("ID decode failed"));
191 #endif
192  return false;
193  }
194  LongUnion tDecodedRawData;
195 #if defined(LOCAL_DEBUG)
196  Serial.print(F("31 bit WandId=0x"));
197  Serial.println(decodedIRData.decodedRawData, HEX);
198 #endif
199  uint32_t tWandId = decodedIRData.decodedRawData; // save tWandId for later use
200  tDecodedRawData.ULong = decodedIRData.decodedRawData << 1; // shift for checksum computation
201  uint8_t tChecksum = tDecodedRawData.Bytes[0] + tDecodedRawData.Bytes[1] + tDecodedRawData.Bytes[2] + tDecodedRawData.Bytes[3];
202 #if defined(LOCAL_DEBUG)
203  Serial.print(F("31 bit WandId=0x"));
204  Serial.print(decodedIRData.decodedRawData, HEX);
205  Serial.print(F(" shifted=0x"));
206  Serial.println(tDecodedRawData.ULong, HEX);
207 #endif
208  /*
209  * Decode the 9 bit Magnitude + 8 bit checksum
210  */
213 #if defined(LOCAL_DEBUG)
214  Serial.print(F("MagiQuest: "));
215  Serial.println(F("Magnitude + checksum decode failed"));
216 #endif
217  return false;
218  }
219 
220 #if defined(LOCAL_DEBUG)
221  Serial.print(F("Magnitude + checksum=0x"));
222  Serial.println(decodedIRData.decodedRawData, HEX);
223 #endif
224  tDecodedRawData.ULong = decodedIRData.decodedRawData;
225  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
226 
227  tChecksum += tDecodedRawData.UBytes[2] /* only one bit */+ tDecodedRawData.UBytes[1] + tDecodedRawData.UBytes[0];
228  if (tChecksum != 0) {
230 #if defined(LOCAL_DEBUG)
231  Serial.print(F("Checksum 0x"));
232  Serial.print(tChecksum, HEX);
233  Serial.println(F(" is not 0"));
234 #endif
235  }
236 
237  // Success
238  decodedIRData.decodedRawData = tWandId; // 31 bit wand_id
239  decodedIRData.address = tWandId; // lower 16 bit of wand_id
240  decodedIRData.extra = tWandId >> 16; // upper 15 bit of wand_id
241 
245 
246  return true;
247 }
248 #if defined(LOCAL_DEBUG)
249 #undef LOCAL_DEBUG
250 #endif
251 #endif // _IR_MAGIQUEST_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:110
SUPPRESS_STOP_BIT
#define SUPPRESS_STOP_BIT
Definition: IRProtocol.h:146
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:121
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:147
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:119
MAGIQUEST_ONE_SPACE
#define MAGIQUEST_ONE_SPACE
Definition: ir_MagiQuest.hpp:107
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:113
IR_DEBUG_PRINT
#define IR_DEBUG_PRINT(...)
If DEBUG, print the arguments, otherwise do nothing.
Definition: IRremoteInt.h:161
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:69
MagiQuestProtocolConstants
struct PulseDistanceWidthProtocolConstants MagiQuestProtocolConstants
Definition: ir_MagiQuest.hpp:112
MAGIQUEST_ZERO_MARK
#define MAGIQUEST_ZERO_MARK
Definition: ir_MagiQuest.hpp:108
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:94
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:134
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:358
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRProtocol.h:120
MAGIQUEST_ZERO_SPACE
#define MAGIQUEST_ZERO_SPACE
Definition: ir_MagiQuest.hpp:109
MAGIQUEST_CHECKSUM_BITS
#define MAGIQUEST_CHECKSUM_BITS
Definition: ir_MagiQuest.hpp:86
IRrecv::decodePulseDistanceWidthData
bool decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:954
MAGIQUEST_ONE_MARK
#define MAGIQUEST_ONE_MARK
Definition: ir_MagiQuest.hpp:106
MAGIQUEST_MAGNITUDE_BITS
#define MAGIQUEST_MAGNITUDE_BITS
Definition: ir_MagiQuest.hpp:87
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:111
LongUnion::ULong
uint32_t ULong
Definition: LongUnion.h:95
MAGIQUEST_WAND_ID_BITS
#define MAGIQUEST_WAND_ID_BITS
Definition: ir_MagiQuest.hpp:88
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:100
IRData::extra
uint16_t extra
Contains upper 16 bit of Magiquest WandID, Kaseikyo unknown vendor ID and Distance protocol (HeaderMa...
Definition: IRProtocol.h:112
IRrecv::decodeMagiQuest
bool decodeMagiQuest()
Definition: ir_MagiQuest.hpp:154
LongUnion::Bytes
int8_t Bytes[4]
Definition: LongUnion.h:92
IRData::rawlen
IRRawlenType rawlen
counter of entries in rawbuf of last received frame.
Definition: IRProtocol.h:128
MAGIQUEST_START_BITS
#define MAGIQUEST_START_BITS
Definition: ir_MagiQuest.hpp:89
IRsend::sendPulseDistanceWidthData
void sendPulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits)
Sends PulseDistance from data contained in parameter using ProtocolConstants structure for timing etc...
Definition: IRSend.hpp:812
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:165
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:109
MAGIQUEST_BITS
#define MAGIQUEST_BITS
Definition: ir_MagiQuest.hpp:94
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1188