IRremote
ir_Lego.hpp
Go to the documentation of this file.
1 /*
2  * ir_Lego.hpp
3  *
4  * Contains functions for receiving and sending Lego Power Functions IR Protocol
5  *
6  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
7  *
8  ************************************************************************************
9  * MIT License
10  *
11  * Copyright (c) 2020-2023 Armin Joachimsmeyer
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is furnished
18  * to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in all
21  * copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
24  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
25  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
28  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29  *
30  ************************************************************************************
31  */
32 #ifndef _IR_LEGO_HPP
33 #define _IR_LEGO_HPP
34 
38 //==============================================================================
39 // L EEEEEE EEEE OOOO
40 // L E E O O
41 // L EEEE E EEE O O
42 // L E E E O O
43 // LLLLLL EEEEEE EEEE OOOO
44 //==============================================================================
45 // from LEGO Power Functions RC Manual 26.02.2010 Version 1.20
46 // https://github.com/jurriaan/Arduino-PowerFunctions/raw/master/LEGO_Power_Functions_RC_v120.pdf
47 // https://oberguru.net/elektronik/ir/codes/lego_power_functions_train.lircd.conf
48 //
49 // To ensure correct detection of IR messages six 38 kHz cycles are transmitted as mark.
50 // Low bit consists of 6 cycles of IR and 10 �cycles� of pause,
51 // high bit of 6 cycles IR and 21 �cycles� of pause and start bit of 6 cycles IR and 39 �cycles� of pause.
52 // Low bit range 316 - 526 us
53 // High bit range 526 � 947 us
54 // Start/stop bit range 947 � 1579 us
55 // If tm is the maximum message length (16ms) and Ch is the channel number, then
56 // The delay before transmitting the first message is: (4 � Ch)*tm
57 // The time from start to start for the next 2 messages is: 5*tm
58 // The time from start to start for the following messages is: (6 + 2*Ch)*tm
59 // Supported Devices
60 // LEGO Power Functions IR Receiver 8884
61 // MSB first, 1 start bit + 4 bit channel, 4 bit mode + 4 bit command + 4 bit parity + 1 stop bit.
62 #define LEGO_CHANNEL_BITS 4
63 #define LEGO_MODE_BITS 4
64 #define LEGO_COMMAND_BITS 4
65 #define LEGO_PARITY_BITS 4
66 
67 #define LEGO_BITS (LEGO_CHANNEL_BITS + LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS)
68 
69 #define LEGO_HEADER_MARK 158 // 6 cycles
70 #define LEGO_HEADER_SPACE 1026 // 39 cycles
71 
72 #define LEGO_BIT_MARK 158 // 6 cycles
73 #define LEGO_ONE_SPACE 553 // 21 cycles
74 #define LEGO_ZERO_SPACE 263 // 10 cycles
75 
76 #define LEGO_AVERAGE_DURATION 11000 // LEGO_HEADER_MARK + LEGO_HEADER_SPACE + 16 * 600 + 158
77 
78 #define LEGO_AUTO_REPEAT_PERIOD_MIN 110000 // Every frame is auto repeated 5 times.
79 #define LEGO_AUTO_REPEAT_PERIOD_MAX 230000 // space for channel 3
80 
81 #define LEGO_MODE_EXTENDED 0
82 #define LEGO_MODE_COMBO 1
83 #define LEGO_MODE_SINGLE 0x4 // here the 2 LSB have meanings like Output A / Output B
84 
87  / MICROS_IN_ONE_MILLI), NULL };
88 
89 /************************************
90  * Start of send and decode functions
91  ************************************/
92 /*
93  * Here we process the structured data, and call the send raw data function
94  * @param aMode one of LEGO_MODE_EXTENDED, LEGO_MODE_COMBO, LEGO_MODE_SINGLE
95  */
96 void IRsend::sendLegoPowerFunctions(uint8_t aChannel, uint8_t aCommand, uint8_t aMode, bool aDoSend5Times) {
97  aChannel &= 0x0F; // allow toggle and escape bits too
98  aCommand &= 0x0F;
99  aMode &= 0x0F;
100  uint8_t tParity = 0xF ^ aChannel ^ aMode ^ aCommand;
101  // send 4 bit channel, 4 bit mode, 4 bit command, 4 bit parity
102  uint16_t tRawData = (((aChannel << LEGO_MODE_BITS) | aMode) << (LEGO_COMMAND_BITS + LEGO_PARITY_BITS))
103  | (aCommand << LEGO_PARITY_BITS) | tParity;
104  sendLegoPowerFunctions(tRawData, aChannel, aDoSend5Times);
105 }
106 
107 void IRsend::sendLegoPowerFunctions(uint16_t aRawData, uint8_t aChannel, bool aDoSend5Times) {
108 
109  IR_DEBUG_PRINT(F("sendLego aRawData=0x"));
110  IR_DEBUG_PRINTLN(aRawData, HEX);
111 
112  aChannel &= 0x03; // we have 4 channels
113 
114  uint_fast8_t tNumberOfRepeats = 0;
115  if (aDoSend5Times) {
116  tNumberOfRepeats = 4;
117  }
118 // required for repeat timing, see http://www.hackvandedam.nl/blog/?page_id=559
119  uint8_t tRepeatPeriod = (LEGO_AUTO_REPEAT_PERIOD_MIN / MICROS_IN_ONE_MILLI) + (aChannel * 40); // from 110 to 230
121  sendPulseDistanceWidth(&LegoProtocolConstants, aRawData, LEGO_BITS, tNumberOfRepeats);
122 }
123 
124 /*
125  * Mode is stored in the upper nibble of command
126  */
128 
130  return false;
131  }
132 
133  // Check we have enough data - +4 for initial gap, start bit mark and space + stop bit mark
134  if (decodedIRData.rawDataPtr->rawlen != (2 * LEGO_BITS) + 4) {
135  IR_DEBUG_PRINT(F("LEGO: "));
136  IR_DEBUG_PRINT(F("Data length="));
138  IR_DEBUG_PRINTLN(F(" is not 36"));
139  return false;
140  }
141 
143  IR_DEBUG_PRINT(F("LEGO: "));
144  IR_DEBUG_PRINTLN(F("Decode failed"));
145  return false;
146  }
147 
148  // Stop bit
150  IR_DEBUG_PRINT(F("LEGO: "));
151  IR_DEBUG_PRINTLN(F("Stop bit mark length is wrong"));
152  return false;
153  }
154 
155  // Success
157  uint16_t tDecodedValue = decodedIRData.decodedRawData;
158  uint8_t tToggleEscapeChannel = tDecodedValue >> (LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS);
159  uint8_t tMode = (tDecodedValue >> (LEGO_COMMAND_BITS + LEGO_PARITY_BITS)) & 0xF;
160  uint8_t tData = (tDecodedValue >> LEGO_PARITY_BITS) & 0xF; // lego calls this field "data"
161  uint8_t tParityReceived = tDecodedValue & 0xF;
162 
163  // This is parity as defined in the specifications
164  // But in some scans I saw 0x9 ^ .. as parity formula
165  uint8_t tParityComputed = 0xF ^ tToggleEscapeChannel ^ tMode ^ tData;
166 
167  // parity check
168  if (tParityReceived != tParityComputed) {
169  IR_DEBUG_PRINT(F("LEGO: "));
170  IR_DEBUG_PRINT(F("Parity is not correct. expected=0x"));
171  IR_DEBUG_PRINT(tParityComputed, HEX);
172  IR_DEBUG_PRINT(F(" received=0x"));
173  IR_DEBUG_PRINT(tParityReceived, HEX);
174  IR_DEBUG_PRINT(F(", raw=0x"));
175  IR_DEBUG_PRINT(tDecodedValue, HEX);
176  IR_DEBUG_PRINT(F(", 3 nibbles are 0x"));
177  IR_DEBUG_PRINT(tToggleEscapeChannel, HEX);
178  IR_DEBUG_PRINT(F(", 0x"));
179  IR_DEBUG_PRINT(tMode, HEX);
180  IR_DEBUG_PRINT(F(", 0x"));
181  IR_DEBUG_PRINTLN(tData, HEX);
182  // might not be an error, so just continue
184  }
185 
186  /*
187  * Check for autorepeat (should happen 4 times for one press)
188  */
191  }
192  decodedIRData.address = tToggleEscapeChannel;
193  decodedIRData.command = tData | tMode << LEGO_COMMAND_BITS;
196 
197  return true;
198 }
199 
200 /*********************************************************************************
201  * Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
202  *********************************************************************************/
203 
204 void IRsend::sendLegoPowerFunctions(uint16_t aRawData, bool aDoSend5Times) {
205  sendLegoPowerFunctions(aRawData, (aRawData >> (LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS)) & 0x3, aDoSend5Times);
206 }
207 
209 #endif // _IR_LEGO_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:109
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:249
LEGO_COMMAND_BITS
#define LEGO_COMMAND_BITS
Definition: ir_Lego.hpp:64
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:118
LEGO_ZERO_SPACE
#define LEGO_ZERO_SPACE
Definition: ir_Lego.hpp:74
MICROS_IN_ONE_MILLI
#define MICROS_IN_ONE_MILLI
Definition: IRremote.hpp:254
IRsend::sendPulseDistanceWidth
void sendPulseDistanceWidth(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Sends PulseDistance frames and repeats and enables receiver again.
Definition: IRSend.hpp:702
irparams_struct::rawbuf
uint16_t rawbuf[RAW_BUFFER_LENGTH]
raw data / tick counts per mark/space, first entry is the length of the gap between previous and curr...
Definition: IRremoteInt.h:113
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:129
IRDATA_FLAGS_IS_AUTO_REPEAT
#define IRDATA_FLAGS_IS_AUTO_REPEAT
The current repeat frame is a repeat, that is always sent after a regular frame and cannot be avoided...
Definition: IRProtocol.h:92
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
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:845
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:93
LEGO_MODE_BITS
#define LEGO_MODE_BITS
Definition: ir_Lego.hpp:63
IRrecv::decodeLegoPowerFunctions
bool decodeLegoPowerFunctions()
Definition: ir_Lego.hpp:127
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
PROTOCOL_IS_LSB_FIRST
#define PROTOCOL_IS_LSB_FIRST
Definition: IRProtocol.h:146
LEGO_BITS
#define LEGO_BITS
Definition: ir_Lego.hpp:67
IRData::initialGap
uint16_t initialGap
rawbuf[0] contains the initial gap of the last frame.
Definition: IRProtocol.h:127
IRrecv::checkHeader
bool checkHeader(PulseDistanceWidthProtocolConstants *aProtocolConstants)
Definition: IRReceive.hpp:1018
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:110
matchMark
bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1083
LEGO_PF
@ LEGO_PF
Definition: IRProtocol.h:68
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:99
LEGO_HEADER_SPACE
#define LEGO_HEADER_SPACE
Definition: ir_Lego.hpp:70
LEGO_HEADER_MARK
#define LEGO_HEADER_MARK
Definition: ir_Lego.hpp:69
LegoProtocolConstants
struct PulseDistanceWidthProtocolConstants LegoProtocolConstants
Definition: ir_Lego.hpp:85
LEGO_AUTO_REPEAT_PERIOD_MIN
#define LEGO_AUTO_REPEAT_PERIOD_MIN
Definition: ir_Lego.hpp:78
LEGO_BIT_MARK
#define LEGO_BIT_MARK
Definition: ir_Lego.hpp:72
LEGO_ONE_SPACE
#define LEGO_ONE_SPACE
Definition: ir_Lego.hpp:73
LEGO_PARITY_BITS
#define LEGO_PARITY_BITS
Definition: ir_Lego.hpp:65
LEGO_AUTO_REPEAT_PERIOD_MAX
#define LEGO_AUTO_REPEAT_PERIOD_MAX
Definition: ir_Lego.hpp:79
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:141
PulseDistanceWidthProtocolConstants::RepeatPeriodMillis
unsigned int RepeatPeriodMillis
Definition: IRProtocol.h:137
IRsend::sendLegoPowerFunctions
void sendLegoPowerFunctions(uint8_t aChannel, uint8_t tCommand, uint8_t aMode, bool aDoSend5Times=true)
Definition: ir_Lego.hpp:96
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:108
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:582