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 /*
80  * Protocol selection
81  */
82 //#define DISABLE_PARITY_CHECKS // Disable parity checks. Saves 48 bytes of program memory.
83 //#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.
84 //#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.
85 //#define USE_FAST_PROTOCOL // Use FAST protocol instead of NEC / ONKYO.
86 //#define ENABLE_NEC2_REPEATS // Instead of sending / receiving the NEC special repeat code, send / receive the original frame for repeat.
87 
88 #include "TinyIR.h" // If not defined, it defines IR_RECEIVE_PIN, IR_FEEDBACK_LED_PIN and TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT
89 
90 #include "digitalWriteFast.h"
95 #if defined(DEBUG)
96 #define LOCAL_DEBUG_ATTACH_INTERRUPT
97 #else
98 //#define LOCAL_DEBUG_ATTACH_INTERRUPT // to see if attachInterrupt() or static interrupt (by register tweaking) is used
99 #endif
100 #if defined(TRACE)
101 #define LOCAL_TRACE_STATE_MACHINE
102 #else
103 //#define LOCAL_TRACE_STATE_MACHINE // to see the state of the ISR (Interrupt Service Routine) state machine
104 #endif
105 
106 //#define _IR_MEASURE_TIMING // Activate this if you want to enable internal hardware timing measurement.
107 //#define _IR_TIMING_TEST_PIN 7
110 
111 /*
112  * Set input pin and output pin definitions etc.
113  */
114 #if defined(IR_INPUT_PIN)
115 #warning "IR_INPUT_PIN is deprecated, use IR_RECEIVE_PIN"
116 #define IR_RECEIVE_PIN IR_INPUT_PIN
117 #endif
118 #if !defined(IR_RECEIVE_PIN)
119 #if defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__)
120 #warning "IR_RECEIVE_PIN is not defined, so it is set to 10"
121 #define IR_RECEIVE_PIN 10
122 #elif defined(__AVR_ATtiny816__)
123 #warning "IR_RECEIVE_PIN is not defined, so it is set to 14"
124 #define IR_RECEIVE_PIN 14
125 #else
126 #warning "IR_RECEIVE_PIN is not defined, so it is set to 2"
127 #define IR_RECEIVE_PIN 2
128 #endif
129 #endif
130 
131 #if !defined(IR_FEEDBACK_LED_PIN) && defined(LED_BUILTIN)
132 #define IR_FEEDBACK_LED_PIN LED_BUILTIN
133 #endif
134 
135 #if !( \
136  (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) /* ATtinyX5 */ \
137 || defined(__AVR_ATtiny88__) /* MH-ET LIVE Tiny88 */ \
138 || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) \
139 || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) \
140 || defined(__AVR_ATmega8__) || defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48PB__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PB__) \
141 || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) \
142  /* ATmegas with ports 0,1,2 above and ATtiny167 only 2 pins below */ \
143 || ( (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 */\
144  || (! defined(ARDUINO_AVR_DIGISPARKPRO) && ((IR_RECEIVE_PIN == 3) || (IR_RECEIVE_PIN == 14)))) ) /*ATtinyX7(ATTinyCore) and pin 3 or 14 */ \
145 )
146 #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.
147 #endif
148 
154 
155 #if defined(LOCAL_DEBUG)
156 uint32_t sMicrosOfGap; // The length of the gap before the start bit
157 #endif
158 
163 #if defined(ESP8266) || defined(ESP32)
164 IRAM_ATTR
165 #endif
167 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
168  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
169 #endif
170  /*
171  * Save IR input level
172  * Negative logic, true / HIGH means inactive / IR space, LOW / false means IR mark.
173  */
174  uint_fast8_t tIRLevel = digitalReadFast(IR_RECEIVE_PIN);
175 
176 #if !defined(NO_LED_FEEDBACK_CODE) && defined(IR_FEEDBACK_LED_PIN)
177  digitalWriteFast(IR_FEEDBACK_LED_PIN, !tIRLevel);
178 #endif
179 
180  /*
181  * 1. compute microseconds after last change
182  */
183  // Repeats can be sent after a pause, which is longer than 64000 microseconds, so we need a 32 bit value for check of repeats
184  uint32_t tCurrentMicros = micros();
185  uint32_t tMicrosOfMarkOrSpace32 = tCurrentMicros - TinyIRReceiverControl.LastChangeMicros;
186  uint16_t tMicrosOfMarkOrSpace = tMicrosOfMarkOrSpace32;
187 
188  TinyIRReceiverControl.LastChangeMicros = tCurrentMicros;
189 
190  uint8_t tState = TinyIRReceiverControl.IRReceiverState;
191 
192 #if defined(LOCAL_TRACE_STATE_MACHINE)
193  Serial.print(tState);
194  Serial.print(F(" D="));
195  Serial.print(tMicrosOfMarkOrSpace);
196 // Serial.print(F(" I="));
197 // Serial.print(tIRLevel);
198  Serial.print('|');
199 #endif
200 
201  if (tIRLevel == LOW) {
202  /*
203  * We have a mark here
204  */
205  if (tMicrosOfMarkOrSpace > 2 * TINY_RECEIVER_HEADER_MARK) {
206  // timeout -> must reset state machine
208  }
210  // We are at the beginning of the header mark, check timing at the next transition
212  TinyIRReceiverControl.Flags = IRDATA_FLAGS_EMPTY; // If we do it here, it saves 4 bytes
213 #if defined(LOCAL_TRACE)
214  sMicrosOfGap = tMicrosOfMarkOrSpace32;
215 #endif
216 #if defined(ENABLE_NEC2_REPEATS)
217  // Check for repeat, where full frame is sent again after TINY_RECEIVER_REPEAT_PERIOD ms
218  // Not required for NEC, where repeats are detected by a special header space duration
219  // Must use 32 bit arithmetic here!
220  if (tMicrosOfMarkOrSpace32 < TINY_RECEIVER_MAXIMUM_REPEAT_DISTANCE) {
222  }
223 #endif
224  }
225 
227  if (tMicrosOfMarkOrSpace >= lowerValue25Percent(TINY_RECEIVER_HEADER_SPACE)
228  && tMicrosOfMarkOrSpace <= upperValue25Percent(TINY_RECEIVER_HEADER_SPACE)) {
229  /*
230  * We have a valid data header space here -> initialize data
231  */
233 #if (TINY_RECEIVER_BITS > 16)
235 #else
237 #endif
240 #if !defined(ENABLE_NEC2_REPEATS)
241  // Check for NEC repeat header
242  } else if (tMicrosOfMarkOrSpace >= lowerValue25Percent(NEC_REPEAT_HEADER_SPACE)
243  && tMicrosOfMarkOrSpace <= upperValue25Percent(NEC_REPEAT_HEADER_SPACE)
245  /*
246  * We have a repeat header here and no broken receive before -> set repeat flag
247  */
250 #endif
251  } else {
252  // This parts are optimized by the compiler into jumps to one code :-)
253  // Wrong length -> reset state
255  }
256  }
257 
258  else if (tState == IR_RECEIVER_STATE_WAITING_FOR_DATA_MARK) {
259  // Check data space length
260  if (tMicrosOfMarkOrSpace >= lowerValue50Percent(TINY_RECEIVER_ZERO_SPACE)
261  && tMicrosOfMarkOrSpace <= upperValue50Percent(TINY_RECEIVER_ONE_SPACE)) {
262  // We have a valid bit here
264  if (tMicrosOfMarkOrSpace >= 2 * TINY_RECEIVER_UNIT) {
265  // we received a 1
266 #if (TINY_RECEIVER_BITS > 16)
268 #else
270 #endif
271  } else {
272  // we received a 0 - empty code for documentation
273  }
274  // prepare for next bit
277  } else {
278  // Wrong length -> reset state
280  }
281  } else {
282  // error wrong state for the received level, e.g. if we missed one change interrupt -> reset state
284  }
285  }
286 
287  else {
288  /*
289  * We have a space here
290  */
292  /*
293  * Check length of header mark here
294  */
295  if (tMicrosOfMarkOrSpace >= lowerValue25Percent(TINY_RECEIVER_HEADER_MARK)
296  && tMicrosOfMarkOrSpace <= upperValue25Percent(TINY_RECEIVER_HEADER_MARK)) {
298  } else {
299  // Wrong length of header mark -> reset state
301  }
302  }
303 
304  else if (tState == IR_RECEIVER_STATE_WAITING_FOR_DATA_SPACE) {
305  // Check data mark length
306  if (tMicrosOfMarkOrSpace >= lowerValue50Percent(TINY_RECEIVER_BIT_MARK)
307  && tMicrosOfMarkOrSpace <= upperValue50Percent(TINY_RECEIVER_BIT_MARK)) {
308  /*
309  * We have a valid mark here, check for transmission complete, i.e. the mark of the stop bit
310  */
312 #if !defined(ENABLE_NEC2_REPEATS)
313  || (TinyIRReceiverControl.Flags & IRDATA_FLAGS_IS_REPEAT) // Do not check for full length received, if we have a short repeat frame
314 #endif
315  ) {
316  /*
317  * Code complete -> optionally check parity
318  */
319  // Reset state for new start
321 
322 #if !defined(DISABLE_PARITY_CHECKS) && (TINY_RECEIVER_ADDRESS_BITS == 16) && TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY
323  /*
324  * Check address parity
325  * Address is sent first and contained in the lower word
326  */
328 #if defined(ENABLE_NEC2_REPEATS)
329  TinyIRReceiverControl.Flags |= IRDATA_FLAGS_PARITY_FAILED; // here we can have the repeat flag already set
330 #else
331  TinyIRReceiverControl.Flags = IRDATA_FLAGS_PARITY_FAILED; // here we do not check anything, if we have a repeat
332 #endif
333  }
334 #endif
335 #if !defined(DISABLE_PARITY_CHECKS) && (TINY_RECEIVER_COMMAND_BITS == 16) && TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
336  /*
337  * Check command parity
338  */
339 #if (TINY_RECEIVER_ADDRESS_BITS > 0)
341 #if defined(ENABLE_NEC2_REPEATS)
343 #else
345 #endif
346 # if defined(LOCAL_DEBUG)
347  Serial.print(F("Parity check for command failed. Command="));
348  Serial.print(TinyIRReceiverControl.IRRawData.UBytes[2], HEX);
349  Serial.print(F(" parity="));
350  Serial.println(TinyIRReceiverControl.IRRawData.UBytes[3], HEX);
351 # endif
352 #else
353  // No address, so command and parity are in the lowest bytes
356 # if defined(LOCAL_DEBUG)
357  Serial.print(F("Parity check for command failed. Command="));
358  Serial.print(TinyIRReceiverControl.IRRawData.UBytes[0], HEX);
359  Serial.print(F(" parity="));
360  Serial.println(TinyIRReceiverControl.IRRawData.UBytes[1], HEX);
361 # endif
362 #endif
363  }
364 #endif
365  /*
366  * Call user provided callback here
367  * The parameter size is dependent of the code variant used in order to save program memory.
368  * We have 6 cases: 0, 8 bit or 16 bit address, each with 8 or 16 bit command
369  */
370 #if !defined(ARDUINO_ARCH_MBED) && !defined(ESP32) // no Serial etc. in callback for ESP -> no interrupt required, WDT is running!
371  interrupts(); // enable interrupts, so delay() etc. works in callback
372 #endif
375 #if (TINY_RECEIVER_ADDRESS_BITS > 0)
376 # if TINY_RECEIVER_ADDRESS_HAS_8_BIT_PARITY
377  // Here we have 8 bit address
379 # else
380  // Here we have 16 bit address
382 # endif
383 # if TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
384  // Here we have 8 bit command
386 # else
387  // Here we have 16 bit command
389 # endif
390 
391 #else
392  // Here we have NO address
393 # if TINY_RECEIVER_COMMAND_HAS_8_BIT_PARITY
394  // Here we have 8 bit command
396 # else
397  // Here we have 16 bit command
399 # endif
400 #endif
401 #if defined(USE_CALLBACK_FOR_TINY_RECEIVER)
402  handleReceivedTinyIRData();
403 #endif
404 
405  } else {
406  // not finished yet
408  }
409  } else {
410  // Wrong length -> reset state
412  }
413  } else {
414  // error wrong state for the received level, e.g. if we missed one change interrupt -> reset state
416  }
417  }
418 
420 #ifdef _IR_MEASURE_TIMING
421  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
422 #endif
423 }
424 
427 }
428 
429 /*
430  * Checks if IR_RECEIVE_PIN is connected and high
431  * @return true, if IR Receiver is attached
432  */
434  pinModeFast(IR_RECEIVE_PIN, OUTPUT);
435  digitalWriteFast(IR_RECEIVE_PIN, LOW); // discharge pin capacity
436  pinModeFast(IR_RECEIVE_PIN, INPUT);
437  return digitalRead(IR_RECEIVE_PIN); // use slow digitalRead here, since the pin capacity is not fully charged again if we use digitalReadFast.
438 }
439 
445  pinModeFast(IR_RECEIVE_PIN, INPUT);
446 
447 #if !defined(NO_LED_FEEDBACK_CODE) && defined(IR_FEEDBACK_LED_PIN)
448  pinModeFast(IR_FEEDBACK_LED_PIN, OUTPUT);
449 #endif
451 }
452 
453 void printTinyReceiverResultMinimal(Print *aSerial) {
454 // 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
455  // 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
456 #if defined(USE_FAST_PROTOCOL)
457  aSerial->print(F("C=0x"));
458 #else
459  aSerial->print(F("A=0x"));
460  aSerial->print(TinyIRReceiverData.Address, HEX);
461  aSerial->print(F(" C=0x"));
462 #endif
463  aSerial->print(TinyIRReceiverData.Command, HEX);
465  aSerial->print(F(" R"));
466  }
467 #if !defined(DISABLE_PARITY_CHECKS)
469  aSerial->print(F(" P"));
470  }
471 #endif
472  aSerial->println();
473 }
474 
475 #if defined (LOCAL_DEBUG_ATTACH_INTERRUPT) && !defined(STR)
476 // Helper macro for getting a macro definition as string
477 #define STR_HELPER(x) #x
478 #define STR(x) STR_HELPER(x)
479 #endif
480 
481 /**************************************************
482  * Pin to interrupt mapping for different platforms
483  **************************************************/
484 #if defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__)
485 #define USE_ATTACH_INTERRUPT_DIRECT
486 
487 #elif !defined(__AVR__) || defined(TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT)
488 // Default for all NON AVR platforms
489 #define USE_ATTACH_INTERRUPT
490 
491 #else
492 # if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
493 #define USE_PCIE
494 
495 # elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
496 # if defined(ARDUINO_AVR_DIGISPARKPRO)
497 # if (IR_RECEIVE_PIN == 3)
498 #define USE_INT0
499 # elif (IR_RECEIVE_PIN == 9)
500 #define USE_INT1
501 # else
502 # error "IR_RECEIVE_PIN must be 9 or 3."
503 # endif // if (IR_RECEIVE_PIN == 9)
504 # else // defined(ARDUINO_AVR_DIGISPARKPRO)
505 # if (IR_RECEIVE_PIN == 14)
506 #define USE_INT0
507 # elif (IR_RECEIVE_PIN == 3)
508 #define USE_INT1
509 # else
510 # error "IR_RECEIVE_PIN must be 14 or 3."
511 # endif // if (IR_RECEIVE_PIN == 14)
512 # endif
513 
514 # elif (defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__))
515 # if (IR_RECEIVE_PIN == 21)
516 #define USE_INT0
517 # elif (IR_RECEIVE_PIN == 20)
518 #define USE_INT1
519 # else
520 #warning "No pin mapping for IR_RECEIVE_PIN to interrupt found -> attachInterrupt() is used now."
521 #define USE_ATTACH_INTERRUPT
522 # endif
523 
524 # else // defined(__AVR_ATtiny25__)
525 /*
526  * ATmegas + ATtiny88 here
527  */
528 # if (IR_RECEIVE_PIN == 2)
529 #define USE_INT0
530 # elif (IR_RECEIVE_PIN == 3)
531 #define USE_INT1
532 
533 # elif IR_RECEIVE_PIN == 4 || IR_RECEIVE_PIN == 5 || IR_RECEIVE_PIN == 6 || IR_RECEIVE_PIN == 7
534  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 20 to 23 for port PD4 to PD7 (Arduino pin 4 to 7)
535 #define USE_PCINT2
536 # 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
537  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 0 to 5 for port PB0 to PB5 (Arduino pin 8 to 13)
538 #define USE_PCINT0
539 # 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
540  //ATmega328 (Uno, Nano ) etc. Enable pin change interrupt 8 to 13 for port PC0 to PC5 (Arduino pin A0 to A5)
541 #define USE_PCINT1
542 
543 # else
544 #warning "No pin mapping for IR_RECEIVE_PIN to interrupt found -> attachInterrupt() is used now."
545 #define USE_ATTACH_INTERRUPT
546 # endif // if (IR_RECEIVE_PIN == 2)
547 # endif // defined(__AVR_ATtiny25__)
548 #endif // ! defined(__AVR__) || defined(TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT)
549 
555 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
556  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
557 #endif
558 
559 #if defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT)
560 # if defined(USE_ATTACH_INTERRUPT)
561 #if defined(NOT_AN_INTERRUPT)
562  if(digitalPinToInterrupt(IR_RECEIVE_PIN) == NOT_AN_INTERRUPT){
563  return false;
564  }
565 #endif
566  // costs 112 bytes program memory + 4 bytes RAM
567  attachInterrupt(digitalPinToInterrupt(IR_RECEIVE_PIN), IRPinChangeInterruptHandler, CHANGE);
568 # else
569  // 2.2 us more than version configured with macros and not compatible
570  attachInterrupt(IR_RECEIVE_PIN, IRPinChangeInterruptHandler, CHANGE); // no extra pin mapping here
571 # endif
572 
573 # if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
574  Serial.println(F("Use attachInterrupt for pin=" STR(IR_RECEIVE_PIN)));
575 # endif
576 
577 #else
578 # if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
579  Serial.println(F("Use static interrupt for pin=" STR(IR_RECEIVE_PIN)));
580 # endif
581 # if defined(USE_INT0)
582  // interrupt on any logical change
583  EICRA |= _BV(ISC00);
584  // clear interrupt bit
585  EIFR |= 1 << INTF0;
586  // enable interrupt on next change
587  EIMSK |= 1 << INT0;
588 
589 # elif defined(USE_INT1)
590  EICRA |= _BV(ISC10);
591 // clear interrupt bit
592  EIFR |= 1 << INTF1;
593 // enable interrupt on next change
594  EIMSK |= 1 << INT1;
595 
596 # elif defined(USE_PCIE) // For ATtiny85 etc.
597  // use PinChangeInterrupt no INT0 for pin PB2
598  PCMSK = _BV(IR_RECEIVE_PIN);
599  // clear interrupt bit
600  GIFR |= 1 << PCIF;
601  // enable interrupt on next change
602  GIMSK |= 1 << PCIE;
603 
604 # elif defined(USE_PCINT0)
605  PCICR |= _BV(PCIE0);
606  PCMSK0 = digitalPinToBitMask(IR_RECEIVE_PIN);
607 # elif defined(USE_PCINT1)
608  PCICR |= _BV(PCIE1);
609  PCMSK1 = digitalPinToBitMask(IR_RECEIVE_PIN);
610 # elif defined(USE_PCINT2)
611  PCICR |= _BV(PCIE2);
612  PCMSK2 = digitalPinToBitMask(IR_RECEIVE_PIN);
613 # else
614  return false;
615 # endif
616 #endif // defined(USE_ATTACH_INTERRUPT)
617  return true;
618 }
619 
621 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
622  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
623 #endif
624 
625 #if defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT)
626 # if defined(USE_ATTACH_INTERRUPT)
627  detachInterrupt(digitalPinToInterrupt(IR_RECEIVE_PIN));
628 # else
629  detachInterrupt(IR_RECEIVE_PIN);
630 # endif
631 
632 #else
633 # if defined(USE_INT0)
634  // clear interrupt bit
635  EIFR |= 1 << INTF0;
636  // disable interrupt on next change
637  EIMSK &= ~(1 << INT0);
638 
639 # elif defined(USE_INT1)
640  // clear interrupt bit
641  EIFR |= 1 << INTF1;
642  // disable interrupt on next change
643  EIMSK &= ~(1 << INT1);
644 
645 # elif defined(USE_PCIE) // For ATtiny85 etc.
646  // clear interrupt bit
647  GIFR |= 1 << PCIF;
648  // disable interrupt on next change
649  GIMSK &= ~(1 << PCIE);
650 
651 # elif defined(USE_PCINT0)
652  PCICR &= ~(_BV(PCIE0));
653 # elif defined(USE_PCINT1)
654  PCICR &= ~(_BV(PCIE1));
655 # elif defined(USE_PCINT2)
656  PCICR &= ~(_BV(PCIE2));
657 
658 # endif
659 #endif // defined(USE_ATTACH_INTERRUPT)
660 }
661 
662 /*
663  * Specify the right INT0, INT1 or PCINT0 interrupt vector according to different pins and cores.
664  * The default value of TINY_RECEIVER_USE_ARDUINO_ATTACH_INTERRUPT is set in TinyIRReceiver.h
665  */
666 #if !(defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT))
667 # if defined(USE_INT0)
668 ISR(INT0_vect)
669 
670 # elif defined(USE_INT1)
671 ISR(INT1_vect)
672 
673 # elif defined(USE_PCIE) // For ATtiny85 etc.
674 // on ATtinyX5 we do not have a INT1_vect but we can use the PCINT0_vect
675 ISR(PCINT0_vect)
676 
677 # elif defined(USE_PCINT0)
678 ISR(PCINT0_vect)
679 # elif defined(USE_PCINT1)
680 ISR(PCINT1_vect)
681 # elif defined(USE_PCINT2)
682 ISR(PCINT2_vect)
683 # else
684 void dummyFunctionToAvoidCompilerErrors()
685 # endif
686 {
688 }
689 #endif // !(defined(USE_ATTACH_INTERRUPT) || defined(USE_ATTACH_INTERRUPT_DIRECT))
690 
693 #if defined(LOCAL_DEBUG_ATTACH_INTERRUPT)
694 #undef LOCAL_DEBUG_ATTACH_INTERRUPT
695 #endif
696 #if defined(LOCAL_TRACE_STATE_MACHINE)
697 #undef LOCAL_TRACE_STATE_MACHINE
698 #endif
699 
700 #if defined(LOCAL_DEBUG)
701 #undef LOCAL_DEBUG
702 #endif
703 #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:108
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:92
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:554
TinyIR.h
TinyIRReceiverData
volatile TinyIRReceiverCallbackDataStruct TinyIRReceiverData
Definition: TinyIRReceiver.hpp:109
LongUnion::LowWord
uint16_t LowWord
Definition: LongUnion.h:80
IR_RECEIVE_PIN
#define IR_RECEIVE_PIN
Definition: TinyIRReceiver.hpp:127
isTinyReceiverIdle
bool isTinyReceiverIdle()
Definition: TinyIRReceiver.hpp:425
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:94
disablePCIInterruptForTinyReceiver
void disablePCIInterruptForTinyReceiver()
Definition: TinyIRReceiver.hpp:620
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:166
TinyIRReceiverCallbackDataStruct::Command
uint16_t Command
Definition: TinyIR.h:241
printTinyReceiverResultMinimal
void printTinyReceiverResultMinimal(Print *aSerial)
Definition: TinyIRReceiver.hpp:453
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:91
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:433
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:444