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 #if !defined(NO_LED_RECEIVE_FEEDBACK_CODE)
54 #define LED_RECEIVE_FEEDBACK_CODE // Resolve the double negative
55 #endif
56 
64 
65 /*
66  * The control structure instance
67  */
68 //struct irparams_struct irparams; // the irparams instance
69 unsigned long sMicrosAtLastStopTimer = 0; // Used to adjust TickCounterForISR with uncounted ticks between stopTimer() and restartTimer()
70 
76  setReceivePin(0);
77 }
78 
79 IRrecv::IRrecv(uint_fast8_t aReceivePin) {
80  setReceivePin(aReceivePin);
81 }
82 
88 IRrecv::IRrecv(uint_fast8_t aReceivePin, uint_fast8_t aFeedbackLEDPin) {
89  setReceivePin(aReceivePin);
90 #if defined(LED_RECEIVE_FEEDBACK_CODE)
91  setLEDFeedbackPin(aFeedbackLEDPin);
92 #else
93  (void) aFeedbackLEDPin;
94 #endif
95 }
96 
97 /**********************************************************************************************************************
98  * Interrupt Service Routine - Called every 50 us
99  *
100  * Duration in ticks of 50 us of alternating SPACE, MARK are recorded in irparams.rawbuf array.
101  * 'rawlen' counts the number of entries recorded so far.
102  * First entry is the SPACE between transmissions.
103  *
104  * As soon as one SPACE entry gets longer than RECORD_GAP_TICKS, state switches to STOP (frame received). Timing of SPACE continues.
105  * A call of resume() switches from STOP to IDLE.
106  * As soon as first MARK arrives in IDLE, gap width is recorded and new logging starts.
107  *
108  * With digitalRead and Feedback LED
109  * 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
110  * With portInputRegister and mask and Feedback LED code commented
111  * 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
112  * => Minimal CPU frequency is 4 MHz
113  *
114  **********************************************************************************************************************/
115 #if defined(ESP8266) || defined(ESP32)
116 #pragma GCC diagnostic push
117 #pragma GCC diagnostic ignored "-Wvolatile"
118 IRAM_ATTR
119 #endif
120 
122 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
123  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
124 #endif
125 // 7 - 8.5 us for ISR body (without pushes and pops) for ATmega328 @16MHz
126 
127 #if defined(TIMER_REQUIRES_RESET_INTR_PENDING)
128  timerResetInterruptPending(); // reset TickCounterForISR interrupt flag if required (currently only for Teensy and ATmega4809)
129 #endif
130 
131 // Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on]
132 #if defined(__AVR__)
133  uint8_t tIRInputLevel = *irparams.IRReceivePinPortInputRegister & irparams.IRReceivePinMask;
134 #else
135  uint_fast8_t tIRInputLevel = (uint_fast8_t) digitalReadFast(irparams.IRReceivePin);
136 #endif
137 
138  uint_fast16_t tTickCounterForISR = irparams.TickCounterForISR;
139  /*
140  * Increase TickCounter and clip it at maximum 0xFFFF / 3.2 seconds at 50 us ticks
141  */
142  if (irparams.TickCounterForISR < UINT16_MAX) {
143  tTickCounterForISR++; // One more 50uS tick
144  irparams.TickCounterForISR = tTickCounterForISR;
145  }
146 
147  /*
148  * Due to a ESP32 compiler bug https://github.com/espressif/esp-idf/issues/1552 no switch statements are possible for ESP32
149  * So we change the code to if / else if
150  */
151 // switch (irparams.StateForISR) {
152 //
153  uint_fast8_t tStateForISR = irparams.StateForISR;
154  if (tStateForISR == IR_REC_STATE_IDLE) {
155  /*
156  * Here we are just resumed and maybe in the middle of a transmission
157  */
158  if (tIRInputLevel == INPUT_MARK) {
159  // check if we did not start in the middle of a transmission by checking the minimum length of leading space
160  if (tTickCounterForISR > RECORD_GAP_TICKS) {
161 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
162 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
163 #endif
164  /*
165  * Gap between two transmissions just ended; Record gap duration + start recording transmission
166  * Initialize all state machine variables
167  */
168  irparams.OverflowFlag = false;
169  // irparams.rawbuf[0] = irparams.TickCounterForISR;
170  // Usage of initialGapTicks enables usage of 8 bit buffer instead of 16 bit since 4.4,
171  // because the big gap value is not stored in this buffer any more
172  irparams.initialGapTicks = tTickCounterForISR;
173  irparams.rawlen = 1;
175  } // otherwise stay in idle state
176  irparams.TickCounterForISR = 0; // reset counter in both cases
177  }
178 
179  } else if (tStateForISR == IR_REC_STATE_MARK) {
180  // Timing mark here, rawlen is even
181  if (tIRInputLevel != INPUT_MARK) {
182  /*
183  * Mark ended here. Record mark time in rawbuf array
184  */
185 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
186 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
187 #endif
188 #if RECORD_GAP_TICKS <= 400
189  if (tTickCounterForISR > UINT8_MAX) {
190  tTickCounterForISR = UINT8_MAX;
191  }
192 #endif
193  irparams.rawbuf[irparams.rawlen++] = tTickCounterForISR; // record mark
195  irparams.TickCounterForISR = 0; // This resets the tick counter also at end of frame :-)
196  }
197 
198  } else if (tStateForISR == IR_REC_STATE_SPACE) {
199  /*
200  * In space receiving here, rawlen is odd
201  * Check for timeout or overflow
202  */
203  if (tTickCounterForISR > RECORD_GAP_TICKS || irparams.rawlen >= RAW_BUFFER_LENGTH - 1) {
205  // Flag up a read OverflowFlag; Stop the state machine
206  irparams.OverflowFlag = true;
207  }
208  /*
209  * Overflow or maximum space duration reached here.
210  * Current code is ready for processing!
211  * We received a long space, which indicates gap between codes.
212  * Switch to IR_REC_STATE_STOP
213  * Don't reset TickCounterForISR; keep counting width of next leading space
214  */
215  /*
216  * These 2 variables allow to call resume() directly after decode.
217  * After resume(), irparams.initialGapTicks and irparams.rawlen are
218  * the first variables, which are overwritten by the next received frame.
219  * since 4.3.0.
220  * For backward compatibility, there are the same 2 statements in decode() if IrReceiver is not used.
221  */
224 
225  irparams.StateForISR = IR_REC_STATE_STOP; // This signals the decode(), that a complete frame was received
226 #if !defined(IR_REMOTE_DISABLE_RECEIVE_COMPLETE_CALLBACK)
227  /*
228  * Call callback if registered (not nullptr)
229  */
230  if (irparams.ReceiveCompleteCallbackFunction != nullptr) {
232  }
233 #endif
234  } else if (tIRInputLevel == INPUT_MARK) {
235  /*
236  * Space ended here.
237  */
238 
239 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
240 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
241 #endif
242 #if RECORD_GAP_TICKS <= 400
243  if (tTickCounterForISR > UINT8_MAX) {
244  tTickCounterForISR = UINT8_MAX;
245  }
246 #endif
247  irparams.rawbuf[irparams.rawlen++] = tTickCounterForISR; // record space
250  }
251  } else if (tStateForISR == IR_REC_STATE_STOP) {
252  /*
253  * Complete command received
254  * stay here until resume() is called, which switches state to IR_REC_STATE_IDLE
255  */
256 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
257 // digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
258 #endif
259  if (tIRInputLevel == INPUT_MARK) {
260  // Reset gap TickCounterForISR, to prepare for detection if we are in the middle of a transmission after call of resume()
262  }
263  }
264 
265 #if defined(LED_RECEIVE_FEEDBACK_CODE)
267  setFeedbackLED(tIRInputLevel == INPUT_MARK);
268  }
269 #endif
270 
271 #ifdef _IR_MEASURE_TIMING
272  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
273 #endif
274 
275 }
276 /*
277  * The handler which directly calls the interrupt handler function of the IRrecv object.
278  * This must be a separate function, because we need this static function in IRTimer.hpp.
279  * Doing it this way, we are able to modify the body of this function to support multiple IRrecv instances for receiving
280  */
283 #if defined(SUPPORT_MULTIPLE_RECEIVER_INSTANCES)
284  // Quick and dirty solution by used defined extension
285  UserIRReceiveTimerInterruptHandler();
286 #endif
287 }
288 
289 /**********************************************************************************************************************
290  * Interrupt Service Routine - Called every 50 us
291  * This in turn calls calls the static interrupt handler function, which in turn calls the interrupt handler function of the IRrecv object
292  */
293 #if defined(TIMER_INTR_NAME) || defined(ISR)
294 # if defined(TIMER_INTR_NAME)
295 ISR (TIMER_INTR_NAME) // for ISR definitions
296 # elif defined(ISR)
297 ISR()
298 // for functions definitions which are called by separate (board specific) ISR
299 # endif
300 {
302 }
303 #endif
304 
305 /**********************************************************************************************************************
306  * Stream like API
307  **********************************************************************************************************************/
308 
315 void IRrecv::begin(uint_fast8_t aReceivePin, bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
316 
317  setReceivePin(aReceivePin);
318 #if defined(LED_RECEIVE_FEEDBACK_CODE)
319  setLEDFeedback(aEnableLEDFeedback);
320  setLEDFeedbackPin(aFeedbackLEDPin);
321 #else
322  (void) aEnableLEDFeedback;
323  (void) aFeedbackLEDPin;
324 #endif
325 
326 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
327  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
328 #endif
329  start();
330 }
331 
335 void IRrecv::setReceivePin(uint_fast8_t aReceivePinNumber) {
336  irparams.IRReceivePin = aReceivePinNumber;
337 #if defined(__AVR__)
338 # if defined(__digitalPinToBit)
339  if (__builtin_constant_p(aReceivePinNumber)) {
340  irparams.IRReceivePinMask = 1UL << (__digitalPinToBit(aReceivePinNumber));
341  } else {
342  irparams.IRReceivePinMask = digitalPinToBitMask(aReceivePinNumber); // requires 10 bytes PGM, even if not referenced (?because it is assembler code?)
343  }
344 # else
345  irparams.IRReceivePinMask = digitalPinToBitMask(aReceivePinNumber); // requires 10 bytes PGM, even if not referenced (?because it is assembler code?)
346 # endif
347 # if defined(__digitalPinToPINReg)
348  /*
349  * This code is 54 bytes smaller, if aReceivePinNumber is a constant :-), but 38 byte longer if it is not constant (,which is not likely).
350  */
351  if (__builtin_constant_p(aReceivePinNumber)) {
352  irparams.IRReceivePinPortInputRegister = __digitalPinToPINReg(aReceivePinNumber);
353  } else {
354  irparams.IRReceivePinPortInputRegister = portInputRegister(digitalPinToPort(aReceivePinNumber)); // requires 44 bytes PGM, even if not referenced
355  }
356 # else
357  irparams.IRReceivePinPortInputRegister = portInputRegister(digitalPinToPort(aReceivePinNumber)); // requires 44 bytes PGM, even if not referenced
358 # endif
359 #endif
360  // Seems to be at least required by ESP32
361  // Set pin mode once. pinModeFast makes no difference if used, but saves 224 if not referenced :-(
362  if (__builtin_constant_p(aReceivePinNumber)) {
363  pinModeFast(aReceivePinNumber, INPUT);
364  } else {
365  pinModeFast(aReceivePinNumber, INPUT);
366  }
367 }
368 
369 #if !defined(IR_REMOTE_DISABLE_RECEIVE_COMPLETE_CALLBACK)
370 
373 void IRrecv::registerReceiveCompleteCallback(void (*aReceiveCompleteCallbackFunction)(void)) {
374  irparams.ReceiveCompleteCallbackFunction = aReceiveCompleteCallbackFunction;
375 }
376 #endif
377 
384 
385  // Setup for cyclic 50 us interrupt
386  timerConfigForReceive(); // no interrupts enabled here!
387 
388  // Initialize state machine state
389  resume();
390 
391  // Timer interrupt is enabled after state machine reset
392  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
393 #ifdef _IR_MEASURE_TIMING
394  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
395 #endif
396 }
397 
398 /*
399  * Restarts timer interrupts, adjusts TickCounterForISR for correct gap value after stopTimer(). Does not call resume()!
400  */
402  // Setup for cyclic 50 us interrupt
403  timerConfigForReceive(); // no interrupts enabled here!
404  // Timer interrupt is enabled after state machine reset
405  if (sMicrosAtLastStopTimer != 0) {
406  irparams.TickCounterForISR += (micros() - sMicrosAtLastStopTimer) / MICROS_PER_TICK; // adjust TickCounterForISR for correct gap value, which is used for repeat detection
408  }
409  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
410 #ifdef _IR_MEASURE_TIMING
411  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
412 #endif
413 }
418  start();
419 }
420 
431 void IRrecv::restartTimer(uint32_t aMicrosecondsToAddToGapCounter) {
432  irparams.TickCounterForISR += aMicrosecondsToAddToGapCounter / MICROS_PER_TICK;
433  timerConfigForReceive(); // no interrupts enabled here!
434  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
435 #ifdef _IR_MEASURE_TIMING
436  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
437 #endif
438 }
443 void IRrecv::restartTimerWithTicksToAdd(uint16_t aTicksToAddToGapCounter) {
444  irparams.TickCounterForISR += aTicksToAddToGapCounter;
445  timerConfigForReceive(); // no interrupts enabled here!
446  timerEnableReceiveInterrupt(); // Enables the receive sample timer interrupt which consumes a small amount of CPU every 50 us.
447 #ifdef _IR_MEASURE_TIMING
448  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
449 #endif
450 }
451 #if defined(ESP8266) || defined(ESP32)
452 #pragma GCC diagnostic push
453 #endif
454 
459 #if defined(SEND_PWM_BY_TIMER) && !defined(SEND_PWM_DOES_NOT_USE_RECEIVE_TIMER)
460  start();
461 #endif
462 }
463 
467 void IRrecv::stop() {
469 }
470 
471 /*
472  * Stores microseconds of stop, to adjust TickCounterForISR in restartTimer()
473  */
476  sMicrosAtLastStopTimer = micros();
477 }
482  stop();
483 }
487 void IRrecv::end() {
488  stop();
489 }
490 
497 }
498 
504  // This check allows to call resume at arbitrary places or more than once
507  }
508 }
509 
515 
516  if (irparams.OverflowFlag) {
518 #if defined(LOCAL_DEBUG)
519  Serial.print(F("Overflow happened, try to increase the \"RAW_BUFFER_LENGTH\" value of "));
520  Serial.print(RAW_BUFFER_LENGTH);
521  Serial.println(F(" with #define RAW_BUFFER_LENGTH=<biggerValue>"));
522 #endif
523 
524  } else {
526  // save last protocol, command and address for repeat handling (where they are compared or copied back :-))
527  lastDecodedProtocol = decodedIRData.protocol; // repeat patterns can be equal between protocols (e.g. NEC, Samsung and LG), so we must keep the original one
530 
531  }
537 }
538 
544 }
545 
551  return nullptr;
552  }
553  if (decode()) {
554  return &decodedIRData;
555  } else {
556  return nullptr;
557  }
558 }
559 
568  return false;
569  }
570 
571  /*
572  * Support for old examples, which do not use the default IrReceiver instance
573  */
574  if (this != &IrReceiver) {
577  }
578 
579  initDecodedIRData(); // sets IRDATA_FLAGS_WAS_OVERFLOW
580 
582  /*
583  * Set OverflowFlag flag and return true here, to let the loop call resume or print raw data.
584  */
586  return true;
587  }
588 
589 #if defined(DECODE_NEC) || defined(DECODE_ONKYO)
590  IR_TRACE_PRINTLN(F("Attempting NEC/Onkyo decode"));
591  if (decodeNEC()) {
592  return true;
593  }
594 #endif
595 
596 #if defined(DECODE_PANASONIC) || defined(DECODE_KASEIKYO)
597  IR_TRACE_PRINTLN(F("Attempting Panasonic/Kaseikyo decode"));
598  if (decodeKaseikyo()) {
599  return true;
600  }
601 #endif
602 
603 #if defined(DECODE_DENON)
604  IR_TRACE_PRINTLN(F("Attempting Denon/Sharp decode"));
605  if (decodeDenon()) {
606  return true;
607  }
608 #endif
609 
610 #if defined(DECODE_SONY)
611  IR_TRACE_PRINTLN(F("Attempting Sony decode"));
612  if (decodeSony()) {
613  return true;
614  }
615 #endif
616 
617 #if defined(DECODE_RC5)
618  IR_TRACE_PRINTLN(F("Attempting RC5 decode"));
619  if (decodeRC5()) {
620  return true;
621  }
622 #endif
623 
624 #if defined(DECODE_RC6)
625  IR_TRACE_PRINTLN(F("Attempting RC6 decode"));
626  if (decodeRC6()) {
627  return true;
628  }
629 #endif
630 
631 #if defined(DECODE_LG)
632  IR_TRACE_PRINTLN(F("Attempting LG decode"));
633  if (decodeLG()) {
634  return true;
635  }
636 #endif
637 
638 #if defined(DECODE_JVC)
639  IR_TRACE_PRINTLN(F("Attempting JVC decode"));
640  if (decodeJVC()) {
641  return true;
642  }
643 #endif
644 
645 #if defined(DECODE_SAMSUNG)
646  IR_TRACE_PRINTLN(F("Attempting Samsung decode"));
647  if (decodeSamsung()) {
648  return true;
649  }
650 #endif
651  /*
652  * Start of the exotic protocols
653  */
654 
655 #if defined(DECODE_BEO)
656  IR_TRACE_PRINTLN(F("Attempting Bang & Olufsen decode"));
657  if (decodeBangOlufsen()) {
658  return true;
659  }
660 #endif
661 
662 #if defined(DECODE_FAST)
663  IR_TRACE_PRINTLN(F("Attempting FAST decode"));
664  if (decodeFAST()) {
665  return true;
666  }
667 #endif
668 
669 #if defined(DECODE_WHYNTER)
670  IR_TRACE_PRINTLN(F("Attempting Whynter decode"));
671  if (decodeWhynter()) {
672  return true;
673  }
674 #endif
675 
676 #if defined(DECODE_LEGO_PF)
677  IR_TRACE_PRINTLN(F("Attempting Lego Power Functions"));
678  if (decodeLegoPowerFunctions()) {
679  return true;
680  }
681 #endif
682 
683 #if defined(DECODE_BOSEWAVE)
684  IR_TRACE_PRINTLN(F("Attempting Bosewave decode"));
685  if (decodeBoseWave()) {
686  return true;
687  }
688 #endif
689 
690 #if defined(DECODE_MAGIQUEST)
691  IR_TRACE_PRINTLN(F("Attempting MagiQuest decode"));
692  if (decodeMagiQuest()) {
693  return true;
694  }
695 #endif
696 
697  /*
698  * Try the universal decoder for pulse distance protocols
699  */
700 #if defined(DECODE_DISTANCE_WIDTH)
701  IR_TRACE_PRINTLN(F("Attempting universal Distance Width decode"));
702  if (decodeDistanceWidth()) {
703  return true;
704  }
705 #endif
706 
707  /*
708  * Last resort is the universal hash decode which always return true
709  */
710 #if defined(DECODE_HASH)
711  IR_TRACE_PRINTLN(F("Hash decode"));
712  // decodeHash returns a hash on any input.
713  // Thus, it needs to be last in the list.
714  // If you add any decodes, add them before this.
715  if (decodeHash()) {
716  return true;
717  }
718 #endif
719 
720  /*
721  * Return true here, to let the loop decide to call resume or to print raw data.
722  */
723  return true;
724 }
725 
726 /**********************************************************************************************************************
727  * Common decode functions
728  **********************************************************************************************************************/
747 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMicros,
748  bool aIsPulseWidthProtocol, bool aMSBfirst) {
749 
750 #if defined(LOCAL_DEBUG)
751  Serial.print(F("aOneMicros="));
752  Serial.print(aOneMicros);
753  Serial.print(F(", 0.75*aOneMicros="));
754  Serial.print((aOneMicros * 3) / 4);
755  Serial.print(F(", MARK_EXCESS_MICROS=" STR(MARK_EXCESS_MICROS) " isPulseWidthProtocol="));
756  Serial.print(aIsPulseWidthProtocol);
757  Serial.println();
758 #endif
759 
760  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
761  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
762  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
763 
764  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
765 
766  bool tBitValue;
767  uint16_t tCurrentTicks;
768  if (aIsPulseWidthProtocol) {
769  /*
770  * PULSE_WIDTH here.
771  * !!!We only check variable length mark indicating a 1 or 0!!!
772  */
773  tCurrentTicks = *tRawBufPointer++;
774  tBitValue = matchMark(tCurrentTicks, aOneMicros); // Check for variable length mark indicating a 1 or 0
775  tRawBufPointer++;
776  } else {
777  /*
778  * PULSE_DISTANCE -including PULSE_DISTANCE_WIDTH- here.
779  * !!!We only check variable length space indicating a 1 or 0!!!
780  */
781  tRawBufPointer++;
782  tCurrentTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
783  tBitValue = matchSpace(tCurrentTicks, aOneMicros); // Check for variable length space indicating a 1 or 0
784  }
785 
786  if (aMSBfirst) {
787  tDecodedData <<= 1;
788  }
789 
790  if (tBitValue) {
791  // It's a 1 -> set the bit
792  if (aMSBfirst) {
793  tDecodedData |= 1;
794  } else {
795  tDecodedData |= tMask;
796  }
797  IR_TRACE_PRINT(tCurrentTicks);
798  IR_TRACE_PRINTLN(F(" => 1"));
799  } else {
800  // do not set the bit
801  IR_TRACE_PRINT(tCurrentTicks);
802  IR_TRACE_PRINTLN(F(" => 0"));
803  }
804  tMask <<= 1;
805  }
806  decodedIRData.decodedRawData = tDecodedData;
807 }
808 
827 void IRrecv::decodeWithThresholdPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset,
828  uint16_t aOneThresholdMicros, bool aIsPulseWidthProtocol, bool aMSBfirst) {
829 
830 #if defined(LOCAL_DEBUG)
831  Serial.print(F("OneThresholdMicros="));
832  Serial.print(aOneThresholdMicros);
833  Serial.print(F(" isPulseWidthProtocol="));
834  Serial.print(aIsPulseWidthProtocol);
835  Serial.println();
836 #endif
837 
838  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
839  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
840  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
841 
842  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
843 
844  if (!aIsPulseWidthProtocol) {
845  tRawBufPointer++;
846  }
847  uint16_t tCurrentMicros = *tRawBufPointer * MICROS_PER_TICK;
848  bool tBitValue = tCurrentMicros > aOneThresholdMicros; // Check for variable length timing indicating a 1 or 0
849  tRawBufPointer++;
850 
851  if (aIsPulseWidthProtocol) {
852  tRawBufPointer++;
853  }
854 
855  if (aMSBfirst) {
856  tDecodedData <<= 1;
857  }
858 
859  if (tBitValue) {
860  // It's a 1 -> set the bit
861  if (aMSBfirst) {
862  tDecodedData |= 1;
863  } else {
864  tDecodedData |= tMask;
865  }
866  IR_TRACE_PRINT(tCurrentMicros);
867  IR_TRACE_PRINTLN(F(" => 1"));
868  } else {
869  // do not set the bit
870  IR_TRACE_PRINT(tCurrentMicros);
871  IR_TRACE_PRINTLN(F(" => 0"));
872  }
873  tMask <<= 1;
874  }
875  decodedIRData.decodedRawData = tDecodedData;
876 }
877 
881 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
882  uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, bool aMSBfirst) {
883 
884  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
885 
886  bool isPulseDistanceProtocol = (aOneMarkMicros == aZeroMarkMicros); // If true, we check aOneSpaceMicros -> pulse distance protocol
887 
888  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
889  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
890 
891  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
892  // get one mark and space pair
893  unsigned int tMarkTicks;
894  unsigned int tSpaceTicks;
895  bool tBitValue;
896 
897  if (isPulseDistanceProtocol) {
898  /*
899  * PULSE_DISTANCE -including PULSE_DISTANCE_WIDTH- here.
900  * !!!We only check variable length space indicating a 1 or 0!!!
901  */
902  tRawBufPointer++;
903  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
904  tBitValue = matchSpace(tSpaceTicks, aOneSpaceMicros); // Check for variable length space indicating a 1 or 0
905 
906  } else {
907  /*
908  * PULSE_WIDTH here.
909  * !!!We only check variable length mark indicating a 1 or 0!!!
910  */
911  tMarkTicks = *tRawBufPointer++;
912  tBitValue = matchMark(tMarkTicks, aOneMarkMicros); // Check for variable length mark indicating a 1 or 0
913  tRawBufPointer++;
914  }
915 
916  if (aMSBfirst) {
917  tDecodedData <<= 1;
918  }
919 
920  if (tBitValue) {
921  // It's a 1 -> set the bit
922  if (aMSBfirst) {
923  tDecodedData |= 1;
924  } else {
925  tDecodedData |= tMask;
926  }
927  IR_TRACE_PRINTLN(F("=> 1"));
928  } else {
929  // do not set the bit
930  IR_TRACE_PRINTLN(F("=> 0"));
931  }
932  tMask <<= 1;
933  }
934  decodedIRData.decodedRawData = tDecodedData;
935 }
936 
937 /*
938  * Old deprecated version with 7 parameters and unused aZeroSpaceMicros parameter
939  */
940 void IRrecv::decodePulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
941  uint16_t aZeroMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroSpaceMicros, bool aMSBfirst) {
942 
943  (void) aZeroSpaceMicros;
944  decodePulseDistanceWidthData(aNumberOfBits, aStartOffset, aOneMarkMicros, aZeroMarkMicros, aOneSpaceMicros, aMSBfirst);
945 }
946 
947 /*
948  * Only sensible for development or very exotic requirements. - Not used yet
949  * Check for additional required characteristics of timing like length of mark for a constant mark protocol,
950  * where space length determines the bit value. Requires up to 194 additional bytes of program memory.
951  *
952  * @param aZeroMarkMicros For strict checks
953  * @param aZeroSpaceMicros For strict checks
954  * @return true if decoding successful
955  *
956  */
957 bool IRrecv::decodeStrictPulseDistanceWidthData(uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset, uint16_t aOneMarkMicros,
958  uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, bool aMSBfirst) {
959 
960  auto *tRawBufPointer = &irparams.rawbuf[aStartOffset];
961 
962  bool isPulseDistanceProtocol = (aOneMarkMicros == aZeroMarkMicros); // If true, we have a constant mark -> pulse distance protocol
963 
964  IRRawDataType tDecodedData = 0; // For MSB first tDecodedData is shifted left each loop
965  IRRawDataType tMask = 1UL; // Mask is only used for LSB first
966 
967  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
968  // get one mark and space pair
969  unsigned int tMarkTicks;
970  unsigned int tSpaceTicks;
971  bool tBitValue;
972 
973  if (isPulseDistanceProtocol) {
974  /*
975  * PULSE_DISTANCE here (aOneMarkMicros == aZeroMarkMicros)
976  * We additionally check constant mark duration and in case of zero the zero space duration.
977  */
978  tMarkTicks = *tRawBufPointer++;
979  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
980  tBitValue = matchSpace(tSpaceTicks, aOneSpaceMicros); // Check for variable length space indicating a 1 or 0
981 
982  // Check for constant mark duration
983  if (!matchMark(tMarkTicks, aOneMarkMicros)) {
984 #if defined(LOCAL_DEBUG)
985  Serial.print(F("Mark="));
986  Serial.print(tMarkTicks * MICROS_PER_TICK);
987  Serial.print(F(" is not "));
988  Serial.print(aOneMarkMicros);
989  Serial.print(F(". Index="));
990  Serial.print(aNumberOfBits - i);
991  Serial.print(' ');
992 #endif
993  return false;
994  }
995 
996  // in case of 0, check for zero space duration
997  if (!tBitValue && !matchSpace(tSpaceTicks, aZeroSpaceMicros)) {
998 #if defined(LOCAL_DEBUG)
999  Serial.print(F("Space="));
1000  Serial.print(tSpaceTicks * MICROS_PER_TICK);
1001  Serial.print(F(" is not "));
1002  Serial.print(aZeroSpaceMicros);
1003  Serial.print(F(". Index="));
1004  Serial.print(aNumberOfBits - i);
1005  Serial.print(' ');
1006 #endif
1007  return false;
1008  }
1009 
1010  } else {
1011  /*
1012  * PULSE_WIDTH -including PULSE_DISTANCE_WIDTH- here.
1013  * We additionally check two space durations and in case of zero the zero mark duration.
1014  */
1015  tMarkTicks = *tRawBufPointer++;
1016  tBitValue = matchMark(tMarkTicks, aOneMarkMicros); // Check for variable length mark indicating a 1 or 0
1017  tSpaceTicks = *tRawBufPointer++; // maybe buffer overflow for last bit, but we do not evaluate this value :-)
1018 
1019  // Check for space length, which is not constant in case of PULSE_DISTANCE_WIDTH
1020  if ((tBitValue && !matchSpace(tSpaceTicks, aOneSpaceMicros))
1021  || ((!tBitValue && !matchSpace(tSpaceTicks, aZeroSpaceMicros)))) {
1022 #if defined(LOCAL_DEBUG)
1023  Serial.print(F("Space="));
1024  Serial.print(tSpaceTicks * MICROS_PER_TICK);
1025  Serial.print(F(" is not "));
1026  Serial.print(aOneSpaceMicros);
1027  Serial.print(F(" or "));
1028  Serial.print(aZeroSpaceMicros);
1029  Serial.print(F(". Index="));
1030  Serial.print(aNumberOfBits - i);
1031  Serial.print(' ');
1032 #endif
1033  return false;
1034  }
1035  if (!tBitValue && !matchMark(tMarkTicks, aZeroMarkMicros)) {
1036 #if defined(LOCAL_DEBUG)
1037  Serial.print(F("Mark="));
1038  Serial.print(tMarkTicks * MICROS_PER_TICK);
1039  Serial.print(F(" is not "));
1040  Serial.print(aZeroMarkMicros);
1041  Serial.print(F(". Index="));
1042  Serial.print(aNumberOfBits - i);
1043  Serial.print(' ');
1044 #endif
1045  return false;
1046  }
1047  }
1048 
1049  if (aMSBfirst) {
1050  tDecodedData <<= 1;
1051  }
1052 
1053  if (tBitValue) {
1054  // It's a 1 -> set the bit
1055  if (aMSBfirst) {
1056  tDecodedData |= 1;
1057  } else {
1058  tDecodedData |= tMask;
1059  }
1060  IR_TRACE_PRINTLN(F("=> 1"));
1061  } else {
1062  // do not set the bit
1063  IR_TRACE_PRINTLN(F("=> 0"));
1064  }
1065  tMask <<= 1;
1066  }
1067  decodedIRData.decodedRawData = tDecodedData;
1068  return true;
1069 }
1070 
1075 #if defined(USE_STRICT_DECODER)
1076 bool
1077 #else
1078 void
1079 #endif
1080 IRrecv::decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, uint_fast8_t aNumberOfBits,
1081  IRRawlenType aStartOffset) {
1082 
1083 #if defined(USE_STRICT_DECODER)
1084  return decodeStrictPulseDistanceWidthData(aNumberOfBits, aStartOffset, aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros,
1085  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
1086  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1087 
1088 #else
1089  bool tIsPulseWidthProtocol = aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK;
1090  uint16_t tThresholdMicros;
1091 
1092 # if defined(USE_THRESHOLD_DECODER)
1093  if (tIsPulseWidthProtocol) {
1094  // we check the length of marks here
1095  tThresholdMicros = ((aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros
1096  + aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros) / 2) - MARK_EXCESS_MICROS;// MARK_EXCESS_MICROS is 0 here if not explicitly specified by user
1097  } else {
1098  // we check the length of spaces here
1099  tThresholdMicros = ((aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros
1100  + aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros) / 2) + MARK_EXCESS_MICROS;// MARK_EXCESS_MICROS is 0 here if not explicitly specified by user
1101  }
1102  return decodeWithThresholdPulseDistanceWidthData(aNumberOfBits, aStartOffset, tThresholdMicros,
1103  aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1104 # else
1105  if (tIsPulseWidthProtocol) {
1106  tThresholdMicros = aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros;
1107  } else {
1108  tThresholdMicros = aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros;
1109  }
1110  decodePulseDistanceWidthData(aNumberOfBits, aStartOffset, tThresholdMicros,
1111  aProtocolConstants->Flags & PROTOCOL_IS_PULSE_WIDTH_MASK, (aProtocolConstants->Flags & PROTOCOL_IS_MSB_MASK));
1112 # endif
1113 #endif
1114 }
1115 
1117  uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset) {
1118 
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 
1971 // @formatter:off
1972 
1981 void IRrecv::printIRSendUsage(Print *aSerial) {
1984 
1985  /*
1986  * Generating the string:
1987  * Send on a 8 bit platform with:
1988  * uint32_t tRawData[]={0x87654321, 0xAFEDCBA9, 0x5A};
1989  * IrSender.send
1990  * or
1991  * Send on a 8 bit platform with: IrSender.send
1992  * or
1993  * Send with: IrSender.send
1994  */
1995 #if defined(DECODE_DISTANCE_WIDTH)
1996  uint_fast8_t tNumberOfArrayData = 0;
1998 # if __INT_WIDTH__ < 32
1999  aSerial->print(F("Send on a 8 bit platform with: "));
2000  tNumberOfArrayData = ((decodedIRData.numberOfBits - 1) / 32) + 1;
2001  if(tNumberOfArrayData > 1) {
2002  aSerial->println();
2003  aSerial->print(F(" uint32_t tRawData[]={0x"));
2004  for (uint_fast8_t i = 0; i < tNumberOfArrayData; ++i) {
2005  aSerial->print(decodedIRData.decodedRawDataArray[i], HEX);
2006 # else
2007  aSerial->print(F("Send on a 32 bit platform with: "));
2008  tNumberOfArrayData = ((decodedIRData.numberOfBits - 1) / 64) + 1;
2009  if(tNumberOfArrayData > 1) {
2010  aSerial->println();
2011  aSerial->print(F(" uint64_t tRawData[]={0x"));
2012  for (uint_fast8_t i = 0; i < tNumberOfArrayData; ++i) {
2013  PrintULL::print(aSerial, decodedIRData.decodedRawDataArray[i], HEX);
2014 # endif
2015  if (i != tNumberOfArrayData - 1) {
2016  aSerial->print(F(", 0x"));
2017  }
2018  }
2019  aSerial->println(F("};"));
2020  aSerial->print(F(" "));
2021  }
2022  } else { // if (decodedIRData.protocol == PULSE_DISTANCE || decodedIRData.protocol == PULSE_WIDTH)
2023  aSerial->print(F("Send with: "));
2024  }
2025  if (decodedIRData.protocol == UNKNOWN){
2026  aSerial->println();
2027  aSerial->print(F(" "));
2028  printIRResultAsCArray(&Serial);
2029  aSerial->print(F(" "));
2030  }
2031  aSerial->print(F("IrSender.send"));
2032 
2033 #else
2034  aSerial->print(F("Send with: IrSender.send"));
2035 #endif // #if defined(DECODE_DISTANCE_WIDTH)
2036 
2037  /*
2038  * Generating the string:
2039  * Raw(rawIRTimings, sizeof(rawIRTimings) / sizeof(rawIRTimings[0]), 38, <RepeatPeriodMillis>, <numberOfRepeats>
2040  * or
2041  * PulseDistanceWidth(38, 550, 1250, 500, 1250, 1300, 400, 0x3D9EAC, 23, PROTOCOL_IS_LSB_FIRST, <RepeatPeriodMillis>, <numberOfRepeats>);
2042  * or
2043  * PulseDistanceWidthFromArray(38, 8900, 4350, 600, 1650, 600, 550, &tRawData[0], 72, PROTOCOL_IS_LSB_FIRST, <RepeatPeriodMillis>, <numberOfRepeats>);
2044  * or
2045  * <Protocol_Name>(0x<Address>, 0x<Command>, <numberOfRepeats>);
2046  */
2047  if (decodedIRData.protocol == UNKNOWN){
2048  aSerial->print(F("Raw(rawIRTimings, sizeof(rawIRTimings) / sizeof(rawIRTimings[0]), 38, <RepeatPeriodMillis>, <numberOfRepeats>"));
2049  }
2050 #if defined(DECODE_DISTANCE_WIDTH)
2052  /*
2053  * Pulse distance or pulse width here
2054  */
2055  aSerial->print(F("PulseDistanceWidth"));
2056  if(tNumberOfArrayData > 1) {
2057  aSerial->print(F("FromArray(38, "));
2058  } else {
2059  aSerial->print(F("(38, "));
2060  }
2061  printDistanceWidthTimingInfo(aSerial, &decodedIRData.DistanceWidthTimingInfo);
2062 
2063  if(tNumberOfArrayData > 1) {
2064  aSerial->print(F(", &tRawData[0], "));
2065  } else {
2066  aSerial->print(F(", 0x"));
2067 # if (__INT_WIDTH__ < 32)
2068  aSerial->print(decodedIRData.decodedRawData, HEX);
2069 # else
2070  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2071 # endif
2072  aSerial->print(F(", "));
2073  }
2074  aSerial->print(decodedIRData.numberOfBits); // aNumberOfBits
2075  aSerial->print(F(", PROTOCOL_IS_"));
2076 
2078  aSerial->print('M');
2079  } else {
2080  aSerial->print('L');
2081  }
2082  aSerial->print(F("SB_FIRST, <RepeatPeriodMillis>, <numberOfRepeats>"));
2083  }
2084 #endif // defined(DECODE_DISTANCE_WIDTH)
2085  else {
2086  /*
2087  * Regular protocols here
2088  */
2089  aSerial->print(getProtocolString());
2090  aSerial->print(F("(0x"));
2091 #if defined(DECODE_MAGIQUEST)
2092  if (decodedIRData.protocol == MAGIQUEST) {
2093 # if (__INT_WIDTH__ < 32)
2094  aSerial->print(decodedIRData.decodedRawData, HEX);
2095 # else
2096  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2097 # endif
2098  } else {
2099  aSerial->print(decodedIRData.address, HEX);
2100  }
2101 #else
2102  /*
2103  * New decoders have address and command
2104  */
2105  aSerial->print(decodedIRData.address, HEX);
2106 #endif
2107 
2108  aSerial->print(F(", 0x"));
2109  aSerial->print(decodedIRData.command, HEX);
2110  if (decodedIRData.protocol == SONY) {
2111  aSerial->print(F(", 2, "));
2112  aSerial->print(decodedIRData.numberOfBits);
2113  } else {
2114  aSerial->print(F(", <numberOfRepeats>"));
2115  }
2116  }
2117 
2118 #if defined(DECODE_PANASONIC) || defined(DECODE_KASEIKYO) || defined(DECODE_RC6)
2120  // Vendor code parameter, which is after numberOfRepeats parameter
2121  aSerial->print(F(", 0x"));
2122  aSerial->print(decodedIRData.extra, HEX);
2123  }
2124 #endif
2125  aSerial->print(F(");"));
2126  aSerial->println();
2127  }
2128 }
2129 
2130 // @formatter:on
2137 void IRrecv::printIRResultMinimal(Print *aSerial) {
2138  aSerial->print(F("P="));
2139  aSerial->print(decodedIRData.protocol);
2140  if (decodedIRData.protocol == UNKNOWN) {
2141 #if defined(DECODE_HASH)
2142  aSerial->print(F(" #=0x"));
2143 # if (__INT_WIDTH__ < 32)
2144  aSerial->print(decodedIRData.decodedRawData, HEX);
2145 # else
2146  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2147 # endif
2148 #endif
2149  aSerial->print(' ');
2150  aSerial->print((decodedIRData.rawlen + 1) / 2);
2151  aSerial->println(F(" bits received"));
2152  } else {
2153  /*
2154  * New decoders have address and command
2155  */
2156  aSerial->print(F(" A=0x"));
2157  aSerial->print(decodedIRData.address, HEX);
2158 
2159  aSerial->print(F(" C=0x"));
2160  aSerial->print(decodedIRData.command, HEX);
2161 
2162  aSerial->print(F(" Raw=0x"));
2163 #if (__INT_WIDTH__ < 32)
2164  aSerial->print(decodedIRData.decodedRawData, HEX);
2165 #else
2166  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2167 #endif
2168 
2170  aSerial->print(F(" R"));
2171  }
2172  }
2173 }
2174 
2175 /*
2176  * Not used yet
2177  */
2178 void IRrecv::printIRDuration(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2179  uint16_t tSumOfDurationTicks = 0;
2180  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2181  tSumOfDurationTicks += irparams.rawbuf[i];
2182  }
2183  aSerial->print(F("Duration="));
2184  if (aOutputMicrosecondsInsteadOfTicks) {
2185  aSerial->print((uint32_t) tSumOfDurationTicks * MICROS_PER_TICK);
2186  aSerial->println(F("us"));
2187 
2188  } else {
2189  aSerial->print(tSumOfDurationTicks);
2190  aSerial->println(F(" ticks"));
2191  }
2192 }
2193 
2200 void IRrecv::printIRResultRawFormatted(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2201 
2202 // Print Raw data
2203  aSerial->print(F("rawIRTimings["));
2204  aSerial->print(decodedIRData.rawlen);
2205  aSerial->println(F("]: "));
2206 
2207  /*
2208  * Print initial gap
2209  */
2210  aSerial->print(F(" -"));
2211  if (aOutputMicrosecondsInsteadOfTicks) {
2212  aSerial->println((uint32_t) decodedIRData.initialGapTicks * MICROS_PER_TICK);
2213  } else {
2214  aSerial->println(decodedIRData.initialGapTicks);
2215  }
2216 
2217 // Newline is printed every 8. value, if tCounterForNewline % 8 == 0
2218  uint_fast8_t tCounterForNewline = 6; // first newline is after the 2 values of the start bit
2219 
2220 // check if we have a protocol with no or 8 start bits
2221 #if defined(DECODE_DENON) || defined(DECODE_MAGIQUEST)
2222  if (
2223 # if defined(DECODE_DENON)
2225 # endif
2226 # if defined(DECODE_MAGIQUEST)
2228 # endif
2229  false) {
2230  tCounterForNewline = 0; // no or 8 start bits
2231  }
2232 #endif
2233 
2234  uint32_t tDuration;
2235  uint16_t tSumOfDurationTicks = 0;
2236  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2237  auto tCurrentTicks = irparams.rawbuf[i];
2238  if (aOutputMicrosecondsInsteadOfTicks) {
2239  tDuration = tCurrentTicks * MICROS_PER_TICK;
2240  } else {
2241  tDuration = tCurrentTicks;
2242  }
2243  tSumOfDurationTicks += tCurrentTicks; // compute length of protocol frame
2244 
2245  if (!(i & 1)) { // even
2246  aSerial->print('-');
2247  } else { // odd
2248  aSerial->print(F(" +"));
2249  }
2250 
2251  // padding only for big values
2252  if (aOutputMicrosecondsInsteadOfTicks && tDuration < 1000) {
2253  aSerial->print(' ');
2254  }
2255  if (aOutputMicrosecondsInsteadOfTicks && tDuration < 100) {
2256  aSerial->print(' ');
2257  }
2258  if (tDuration < 10) {
2259  aSerial->print(' ');
2260  }
2261  aSerial->print(tDuration);
2262 
2263  if ((i & 1) && (i + 1) < decodedIRData.rawlen) {
2264  aSerial->print(','); //',' not required for last one
2265  }
2266 
2267  tCounterForNewline++;
2268  if ((tCounterForNewline % 8) == 0) {
2269  aSerial->println();
2270  }
2271  }
2272 
2273  aSerial->println();
2274  aSerial->print(F("Duration="));
2275  if (aOutputMicrosecondsInsteadOfTicks) {
2276  aSerial->print((uint32_t) tSumOfDurationTicks * MICROS_PER_TICK);
2277  aSerial->println(F("us"));
2278 
2279  } else {
2280  aSerial->print(tSumOfDurationTicks);
2281  aSerial->println(F(" ticks"));
2282  }
2283  aSerial->println();
2284 
2285 }
2286 
2299 void IRrecv::compensateAndPrintIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks) {
2300  printIRResultAsCArray(aSerial, aOutputMicrosecondsInsteadOfTicks, true);
2301 }
2302 void IRrecv::printIRResultAsCArray(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks, bool aDoCompensate) {
2303 // Start declaration
2304  if (aOutputMicrosecondsInsteadOfTicks) {
2305  aSerial->print(F("uint16_t rawIRTimings[")); // variable type, array name
2306  } else {
2307  aSerial->print(F("uint8_t rawTicks[")); // variable type, array name
2308  }
2309 
2310  aSerial->print(decodedIRData.rawlen - 1); // array size
2311  aSerial->print(F("] = {")); // Start declaration
2312 
2313 // Dump data
2314  for (IRRawlenType i = 1; i < decodedIRData.rawlen; i++) {
2315  uint32_t tDuration = irparams.rawbuf[i] * MICROS_PER_TICK;
2316 
2317  if (aDoCompensate) {
2318  if (i & 1) {
2319  // Mark
2320  tDuration -= MARK_EXCESS_MICROS;
2321  } else {
2322  tDuration += MARK_EXCESS_MICROS;
2323  }
2324  }
2325 
2326  if (aOutputMicrosecondsInsteadOfTicks) {
2327  aSerial->print(tDuration);
2328  } else {
2329  unsigned int tTicks = (tDuration + (MICROS_PER_TICK / 2)) / MICROS_PER_TICK;
2330  /*
2331  * Clip to 8 bit value
2332  */
2333  tTicks = (tTicks > UINT8_MAX) ? UINT8_MAX : tTicks;
2334  aSerial->print(tTicks);
2335  }
2336  if (i + 1 < decodedIRData.rawlen) aSerial->print(','); // ',' not required on last one
2337  if (!(i & 1)) aSerial->print(' ');
2338  }
2339 
2340 // End declaration
2341  aSerial->print(F("};")); //
2342 
2343 // Comment
2344  aSerial->print(F(" // "));
2345  printIRResultShort(aSerial);
2346 }
2347 
2358 
2359 // Store data, skip leading space#
2360  IRRawlenType i;
2361  for (i = 1; i < decodedIRData.rawlen; i++) {
2362  uint32_t tDuration = irparams.rawbuf[i] * MICROS_PER_TICK;
2363  if (i & 1) {
2364  // Mark
2365  tDuration -= MARK_EXCESS_MICROS;
2366  } else {
2367  tDuration += MARK_EXCESS_MICROS;
2368  }
2369 
2370  unsigned int tTicks = (tDuration + (MICROS_PER_TICK / 2)) / MICROS_PER_TICK;
2371  *aArrayPtr = (tTicks > UINT8_MAX) ? UINT8_MAX : tTicks; // we store it in an 8 bit array
2372  aArrayPtr++;
2373  }
2374 }
2375 
2384 // Now dump "known" codes
2385  if (decodedIRData.protocol != UNKNOWN) {
2386 
2387  /*
2388  * New decoders have address and command
2389  */
2390  aSerial->print(F("uint16_t"));
2391  aSerial->print(F(" address = 0x"));
2392  aSerial->print(decodedIRData.address, HEX);
2393  aSerial->println(';');
2394 
2395  aSerial->print(F("uint16_t"));
2396  aSerial->print(F(" command = 0x"));
2397  aSerial->print(decodedIRData.command, HEX);
2398  aSerial->println(';');
2399 
2400  // All protocols have raw data
2401 #if __INT_WIDTH__ < 32
2402  aSerial->print(F("uint32_t rawIRTimings = 0x"));
2403 #else
2404  aSerial->print(F("uint64_t rawIRTimings = 0x"));
2405 #endif
2406 #if (__INT_WIDTH__ < 32)
2407  aSerial->print(decodedIRData.decodedRawData, HEX);
2408 #else
2409  PrintULL::print(aSerial, decodedIRData.decodedRawData, HEX);
2410 #endif
2411  aSerial->println(';');
2412  }
2413 }
2414 
2415 #if defined(__AVR__)
2416 const __FlashStringHelper* IRrecv::getProtocolString() {
2417 // call no class function with same name
2419 }
2420 #else
2422  // call no class function with same name
2424  }
2425 #endif
2426 
2427 /**********************************************************************************************************************
2428  * The OLD and DEPRECATED decode function with parameter aResults, kept for backward compatibility to old 2.0 tutorials
2429  * This function calls the old MSB first decoders and fills only the 3 variables:
2430  * aResults->value
2431  * aResults->bits
2432  * aResults->decode_type
2433  **********************************************************************************************************************/
2435 
2437  return false;
2438  }
2439 
2440 // copy for usage by legacy programs
2441  aResults->rawbuf[0] = irparams.initialGapTicks;
2442  for (int i = 1; i < RAW_BUFFER_LENGTH; ++i) {
2443  aResults->rawbuf[i] = irparams.rawbuf[i]; // copy 8 bit array into a 16 bit array
2444  }
2445  aResults->rawlen = irparams.rawlen;
2446  if (irparams.OverflowFlag) {
2447  // Copy overflow flag to decodedIRData.flags
2448  irparams.OverflowFlag = false;
2449  irparams.rawlen = 0; // otherwise we have OverflowFlag again at next ISR call
2450  IR_DEBUG_PRINTLN(F("Overflow happened"));
2451  }
2452  aResults->overflow = irparams.OverflowFlag;
2453  aResults->value = 0;
2454 
2456 
2457 #if defined(DECODE_NEC)
2458  IR_DEBUG_PRINTLN(F("Attempting old NEC decode"));
2459  if (decodeNECMSB(aResults)) {
2460  return true;
2461  }
2462 #endif
2463 
2464 #if defined(DECODE_SONY)
2465  IR_DEBUG_PRINTLN(F("Attempting old Sony decode"));
2466  if (decodeSonyMSB(aResults)) {
2467  return true;
2468  }
2469 #endif
2470 
2471 #if defined(DECODE_RC5)
2472  IR_DEBUG_PRINTLN(F("Attempting RC5 decode"));
2473  if (decodeRC5()) {
2474  aResults->bits = decodedIRData.numberOfBits;
2475  aResults->value = decodedIRData.decodedRawData;
2476  aResults->decode_type = RC5;
2477 
2478  return true;
2479  }
2480 #endif
2481 
2482 #if defined(DECODE_RC6)
2483  IR_DEBUG_PRINTLN(F("Attempting RC6 decode"));
2484  if (decodeRC6()) {
2485  aResults->bits = decodedIRData.numberOfBits;
2486  aResults->value = decodedIRData.decodedRawData;
2487  aResults->decode_type = RC6;
2488  return true;
2489  }
2490 #endif
2491 
2492 // Removed bool IRrecv::decodePanasonicMSB(decode_results *aResults) since implementations was wrong (wrong length), and nobody recognized it
2493 
2494 #if defined(DECODE_LG)
2495  IR_DEBUG_PRINTLN(F("Attempting old LG decode"));
2496  if (decodeLGMSB(aResults)) {return true;}
2497 #endif
2498 
2499 #if defined(DECODE_JVC)
2500  IR_DEBUG_PRINTLN(F("Attempting old JVC decode"));
2501  if (decodeJVCMSB(aResults)) {
2502  return true;
2503  }
2504 #endif
2505 
2506 #if defined(DECODE_SAMSUNG)
2507  IR_DEBUG_PRINTLN(F("Attempting old SAMSUNG decode"));
2508  if (decodeSAMSUNG(aResults)) {
2509  return true;
2510  }
2511 #endif
2512 
2513 #if defined(DECODE_DENON)
2514  IR_DEBUG_PRINTLN(F("Attempting old Denon decode"));
2515  if (decodeDenonOld(aResults)) {
2516  return true;
2517  }
2518 #endif
2519 
2520 // decodeHash returns a hash on any input.
2521 // Thus, it needs to be last in the list.
2522 // If you add any decodes, add them before this.
2523  if (decodeHashOld(aResults)) {
2524  return true;
2525  }
2526 // Throw away and start over
2527  resume();
2528  return false;
2529 }
2530 
2532 #if defined(_IR_MEASURE_TIMING)
2533 #undef _IR_MEASURE_TIMING
2534 #endif
2535 #if defined(LOCAL_TRACE)
2536 #undef LOCAL_TRACE
2537 #endif
2538 #if defined(LOCAL_DEBUG)
2539 #undef LOCAL_DEBUG
2540 #endif
2541 #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:1080
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:467
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:481
IRrecv::decodePulseDistanceWidthData_P
void decodePulseDistanceWidthData_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, uint_fast8_t aNumberOfBits, IRRawlenType aStartOffset=3)
Definition: IRReceive.hpp:1116
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:417
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:373
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:2200
PulseDistanceWidthProtocolConstants::ProtocolIndex
decode_type_t ProtocolIndex
Definition: IRProtocol.h:162
IRrecv::restartAfterSend
void restartAfterSend()
Restarts receiver after send.
Definition: IRReceive.hpp:458
IRrecv::IRrecv
IRrecv()
Instantiate the IRrecv class.
Definition: IRReceive.hpp:75
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:69
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:315
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:549
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:2421
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:2299
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:2137
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:2178
IRReceiveTimerInterruptHandler
void IRReceiveTimerInterruptHandler()
Definition: IRReceive.hpp:281
IRrecv::getMaximumTicksFromRawData
uint8_t getMaximumTicksFromRawData(bool aSearchSpaceInsteadOfMark)
Definition: IRReceive.hpp:1945
IRrecv::restartTimer
void restartTimer()
Definition: IRReceive.hpp:401
IRrecv::restartTimerWithTicksToAdd
void restartTimerWithTicksToAdd(uint16_t aTicksToAddToGapCounter)
Configures the timer and the state machine for IR reception.
Definition: IRReceive.hpp:443
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:495
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:335
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:383
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:514
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:214
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:542
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:2383
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:2434
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:957
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:487
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:1981
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:474
IRrecv::decode
bool decode()
The main decode function, attempts to decode the recently receive IR signal.
Definition: IRReceive.hpp:566
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:121
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:506
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:503
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:2357
IrReceiver
IRrecv IrReceiver
The receiver instance.
Definition: IRReceive.hpp:63
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:827
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:2302
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