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-2022 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 A G I Q U E S T
50 //
51 //==============================================================================
52 /*
53  * https://github.com/kitlaan/Arduino-IRremote/blob/master/ir_Magiquest.cpp
54  * https://github.com/Arduino-IRremote/Arduino-IRremote/discussions/1027#discussioncomment-3636857
55  * https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1015#issuecomment-1222247231
56 
57  Protocol=MagiQuest Address=0xFF00 Command=0x176 Raw-Data=0x6BCDFF00 56 bits MSB first
58  + 250,- 800 + 250,- 850 + 250,- 850 + 250,- 850 // 8 zero start bits
59  + 250,- 850 + 300,- 800 + 250,- 850 + 250,- 850
60 
61  // 31 ID bits
62  + 550,- 600 + 550,- 550 + 350,- 800 + 600,- 600 // 110 1 6
63  + 200,- 950 + 550,- 600 + 550,- 600 + 550,- 600 // 011 1 B - 1(from above)011 => B
64  + 550,- 600 + 250,- 900 + 300,- 850 + 550,- 600 // 100 1 C
65  + 550,- 600 + 300,- 850 + 550,- 600 + 550,- 600
66  + 550,- 600 + 550,- 600 + 550,- 600 + 550,- 600
67  + 550,- 600 + 550,- 600 + 550,- 600 + 300,- 800
68  + 350,- 850 + 300,- 850 + 300,- 850 + 300,- 850
69  + 300,- 850 + 300,- 850 + 300,- 850 + 550,- 600 // 000 1 - 3 LSB ID bits 000 + 1 MSB magnitude bit 1
70 
71  // 8 bit magnitude
72  + 300,- 850 + 550,- 600 + 550,- 600 + 550,- 600
73  + 300,- 850 + 550,- 600 + 550,- 600 + 250,- 900
74 
75  // Checksum (+ sum of the 5 bytes before == 0)
76  + 250,- 900 + 300,- 900 + 250,- 850 + 550,- 600
77  + 600,- 550 + 300,- 900 + 250,- 850 + 550
78  */
79 // MSB first, 8 start bits (zero), 31 wand id bits, 9 magnitude bits 8 checksum bits and no stop bit => 56 bits
80 #define MAGIQUEST_CHECKSUM_BITS 8 // magiquest_t.cmd.checksum
81 #define MAGIQUEST_MAGNITUDE_BITS 9 // magiquest_t.cmd.magnitude
82 #define MAGIQUEST_WAND_ID_BITS 31 // magiquest_t.cmd.wand_id -> wand-id is handled as 32 bit and always even
83 #define MAGIQUEST_START_BITS 8 // magiquest_t.cmd.StartBits
84 
85 #define MAGIQUEST_PERIOD 1150 // Time for a full MagiQuest "bit" (1100 - 1200 usec)
86 
87 #define MAGIQUEST_DATA_BITS (MAGIQUEST_CHECKSUM_BITS + MAGIQUEST_MAGNITUDE_BITS + MAGIQUEST_WAND_ID_BITS) // 48 Size of the command without the start bits
88 #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
89 
90 /*
91  * 0 = 25% mark & 75% space across 1 period
92  * 1150 * 0.25 = 288 usec mark
93  * 1150 - 288 = 862 usec space
94  * 1 = 50% mark & 50% space across 1 period
95  * 1150 * 0.5 = 575 usec mark
96  * 1150 - 575 = 575 usec space
97  */
98 #define MAGIQUEST_UNIT (MAGIQUEST_PERIOD / 4) // 287.5
99 
100 #define MAGIQUEST_ONE_MARK (2 * MAGIQUEST_UNIT) // 576
101 #define MAGIQUEST_ONE_SPACE (2 * MAGIQUEST_UNIT) // 576
102 #define MAGIQUEST_ZERO_MARK MAGIQUEST_UNIT // 287.5
103 #define MAGIQUEST_ZERO_SPACE (3 * MAGIQUEST_UNIT) // 864
104 
105 // assume 110 as repeat period
108  NULL };
109 //+=============================================================================
110 //
115 void IRsend::sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude) {
116 
117  // Set IR carrier frequency
118  enableIROut(38);
119 
120  aMagnitude &= 0x1FF; // we have 9 bit
121  LongUnion tWandId;
122  tWandId.ULong = aWandId << 1;
123  uint8_t tChecksum = (tWandId.Bytes[0]) + tWandId.Bytes[1] + tWandId.Bytes[2] + tWandId.Bytes[3];
124  tChecksum += aMagnitude + (aMagnitude >> 8);
125  tChecksum = ~tChecksum + 1;
126 
127  // 8 start bits
129  // 48 bit data
130  sendPulseDistanceWidthData(&MagiQuestProtocolConstants, aWandId, MAGIQUEST_WAND_ID_BITS); // send only 31 bit, do not send MSB here
133 #if defined(LOCAL_DEBUG)
134  // must be after sending, in order not to destroy the send timing
135  Serial.print(F("MagiQuest checksum=0x"));
136  Serial.println(tChecksum, HEX);
137 #endif
138 #if !defined(DISABLE_CODE_FOR_RECEIVER)
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
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:117
LongUnion
Union to specify parts / manifestations of a 32 bit Long without casts and shifts.
Definition: LongUnion.h:57
IRsend::sendMagiQuest
void sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude)
Definition: ir_MagiQuest.hpp:115
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:130
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:120
MAGIQUEST_ONE_SPACE
#define MAGIQUEST_ONE_SPACE
Definition: ir_MagiQuest.hpp:101
LongUnion::UBytes
uint8_t UBytes[4]
Definition: LongUnion.h:89
IRrecv::restartAfterSend
void restartAfterSend()
Restarts receiver after send.
Definition: IRReceive.hpp:346
IRData::rawDataPtr
irparams_struct * rawDataPtr
Pointer of the raw timing data to be decoded. Mainly the OverflowFlag and the data buffer filled by r...
Definition: IRProtocol.h:126
IRData::decodedRawData
IRRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send functions.
Definition: IRProtocol.h:122
IR_DEBUG_PRINT
#define IR_DEBUG_PRINT(...)
If DEBUG, print the arguments, otherwise do nothing.
Definition: IRremoteInt.h:133
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:69
MagiQuestProtocolConstants
struct PulseDistanceWidthProtocolConstants MagiQuestProtocolConstants
Definition: ir_MagiQuest.hpp:106
irparams_struct::rawlen
uint_fast8_t rawlen
counter of entries in rawbuf
Definition: IRremoteInt.h:109
IRrecv::decodePulseDistanceWidthData
bool decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, uint_fast8_t aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:768
MAGIQUEST_ZERO_MARK
#define MAGIQUEST_ZERO_MARK
Definition: ir_MagiQuest.hpp:102
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
the current (autorepeat) frame violated parity check
Definition: IRProtocol.h:96
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:74
SEND_NO_STOP_BIT
#define SEND_NO_STOP_BIT
Definition: IRremoteInt.h:394
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:305
IRData::flags
uint8_t flags
See IRDATA_FLAGS_* definitions above.
Definition: IRProtocol.h:121
MAGIQUEST_ZERO_SPACE
#define MAGIQUEST_ZERO_SPACE
Definition: ir_MagiQuest.hpp:103
MAGIQUEST_CHECKSUM_BITS
#define MAGIQUEST_CHECKSUM_BITS
Definition: ir_MagiQuest.hpp:80
MAGIQUEST_ONE_MARK
#define MAGIQUEST_ONE_MARK
Definition: ir_MagiQuest.hpp:100
MAGIQUEST_MAGNITUDE_BITS
#define MAGIQUEST_MAGNITUDE_BITS
Definition: ir_MagiQuest.hpp:81
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:118
LongUnion::ULong
uint32_t ULong
Definition: LongUnion.h:93
MAGIQUEST_WAND_ID_BITS
#define MAGIQUEST_WAND_ID_BITS
Definition: ir_MagiQuest.hpp:82
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:119
IRrecv::decodeMagiQuest
bool decodeMagiQuest()
Definition: ir_MagiQuest.hpp:151
LongUnion::Bytes
int8_t Bytes[4]
Definition: LongUnion.h:90
MAGIQUEST_START_BITS
#define MAGIQUEST_START_BITS
Definition: ir_MagiQuest.hpp:83
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:643
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:137
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:116
MAGIQUEST_BITS
#define MAGIQUEST_BITS
Definition: ir_MagiQuest.hpp:88
IrReceiver
IRrecv IrReceiver
The receiver instance.
Definition: IRReceive.hpp:59
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:961