IRremote
IRReceive.hpp
Go to the documentation of this file.
1 /*
2  * IRReceive.hpp
3  * This file is exclusively included by IRremote.h to enable easy configuration of library switches
4  *
5  * Contains all IRrecv class functions as well as other receiver related functions.
6  *
7  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
8  *
9  ************************************************************************************
10  * MIT License
11  *
12  * Copyright (c) 2009-2025 Ken Shirriff, Rafi Khan, Armin Joachimsmeyer
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a copy
15  * of this software and associated documentation files (the "Software"), to deal
16  * in the Software without restriction, including without limitation the rights
17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18  * copies of the Software, and to permit persons to whom the Software is furnished
19  * to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included in all
22  * copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
25  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
26  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
28  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
29  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  *
31  ************************************************************************************
32  */
33 #ifndef _IR_RECEIVE_HPP
34 #define _IR_RECEIVE_HPP
35 
36 #if defined(DEBUG)
37 #define LOCAL_DEBUG
38 #else
39 //#define LOCAL_DEBUG // This enables debug output only for this file
40 #endif
41 
42 #if defined(TRACE) && !defined(LOCAL_TRACE)
43 #define LOCAL_TRACE
44 #else
45 //#define LOCAL_TRACE // This enables debug output only for this file
46 #endif
47 /*
48  * Low level hardware timing measurement
49  */
50 //#define _IR_MEASURE_TIMING // for ISR
51 //#define _IR_TIMING_TEST_PIN 7 // "pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);" is executed at start()
52 //
53 
54 #if !defined(NO_LED_RECEIVE_FEEDBACK_CODE)
55 #define LED_RECEIVE_FEEDBACK_CODE // Resolve the double negative
56 #endif
57 
65 
66 /*
67  * The control structure instance
68  */
69 //struct irparams_struct irparams; // the irparams instance
70 unsigned long sMicrosAtLastStopTimer = 0; // Used to adjust TickCounterForISR with uncounted ticks between stopTimer() and restartTimer()
71 
77  setReceivePin(0);
78 }
79 
80 IRrecv::IRrecv(uint_fast8_t aReceivePin) {
81  setReceivePin(aReceivePin);
82 }
83 
89 IRrecv::IRrecv(uint_fast8_t aReceivePin, uint_fast8_t aFeedbackLEDPin) {
90  setReceivePin(aReceivePin);
91 #if defined(LED_RECEIVE_FEEDBACK_CODE)
92  setLEDFeedbackPin(aFeedbackLEDPin);
93 #else
94  (void) aFeedbackLEDPin;
95 #endif
96 }
97 
98 /**********************************************************************************************************************
99  * Interrupt Service Routine - Called every 50 us
100  *
101  * Duration in ticks of 50 us of alternating SPACE, MARK are recorded in irparams.rawbuf array.
102  * 'rawlen' counts the number of entries recorded so far.
103  * First entry is the SPACE between transmissions.
104  *
105  * As soon as one SPACE entry gets longer than RECORD_GAP_TICKS, state switches to STOP (frame received). Timing of SPACE continues.
106  * A call of resume() switches from STOP to IDLE.
107  * As soon as first MARK arrives in IDLE, gap width is recorded and new logging starts.
108  *
109  * With digitalRead and Feedback LED
110  * 15 pushs, 1 in, 1 eor before start of code = 2 us @16MHz + * 7.2 us computation time (6us idle time) + * pop + reti = 2.25 us @16MHz => 10.3 to 11.5 us @16MHz
111  * With portInputRegister and mask and Feedback LED code commented
112  * 9 pushs, 1 in, 1 eor before start of code = 1.25 us @16MHz + * 2.25 us computation time + * pop + reti = 1.5 us @16MHz => 5 us @16MHz
113  * => Minimal CPU frequency is 4 MHz
114  *
115  **********************************************************************************************************************/
116 #if defined(ESP8266) || defined(ESP32)
117 #pragma GCC diagnostic push
118 #pragma GCC diagnostic ignored "-Wvolatile"
119 IRAM_ATTR
120 #endif
121 
123 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
124  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
125 #endif
126 // 7 - 8.5 us for ISR body (without pushes and pops) for ATmega328 @16MHz
127 
128 #if defined(TIMER_REQUIRES_RESET_INTR_PENDING)
129  timerResetInterruptPending(); // reset TickCounterForISR interrupt flag if required (currently only for Teensy and ATmega4809)
130 #endif
131 
132 // Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on]
133 #if defined(__AVR__)
134  uint8_t tIRInputLevel = *irparams.IRReceivePinPortInputRegister & irparams.IRReceivePinMask;
135 #else
136  uint_fast8_t tIRInputLevel = (uint_fast8_t) digitalReadFast(irparams.IRReceivePin);
137 #endif
138 
139  uint_fast16_t tTickCounterForISR = irparams.TickCounterForISR;
140  /*
141  * Increase TickCounter and clip it at maximum 0xFFFF / 3.2 seconds at 50 us ticks
142  */
143  if (irparams.TickCounterForISR < UINT16_MAX) {
144  tTickCounterForISR++; // One more 50uS tick
145  irparams.TickCounterForISR = tTickCounterForISR;
146  }
147 
148  /*
149  * Due to a ESP32 compiler bug https://github.com/espressif/esp-idf/issues/1552 no switch statements are possible for ESP32
150  * So we change the code to if / else if
151  */
152 // switch (irparams.StateForISR) {
153 //
154  uint_fast8_t tStateForISR = irparams.StateForISR;
155  if (tStateForISR == IR_REC_STATE_IDLE) {
156  /*
157  * Here we are just resumed and maybe in the middle of a transmission
158  */
159  if (tIRInputLevel == INPUT_MARK) {
160  // check if we did not start in the middle of a transmission by checking the minimum length of leading space
161  if (tTickCounterForISR > RECORD_GAP_TICKS) {
162 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
163 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
164 #endif
165  /*
166  * Gap between two transmissions just ended; Record gap duration + start recording transmission
167  * Initialize all state machine variables
168  */
169  irparams.OverflowFlag = false;
170  // irparams.rawbuf[0] = irparams.TickCounterForISR;
171  // Usage of initialGapTicks enables usage of 8 bit buffer instead of 16 bit since 4.4,
172  // because the big gap value is not stored in this buffer any more
173  irparams.initialGapTicks = tTickCounterForISR;
174  irparams.rawlen = 1;
176  } // otherwise stay in idle state
177  irparams.TickCounterForISR = 0; // reset counter in both cases
178  }
179 
180  } else if (tStateForISR == IR_REC_STATE_MARK) {
181  // Timing mark here, rawlen is even
182  if (tIRInputLevel != INPUT_MARK) {
183  /*
184  * Mark ended here. Record mark time in rawbuf array
185  */
186 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
187 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
188 #endif
189 #if RECORD_GAP_TICKS <= 400
190  if (tTickCounterForISR > UINT8_MAX) {
191  tTickCounterForISR = UINT8_MAX;
192  }
193 #endif
194  irparams.rawbuf[irparams.rawlen++] = tTickCounterForISR; // record mark
196  irparams.TickCounterForISR = 0; // This resets the tick counter also at end of frame :-)
197  }
198 
199  } else if (tStateForISR == IR_REC_STATE_SPACE) {
200  /*
201  * In space receiving here, rawlen is odd
202  * Check for timeout or overflow
203  */
204  if (tTickCounterForISR > RECORD_GAP_TICKS || irparams.rawlen >= RAW_BUFFER_LENGTH - 1) {
206  // Flag up a read OverflowFlag; Stop the state machine
207  irparams.OverflowFlag = true;
208  }
209  /*
210  * Overflow or maximum space duration reached here.
211  * Current code is ready for processing!
212  * We received a long space, which indicates gap between codes.
213  * Switch to IR_REC_STATE_STOP
214  * Don't reset TickCounterForISR; keep counting width of next leading space
215  */
216  /*
217  * These 2 variables allow to call resume() directly after decode.
218  * After resume(), irparams.initialGapTicks and irparams.rawlen are
219  * the first variables, which are overwritten by the next received frame.
220  * since 4.3.0.
221  * For backward compatibility, there are the same 2 statements in decode() if IrReceiver is not used.
222  */
225 
226  irparams.StateForISR = IR_REC_STATE_STOP; // This signals the decode(), that a complete frame was received
227 #if !defined(IR_REMOTE_DISABLE_RECEIVE_COMPLETE_CALLBACK)
228  /*
229  * Call callback if registered (not nullptr)
230  */
231  if (irparams.ReceiveCompleteCallbackFunction != nullptr) {
233  }
234 #endif
235  } else if (tIRInputLevel == INPUT_MARK) {
236  /*
237  * Space ended here.
238  */
239 
240 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
241 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
242 #endif
243 #if RECORD_GAP_TICKS <= 400
244  if (tTickCounterForISR > UINT8_MAX) {
245  tTickCounterForISR = UINT8_MAX;
246  }
247 #endif
248  irparams.rawbuf[irparams.rawlen++] = tTickCounterForISR; // record space
251  }
252  } else if (tStateForISR == IR_REC_STATE_STOP) {
253  /*
254  * Complete command received
255  * stay here until resume() is called, which switches state to IR_REC_STATE_IDLE
256  */
257 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
258 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
259 #endif
260  if (tIRInputLevel == INPUT_MARK) {
261  // Reset gap TickCounterForISR, to prepare for detection if we are in the middle of a transmission after call of resume()
263  }
264  }
265 
266 #if defined(LED_RECEIVE_FEEDBACK_CODE)
268  setFeedbackLED(tIRInputLevel == INPUT_MARK);
269  }
270 #endif
271 
272 #ifdef _IR_MEASURE_TIMING
273  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
274 #endif
275 
276 }
277 /*
278  * The handler which directly calls the interrupt handler function of the IRrecv object.
279  * This must be a separate function, because we need this static function in IRTimer.hpp.
280  * Doing it this way, we are able to modify the body of this function to support multiple IRrecv instances for receiving
281  */
284 #if defined(SUPPORT_MULTIPLE_RECEIVER_INSTANCES)
285  // Quick and dirty solution by used defined extension
286  UserIRReceiveTimerInterruptHandler();
287 #endif
288 }
289 
290 /**********************************************************************************************************************
291  * Interrupt Service Routine - Called every 50 us
292  * This in turn calls calls the static interrupt handler function, which in turn calls the interrupt handler function of the IRrecv object
293  */
294 #if defined(TIMER_INTR_NAME) || defined(ISR)
295 # if defined(TIMER_INTR_NAME)
296 ISR (TIMER_INTR_NAME) // for ISR definitions
297 # elif defined(ISR)
298 ISR()
299 // for functions definitions which are called by separate (board specific) ISR
300 # endif
301 {
303 }
304 #endif
305 
306 /**********************************************************************************************************************
307  * Stream like API
308  **********************************************************************************************************************/
309 
316 void IRrecv::begin(uint_fast8_t aReceivePin, bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
317 
318  setReceivePin(aReceivePin);
319 #if defined(LED_RECEIVE_FEEDBACK_CODE)
320  setLEDFeedback(aEnableLEDFeedback);
321  setLEDFeedbackPin(aFeedbackLEDPin);
322 #else
323  (void) aEnableLEDFeedback;
324  (void) aFeedbackLEDPin;
325 #endif
326 
327 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
328  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
329 #endif
330  start();
331 }
332 
336 void IRrecv::setReceivePin(uint_fast8_t aReceivePinNumber) {
337  irparams.IRReceivePin = aReceivePinNumber;
338 #if defined(__AVR__)
339 # if defined(__digitalPinToBit)
340  if (__builtin_constant_p(aReceivePinNumber)) {
341  irparams.IRReceivePinMask = 1UL << (__digitalPinToBit(aReceivePinNumber));
342  } else {
343  irparams.IRReceivePinMask = digitalPinToBitMask(aReceivePinNumber); // requires 10 bytes PGM, even if not referenced (?because it is assembler code?)
344  }
345 # else
346  irparams.IRReceivePinMask = digitalPinToBitMask(aReceivePinNumber); // requires 10 bytes PGM, even if not referenced (?because it is assembler code?)
347 # endif
348 # if defined(__digitalPinToPINReg)
349  /*
350  * This code is 54 bytes smaller, if aReceivePinNumber is a constant :-), but 38 byte longer if it is not constant (,which is not likely).
351  */
352  if (__builtin_constant_p(aReceivePinNumber)) {
353  irparams.IRReceivePinPortInputRegister = __digitalPinToPINReg(aReceivePinNumber);
354  } else {
355  irparams.IRReceivePinPortInputRegister = portInputRegister(digitalPinToPort(aReceivePinNumber)); // requires 44 bytes PGM, even if not referenced
356  }
357 # else
358  irparams.IRReceivePinPortInputRegister = portInputRegister(digitalPinToPort(aReceivePinNumber)); // requires 44 bytes PGM, even if not referenced
359 # endif
360 #endif
361  // Seems to be at least required by ESP32
362  // Set pin mode once. pinModeFast makes no difference if used, but saves 224 if not referenced :-(
363  if (__builtin_constant_p(aReceivePinNumber)) {
364  pinModeFast(aReceivePinNumber, INPUT);
365  } else {
366  pinModeFast(aReceivePinNumber, INPUT);
367  }
368 }
369 
370 #if !defined(IR_REMOTE_DISABLE_RECEIVE_COMPLETE_CALLBACK)
371 
374 void IRrecv::registerReceiveCompleteCallback(void (*aReceiveCompleteCallbackFunction)(void)) {
375  irparams.ReceiveCompleteCallbackFunction = aReceiveCompleteCallbackFunction;
376 }
377 #endif
378 
385 
386  // Setup for cyclic 50 us interrupt
387  timerConfigForReceive(); // no interrupts enabled here!
388 
389  // Initialize state machine state
390  resume();
391 
392  // Timer interrupt is enabled after state machine reset
393  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
394 #ifdef _IR_MEASURE_TIMING
395  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
396 #endif
397 }
398 
399 /*
400  * Restarts timer interrupts, adjusts TickCounterForISR for correct gap value after stopTimer(). Does not call resume()!
401  */
403  // Setup for cyclic 50 us interrupt
404  timerConfigForReceive(); // no interrupts enabled here!
405  // Timer interrupt is enabled after state machine reset
406  if (sMicrosAtLastStopTimer != 0) {
407  irparams.TickCounterForISR += (micros() - sMicrosAtLastStopTimer) / MICROS_PER_TICK; // adjust TickCounterForISR for correct gap value, which is used for repeat detection
409  }
410  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
411 #ifdef _IR_MEASURE_TIMING
412  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
413 #endif
414 }
419  start();
420 }
421 
432 void IRrecv::restartTimer(uint32_t aMicrosecondsToAddToGapCounter) {
433  irparams.TickCounterForISR += aMicrosecondsToAddToGapCounter / MICROS_PER_TICK;
434  timerConfigForReceive(); // no interrupts enabled here!
435  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
436 #ifdef _IR_MEASURE_TIMING
437  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
438 #endif
439 }
444 void IRrecv::restartTimerWithTicksToAdd(uint16_t aTicksToAddToGapCounter) {
445  irparams.TickCounterForISR += aTicksToAddToGapCounter;
446  timerConfigForReceive(); // no interrupts enabled here!
447  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
448 #ifdef _IR_MEASURE_TIMING
449  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
450 #endif
451 }
452 #if defined(ESP8266) || defined(ESP32)
453 #pragma GCC diagnostic push
454 #endif
455 
460 #if defined(SEND_PWM_BY_TIMER) && !defined(SEND_PWM_DOES_NOT_USE_RECEIVE_TIMER)
461  start();
462 #endif
463 }
464 
468 void IRrecv::stop() {
470 }
471 
472 /*
473  * Stores microseconds of stop, to adjust TickCounterForISR in restartTimer()
474  */
477  sMicrosAtLastStopTimer = micros();
478 }
483  stop();
484 }
488 void IRrecv::end() {
489  stop();
490 }
491 
498 }
499 
505  // This check allows to call resume at arbitrary places or more than once
508  }
509 }
510 
516 
517  if (irparams.OverflowFlag) {
519 #if defined(LOCAL_DEBUG)
520  Serial.print(F("Overflow happened, try to increase the \"RAW_BUFFER_LENGTH\" value of "));
521  Serial.print(RAW_BUFFER_LENGTH);
522  Serial.println(F(" with #define RAW_BUFFER_LENGTH=<biggerValue>"));
523 #endif
524 
525  } else {
527  // save last protocol, command and address for repeat handling (where they are compared or copied back :-))
528  lastDecodedProtocol = decodedIRData.protocol; // repeat patterns can be equal between protocols (e.g. NEC, Samsung and LG), so we must keep the original one
531 
532  }
538 }
539 
545 }
546 
552  return nullptr;
553  }
554  if (decode()) {
555  return &decodedIRData;
556  } else {
557  return nullptr;
558  }
559 }
560 
569  return false;
570  }
571 
572  /*
573  * Support for old examples, which do not use the default IrReceiver instance
574  */
575  if (this != &IrReceiver) {
578  }
579 
580  initDecodedIRData(); // sets IRDATA_FLAGS_WAS_OVERFLOW
581 
583  /*
584  * Set OverflowFlag flag and return true here, to let the loop call resume or print raw data.
585  */
587  return true;
588  }
589 
590 #if defined(DECODE_NEC) || defined(DECODE_ONKYO)
591  IR_TRACE_PRINTLN(F("Attempting NEC/Onkyo decode"));
592  if (decodeNEC()) {
593  return true;
594  }
595 #endif
596 
597 #if defined(DECODE_PANASONIC) || defined(DECODE_KASEIKYO)
598  IR_TRACE_PRINTLN(F("Attempting Panasonic/Kaseikyo decode"));
599  if (decodeKaseikyo()) {
600  return true;
601  }
602 #endif
603 
604 #if defined(DECODE_DENON)
605  IR_TRACE_PRINTLN(F("Attempting Denon/Sharp decode"));
606  if (decodeDenon()) {
607  return true;
608  }
609 #endif
610 
611 #if defined(DECODE_SONY)
612  IR_TRACE_PRINTLN(F("Attempting Sony decode"));
613  if (decodeSony()) {
614  return true;
615  }
616 #endif
617 
618 #if defined(DECODE_RC5)
619  IR_TRACE_PRINTLN(F("Attempting RC5 decode"));
620  if (decodeRC5()) {
621  return true;
622  }
623 #endif
624 
625 #if defined(DECODE_RC6)
626  IR_TRACE_PRINTLN(F("Attempting RC6 decode"));
627  if (decodeRC6()) {
628  return true;
629  }
630 #endif
631 
632 #if defined(DECODE_LG)
633  IR_TRACE_PRINTLN(F("Attempting LG decode"));
634  if (decodeLG()) {
635  return true;
636  }
637 #endif
638 
639 #if defined(DECODE_JVC)
640  IR_TRACE_PRINTLN(F("Attempting JVC decode"));
641  if (decodeJVC()) {
642  return true;
643  }
644 #endif
645 
646 #if defined(DECODE_SAMSUNG)
647  IR_TRACE_PRINTLN(F("Attempting Samsung decode"));
648  if (decodeSamsung()) {
649  return true;
650  }
651 #endif
652  /*
653  * Start of the exotic protocols
654  */
655 
656 #if defined(DECODE_BEO)
657  IR_TRACE_PRINTLN(F("Attempting Bang & Olufsen decode"));
658  if (decodeBangOlufsen()) {
659  return true;
660  }
661 #endif
662 
663 #if defined(DECODE_FAST)
664  IR_TRACE_PRINTLN(F("Attempting FAST decode"));
665  if (decodeFAST()) {
666  return true;
667  }
668 #endif
669 
670 #if defined(DECODE_WHYNTER)
671  IR_TRACE_PRINTLN(F("Attempting Whynter decode"));
672  if (decodeWhynter()) {
673  return true;
674  }
675 #endif
676 
677 #if defined(DECODE_LEGO_PF)
678  IR_TRACE_PRINTLN(F("Attempting Lego Power Functions"));
679  if (decodeLegoPowerFunctions()) {
680  return true;
681  }
682 #endif
683 
684 #if defined(DECODE_BOSEWAVE)
685  IR_TRACE_PRINTLN(F("Attempting Bosewave decode"));
686  if (decodeBoseWave()) {
687  return true;
688  }
689 #endif
690 
691 #if defined(DECODE_MAGIQUEST)
692  IR_TRACE_PRINTLN(F("Attempting MagiQuest decode"));
693  if (decodeMagiQuest()) {
694  return true;
695  }
696 #endif
697 
698  /*
699  * Try the universal decoder for pulse distance protocols
700  */
701 #if defined(DECODE_DISTANCE_WIDTH)
702  IR_TRACE_PRINTLN(F("Attempting universal Distance Width decode"));
703  if (decodeDistanceWidth()) {
704  return true;
705  }
706 #endif
707 
708  /*
709  * Last resort is the universal hash decode which always return true
710  */
711 #if defined(DECODE_HASH)
712  IR_TRACE_PRINTLN(F("Hash decode"));
713  // decodeHash returns a hash on any input.
714  // Thus, it needs to be last in the list.
715  // If you add any decodes, add them before this.
716  if (decodeHash()) {
717  return true;
718  }
719 #endif
720 
721  /*
722  * Return true here, to let the loop decide to call resume or to print raw data.
723  */
724  return true;
725 }
726 
727 /**********************************************************************************************************************
728  * Common decode functions
729  **********************************************************************************************************************/
748 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMicros,
749  bool aIsPulseWidthProtocol, bool aMSBfirst) {
750 
751 #if defined(LOCAL_DEBUG)
752  Serial.print(F("aOneMicros="));
753  Serial.print(aOneMicros);
754  Serial.print(F(", 0.75*aOneMicros="));
755  Serial.print((aOneMicros * 3) / 4);
756  Serial.print(F(", MARK_EXCESS_MICROS=" STR(MARK_EXCESS_MICROS) " isPulseWidthProtocol="));
757  Serial.print(aIsPulseWidthProtocol);
758  Serial.println();
759 #endif
760 
761  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
762  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
763  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
764 
765  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
766 
767  bool tBitValue;
768  uint16_t tCurrentTicks;
769  if (aIsPulseWidthProtocol) {
770  /*
771  * PULSE_WIDTH here.
772  * !!!We only check variable length mark indicating a 1 or 0!!!
773  */
774  tCurrentTicks = *tRawBufPointer++;
775  tBitValue = matchMark(tCurrentTicks, aOneMicros); // Check for variable length mark indicating a 1 or 0
776  tRawBufPointer++;
777  } else {
778  /*
779  * PULSE_DISTANCE -including PULSE_DISTANCE_WIDTH- here.
780  * !!!We only check variable length space indicating a 1 or 0!!!
781  */
782  tRawBufPointer++;
783  tCurrentTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
784  tBitValue = matchSpace(tCurrentTicks, aOneMicros); // Check for variable length space indicating a 1 or 0
785  }
786 
787  if (aMSBfirst) {
788  tDecodedData <<= 1;
789  }
790 
791  if (tBitValue) {
792  // It's a 1 -> set the bit
793  if (aMSBfirst) {
794  tDecodedData |= 1;
795  } else {
796  tDecodedData |= tMask;
797  }
798  IR_TRACE_PRINT(tCurrentTicks);
799  IR_TRACE_PRINTLN(F(" => 1"));
800  } else {
801  // do not set the bit
802  IR_TRACE_PRINT(tCurrentTicks);
803  IR_TRACE_PRINTLN(F(" => 0"));
804  }
805  tMask <<= 1;
806  }
807  decodedIRData.decodedRawData = tDecodedData;
808 }
809 
828 void IRrecv::decodeWithThresholdPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset,
829  uint16_t aOneThresholdMicros, bool aIsPulseWidthProtocol, bool aMSBfirst) {
830 
831 #if defined(LOCAL_DEBUG)
832  Serial.print(F("OneThresholdMicros="));
833  Serial.print(aOneThresholdMicros);
834  Serial.print(F(" isPulseWidthProtocol="));
835  Serial.print(aIsPulseWidthProtocol);
836  Serial.println();
837 #endif
838 
839  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
840  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
841  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
842 
843  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
844 
845  if (!aIsPulseWidthProtocol) {
846  tRawBufPointer++;
847  }
848  uint16_t tCurrentMicros = *tRawBufPointer * MICROS_PER_TICK;
849  bool tBitValue = tCurrentMicros > aOneThresholdMicros; // Check for variable length timing indicating a 1 or 0
850  tRawBufPointer++;
851 
852  if (aIsPulseWidthProtocol) {
853  tRawBufPointer++;
854  }
855 
856  if (aMSBfirst) {
857  tDecodedData <<= 1;
858  }
859 
860  if (tBitValue) {
861  // It's a 1 -> set the bit
862  if (aMSBfirst) {
863  tDecodedData |= 1;
864  } else {
865  tDecodedData |= tMask;
866  }
867  IR_TRACE_PRINT(tCurrentMicros);
868  IR_TRACE_PRINTLN(F(" => 1"));
869  } else {
870  // do not set the bit
871  IR_TRACE_PRINT(tCurrentMicros);
872  IR_TRACE_PRINTLN(F(" => 0"));
873  }
874  tMask <<= 1;
875  }
876  decodedIRData.decodedRawData = tDecodedData;
877 }
878 
882 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
883  uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, bool aMSBfirst) {
884 
885  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
886 
887  bool isPulseDistanceProtocol = (aOneMarkMicros == aZeroMarkMicros); // If true, we check aOneSpaceMicros -> pulse distance protocol
888 
889  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
890  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
891 
892  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
893  // get one mark and space pair
894  unsigned int tMarkTicks;
895  unsigned int tSpaceTicks;
896  bool tBitValue;
897 
898  if (isPulseDistanceProtocol) {
899  /*
900  * PULSE_DISTANCE -including PULSE_DISTANCE_WIDTH- here.
901  * !!!We only check variable length space indicating a 1 or 0!!!
902  */
903  tRawBufPointer++;
904  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
905  tBitValue = matchSpace(tSpaceTicks, aOneSpaceMicros); // Check for variable length space indicating a 1 or 0
906 
907  } else {
908  /*
909  * PULSE_WIDTH here.
910  * !!!We only check variable length mark indicating a 1 or 0!!!
911  */
912  tMarkTicks = *tRawBufPointer++;
913  tBitValue = matchMark(tMarkTicks, aOneMarkMicros); // Check for variable length mark indicating a 1 or 0
914  tRawBufPointer++;
915  }
916 
917  if (aMSBfirst) {
918  tDecodedData <<= 1;
919  }
920 
921  if (tBitValue) {
922  // It's a 1 -> set the bit
923  if (aMSBfirst) {
924  tDecodedData |= 1;
925  } else {
926  tDecodedData |= tMask;
927  }
928  IR_TRACE_PRINTLN(F("=> 1"));
929  } else {
930  // do not set the bit
931  IR_TRACE_PRINTLN(F("=> 0"));
932  }
933  tMask <<= 1;
934  }
935  decodedIRData.decodedRawData = tDecodedData;
936 }
937 
938 /*
939  * Old deprecated version with 7 parameters and unused aZeroSpaceMicros parameter
940  */
941 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
942  uint16_t aZeroMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroSpaceMicros, bool aMSBfirst) {
943 
944  (void) aZeroSpaceMicros;
945  decodePulseDistanceWidthData(aNumberOfBits, aStartOffset, aOneMarkMicros, aZeroMarkMicros, aOneSpaceMicros, aMSBfirst);
946 }
947 
948 /*
949  * Only sensible for development or very exotic requirements. - Not used yet
950  * Check for additional required characteristics of timing like length of mark for a constant mark protocol,
951  * where space length determines the bit value. Requires up to 194 additional bytes of program memory.
952  *
953  * @param aZeroMarkMicros For strict checks
954  * @param aZeroSpaceMicros For strict checks
955  * @return true if decoding successful
956  *
957  */
958 bool IRrecv::decodeStrictPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
959  uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, bool aMSBfirst) {
960 
961  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
962 
963  bool isPulseDistanceProtocol = (aOneMarkMicros == aZeroMarkMicros); // If true, we have a constant mark -> pulse distance protocol
964 
965  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
966  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
967 
968  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
969  // get one mark and space pair
970  unsigned int tMarkTicks;
971  unsigned int tSpaceTicks;
972  bool tBitValue;
973 
974  if (isPulseDistanceProtocol) {
975  /*
976  * PULSE_DISTANCE here (aOneMarkMicros == aZeroMarkMicros)
977  * We additionally check constant mark duration and in case of zero the zero space duration.
978  */
979  tMarkTicks = *tRawBufPointer++;
980  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
981  tBitValue = matchSpace(tSpaceTicks, aOneSpaceMicros); // Check for variable length space indicating a 1 or 0
982 
983  // Check for constant mark duration
984  if (!matchMark(tMarkTicks, aOneMarkMicros)) {
985 #if defined(LOCAL_DEBUG)
986  Serial.print(F("Mark="));
987  Serial.print(tMarkTicks * MICROS_PER_TICK);
988  Serial.print(F(" is not "));
989  Serial.print(aOneMarkMicros);
990  Serial.print(F(". Index="));
991  Serial.print(aNumberOfBits - i);
992  Serial.print(' ');
993 #endif
994  return false;
995  }
996 
997  // in case of 0, check for zero space duration
998  if (!tBitValue && !matchSpace(tSpaceTicks, aZeroSpaceMicros)) {
999 #if defined(LOCAL_DEBUG)
1000  Serial.print(F("Space="));
1001  Serial.print(tSpaceTicks * MICROS_PER_TICK);
1002  Serial.print(F(" is not "));
1003  Serial.print(aZeroSpaceMicros);
1004  Serial.print(F(". Index="));
1005  Serial.print(aNumberOfBits - i);
1006  Serial.print(' ');
1007 #endif
1008  return false;
1009  }
1010 
1011  } else {
1012  /*
1013  * PULSE_WIDTH -including PULSE_DISTANCE_WIDTH- here.
1014  * We additionally check two space durations and in case of zero the zero mark duration.
1015  */
1016  tMarkTicks = *tRawBufPointer++;
1017  tBitValue = matchMark(tMarkTicks, aOneMarkMicros); // Check for variable length mark indicating a 1 or 0
1018  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
1019 
1020  // Check for space length, which is not constant in case of PULSE_DISTANCE_WIDTH
1021  if ((tBitValue && !matchSpace(tSpaceTicks, aOneSpaceMicros))
1022  || ((!tBitValue && !matchSpace(tSpaceTicks, aZeroSpaceMicros)))) {
1023 #if defined(LOCAL_DEBUG)
1024  Serial.print(F("Space="));
1025  Serial.print(tSpaceTicks * MICROS_PER_TICK);
1026  Serial.print(F(" is not "));
1027  Serial.print(aOneSpaceMicros);
1028  Serial.print(F(" or "));
1029  Serial.print(aZeroSpaceMicros);
1030  Serial.print(F(". Index="));
1031  Serial.print(aNumberOfBits - i);
1032  Serial.print(' ');
1033 #endif
1034  return false;
1035  }
1036  if (!tBitValue && !matchMark(tMarkTicks, aZeroMarkMicros)) {
1037 #if defined(LOCAL_DEBUG)
1038  Serial.print(F("Mark="));
1039  Serial.print(tMarkTicks * MICROS_PER_TICK);
1040  Serial.print(F(" is not "));
1041  Serial.print(aZeroMarkMicros);
1042  Serial.print(F(". Index="));
1043  Serial.print(aNumberOfBits - i);
1044  Serial.print(' ');
1045 #endif
1046  return false;
1047  }
1048  }
1049 
1050  if (aMSBfirst) {
1051  tDecodedData <<= 1;
1052  }
1053 
1054  if (tBitValue) {
1055  // It's a 1 -> set the bit
1056  if (aMSBfirst) {
1057  tDecodedData |= 1;
1058  } else {
1059  tDecodedData |= tMask;
1060  }
1061  IR_TRACE_PRINTLN(F("=> 1"));
1062  } else {
1063  // do not set the bit
1064  IR_TRACE_PRINTLN(F("=> 0"));
1065  }
1066  tMask <<= 1;
1067  }
1068  decodedIRData.decodedRawData = tDecodedData;
1069  return true;
1070 }
1071 
1076 #if defined(USE_STRICT_DECODER)
1077 bool
1078 #else
1079 void
1080 #endif
1081 IRrecv::decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits,
1082  IRRawlenType aStartOffset) {
1083 
1084 #if defined(USE_STRICT_DECODER)
1085  return decodeStrictPulseDistanceWidthData(aNumberOfBits, aStartOffset, aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros,
1086  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
1087  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1088 
1089 #else
1090  bool tIsPulseWidthProtocol = aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK;
1091  uint16_t tThresholdMicros;
1092 
1093 # if defined(USE_THRESHOLD_DECODER)
1094  if (tIsPulseWidthProtocol) {
1095  // we check the length of marks here
1096  tThresholdMicros = ((aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros
1097  + aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros) / 2) - MARK_EXCESS_MICROS;// MARK_EXCESS_MICROS is 0 here if not explicitly specified by user
1098  } else {
1099  // we check the length of spaces here
1100  tThresholdMicros = ((aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros
1101  + aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros) / 2) + MARK_EXCESS_MICROS;// MARK_EXCESS_MICROS is 0 here if not explicitly specified by user
1102  }
1103  return decodeWithThresholdPulseDistanceWidthData(aNumberOfBits, aStartOffset, tThresholdMicros,
1104  aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1105 # else
1106  if (tIsPulseWidthProtocol) {
1107  tThresholdMicros = aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros;
1108  } else {
1109  tThresholdMicros = aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros;
1110  }
1111  decodePulseDistanceWidthData(aNumberOfBits, aStartOffset, tThresholdMicros,
1112  aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1113 # endif
1114 #endif
1115 }
1116 
1118  uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset) {
1119  PulseDistanceWidthProtocolConstants tTemporaryPulseDistanceWidthProtocolConstants;
1120  memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1121  sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1122 
1123  decodePulseDistanceWidthData(&tTemporaryPulseDistanceWidthProtocolConstants, aNumberOfBits, aStartOffset);
1124 }
1125 
1126 /*
1127  * Static variables for the getBiphaselevel function
1128  */
1129 uint_fast8_t sBiphaseDecodeRawbuffOffset; // Index into raw timing array
1130 uint16_t sBiphaseCurrentTimingIntervals; // 1, 2 or 3. Number of aBiphaseTimeUnit intervals of the current rawbuf[sBiphaseDecodeRawbuffOffset] timing.
1131 uint_fast8_t sBiphaseUsedTimingIntervals; // Number of already used intervals of sCurrentTimingIntervals.
1133 
1134 void IRrecv::initBiphaselevel(uint_fast8_t aRCDecodeRawbuffOffset, uint16_t aBiphaseTimeUnit) {
1135  sBiphaseDecodeRawbuffOffset = aRCDecodeRawbuffOffset;
1136  sBiphaseTimeUnit = aBiphaseTimeUnit;
1138 }
1139 
1156 uint_fast8_t IRrecv::getBiphaselevel() {
1157  uint_fast8_t tLevelOfCurrentInterval; // 0 (SPACE) or 1 (MARK)
1158 
1160  return SPACE; // After end of recorded buffer, assume space.
1161  }
1162 
1163  tLevelOfCurrentInterval = (sBiphaseDecodeRawbuffOffset) & 1; // on odd rawbuf offsets we have mark timings
1164 
1165  /*
1166  * Setup data if sUsedTimingIntervals is 0
1167  */
1168  if (sBiphaseUsedTimingIntervals == 0) {
1169  uint16_t tCurrentTimingWith = irparams.rawbuf[sBiphaseDecodeRawbuffOffset];
1170  uint16_t tMarkExcessCorrection = (tLevelOfCurrentInterval == MARK) ? MARK_EXCESS_MICROS : -MARK_EXCESS_MICROS;
1171 
1172  if (matchTicks(tCurrentTimingWith, sBiphaseTimeUnit + tMarkExcessCorrection)) {
1174  } else if (matchTicks(tCurrentTimingWith, (2 * sBiphaseTimeUnit) + tMarkExcessCorrection)) {
1176  } else if (matchTicks(tCurrentTimingWith, (3 * sBiphaseTimeUnit) + tMarkExcessCorrection)) {
1178  } else {
1179  return -1;
1180  }
1181  }
1182 
1183 // We use another interval from tCurrentTimingIntervals
1185 
1186 // keep track of current timing offset
1188  // we have used all intervals of current timing, switch to next timing value
1191  }
1192 
1193  IR_TRACE_PRINTLN(tLevelOfCurrentInterval);
1194 
1195  return tLevelOfCurrentInterval;
1196 }
1197 
1198 /**********************************************************************************************************************
1199  * Internal Hash decode function
1200  **********************************************************************************************************************/
1201 #define FNV_PRIME_32 16777619
1202 #define FNV_BASIS_32 2166136261
1204 
1209 uint_fast8_t IRrecv::compare(uint16_t oldval, uint16_t newval) {
1210  if (newval * 10 < oldval * 8) {
1211  return 0;
1212  }
1213  if (oldval * 10 < newval * 8) {
1214  return 2;
1215  }
1216  return 1;
1217 }
1218 
1237  unsigned long hash = FNV_BASIS_32; // the result is the same no matter if we use a long or unsigned long variable
1238 
1239 // Require at least 6 samples to prevent triggering on noise
1240  if (decodedIRData.rawlen < 6) {
1241  IR_DEBUG_PRINT(F("HASH: "));
1242  IR_DEBUG_PRINT(F("Data length="));
1244  IR_DEBUG_PRINTLN(F(" is less than 6"));
1245  return false;
1246  }
1247  for (IRRawlenType i = 1; (i + 2) < decodedIRData.rawlen; i++) {
1248  // Compare mark with mark and space with space
1249  uint_fast8_t value = compare(irparams.rawbuf[i], irparams.rawbuf[i + 2]);
1250  // Add value into the hash
1251  hash = (hash * FNV_PRIME_32) ^ value;
1252  }
1253 
1257 
1258  return true;
1259 }
1260 
1262  unsigned long hash = FNV_BASIS_32;
1263 
1264 // Require at least 6 samples to prevent triggering on noise
1265  if (aResults->rawlen < 6) {
1266  return false;
1267  }
1268 
1269  for (uint8_t i = 3; i < aResults->rawlen; i++) {
1270  uint_fast8_t value = compare(aResults->rawbuf[i - 2], aResults->rawbuf[i]);
1271  // Add value into the hash
1272  hash = (hash * FNV_PRIME_32) ^ value;
1273  }
1274 
1275  aResults->value = hash;
1276  aResults->bits = 32;
1277  aResults->decode_type = UNKNOWN;
1279 
1280  return true;
1281 }
1282 
1283 /**********************************************************************************************************************
1284  * Match functions
1285  **********************************************************************************************************************/
1286 
1287 /*
1288  * returns true if values do match
1289  */
1291 // Check header "mark" and "space"
1292  if (!matchMark(irparams.rawbuf[1], aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros)) {
1293 #if defined(LOCAL_TRACE)
1294  Serial.print(::getProtocolString(aProtocolConstants->ProtocolIndex));
1295  Serial.println(F(": Header mark length is wrong"));
1296 #endif
1297  return false;
1298  }
1299  if (!matchSpace(irparams.rawbuf[2], aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros)) {
1300 #if defined(LOCAL_TRACE)
1301  Serial.print(::getProtocolString(aProtocolConstants->ProtocolIndex));
1302  Serial.println(F(": Header space length is wrong"));
1303 #endif
1304  return false;
1305  }
1306  return true;
1307 }
1308 
1310 // Check header "mark" and "space"
1311  if (!matchMark(irparams.rawbuf[1], pgm_read_word(&aProtocolConstantsPGM->DistanceWidthTimingInfo.HeaderMarkMicros))) {
1312 #if defined(LOCAL_TRACE)
1313  Serial.print(::getProtocolString((decode_type_t) pgm_read_byte(&aProtocolConstantsPGM->ProtocolIndex)));
1314  Serial.println(F(": Header mark length is wrong"));
1315 #endif
1316  return false;
1317  }
1318  if (!matchSpace(irparams.rawbuf[2], pgm_read_word(&aProtocolConstantsPGM->DistanceWidthTimingInfo.HeaderSpaceMicros))) {
1319 #if defined(LOCAL_TRACE)
1320  Serial.print(::getProtocolString((decode_type_t) pgm_read_byte(&aProtocolConstantsPGM->ProtocolIndex)));
1321  Serial.println(F(": Header space length is wrong"));
1322 #endif
1323  return false;
1324  }
1325  return true;
1326 }
1327 
1328 /*
1329  * Does not check for same address and command, because it is almost not possible to press 2 different buttons on the remote within around 100 ms.
1330  * And if really required, it can be enabled here, or done manually in user program.
1331  * And we have still no RC6 toggle bit check for detecting a second press on the same button.
1332  */
1333 void IRrecv::checkForRepeatSpaceTicksAndSetFlag(uint16_t aMaximumRepeatSpaceTicks) {
1334  if (decodedIRData.initialGapTicks < aMaximumRepeatSpaceTicks
1335 #if defined(ENABLE_COMPLETE_REPEAT_CHECK)
1336 // Check also for same command and address values to detect a repeat. Not sensible for standard protocols, because it is almost not possible to press 2 different buttons on the remote within around 100 ms
1337  && decodedIRData.address == lastDecodedAddress && decodedIRData.command == lastDecodedCommand /* requires around 44 bytes program space */
1338 #endif
1339  ) {
1341  }
1342 }
1343 
1348 bool matchTicks(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros) {
1349  uint16_t tMeasuredMicros = (aMeasuredTicks * MICROS_PER_TICK);
1350  uint16_t tMatchValueMicrosQuarter = aMatchValueMicros / 4;
1351 #if defined(LOCAL_TRACE)
1352  Serial.print(F("Testing (actual vs desired): "));
1353  Serial.print(tMeasuredMicros);
1354  Serial.print(F("us vs "));
1355  Serial.print(aMatchValueMicros);
1356  Serial.print(F("us: "));
1357  Serial.print(tMatchValueMicrosQuarter * 3); // rounded value because we divide first
1358  Serial.print(F(" <= "));
1359  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1360  Serial.print(F(" <= "));
1361  Serial.print(tMatchValueMicrosQuarter * 5);
1362 #endif
1363  bool passed = (tMeasuredMicros >= (tMatchValueMicrosQuarter * 3) && tMeasuredMicros <= (tMatchValueMicrosQuarter * 5));
1364 #if defined(LOCAL_TRACE)
1365  if (passed) {
1366  Serial.println(F(" => passed"));
1367  } else {
1368  Serial.println(F(" => FAILED"));
1369  }
1370 #endif
1371  return passed;
1372 }
1373 
1378 bool matchTicks(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros, int16_t aCompensationMicrosForTicks) {
1379  uint16_t tMeasuredMicros = (aMeasuredTicks * MICROS_PER_TICK) + aCompensationMicrosForTicks;
1380  uint16_t tMatchValueMicrosQuarter = aMatchValueMicros / 4;
1381 #if defined(LOCAL_TRACE)
1382  Serial.print(F("Testing (actual vs desired): "));
1383  Serial.print(tMeasuredMicros);
1384  Serial.print(F("us vs "));
1385  Serial.print(aMatchValueMicros);
1386  Serial.print(F("us: "));
1387  Serial.print(tMatchValueMicrosQuarter * 3); // rounded value because we divide first
1388  Serial.print(F(" < "));
1389  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1390  Serial.print(F(" <= "));
1391  Serial.print(tMatchValueMicrosQuarter * 5);
1392 #endif
1393  bool passed = (tMeasuredMicros > (tMatchValueMicrosQuarter * 3) && tMeasuredMicros <= (tMatchValueMicrosQuarter * 5));
1394 #if defined(LOCAL_TRACE)
1395  if (passed) {
1396  Serial.println(F(" => passed"));
1397  } else {
1398  Serial.println(F(" => FAILED"));
1399  }
1400 #endif
1401  return passed;
1402 }
1403 bool MATCH(uint16_t measured_ticks, uint16_t desired_us) {
1404  return matchTicks(measured_ticks, desired_us);
1405 }
1406 
1411 bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros) {
1412 #if (MARK_EXCESS_MICROS == 0)
1413  return matchTicks(aMeasuredTicks, aMatchValueMicros);
1414 #else
1415 
1416 # if !defined(USE_OLD_MATCH_FUNCTIONS)
1417  return matchTicks(aMeasuredTicks, aMatchValueMicros, -MARK_EXCESS_MICROS); // New handling of MARK_EXCESS_MICROS without strange rounding errors
1418 # endif
1419 
1420  // old version here
1421  aMatchValueMicros += MARK_EXCESS_MICROS;
1422 # if defined(LOCAL_TRACE)
1423  Serial.print(F("Testing mark (actual vs desired): "));
1424  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1425  Serial.print(F("us vs "));
1426  Serial.print(aMatchValueMicros);
1427  Serial.print(F("us: "));
1428 // Serial.print(F("TICKS_LOW="));
1429 // Serial.print(TICKS_LOW(aMatchValueMicros));
1430 // Serial.print(F(" "));
1431  Serial.print(TICKS_LOW(aMatchValueMicros) * MICROS_PER_TICK);
1432  Serial.print(F(" <= "));
1433  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1434  Serial.print(F(" <= "));
1435  Serial.print(TICKS_HIGH(aMatchValueMicros) * MICROS_PER_TICK);
1436 # endif
1437  // compensate for marks exceeded by demodulator hardware
1438  bool passed = ((aMeasuredTicks >= TICKS_LOW(aMatchValueMicros))
1439  && (aMeasuredTicks <= TICKS_HIGH(aMatchValueMicros)));
1440 # if defined(LOCAL_TRACE)
1441  if (passed) {
1442  Serial.println(F(" => passed"));
1443  } else {
1444  Serial.println(F(" => FAILED"));
1445  }
1446 # endif
1447  return passed;
1448 #endif
1449 }
1450 
1451 bool MATCH_MARK(uint16_t measured_ticks, uint16_t desired_us) {
1452  return matchMark(measured_ticks, desired_us);
1453 }
1454 
1459 bool matchSpace(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros) {
1460 #if (MARK_EXCESS_MICROS == 0)
1461  return matchTicks(aMeasuredTicks, aMatchValueMicros);
1462 #else
1463 # if !defined(USE_OLD_MATCH_FUNCTIONS)
1464  return matchTicks(aMeasuredTicks, aMatchValueMicros, MARK_EXCESS_MICROS); // New handling of MARK_EXCESS_MICROS without strange rounding errors
1465 # endif
1466  // old version here
1467  aMatchValueMicros -= MARK_EXCESS_MICROS;
1468 # if defined(LOCAL_TRACE)
1469  Serial.print(F("Testing space (actual vs desired): "));
1470  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1471  Serial.print(F("us vs "));
1472  Serial.print(aMatchValueMicros);
1473  Serial.print(F("us: "));
1474  Serial.print(F("LOW="));
1475  Serial.print(TICKS_LOW(aMatchValueMicros));
1476  Serial.print(F(" "));
1477  Serial.print(TICKS_LOW(aMatchValueMicros) * MICROS_PER_TICK);
1478  Serial.print(F(" <= "));
1479  Serial.print(aMeasuredTicks * MICROS_PER_TICK);
1480  Serial.print(F(" <= "));
1481  Serial.print(TICKS_HIGH(aMatchValueMicros) * MICROS_PER_TICK);
1482 # endif
1483  // compensate for spaces shortened by demodulator hardware
1484  bool passed = ((aMeasuredTicks >= TICKS_LOW(aMatchValueMicros))
1485  && (aMeasuredTicks <= TICKS_HIGH(aMatchValueMicros)));
1486 # if defined(LOCAL_TRACE)
1487  if (passed) {
1488  Serial.println(F(" => passed"));
1489  } else {
1490  Serial.println(F(" => FAILED"));
1491  }
1492 # endif
1493  return passed;
1494 #endif
1495 }
1496 
1497 bool MATCH_SPACE(uint16_t measured_ticks, uint16_t desired_us) {
1498  return matchSpace(measured_ticks, desired_us);
1499 }
1500 
1505  return MARK_EXCESS_MICROS;
1506 }
1507 
1513 bool IRrecv::checkForRecordGapsMicros(Print *aSerial) {
1514  /*
1515  * Check if protocol is not detected and detected space between two transmissions
1516  * is smaller than known value for protocols (Sony with around 24 ms)
1517  */
1520  aSerial->println();
1521  aSerial->print(F("Space of "));
1522  aSerial->print(decodedIRData.initialGapTicks * MICROS_PER_TICK);
1523  aSerial->print(F(" us between two detected transmission is smaller than the minimal gap of "));
1524  aSerial->print(RECORD_GAP_MICROS_WARNING_THRESHOLD);
1525  aSerial->println(F(" us known for implemented protocols like NEC, Sony, RC% etc.."));
1526  aSerial->println(F("But it can be OK for some yet unsupported protocols, and especially for repeats."));
1527  aSerial->println(F("If you get unexpected results, try to increase the RECORD_GAP_MICROS in IRremote.h."));
1528  aSerial->println();
1529  return true;
1530  }
1531  return false;
1532 }
1533 
1534 /**********************************************************************************************************************
1535  * Print functions
1536  * Since a library should not allocate the "Serial" object, all functions require a pointer to a Print object.
1537  **********************************************************************************************************************/
1538 void IRrecv::printActiveIRProtocols(Print *aSerial) {
1539 // call no class function with same name
1540  ::printActiveIRProtocols(aSerial);
1541 }
1542 /*
1543  * Prints a list of enabled protocols for this application.
1544  * @param aSerial pointer to serial used for printing. Use "&Serial".
1545  */
1546 void printActiveIRProtocols(Print *aSerial) {
1547 #if defined(DECODE_ONKYO)
1548  aSerial->print(F("Onkyo, "));
1549 #elif defined(DECODE_NEC)
1550  aSerial->print(F("NEC/NEC2/Onkyo/Apple, "));
1551 #endif
1552 #if defined(DECODE_PANASONIC) || defined(DECODE_KASEIKYO)
1553  aSerial->print(F("Panasonic/Kaseikyo, "));
1554 #endif
1555 #if defined(DECODE_DENON)
1556  aSerial->print(F("Denon/Sharp, "));
1557 #endif
1558 #if defined(DECODE_SONY)
1559  aSerial->print(F("Sony, "));
1560 #endif
1561 #if defined(DECODE_RC5)
1562  aSerial->print(F("RC5, "));
1563 #endif
1564 #if defined(DECODE_RC6)
1565  aSerial->print(F("RC6, "));
1566 #endif
1567 #if defined(DECODE_LG)
1568  aSerial->print(F("LG, "));
1569 #endif
1570 #if defined(DECODE_JVC)
1571  aSerial->print(F("JVC, "));
1572 #endif
1573 #if defined(DECODE_SAMSUNG)
1574  aSerial->print(F("Samsung, "));
1575 #endif
1576  /*
1577  * Start of the exotic protocols
1578  */
1579 #if defined(DECODE_BEO)
1580  aSerial->print(F("Bang & Olufsen, "));
1581 #endif
1582 #if defined(DECODE_FAST)
1583  aSerial->print(F("FAST, "));
1584 #endif
1585 #if defined(DECODE_WHYNTER)
1586  aSerial->print(F("Whynter, "));
1587 #endif
1588 #if defined(DECODE_LEGO_PF)
1589  aSerial->print(F("Lego Power Functions, "));
1590 #endif
1591 #if defined(DECODE_BOSEWAVE)
1592  aSerial->print(F("Bosewave, "));
1593 #endif
1594 #if defined(DECODE_MAGIQUEST)
1595  aSerial->print(F("MagiQuest, "));
1596 #endif
1597 #if defined(DECODE_DISTANCE_WIDTH)
1598  aSerial->print(F("Universal Pulse Distance Width, "));
1599 #endif
1600 #if defined(DECODE_HASH)
1601  aSerial->print(F("Hash "));
1602 #endif
1603 #if defined(NO_DECODER) // for sending raw only
1604  (void)aSerial; // to avoid compiler warnings
1605 #endif
1606 }
1607 
1622 bool IRrecv::printIRResultShort(Print *aSerial, bool aPrintRepeatGap, bool aCheckForRecordGapsMicros) {
1623  // DEPRECATED
1624  (void) aPrintRepeatGap;
1625  return printIRResultShort(aSerial, aCheckForRecordGapsMicros);
1626 }
1627 bool IRrecv::printIRResultShort(Print *aSerial, bool aCheckForRecordGapsMicros) {
1628 
1629  uint8_t tFlags = decodedIRData.flags;
1630  if (tFlags & IRDATA_FLAGS_WAS_OVERFLOW) {
1631  aSerial->println(F("Overflow"));
1632  } else {
1633  aSerial->print(F("Protocol="));
1634  aSerial->print(getProtocolString());
1635  if (decodedIRData.protocol == UNKNOWN) {
1636 #if defined(DECODE_HASH)
1637  aSerial->print(F(" Hash=0x"));
1638 #if (__INT_WIDTH__ < 32)
1639  aSerial->print(decodedIRData.decodedRawData, HEX);
1640 #else
1641  PrintULL::print(aSerial,decodedIRData.decodedRawData, HEX);
1642 #endif
1643 
1644 #endif
1645 #if !defined(DISABLE_CODE_FOR_RECEIVER)
1646  aSerial->print(' ');
1647  aSerial->print((decodedIRData.rawlen + 1) / 2);
1648  aSerial->println(F(" bits (incl. gap and start) received"));
1649 #endif
1650  } else {
1651 #if defined(DECODE_DISTANCE_WIDTH)
1653 #endif
1654  /*
1655  * New decoders have address and command
1656  */
1657  aSerial->print(F(" Address=0x"));
1658  aSerial->print(decodedIRData.address, HEX);
1659 
1660  aSerial->print(F(", Command=0x"));
1661  aSerial->print(decodedIRData.command, HEX);
1662 
1663  if (tFlags & IRDATA_FLAGS_EXTRA_INFO) {
1664  aSerial->print(F(", Extra=0x"));
1665  aSerial->print(decodedIRData.extra, HEX);
1666  }
1667 
1668  if (tFlags & IRDATA_FLAGS_PARITY_FAILED) {
1669  aSerial->print(F(", Parity fail"));
1670  }
1671 
1672  if (tFlags & IRDATA_FLAGS_TOGGLE_BIT) {
1673  aSerial->print(F(", Toggle=1"));
1674  }
1675 #if defined(DECODE_DISTANCE_WIDTH)
1676  }
1677 #endif
1678 
1679  /*
1680  * Print raw data, numberOfBits and MSB or LSB
1681  */
1682  if (!(tFlags & IRDATA_FLAGS_IS_REPEAT) || decodedIRData.decodedRawData != 0) {
1683  aSerial->print(F(", Raw-Data=0x"));
1684 #if (__INT_WIDTH__ < 32)
1685  aSerial->print(decodedIRData.decodedRawData, HEX);
1686 #else
1687  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
1688 #endif
1689  aSerial->print(F(", "));
1690 
1691  /*
1692  * Print number of bits processed
1693  */
1694  aSerial->print(decodedIRData.numberOfBits);
1695  aSerial->print(F(" bits,"));
1696 
1697  if (tFlags & IRDATA_FLAGS_IS_MSB_FIRST) {
1698  aSerial->print(F(" MSB first"));
1699  } else {
1700  aSerial->print(F(" LSB first"));
1701  }
1702  }
1703 
1704  /*
1705  * Print gap and duration, in order to be able to compute the repeat period of the protocol by adding the next gap time
1706  */
1708  aSerial->print(F(", "));
1709  if (tFlags & IRDATA_FLAGS_IS_AUTO_REPEAT) {
1710  aSerial->print(F("Auto-"));
1711  }
1712  aSerial->print(F("Repeat"));
1713  }
1714 #if !defined(DISABLE_CODE_FOR_RECEIVER)
1715  aSerial->print(F(", Gap="));
1716  aSerial->print((uint32_t) decodedIRData.initialGapTicks * MICROS_PER_TICK);
1717  aSerial->print(F("us"));
1718 
1719  /*
1720  * Print complete duration of IR frame
1721  */
1722  uint16_t tSumOfDurationTicks = 0;
1723  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
1724  tSumOfDurationTicks += irparams.rawbuf[i];
1725  }
1726  aSerial->print(F(", Duration="));
1727  aSerial->print((uint32_t) tSumOfDurationTicks * MICROS_PER_TICK);
1728  aSerial->println(F("us"));
1729 #else
1730  aSerial->println();
1731 #endif
1732  }
1733  }
1734 
1735 // call no class function with same name
1736  if (aCheckForRecordGapsMicros && decodedIRData.protocol != UNKNOWN) {
1737  return checkForRecordGapsMicros(aSerial);
1738  }
1739  return false;
1740 }
1741 
1742 /*
1743  * Only used in example ReceiveAndSend.cpp
1744  */
1745 void printIRDataShort(Print *aSerial, IRData *aIRDataPtr) {
1746 
1747  aSerial->print(F("Protocol="));
1748  aSerial->print(getProtocolString(aIRDataPtr->protocol));
1749 #if defined(DECODE_DISTANCE_WIDTH)
1750  if (aIRDataPtr->protocol != PULSE_DISTANCE && aIRDataPtr->protocol != PULSE_WIDTH) {
1751 #endif
1752  /*
1753  * New decoders have address and command
1754  */
1755  aSerial->print(F(" Address=0x"));
1756  aSerial->print(aIRDataPtr->address, HEX);
1757 
1758  aSerial->print(F(" Command=0x"));
1759  aSerial->print(aIRDataPtr->command, HEX);
1760 
1761 #if defined(DECODE_DISTANCE_WIDTH)
1762  }
1763 #endif
1764 
1765  /*
1766  * Print number of bits
1767  */
1768  aSerial->print(' ');
1769  aSerial->print(aIRDataPtr->numberOfBits, DEC);
1770  aSerial->print(F(" bits"));
1771 
1772  if (aIRDataPtr->flags & IRDATA_FLAGS_IS_MSB_FIRST) {
1773  aSerial->print(F(" MSB first"));
1774  } else {
1775  aSerial->print(F(" LSB first"));
1776  }
1777 
1778  /*
1779  * Print gap and duration, in order to be able to compute the repeat period of the protocol by adding the next gap time
1780  */
1782  aSerial->print(' ');
1783  if (aIRDataPtr->flags & IRDATA_FLAGS_IS_AUTO_REPEAT) {
1784  aSerial->print(F("Auto-"));
1785  }
1786  aSerial->print(F("Repeat"));
1787  }
1788  aSerial->println();
1789 }
1790 
1800 void printIRResultShort(Print *aSerial, IRData *aIRDataPtr, bool aPrintRepeatGap) {
1801  // DEPRECATED
1802 
1803  (void) aPrintRepeatGap;
1804  printIRDataShort(aSerial, aIRDataPtr);
1805 }
1806 void printIRResultShort(Print *aSerial, IRData *aIRDataPtr) {
1807  // DEPRECATED
1808 
1809  if (aIRDataPtr->flags & IRDATA_FLAGS_WAS_OVERFLOW) {
1810  aSerial->println(F("Overflow"));
1811  return;
1812  }
1813  aSerial->print(F("Protocol="));
1814  aSerial->print(getProtocolString(aIRDataPtr->protocol));
1815  if (aIRDataPtr->protocol == UNKNOWN) {
1816 #if defined(DECODE_HASH)
1817  aSerial->print(F(" Hash=0x"));
1818 #if (__INT_WIDTH__ < 32)
1819  aSerial->print(aIRDataPtr->decodedRawData, HEX);
1820 #else
1821  PrintULL::print(aSerial,aIRDataPtr->decodedRawData, HEX);
1822 #endif
1823 
1824 #endif
1825 #if !defined(DISABLE_CODE_FOR_RECEIVER)
1826  aSerial->print(' ');
1827  aSerial->print((aIRDataPtr->rawlen + 1) / 2, DEC);
1828  aSerial->println(F(" bits (incl. gap and start) received"));
1829 #endif
1830  } else {
1831 #if defined(DECODE_DISTANCE_WIDTH)
1832  if (aIRDataPtr->protocol != PULSE_DISTANCE && aIRDataPtr->protocol != PULSE_WIDTH) {
1833 #endif
1834  /*
1835  * New decoders have address and command
1836  */
1837  aSerial->print(F(" Address=0x"));
1838  aSerial->print(aIRDataPtr->address, HEX);
1839 
1840  aSerial->print(F(" Command=0x"));
1841  aSerial->print(aIRDataPtr->command, HEX);
1842 
1843  if (aIRDataPtr->flags & IRDATA_FLAGS_EXTRA_INFO) {
1844  aSerial->print(F(" Extra=0x"));
1845  aSerial->print(aIRDataPtr->extra, HEX);
1846  }
1847 
1848  if (aIRDataPtr->flags & IRDATA_FLAGS_PARITY_FAILED) {
1849  aSerial->print(F(" Parity fail"));
1850  }
1851 
1852  if (aIRDataPtr->flags & IRDATA_FLAGS_TOGGLE_BIT) {
1853  aSerial->print(F(" Toggle=1"));
1854  }
1855 #if defined(DECODE_DISTANCE_WIDTH)
1856  }
1857 #endif
1858 
1859  /*
1860  * Print raw data
1861  */
1862  if (!(aIRDataPtr->flags & IRDATA_FLAGS_IS_REPEAT) || aIRDataPtr->decodedRawData != 0) {
1863  aSerial->print(F(" Raw-Data=0x"));
1864 #if (__INT_WIDTH__ < 32)
1865  aSerial->print(aIRDataPtr->decodedRawData, HEX);
1866 #else
1867  PrintULL::print(aSerial, aIRDataPtr->decodedRawData, HEX);
1868 #endif
1869  /*
1870  * Print number of bits processed
1871  */
1872  aSerial->print(' ');
1873  aSerial->print(aIRDataPtr->numberOfBits, DEC);
1874  aSerial->print(F(" bits"));
1875 
1876  if (aIRDataPtr->flags & IRDATA_FLAGS_IS_MSB_FIRST) {
1877  aSerial->print(F(" MSB first"));
1878  } else {
1879  aSerial->print(F(" LSB first"));
1880  }
1881  }
1882 
1883  /*
1884  * Print gap and duration, in order to be able to compute the repeat period of the protocol by adding the next gap time
1885  */
1887  aSerial->print(' ');
1888  if (aIRDataPtr->flags & IRDATA_FLAGS_IS_AUTO_REPEAT) {
1889  aSerial->print(F("Auto-"));
1890  }
1891  aSerial->print(F("Repeat"));
1892  }
1893 #if !defined(DISABLE_CODE_FOR_RECEIVER)
1894  aSerial->print(F(" Gap="));
1895  aSerial->print((uint32_t) aIRDataPtr->initialGapTicks * MICROS_PER_TICK);
1896  aSerial->println(F("us"));
1897 #else
1898  aSerial->println();
1899 #endif
1900  }
1901 }
1902 
1903 void IRrecv::printDistanceWidthTimingInfo(Print *aSerial, DistanceWidthTimingInfoStruct *aDistanceWidthTimingInfo) {
1904  aSerial->print(aDistanceWidthTimingInfo->HeaderMarkMicros);
1905  aSerial->print(F(", "));
1906  aSerial->print(aDistanceWidthTimingInfo->HeaderSpaceMicros);
1907  aSerial->print(F(", "));
1908  aSerial->print(aDistanceWidthTimingInfo->OneMarkMicros);
1909  aSerial->print(F(", "));
1910  aSerial->print(aDistanceWidthTimingInfo->OneSpaceMicros);
1911  aSerial->print(F(", "));
1912  aSerial->print(aDistanceWidthTimingInfo->ZeroMarkMicros);
1913  aSerial->print(F(", "));
1914  aSerial->print(aDistanceWidthTimingInfo->ZeroSpaceMicros);
1915 }
1916 
1917 /*
1918  * Get maximum of mark ticks in rawDataPtr.
1919  * Skip leading start and trailing stop bit.
1920  */
1922  uint8_t tMaximumTick = 0;
1923  for (IRRawlenType i = 3; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1924  auto tTick = irparams.rawbuf[i];
1925  if (tMaximumTick < tTick) {
1926  tMaximumTick = tTick;
1927  }
1928  }
1929  return tMaximumTick;
1930 }
1932  uint8_t tMaximumTick = 0;
1933  for (IRRawlenType i = 4; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1934  auto tTick = irparams.rawbuf[i];
1935  if (tMaximumTick < tTick) {
1936  tMaximumTick = tTick;
1937  }
1938  }
1939  return tMaximumTick;
1940 }
1941 
1942 /*
1943  * The optimizing compiler internally generates this function, if getMaximumMarkTicksFromRawData() and getMaximumSpaceTicksFromRawData() is used.
1944  */
1945 uint8_t IRrecv::getMaximumTicksFromRawData(bool aSearchSpaceInsteadOfMark) {
1946  uint8_t tMaximumTick = 0;
1947  IRRawlenType i;
1948  if (aSearchSpaceInsteadOfMark) {
1949  i = 4;
1950  } else {
1951  i = 3;
1952  }
1953  for (; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1954  auto tTick = irparams.rawbuf[i];
1955  if (tMaximumTick < tTick) {
1956  tMaximumTick = tTick;
1957  }
1958  }
1959  return tMaximumTick;
1960 }
1961 
1963  uint16_t tSumOfDurationTicks = 0;
1964 
1965  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
1966  tSumOfDurationTicks += irparams.rawbuf[i];
1967  }
1968  return tSumOfDurationTicks * (uint32_t) MICROS_PER_TICK;
1969 }
1970 
1979 void IRrecv::printIRSendUsage(Print *aSerial) {
1983 #if defined(DECODE_DISTANCE_WIDTH)
1984  uint_fast8_t tNumberOfArrayData = 0;
1986 # if __INT_WIDTH__ < 32
1987  aSerial->print(F("Send on a 8 bit platform with: "));
1988  tNumberOfArrayData = ((decodedIRData.numberOfBits - 1) / 32) + 1;
1989  if(tNumberOfArrayData > 1) {
1990  aSerial->println();
1991  aSerial->print(F(" uint32_t tRawData[]={0x"));
1992 # else
1993  aSerial->print(F("Send on a 32 bit platform with: "));
1994  tNumberOfArrayData = ((decodedIRData.numberOfBits - 1) / 64) + 1;
1995  if(tNumberOfArrayData > 1) {
1996  aSerial->println();
1997  aSerial->print(F(" uint64_t tRawData[]={0x"));
1998 # endif
1999  for (uint_fast8_t i = 0; i < tNumberOfArrayData; ++i) {
2000 # if (__INT_WIDTH__ < 32)
2001  aSerial->print(decodedIRData.decodedRawDataArray[i], HEX);
2002 # else
2003  PrintULL::print(aSerial, decodedIRData.decodedRawDataArray[i], HEX);
2004 # endif
2005  if (i != tNumberOfArrayData - 1) {
2006  aSerial->print(F(", 0x"));
2007  }
2008  }
2009  aSerial->println(F("};"));
2010  aSerial->print(F(" "));
2011  }
2012  } else {
2013  aSerial->print(F("Send with: "));
2014  }
2015  aSerial->print(F("IrSender.send"));
2016 
2017 #else
2018  aSerial->print(F("Send with: IrSender.send"));
2019 #endif
2020 
2021 #if defined(DECODE_DISTANCE_WIDTH)
2023 #endif
2024  aSerial->print(getProtocolString());
2025  aSerial->print(F("(0x"));
2026 #if defined(DECODE_MAGIQUEST)
2027  if (decodedIRData.protocol == MAGIQUEST) {
2028 # if (__INT_WIDTH__ < 32)
2029  aSerial->print(decodedIRData.decodedRawData, HEX);
2030 # else
2031  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2032 # endif
2033  } else {
2034  aSerial->print(decodedIRData.address, HEX);
2035  }
2036 #else
2037  /*
2038  * New decoders have address and command
2039  */
2040  aSerial->print(decodedIRData.address, HEX);
2041 #endif
2042 
2043  aSerial->print(F(", 0x"));
2044  aSerial->print(decodedIRData.command, HEX);
2045  if (decodedIRData.protocol == SONY) {
2046  aSerial->print(F(", 2, "));
2047  aSerial->print(decodedIRData.numberOfBits);
2048  } else {
2049  aSerial->print(F(", <numberOfRepeats>"));
2050  }
2051 
2052 #if defined(DECODE_DISTANCE_WIDTH)
2053  } else {
2054  /*
2055  * Pulse distance or pulse width here
2056  */
2057  aSerial->print(F("PulseDistanceWidth"));
2058  if(tNumberOfArrayData > 1) {
2059  aSerial->print(F("FromArray(38, "));
2060  } else {
2061  aSerial->print(F("(38, "));
2062  }
2063  printDistanceWidthTimingInfo(aSerial, &decodedIRData.DistanceWidthTimingInfo);
2064 
2065  if(tNumberOfArrayData > 1) {
2066  aSerial->print(F(", &tRawData[0], "));
2067  } else {
2068  aSerial->print(F(", 0x"));
2069 # if (__INT_WIDTH__ < 32)
2070  aSerial->print(decodedIRData.decodedRawData, HEX);
2071 # else
2072  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2073 # endif
2074  aSerial->print(F(", "));
2075  }
2076  aSerial->print(decodedIRData.numberOfBits); // aNumberOfBits
2077  aSerial->print(F(", PROTOCOL_IS_"));
2078 
2080  aSerial->print('M');
2081  } else {
2082  aSerial->print('L');
2083  }
2084  aSerial->print(F("SB_FIRST, <RepeatPeriodMillis>, <numberOfRepeats>"));
2085  }
2086 #endif
2087 #if defined(DECODE_PANASONIC) || defined(DECODE_KASEIKYO) || defined(DECODE_RC6)
2089  aSerial->print(F(", 0x"));
2090  aSerial->print(decodedIRData.extra, HEX);
2091  }
2092 #endif
2093  aSerial->print(F(");"));
2094  aSerial->println();
2095  }
2096 }
2097 
2104 void IRrecv::printIRResultMinimal(Print *aSerial) {
2105  aSerial->print(F("P="));
2106  aSerial->print(decodedIRData.protocol);
2107  if (decodedIRData.protocol == UNKNOWN) {
2108 #if defined(DECODE_HASH)
2109  aSerial->print(F(" #=0x"));
2110 # if (__INT_WIDTH__ < 32)
2111  aSerial->print(decodedIRData.decodedRawData, HEX);
2112 # else
2113  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2114 # endif
2115 #endif
2116  aSerial->print(' ');
2117  aSerial->print((decodedIRData.rawlen + 1) / 2);
2118  aSerial->println(F(" bits received"));
2119  } else {
2120  /*
2121  * New decoders have address and command
2122  */
2123  aSerial->print(F(" A=0x"));
2124  aSerial->print(decodedIRData.address, HEX);
2125 
2126  aSerial->print(F(" C=0x"));
2127  aSerial->print(decodedIRData.command, HEX);
2128 
2129  aSerial->print(F(" Raw=0x"));
2130 #if (__INT_WIDTH__ < 32)
2131  aSerial->print(decodedIRData.decodedRawData, HEX);
2132 #else
2133  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2134 #endif
2135 
2137  aSerial->print(F(" R"));
2138  }
2139  }
2140 }
2141 
2142 /*
2143  * Not used yet
2144  */
2145 void IRrecv::printIRDuration(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2146  uint16_t tSumOfDurationTicks = 0;
2147  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2148  tSumOfDurationTicks += irparams.rawbuf[i];
2149  }
2150  aSerial->print(F("Duration="));
2151  if (aOutputMicrosecondsInsteadOfTicks) {
2152  aSerial->print((uint32_t) tSumOfDurationTicks * MICROS_PER_TICK);
2153  aSerial->println(F("us"));
2154 
2155  } else {
2156  aSerial->print(tSumOfDurationTicks);
2157  aSerial->println(F(" ticks"));
2158  }
2159 }
2160 
2167 void IRrecv::printIRResultRawFormatted(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2168 
2169 // Print Raw data
2170  aSerial->print(F("rawData["));
2171  aSerial->print(decodedIRData.rawlen);
2172  aSerial->println(F("]: "));
2173 
2174  /*
2175  * Print initial gap
2176  */
2177  aSerial->print(F(" -"));
2178  if (aOutputMicrosecondsInsteadOfTicks) {
2179  aSerial->println((uint32_t) decodedIRData.initialGapTicks * MICROS_PER_TICK);
2180  } else {
2181  aSerial->println(decodedIRData.initialGapTicks);
2182  }
2183 
2184 // Newline is printed every 8. value, if tCounterForNewline % 8 == 0
2185  uint_fast8_t tCounterForNewline = 6; // first newline is after the 2 values of the start bit
2186 
2187 // check if we have a protocol with no or 8 start bits
2188 #if defined(DECODE_DENON) || defined(DECODE_MAGIQUEST)
2189  if (
2190 # if defined(DECODE_DENON)
2192 # endif
2193 # if defined(DECODE_MAGIQUEST)
2195 # endif
2196  false) {
2197  tCounterForNewline = 0; // no or 8 start bits
2198  }
2199 #endif
2200 
2201  uint32_t tDuration;
2202  uint16_t tSumOfDurationTicks = 0;
2203  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2204  auto tCurrentTicks = irparams.rawbuf[i];
2205  if (aOutputMicrosecondsInsteadOfTicks) {
2206  tDuration = tCurrentTicks * MICROS_PER_TICK;
2207  } else {
2208  tDuration = tCurrentTicks;
2209  }
2210  tSumOfDurationTicks += tCurrentTicks; // compute length of protocol frame
2211 
2212  if (!(i & 1)) { // even
2213  aSerial->print('-');
2214  } else { // odd
2215  aSerial->print(F(" +"));
2216  }
2217 
2218  // padding only for big values
2219  if (aOutputMicrosecondsInsteadOfTicks && tDuration < 1000) {
2220  aSerial->print(' ');
2221  }
2222  if (aOutputMicrosecondsInsteadOfTicks && tDuration < 100) {
2223  aSerial->print(' ');
2224  }
2225  if (tDuration < 10) {
2226  aSerial->print(' ');
2227  }
2228  aSerial->print(tDuration);
2229 
2230  if ((i & 1) && (i + 1) < decodedIRData.rawlen) {
2231  aSerial->print(','); //',' not required for last one
2232  }
2233 
2234  tCounterForNewline++;
2235  if ((tCounterForNewline % 8) == 0) {
2236  aSerial->println();
2237  }
2238  }
2239 
2240  aSerial->println();
2241  aSerial->print(F("Duration="));
2242  if (aOutputMicrosecondsInsteadOfTicks) {
2243  aSerial->print((uint32_t) tSumOfDurationTicks * MICROS_PER_TICK);
2244  aSerial->println(F("us"));
2245 
2246  } else {
2247  aSerial->print(tSumOfDurationTicks);
2248  aSerial->println(F(" ticks"));
2249  }
2250  aSerial->println();
2251 
2252 }
2253 
2266 void IRrecv::compensateAndPrintIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2267  printIRResultAsCArray(aSerial, aOutputMicrosecondsInsteadOfTicks, true);
2268 }
2269 void IRrecv::printIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks, bool aDoCompensate) {
2270 // Start declaration
2271  if (aOutputMicrosecondsInsteadOfTicks) {
2272  aSerial->print(F("uint16_t rawData[")); // variable type, array name
2273  } else {
2274  aSerial->print(F("uint8_t rawTicks[")); // variable type, array name
2275  }
2276 
2277  aSerial->print(decodedIRData.rawlen - 1); // array size
2278  aSerial->print(F("] = {")); // Start declaration
2279 
2280 // Dump data
2281  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2282  uint32_t tDuration = irparams.rawbuf[i] * MICROS_PER_TICK;
2283 
2284  if (aDoCompensate) {
2285  if (i & 1) {
2286  // Mark
2287  tDuration -= MARK_EXCESS_MICROS;
2288  } else {
2289  tDuration += MARK_EXCESS_MICROS;
2290  }
2291  }
2292 
2293  if (aOutputMicrosecondsInsteadOfTicks) {
2294  aSerial->print(tDuration);
2295  } else {
2296  unsigned int tTicks = (tDuration + (MICROS_PER_TICK / 2)) / MICROS_PER_TICK;
2297  /*
2298  * Clip to 8 bit value
2299  */
2300  tTicks = (tTicks > UINT8_MAX) ? UINT8_MAX : tTicks;
2301  aSerial->print(tTicks);
2302  }
2303  if (i + 1 < decodedIRData.rawlen) aSerial->print(','); // ',' not required on last one
2304  if (!(i & 1)) aSerial->print(' ');
2305  }
2306 
2307 // End declaration
2308  aSerial->print(F("};")); //
2309 
2310 // Comment
2311  aSerial->print(F(" // "));
2312  printIRResultShort(aSerial);
2313 
2314 // Newline
2315  aSerial->println();
2316 }
2317 
2328 
2329 // Store data, skip leading space#
2330  IRRawlenType i;
2331  for (i = 1; i < decodedIRData.rawlen; i++) {
2332  uint32_t tDuration = irparams.rawbuf[i] * MICROS_PER_TICK;
2333  if (i & 1) {
2334  // Mark
2335  tDuration -= MARK_EXCESS_MICROS;
2336  } else {
2337  tDuration += MARK_EXCESS_MICROS;
2338  }
2339 
2340  unsigned int tTicks = (tDuration + (MICROS_PER_TICK / 2)) / MICROS_PER_TICK;
2341  *aArrayPtr = (tTicks > UINT8_MAX) ? UINT8_MAX : tTicks; // we store it in an 8 bit array
2342  aArrayPtr++;
2343  }
2344 }
2345 
2354 // Now dump "known" codes
2355  if (decodedIRData.protocol != UNKNOWN) {
2356 
2357  /*
2358  * New decoders have address and command
2359  */
2360  aSerial->print(F("uint16_t"));
2361  aSerial->print(F(" address = 0x"));
2362  aSerial->print(decodedIRData.address, HEX);
2363  aSerial->println(';');
2364 
2365  aSerial->print(F("uint16_t"));
2366  aSerial->print(F(" command = 0x"));
2367  aSerial->print(decodedIRData.command, HEX);
2368  aSerial->println(';');
2369 
2370  // All protocols have raw data
2371 #if __INT_WIDTH__ < 32
2372  aSerial->print(F("uint32_t rawData = 0x"));
2373 #else
2374  aSerial->print(F("uint64_t rawData = 0x"));
2375 #endif
2376 #if (__INT_WIDTH__ < 32)
2377  aSerial->print(decodedIRData.decodedRawData, HEX);
2378 #else
2379  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2380 #endif
2381  aSerial->println(';');
2382  aSerial->println();
2383  }
2384 }
2385 
2386 #if defined(__AVR__)
2387 const __FlashStringHelper* IRrecv::getProtocolString() {
2388 // call no class function with same name
2390 }
2391 #else
2393  // call no class function with same name
2395  }
2396 #endif
2397 
2398 /**********************************************************************************************************************
2399  * The OLD and DEPRECATED decode function with parameter aResults, kept for backward compatibility to old 2.0 tutorials
2400  * This function calls the old MSB first decoders and fills only the 3 variables:
2401  * aResults->value
2402  * aResults->bits
2403  * aResults->decode_type
2404  **********************************************************************************************************************/
2406 
2408  return false;
2409  }
2410 
2411 // copy for usage by legacy programs
2412  aResults->rawbuf[0] = irparams.initialGapTicks;
2413  for (int i = 1; i < RAW_BUFFER_LENGTH; ++i) {
2414  aResults->rawbuf[i] = irparams.rawbuf[i]; // copy 8 bit array into a 16 bit array
2415  }
2416  aResults->rawlen = irparams.rawlen;
2417  if (irparams.OverflowFlag) {
2418  // Copy overflow flag to decodedIRData.flags
2419  irparams.OverflowFlag = false;
2420  irparams.rawlen = 0; // otherwise we have OverflowFlag again at next ISR call
2421  IR_DEBUG_PRINTLN(F("Overflow happened"));
2422  }
2423  aResults->overflow = irparams.OverflowFlag;
2424  aResults->value = 0;
2425 
2427 
2428 #if defined(DECODE_NEC)
2429  IR_DEBUG_PRINTLN(F("Attempting old NEC decode"));
2430  if (decodeNECMSB(aResults)) {
2431  return true;
2432  }
2433 #endif
2434 
2435 #if defined(DECODE_SONY)
2436  IR_DEBUG_PRINTLN(F("Attempting old Sony decode"));
2437  if (decodeSonyMSB(aResults)) {
2438  return true;
2439  }
2440 #endif
2441 
2442 #if defined(DECODE_RC5)
2443  IR_DEBUG_PRINTLN(F("Attempting RC5 decode"));
2444  if (decodeRC5()) {
2445  aResults->bits = decodedIRData.numberOfBits;
2446  aResults->value = decodedIRData.decodedRawData;
2447  aResults->decode_type = RC5;
2448 
2449  return true;
2450  }
2451 #endif
2452 
2453 #if defined(DECODE_RC6)
2454  IR_DEBUG_PRINTLN(F("Attempting RC6 decode"));
2455  if (decodeRC6()) {
2456  aResults->bits = decodedIRData.numberOfBits;
2457  aResults->value = decodedIRData.decodedRawData;
2458  aResults->decode_type = RC6;
2459  return true;
2460  }
2461 #endif
2462 
2463 // Removed bool IRrecv::decodePanasonicMSB(decode_results *aResults) since implementations was wrong (wrong length), and nobody recognized it
2464 
2465 #if defined(DECODE_LG)
2466  IR_DEBUG_PRINTLN(F("Attempting old LG decode"));
2467  if (decodeLGMSB(aResults)) {return true;}
2468 #endif
2469 
2470 #if defined(DECODE_JVC)
2471  IR_DEBUG_PRINTLN(F("Attempting old JVC decode"));
2472  if (decodeJVCMSB(aResults)) {
2473  return true;
2474  }
2475 #endif
2476 
2477 #if defined(DECODE_SAMSUNG)
2478  IR_DEBUG_PRINTLN(F("Attempting old SAMSUNG decode"));
2479  if (decodeSAMSUNG(aResults)) {
2480  return true;
2481  }
2482 #endif
2483 
2484 #if defined(DECODE_DENON)
2485  IR_DEBUG_PRINTLN(F("Attempting old Denon decode"));
2486  if (decodeDenonOld(aResults)) {
2487  return true;
2488  }
2489 #endif
2490 
2491 // decodeHash returns a hash on any input.
2492 // Thus, it needs to be last in the list.
2493 // If you add any decodes, add them before this.
2494  if (decodeHashOld(aResults)) {
2495  return true;
2496  }
2497 // Throw away and start over
2498  resume();
2499  return false;
2500 }
2501 
2503 #if defined(_IR_MEASURE_TIMING)
2504 #undef _IR_MEASURE_TIMING
2505 #endif
2506 #if defined(LOCAL_TRACE)
2507 #undef LOCAL_TRACE
2508 #endif
2509 #if defined(LOCAL_DEBUG)
2510 #undef LOCAL_DEBUG
2511 #endif
2512 #endif // _IR_RECEIVE_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRremoteInt.h:152
timerConfigForReceive
void timerConfigForReceive()
Configures the timer to be able to generate the receive sample interrupt, which consumes a small amou...
Definition: IRTimer.hpp:112
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:207
IRrecv::decodeHash
bool decodeHash()
Decodes an arbitrary IR code to a 32-bit value.
Definition: IRReceive.hpp:1236
decode_results
Results returned from old decoders !!!deprecated!!!
Definition: IRremoteInt.h:208
digitalReadFast
#define digitalReadFast
Definition: digitalWriteFast.h:399
DistanceWidthTimingInfoStruct::HeaderMarkMicros
uint16_t HeaderMarkMicros
Definition: IRProtocol.h:135
decode_results::rawbuf
uint16_t * rawbuf
Definition: IRremoteInt.h:219
IRrecv::decodePulseDistanceWidthData
void decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Decode pulse distance protocols for PulseDistanceWidthProtocolConstants.
Definition: IRReceive.hpp:1081
setLEDFeedbackPin
void setLEDFeedbackPin(uint8_t aFeedbackLEDPin)
Definition: IRFeedbackLED.hpp:53
setFeedbackLED
void setFeedbackLED(bool aSwitchLedOn)
Flash LED while receiving or sending IR data.
Definition: IRFeedbackLED.hpp:82
IRrecv::stop
void stop()
Disables the timer for IR reception.
Definition: IRReceive.hpp:468
IRrecv::lastDecodedProtocol
decode_type_t lastDecodedProtocol
Definition: IRremoteInt.h:412
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRremoteInt.h:161
IRrecv::printDistanceWidthTimingInfo
void printDistanceWidthTimingInfo(Print *aSerial, DistanceWidthTimingInfoStruct *aDistanceWidthTimingInfo)
Definition: IRReceive.hpp:1903
RECORD_GAP_TICKS
#define RECORD_GAP_TICKS
Minimum gap between IR transmissions, in MICROS_PER_TICK.
Definition: IRremote.hpp:129
IRrecv::disableIRIn
void disableIRIn()
Alias for stop().
Definition: IRReceive.hpp:482
IRrecv::decodePulseDistanceWidthData_P
void decodePulseDistanceWidthData_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Definition: IRReceive.hpp:1117
IRRawlenType
unsigned int IRRawlenType
Definition: IRremoteInt.h:87
IRrecv::checkHeader_P
bool checkHeader_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM)
Definition: IRReceive.hpp:1309
IRrecv::enableIRIn
void enableIRIn()
Alias for start().
Definition: IRReceive.hpp:418
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:105
pinModeFast
#define pinModeFast
Definition: digitalWriteFast.h:383
IRrecv::checkForRecordGapsMicros
bool checkForRecordGapsMicros(Print *aSerial)
Checks if protocol is not detected and detected space between two transmissions is smaller than known...
Definition: IRReceive.hpp:1513
digitalWriteFast
#define digitalWriteFast
Definition: digitalWriteFast.h:347
IRrecv::registerReceiveCompleteCallback
void registerReceiveCompleteCallback(void(*aReceiveCompleteCallbackFunction)(void))
Sets the function to call if a complete protocol frame has arrived.
Definition: IRReceive.hpp:374
IRrecv
Definition: IRremoteInt.h:226
DECODE_MAGIQUEST
#define DECODE_MAGIQUEST
Definition: IRProtocol.h:70
IRrecv::decodeDistanceWidth
bool decodeDistanceWidth()
Definition: ir_DistanceWidthProtocol.hpp:202
SONY
@ SONY
Definition: IRProtocol.h:118
PULSE_WIDTH
@ PULSE_WIDTH
Definition: IRProtocol.h:95
decode_results::overflow
bool overflow
Definition: IRremoteInt.h:221
IRDATA_FLAGS_IS_REPEAT
#define IRDATA_FLAGS_IS_REPEAT
The gap between the preceding frame is as smaller than the maximum gap expected for a repeat....
Definition: IRProtocol.h:147
decode_type_t
decode_type_t
An enum consisting of all supported formats.
Definition: IRProtocol.h:93
IRrecv::printIRResultRawFormatted
void printIRResultRawFormatted(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks=true)
Dump out the timings in IrReceiver.irparams.rawbuf[] array 8 values per line.
Definition: IRReceive.hpp:2167
PulseDistanceWidthProtocolConstants::ProtocolIndex
decode_type_t ProtocolIndex
Definition: IRProtocol.h:162
IRrecv::restartAfterSend
void restartAfterSend()
Restarts receiver after send.
Definition: IRReceive.hpp:459
IRrecv::IRrecv
IRrecv()
Instantiate the IRrecv class.
Definition: IRReceive.hpp:76
sBiphaseDecodeRawbuffOffset
uint_fast8_t sBiphaseDecodeRawbuffOffset
Definition: IRReceive.hpp:1129
TICKS_LOW
#define TICKS_LOW(us)
Definition: IRremoteInt.h:489
sMicrosAtLastStopTimer
unsigned long sMicrosAtLastStopTimer
Definition: IRReceive.hpp:70
DistanceWidthTimingInfoStruct::OneSpaceMicros
uint16_t OneSpaceMicros
Definition: IRProtocol.h:138
IRrecv::printIRResultShort
bool printIRResultShort(Print *aSerial, bool aPrintRepeatGap, bool aCheckForRecordGapsMicros) __attribute__((deprecated("Remove second parameter
Function to print values and flags of IrReceiver.decodedIRData in one line.
Definition: IRReceive.hpp:1622
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:148
decode_results::bits
uint8_t bits
Definition: IRremoteInt.h:214
decode_results::decode_type
decode_type_t decode_type
Definition: IRremoteInt.h:211
IRData::decodedRawData
IRRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send<protocol>Raw functions.
Definition: IRremoteInt.h:155
matchTicks
bool matchTicks(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Match function WITHOUT compensating for marks exceeded or spaces shortened by demodulator hardware.
Definition: IRReceive.hpp:1348
irparams_struct::ReceiveCompleteCallbackFunction
void(* ReceiveCompleteCallbackFunction)(void)
The function to call if a protocol message has arrived, i.e. StateForISR changed to IR_REC_STATE_STOP...
Definition: IRremoteInt.h:135
PULSE_DISTANCE
@ PULSE_DISTANCE
Definition: IRProtocol.h:96
IRrecv::begin
void begin(uint_fast8_t aReceivePin, bool aEnableLEDFeedback=false, uint_fast8_t aFeedbackLEDPin=USE_DEFAULT_FEEDBACK_LED_PIN)
Initializes the receive and feedback pin.
Definition: IRReceive.hpp:316
IRrecv::checkForRepeatSpaceTicksAndSetFlag
void checkForRepeatSpaceTicksAndSetFlag(uint16_t aMaximumRepeatSpaceTicks)
Definition: IRReceive.hpp:1333
IR_DEBUG_PRINT
#define IR_DEBUG_PRINT(...)
If DEBUG, print the arguments, otherwise do nothing.
Definition: IRremoteInt.h:186
RECORD_GAP_MICROS_WARNING_THRESHOLD
#define RECORD_GAP_MICROS_WARNING_THRESHOLD
Threshold for warnings at printIRResult*() to report about changing the RECORD_GAP_MICROS value to a ...
Definition: IRremote.hpp:125
IRrecv::decodeSonyMSB
bool decodeSonyMSB(decode_results *aResults)
Definition: ir_Sony.hpp:148
IRrecv::decodeSony
bool decodeSony()
Definition: ir_Sony.hpp:109
matchSpace
bool matchSpace(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for spaces shortened by demodulator hardware.
Definition: IRReceive.hpp:1459
DistanceWidthTimingInfoStruct::ZeroMarkMicros
uint16_t ZeroMarkMicros
Definition: IRProtocol.h:139
IR_TRACE_PRINT
#define IR_TRACE_PRINT(...)
Definition: IRremoteInt.h:197
IRrecv::read
IRData * read()
Returns pointer to IrReceiver.decodedIRData if IR receiver data is available, else nullptr.
Definition: IRReceive.hpp:550
IRrecv::getBiphaselevel
uint_fast8_t getBiphaselevel()
Gets the level of one time interval (aBiphaseTimeUnit) at a time from the raw buffer.
Definition: IRReceive.hpp:1156
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:123
sBiphaseCurrentTimingIntervals
uint16_t sBiphaseCurrentTimingIntervals
Definition: IRReceive.hpp:1130
timerDisableReceiveInterrupt
void timerDisableReceiveInterrupt()
Disables the receive sample timer interrupt.
Definition: IRTimer.hpp:124
IRrecv::decodeLGMSB
bool decodeLGMSB(decode_results *aResults)
Definition: ir_LG.hpp:284
PulseDistanceWidthProtocolConstants::Flags
uint8_t Flags
Definition: IRProtocol.h:165
PROTOCOL_IS_PULSE_WIDTH_MASK
#define PROTOCOL_IS_PULSE_WIDTH_MASK
Definition: IRProtocol.h:176
DECODE_DENON
#define DECODE_DENON
Definition: IRProtocol.h:56
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:149
decode_results::value
uint32_t value
Definition: IRremoteInt.h:213
DistanceWidthTimingInfoStruct
Definition: IRProtocol.h:134
MATCH_SPACE
bool MATCH_SPACE(uint16_t measured_ticks, uint16_t desired_us)
Definition: IRReceive.hpp:1497
IRrecv::decodeSAMSUNG
bool decodeSAMSUNG(decode_results *aResults)
Definition: ir_Samsung.hpp:364
IRrecv::decodeBangOlufsen
bool decodeBangOlufsen()
Definition: ir_BangOlufsen.hpp:298
IRrecv::decodeLegoPowerFunctions
bool decodeLegoPowerFunctions()
Definition: ir_Lego.hpp:150
irparams_struct::OverflowFlag
bool OverflowFlag
Raw buffer OverflowFlag occurred.
Definition: IRremoteInt.h:137
IRrecv::decodeFAST
bool decodeFAST()
Definition: ir_FAST.hpp:98
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:161
printIRResultShort
void printIRResultShort(Print *aSerial, IRData *aIRDataPtr, bool aPrintRepeatGap)
Deprecated static function to be able to print data to send or copied received data.
Definition: IRReceive.hpp:1800
FeedbackLEDControlStruct::LedFeedbackEnabled
bool LedFeedbackEnabled
Disabled for receive at default. Feedback for send is always enabled and can be disabled by NO_LED_SE...
Definition: IRFeedbackLED.hpp:44
IRrecv::getProtocolString
const char * getProtocolString()
Definition: IRReceive.hpp:2392
irparams_struct::rawlen
IRRawlenType rawlen
counter of entries in rawbuf
Definition: IRremoteInt.h:138
IRrecv::decodedIRData
IRData decodedIRData
Definition: IRremoteInt.h:409
IRData
Data structure for the user application, available as decodedIRData.
Definition: IRremoteInt.h:150
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:152
FNV_PRIME_32
#define FNV_PRIME_32
used for decodeHash()
Definition: IRReceive.hpp:1201
IRrecv::compensateAndPrintIRResultAsCArray
void compensateAndPrintIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks=true)
Dump out the IrReceiver.irparams.rawbuf[] to be used as C definition for sendRaw().
Definition: IRReceive.hpp:2266
IRrecv::decodeSamsung
bool decodeSamsung()
Definition: ir_Samsung.hpp:273
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRremoteInt.h:162
IRDATA_FLAGS_IS_PROTOCOL_WITH_DIFFERENT_REPEAT
#define IRDATA_FLAGS_IS_PROTOCOL_WITH_DIFFERENT_REPEAT
Here we have a repeat of type NEC2 or SamsungLG.
Definition: IRProtocol.h:153
IRrecv::printIRResultMinimal
void printIRResultMinimal(Print *aSerial)
Function to print protocol number, address, command, raw data and repeat flag of IrReceiver....
Definition: IRReceive.hpp:2104
DistanceWidthTimingInfoStruct::OneMarkMicros
uint16_t OneMarkMicros
Definition: IRProtocol.h:137
IRDATA_FLAGS_WAS_OVERFLOW
#define IRDATA_FLAGS_WAS_OVERFLOW
irparams.rawlen is set to 0 in this case to avoid endless OverflowFlag.
Definition: IRProtocol.h:154
MATCH
bool MATCH(uint16_t measured_ticks, uint16_t desired_us)
Definition: IRReceive.hpp:1403
IRrecv::checkHeader
bool checkHeader(PulseDistanceWidthProtocolConstants *aProtocolConstants)
Definition: IRReceive.hpp:1290
sBiphaseUsedTimingIntervals
uint_fast8_t sBiphaseUsedTimingIntervals
Definition: IRReceive.hpp:1131
IRrecv::compare
uint_fast8_t compare(uint16_t oldval, uint16_t newval)
Compare two (tick) values for Hash decoder Use a tolerance of 20% to enable e.g.
Definition: IRReceive.hpp:1209
IRrecv::printActiveIRProtocols
static void printActiveIRProtocols(Print *aSerial)
Definition: IRReceive.hpp:1538
printActiveIRProtocols
void printActiveIRProtocols(Print *aSerial)
Definition: IRReceive.hpp:1546
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRremoteInt.h:153
IR_REC_STATE_STOP
#define IR_REC_STATE_STOP
Definition: IRremoteInt.h:119
IR_REC_STATE_MARK
#define IR_REC_STATE_MARK
Definition: IRremoteInt.h:117
IRrecv::printIRDuration
void printIRDuration(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks)
Definition: IRReceive.hpp:2145
IRReceiveTimerInterruptHandler
void IRReceiveTimerInterruptHandler()
Definition: IRReceive.hpp:282
IRrecv::getMaximumTicksFromRawData
uint8_t getMaximumTicksFromRawData(bool aSearchSpaceInsteadOfMark)
Definition: IRReceive.hpp:1945
IRrecv::restartTimer
void restartTimer()
Definition: IRReceive.hpp:402
IRrecv::restartTimerWithTicksToAdd
void restartTimerWithTicksToAdd(uint16_t aTicksToAddToGapCounter)
Configures the timer and the state machine for IR reception.
Definition: IRReceive.hpp:444
FNV_BASIS_32
#define FNV_BASIS_32
used for decodeHash()
Definition: IRReceive.hpp:1202
IRrecv::isIdle
bool isIdle()
Returns status of reception.
Definition: IRReceive.hpp:496
sBiphaseTimeUnit
uint16_t sBiphaseTimeUnit
Definition: IRReceive.hpp:1132
timerResetInterruptPending
void timerResetInterruptPending()
timerEnableReceiveInterrupt
void timerEnableReceiveInterrupt()
Enables the receive sample timer interrupt, which consumes a small amount of CPU every 50 us.
Definition: IRTimer.hpp:117
getMarkExcessMicros
int getMarkExcessMicros()
Getter function for MARK_EXCESS_MICROS.
Definition: IRReceive.hpp:1504
matchMark
bool matchMark(uint16_t aMeasuredTicks, uint16_t aMatchValueMicros)
Compensate for marks exceeded by demodulator hardware.
Definition: IRReceive.hpp:1411
MATCH_MARK
bool MATCH_MARK(uint16_t measured_ticks, uint16_t desired_us)
Definition: IRReceive.hpp:1451
irparams_struct::TickCounterForISR
volatile uint_fast16_t TickCounterForISR
Counts 50uS ticks. The value is copied into the rawbuf array on every transition. Counting is indepen...
Definition: IRremoteInt.h:133
irparams_struct::StateForISR
volatile uint8_t StateForISR
State Machine state.
Definition: IRremoteInt.h:127
IRrecv::setReceivePin
void setReceivePin(uint_fast8_t aReceivePinNumber)
Sets / changes the receiver pin number.
Definition: IRReceive.hpp:336
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:140
DistanceWidthTimingInfoStruct::ZeroSpaceMicros
uint16_t ZeroSpaceMicros
Definition: IRProtocol.h:140
IRrecv::decodeDenonOld
bool decodeDenonOld(decode_results *aResults)
Definition: ir_Denon.hpp:292
IRRawDataType
uint32_t IRRawDataType
Definition: IRremoteInt.h:105
IRrecv::start
void start()
Start the receiving process.
Definition: IRReceive.hpp:384
IR_TRACE_PRINTLN
#define IR_TRACE_PRINTLN(...)
Definition: IRremoteInt.h:198
IRrecv::initDecodedIRData
void initDecodedIRData()
Is internally called by decode before calling decoders.
Definition: IRReceive.hpp:515
IRrecv::irparams
irparams_struct irparams
Definition: IRremoteInt.h:408
KASEIKYO
@ KASEIKYO
Definition: IRProtocol.h:106
IRrecv::lastDecodedCommand
uint16_t lastDecodedCommand
Definition: IRremoteInt.h:414
DENON
@ DENON
Definition: IRProtocol.h:98
IRDATA_FLAGS_IS_MSB_FIRST
#define IRDATA_FLAGS_IS_MSB_FIRST
Value is mainly determined by the (known) protocol.
Definition: IRProtocol.h:155
TICKS_HIGH
#define TICKS_HIGH(us)
Definition: IRremoteInt.h:490
IRrecv::decodeRC5
bool decodeRC5()
Try to decode data as RC5 protocol.
Definition: ir_RC5_RC6.hpp:158
IRrecv::getMaximumMarkTicksFromRawData
uint8_t getMaximumMarkTicksFromRawData()
Definition: IRReceive.hpp:1921
RC6A
@ RC6A
Definition: IRProtocol.h:113
IRrecv::decodeBoseWave
bool decodeBoseWave()
Definition: ir_BoseWave.hpp:64
setLEDFeedback
void setLEDFeedback(bool aEnableLEDFeedback)
Definition: IRFeedbackLED.hpp:60
IRDATA_FLAGS_TOGGLE_BIT
#define IRDATA_FLAGS_TOGGLE_BIT
Is set if RC5 or RC6 toggle bit is set.
Definition: IRProtocol.h:150
IRDATA_FLAGS_EMPTY
#define IRDATA_FLAGS_EMPTY
Definition: IRProtocol.h:146
RC5
@ RC5
Definition: IRProtocol.h:111
IRrecv::available
bool available()
Returns true if IR receiver data is available.
Definition: IRReceive.hpp:543
IRData::extra
uint16_t extra
Contains upper 16 bit of Magiquest WandID, Kaseikyo unknown vendor ID and Distance protocol (HeaderMa...
Definition: IRremoteInt.h:154
IRrecv::printIRResultAsCVariables
void printIRResultAsCVariables(Print *aSerial)
Print results as C variables to be used for sendXXX() uint16_t address = 0x44; uint16_t command = 0x1...
Definition: IRReceive.hpp:2353
PulseDistanceWidthProtocolConstants::DistanceWidthTimingInfo
DistanceWidthTimingInfoStruct DistanceWidthTimingInfo
Definition: IRProtocol.h:164
IRrecv::getMaximumSpaceTicksFromRawData
uint8_t getMaximumSpaceTicksFromRawData()
Definition: IRReceive.hpp:1931
IRrecv::decodeMagiQuest
bool decodeMagiQuest()
Definition: ir_MagiQuest.hpp:155
INPUT_MARK
#define INPUT_MARK
Sensor output for a mark ("flash")
Definition: IRremote.hpp:140
IRrecv::decode_old
bool decode_old(decode_results *aResults)
Definition: IRReceive.hpp:2405
FeedbackLEDControl
struct FeedbackLEDControlStruct FeedbackLEDControl
The feedback LED control instance.
Definition: IRFeedbackLED.hpp:47
IRrecv::decodeStrictPulseDistanceWidthData
bool decodeStrictPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, bool aMSBfirst)
Definition: IRReceive.hpp:958
IRrecv::initBiphaselevel
void initBiphaselevel(uint_fast8_t aRCDecodeRawbuffOffset, uint16_t aBiphaseTimeUnit)
Definition: IRReceive.hpp:1134
IRrecv::end
void end()
Alias for stop().
Definition: IRReceive.hpp:488
SPACE
#define SPACE
Definition: IRremoteInt.h:39
IRData::rawlen
IRRawlenType rawlen
Counter of entries in rawbuf of last received frame.
Definition: IRremoteInt.h:170
IRrecv::decodeNECMSB
bool decodeNECMSB(decode_results *aResults)
Definition: ir_NEC.hpp:338
IRrecv::decodeNEC
bool decodeNEC()
Decodes also Onkyo and Apple.
Definition: ir_NEC.hpp:237
PROTOCOL_IS_MSB_MASK
#define PROTOCOL_IS_MSB_MASK
Definition: IRProtocol.h:180
RC6
@ RC6
Definition: IRProtocol.h:112
IRrecv::decodeHashOld
bool decodeHashOld(decode_results *aResults)
Definition: IRReceive.hpp:1261
IRrecv::printIRSendUsage
void printIRSendUsage(Print *aSerial)
Function to print values and flags of IrReceiver.decodedIRData in one line.
Definition: IRReceive.hpp:1979
IRrecv::getTotalDurationOfRawData
uint32_t getTotalDurationOfRawData()
Definition: IRReceive.hpp:1962
IRrecv::decodeDenon
bool decodeDenon()
Definition: ir_Denon.hpp:169
IRrecv::decodeLG
bool decodeLG()
Definition: ir_LG.hpp:176
IRrecv::stopTimer
void stopTimer()
Definition: IRReceive.hpp:475
IRrecv::decode
bool decode()
The main decode function, attempts to decode the recently receive IR signal.
Definition: IRReceive.hpp:567
IRrecv::decodeJVC
bool decodeJVC()
Definition: ir_JVC.hpp:120
UNKNOWN
@ UNKNOWN
Definition: IRProtocol.h:94
RAW_BUFFER_LENGTH
#define RAW_BUFFER_LENGTH
The RAW_BUFFER_LENGTH determines the length of the byte buffer where the received IR timing data is s...
Definition: IRremoteInt.h:77
IRrecv::decodeKaseikyo
bool decodeKaseikyo()
Definition: ir_Kaseikyo.hpp:199
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:190
IRrecv::ReceiveInterruptHandler
void ReceiveInterruptHandler()
Definition: IRReceive.hpp:122
decode_results::rawlen
uint_fast8_t rawlen
Definition: IRremoteInt.h:220
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRremoteInt.h:151
IRrecv::decodeRC6
bool decodeRC6()
Try to decode data as RC6 protocol.
Definition: ir_RC5_RC6.hpp:450
IR_REC_STATE_SPACE
#define IR_REC_STATE_SPACE
Definition: IRremoteInt.h:118
printIRDataShort
void printIRDataShort(Print *aSerial, IRData *aIRDataPtr)
Definition: IRReceive.hpp:1745
IRrecv::resume
void resume()
Restart the ISR (Interrupt Service Routine) state machine, to enable receiving of the next IR frame.
Definition: IRReceive.hpp:504
MARK
#define MARK
Definition: IRremoteInt.h:38
DistanceWidthTimingInfoStruct::HeaderSpaceMicros
uint16_t HeaderSpaceMicros
Definition: IRProtocol.h:136
IRrecv::lastDecodedAddress
uint16_t lastDecodedAddress
Definition: IRremoteInt.h:413
IRrecv::compensateAndStoreIRResultInArray
void compensateAndStoreIRResultInArray(uint8_t *aArrayPtr)
Store the decodedIRData to be used for sendRaw().
Definition: IRReceive.hpp:2327
IrReceiver
IRrecv IrReceiver
The receiver instance.
Definition: IRReceive.hpp:64
IRData::initialGapTicks
uint16_t initialGapTicks
Contains the initial gap (pre 4.4: the value in rawbuf[0]) of the last received frame.
Definition: IRremoteInt.h:171
IRrecv::decodeWithThresholdPulseDistanceWidthData
void decodeWithThresholdPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneThresholdMicros, bool aIsPulseWidthProtocol, bool aMSBfirst)
New threshold decoder to be activated by USE_THRESHOLD_DECODER Assumes a 0 for shorter and a 1 for lo...
Definition: IRReceive.hpp:828
IR_REC_STATE_IDLE
#define IR_REC_STATE_IDLE
Definition: IRremoteInt.h:116
getProtocolString
const char * getProtocolString(decode_type_t aProtocol)
Definition: IRProtocol.hpp:98
IRrecv::printIRResultAsCArray
void printIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks=true, bool aDoCompensate=true)
Definition: IRReceive.hpp:2269
IRrecv::decodeJVCMSB
bool decodeJVCMSB(decode_results *aResults)
Definition: ir_JVC.hpp:171
SHARP
@ SHARP
Definition: IRProtocol.h:117
IRrecv::decodeWhynter
bool decodeWhynter()
Definition: ir_Others.hpp:94
irparams_struct::IRReceivePin
uint_fast8_t IRReceivePin
Pin connected to IR data from detector.
Definition: IRremoteInt.h:128
irparams_struct::initialGapTicks
uint16_t initialGapTicks
Tick counts of the length of the gap between previous and current IR frame. Pre 4....
Definition: IRremoteInt.h:139