41 #if defined(TRACE) && !defined(LOCAL_TRACE)
56 #if defined(IR_SEND_PIN)
57 #define sendPin IR_SEND_PIN
60 #if !defined(NO_LED_SEND_FEEDBACK_CODE)
61 #define LED_SEND_FEEDBACK_CODE // Resolve the double negative
72 #if !defined(IR_SEND_PIN)
80 #if defined(IR_SEND_PIN)
85 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
98 #else // defined(IR_SEND_PIN)
121 #if defined(IR_SEND_PIN)
127 #if defined(LED_SEND_FEEDBACK_CODE)
130 (void) aFeedbackLEDPin;
133 #endif // defined(IR_SEND_PIN)
136 void IRsend::begin(uint_fast8_t aSendPin,
bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
137 (void) aEnableLEDFeedback;
138 begin(aSendPin,aFeedbackLEDPin);
155 auto tProtocol = aIRSendData->
protocol;
156 auto tAddress = aIRSendData->
address;
157 auto tCommand = aIRSendData->
command;
197 if (tProtocol ==
NEC) {
200 }
else if (tProtocol ==
SAMSUNG) {
209 }
else if (tProtocol ==
SONY) {
215 }
else if (tProtocol ==
DENON) {
218 }
else if (tProtocol ==
SHARP) {
221 }
else if (tProtocol ==
LG) {
224 }
else if (tProtocol ==
JVC) {
227 }
else if (tProtocol ==
RC5) {
230 }
else if (tProtocol ==
RC6) {
245 }
else if (tProtocol ==
NEC2) {
248 }
else if (tProtocol ==
ONKYO) {
251 }
else if (tProtocol ==
APPLE) {
254 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
262 }
else if (tProtocol ==
FAST) {
266 }
else if (tProtocol ==
LEGO_PF) {
318 if (aProtocol ==
NEC) {
321 }
else if (aProtocol ==
SAMSUNG) {
330 }
else if (aProtocol ==
SONY) {
336 }
else if (aProtocol ==
DENON) {
339 }
else if (aProtocol ==
SHARP) {
342 }
else if (aProtocol ==
LG) {
345 }
else if (aProtocol ==
JVC) {
348 }
else if (aProtocol ==
RC5) {
351 }
else if (aProtocol ==
RC6) {
366 }
else if (aProtocol ==
NEC2) {
369 }
else if (aProtocol ==
ONKYO) {
372 }
else if (aProtocol ==
APPLE) {
375 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
379 }
else if (aProtocol ==
FAST) {
383 }
else if (aProtocol ==
LEGO_PF) {
401 void IRsend::sendRaw(
const uint16_t aBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
408 for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
411 space(aBufferWithMicroseconds[i]);
413 mark(aBufferWithMicroseconds[i]);
422 void IRsend::sendRaw(
const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
426 for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
442 uint_fast8_t aIRFrequencyKilohertz) {
443 #if !defined(__AVR__)
444 sendRaw(aBufferWithMicroseconds, aLengthOfBuffer, aIRFrequencyKilohertz);
451 for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
452 auto duration = pgm_read_word(&aBufferWithMicroseconds[i]);
456 # if defined(LOCAL_DEBUG)
457 Serial.print(F(
"S="));
461 # if defined(LOCAL_DEBUG)
462 Serial.print(F(
"M="));
465 # if defined(LOCAL_DEBUG)
466 Serial.println(duration);
476 void IRsend::sendRaw_P(
const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
477 #if !defined(__AVR__)
478 sendRaw(aBufferWithTicks, aLengthOfBuffer, aIRFrequencyKilohertz);
483 uint_fast16_t duration;
484 for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
485 duration = pgm_read_byte(&aBufferWithTicks[i]) * (uint_fast16_t)
MICROS_PER_TICK;
489 # if defined(LOCAL_DEBUG)
490 Serial.print(F(
"S="));
494 # if defined(LOCAL_DEBUG)
495 Serial.print(F(
"M="));
500 # if defined(LOCAL_DEBUG)
501 Serial.println(duration);
518 uint16_t aZeroSpaceMicros,
IRRawDataType aData, uint_fast8_t aNumberOfBits, uint8_t aFlags) {
520 #if defined(LOCAL_DEBUG)
521 Serial.print(aData, HEX);
523 Serial.println(aNumberOfBits);
529 for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
531 #if defined(LOCAL_TRACE)
534 mark(aOneMarkMicros);
535 space(aOneSpaceMicros);
537 #if defined(LOCAL_TRACE)
540 mark(aZeroMarkMicros);
541 space(aZeroSpaceMicros);
554 if ((!(aFlags &
SUPPRESS_STOP_BIT)) && (abs(aOneSpaceMicros - aZeroSpaceMicros) > (aOneSpaceMicros / 4))) {
556 #if defined(LOCAL_TRACE)
559 mark(aOneMarkMicros);
561 #if defined(LOCAL_TRACE)
579 uint_fast8_t aNumberOfBits) {
587 uint_fast8_t aNumberOfBits) {
590 memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
591 sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
610 uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
IRRawDataType aData,
611 uint_fast8_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats,
612 void (*aSpecialSendRepeatFunction)()) {
615 if (aSpecialSendRepeatFunction !=
nullptr) {
616 aSpecialSendRepeatFunction();
627 while (tNumberOfCommands > 0) {
628 unsigned long tStartOfFrameMillis = millis();
630 if (tNumberOfCommands < ((uint_fast8_t)
aNumberOfRepeats + 1) && aSpecialSendRepeatFunction !=
nullptr) {
632 aSpecialSendRepeatFunction();
635 mark(aHeaderMarkMicros);
636 space(aHeaderSpaceMicros);
643 if (tNumberOfCommands > 0) {
647 auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
648 if (aRepeatPeriodMillis > tFrameDurationMillis) {
649 delay(aRepeatPeriodMillis - tFrameDurationMillis);
656 uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
657 IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
658 int_fast8_t aNumberOfRepeats) {
666 #if defined(LOCAL_DEBUG)
668 Serial.print(F(
"Data[0]=0x"));
669 Serial.print(aDecodedRawDataArray[0], HEX);
670 if (tNumberOf32Or64BitChunks > 1) {
671 Serial.print(F(
" Data[1]=0x"));
672 Serial.print(aDecodedRawDataArray[1], HEX);
674 Serial.print(F(
" #="));
675 Serial.println(aNumberOfBits);
679 while (tNumberOfCommands > 0) {
680 unsigned long tStartOfFrameMillis = millis();
683 mark(aHeaderMarkMicros);
684 space(aHeaderSpaceMicros);
686 for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
687 uint8_t tNumberOfBitsForOneSend;
691 if (i == (tNumberOf32Or64BitChunks - 1)) {
693 tNumberOfBitsForOneSend = aNumberOfBits;
702 tNumberOfBitsForOneSend, tFlags);
708 if (tNumberOfCommands > 0) {
712 auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
713 if (aRepeatPeriodMillis > tFrameDurationMillis) {
714 delay(aRepeatPeriodMillis - tFrameDurationMillis);
721 uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
722 IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
723 int_fast8_t aNumberOfRepeats) {
731 #if defined(LOCAL_DEBUG)
733 Serial.print(F(
"Data[0]=0x"));
734 Serial.print(aDecodedRawDataPGMArray[0], HEX);
735 if (tNumberOf32Or64BitChunks > 1) {
736 Serial.print(F(
" Data[1]=0x"));
737 Serial.print(aDecodedRawDataPGMArray[1], HEX);
739 Serial.print(F(
" #="));
740 Serial.println(aNumberOfBits);
744 while (tNumberOfCommands > 0) {
745 unsigned long tStartOfFrameMillis = millis();
748 mark(aHeaderMarkMicros);
749 space(aHeaderSpaceMicros);
751 for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
752 uint8_t tNumberOfBitsForOneSend;
756 if (i == (tNumberOf32Or64BitChunks - 1)) {
758 tNumberOfBitsForOneSend = aNumberOfBits;
767 #if (__INT_WIDTH__ < 32)
768 tDecodedRawData = pgm_read_dword(&aDecodedRawDataPGMArray[i]);
770 tDecodedRawData = aDecodedRawDataPGMArray[i];
773 tNumberOfBitsForOneSend, tFlags);
779 if (tNumberOfCommands > 0) {
783 auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
784 if (aRepeatPeriodMillis > tFrameDurationMillis) {
785 delay(aRepeatPeriodMillis - tFrameDurationMillis);
803 IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
804 int_fast8_t aNumberOfRepeats) {
808 aDistanceWidthTimingInfo->
ZeroSpaceMicros, aDecodedRawDataArray, aNumberOfBits, aFlags, aRepeatPeriodMillis,
814 uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
817 memcpy_P(&tTemporaryDistanceWidthTimingInfo, aDistanceWidthTimingInfoPGM,
sizeof(tTemporaryDistanceWidthTimingInfo));
834 uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
836 #if defined(LOCAL_DEBUG)
837 Serial.print(F(
"Data=0x"));
838 Serial.print(aData, HEX);
839 Serial.print(F(
" #="));
840 Serial.println(aNumberOfBits);
861 while (tNumberOfCommands > 0) {
862 unsigned long tStartOfFrameMillis = millis();
878 if (tNumberOfCommands > 0) {
879 auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
900 IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
914 #if defined(LOCAL_DEBUG)
916 Serial.print(F(
"Data[0]=0x"));
917 Serial.print(aDecodedRawDataArray[0], HEX);
918 if (tNumberOf32Or64BitChunks > 1) {
919 Serial.print(F(
" Data[1]=0x"));
920 Serial.print(aDecodedRawDataArray[1], HEX);
922 Serial.print(F(
" #="));
923 Serial.println(aNumberOfBits);
928 while (tNumberOfCommands > 0) {
929 auto tStartOfFrameMillis = millis();
930 auto tNumberOfBits = aNumberOfBits;
935 uint8_t tOriginalFlags = aProtocolConstants->
Flags;
937 for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
938 uint8_t tNumberOfBitsForOneSend;
941 if (i == (tNumberOf32Or64BitChunks - 1)) {
943 tNumberOfBitsForOneSend = tNumberOfBits;
944 tFlags = tOriginalFlags;
961 if (tNumberOfCommands > 0) {
965 auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
974 IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
988 #if defined(LOCAL_DEBUG)
990 Serial.print(F(
"Data[0]=0x"));
991 Serial.print(aDecodedRawDataPGMArray[0], HEX);
992 if (tNumberOf32Or64BitChunks > 1) {
993 Serial.print(F(
" Data[1]=0x"));
994 Serial.print(aDecodedRawDataPGMArray[1], HEX);
996 Serial.print(F(
" #="));
997 Serial.println(aNumberOfBits);
1002 while (tNumberOfCommands > 0) {
1003 auto tStartOfFrameMillis = millis();
1004 auto tNumberOfBits = aNumberOfBits;
1009 uint8_t tOriginalFlags = aProtocolConstants->
Flags;
1011 for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
1012 uint8_t tNumberOfBitsForOneSend;
1015 if (i == (tNumberOf32Or64BitChunks - 1)) {
1017 tNumberOfBitsForOneSend = tNumberOfBits;
1018 tFlags = tOriginalFlags;
1026 #if (__INT_WIDTH__ < 32)
1027 tDecodedRawData = pgm_read_dword(&aDecodedRawDataPGMArray[i]);
1029 tDecodedRawData = aDecodedRawDataPGMArray[i];
1038 tNumberOfCommands--;
1040 if (tNumberOfCommands > 0) {
1044 auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
1057 IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1060 memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1061 sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1066 IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1069 memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1070 sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1076 uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1078 memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1079 sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1098 #if defined(LOCAL_TRACE)
1104 uint32_t tMask = 1UL << aNumberOfBits;
1105 uint_fast8_t tLastBitValue = 1;
1106 bool tNextBitIsOne = 1;
1107 for (uint_fast8_t i = aNumberOfBits + 1; i > 0; i--) {
1108 bool tCurrentBitIsOne = tNextBitIsOne;
1110 tNextBitIsOne = ((aData & tMask) != 0) || (i == 1);
1111 if (tCurrentBitIsOne) {
1112 #if defined(LOCAL_TRACE)
1115 space(aBiphaseTimeUnit);
1116 if (tNextBitIsOne) {
1117 mark(aBiphaseTimeUnit);
1120 mark(2 * aBiphaseTimeUnit);
1125 #if defined(LOCAL_TRACE)
1128 if (!tLastBitValue) {
1129 mark(aBiphaseTimeUnit);
1131 space(aBiphaseTimeUnit);
1155 #if defined(SEND_PWM_BY_TIMER) || defined(USE_NO_SEND_PWM)
1156 # if defined(LED_SEND_FEEDBACK_CODE)
1161 #if defined(SEND_PWM_BY_TIMER)
1170 #elif defined(USE_NO_SEND_PWM)
1174 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1177 # elif defined(USE_ACTIVE_HIGH_OUTPUT_FOR_NO_SEND_PWM) || defined(USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN) // USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN is old and deprecated
1185 # if defined(LED_SEND_FEEDBACK_CODE)
1190 #else // defined(SEND_PWM_BY_TIMER)
1192 unsigned long tMicrosOfEndOfNextPWMPause = micros();
1193 # if defined(LED_SEND_FEEDBACK_CODE)
1194 unsigned long tStartMicros = tMicrosOfEndOfNextPWMPause + (136 / CLOCKS_PER_MICRO);
1195 bool tFeedbackLedIsActive =
false;
1197 unsigned long tStartMicros = tMicrosOfEndOfNextPWMPause + (112 / CLOCKS_PER_MICRO);
1209 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1210 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1211 if (__builtin_constant_p(
sendPin)) {
1223 if (__builtin_constant_p(
sendPin)) {
1238 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1239 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1240 if (__builtin_constant_p(
sendPin)) {
1250 if (__builtin_constant_p(
sendPin)) {
1262 # if defined(LED_SEND_FEEDBACK_CODE)
1266 if (!tFeedbackLedIsActive) {
1267 tFeedbackLedIsActive =
true;
1278 #if defined(__AVR__) // micros() for STM sometimes give decreasing values if interrupts are disabled. See https://github.com/stm32duino/Arduino_Core_STM32/issues/1680
1281 unsigned long tMicros;
1283 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1292 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1300 uint16_t tDeltaMicros = tMicros - tStartMicros;
1303 if (tDeltaMicros >= aMarkMicros) {
1304 #if defined(LED_SEND_FEEDBACK_CODE)
1307 #if defined(__AVR__)
1312 }
while (tMicros < tMicrosOfEndOfNextPWMPause);
1323 #if defined(SEND_PWM_BY_TIMER)
1325 #elif defined(USE_NO_SEND_PWM)
1326 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1329 # elif defined(USE_ACTIVE_HIGH_OUTPUT_FOR_NO_SEND_PWM) || defined(USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN) // USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN is old and deprecated
1335 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1336 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1337 if (__builtin_constant_p(
sendPin)) {
1346 if (__builtin_constant_p(
sendPin)) {
1354 #if defined(LED_SEND_FEEDBACK_CODE)
1373 #if defined(ESP32) || defined(ESP8266)
1378 if (aMicroseconds > 16383) {
1379 delay(aMicroseconds / 1000UL);
1381 delayMicroseconds(
static_cast<uint16_t
>(aMicroseconds % 1000UL));
1383 delayMicroseconds(aMicroseconds);
1387 # if defined(__AVR__)
1388 unsigned long start = micros() - (64 / clockCyclesPerMicrosecond());
1390 unsigned long start = micros();
1393 while (micros() - start < aMicroseconds) {
1405 #if defined(SEND_PWM_BY_TIMER)
1408 #elif defined(USE_NO_SEND_PWM)
1409 (void) aFrequencyKHz;
1413 # if defined(IR_SEND_PIN)
1419 #endif // defined(SEND_PWM_BY_TIMER)
1421 #if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && defined(OUTPUT_OPEN_DRAIN) // the mode INPUT for mimicking open drain is set at IRLedOff()
1422 # if defined(IR_SEND_PIN)
1431 # if defined(__AVR__) || !defined(SEND_PWM_BY_TIMER)
1432 # if defined(IR_SEND_PIN)
1435 if (__builtin_constant_p(
sendPin)) {
1442 #endif // defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
1445 #if defined(SEND_PWM_BY_TIMER)
1447 void IRsend::enableHighFrequencyIROut(uint_fast16_t aFrequencyKHz) {
1451 # if defined(__AVR__)
1452 # if defined(IR_SEND_PIN)
1466 #if defined(_IR_MEASURE_TIMING)
1467 #undef _IR_MEASURE_TIMING
1469 #if defined(LOCAL_TRACE)
1472 #if defined(LOCAL_DEBUG)
1475 #endif // _IR_SEND_HPP