IRremote
ir_LG.hpp
Go to the documentation of this file.
1 /*
2  * ir_LG.hpp
3  *
4  * Contains functions for receiving and sending LG IR Protocol for air conditioner
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) 2017-2022 Darryl Smith, 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_LG_HPP
33 #define _IR_LG_HPP
34 
35 #if defined(DEBUG) && !defined(LOCAL_DEBUG)
36 #define LOCAL_DEBUG
37 #else
38 //#define LOCAL_DEBUG // This enables debug output only for this file
39 #endif
40 
44 //==============================================================================
45 // L GGGG
46 // L G
47 // L G GG
48 // L G G
49 // LLLLL GGG
50 //==============================================================================
51 /*
52  * Protocol=LG Address=0xF1 Command=0x7776 Raw-Data=0xF17776B 28 bits MSB first
53  +8950,-4150
54  + 500,-1550 + 550,-1550 + 500,-1550 + 500,-1600
55  + 500,- 700 + 350,- 600 + 450,- 600 + 450,-1550
56  + 500,- 550 + 500,-1550 + 500,-1600 + 500,-1550
57  + 550,- 550 + 500,-1550 + 500,-1550 + 550,-1550
58  + 500,- 550 + 500,-1550 + 500,-1600 + 500,-1550
59  + 500,- 550 + 500,-1550 + 500,-1600 + 500,- 550
60  + 500,-1550 + 500,- 600 + 450,-1600 + 500,-1550
61  + 500
62 Sum: 62400
63 */
64 
65 // LG originally added by Darryl Smith (based on the JVC protocol)
66 // see: https://github.com/Arduino-IRremote/Arduino-IRremote/tree/master/examples/LGAirConditionerSendDemo
67 // see: https://www.mikrocontroller.net/articles/IRMP_-_english#LGAIR
68 // MSB first, 1 start bit + 8 bit address + 16 bit command + 4 bit checksum + 1 stop bit (28 data bits).
69 // Bit and repeat timing is like NEC
70 // LG2 has different header timing and a shorter bit time
71 /*
72  * LG remote IR-LED measurements: Type AKB 73315611 for air conditioner, Ver1.1 from 2011.03.01
73  * Protocol: LG2
74  * Internal crystal: 4 MHz
75  * Header: 8.9 ms mark 4.15 ms space
76  * Data: 500 / 540 and 500 / 1580;
77  * Clock is not synchronized with gate so you have 19 and sometimes 19 and a spike pulses for mark
78  * Duty: 9 us on 17 us off => around 33 % duty
79  * NO REPEAT: If value like temperature has changed during long press, the last value is send at button release.
80  * If you do a double press, the next value can be sent after around 118 ms. Tested with the fan button.
81 
82  * LG remote IR-LED measurements: Type AKB 75095308 for LG TV
83  * Protocol: NEC!!!
84  * Frequency 37.88 kHz
85  * Header: 9.0 ms mark 4.5 ms space
86  * Data: 560 / 560 and 560 / 1680;
87  * Clock is synchronized with gate, mark always starts with a full period
88  * Duty: 13 us on 13 us off => 50 % duty
89  * Repeat: 110 ms 9.0 ms mark, 2250 us space, 560 stop
90  * LSB first!
91  *
92  * The codes of the LG air conditioner are documented in https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/ac_LG.cpp
93  */
94 #define LG_ADDRESS_BITS 8
95 #define LG_COMMAND_BITS 16
96 #define LG_CHECKSUM_BITS 4
97 #define LG_BITS (LG_ADDRESS_BITS + LG_COMMAND_BITS + LG_CHECKSUM_BITS) // 28
98 
99 #define LG_UNIT 500 // 19 periods of 38 kHz
100 
101 #define LG_HEADER_MARK (18 * LG_UNIT) // 9000
102 #define LG_HEADER_SPACE 4200 // 4200 | 84
103 
104 #define LG2_HEADER_MARK (19 * LG_UNIT) // 9500
105 #define LG2_HEADER_SPACE (6 * LG_UNIT) // 3000
106 
107 #define LG_BIT_MARK LG_UNIT
108 #define LG_ONE_SPACE 1580 // 60 periods of 38 kHz
109 #define LG_ZERO_SPACE 550
110 
111 #define LG_REPEAT_HEADER_SPACE (4 * LG_UNIT) // 2250
112 #define LG_REPEAT_PERIOD 110000 // Commands are repeated every 110 ms (measured from start to start) for as long as the key on the remote control is held down.
113 //#define LG_AVERAGE_DURATION 58000 // LG_HEADER_MARK + LG_HEADER_SPACE + 32 * 2,5 * LG_UNIT) + LG_UNIT // 2.5 because we assume more zeros than ones
114 //#define LG_REPEAT_DURATION (LG_HEADER_MARK + LG_REPEAT_HEADER_SPACE + LG_BIT_MARK)
115 //#define LG_REPEAT_DISTANCE (LG_REPEAT_PERIOD - LG_AVERAGE_DURATION) // 52 ms
116 
120 
124 
125 /************************************
126  * Start of send and decode functions
127  ************************************/
128 /*
129  * Send special LG2 repeat not used yet
130  */
132  enableIROut (LG_KHZ); // 38 kHz
133  mark(LG2_HEADER_MARK); // + 3000
134  space(LG_REPEAT_HEADER_SPACE); // - 2250
135  mark(LG_BIT_MARK); // + 500
136 #if !defined(DISABLE_CODE_FOR_RECEIVER)
138 #endif
139 }
140 
146  IrSender.enableIROut(LG_KHZ); // 38 kHz
147  IrSender.mark(LG2_HEADER_MARK); // + 3000
149  IrSender.mark(LG_BIT_MARK); // + 500
150 #if !defined(DISABLE_CODE_FOR_RECEIVER)
152 #endif
153 }
154 
155 uint32_t IRsend::computeLGRawDataAndChecksum(uint8_t aAddress, uint16_t aCommand) {
156  uint32_t tRawData = ((uint32_t) aAddress << (LG_COMMAND_BITS + LG_CHECKSUM_BITS)) | ((uint32_t) aCommand << LG_CHECKSUM_BITS);
157  /*
158  * My guess of the 4 bit checksum
159  * Addition of all 4 nibbles of the 16 bit command
160  */
161  uint8_t tChecksum = 0;
162  uint16_t tTempForChecksum = aCommand;
163  for (int i = 0; i < 4; ++i) {
164  tChecksum += tTempForChecksum & 0xF; // add low nibble
165  tTempForChecksum >>= 4; // shift by a nibble
166  }
167  return (tRawData | (tChecksum & 0xF));
168 }
169 
173 void IRsend::sendLG(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
175 }
176 
180 void IRsend::sendLG2(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
182 }
183 
185  decode_type_t tProtocol = LG;
186  uint16_t tHeaderSpace = LG_HEADER_SPACE;
187 
188  /*
189  * First check for right data length
190  * Next check start bit
191  * Next try the decode
192  */
193 
194 // Check we have the right amount of data (60). The +4 is for initial gap, start bit mark and space + stop bit mark.
195  if (decodedIRData.rawDataPtr->rawlen != ((2 * LG_BITS) + 4) && (decodedIRData.rawDataPtr->rawlen != 4)) {
196  IR_DEBUG_PRINT(F("LG: "));
197  IR_DEBUG_PRINT(F("Data length="));
199  IR_DEBUG_PRINTLN(F(" is not 60 or 4"));
200  return false;
201  }
202 
203 // Check header "mark" this must be done for repeat and data
206 #if defined(LOCAL_DEBUG)
207  Serial.print(F("LG: "));
208  Serial.println(F("Header mark is wrong"));
209 #endif
210  return false;
211  } else {
212  tProtocol = LG2;
213  tHeaderSpace = LG2_HEADER_SPACE;
214  }
215  }
216 
217 // Check for repeat - here we have another header space length
218  if (decodedIRData.rawDataPtr->rawlen == 4) {
225  return true;
226  }
227 #if defined(LOCAL_DEBUG)
228  Serial.print(F("LG: "));
229  Serial.print(F("Repeat header space is wrong"));
230 #endif
231  return false;
232  }
233 
234 // Check command header space
235  if (!matchSpace(decodedIRData.rawDataPtr->rawbuf[2], tHeaderSpace)) {
236 #if defined(LOCAL_DEBUG)
237  Serial.print(F("LG: "));
238  Serial.println(F("Header space length is wrong"));
239 #endif
240  return false;
241  }
242 
244 #if defined(LOCAL_DEBUG)
245  Serial.print(F("LG: "));
246  Serial.println(F("Decode failed"));
247 #endif
248  return false;
249  }
250 
251 // Success
255 
256  /*
257  * My guess of the checksum
258  */
259  uint8_t tChecksum = 0;
260  uint16_t tTempForChecksum = decodedIRData.command;
261  for (int i = 0; i < 4; ++i) {
262  tChecksum += tTempForChecksum & 0xF; // add low nibble
263  tTempForChecksum >>= 4; // shift by a nibble
264  }
265 // Checksum check
266  if ((tChecksum & 0xF) != (decodedIRData.decodedRawData & 0xF)) {
267 #if defined(LOCAL_DEBUG)
268  Serial.print(F("LG: "));
269  Serial.print(F("4 bit checksum is not correct. expected=0x"));
270  Serial.print(tChecksum, HEX);
271  Serial.print(F(" received=0x"));
272  Serial.print((decodedIRData.decodedRawData & 0xF), HEX);
273  Serial.print(F(" data=0x"));
274  Serial.println(decodedIRData.command, HEX);
275 #endif
277  }
278 
279  decodedIRData.protocol = tProtocol; // LG or LG2
281 
282  return true;
283 }
284 
285 /*********************************************************************************
286  * Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
287  *********************************************************************************/
288 
294 void IRsend::sendLGRaw(uint32_t aRawData, int_fast8_t aNumberOfRepeats) {
296 }
297 
299  unsigned int offset = 1; // Skip first space
300 
301 // Check we have enough data (60) - +4 for initial gap, start bit mark and space + stop bit mark
302  if (aResults->rawlen != (2 * LG_BITS) + 4) {
303  return false;
304  }
305 
306 // Initial mark/space
307  if (!matchMark(aResults->rawbuf[offset], LG_HEADER_MARK)) {
308  return false;
309  }
310  offset++;
311 
312  if (!matchSpace(aResults->rawbuf[offset], LG_HEADER_SPACE)) {
313  return false;
314  }
315  offset++;
316 
318  return false;
319  }
320 // Stop bit
321  if (!matchMark(aResults->rawbuf[offset + (2 * LG_BITS)], LG_BIT_MARK)) {
322 #if defined(LOCAL_DEBUG)
323  Serial.println(F("Stop bit mark length is wrong"));
324 #endif
325  return false;
326  }
327 
328 // Success
329  aResults->value = decodedIRData.decodedRawData;
330  aResults->bits = LG_BITS;
331  aResults->decode_type = LG;
333  return true;
334 }
335 
336 //+=============================================================================
337 void IRsend::sendLG(unsigned long data, int nbits) {
338 // Set IR carrier frequency
340 #if !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__))
341  Serial.println(F(
342  "The function sendLG(data, nbits) is deprecated and may not work as expected! Use sendLGRaw(data, NumberOfRepeats) or better sendLG(Address, Command, NumberOfRepeats)."));
343 #endif
344 // Header
347 // mark(LG_BIT_MARK);
348 
349 // Data + stop bit
351  SEND_STOP_BIT);
352 #if !defined(DISABLE_CODE_FOR_RECEIVER)
354 #endif
355 }
356 
358 #if defined(LOCAL_DEBUG)
359 #undef LOCAL_DEBUG
360 #endif
361 #endif // _IR_LG_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:117
LG_REPEAT_HEADER_SPACE
#define LG_REPEAT_HEADER_SPACE
Definition: ir_LG.hpp:111
IRsend::sendLGRaw
void sendLGRaw(uint32_t aRawData, int_fast8_t aNumberOfRepeats=NO_REPEATS)
Here you can put your raw data, even one with "wrong" checksum.
Definition: ir_LG.hpp:294
decode_results
Results returned from old decoders !!!deprecated!!!
Definition: IRremoteInt.h:155
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:130
IRrecv::lastDecodedProtocol
decode_type_t lastDecodedProtocol
Definition: IRremoteInt.h:308
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:120
LG_REPEAT_PERIOD
#define LG_REPEAT_PERIOD
Definition: ir_LG.hpp:112
IRsend::aNumberOfRepeats
void uint8_t int_fast8_t aNumberOfRepeats
Definition: IRremoteInt.h:474
MICROS_IN_ONE_MILLI
#define MICROS_IN_ONE_MILLI
Definition: IRremote.hpp:263
IRsend::mark
void mark(unsigned int aMarkMicros)
Sends an IR mark for the specified number of microseconds.
Definition: IRSend.hpp:757
IRDATA_FLAGS_IS_REPEAT
#define IRDATA_FLAGS_IS_REPEAT
Definition: IRProtocol.h:94
decode_type_t
decode_type_t
An enum consisting of all supported formats.
Definition: IRProtocol.h:40
IRrecv::restartAfterSend
void restartAfterSend()
Restarts receiver after send.
Definition: IRReceive.hpp:346
IRsend::sendPulseDistanceWidth
void sendPulseDistanceWidth(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Sends PulseDistance frames and repeats.
Definition: IRSend.hpp:532
decode_results::rawbuf
unsigned int * rawbuf
Definition: IRremoteInt.h:166
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
decode_results::bits
uint8_t bits
Definition: IRremoteInt.h:161
decode_results::decode_type
decode_type_t decode_type
Definition: IRremoteInt.h:158
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
sendLG2SpecialRepeat
void sendLG2SpecialRepeat()
Static function for sending special repeat frame.
Definition: ir_LG.hpp:145
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
IRrecv::decodeLGMSB
bool decodeLGMSB(decode_results *aResults)
Definition: ir_LG.hpp:298
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
the current (autorepeat) frame violated parity check
Definition: IRProtocol.h:96
LG_CHECKSUM_BITS
#define LG_CHECKSUM_BITS
Definition: ir_LG.hpp:96
decode_results::value
uint32_t value
Definition: IRremoteInt.h:160
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:74
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:305
IRsend::sendLG2Repeat
void sendLG2Repeat()
Definition: ir_LG.hpp:131
matchSpace
bool matchSpace(unsigned int aMeasuredTicks, unsigned int aMatchValueMicros)
Compensate for spaces shortened by demodulator hardware.
Definition: IRReceive.hpp:1033
LG_COMMAND_BITS
#define LG_COMMAND_BITS
Definition: ir_LG.hpp:95
SEND_STOP_BIT
#define SEND_STOP_BIT
Definition: IRremoteInt.h:393
IRData::flags
uint8_t flags
See IRDATA_FLAGS_* definitions above.
Definition: IRProtocol.h:121
LG_ONE_SPACE
#define LG_ONE_SPACE
Definition: ir_LG.hpp:108
irparams_struct::rawbuf
unsigned int 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
IRsend::computeLGRawDataAndChecksum
uint32_t computeLGRawDataAndChecksum(uint8_t aAddress, uint16_t aCommand)
Definition: ir_LG.hpp:155
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:118
LG_BITS
#define LG_BITS
Definition: ir_LG.hpp:97
LG_KHZ
#define LG_KHZ
Definition: IRProtocol.h:142
LG2_HEADER_MARK
#define LG2_HEADER_MARK
Definition: ir_LG.hpp:104
IrSender
IRsend IrSender
Definition: IRSend.hpp:59
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:100
IRrecv::lastDecodedCommand
uint32_t lastDecodedCommand
Definition: IRremoteInt.h:310
IRsend::space
static void space(unsigned int aSpaceMicros)
Sends an IR space for the specified number of microseconds.
Definition: IRSend.hpp:927
LG2_HEADER_SPACE
#define LG2_HEADER_SPACE
Definition: ir_LG.hpp:105
LGProtocolConstants
struct PulseDistanceWidthProtocolConstants LGProtocolConstants
Definition: ir_LG.hpp:117
LG2
@ LG2
Definition: IRProtocol.h:48
LG_HEADER_MARK
#define LG_HEADER_MARK
Definition: ir_LG.hpp:101
LG_ZERO_SPACE
#define LG_ZERO_SPACE
Definition: ir_LG.hpp:109
LG2ProtocolConstants
struct PulseDistanceWidthProtocolConstants LG2ProtocolConstants
Definition: ir_LG.hpp:121
LG_HEADER_SPACE
#define LG_HEADER_SPACE
Definition: ir_LG.hpp:102
IRrecv::decodeLG
bool decodeLG()
Definition: ir_LG.hpp:184
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
IRrecv::lastDecodedAddress
uint32_t lastDecodedAddress
Definition: IRremoteInt.h:309
LG_BIT_MARK
#define LG_BIT_MARK
Definition: ir_LG.hpp:107
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:137
matchMark
bool matchMark(unsigned int aMeasuredTicks, unsigned int aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1000
decode_results::rawlen
uint_fast8_t rawlen
Definition: IRremoteInt.h:167
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:116
IRsend::sendLG
void sendLG(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
LG uses the NEC repeat.
Definition: ir_LG.hpp:173
IRsend::aCommand
void uint8_t aCommand
Definition: IRremoteInt.h:474
LG
@ LG
Definition: IRProtocol.h:47
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
IRsend::sendLG2
void sendLG2(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
LG2 uses a special repeat.
Definition: ir_LG.hpp:180
sendNECSpecialRepeat
void sendNECSpecialRepeat()
Static function for sending special repeat frame.
Definition: ir_NEC.hpp:134