IRremote
ir_RC5_RC6.hpp
Go to the documentation of this file.
1 /*
2  * ir_RC5_RC6.hpp
3  *
4  * Contains functions for receiving and sending RC5, RC5X, RC6 protocols
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-2026 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_RC5_RC6_HPP
33 #define _IR_RC5_RC6_HPP
34 
35 // This block must be located after the includes of other *.hpp files
36 //#define LOCAL_DEBUG // This enables debug output only for this file - only for development
37 //#define LOCAL_TRACE // This enables trace output only for this file - only for development
38 #include "LocalDebugLevelStart.h"
39 
43 uint8_t sLastSendToggleValue = 1; // To start first command with toggle 0. Only required for biphase protocols.
44 
45 //==============================================================================
46 // RRRR CCCC 55555
47 // R R C 5
48 // RRRR C 5555
49 // R R C 5
50 // R R CCCC 5555
51 //==============================================================================
52 /*
53  Protocol=RC5 Address=0x11, Command=0x36, Raw-Data=0x1476, 13 bits, MSB first
54  + 950,- 850
55  +1850,-1700 +1850,- 850 + 900,- 850 +1000,-1700
56  + 950,- 850 + 950,- 800 +1850,-1750 + 950,- 850
57  +1850
58  Duration=23300us
59 
60  RC5X with 7.th MSB of command set as 1
61  Protocol=RC5 Address=0x11, Command=0x76, Toggle=1, Raw-Data=0xC76, 13 bits, MSB first
62  +1900,-1700
63  + 950,- 850 +1850,- 800 + 950,- 800 +1000,-1700
64  +1000,- 750 + 950,- 900 +1800,-1700 +1000,- 800
65  +1850
66  Duration=23250us
67 
68  Protocol=Marantz Address=0x11, Command=0x76, Extra=0x9, Toggle=1, Raw-Data=0x31D89, 19 bits, MSB first
69  +1850,-1700
70  + 950,- 850 +1850,- 850 + 950,- 800 +1000,-1700
71  + 950,-4350 + 950,- 900 +1850,-1700 + 900,- 850
72  +1850,- 850 + 950,- 800 +1000,-1700 +1800,- 900
73  + 900,-1750 + 950
74  Duration=38400us
75  */
76 //
77 // see: https://www.sbprojects.net/knowledge/ir/rc5.php
78 // https://en.wikipedia.org/wiki/Manchester_code
79 // https://en.wikipedia.org/wiki/RC-5
80 // mark->space => 0
81 // space->mark => 1
82 // MSB first, 1 start bit, 1 field bit, 1 toggle bit + 5 bit address + 6 bit command, no stop bit 14 bits incl. field bit and start bit
83 // Field bit is 1 for RC5 and 0 (=inverted 7. command bit) for RC5X. That way the first 64 commands of RC5X are indistinguishable from RC5.
84 // SF TAAA AACC CCCC
85 // IR duty factor is 25%
86 //
87 // MARANTZ
88 // https://forum.arduino.cc/t/sending-rc-5-extended-code-using-irsender/1045841/10 - Protocol Maranz Extended
89 // Marantz uses RC5X and adds a a pause after the address / first 8 bits
90 // After the 6 bit command (of RC5) an additional 6 bit command extension is sent -> 20 bits incl. field bit and start bit
91 //
92 #define RC5_ADDRESS_BITS 5
93 #define RC5_COMMAND_BITS 6
94 #define RC5_COMMAND_FIELD_BIT 1
95 #define RC5_TOGGLE_BIT 1
96 
97 #define RC5_BITS (RC5_COMMAND_FIELD_BIT + RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS) // 13
98 
99 #define RC5_UNIT 889 // 32 periods of 36 kHz (888.8888)
100 
101 #define MIN_RC5_MARKS ((RC5_BITS + 1) / 2) // 7 - Divided by 2 to handle the bit sequence of 01010101 which gives one mark and space for each 2 bits
102 
103 #define RC5_DURATION (26 * RC5_UNIT) // 23114
104 #define RC5_REPEAT_PERIOD (128L * RC5_UNIT) // 113792
105 #define RC5_REPEAT_DISTANCE (RC5_REPEAT_PERIOD - RC5_DURATION) // 90 ms
106 #define RC5_MAXIMUM_REPEAT_DISTANCE (RC5_REPEAT_DISTANCE + (RC5_REPEAT_DISTANCE / 4)) // Just a guess
107 
108 #define MARANTZ_COMMAND_EXTENSION_BITS 6
109 #define MARANTZ_BITS (RC5_COMMAND_FIELD_BIT + RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS + MARANTZ_COMMAND_EXTENSION_BITS) // 19
110 #define MARANTZ_PAUSE_BIT_INDEX (RC5_COMMAND_FIELD_BIT + RC5_TOGGLE_BIT + RC5_ADDRESS_BITS) // 7
111 #define MARANTZ_PAUSE_DURATION (4 * RC5_UNIT) // 3556
112 
113 #define MARANTZ_DURATION (42L * RC5_UNIT) // RC5 + 6 Extension bits + 4 pause units = 37338
114 #define MARANTZ_REPEAT_DISTANCE (RC5_REPEAT_PERIOD - MARANTZ_DURATION) // 100 ms
115 
116 /************************************
117  * Start of send and decode functions
118  ************************************/
119 
130 void IRsend::sendRC5Marantz(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t aMarantzExtension,
131  bool aEnableAutomaticToggle) {
132 
133  // Set IR carrier frequency
135 
136  uint16_t tIRData = (aAddress & 0x1F);
137 
138  /*
139  * Process field bit (the bit after start bit)
140  * Field bit is 1 for RC5 and 0 (inverted 7. command bit) for RC5X
141  */
142  if (aCommand >= 0x40) { // Auto discovery of RC5X
143  // Mask bit 7 of command to set field bit to 0 (inverted 1) for RC5X
144  aCommand &= 0x3F;
145  } else {
146  // Set field bit to 1 for RC5
147  tIRData |= 1 << (RC5_TOGGLE_BIT + RC5_ADDRESS_BITS); // 1 << 6 = 0x40
148  }
149 
150  // Combine command and command extension for the 2nd part of data to be sent after the pause
151  uint16_t tIRExtData = (aCommand << MARANTZ_COMMAND_EXTENSION_BITS);
152  // Set the Marantz command extension bits
153  tIRExtData |= (aMarantzExtension & 0x3F);
154 
155  if (aEnableAutomaticToggle) {
156  if (sLastSendToggleValue == 0) {
158  // set toggled bit
159  tIRData |= 1 << (RC5_ADDRESS_BITS);
160  } else {
162  }
163  }
164 
165  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
166  while (tNumberOfCommands > 0) {
167 
168  // start bit is sent by sendBiphaseData followed by the field bit and toggle bit and address
170  // pause before the bits of command and command extension to indicate that it's Marantz-RC5x
171  space(MARANTZ_PAUSE_DURATION); // Marantz-RC5x has a pause before the bits of command and command extension
172  // send command and command extension
174 
175  tNumberOfCommands--;
176  // skip last delay!
177  if (tNumberOfCommands > 0) {
178  // send repeated command in a fixed raster
180  }
181  }
182 }
183 
189 void IRsend::sendRC5(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle) {
190 
191  // Set IR carrier frequency
193 
194  uint16_t tIRData = ((aAddress & 0x1F) << (RC5_COMMAND_BITS)); // << 6
195 
196  /*
197  * Process field bit (the bit after start bit)
198  * Field bit is 1 for RC5 and 0 (inverted 7. command bit) for RC5X
199  */
200  if (aCommand >= 0x40) { // Auto discovery of RC5X
201  // Mask bit 7 of command to set field bit to 0 (inverted 1) for RC5X
202  aCommand &= 0x3F;
203  } else {
204  // Set field bit to 1 for RC5
205  tIRData |= 1 << (RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS); // 1 << 12 = 0x1000
206  }
207  tIRData |= aCommand;
208 
209  if (aEnableAutomaticToggle) {
210  if (sLastSendToggleValue == 0) {
212  // set toggled bit
213  tIRData |= 1 << (RC5_ADDRESS_BITS + RC5_COMMAND_BITS);
214  } else {
216  }
217  }
218 
219  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
220  while (tNumberOfCommands > 0) {
221 
222  // start bit is sent by sendBiphaseData
223  sendBiphaseData(RC5_UNIT, tIRData, RC5_BITS);
224 
225  tNumberOfCommands--;
226  // skip last delay!
227  if (tNumberOfCommands > 0) {
228  // send repeated command in a fixed raster
230  }
231  }
232 }
233 
234 #if defined(DECODE_RC5) || defined(DECODE_MARANTZ) || defined(DECODE_RC6)
235 void IRrecv::initBiphaselevel(uint_fast8_t aRCDecodeRawbuffOffset, uint16_t aBiphaseTimeUnit) {
236  irparams.RawbuffOffsetForNextBiphaseLevel = aRCDecodeRawbuffOffset;
237  irparams.BiphaseTimeUnit = aBiphaseTimeUnit;
238  irparams.AlreadyUsedTimingIntervalsOfCurrentInterval = 0;
239 }
240 
241 /*
242  * Margin is 1/2 of unit.
243  */
244 uint8_t IRrecv::getNumberOfUnitsInInterval(uint16_t aCurrentInterval, uint16_t aTimeUnit) {
245  return (aCurrentInterval + (aTimeUnit / 2)) / aTimeUnit;
246 }
247 
265 uint_fast8_t IRrecv::getBiphaselevel() {
266  uint_fast8_t tLevelOfCurrentInterval; // Return value: 0 (SPACE) or 1 (MARK)
267 
268  if (irparams.RawbuffOffsetForNextBiphaseLevel >= decodedIRData.rawlen) {
269  return SPACE; // After end of recorded buffer, assume space.
270  }
271 
272  tLevelOfCurrentInterval = (irparams.RawbuffOffsetForNextBiphaseLevel) & 1; // on odd rawbuf offsets we have mark timings
273 
274  /*
275  * Refill NumberOfTimingIntervalsInCurrentInterval if AlreadyUsedTimingIntervalsOfCurrentInterval is 0
276  * i.e. we went to next rawbuf interval
277  */
278  if (irparams.AlreadyUsedTimingIntervalsOfCurrentInterval == 0) {
279  uint16_t tCurrentIntervalWithMicros = irparams.rawbuf[irparams.RawbuffOffsetForNextBiphaseLevel] * MICROS_PER_TICK;
280  uint16_t tMarkExcessCorrectionMicros = (tLevelOfCurrentInterval == MARK) ? MARK_EXCESS_MICROS : -MARK_EXCESS_MICROS;
281  irparams.NumberOfTimingIntervalsInCurrentInterval = getNumberOfUnitsInInterval(
282  tCurrentIntervalWithMicros + tMarkExcessCorrectionMicros, irparams.BiphaseTimeUnit);
283  // 666 is 3/4 of RC5 time unit
284  TRACE_PRINT(tLevelOfCurrentInterval);
285  TRACE_PRINT(F("="));
286  TRACE_PRINT(tCurrentIntervalWithMicros + tMarkExcessCorrectionMicros);
287  TRACE_PRINT(F(" "));
288  TRACE_PRINTLN(irparams.NumberOfTimingIntervalsInCurrentInterval);
289  }
290  if (irparams.NumberOfTimingIntervalsInCurrentInterval == 0) {
291  return NO_MARK_OR_SPACE;
292  }
293 
294 // We use another interval from tCurrentTimingIntervals
295  irparams.AlreadyUsedTimingIntervalsOfCurrentInterval++;
296 
297  if (irparams.AlreadyUsedTimingIntervalsOfCurrentInterval >= irparams.NumberOfTimingIntervalsInCurrentInterval) {
298  /*
299  * We have used all intervals of current interval (mark or space duration in rawbuf), go to next rawbuf interval
300  */
301  irparams.AlreadyUsedTimingIntervalsOfCurrentInterval = 0;
302  irparams.RawbuffOffsetForNextBiphaseLevel++;
303  }
304 
305 
306  return tLevelOfCurrentInterval;
307 }
308 # endif // defined(DECODE_RC5) || defined(DECODE_MARANTZ) || defined(DECODE_RC6)
309 
310 #if defined(DECODE_RC5) || defined(DECODE_MARANTZ)
311 
326 bool IRrecv::decodeRC5() {
327  uint8_t tBitIndex;
328  uint32_t tDecodedRawData = 0;
329 
330  // Set Biphase decoding start values
331  initBiphaselevel(1, RC5_UNIT); // Skip gap space
332 
333  // Check we have the right amount of data (11 to 26). The +2 is for initial gap and start bit mark.
334  if (decodedIRData.rawlen < ((RC5_BITS + 1) / 2) + 2 && (RC5_BITS + 2) < decodedIRData.rawlen) {
335  // no debug output, since this check is mainly to determine the received protocol
336  DEBUG_PRINT(F("RC5: Data length="));
338  DEBUG_PRINTLN(F(" is not between 9 and 15"));
339  return false;
340  }
341 
342  // Check length of first mark / header
343  if (irparams.rawbuf[1] > (((2 * RC5_UNIT) + (RC5_UNIT / 2)) / MICROS_PER_TICK)) {
344  DEBUG_PRINTLN(F("RC5: first MARK is too long"));
345  return false;
346  }
347 
348  // Check start bit, the first space is included in the gap
349  if (getBiphaselevel() != MARK) {
350  DEBUG_PRINTLN(F("RC5: first getBiphaselevel() is not MARK"));
351  return false;
352  }
353 
354  /*
355  * Get data bits - MSB first
356  */
357 #if defined(DECODE_MARANTZ)
358  bool RC5Marantz = false;
359 #endif
360  for (tBitIndex = 0; irparams.RawbuffOffsetForNextBiphaseLevel < decodedIRData.rawlen; tBitIndex++) {
361  // get next 2 levels and check for transition
362  uint8_t tStartLevel = getBiphaselevel();
363  uint8_t tEndLevel = getBiphaselevel();
364 
365  if ((tStartLevel == SPACE) && (tEndLevel == MARK)) {
366  // we have a space to mark transition here
367  tDecodedRawData = (tDecodedRawData << 1) | 1;
368  } else if ((tStartLevel == MARK) && (tEndLevel == SPACE)) {
369  // we have a mark to space transition here
370  tDecodedRawData = (tDecodedRawData << 1) | 0;
371 #if defined(DECODE_MARANTZ)
372  } else if (tBitIndex == MARANTZ_PAUSE_BIT_INDEX) {
373  /*
374  * Check for RC5 Marantz format i.e. long space after 8 bits (including start bit)
375  * Check if timing buffer contains a pause, which is longer than 3/4 the expected pause
376  * Some dumb compiler throw a warning: comparison is always false due to limited range of data type [-Wtype-limits] which is nonsense
377  */
378  if (irparams.rawbuf[irparams.RawbuffOffsetForNextBiphaseLevel] > ((MARANTZ_PAUSE_DURATION * 3L) / (MICROS_PER_TICK * 4L))) { // 3556 * 3 / 200 = 53
379  RC5Marantz = true;
380  DEBUG_PRINTLN(F("Marantz detected"));
381  /*
382  * Here we are at the space interval and have 4 cases:
383  * With 0 -> mark+space and 1 -> space+mark and pause = 4*space we get the following space length
384  * 0 | pause | 0 -> 5*space
385  * 0 | pause | 1 -> 6*space
386  * 1 | pause | 0 -> 4*space
387  * 1 | pause | 1 -> 5*space
388  */
389  irparams.AlreadyUsedTimingIntervalsOfCurrentInterval += 2; // We already consumed 2 to get here
390  if (irparams.AlreadyUsedTimingIntervalsOfCurrentInterval >= irparams.NumberOfTimingIntervalsInCurrentInterval){
391  irparams.RawbuffOffsetForNextBiphaseLevel++;
392  }
393  }
394 #endif
395  } else {
396  DEBUG_PRINT(F("RC5: no transition found, decode failed, BitIndex="));
397  DEBUG_PRINTLN(tBitIndex);
398  return false;
399  }
400  }
401 
402  // Success
403 
404  LongUnion tValue;
405  tValue.ULong = tDecodedRawData;
406  decodedIRData.decodedRawData = tDecodedRawData;
407 
408 #if defined(DECODE_MARANTZ)
409  if (RC5Marantz) {
410  decodedIRData.numberOfBits = tBitIndex - 1; // Above we count space handling as bit
411 
412  decodedIRData.extra = tValue.UWord.LowWord & 0x3F;
415 
416  // Get the inverted 7. command bit to decide if we have RC5X. For RC5, the inverted value is always 1 and serves as a second start bit.
418  // Here we have detected RC5X!
419  decodedIRData.command += 0x40;
420  }
421 
425  }
427  } else {
428 #endif
429  decodedIRData.numberOfBits = tBitIndex; // must be RC5_BITS
430 
431  decodedIRData.command = tValue.UByte.LowByte & 0x3F;
432  decodedIRData.address = (tValue.UWord.LowWord >> RC5_COMMAND_BITS) & 0x1F;
433 
434  // Get the inverted 7. command bit to decide if we have RC5X. For RC5, the inverted value is always 1 and serves as a second start bit.
435  if ((tValue.UWord.LowWord & (1 << (RC5_TOGGLE_BIT + RC5_ADDRESS_BITS + RC5_COMMAND_BITS))) == 0) {
436  // Here we have detected RC5X!
437  decodedIRData.command += 0x40;
438  }
439 
441  if (tValue.UByte.MidLowByte & 0x8) {
443  }
445 
446 #if defined(DECODE_MARANTZ)
447  }
448 #endif
449  // check for repeat
451 
452  return true;
453 }
454 #endif // defined(DECODE_RC5) || defined(DECODE_MARANTZ)
455 
456 //+=============================================================================
457 // RRRR CCCC 6666
458 // R R C 6
459 // RRRR C 6666
460 // R R C 6 6
461 // R R CCCC 666
462 //+=============================================================================
463 //
464 /*
465  Protocol=RC6 Address=0xF1, Command=0x76, Raw-Data=0xF176, 20 bits, MSB first
466  +2700,- 850
467  + 550,- 800 + 550,- 350 + 550,- 350 + 550,- 800
468  +1400,- 400 + 550,- 400 + 550,- 350 + 550,- 800
469  + 550,- 350 + 500,- 450 +1000,- 750 +1000,- 450
470  + 500,- 400 + 500,- 850 + 950,- 450 + 550,- 750
471  + 550
472  Duration=23600us
473 
474  Protocol=RC6A Address=0xF1, Command=0x76, Extra=0x2711, Toggle=1, Raw-Data=0xA711F176, 35 bits, MSB first
475  +2700,- 850
476  + 500,- 400 + 500,- 400 + 500,- 850 +1450,-1300
477  +1000,- 850 + 550,- 350 +1000,- 400 + 550,- 350
478  + 500,- 850 + 500,- 450 + 500,- 400 + 950,- 900
479  + 500,- 400 + 550,- 350 +1000,- 400 + 500,- 400
480  + 550,- 400 + 500,- 400 + 500,- 850 + 550,- 350
481  + 550,- 400 +1000,- 800 +1000,- 400 + 500,- 400
482  + 500,- 900 +1000,- 350 + 550,- 850 + 500
483  Duration=37450us
484  */
485 // Frame RC6: 1 start bit + 1 Bit "1" + 3 mode bits (000) + 1 toggle bit + 8 address + 8 command bits + 2666us pause - 22 bits incl. start bit and constant bit 1
486 // Frame RC6A: 1 start bit + 1 Bit "1" + 3 mode bits (110) + 1 toggle bit + "1" + 14 customer bits + 8 system bits + 8 command bits + 2666us pause - 37 bits incl. start bit
487 // !!! toggle bit has double timing !!!
488 // mark->space => 1 - Inverse of RC5!
489 // space->mark => 0
490 // https://www.sbprojects.net/knowledge/ir/rc6.php
491 // https://www.mikrocontroller.net/articles/IRMP_-_english#RC6_.2B_RC6A
492 // https://en.wikipedia.org/wiki/Manchester_code
493 #define MIN_RC6_SAMPLES 1
494 
495 #define RC6_RPT_LENGTH 46000
496 
497 #define RC6_LEADING_BIT 1
498 #define RC6_MODE_BITS 3 // never seen others than all 0 for Philips TV
499 #define RC6_TOGGLE_BIT 1 // toggles at every key press. Can be used to distinguish repeats from 2 key presses and has another timing :-(.
500 #define RC6_TOGGLE_BIT_INDEX RC6_MODE_BITS // fourth position, index = 3
501 #define RC6_ADDRESS_BITS 8
502 #define RC6_COMMAND_BITS 8
503 #define RC6_CUSTOMER_BITS 14
504 
505 #define RC6_BITS (RC6_LEADING_BIT + RC6_MODE_BITS + RC6_TOGGLE_BIT + RC6_ADDRESS_BITS + RC6_COMMAND_BITS) // 21
506 #define RC6A_BITS (RC6_LEADING_BIT + RC6_MODE_BITS + RC6_TOGGLE_BIT + 1 + RC6_CUSTOMER_BITS + RC6_ADDRESS_BITS + RC6_COMMAND_BITS) // 36
507 
508 #define RC6_UNIT 444 // 16 periods of 36 kHz (444.4444)
509 
510 #define RC6_HEADER_MARK (6 * RC6_UNIT) // 2666
511 #define RC6_HEADER_SPACE (2 * RC6_UNIT) // 889
512 
513 #define RC6_TRAILING_SPACE (6 * RC6_UNIT) // 2666
514 #define MIN_RC6_MARKS 4 + ((RC6_ADDRESS_BITS + RC6_COMMAND_BITS) / 2) // 12, 4 are for preamble
515 
516 #define RC6_REPEAT_DISTANCE 107000 // just a guess but > 2.666ms
517 #define RC6_MAXIMUM_REPEAT_DISTANCE (RC6_REPEAT_DISTANCE + (RC6_REPEAT_DISTANCE / 4)) // Just a guess
518 
522 void IRsend::sendRC6(uint32_t aRawData, uint8_t aNumberOfBitsToSend) { // Deprecated
523  sendRC6Raw(aRawData, aNumberOfBitsToSend);
524 }
525 void IRsend::sendRC6Raw(uint32_t aRawData, uint8_t aNumberOfBitsToSend) {
526 // Set IR carrier frequency
528 
529 // Header
532 
533 // Start bit
534  mark(RC6_UNIT);
535  space(RC6_UNIT);
536 
537 // Data MSB first
538  uint32_t mask = 1UL << (aNumberOfBitsToSend - 1);
539  for (uint_fast8_t i = 1; mask; i++, mask >>= 1) {
540  // The fourth bit we send is the "double width toggle bit"
541  unsigned int t = (i == (RC6_TOGGLE_BIT_INDEX + 1)) ? (RC6_UNIT * 2) : (RC6_UNIT);
542  if (aRawData & mask) {
543  mark(t);
544  space(t);
545  } else {
546  space(t);
547  mark(t);
548  }
549  }
550 }
551 
556 void IRsend::sendRC6(uint64_t aRawData, uint8_t aNumberOfBitsToSend) { // Deprecated
557  sendRC6Raw(aRawData, aNumberOfBitsToSend);
558 }
559 void IRsend::sendRC6Raw(uint64_t aRawData, uint8_t aNumberOfBitsToSend) {
560 // Set IR carrier frequency
562 
563 // Header
566 
567 // Start bit
568  mark(RC6_UNIT);
569  space(RC6_UNIT);
570 
571 // Data MSB first
572  uint64_t mask = 1ULL << (aNumberOfBitsToSend - 1);
573  for (uint_fast8_t i = 1; mask; i++, mask >>= 1) {
574  // The fourth bit we send is the "double width toggle bit"
575  unsigned int t = (i == (RC6_TOGGLE_BIT_INDEX + 1)) ? (RC6_UNIT * 2) : (RC6_UNIT);
576  if (aRawData & mask) {
577  mark(t);
578  space(t);
579  } else {
580  space(t);
581  mark(t);
582  }
583  }
584 }
585 
591 void IRsend::sendRC6(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle) {
592 
593  LongUnion tIRRawData;
594  tIRRawData.UByte.LowByte = aCommand;
595  tIRRawData.UByte.MidLowByte = aAddress;
596 
597  tIRRawData.UWord.HighWord = 0; // must clear high word for the 3 mode bits to be 0
598  if (aEnableAutomaticToggle) {
599  if (sLastSendToggleValue == 0) {
601  // set toggle bit
602  tIRRawData.UByte.MidHighByte = 1; // 3 Mode bits are 0
603  } else {
605  }
606  }
607 
608  DEBUG_PRINT(F("RC6: ToggleValue="));
610  DEBUG_PRINT(F(" RawData="));
611  DEBUG_PRINTLN(tIRRawData.ULong, HEX);
612 
613  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
614  while (tNumberOfCommands > 0) {
615 
616  // start and leading bits are sent by sendRC6
617  sendRC6Raw(tIRRawData.ULong, RC6_BITS - 1); // -1 since the leading bit is additionally sent by sendRC6
618 
619  tNumberOfCommands--;
620  // skip last delay!
621  if (tNumberOfCommands > 0) {
622  // send repeated command in a fixed raster
624  }
625  }
626 }
627 
633 void IRsend::sendRC6A(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint16_t aCustomer,
634  bool aEnableAutomaticToggle) {
635 
636  LongUnion tIRRawData;
637  tIRRawData.UByte.LowByte = aCommand;
638  tIRRawData.UByte.MidLowByte = aAddress;
639 
640  tIRRawData.UWord.HighWord = aCustomer | 0x400; // bit 31 is always 1
641 
642  if (aEnableAutomaticToggle) {
643  if (sLastSendToggleValue == 0) {
645  // set toggled bit
646  tIRRawData.UByte.HighByte |= 0x80; // toggle bit is bit 32
647  } else {
649  }
650  }
651 
652  // Set mode bits
653  uint64_t tRawData = tIRRawData.ULong + 0x0600000000;
654 
655  DEBUG_PRINT(F("RC6A: ToggleValue="));
657  DEBUG_PRINT(F(" RawData="));
658  DEBUG_PRINTLN(tIRRawData.ULong, HEX);
659 
660  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
661  while (tNumberOfCommands > 0) {
662 
663  // start and leading bits are sent by sendRC6
664  sendRC6Raw(tRawData, RC6A_BITS - 1); // -1 since the leading bit is additionally sent by sendRC6
665 
666  tNumberOfCommands--;
667  // skip last delay!
668  if (tNumberOfCommands > 0) {
669  // send repeated command in a fixed raster
671  }
672  }
673 }
674 
675 #if defined(DECODE_RC6)
676 
692 bool IRrecv::decodeRC6() {
693  uint8_t tBitIndex;
694  uint32_t tDecodedRawData = 0;
695 
696  // Check we have the right amount of data (). The +3 for initial gap, start bit mark and space
698  DEBUG_PRINT(F("RC6: Data length="));
700  DEBUG_PRINTLN(F(" is not between 15 and 25"));
701  return false;
702  }
703 
704  // Check header "mark" and "space", this must be done for repeat and data
706  // no debug output, since this check is mainly to determine the received protocol
707  DEBUG_PRINTLN(F("RC6: Header mark or space length is wrong"));
708  return false;
709  }
710 
711  // Set Biphase decoding start values
712  initBiphaselevel(3, RC6_UNIT); // Skip gap-space and start-bit mark + space
713 
714  // Check first bit, which is known to be a 1 (mark->space)
715  if (getBiphaselevel() != MARK) {
716  DEBUG_PRINTLN(F("RC6: first getBiphaselevel() is not MARK"));
717  return false;
718  }
719  // Check second bit
720  if (getBiphaselevel() != SPACE) {
721  DEBUG_PRINTLN(F("RC6: second getBiphaselevel() is not SPACE"));
722  return false;
723  }
724 
725  for (tBitIndex = 0; irparams.RawbuffOffsetForNextBiphaseLevel < decodedIRData.rawlen; tBitIndex++) {
726  uint8_t tStartLevel; // start level of coded bit
727  uint8_t tEndLevel; // end level of coded bit
728 
729  tStartLevel = getBiphaselevel();
730  tEndLevel = getBiphaselevel();
731 
732  if (tBitIndex == RC6_TOGGLE_BIT_INDEX) {
733  /*
734  * Toggle bit is double wide; level of 1. and 2. time slot and 3. and 4.time slot must be equal
735  */
736  if (tStartLevel != tEndLevel) { // 1. and 2. time slot must be equal
737  DEBUG_PRINTLN(F("RC6: Toggle mark or space length is wrong"));
738  return false;
739  }
740  tEndLevel = getBiphaselevel();
741  if (tEndLevel != getBiphaselevel()) { // 3. and 4. time slot must be equal
742  DEBUG_PRINTLN(F("RC6: Toggle mark or space length is wrong"));
743  return false;
744  }
745  }
746 
747  /*
748  * Determine tDecodedRawData bit value by checking the transition type
749  */
750  if ((tStartLevel == MARK) && (tEndLevel == SPACE)) {
751  // we have a mark to space transition here
752  tDecodedRawData = (tDecodedRawData << 1) | 1; // inverted compared to RC5
753  } else if ((tStartLevel == SPACE) && (tEndLevel == MARK)) {
754  // we have a space to mark transition here
755  tDecodedRawData = (tDecodedRawData << 1) | 0;
756  } else {
757  DEBUG_PRINTLN(F("RC6: Decode failed"));
758  // we have no transition here or one level is -1 -> error
759  return false; // Error
760  }
761  }
762 
763 // Success
764  decodedIRData.numberOfBits = tBitIndex;
765 
766  LongUnion tValue;
767  tValue.ULong = tDecodedRawData;
768  decodedIRData.decodedRawData = tDecodedRawData;
769 
770  if (tBitIndex < 35) {
771  // RC6 8 address bits, 8 command bits
775  // Check for toggle flag
776  if ((tValue.UByte.MidHighByte & 1) != 0) {
778  }
779  if (tBitIndex > 20) {
781  }
783 
784  } else {
785  // RC6A
789  decodedIRData.extra = tValue.UWord.HighWord & 0x3FFF; // Mask to 14 bits, remove toggle and constant 1
790  if ((tValue.UByte.HighByte & 0x80) != 0) {
792  }
794  }
795 
796  // check for repeat, do not check toggle bit yet
798 
799  return true;
800 }
801 #endif // #if defined(DECODE_RC6)
802 
803 /*********************************************************************************
804  * Old deprecated functions, kept for backward compatibility to old 2.0 tutorials
805  *********************************************************************************/
806 
810 void IRsend::sendRC5(uint32_t data, uint8_t nbits) {
811  // Set IR carrier frequency
813 
814  // Start
815  mark(RC5_UNIT);
816  space(RC5_UNIT);
817  mark(RC5_UNIT);
818 
819  // Data - Biphase code MSB first
820  for (uint32_t mask = 1UL << (nbits - 1); mask; mask >>= 1) {
821  if (data & mask) {
822  space(RC5_UNIT); // 1 is space, then mark
823  mark(RC5_UNIT);
824  } else {
825  mark(RC5_UNIT);
826  space(RC5_UNIT);
827  }
828  }
829 }
830 
831 /*
832  * Deprecated, use sendRC5(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle) instead
833  */
834 void IRsend::sendRC5ext(uint8_t addr, uint8_t cmd, bool toggle) {
835 // Set IR carrier frequency
837 
838  uint8_t addressBits = 5;
839  uint8_t commandBits = 7;
840 // unsigned long nbits = addressBits + commandBits;
841 
842 // Start
843  mark(RC5_UNIT);
844 
845 // Bit #6 of the command part, but inverted!
846  uint8_t cmdBit6 = (1UL << (commandBits - 1)) & cmd;
847  if (cmdBit6) {
848  // Inverted (1 -> 0 = mark-to-space)
849  mark(RC5_UNIT);
850  space(RC5_UNIT);
851  } else {
852  space(RC5_UNIT);
853  mark(RC5_UNIT);
854  }
855  commandBits--;
856 
857 // Toggle bit
858  static int toggleBit = 1;
859  if (toggle) {
860  if (toggleBit == 0) {
861  toggleBit = 1;
862  } else {
863  toggleBit = 0;
864  }
865  }
866  if (toggleBit) {
867  space(RC5_UNIT);
868  mark(RC5_UNIT);
869  } else {
870  mark(RC5_UNIT);
871  space(RC5_UNIT);
872  }
873 
874 // Address
875  for (uint_fast8_t mask = 1UL << (addressBits - 1); mask; mask >>= 1) {
876  if (addr & mask) {
877  space(RC5_UNIT); // 1 is space, then mark
878  mark(RC5_UNIT);
879  } else {
880  mark(RC5_UNIT);
881  space(RC5_UNIT);
882  }
883  }
884 
885 // Command
886  for (uint_fast8_t mask = 1UL << (commandBits - 1); mask; mask >>= 1) {
887  if (cmd & mask) {
888  space(RC5_UNIT); // 1 is space, then mark
889  mark(RC5_UNIT);
890  } else {
891  mark(RC5_UNIT);
892  space(RC5_UNIT);
893  }
894  }
895 }
896 
898 #include "LocalDebugLevelEnd.h"
899 
900 #endif // _IR_RC5_RC6_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRremoteInt.h:164
MARANTZ_PAUSE_BIT_INDEX
#define MARANTZ_PAUSE_BIT_INDEX
Definition: ir_RC5_RC6.hpp:110
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:133
LongUnion
Union to specify parts / manifestations of a 32 bit Long without casts and shifts.
Definition: LongUnion.h:59
RC5_RC6_KHZ
#define RC5_RC6_KHZ
Definition: IRProtocol.h:175
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRremoteInt.h:173
DEBUG_PRINT
#define DEBUG_PRINT(...)
Definition: LocalDebugLevelStart.h:79
IRsend::aNumberOfRepeats
void int_fast8_t aNumberOfRepeats
Definition: IRremoteInt.h:528
MICROS_IN_ONE_MILLI
#define MICROS_IN_ONE_MILLI
Definition: IRremote.hpp:217
MARK_EXCESS_MICROS
#define MARK_EXCESS_MICROS
MARK_EXCESS_MICROS is subtracted from all marks and added to all spaces before decoding,...
Definition: IRremote.hpp:111
LongUnion::UByte
struct LongUnion::@4 UByte
TRACE_PRINTLN
#define TRACE_PRINTLN(...)
Definition: LocalDebugLevelStart.h:70
TRACE_PRINT
#define TRACE_PRINT(...)
Definition: LocalDebugLevelStart.h:69
IRsend::sendRC6Raw
void sendRC6Raw(uint32_t data, uint8_t nbits)
Definition: ir_RC5_RC6.hpp:525
IRsend::mark
void mark(uint16_t aMarkMicros)
Sends an IR mark for the specified number of microseconds.
Definition: IRSend.hpp:1247
IRsend::sendRC6
void sendRC6(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
Assemble raw data for RC6 from parameters and toggle state and send We do not wait for the minimal tr...
Definition: ir_RC5_RC6.hpp:591
sLastSendToggleValue
uint8_t sLastSendToggleValue
Definition: ir_RC5_RC6.hpp:43
RC5_UNIT
#define RC5_UNIT
Definition: ir_RC5_RC6.hpp:99
LongUnion::LowByte
uint8_t LowByte
Definition: LongUnion.h:61
RC6_BITS
#define RC6_BITS
Definition: ir_RC5_RC6.hpp:505
LongUnion::HighByte
uint8_t HighByte
Definition: LongUnion.h:64
RC5_REPEAT_DISTANCE
#define RC5_REPEAT_DISTANCE
Definition: ir_RC5_RC6.hpp:105
IRrecv::checkForRepeatSpaceTicksAndSetFlag
void checkForRepeatSpaceTicksAndSetFlag(uint16_t aMaximumRepeatSpaceTicks)
Definition: IRReceive.hpp:1248
LongUnion::LowWord
uint16_t LowWord
Definition: LongUnion.h:80
matchSpace
bool matchSpace(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for spaces shortened by demodulator hardware.
Definition: IRReceive.hpp:1375
RC5_ADDRESS_BITS
#define RC5_ADDRESS_BITS
Definition: ir_RC5_RC6.hpp:92
RC6_HEADER_SPACE
#define RC6_HEADER_SPACE
Definition: ir_RC5_RC6.hpp:511
LocalDebugLevelStart.h
LongUnion::MidLowByte
uint8_t MidLowByte
Definition: LongUnion.h:62
MIN_RC6_MARKS
#define MIN_RC6_MARKS
Definition: ir_RC5_RC6.hpp:514
LongUnion::HighWord
uint16_t HighWord
Definition: LongUnion.h:81
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:401
IRDATA_FLAGS_EXTRA_INFO
#define IRDATA_FLAGS_EXTRA_INFO
There is extra info not contained in address and data (e.g. Kaseikyo unknown vendor ID,...
Definition: IRProtocol.h:130
MARANTZ_REPEAT_DISTANCE
#define MARANTZ_REPEAT_DISTANCE
Definition: ir_RC5_RC6.hpp:114
IRsend::sendRC5ext
void sendRC5ext(uint8_t addr, uint8_t cmd, bool toggle) __attribute__((deprecated("Please use sendRC5(uint8_t aAddress
Definition: ir_RC5_RC6.hpp:834
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRremoteInt.h:174
NO_MARK_OR_SPACE
#define NO_MARK_OR_SPACE
Definition: IRremoteInt.h:40
RC5_COMMAND_BITS
#define RC5_COMMAND_BITS
Definition: ir_RC5_RC6.hpp:93
RC6_HEADER_MARK
#define RC6_HEADER_MARK
Definition: ir_RC5_RC6.hpp:510
RC5_BITS
#define RC5_BITS
Definition: ir_RC5_RC6.hpp:97
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRremoteInt.h:165
IRData::decodedRawData
IRDecodedRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send<protocol>Raw functions.
Definition: IRremoteInt.h:167
IRsend::sendRC5Marantz
void sendRC5Marantz(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t aMarantzExtension, bool aEnableAutomaticToggle=true)
!!! Not tested, because no Marantz remote was at hand and no receive function was contributed!...
Definition: ir_RC5_RC6.hpp:130
RC6_MAXIMUM_REPEAT_DISTANCE
#define RC6_MAXIMUM_REPEAT_DISTANCE
Definition: ir_RC5_RC6.hpp:517
IRsend::sendBiphaseData
void sendBiphaseData(uint16_t aBiphaseTimeUnit, uint32_t aData, uint_fast8_t aNumberOfBits, bool aSendStartBit=true)
Sends Biphase (Manchester) coded data MSB first This function concatenates two marks to one longer ma...
Definition: IRSend.hpp:1178
MARANTZ
@ MARANTZ
Definition: IRProtocol.h:103
matchMark
bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1327
RC5_COMMAND_FIELD_BIT
#define RC5_COMMAND_FIELD_BIT
Definition: ir_RC5_RC6.hpp:94
RC5_TOGGLE_BIT
#define RC5_TOGGLE_BIT
Definition: ir_RC5_RC6.hpp:95
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:147
LongUnion::ULong
uint32_t ULong
Definition: LongUnion.h:95
IRrecv::irparams
irparams_struct irparams
Definition: IRremoteInt.h:400
DEBUG_PRINTLN
#define DEBUG_PRINTLN(...)
Definition: LocalDebugLevelStart.h:80
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:133
RC6A
@ RC6A
Definition: IRProtocol.h:99
RC6_REPEAT_DISTANCE
#define RC6_REPEAT_DISTANCE
Definition: ir_RC5_RC6.hpp:516
MARANTZ_COMMAND_EXTENSION_BITS
#define MARANTZ_COMMAND_EXTENSION_BITS
Definition: ir_RC5_RC6.hpp:108
IRDATA_FLAGS_TOGGLE_BIT
#define IRDATA_FLAGS_TOGGLE_BIT
Is set if RC5 or RC6 toggle bit is set.
Definition: IRProtocol.h:128
RC5
@ RC5
Definition: IRProtocol.h:99
IRData::extra
uint16_t extra
Contains upper 16 bit of Magiquest WandID, Kaseikyo unknown vendor ID and Distance protocol (HeaderMa...
Definition: IRremoteInt.h:166
RC6_TOGGLE_BIT_INDEX
#define RC6_TOGGLE_BIT_INDEX
Definition: ir_RC5_RC6.hpp:500
IRsend::space
static void space(uint16_t aSpaceMicros)
Sends an IR space for the specified number of microseconds.
Definition: IRSend.hpp:1458
IRsend::sendRC5
void sendRC5(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
Definition: ir_RC5_RC6.hpp:189
SPACE
#define SPACE
Definition: IRremoteInt.h:38
IRData::rawlen
IRRawlenType rawlen
Counter of entries in rawbuf of last received frame.
Definition: IRremoteInt.h:182
MARANTZ_PAUSE_DURATION
#define MARANTZ_PAUSE_DURATION
Definition: ir_RC5_RC6.hpp:111
LongUnion::MidHighByte
uint8_t MidHighByte
Definition: LongUnion.h:63
RC6
@ RC6
Definition: IRProtocol.h:99
LongUnion::UWord
struct LongUnion::@6 UWord
RC6_UNIT
#define RC6_UNIT
Definition: ir_RC5_RC6.hpp:508
IRsend::sendRC6A
void sendRC6A(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint16_t aCustomer, bool aEnableAutomaticToggle=true)
Assemble raw data for RC6 from parameters and toggle state and send We do not wait for the minimal tr...
Definition: ir_RC5_RC6.hpp:633
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRremoteInt.h:163
MARK
#define MARK
Definition: IRremoteInt.h:39
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:617
RC5_MAXIMUM_REPEAT_DISTANCE
#define RC5_MAXIMUM_REPEAT_DISTANCE
Definition: ir_RC5_RC6.hpp:106
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1498
LocalDebugLevelEnd.h
RC6A_BITS
#define RC6A_BITS
Definition: ir_RC5_RC6.hpp:506