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 // For original LEGO receiver see: https://www.philohome.com/pfrec/pfrec.htm and https://www.youtube.com/watch?v=KCM4Ug1bPrM
49 //
50 // To ensure correct detection of IR messages six 38 kHz cycles are transmitted as mark.
51 // Low bit consists of 6 cycles of IR and 10 �cycles� of pause,
52 // high bit of 6 cycles IR and 21 �cycles� of pause and start bit of 6 cycles IR and 39 �cycles� of pause.
53 // Low bit range 316 - 526 us
54 // High bit range 526 � 947 us
55 // Start/stop bit range 947 � 1579 us
56 // If tm is the maximum message length (16ms) and Ch is the channel number, then
57 // The delay before transmitting the first message is: (4 � Ch)*tm
58 // The time from start to start for the next 2 messages is: 5*tm
59 // The time from start to start for the following messages is: (6 + 2*Ch)*tm
60 // Supported Devices
61 // LEGO Power Functions IR Receiver 8884
62 // MSB first, 1 start bit + 4 bit channel, 4 bit mode + 4 bit command + 4 bit parity + 1 stop bit.
63 #define LEGO_CHANNEL_BITS 4
64 #define LEGO_MODE_BITS 4
65 #define LEGO_COMMAND_BITS 4
66 #define LEGO_PARITY_BITS 4
67 
68 #define LEGO_BITS (LEGO_CHANNEL_BITS + LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS)
69 
70 #define LEGO_HEADER_MARK 158 // 6 cycles
71 #define LEGO_HEADER_SPACE 1026 // 39 cycles
72 
73 #define LEGO_BIT_MARK 158 // 6 cycles
74 #define LEGO_ONE_SPACE 553 // 21 cycles
75 #define LEGO_ZERO_SPACE 263 // 10 cycles
76 
77 #define LEGO_AVERAGE_DURATION 11000 // LEGO_HEADER_MARK + LEGO_HEADER_SPACE + 16 * 600 + 158
78 
79 #define LEGO_AUTO_REPEAT_PERIOD_MIN 110000 // Every frame is auto repeated 5 times.
80 #define LEGO_AUTO_REPEAT_PERIOD_MAX 230000 // space for channel 3
81 
82 #define LEGO_MODE_EXTENDED 0
83 #define LEGO_MODE_COMBO 1
84 #define LEGO_MODE_SINGLE 0x4 // here the 2 LSB have meanings like Output A / Output B
85 
88  / MICROS_IN_ONE_MILLI), NULL };
89 
90 /************************************
91  * Start of send and decode functions
92  ************************************/
93 /*
94  * Here we process the structured data, and call the send raw data function
95  * @param aMode one of LEGO_MODE_EXTENDED, LEGO_MODE_COMBO, LEGO_MODE_SINGLE
96  */
97 void IRsend::sendLegoPowerFunctions(uint8_t aChannel, uint8_t aCommand, uint8_t aMode, bool aDoSend5Times) {
98  aChannel &= 0x0F; // allow toggle and escape bits too
99  aCommand &= 0x0F;
100  aMode &= 0x0F;
101  uint8_t tParity = 0xF ^ aChannel ^ aMode ^ aCommand;
102  // send 4 bit channel, 4 bit mode, 4 bit command, 4 bit parity
103  uint16_t tRawData = (((aChannel << LEGO_MODE_BITS) | aMode) << (LEGO_COMMAND_BITS + LEGO_PARITY_BITS))
104  | (aCommand << LEGO_PARITY_BITS) | tParity;
105  sendLegoPowerFunctions(tRawData, aChannel, aDoSend5Times);
106 }
107 
108 void IRsend::sendLegoPowerFunctions(uint16_t aRawData, uint8_t aChannel, bool aDoSend5Times) {
109 
110  IR_DEBUG_PRINT(F("sendLego aRawData=0x"));
111  IR_DEBUG_PRINTLN(aRawData, HEX);
112 
113  aChannel &= 0x03; // we have 4 channels
114 
115  uint_fast8_t tNumberOfRepeats = 0;
116  if (aDoSend5Times) {
117  tNumberOfRepeats = 4;
118  }
119 // required for repeat timing, see http://www.hackvandedam.nl/blog/?page_id=559
120  uint8_t tRepeatPeriod = (LEGO_AUTO_REPEAT_PERIOD_MIN / MICROS_IN_ONE_MILLI) + (aChannel * 40); // from 110 to 230
122  sendPulseDistanceWidth(&LegoProtocolConstants, aRawData, LEGO_BITS, tNumberOfRepeats);
123 }
124 
125 /*
126  * Mode is stored in the upper nibble of command
127  */
129 
131  return false;
132  }
133 
134  // Check we have enough data - +4 for initial gap, start bit mark and space + stop bit mark
135  if (decodedIRData.rawDataPtr->rawlen != (2 * LEGO_BITS) + 4) {
136  IR_DEBUG_PRINT(F("LEGO: "));
137  IR_DEBUG_PRINT(F("Data length="));
139  IR_DEBUG_PRINTLN(F(" is not 36"));
140  return false;
141  }
142 
144  IR_DEBUG_PRINT(F("LEGO: "));
145  IR_DEBUG_PRINTLN(F("Decode failed"));
146  return false;
147  }
148 
149  // Stop bit
151  IR_DEBUG_PRINT(F("LEGO: "));
152  IR_DEBUG_PRINTLN(F("Stop bit mark length is wrong"));
153  return false;
154  }
155 
156  // Success
158  uint16_t tDecodedValue = decodedIRData.decodedRawData;
159  uint8_t tToggleEscapeChannel = tDecodedValue >> (LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS);
160  uint8_t tMode = (tDecodedValue >> (LEGO_COMMAND_BITS + LEGO_PARITY_BITS)) & 0xF;
161  uint8_t tData = (tDecodedValue >> LEGO_PARITY_BITS) & 0xF; // lego calls this field "data"
162  uint8_t tParityReceived = tDecodedValue & 0xF;
163 
164  // This is parity as defined in the specifications
165  // But in some scans I saw 0x9 ^ .. as parity formula
166  uint8_t tParityComputed = 0xF ^ tToggleEscapeChannel ^ tMode ^ tData;
167 
168  // parity check
169  if (tParityReceived != tParityComputed) {
170  IR_DEBUG_PRINT(F("LEGO: "));
171  IR_DEBUG_PRINT(F("Parity is not correct. expected=0x"));
172  IR_DEBUG_PRINT(tParityComputed, HEX);
173  IR_DEBUG_PRINT(F(" received=0x"));
174  IR_DEBUG_PRINT(tParityReceived, HEX);
175  IR_DEBUG_PRINT(F(", raw=0x"));
176  IR_DEBUG_PRINT(tDecodedValue, HEX);
177  IR_DEBUG_PRINT(F(", 3 nibbles are 0x"));
178  IR_DEBUG_PRINT(tToggleEscapeChannel, HEX);
179  IR_DEBUG_PRINT(F(", 0x"));
180  IR_DEBUG_PRINT(tMode, HEX);
181  IR_DEBUG_PRINT(F(", 0x"));
182  IR_DEBUG_PRINTLN(tData, HEX);
183  // might not be an error, so just continue
185  }
186 
187  /*
188  * Check for autorepeat (should happen 4 times for one press)
189  */
192  }
193  decodedIRData.address = tToggleEscapeChannel;
194  decodedIRData.command = tData | tMode << LEGO_COMMAND_BITS;
197 
198  return true;
199 }
200 
201 /*********************************************************************************
202  * Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
203  *********************************************************************************/
204 
205 void IRsend::sendLegoPowerFunctions(uint16_t aRawData, bool aDoSend5Times) {
206  sendLegoPowerFunctions(aRawData, (aRawData >> (LEGO_MODE_BITS + LEGO_COMMAND_BITS + LEGO_PARITY_BITS)) & 0x3, aDoSend5Times);
207 }
208 
210 #endif // _IR_LEGO_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:110
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:250
LEGO_COMMAND_BITS
#define LEGO_COMMAND_BITS
Definition: ir_Lego.hpp:65
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:119
LEGO_ZERO_SPACE
#define LEGO_ZERO_SPACE
Definition: ir_Lego.hpp:75
MICROS_IN_ONE_MILLI
#define MICROS_IN_ONE_MILLI
Definition: IRremote.hpp:255
IRsend::sendPulseDistanceWidth
void sendPulseDistanceWidth(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Sends PulseDistance frames and repeats.
Definition: IRSend.hpp:691
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:131
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:93
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
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:94
LEGO_MODE_BITS
#define LEGO_MODE_BITS
Definition: ir_Lego.hpp:64
IRrecv::decodeLegoPowerFunctions
bool decodeLegoPowerFunctions()
Definition: ir_Lego.hpp:128
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:134
irparams_struct::rawlen
IRRawlenType rawlen
counter of entries in rawbuf
Definition: IRremoteInt.h:142
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
PROTOCOL_IS_LSB_FIRST
#define PROTOCOL_IS_LSB_FIRST
Definition: IRProtocol.h:148
LEGO_BITS
#define LEGO_BITS
Definition: ir_Lego.hpp:68
IRrecv::checkHeader
bool checkHeader(PulseDistanceWidthProtocolConstants *aProtocolConstants)
Definition: IRReceive.hpp:1126
IRrecv::decodePulseDistanceWidthData
bool decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:954
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:111
matchMark
bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1193
LEGO_PF
@ LEGO_PF
Definition: IRProtocol.h:68
irparams_struct::rawbuf
IRRawbufType rawbuf[RAW_BUFFER_LENGTH]
raw data / tick counts per mark/space. With 8 bit we can only store up to 12.7 ms....
Definition: IRremoteInt.h:144
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:100
LEGO_HEADER_SPACE
#define LEGO_HEADER_SPACE
Definition: ir_Lego.hpp:71
LEGO_HEADER_MARK
#define LEGO_HEADER_MARK
Definition: ir_Lego.hpp:70
LegoProtocolConstants
struct PulseDistanceWidthProtocolConstants LegoProtocolConstants
Definition: ir_Lego.hpp:86
LEGO_AUTO_REPEAT_PERIOD_MIN
#define LEGO_AUTO_REPEAT_PERIOD_MIN
Definition: ir_Lego.hpp:79
LEGO_BIT_MARK
#define LEGO_BIT_MARK
Definition: ir_Lego.hpp:73
LEGO_ONE_SPACE
#define LEGO_ONE_SPACE
Definition: ir_Lego.hpp:74
LEGO_PARITY_BITS
#define LEGO_PARITY_BITS
Definition: ir_Lego.hpp:66
LEGO_AUTO_REPEAT_PERIOD_MAX
#define LEGO_AUTO_REPEAT_PERIOD_MAX
Definition: ir_Lego.hpp:80
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:165
PulseDistanceWidthProtocolConstants::RepeatPeriodMillis
unsigned int RepeatPeriodMillis
Definition: IRProtocol.h:139
IRsend::sendLegoPowerFunctions
void sendLegoPowerFunctions(uint8_t aChannel, uint8_t tCommand, uint8_t aMode, bool aDoSend5Times=true)
Definition: ir_Lego.hpp:97
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:109
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:610
IRData::initialGapTicks
uint16_t initialGapTicks
contains the initial gap (pre 4.4: the value in rawbuf[0]) of the last received frame.
Definition: IRProtocol.h:129