IRremote
TinyIRReceiver.hpp
Go to the documentation of this file.
1 /*
2  * TinyIRReceiver.hpp
3  *
4  * Receives IR protocol data of NEC protocol using pin change interrupts.
5  * NEC is the protocol of most cheap remote controls for Arduino.
6  *
7  * Parity check is done for address and data.
8  * On a completely received IR command, the user function handleReceivedIRData(uint8_t aAddress, uint8_t aCommand, uint8_t aFlags)
9  * is called in interrupt context but with interrupts being enabled to enable use of delay() etc.
10  * !!!!!!!!!!!!!!!!!!!!!!
11  * Functions called in interrupt context should be running as short as possible,
12  * so if you require longer action, save the data (address + command) and handle them in the main loop.
13  * !!!!!!!!!!!!!!!!!!!!!
14  * aFlags can contain one of IRDATA_FLAGS_EMPTY, IRDATA_FLAGS_IS_REPEAT and IRDATA_FLAGS_PARITY_FAILED bits
15  *
16  * The FAST protocol is a proprietary modified JVC protocol without address, with parity and with a shorter header.
17  * FAST Protocol characteristics:
18  * - Bit timing is like NEC or JVC
19  * - The header is shorter, 3156 vs. 12500
20  * - No address and 16 bit data, interpreted as 8 bit command and 8 bit inverted command,
21  * leading to a fixed protocol length of (6 + (16 * 3) + 1) * 526 = 55 * 526 = 28930 microseconds or 29 ms.
22  * - Repeats are sent as complete frames but in a 50 ms period / with a 21 ms distance.
23  *
24  *
25  * This file is part of IRMP https://github.com/IRMP-org/IRMP.
26  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
27  *
28  ************************************************************************************
29  * MIT License
30  *
31  * Copyright (c) 2022-2024 Armin Joachimsmeyer
32  *
33  * Permission is hereby granted, free of charge, to any person obtaining a copy
34  * of this software and associated documentation files (the "Software"), to deal
35  * in the Software without restriction, including without limitation the rights
36  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37  * copies of the Software, and to permit persons to whom the Software is furnished
38  * to do so, subject to the following conditions:
39  *
40  * The above copyright notice and this permission notice shall be included in all
41  * copies or substantial portions of the Software.
42  *
43  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
44  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
45  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
46  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
47  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
48  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49  *
50  ************************************************************************************
51  */
52 
53 /*
54  * This library can be configured at compile time by the following options / macros:
55  * For more details see: https://github.com/Arduino-IRremote/Arduino-IRremote#compile-options--macros-for-this-library (scroll down)
56  *
57  * - IR_RECEIVE_PIN The pin number for TinyIRReceiver IR input.
58  * - IR_FEEDBACK_LED_PIN The pin number for TinyIRReceiver feedback LED.
59  * - NO_LED_FEEDBACK_CODE Disables the feedback LED function. Saves 14 bytes program memory.
60  * - DISABLE_PARITY_CHECKS Disable parity checks. Saves 48 bytes of program memory.
61  * - USE_EXTENDED_NEC_PROTOCOL Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value.
62  * - USE_ONKYO_PROTOCOL Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value.
63  * - USE_FAST_PROTOCOL Use FAST protocol (no address and 16 bit data, interpreted as 8 bit command and 8 bit inverted command) instead of NEC.
64  * - ENABLE_NEC2_REPEATS Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat.
65  * - USE_CALLBACK_FOR_TINY_RECEIVER Call the fixed function "void handleReceivedTinyIRData()" each time a frame or repeat is received.
66  */
67 
68 #ifndef _TINY_IR_RECEIVER_HPP
69 #define _TINY_IR_RECEIVER_HPP
70 
71 #include <Arduino.h>
72 
73 #if defined(DEBUG) && !defined(LOCAL_DEBUG)
74 #define LOCAL_DEBUG
75 #else
76 //#define LOCAL_DEBUG // This enables debug output only for this file
77 #endif
78 
79 //#define DISABLE_PARITY_CHECKS // Disable parity checks. Saves 48 bytes of program memory.
80 //#define USE_EXTENDED_NEC_PROTOCOL // Like NEC, but take the 16 bit address as one 16 bit value and not as 8 bit normal and 8 bit inverted value.
81 //#define USE_ONKYO_PROTOCOL // Like NEC, but take the 16 bit address and command each as one 16 bit value and not as 8 bit normal and 8 bit inverted value.
82 //#define USE_FAST_PROTOCOL // Use FAST protocol instead of NEC / ONKYO.
83 //#define ENABLE_NEC2_REPEATS // Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat.
84 
85 #include "TinyIR.h" // If not defined, it defines IR_RECEIVE_PIN, IR_FEEDBACK_LED_PIN and TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT
86 
87 #include "digitalWriteFast.h"
92 #if defined(DEBUG)
93 #define LOCAL_DEBUG_ATTACH_INTERRUPT
94 #else
95 //#define LOCAL_DEBUG_ATTACH_INTERRUPT // to see if attachInterrupt() or static interrupt (by register tweaking) is used
96 #endif
97 #if defined(TRACE)
98 #define LOCAL_TRACE_STATE_MACHINE
99 #else
100 //#define LOCAL_TRACE_STATE_MACHINE // to see the state of the ISR (Interrupt Service Routine) state machine
101 #endif
102 
103 //#define _IR_MEASURE_TIMING // Activate this if you want to enable internal hardware timing measurement.
104 //#define _IR_TIMING_TEST_PIN 7
107 
108 /*
109  * Set input pin and output pin definitions etc.
110  */
111 #if defined(IR_INPUT_PIN)
112 #warning "IR_INPUT_PIN is deprecated, use IR_RECEIVE_PIN"
113 #define IR_RECEIVE_PIN IR_INPUT_PIN
114 #endif
115 #if !defined(IR_RECEIVE_PIN)
116 #if defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__)
117 #warning "IR_RECEIVE_PIN is not defined, so it is set to 10"
118 #define IR_RECEIVE_PIN 10
119 #elif defined(__AVR_ATtiny816__)
120 #warning "IR_RECEIVE_PIN is not defined, so it is set to 14"
121 #define IR_RECEIVE_PIN 14
122 #else
123 #warning "IR_RECEIVE_PIN is not defined, so it is set to 2"
124 #define IR_RECEIVE_PIN 2
125 #endif
126 #endif
127 
128 #if !defined(IR_FEEDBACK_LED_PIN) && defined(LED_BUILTIN)
129 #define IR_FEEDBACK_LED_PIN LED_BUILTIN
130 #endif
131 
132 #if !( \
133  (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) /* ATtinyX5 */ \
134 || defined(__AVR_ATtiny88__) /* MH-ET LIVE Tiny88 */ \
135 || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) \
136 || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) \
137 || defined(__AVR_ATmega8__) || defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48PB__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PB__) \
138 || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) \
139  /* ATmegas with ports 0,1,2 above and ATtiny167 only 2 pins below */ \
140 || ( (defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)) && ( (defined(ARDUINO_AVR_DIGISPARKPRO) && ((IR_RECEIVE_PIN == 3) || (IR_RECEIVE_PIN == 9))) /*ATtinyX7(digisparkpro) and pin 3 or 9 */\
141  || (! defined(ARDUINO_AVR_DIGISPARKPRO) && ((IR_RECEIVE_PIN == 3) || (IR_RECEIVE_PIN == 14)))) ) /*ATtinyX7(ATTinyCore) and pin 3 or 14 */ \
142 )
143 #define TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT // Cannot use any static ISR vector here. In other cases we have code provided for generating interrupt on pin change.
144 #endif
145 
151 
152 #if defined(LOCAL_DEBUG)
153 uint32_t sMicrosOfGap; // The length of the gap before the start bit
154 #endif
155 
160 #if defined(ESP8266) || defined(ESP32)
161 IRAM_ATTR
162 #endif
164 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
165  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
166 #endif
167  /*
168  * Save IR input level
169  * Negative logic, true / HIGH means inactive / IR space, LOW / false means IR mark.
170  */
171  uint_fast8_t tIRLevel = digitalReadFast(IR_RECEIVE_PIN);
172 
173 #if !defined(NO_LED_FEEDBACK_CODE) && defined(IR_FEEDBACK_LED_PIN)
174  digitalWriteFast(IR_FEEDBACK_LED_PIN, !tIRLevel);
175 #endif
176 
177  /*
178  * 1. compute microseconds after last change
179  */
180  // Repeats can be sent after a pause, which is longer than 64000 microseconds, so we need a 32 bit value for check of repeats
181  uint32_t tCurrentMicros = micros();
182  uint32_t tMicrosOfMarkOrSpace32 = tCurrentMicros - TinyIRReceiverControl.LastChangeMicros;
183  uint16_t tMicrosOfMarkOrSpace = tMicrosOfMarkOrSpace32;
184 
185  TinyIRReceiverControl.LastChangeMicros = tCurrentMicros;
186 
187  uint8_t tState = TinyIRReceiverControl.IRReceiverState;
188 
189 #if defined(LOCAL_TRACE_STATE_MACHINE)
190  Serial.print(tState);
191  Serial.print(F(" D="));
192  Serial.print(tMicrosOfMarkOrSpace);
193 // Serial.print(F(" I="));
194 // Serial.print(tIRLevel);
195  Serial.print('|');
196 #endif
197 
198  if (tIRLevel == LOW) {
199  /*
200  * We have a mark here
201  */
202  if (tMicrosOfMarkOrSpace > 2 * TINY_RECEIVER_HEADER_MARK) {
203  // timeout -> must reset state machine
205  }
207  // We are at the beginning of the header mark, check timing at the next transition
209  TinyIRReceiverControl.Flags = IRDATA_FLAGS_EMPTY; // If we do it here, it saves 4 bytes
210 #if defined(LOCAL_TRACE)
211  sMicrosOfGap = tMicrosOfMarkOrSpace32;
212 #endif
213 #if defined(ENABLE_NEC2_REPEATS)
214  // Check for repeat, where full frame is sent again after TINY_RECEIVER_REPEAT_PERIOD ms
215  // Not required for NEC, where repeats are detected by a special header space duration
216  // Must use 32 bit arithmetic here!
217  if (tMicrosOfMarkOrSpace32 < TINY_RECEIVER_MAXIMUM_REPEAT_DISTANCE) {
219  }
220 #endif
221  }
222 
224  if (tMicrosOfMarkOrSpace >= lowerValue25Percent(TINY_RECEIVER_HEADER_SPACE)
225  && tMicrosOfMarkOrSpace <= upperValue25Percent(TINY_RECEIVER_HEADER_SPACE)) {
226  /*
227  * We have a valid data header space here -> initialize data
228  */
230 #if (TINY_RECEIVER_BITS > 16)
232 #else
234 #endif
237 #if !defined(ENABLE_NEC2_REPEATS)
238  // Check for NEC repeat header
239  } else if (tMicrosOfMarkOrSpace >= lowerValue25Percent(NEC_REPEAT_HEADER_SPACE)
240  && tMicrosOfMarkOrSpace <= upperValue25Percent(NEC_REPEAT_HEADER_SPACE)
242  /*
243  * We have a repeat header here and no broken receive before -> set repeat flag
244  */
247 #endif
248  } else {
249  // This parts are optimized by the compiler into jumps to one code :-)
250  // Wrong length -> reset state
252  }
253  }
254 
255  else if (tState == IR_RECEIVER_STATE_WAITING_FOR_DATA_MARK) {
256  // Check data space length
257  if (tMicrosOfMarkOrSpace >= lowerValue50Percent(TINY_RECEIVER_ZERO_SPACE)
258  && tMicrosOfMarkOrSpace <= upperValue50Percent(TINY_RECEIVER_ONE_SPACE)) {
259  // We have a valid bit here
261  if (tMicrosOfMarkOrSpace >= 2 * TINY_RECEIVER_UNIT) {
262  // we received a 1
263 #if (TINY_RECEIVER_BITS > 16)
265 #else
267 #endif
268  } else {
269  // we received a 0 - empty code for documentation
270  }
271  // prepare for next bit
274  } else {
275  // Wrong length -> reset state
277  }
278  } else {
279  // error wrong state for the received level, e.g. if we missed one change interrupt -> reset state
281  }
282  }
283 
284  else {
285  /*
286  * We have a space here
287  */
289  /*
290  * Check length of header mark here
291  */
292  if (tMicrosOfMarkOrSpace >= lowerValue25Percent(TINY_RECEIVER_HEADER_MARK)
293  && tMicrosOfMarkOrSpace <= upperValue25Percent(TINY_RECEIVER_HEADER_MARK)) {
295  } else {
296  // Wrong length of header mark -> reset state
298  }
299  }
300 
301  else if (tState == IR_RECEIVER_STATE_WAITING_FOR_DATA_SPACE) {
302  // Check data mark length
303  if (tMicrosOfMarkOrSpace >= lowerValue50Percent(TINY_RECEIVER_BIT_MARK)
304  && tMicrosOfMarkOrSpace <= upperValue50Percent(TINY_RECEIVER_BIT_MARK)) {
305  /*
306  * We have a valid mark here, check for transmission complete, i.e. the mark of the stop bit
307  */
309 #if !defined(ENABLE_NEC2_REPEATS)
310  || (TinyIRReceiverControl.Flags & IRDATA_FLAGS_IS_REPEAT) // Do not check for full length received, if we have a short repeat frame
311 #endif
312  ) {
313  /*
314  * Code complete -> optionally check parity
315  */
316  // Reset state for new start
318 
319 #if !defined(DISABLE_PARITY_CHECKS) && (TINY_RECEIVER_ADDRESS_BITS == 16) && TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY
320  /*
321  * Check address parity
322  * Address is sent first and contained in the lower word
323  */
325 #if defined(ENABLE_NEC2_REPEATS)
326  TinyIRReceiverControl.Flags |= IRDATA_FLAGS_PARITY_FAILED; // here we can have the repeat flag already set
327 #else
328  TinyIRReceiverControl.Flags = IRDATA_FLAGS_PARITY_FAILED; // here we do not check anything, if we have a repeat
329 #endif
330  }
331 #endif
332 #if !defined(DISABLE_PARITY_CHECKS) && (TINY_RECEIVER_COMMAND_BITS == 16) && TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
333  /*
334  * Check command parity
335  */
336 #if (TINY_RECEIVER_ADDRESS_BITS > 0)
338 #if defined(ENABLE_NEC2_REPEATS)
340 #else
342 #endif
343 # if defined(LOCAL_DEBUG)
344  Serial.print(F("Parity check for command failed. Command="));
345  Serial.print(TinyIRReceiverControl.IRRawData.UBytes[2], HEX);
346  Serial.print(F(" parity="));
347  Serial.println(TinyIRReceiverControl.IRRawData.UBytes[3], HEX);
348 # endif
349 #else
350  // No address, so command and parity are in the lowest bytes
353 # if defined(LOCAL_DEBUG)
354  Serial.print(F("Parity check for command failed. Command="));
355  Serial.print(TinyIRReceiverControl.IRRawData.UBytes[0], HEX);
356  Serial.print(F(" parity="));
357  Serial.println(TinyIRReceiverControl.IRRawData.UBytes[1], HEX);
358 # endif
359 #endif
360  }
361 #endif
362  /*
363  * Call user provided callback here
364  * The parameter size is dependent of the code variant used in order to save program memory.
365  * We have 6 cases: 0, 8 bit or 16 bit address, each with 8 or 16 bit command
366  */
367 #if !defined(ARDUINO_ARCH_MBED) && !defined(ESP32) // no Serial etc. in callback for ESP -> no interrupt required, WDT is running!
368  interrupts(); // enable interrupts, so delay() etc. works in callback
369 #endif
372 #if (TINY_RECEIVER_ADDRESS_BITS > 0)
373 # if TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY
374  // Here we have 8 bit address
376 # else
377  // Here we have 16 bit address
379 # endif
380 # if TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
381  // Here we have 8 bit command
383 # else
384  // Here we have 16 bit command
386 # endif
387 
388 #else
389  // Here we have NO address
390 # if TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
391  // Here we have 8 bit command
393 # else
394  // Here we have 16 bit command
396 # endif
397 #endif
398 #if defined(USE_CALLBACK_FOR_TINY_RECEIVER)
399  handleReceivedTinyIRData();
400 #endif
401 
402  } else {
403  // not finished yet
405  }
406  } else {
407  // Wrong length -> reset state
409  }
410  } else {
411  // error wrong state for the received level, e.g. if we missed one change interrupt -> reset state
413  }
414  }
415 
417 #ifdef _IR_MEASURE_TIMING
418  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
419 #endif
420 }
421 
424 }
425 
426 /*
427  * Checks if IR_RECEIVE_PIN is connected and high
428  * @return true, if IR Receiver is attached
429  */
431  pinModeFast(IR_RECEIVE_PIN, OUTPUT);
432  digitalWriteFast(IR_RECEIVE_PIN, LOW); // discharge pin capacity
433  pinModeFast(IR_RECEIVE_PIN, INPUT);
434  return digitalRead(IR_RECEIVE_PIN); // use slow digitalRead here, since the pin capacity is not fully charged again if we use digitalReadFast.
435 }
436 
442  pinModeFast(IR_RECEIVE_PIN, INPUT);
443 
444 #if !defined(NO_LED_FEEDBACK_CODE) && defined(IR_FEEDBACK_LED_PIN)
445  pinModeFast(IR_FEEDBACK_LED_PIN, OUTPUT);
446 #endif
448 }
449 
450 void printTinyReceiverResultMinimal(Print *aSerial) {
451 // Print only very short output, since we are in an interrupt context and do not want to miss the next interrupts of the repeats coming soon
452  // Print only very short output, since we are in an interrupt context and do not want to miss the next interrupts of the repeats coming soon
453 #if defined(USE_FAST_PROTOCOL)
454  aSerial->print(F("C=0x"));
455 #else
456  aSerial->print(F("A=0x"));
457  aSerial->print(TinyIRReceiverData.Address, HEX);
458  aSerial->print(F(" C=0x"));
459 #endif
460  aSerial->print(TinyIRReceiverData.Command, HEX);
462  aSerial->print(F(" R"));
463  }
464 #if !defined(DISABLE_PARITY_CHECKS)
466  aSerial->print(F(" P"));
467  }
468 #endif
469  aSerial->println();
470 }
471 
472 #if defined (LOCAL_DEBUG_ATTACH_INTERRUPT) && !defined(STR)
473 // Helper macro for getting a macro definition as string
474 #define STR_HELPER(x) #x
475 #define STR(x) STR_HELPER(x)
476 #endif
477 
478 /**************************************************
479  * Pin to interrupt mapping for different platforms
480  **************************************************/
481 #if defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__)
482 #define USE_ATTACH_INTERRUPT_DIRECT
483 
484 #elif !defined(__AVR__) || defined(TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT)
485 // Default for all NON AVR platforms
486 #define USE_ATTACH_INTERRUPT
487 
488 #else
489 # if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
490 #define USE_PCIE
491 
492 # elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
493 # if defined(ARDUINO_AVR_DIGISPARKPRO)
494 # if (IR_RECEIVE_PIN == 3)
495 #define USE_INT0
496 # elif (IR_RECEIVE_PIN == 9)
497 #define USE_INT1
498 # else
499 # error "IR_RECEIVE_PIN must be 9 or 3."
500 # endif // if (IR_RECEIVE_PIN == 9)
501 # else // defined(ARDUINO_AVR_DIGISPARKPRO)
502 # if (IR_RECEIVE_PIN == 14)
503 #define USE_INT0
504 # elif (IR_RECEIVE_PIN == 3)
505 #define USE_INT1
506 # else
507 # error "IR_RECEIVE_PIN must be 14 or 3."
508 # endif // if (IR_RECEIVE_PIN == 14)
509 # endif
510 
511 # elif (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__))
512 # if (IR_RECEIVE_PIN == 21)
513 #define USE_INT0
514 # elif (IR_RECEIVE_PIN == 20)
515 #define USE_INT1
516 # else
517 #warning "No pin mapping for IR_RECEIVE_PIN to interrupt found -> attachInterrupt() is used now."
518 #define USE_ATTACH_INTERRUPT
519 # endif
520 
521 # else // defined(__AVR_ATtiny25__)
522 /*
523  * ATmegas + ATtiny88 here
524  */
525 # if (IR_RECEIVE_PIN == 2)
526 #define USE_INT0
527 # elif (IR_RECEIVE_PIN == 3)
528 #define USE_INT1
529 
530 # elif IR_RECEIVE_PIN == 4 || IR_RECEIVE_PIN == 5 || IR_RECEIVE_PIN == 6 || IR_RECEIVE_PIN == 7
531  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 20 to 23 for port PD4 to PD7 (Arduino pin 4 to 7)
532 #define USE_PCINT2
533 # elif IR_RECEIVE_PIN == 8 || IR_RECEIVE_PIN == 9 || IR_RECEIVE_PIN == 10 || IR_RECEIVE_PIN == 11 || IR_RECEIVE_PIN == 12 || IR_RECEIVE_PIN == 13
534  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 0 to 5 for port PB0 to PB5 (Arduino pin 8 to 13)
535 #define USE_PCINT0
536 # elif IR_RECEIVE_PIN == A0 || IR_RECEIVE_PIN == A1 || IR_RECEIVE_PIN == A2 || IR_RECEIVE_PIN == A3 || IR_RECEIVE_PIN == A4 || IR_RECEIVE_PIN == A5
537  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 8 to 13 for port PC0 to PC5 (Arduino pin A0 to A5)
538 #define USE_PCINT1
539 
540 # else
541 #warning "No pin mapping for IR_RECEIVE_PIN to interrupt found -> attachInterrupt() is used now."
542 #define USE_ATTACH_INTERRUPT
543 # endif // if (IR_RECEIVE_PIN == 2)
544 # endif // defined(__AVR_ATtiny25__)
545 #endif // ! defined(__AVR__) || defined(TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT)
546 
552 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
553  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
554 #endif
555 
556 #if defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT)
557 # if defined(USE_ATTACH_INTERRUPT)
558 #if defined(NOT_AN_INTERRUPT)
559  if(digitalPinToInterrupt(IR_RECEIVE_PIN) == NOT_AN_INTERRUPT){
560  return false;
561  }
562 #endif
563  // costs 112 bytes program memory + 4 bytes RAM
564  attachInterrupt(digitalPinToInterrupt(IR_RECEIVE_PIN), IRPinChangeInterruptHandler, CHANGE);
565 # else
566  // 2.2 us more than version configured with macros and not compatible
567  attachInterrupt(IR_RECEIVE_PIN, IRPinChangeInterruptHandler, CHANGE); // no extra pin mapping here
568 # endif
569 
570 # if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
571  Serial.println(F("Use attachInterrupt for pin=" STR(IR_RECEIVE_PIN)));
572 # endif
573 
574 #else
575 # if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
576  Serial.println(F("Use static interrupt for pin=" STR(IR_RECEIVE_PIN)));
577 # endif
578 # if defined(USE_INT0)
579  // interrupt on any logical change
580  EICRA |= _BV(ISC00);
581  // clear interrupt bit
582  EIFR |= 1 << INTF0;
583  // enable interrupt on next change
584  EIMSK |= 1 << INT0;
585 
586 # elif defined(USE_INT1)
587  EICRA |= _BV(ISC10);
588 // clear interrupt bit
589  EIFR |= 1 << INTF1;
590 // enable interrupt on next change
591  EIMSK |= 1 << INT1;
592 
593 # elif defined(USE_PCIE) // For ATtiny85 etc.
594  // use PinChangeInterrupt no INT0 for pin PB2
595  PCMSK = _BV(IR_RECEIVE_PIN);
596  // clear interrupt bit
597  GIFR |= 1 << PCIF;
598  // enable interrupt on next change
599  GIMSK |= 1 << PCIE;
600 
601 # elif defined(USE_PCINT0)
602  PCICR |= _BV(PCIE0);
603  PCMSK0 = digitalPinToBitMask(IR_RECEIVE_PIN);
604 # elif defined(USE_PCINT1)
605  PCICR |= _BV(PCIE1);
606  PCMSK1 = digitalPinToBitMask(IR_RECEIVE_PIN);
607 # elif defined(USE_PCINT2)
608  PCICR |= _BV(PCIE2);
609  PCMSK2 = digitalPinToBitMask(IR_RECEIVE_PIN);
610 # else
611  return false;
612 # endif
613 #endif // defined(USE_ATTACH_INTERRUPT)
614  return true;
615 }
616 
618 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
619  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
620 #endif
621 
622 #if defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT)
623 # if defined(USE_ATTACH_INTERRUPT)
624  detachInterrupt(digitalPinToInterrupt(IR_RECEIVE_PIN));
625 # else
626  detachInterrupt(IR_RECEIVE_PIN);
627 # endif
628 
629 #else
630 # if defined(USE_INT0)
631  // clear interrupt bit
632  EIFR |= 1 << INTF0;
633  // disable interrupt on next change
634  EIMSK &= ~(1 << INT0);
635 
636 # elif defined(USE_INT1)
637  // clear interrupt bit
638  EIFR |= 1 << INTF1;
639  // disable interrupt on next change
640  EIMSK &= ~(1 << INT1);
641 
642 # elif defined(USE_PCIE) // For ATtiny85 etc.
643  // clear interrupt bit
644  GIFR |= 1 << PCIF;
645  // disable interrupt on next change
646  GIMSK &= ~(1 << PCIE);
647 
648 # elif defined(USE_PCINT0)
649  PCICR &= ~(_BV(PCIE0));
650 # elif defined(USE_PCINT1)
651  PCICR &= ~(_BV(PCIE1));
652 # elif defined(USE_PCINT2)
653  PCICR &= ~(_BV(PCIE2));
654 
655 # endif
656 #endif // defined(USE_ATTACH_INTERRUPT)
657 }
658 
659 /*
660  * Specify the right INT0, INT1 or PCINT0 interrupt vector according to different pins and cores.
661  * The default value of TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT is set in TinyIRReceiver.h
662  */
663 #if !(defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT))
664 # if defined(USE_INT0)
665 ISR(INT0_vect)
666 
667 # elif defined(USE_INT1)
668 ISR(INT1_vect)
669 
670 # elif defined(USE_PCIE) // For ATtiny85 etc.
671 // on ATtinyX5 we do not have a INT1_vect but we can use the PCINT0_vect
672 ISR(PCINT0_vect)
673 
674 # elif defined(USE_PCINT0)
675 ISR(PCINT0_vect)
676 # elif defined(USE_PCINT1)
677 ISR(PCINT1_vect)
678 # elif defined(USE_PCINT2)
679 ISR(PCINT2_vect)
680 # else
681 void dummyFunctionToAvoidCompilerErrors()
682 # endif
683 {
685 }
686 #endif // !(defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT))
687 
690 #if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
691 #undef LOCAL_DEBUG_ATTACH_INTERRUPT
692 #endif
693 #if defined(LOCAL_TRACE_STATE_MACHINE)
694 #undef LOCAL_TRACE_STATE_MACHINE
695 #endif
696 
697 #if defined(LOCAL_DEBUG)
698 #undef LOCAL_DEBUG
699 #endif
700 #endif // _TINY_IR_RECEIVER_HPP
TinyIRReceiverStruct::IRReceiverState
uint8_t IRReceiverState
The state of the state machine.
Definition: TinyIR.h:204
lowerValue25Percent
#define lowerValue25Percent(aDuration)
Definition: TinyIR.h:182
digitalReadFast
#define digitalReadFast
Definition: digitalWriteFast.h:393
IR_RECEIVER_STATE_WAITING_FOR_START_MARK
#define IR_RECEIVER_STATE_WAITING_FOR_START_MARK
Definition: TinyIR.h:190
TinyIRReceiverCallbackDataStruct::Flags
uint8_t Flags
Definition: TinyIR.h:245
TinyIRReceiverStruct
Control and data variables of the state machine for TinyReceiver.
Definition: TinyIR.h:199
IR_RECEIVER_STATE_WAITING_FOR_DATA_MARK
#define IR_RECEIVER_STATE_WAITING_FOR_DATA_MARK
Definition: TinyIR.h:194
TinyIRReceiverStruct::Flags
uint8_t Flags
One of IRDATA_FLAGS_EMPTY, IRDATA_FLAGS_IS_REPEAT, and IRDATA_FLAGS_PARITY_FAILED.
Definition: TinyIR.h:216
pinModeFast
#define pinModeFast
Definition: digitalWriteFast.h:371
digitalWriteFast
#define digitalWriteFast
Definition: digitalWriteFast.h:339
TinyIRReceiverControl
TinyIRReceiverStruct TinyIRReceiverControl
Definition: TinyIRReceiver.hpp:105
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:91
LongUnion::UBytes
uint8_t UBytes[4]
Definition: LongUnion.h:91
enablePCIInterruptForTinyReceiver
bool enablePCIInterruptForTinyReceiver()
Initializes hardware interrupt generation according to IR_RECEIVE_PIN or use attachInterrupt() functi...
Definition: TinyIRReceiver.hpp:551
TinyIR.h
TinyIRReceiverData
volatile TinyIRReceiverCallbackDataStruct TinyIRReceiverData
Definition: TinyIRReceiver.hpp:106
LongUnion::LowWord
uint16_t LowWord
Definition: LongUnion.h:80
IR_RECEIVE_PIN
#define IR_RECEIVE_PIN
Definition: TinyIRReceiver.hpp:124
isTinyReceiverIdle
bool isTinyReceiverIdle()
Definition: TinyIRReceiver.hpp:422
TINY_RECEIVER_ONE_SPACE
#define TINY_RECEIVER_ONE_SPACE
Definition: TinyIR.h:157
IRDATA_FLAGS_PARITY_FAILED
#define IRDATA_FLAGS_PARITY_FAILED
The current (autorepeat) frame violated parity check.
Definition: IRProtocol.h:93
disablePCIInterruptForTinyReceiver
void disablePCIInterruptForTinyReceiver()
Definition: TinyIRReceiver.hpp:617
digitalWriteFast.h
handleTinyReceivedIRData
void handleTinyReceivedIRData()
Declaration of the callback function provided by the user application.
TinyIRReceiverCallbackDataStruct::Address
uint16_t Address
Definition: TinyIR.h:234
TINY_RECEIVER_BITS
#define TINY_RECEIVER_BITS
Definition: TinyIR.h:150
LongUnion::HighWord
uint16_t HighWord
Definition: LongUnion.h:81
IR_RECEIVER_STATE_WAITING_FOR_DATA_SPACE
#define IR_RECEIVER_STATE_WAITING_FOR_DATA_SPACE
Definition: TinyIR.h:193
TinyIRReceiverCallbackDataStruct::justWritten
bool justWritten
Is set true if new data is available. Used by the main loop, to avoid multiple evaluations of the sam...
Definition: TinyIR.h:246
upperValue50Percent
#define upperValue50Percent(aDuration)
Definition: TinyIR.h:185
TinyIRReceiverStruct::LastChangeMicros
uint32_t LastChangeMicros
Microseconds of last Pin Change Interrupt.
Definition: TinyIR.h:203
TINY_RECEIVER_HEADER_MARK
#define TINY_RECEIVER_HEADER_MARK
Definition: TinyIR.h:153
TinyIRReceiverStruct::IRRawDataMask
uint32_t IRRawDataMask
The corresponding bit mask for IRRawDataBitCounter.
Definition: TinyIR.h:210
TinyIRReceiverCallbackDataStruct
Is filled before calling the user callback to transfer received data to main loop for further process...
Definition: TinyIR.h:231
IRPinChangeInterruptHandler
void IRPinChangeInterruptHandler(void)
The ISR (Interrupt Service Routine) of TinyIRRreceiver.
Definition: TinyIRReceiver.hpp:163
TinyIRReceiverCallbackDataStruct::Command
uint16_t Command
Definition: TinyIR.h:241
printTinyReceiverResultMinimal
void printTinyReceiverResultMinimal(Print *aSerial)
Definition: TinyIRReceiver.hpp:450
TinyIRReceiverStruct::IRRawDataBitCounter
uint8_t IRRawDataBitCounter
How many bits are currently contained in raw data.
Definition: TinyIR.h:205
TINY_RECEIVER_HEADER_SPACE
#define TINY_RECEIVER_HEADER_SPACE
Definition: TinyIR.h:154
LongUnion::ULong
uint32_t ULong
Definition: LongUnion.h:95
TINY_RECEIVER_UNIT
#define TINY_RECEIVER_UNIT
Definition: TinyIR.h:151
IRDATA_FLAGS_EMPTY
#define IRDATA_FLAGS_EMPTY
Definition: IRProtocol.h:90
TINY_RECEIVER_BIT_MARK
#define TINY_RECEIVER_BIT_MARK
Definition: TinyIR.h:156
upperValue25Percent
#define upperValue25Percent(aDuration)
Definition: TinyIR.h:183
NEC_REPEAT_HEADER_SPACE
#define NEC_REPEAT_HEADER_SPACE
Definition: ir_NEC.hpp:107
TINY_RECEIVER_ZERO_SPACE
#define TINY_RECEIVER_ZERO_SPACE
Definition: TinyIR.h:158
TINY_RECEIVER_MAXIMUM_REPEAT_DISTANCE
#define TINY_RECEIVER_MAXIMUM_REPEAT_DISTANCE
Definition: TinyIR.h:160
isIRReceiverAttachedForTinyReceiver
bool isIRReceiverAttachedForTinyReceiver()
Definition: TinyIRReceiver.hpp:430
lowerValue50Percent
#define lowerValue50Percent(aDuration)
Definition: TinyIR.h:184
IR_RECEIVER_STATE_WAITING_FOR_FIRST_DATA_MARK
#define IR_RECEIVER_STATE_WAITING_FOR_FIRST_DATA_MARK
Definition: TinyIR.h:192
LongUnion::UWord
struct LongUnion::@6 UWord
TinyIRReceiverStruct::IRRawData
LongUnion IRRawData
The current raw data. LongUnion helps with decoding of address and command.
Definition: TinyIR.h:211
IR_RECEIVER_STATE_WAITING_FOR_START_SPACE
#define IR_RECEIVER_STATE_WAITING_FOR_START_SPACE
Definition: TinyIR.h:191
initPCIInterruptForTinyReceiver
bool initPCIInterruptForTinyReceiver()
Sets IR_RECEIVE_PIN mode to INPUT, and if IR_FEEDBACK_LED_PIN is defined, sets feedback LED output mo...
Definition: TinyIRReceiver.hpp:441