IRremote
IRSend.hpp
Go to the documentation of this file.
1 /*
2  * IRSend.hpp
3  *
4  * Contains common functions for sending
5  *
6  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
7  *
8  ************************************************************************************
9  * MIT License
10  *
11  * Copyright (c) 2009-2023 Ken Shirriff, Rafi Khan, Armin Joachimsmeyer
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is furnished
18  * to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in all
21  * copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
24  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
25  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
28  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29  *
30  ************************************************************************************
31  */
32 #ifndef _IR_SEND_HPP
33 #define _IR_SEND_HPP
34 
35 #if defined(DEBUG) && !defined(LOCAL_DEBUG)
36 #define LOCAL_DEBUG
37 #else
38 //#define LOCAL_DEBUG // This enables debug output only for this file
39 #endif
40 
41 #if defined(TRACE) && !defined(LOCAL_TRACE)
42 #define LOCAL_TRACE
43 #else
44 //#define LOCAL_TRACE // This enables debug output only for this file
45 #endif
46 
47 /*
48  * Low level hardware timing measurement
49  */
50 //#define _IR_MEASURE_TIMING // for mark()
51 //#define _IR_TIMING_TEST_PIN 7 // "pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);" is executed at begin()
52 //
53 /*
54  * This improves readability of code by avoiding a lot of #if defined clauses
55  */
56 #if defined(IR_SEND_PIN)
57 #define sendPin IR_SEND_PIN
58 #endif
59 
64 // The sender instance
66 
67 IRsend::IRsend() { // @suppress("Class members should be properly initialized")
68 #if !defined(IR_SEND_PIN)
69  sendPin = 0;
70 #endif
71 
72 #if !defined(NO_LED_FEEDBACK_CODE)
74 #endif
75 }
76 
77 #if defined(IR_SEND_PIN)
78 
82 void IRsend::begin(){
83 # if !defined(NO_LED_FEEDBACK_CODE)
85 # endif
86 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
87  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
88 #endif
89 }
90 
96 void IRsend::begin(bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
97 #if !defined(NO_LED_FEEDBACK_CODE)
98  uint_fast8_t tEnableLEDFeedback = DO_NOT_ENABLE_LED_FEEDBACK;
99  if(aEnableLEDFeedback) {
100  tEnableLEDFeedback = LED_FEEDBACK_ENABLED_FOR_SEND;
101  }
102  setLEDFeedback(aFeedbackLEDPin, tEnableLEDFeedback);
103 #else
104  (void) aEnableLEDFeedback;
105  (void) aFeedbackLEDPin;
106 #endif
107 }
108 
109 #else // defined(IR_SEND_PIN)
110 IRsend::IRsend(uint_fast8_t aSendPin) { // @suppress("Class members should be properly initialized")
111  sendPin = aSendPin;
112 # if !defined(NO_LED_FEEDBACK_CODE)
114 # endif
115 }
116 
121 void IRsend::begin(uint_fast8_t aSendPin) {
122  sendPin = aSendPin;
123 # if !defined(NO_LED_FEEDBACK_CODE)
125 # endif
126 }
127 
128 void IRsend::setSendPin(uint_fast8_t aSendPin) {
129  sendPin = aSendPin;
130 }
131 
138 void IRsend::begin(uint_fast8_t aSendPin, bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
139 #if defined(IR_SEND_PIN)
140  (void) aSendPin; // for backwards compatibility
141 #else
142  sendPin = aSendPin;
143 #endif
144 
145 #if !defined(NO_LED_FEEDBACK_CODE)
146  uint_fast8_t tEnableLEDFeedback = DO_NOT_ENABLE_LED_FEEDBACK;
147  if (aEnableLEDFeedback) {
148  tEnableLEDFeedback = LED_FEEDBACK_ENABLED_FOR_SEND;
149  }
150  setLEDFeedback(aFeedbackLEDPin, tEnableLEDFeedback);
151 #else
152  (void) aEnableLEDFeedback;
153  (void) aFeedbackLEDPin;
154 #endif
155 }
156 #endif // defined(IR_SEND_PIN)
157 
170 size_t IRsend::write(IRData *aIRSendData, int_fast8_t aNumberOfRepeats) {
171 
172  auto tProtocol = aIRSendData->protocol;
173  auto tAddress = aIRSendData->address;
174  auto tCommand = aIRSendData->command;
175  bool tIsRepeat = (aIRSendData->flags & IRDATA_FLAGS_IS_REPEAT);
176  if (tIsRepeat) {
177  aNumberOfRepeats = -1; // if aNumberOfRepeats < 0 then only a special repeat frame will be sent
178  }
179 // switch (tProtocol) { // 26 bytes bigger than if, else if, else
180 // case NEC:
181 // sendNEC(tAddress, tCommand, aNumberOfRepeats, tSendRepeat);
182 // break;
183 // case SAMSUNG:
184 // sendSamsung(tAddress, tCommand, aNumberOfRepeats);
185 // break;
186 // case SONY:
187 // sendSony(tAddress, tCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
188 // break;
189 // case PANASONIC:
190 // sendPanasonic(tAddress, tCommand, aNumberOfRepeats);
191 // break;
192 // case DENON:
193 // sendDenon(tAddress, tCommand, aNumberOfRepeats);
194 // break;
195 // case SHARP:
196 // sendSharp(tAddress, tCommand, aNumberOfRepeats);
197 // break;
198 // case JVC:
199 // sendJVC((uint8_t) tAddress, (uint8_t) tCommand, aNumberOfRepeats); // casts are required to specify the right function
200 // break;
201 // case RC5:
202 // sendRC5(tAddress, tCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
203 // break;
204 // case RC6:
205 // // No toggle for repeats// sendRC6(tAddress, tCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
206 // break;
207 // default:
208 // break;
209 // }
210 
211  /*
212  * Order of protocols is in guessed relevance :-)
213  */
214  if (tProtocol == NEC) {
215  sendNEC(tAddress, tCommand, aNumberOfRepeats);
216 
217  } else if (tProtocol == SAMSUNG) {
218  sendSamsung(tAddress, tCommand, aNumberOfRepeats);
219 
220  } else if (tProtocol == SAMSUNG48) {
221  sendSamsung48(tAddress, tCommand, aNumberOfRepeats);
222 
223  } else if (tProtocol == SAMSUNGLG) {
224  sendSamsungLG(tAddress, tCommand, aNumberOfRepeats);
225 
226  } else if (tProtocol == SONY) {
227  sendSony(tAddress, tCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
228 
229  } else if (tProtocol == PANASONIC) {
230  sendPanasonic(tAddress, tCommand, aNumberOfRepeats);
231 
232  } else if (tProtocol == DENON) {
233  sendDenon(tAddress, tCommand, aNumberOfRepeats);
234 
235  } else if (tProtocol == SHARP) {
236  sendSharp(tAddress, tCommand, aNumberOfRepeats);
237 
238  } else if (tProtocol == LG) {
239  sendLG(tAddress, tCommand, aNumberOfRepeats);
240 
241  } else if (tProtocol == JVC) {
242  sendJVC((uint8_t) tAddress, (uint8_t) tCommand, aNumberOfRepeats); // casts are required to specify the right function
243 
244  } else if (tProtocol == RC5) {
245  sendRC5(tAddress, tCommand, aNumberOfRepeats, !tIsRepeat); // No toggle for repeats
246 
247  } else if (tProtocol == RC6) {
248  sendRC6(tAddress, tCommand, aNumberOfRepeats, !tIsRepeat); // No toggle for repeats
249 
250  } else if (tProtocol == KASEIKYO_JVC) {
251  sendKaseikyo_JVC(tAddress, tCommand, aNumberOfRepeats);
252 
253  } else if (tProtocol == KASEIKYO_DENON) {
254  sendKaseikyo_Denon(tAddress, tCommand, aNumberOfRepeats);
255 
256  } else if (tProtocol == KASEIKYO_SHARP) {
257  sendKaseikyo_Sharp(tAddress, tCommand, aNumberOfRepeats);
258 
259  } else if (tProtocol == KASEIKYO_MITSUBISHI) {
260  sendKaseikyo_Mitsubishi(tAddress, tCommand, aNumberOfRepeats);
261 
262  } else if (tProtocol == NEC2) {
263  sendNEC2(tAddress, tCommand, aNumberOfRepeats);
264 
265  } else if (tProtocol == ONKYO) {
266  sendOnkyo(tAddress, tCommand, aNumberOfRepeats);
267 
268  } else if (tProtocol == APPLE) {
269  sendApple(tAddress, tCommand, aNumberOfRepeats);
270 
271 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
272  } else if (tProtocol == BOSEWAVE) {
273  sendBoseWave(tCommand, aNumberOfRepeats);
274 
275  } else if (tProtocol == MAGIQUEST) {
276  // we have a 32 bit ID/address
277  sendMagiQuest(aIRSendData->decodedRawData, tCommand);
278 
279  } else if (tProtocol == FAST) {
280  // We have only 8 bit command
281  sendFAST(tCommand, aNumberOfRepeats);
282 
283  } else if (tProtocol == LEGO_PF) {
284  sendLegoPowerFunctions(tAddress, tCommand, tCommand >> 4, tIsRepeat); // send 5 autorepeats
285 #endif
286 
287  } else {
288  return 0; // Not supported by write. E.g for BANG_OLUFSEN
289  }
290  return 1;
291 }
292 
298 size_t IRsend::write(decode_type_t aProtocol, uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
299 
300 // switch (aProtocol) { // 26 bytes bigger than if, else if, else
301 // case NEC:
302 // sendNEC(aAddress, aCommand, aNumberOfRepeats, tSendRepeat);
303 // break;
304 // case SAMSUNG:
305 // sendSamsung(aAddress, aCommand, aNumberOfRepeats);
306 // break;
307 // case SONY:
308 // sendSony(aAddress, aCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
309 // break;
310 // case PANASONIC:
311 // sendPanasonic(aAddress, aCommand, aNumberOfRepeats);
312 // break;
313 // case DENON:
314 // sendDenon(aAddress, aCommand, aNumberOfRepeats);
315 // break;
316 // case SHARP:
317 // sendSharp(aAddress, aCommand, aNumberOfRepeats);
318 // break;
319 // case JVC:
320 // sendJVC((uint8_t) aAddress, (uint8_t) aCommand, aNumberOfRepeats); // casts are required to specify the right function
321 // break;
322 // case RC5:
323 // sendRC5(aAddress, aCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
324 // break;
325 // case RC6:
326 // // No toggle for repeats// sendRC6(aAddress, aCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
327 // break;
328 // default:
329 // break;
330 // }
331 
332  /*
333  * Order of protocols is in guessed relevance :-)
334  */
335  if (aProtocol == NEC) {
336  sendNEC(aAddress, aCommand, aNumberOfRepeats);
337 
338  } else if (aProtocol == SAMSUNG) {
340 
341  } else if (aProtocol == SAMSUNG48) {
343 
344  } else if (aProtocol == SAMSUNGLG) {
346 
347  } else if (aProtocol == SONY) {
349 
350  } else if (aProtocol == PANASONIC) {
352 
353  } else if (aProtocol == DENON) {
354  sendDenon(aAddress, aCommand, aNumberOfRepeats);
355 
356  } else if (aProtocol == SHARP) {
357  sendSharp(aAddress, aCommand, aNumberOfRepeats);
358 
359  } else if (aProtocol == LG) {
360  sendLG(aAddress, aCommand, aNumberOfRepeats);
361 
362  } else if (aProtocol == JVC) {
363  sendJVC((uint8_t) aAddress, (uint8_t) aCommand, aNumberOfRepeats); // casts are required to specify the right function
364 
365  } else if (aProtocol == RC5) {
366  sendRC5(aAddress, aCommand, aNumberOfRepeats, (aNumberOfRepeats > 0)); // No toggle for repeats
367 
368  } else if (aProtocol == RC6) {
369  sendRC6(aAddress, aCommand, aNumberOfRepeats, (aNumberOfRepeats > 0)); // No toggle for repeats
370 
371  } else if (aProtocol == KASEIKYO_JVC) {
373 
374  } else if (aProtocol == KASEIKYO_DENON) {
376 
377  } else if (aProtocol == KASEIKYO_SHARP) {
379 
380  } else if (aProtocol == KASEIKYO_MITSUBISHI) {
382 
383  } else if (aProtocol == NEC2) {
384  sendNEC2(aAddress, aCommand, aNumberOfRepeats);
385 
386  } else if (aProtocol == ONKYO) {
387  sendOnkyo(aAddress, aCommand, aNumberOfRepeats);
388 
389  } else if (aProtocol == APPLE) {
390  sendApple(aAddress, aCommand, aNumberOfRepeats);
391 
392 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
393  } else if (aProtocol == BOSEWAVE) {
395 
396  } else if (aProtocol == FAST) {
397  // We have only 8 bit command
399 
400  } else if (aProtocol == LEGO_PF) {
401  sendLegoPowerFunctions(aAddress, aCommand, aCommand >> 4, (aNumberOfRepeats < 0)); // send 5 autorepeats, except for dedicated repeats
402 #endif
403 
404  } else {
405  return 0; // Not supported by write. E.g for BANG_OLUFSEN
406  }
407  return 1;
408 }
409 
414 void IRsend::sendRaw(const uint16_t aBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
415 // Set IR carrier frequency
416  enableIROut(aIRFrequencyKilohertz);
417 
418  /*
419  * Raw data starts with a mark.
420  */
421  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
422  if (i & 1) {
423  // Odd
424  space(aBufferWithMicroseconds[i]);
425  } else {
426  mark(aBufferWithMicroseconds[i]);
427  }
428  }
429 }
430 
435 void IRsend::sendRaw(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
436 // Set IR carrier frequency
437  enableIROut(aIRFrequencyKilohertz);
438 
439  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
440  if (i & 1) {
441  // Odd
442  space(aBufferWithTicks[i] * MICROS_PER_TICK);
443  } else {
444  mark(aBufferWithTicks[i] * MICROS_PER_TICK);
445  }
446  }
447  IRLedOff(); // Always end with the LED off
448 }
449 
454 void IRsend::sendRaw_P(const uint16_t aBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer,
455  uint_fast8_t aIRFrequencyKilohertz) {
456 #if !defined(__AVR__)
457  sendRaw(aBufferWithMicroseconds, aLengthOfBuffer, aIRFrequencyKilohertz); // Let the function work for non AVR platforms
458 #else
459 // Set IR carrier frequency
460  enableIROut(aIRFrequencyKilohertz);
461  /*
462  * Raw data starts with a mark
463  */
464  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
465  auto duration = pgm_read_word(&aBufferWithMicroseconds[i]);
466  if (i & 1) {
467  // Odd
468  space(duration);
469 # if defined(LOCAL_DEBUG)
470  Serial.print(F("S="));
471 # endif
472  } else {
473  mark(duration);
474 # if defined(LOCAL_DEBUG)
475  Serial.print(F("M="));
476 # endif
477  }
478 # if defined(LOCAL_DEBUG)
479  Serial.println(duration);
480 # endif
481  }
482 #endif
483 }
484 
489 void IRsend::sendRaw_P(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
490 #if !defined(__AVR__)
491  sendRaw(aBufferWithTicks, aLengthOfBuffer, aIRFrequencyKilohertz); // Let the function work for non AVR platforms
492 #else
493 // Set IR carrier frequency
494  enableIROut(aIRFrequencyKilohertz);
495 
496  uint_fast16_t duration;
497  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
498  duration = pgm_read_byte(&aBufferWithTicks[i]) * (uint_fast16_t) MICROS_PER_TICK;
499  if (i & 1) {
500  // Odd
501  space(duration);
502 # if defined(LOCAL_DEBUG)
503  Serial.print(F("S="));
504 # endif
505  } else {
506  mark(duration);
507 # if defined(LOCAL_DEBUG)
508  Serial.print(F("M="));
509 # endif
510  }
511  }
512  IRLedOff(); // Always end with the LED off
513 # if defined(LOCAL_DEBUG)
514  Serial.println(duration);
515 # endif
516 #endif
517 }
518 
526 void IRsend::sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, DistanceWidthTimingInfoStruct *aDistanceWidthTimingInfo,
527  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
528  int_fast8_t aNumberOfRepeats) {
529  sendPulseDistanceWidthFromArray(aFrequencyKHz, aDistanceWidthTimingInfo->HeaderMarkMicros,
530  aDistanceWidthTimingInfo->HeaderSpaceMicros, aDistanceWidthTimingInfo->OneMarkMicros,
531  aDistanceWidthTimingInfo->OneSpaceMicros, aDistanceWidthTimingInfo->ZeroMarkMicros,
532  aDistanceWidthTimingInfo->ZeroSpaceMicros, aDecodedRawDataArray, aNumberOfBits, aFlags, aRepeatPeriodMillis,
534 }
535 void IRsend::sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
536  uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
537  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
538  int_fast8_t aNumberOfRepeats) {
539 
540  // Set IR carrier frequency
541  enableIROut(aFrequencyKHz);
542 
543  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
544  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
545 
546 #if defined(LOCAL_DEBUG)
547  // fist data
548  Serial.print(F("Data[0]=0x"));
549  Serial.print(aDecodedRawDataArray[0], HEX);
550  if (tNumberOf32Or64BitChunks > 1) {
551  Serial.print(F(" Data[1]=0x"));
552  Serial.print(aDecodedRawDataArray[1], HEX);
553  }
554  Serial.print(F(" #="));
555  Serial.println(aNumberOfBits);
556  Serial.flush();
557 #endif
558 
559  while (tNumberOfCommands > 0) {
560  unsigned long tStartOfFrameMillis = millis();
561 
562  // Header
563  mark(aHeaderMarkMicros);
564  space(aHeaderSpaceMicros);
565 
566  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
567  uint8_t tNumberOfBitsForOneSend;
568 
569  // Manage stop bit
570  uint8_t tFlags;
571  if (i == (tNumberOf32Or64BitChunks - 1)) {
572  // End of data
573  tNumberOfBitsForOneSend = aNumberOfBits;
574  tFlags = aFlags;
575  } else {
576  // intermediate data
577  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
578  tFlags = aFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
579  }
580 
581  sendPulseDistanceWidthData(aOneMarkMicros, aOneSpaceMicros, aZeroMarkMicros, aZeroSpaceMicros, aDecodedRawDataArray[i],
582  tNumberOfBitsForOneSend, tFlags);
583  aNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
584  }
585 
586  tNumberOfCommands--;
587  // skip last delay!
588  if (tNumberOfCommands > 0) {
589  /*
590  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
591  */
592  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
593  if (aRepeatPeriodMillis > tFrameDurationMillis) {
594  delay(aRepeatPeriodMillis - tFrameDurationMillis);
595  }
596  }
597  }
598 }
599 
610  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
611 
612 // Calling sendPulseDistanceWidthFromArray() costs 68 bytes program memory compared to the implementation below
613 // sendPulseDistanceWidthFromArray(aProtocolConstants->FrequencyKHz, aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros,
614 // aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros,
615 // aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
616 // aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros,
617 // aDecodedRawDataArray, aNumberOfBits, aProtocolConstants->Flags, aProtocolConstants->RepeatPeriodMillis,
618 // aNumberOfRepeats);
619  // Set IR carrier frequency
620  enableIROut(aProtocolConstants->FrequencyKHz);
621 
622  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
623 
624 #if defined(LOCAL_DEBUG)
625  // fist data
626  Serial.print(F("Data[0]=0x"));
627  Serial.print(aDecodedRawDataArray[0], HEX);
628  if (tNumberOf32Or64BitChunks > 1) {
629  Serial.print(F(" Data[1]=0x"));
630  Serial.print(aDecodedRawDataArray[1], HEX);
631  }
632  Serial.print(F(" #="));
633  Serial.println(aNumberOfBits);
634  Serial.flush();
635 #endif
636 
637  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
638  while (tNumberOfCommands > 0) {
639  auto tStartOfFrameMillis = millis();
640  auto tNumberOfBits = aNumberOfBits; // refresh value for repeats
641 
642  // Header
643  mark(aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros);
644  space(aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros);
645  uint8_t tOriginalFlags = aProtocolConstants->Flags;
646 
647  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
648  uint8_t tNumberOfBitsForOneSend;
649 
650  uint8_t tFlags;
651  if (i == (tNumberOf32Or64BitChunks - 1)) {
652  // End of data
653  tNumberOfBitsForOneSend = tNumberOfBits;
654  tFlags = tOriginalFlags;
655  } else {
656  // intermediate data
657  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
658  tFlags = tOriginalFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
659  }
660 
662  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
663  aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
664  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, aDecodedRawDataArray[i], tNumberOfBitsForOneSend,
665  tFlags);
666  tNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
667  }
668 
669  tNumberOfCommands--;
670  // skip last delay!
671  if (tNumberOfCommands > 0) {
672  /*
673  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
674  */
675  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
676  if (aProtocolConstants->RepeatPeriodMillis > tFrameDurationMillis) {
677  delay(aProtocolConstants->RepeatPeriodMillis - tFrameDurationMillis);
678  }
679  }
680  }
681 }
682 
692  uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
693 
694 #if defined(LOCAL_DEBUG)
695  Serial.print(F("Data=0x"));
696  Serial.print(aData, HEX);
697  Serial.print(F(" #="));
698  Serial.println(aNumberOfBits);
699  Serial.flush();
700 #endif
701 
702  if (aNumberOfRepeats < 0) {
703  if (aProtocolConstants->SpecialSendRepeatFunction != NULL) {
704  /*
705  * Send only a special repeat and return
706  */
707  aProtocolConstants->SpecialSendRepeatFunction();
708  return;
709  } else {
710  // Send only one plain frame (as repeat)
711  aNumberOfRepeats = 0;
712  }
713  }
714 
715  // Set IR carrier frequency
716  enableIROut(aProtocolConstants->FrequencyKHz);
717 
718  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
719  while (tNumberOfCommands > 0) {
720  unsigned long tStartOfFrameMillis = millis();
721 
722  if (tNumberOfCommands < ((uint_fast8_t) aNumberOfRepeats + 1) && aProtocolConstants->SpecialSendRepeatFunction != NULL) {
723  // send special repeat, if specified and we are not in the first loop
724  aProtocolConstants->SpecialSendRepeatFunction();
725  } else {
726  /*
727  * Send Header and regular frame
728  */
729  mark(aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros);
730  space(aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros);
731  sendPulseDistanceWidthData(aProtocolConstants, aData, aNumberOfBits);
732  }
733 
734  tNumberOfCommands--;
735  // skip last delay!
736  if (tNumberOfCommands > 0) {
737  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
738  /*
739  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
740  */
741  if (aProtocolConstants->RepeatPeriodMillis > tCurrentFrameDurationMillis) {
742  delay(aProtocolConstants->RepeatPeriodMillis - tCurrentFrameDurationMillis);
743  }
744  }
745  }
746 }
747 
758 void IRsend::sendPulseDistanceWidth(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
759  uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, IRRawDataType aData,
760  uint_fast8_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats,
761  void (*aSpecialSendRepeatFunction)()) {
762 
763  if (aNumberOfRepeats < 0) {
764  if (aSpecialSendRepeatFunction != NULL) {
765  aSpecialSendRepeatFunction();
766  return;
767  } else {
768  aNumberOfRepeats = 0; // send a plain frame as repeat
769  }
770  }
771 
772  // Set IR carrier frequency
773  enableIROut(aFrequencyKHz);
774 
775  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
776  while (tNumberOfCommands > 0) {
777  unsigned long tStartOfFrameMillis = millis();
778 
779  if (tNumberOfCommands < ((uint_fast8_t) aNumberOfRepeats + 1) && aSpecialSendRepeatFunction != NULL) {
780  // send special repeat
781  aSpecialSendRepeatFunction();
782  } else {
783  // Header and regular frame
784  mark(aHeaderMarkMicros);
785  space(aHeaderSpaceMicros);
786  sendPulseDistanceWidthData(aOneMarkMicros, aOneSpaceMicros, aZeroMarkMicros, aZeroSpaceMicros, aData, aNumberOfBits,
787  aFlags);
788  }
789 
790  tNumberOfCommands--;
791  // skip last delay!
792  if (tNumberOfCommands > 0) {
793  /*
794  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
795  */
796  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
797  if (aRepeatPeriodMillis > tFrameDurationMillis) {
798  delay(aRepeatPeriodMillis - tFrameDurationMillis);
799  }
800  }
801  }
802 }
803 
813  uint_fast8_t aNumberOfBits) {
814 
816  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
817  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, aData, aNumberOfBits, aProtocolConstants->Flags);
818 }
819 
828 void IRsend::sendPulseDistanceWidthData(uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros,
829  uint16_t aZeroSpaceMicros, IRRawDataType aData, uint_fast8_t aNumberOfBits, uint8_t aFlags) {
830 
831 #if defined(LOCAL_DEBUG)
832  Serial.print(aData, HEX);
833  Serial.print('|');
834  Serial.println(aNumberOfBits);
835  Serial.flush();
836 #endif
837 
838  // For MSBFirst, send data from MSB to LSB until mask bit is shifted out
839  IRRawDataType tMask = 1ULL << (aNumberOfBits - 1);
840  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
841  if (((aFlags & PROTOCOL_IS_MSB_FIRST) && (aData & tMask)) || (!(aFlags & PROTOCOL_IS_MSB_FIRST) && (aData & 1))) {
842 #if defined(LOCAL_TRACE)
843  Serial.print('1');
844 #endif
845  mark(aOneMarkMicros);
846  space(aOneSpaceMicros);
847  } else {
848 #if defined(LOCAL_TRACE)
849  Serial.print('0');
850 #endif
851  mark(aZeroMarkMicros);
852  space(aZeroSpaceMicros);
853  }
854  if (aFlags & PROTOCOL_IS_MSB_FIRST) {
855  tMask >>= 1;
856  } else {
857  aData >>= 1;
858  }
859  }
860  /*
861  * Stop bit is sent for all pulse distance protocols i.e. aOneSpaceMicros != aZeroSpaceMicros.
862  * Therefore it is not sent for Sony :-)
863  * For sending from an array, no intermediate stop bit must be sent for all but last data chunk.
864  */
865  if ((!(aFlags & SUPPRESS_STOP_BIT)) && (abs(aOneSpaceMicros - aZeroSpaceMicros) > (aOneSpaceMicros / 4))) {
866  // Send stop bit here
867 #if defined(LOCAL_TRACE)
868  Serial.print('S');
869 #endif
870  mark(aOneMarkMicros); // Use aOneMarkMicros for stop bits. This seems to be correct for all protocols :-)
871  }
872 #if defined(LOCAL_TRACE)
873  Serial.println();
874 #endif
875 }
876 
887 void IRsend::sendBiphaseData(uint16_t aBiphaseTimeUnit, uint32_t aData, uint_fast8_t aNumberOfBits) {
888 
889  IR_TRACE_PRINT(F("0x"));
890  IR_TRACE_PRINT(aData, HEX);
891 
892 #if defined(LOCAL_TRACE)
893  Serial.print('S');
894 #endif
895 
896 // Data - Biphase code MSB first
897 // prepare for start with sending the start bit, which is 1
898  uint32_t tMask = 1UL << aNumberOfBits; // mask is now set for the virtual start bit
899  uint_fast8_t tLastBitValue = 1; // Start bit is a 1
900  bool tNextBitIsOne = 1; // Start bit is a 1
901  for (uint_fast8_t i = aNumberOfBits + 1; i > 0; i--) {
902  bool tCurrentBitIsOne = tNextBitIsOne;
903  tMask >>= 1;
904  tNextBitIsOne = ((aData & tMask) != 0) || (i == 1); // true for last bit to avoid extension of mark
905  if (tCurrentBitIsOne) {
906 #if defined(LOCAL_TRACE)
907  Serial.print('1');
908 #endif
909  space(aBiphaseTimeUnit);
910  if (tNextBitIsOne) {
911  mark(aBiphaseTimeUnit);
912  } else {
913  // if next bit is 0, extend the current mark in order to generate a continuous signal without short breaks
914  mark(2 * aBiphaseTimeUnit);
915  }
916  tLastBitValue = 1;
917 
918  } else {
919 #if defined(LOCAL_TRACE)
920  Serial.print('0');
921 #endif
922  if (!tLastBitValue) {
923  mark(aBiphaseTimeUnit);
924  }
925  space(aBiphaseTimeUnit);
926  tLastBitValue = 0;
927  }
928  }
929  IR_TRACE_PRINTLN(F(""));
930 }
931 
947 void IRsend::mark(uint16_t aMarkMicros) {
948 
949 #if defined(SEND_PWM_BY_TIMER) || defined(USE_NO_SEND_PWM)
950 # if !defined(NO_LED_FEEDBACK_CODE)
952  setFeedbackLED(true);
953  }
954 # endif
955 #endif
956 
957 #if defined(SEND_PWM_BY_TIMER)
958  /*
959  * Generate hardware PWM signal
960  */
961  enableSendPWMByTimer(); // Enable timer or ledcWrite() generated PWM output
962  customDelayMicroseconds(aMarkMicros);
963  IRLedOff(); // disables hardware PWM and manages feedback LED
964  return;
965 
966 #elif defined(USE_NO_SEND_PWM)
967  /*
968  * Here we generate no carrier PWM, just simulate an active low receiver signal.
969  */
970 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
971  // Here we have no hardware supported Open Drain outputs, so we must mimicking it
972  pinModeFast(sendPin, OUTPUT); // active state for mimicking open drain
973 # elif defined(USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN)
974  digitalWriteFast(sendPin, HIGH); // Set output to active high.
975 # else
976  digitalWriteFast(sendPin, LOW); // Set output to active low.
977 # endif
978 
979  customDelayMicroseconds(aMarkMicros);
980  IRLedOff();
981 # if !defined(NO_LED_FEEDBACK_CODE)
983  setFeedbackLED(false);
984  }
985  return;
986 # endif
987 
988 #else // defined(SEND_PWM_BY_TIMER)
989  /*
990  * Generate PWM by bit banging
991  */
992  unsigned long tStartMicros = micros();
993  unsigned long tNextPeriodEnding = tStartMicros;
994  unsigned long tMicros;
995 # if !defined(NO_LED_FEEDBACK_CODE)
996  bool FeedbackLedIsActive = false;
997 # endif
998 
999  do {
1000 // digitalToggleFast(_IR_TIMING_TEST_PIN);
1001  /*
1002  * Output the PWM pulse
1003  */
1004  noInterrupts(); // do not let interrupts extend the short on period
1005 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
1006 # if defined(OUTPUT_OPEN_DRAIN)
1007  digitalWriteFast(sendPin, LOW); // set output with pin mode OUTPUT_OPEN_DRAIN to active low
1008 # else
1009  pinModeFast(sendPin, OUTPUT); // active state for mimicking open drain
1010 # endif
1011 # else
1012  // 3.5 us from FeedbackLed on to pin setting. 5.7 us from call of mark() to pin setting incl. setting of feedback pin.
1013  // 4.3 us from do{ to pin setting if sendPin is no constant
1014  digitalWriteFast(sendPin, HIGH);
1015 # endif
1016  delayMicroseconds (periodOnTimeMicros); // On time is 8 us for 30% duty cycle. This is normally implemented by a blocking wait.
1017 
1018  /*
1019  * Output the PWM pause
1020  */
1021 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1022 # if defined(OUTPUT_OPEN_DRAIN)
1023  digitalWriteFast(sendPin, HIGH); // Set output with pin mode OUTPUT_OPEN_DRAIN to inactive high.
1024 # else
1025  pinModeFast(sendPin, INPUT); // to mimic the open drain inactive state
1026 # endif
1027 
1028 # else
1029  digitalWriteFast(sendPin, LOW);
1030 # endif
1031  /*
1032  * Enable interrupts at start of the longer off period. Required at least to keep micros correct.
1033  * If receive interrupt is still active, it takes 3.4 us from now until receive ISR is active (for 7 us + pop's)
1034  */
1035  interrupts();
1036 
1037 # if !defined(NO_LED_FEEDBACK_CODE)
1038  /*
1039  * Delayed call of setFeedbackLED() to get better startup timing, especially required for consecutive marks
1040  */
1041  if (!FeedbackLedIsActive) {
1042  FeedbackLedIsActive = true;
1044  setFeedbackLED(true);
1045  }
1046  }
1047 # endif
1048  /*
1049  * PWM pause timing
1050  * Measured delta between pause duration values are 13 us for a 16 MHz Uno (from 13 to 26), if interrupts are disabled below
1051  * Measured delta between pause duration values are 20 us for a 16 MHz Uno (from 7.8 to 28), if interrupts are not disabled below
1052  * Minimal pause duration is 5.2 us with NO_LED_FEEDBACK_CODE enabled
1053  * and 8.1 us with NO_LED_FEEDBACK_CODE disabled.
1054  */
1055  tNextPeriodEnding += periodTimeMicros;
1056 #if defined(__AVR__) // micros() for STM sometimes give decreasing values if interrupts are disabled. See https://github.com/stm32duino/Arduino_Core_STM32/issues/1680
1057  noInterrupts(); // disable interrupts (especially the 20 us receive interrupts) only at start of the PWM pause. Otherwise it may extend the pause too much.
1058 #endif
1059  do {
1060 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1061  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
1062 #endif
1063  /*
1064  * For AVR @16MHz we have only 4 us resolution.
1065  * The duration of the micros() call itself is 3 us.
1066  * It takes 0.9 us from signal going low here.
1067  * The rest of the loop takes 1.2 us with NO_LED_FEEDBACK_CODE enabled
1068  * and 3 us with NO_LED_FEEDBACK_CODE disabled.
1069  */
1070 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1071  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
1072 #endif
1073  /*
1074  * Exit the forever loop if aMarkMicros has reached
1075  */
1076  tMicros = micros();
1077  uint16_t tDeltaMicros = tMicros - tStartMicros;
1078 #if defined(__AVR__)
1079  // reset feedback led in the last pause before end
1080 // tDeltaMicros += (160 / CLOCKS_PER_MICRO); // adding this once increases program size, so do it below !
1081 # if !defined(NO_LED_FEEDBACK_CODE)
1082  if (tDeltaMicros >= aMarkMicros - (30 + (112 / CLOCKS_PER_MICRO))) { // 30 to be constant. Using periodTimeMicros increases program size too much.
1084  setFeedbackLED(false);
1085  }
1086  }
1087 # endif
1088  // Just getting variables and check for end condition takes minimal 3.8 us
1089  if (tDeltaMicros >= aMarkMicros - (112 / CLOCKS_PER_MICRO)) { // To compensate for call duration - 112 is an empirical value
1090 #else
1091  if (tDeltaMicros >= aMarkMicros) {
1092 # if !defined(NO_LED_FEEDBACK_CODE)
1094  setFeedbackLED(false);
1095  }
1096 # endif
1097 #endif
1098 #if defined(__AVR__)
1099  interrupts();
1100 #endif
1101  return;
1102  }
1103  } while (tMicros < tNextPeriodEnding);
1104  } while (true);
1105 # endif
1106 }
1107 
1114 #if defined(SEND_PWM_BY_TIMER)
1115  disableSendPWMByTimer(); // Disable PWM output
1116 #elif defined(USE_NO_SEND_PWM)
1117 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1118  digitalWriteFast(sendPin, LOW); // prepare for all next active states.
1119  pinModeFast(sendPin, INPUT);// inactive state for open drain
1120 # elif defined(USE_ACTIVE_HIGH_OUTPUT_FOR_SEND_PIN)
1121  digitalWriteFast(sendPin, LOW); // Set output to inactive low.
1122 # else
1123  digitalWriteFast(sendPin, HIGH); // Set output to inactive high.
1124 # endif
1125 #else
1126 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
1127 # if defined(OUTPUT_OPEN_DRAIN)
1128  digitalWriteFast(sendPin, HIGH); // Set output to inactive high.
1129 # else
1130  pinModeFast(sendPin, INPUT); // inactive state to mimic open drain
1131 # endif
1132 # else
1133  digitalWriteFast(sendPin, LOW);
1134 # endif
1135 #endif
1136 
1137 #if !defined(NO_LED_FEEDBACK_CODE)
1139  setFeedbackLED(false);
1140  }
1141 #endif
1142 }
1143 
1148 void IRsend::space(uint16_t aSpaceMicros) {
1149  customDelayMicroseconds(aSpaceMicros);
1150 }
1151 
1156 void IRsend::customDelayMicroseconds(unsigned long aMicroseconds) {
1157 #if defined(ESP32) || defined(ESP8266)
1158  // from https://github.com/crankyoldgit/IRremoteESP8266/blob/00b27cc7ea2e7ac1e48e91740723c805a38728e0/src/IRsend.cpp#L123
1159  // Invoke a delay(), where possible, to avoid triggering the WDT.
1160  // see https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1114 for the reason of checking for > 16383)
1161  // delayMicroseconds() is only accurate to 16383 us. Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
1162  if (aMicroseconds > 16383) {
1163  delay(aMicroseconds / 1000UL); // Delay for as many whole milliseconds as we can.
1164  // Delay the remaining sub-millisecond.
1165  delayMicroseconds(static_cast<uint16_t>(aMicroseconds % 1000UL));
1166  } else {
1167  delayMicroseconds(aMicroseconds);
1168  }
1169 #else
1170 
1171 # if defined(__AVR__)
1172  unsigned long start = micros() - (64 / clockCyclesPerMicrosecond()); // - (64 / clockCyclesPerMicrosecond()) for reduced resolution and additional overhead
1173 # else
1174  unsigned long start = micros();
1175 # endif
1176 // overflow invariant comparison :-)
1177  while (micros() - start < aMicroseconds) {
1178  }
1179 #endif
1180 }
1181 
1188 void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
1189 #if defined(SEND_PWM_BY_TIMER)
1190  timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
1191 
1192 #elif defined(USE_NO_SEND_PWM)
1193  (void) aFrequencyKHz;
1194 
1195 #else
1196  periodTimeMicros = (1000U + (aFrequencyKHz / 2)) / aFrequencyKHz; // rounded value -> 26 for 38.46 kHz, 27 for 37.04 kHz, 25 for 40 kHz.
1197 # if defined(IR_SEND_PIN)
1198  periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50) / 100U); // +50 for rounding -> 830/100 for 30% and 16 MHz
1199 # else
1200 // Heuristics! We require a nanosecond correction for "slow" digitalWrite() functions
1201  periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50 - (PULSE_CORRECTION_NANOS / 10)) / 100U); // +50 for rounding -> 530/100 for 30% and 16 MHz
1202 # endif
1203 #endif // defined(SEND_PWM_BY_TIMER)
1204 
1205 #if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && defined(OUTPUT_OPEN_DRAIN) // the mode INPUT for mimicking open drain is set at IRLedOff()
1206 # if defined(IR_SEND_PIN)
1207  pinModeFast(IR_SEND_PIN, OUTPUT_OPEN_DRAIN);
1208 # else
1209  pinModeFast(sendPin, OUTPUT_OPEN_DRAIN);
1210 # endif
1211 #else
1212 
1213 // For Non AVR platforms pin mode for SEND_PWM_BY_TIMER must be handled by the timerConfigForSend() function
1214 // because ESP 2.0.2 ledcWrite does not work if pin mode is set, and RP2040 requires gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
1215 # if defined(__AVR__) || !defined(SEND_PWM_BY_TIMER)
1216 # if defined(IR_SEND_PIN)
1217  pinModeFast(IR_SEND_PIN, OUTPUT);
1218 # else
1219  pinModeFast(sendPin, OUTPUT);
1220 # endif
1221 # endif
1222 #endif // defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
1223 }
1224 
1225 #if defined(SEND_PWM_BY_TIMER)
1226 // Used for Bang&Olufsen
1227 void IRsend::enableHighFrequencyIROut(uint_fast16_t aFrequencyKHz) {
1228  timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
1229  // For Non AVR platforms pin mode for SEND_PWM_BY_TIMER must be handled by the timerConfigForSend() function
1230  // because ESP 2.0.2 ledcWrite does not work if pin mode is set, and RP2040 requires gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
1231 # if defined(__AVR__)
1232 # if defined(IR_SEND_PIN)
1233  pinModeFast(IR_SEND_PIN, OUTPUT);
1234 # else
1235  pinModeFast(sendPin, OUTPUT);
1236 # endif
1237 # endif
1238 }
1239 #endif
1240 
1242  return PULSE_CORRECTION_NANOS;
1243 }
1244 
1246 #if defined(_IR_MEASURE_TIMING)
1247 #undef _IR_MEASURE_TIMING
1248 #endif
1249 #if defined(LOCAL_TRACE)
1250 #undef LOCAL_TRACE
1251 #endif
1252 #if defined(LOCAL_DEBUG)
1253 #undef LOCAL_DEBUG
1254 #endif
1255 #endif // _IR_SEND_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRProtocol.h:110
SUPPRESS_STOP_BIT
#define SUPPRESS_STOP_BIT
Definition: IRProtocol.h:146
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:250
BITS_IN_RAW_DATA_TYPE
#define BITS_IN_RAW_DATA_TYPE
Definition: IRremoteInt.h:110
ONKYO
@ ONKYO
Definition: IRProtocol.h:51
DistanceWidthTimingInfoStruct::HeaderMarkMicros
uint16_t HeaderMarkMicros
Definition: IRProtocol.h:80
IRsend::sendApple
void sendApple(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
Apple: Send NEC with fixed 16 bit Apple address 0x87EE.
Definition: ir_NEC.hpp:213
IRsend::sendMagiQuest
void sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude)
Definition: ir_MagiQuest.hpp:121
KASEIKYO_DENON
@ KASEIKYO_DENON
Definition: IRProtocol.h:54
PROTOCOL_IS_MSB_FIRST
#define PROTOCOL_IS_MSB_FIRST
Definition: IRProtocol.h:147
setFeedbackLED
void setFeedbackLED(bool aSwitchLedOn)
Flash LED while receiving or sending IR data.
Definition: IRFeedbackLED.hpp:108
JVC
@ JVC
Definition: IRProtocol.h:46
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRProtocol.h:119
IRsend::aNumberOfRepeats
void int_fast8_t aNumberOfRepeats
Definition: IRremoteInt.h:547
IRsend::sendPin
uint8_t sendPin
Definition: IRremoteInt.h:645
IRsend::sendJVC
void sendJVC(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
The JVC protocol repeats by skipping the header mark and space -> this leads to a poor repeat detecti...
Definition: ir_JVC.hpp:92
IRsend::sendKaseikyo_Sharp
void sendKaseikyo_Sharp(uint16_t aAddress, uint8_t aData, int_fast8_t aNumberOfRepeats)
Stub using Kaseikyo with SHARP_VENDOR_ID_CODE.
Definition: ir_Kaseikyo.hpp:185
KASEIKYO_SHARP
@ KASEIKYO_SHARP
Definition: IRProtocol.h:55
FAST
@ FAST
Definition: IRProtocol.h:71
IRsend::setSendPin
void setSendPin(uint_fast8_t aSendPin)
Definition: IRSend.hpp:128
pinModeFast
#define pinModeFast
Definition: digitalWriteFast.h:371
IRsend::sendBoseWave
void sendBoseWave(uint8_t aCommand, int_fast8_t aNumberOfRepeats=NO_REPEATS)
Definition: ir_BoseWave.hpp:57
IRsend::sendSony
void sendSony(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t numberOfBits=12)
Definition: ir_Sony.hpp:103
digitalWriteFast
#define digitalWriteFast
Definition: digitalWriteFast.h:339
PULSE_CORRECTION_NANOS
#define PULSE_CORRECTION_NANOS
Define to disable carrier PWM generation in software and use (restricted) hardware PWM.
Definition: IRremote.hpp:235
IRsend::mark
void mark(uint16_t aMarkMicros)
Sends an IR mark for the specified number of microseconds.
Definition: IRSend.hpp:947
SONY
@ SONY
Definition: IRProtocol.h:64
KASEIKYO_JVC
@ KASEIKYO_JVC
Definition: IRProtocol.h:56
PulseDistanceWidthProtocolConstants::SpecialSendRepeatFunction
void(* SpecialSendRepeatFunction)()
Definition: IRProtocol.h:140
IRsend::sendSamsung48
void sendSamsung48(uint16_t aAddress, uint32_t aCommand, int_fast8_t aNumberOfRepeats)
Here we send Samsung48 We send 2 x (8 bit command and then ~command)
Definition: ir_Samsung.hpp:233
IRsend::sendRC6
void sendRC6(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
Assemble raw data for RC6 from parameters and toggle state and send We do not wait for the minimal tr...
Definition: ir_RC5_RC6.hpp:350
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
decode_type_t
decode_type_t
An enum consisting of all supported formats.
Definition: IRProtocol.h:40
IRsend::customDelayMicroseconds
static void customDelayMicroseconds(unsigned long aMicroseconds)
Custom delay function that circumvents Arduino's delayMicroseconds 16 bit limit and is (mostly) not e...
Definition: IRSend.hpp:1156
IRsend::sendPulseDistanceWidth
void sendPulseDistanceWidth(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Sends PulseDistance frames and repeats.
Definition: IRSend.hpp:691
IRsend::IRsend
IRsend()
Definition: IRSend.hpp:67
SAMSUNG
@ SAMSUNG
Definition: IRProtocol.h:60
BOSEWAVE
@ BOSEWAVE
Definition: IRProtocol.h:67
DistanceWidthTimingInfoStruct::OneSpaceMicros
uint16_t OneSpaceMicros
Definition: IRProtocol.h:83
IRData::decodedRawData
IRRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send functions.
Definition: IRProtocol.h:113
IRsend::sendRaw_P
void sendRaw_P(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
New function using an 8 byte tick (50 us) timing array in FLASH to save program memory Raw data start...
Definition: IRSend.hpp:489
IRsend
Main class for sending IR signals.
Definition: IRremoteInt.h:454
DistanceWidthTimingInfoStruct::ZeroMarkMicros
uint16_t ZeroMarkMicros
Definition: IRProtocol.h:84
IR_TRACE_PRINT
#define IR_TRACE_PRINT(...)
Definition: IRremoteInt.h:172
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:69
NEC2
@ NEC2
Definition: IRProtocol.h:50
PulseDistanceWidthProtocolConstants::Flags
uint8_t Flags
Definition: IRProtocol.h:138
IRsend::sendSamsung
void sendSamsung(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
Here we send Samsung32 If we get a command < 0x100, we send command and then ~command If we get an ad...
Definition: ir_Samsung.hpp:171
DistanceWidthTimingInfoStruct
Definition: IRProtocol.h:79
IRsend::sendRaw
void sendRaw(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
Function using an 8 byte tick timing array to save program memory Raw data starts with a Mark.
Definition: IRSend.hpp:435
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:134
FeedbackLEDControlStruct::LedFeedbackEnabled
uint8_t LedFeedbackEnabled
LED_FEEDBACK_ENABLED_FOR_RECEIVE or LED_FEEDBACK_ENABLED_FOR_SEND -> enable blinking of pin on IR pro...
Definition: IRFeedbackLED.hpp:44
PANASONIC
@ PANASONIC
Definition: IRProtocol.h:52
timerConfigForSend
void timerConfigForSend(uint16_t aFrequencyKHz)
IF PWM should be generated not by software, but by a timer, this function sets output pin mode,...
Definition: IRTimer.hpp:127
IRData
Data structure for the user application, available as decodedIRData.
Definition: IRProtocol.h:108
IR_SEND_PIN
#define IR_SEND_PIN
Definition: TinyIRSender.hpp:65
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRProtocol.h:120
IRsend::sendSamsungLG
void sendSamsungLG(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Samsung.hpp:148
LED_FEEDBACK_ENABLED_FOR_SEND
#define LED_FEEDBACK_ENABLED_FOR_SEND
Definition: IRremoteInt.h:394
DistanceWidthTimingInfoStruct::OneMarkMicros
uint16_t OneMarkMicros
Definition: IRProtocol.h:82
DO_NOT_ENABLE_LED_FEEDBACK
#define DO_NOT_ENABLE_LED_FEEDBACK
Definition: IRremoteInt.h:391
IRsend::sendSharp
void sendSharp(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Denon.hpp:116
IRsend::begin
void begin(uint_fast8_t aSendPin)
Initializes the send pin and enable LED feedback with board specific FEEDBACK_LED_ON() and FEEDBACK_L...
Definition: IRSend.hpp:121
IRsend::sendKaseikyo_JVC
void sendKaseikyo_JVC(uint16_t aAddress, uint8_t aData, int_fast8_t aNumberOfRepeats)
Stub using Kaseikyo with JVC_VENDOR_ID_CODE.
Definition: ir_Kaseikyo.hpp:192
IRsend::sendNEC
void sendNEC(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
NEC Send frame and special repeats There is NO delay after the last sent repeat!
Definition: ir_NEC.hpp:183
IRsend::periodOnTimeMicros
uint16_t periodOnTimeMicros
Definition: IRremoteInt.h:648
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRProtocol.h:111
NEC
@ NEC
Definition: IRProtocol.h:49
IRsend::sendPanasonic
void sendPanasonic(uint16_t aAddress, uint8_t aData, int_fast8_t aNumberOfRepeats)
Stub using Kaseikyo with PANASONIC_VENDOR_ID_CODE.
Definition: ir_Kaseikyo.hpp:164
APPLE
@ APPLE
Definition: IRProtocol.h:44
IRsend::getPulseCorrectionNanos
uint16_t getPulseCorrectionNanos()
Definition: IRSend.hpp:1241
IRsend::write
size_t write(IRData *aIRSendData, int_fast8_t aNumberOfRepeats=NO_REPEATS)
Interprets and sends a IRData structure.
Definition: IRSend.hpp:170
IRsend::sendDenon
void sendDenon(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aSendSharp=false)
Definition: ir_Denon.hpp:120
LEGO_PF
@ LEGO_PF
Definition: IRProtocol.h:68
DistanceWidthTimingInfoStruct::ZeroSpaceMicros
uint16_t ZeroSpaceMicros
Definition: IRProtocol.h:85
IRRawDataType
uint32_t IRRawDataType
Definition: IRremoteInt.h:109
IR_TRACE_PRINTLN
#define IR_TRACE_PRINTLN(...)
Definition: IRremoteInt.h:173
KASEIKYO_MITSUBISHI
@ KASEIKYO_MITSUBISHI
Definition: IRProtocol.h:57
DENON
@ DENON
Definition: IRProtocol.h:45
enableSendPWMByTimer
void enableSendPWMByTimer()
Enables output of the PWM signal of the timer at the timer pin.
Definition: IRTimer.hpp:133
IrSender
IRsend IrSender
Definition: IRSend.hpp:65
IR_SEND_DUTY_CYCLE_PERCENT
#define IR_SEND_DUTY_CYCLE_PERCENT
Duty cycle in percent for sent signals.
Definition: IRremote.hpp:243
SIRCS_12_PROTOCOL
#define SIRCS_12_PROTOCOL
Definition: IRProtocol.h:75
RC5
@ RC5
Definition: IRProtocol.h:58
PulseDistanceWidthProtocolConstants::DistanceWidthTimingInfo
DistanceWidthTimingInfoStruct DistanceWidthTimingInfo
Definition: IRProtocol.h:137
IRsend::periodTimeMicros
uint16_t periodTimeMicros
Definition: IRremoteInt.h:647
IRsend::space
static void space(uint16_t aSpaceMicros)
Sends an IR space for the specified number of microseconds.
Definition: IRSend.hpp:1148
IRsend::sendRC5
void sendRC5(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
Definition: ir_RC5_RC6.hpp:103
FeedbackLEDControl
struct FeedbackLEDControlStruct FeedbackLEDControl
The feedback LED control instance.
Definition: IRFeedbackLED.hpp:47
disableSendPWMByTimer
void disableSendPWMByTimer()
Disables output of the PWM signal of the timer at the timer pin and set it to inactive.
Definition: IRTimer.hpp:138
IRsend::sendNEC2
void sendNEC2(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
NEC2 Send frame !!! and repeat the frame for each requested repeat !!! There is NO delay after the la...
Definition: ir_NEC.hpp:201
IRsend::sendKaseikyo_Mitsubishi
void sendKaseikyo_Mitsubishi(uint16_t aAddress, uint8_t aData, int_fast8_t aNumberOfRepeats)
Stub using Kaseikyo with MITSUBISHI_VENDOR_ID_CODE.
Definition: ir_Kaseikyo.hpp:178
RC6
@ RC6
Definition: IRProtocol.h:59
IRsend::IRLedOff
void IRLedOff()
Just switch the IR sending LED off to send an IR space A space is "no output", so the PWM output is d...
Definition: IRSend.hpp:1113
IRsend::sendPulseDistanceWidthFromArray
void sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros, uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats)
Definition: IRSend.hpp:535
sendFAST
void sendFAST(uint8_t aSendPin, uint16_t aCommand, uint_fast8_t aNumberOfRepeats=0)
Definition: TinyIRSender.hpp:294
IRsend::sendPulseDistanceWidthData
void sendPulseDistanceWidthData(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits)
Sends PulseDistance from data contained in parameter using ProtocolConstants structure for timing etc...
Definition: IRSend.hpp:812
IRsend::sendOnkyo
void sendOnkyo(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
There is NO delay after the last sent repeat!
Definition: ir_NEC.hpp:192
PulseDistanceWidthProtocolConstants::RepeatPeriodMillis
unsigned int RepeatPeriodMillis
Definition: IRProtocol.h:139
IRsend::sendLegoPowerFunctions
void sendLegoPowerFunctions(uint8_t aChannel, uint8_t tCommand, uint8_t aMode, bool aDoSend5Times=true)
Definition: ir_Lego.hpp:97
USE_DEFAULT_FEEDBACK_LED_PIN
#define USE_DEFAULT_FEEDBACK_LED_PIN
Definition: IRremoteInt.h:64
SAMSUNGLG
@ SAMSUNGLG
Definition: IRProtocol.h:61
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRProtocol.h:109
IRsend::sendBiphaseData
void sendBiphaseData(uint16_t aBiphaseTimeUnit, uint32_t aData, uint_fast8_t aNumberOfBits)
Sends Biphase data MSB first Always send start bit, do not send the trailing space of the start bit 0...
Definition: IRSend.hpp:887
SAMSUNG48
@ SAMSUNG48
Definition: IRProtocol.h:62
IRsend::sendLG
void sendLG(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
LG uses the NEC repeat.
Definition: ir_LG.hpp:165
PulseDistanceWidthProtocolConstants::FrequencyKHz
uint_fast8_t FrequencyKHz
Definition: IRProtocol.h:136
DistanceWidthTimingInfoStruct::HeaderSpaceMicros
uint16_t HeaderSpaceMicros
Definition: IRProtocol.h:81
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:610
LG
@ LG
Definition: IRProtocol.h:47
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1188
IRsend::sendKaseikyo_Denon
void sendKaseikyo_Denon(uint16_t aAddress, uint8_t aData, int_fast8_t aNumberOfRepeats)
Stub using Kaseikyo with DENON_VENDOR_ID_CODE.
Definition: ir_Kaseikyo.hpp:171
setLEDFeedback
void setLEDFeedback(uint8_t aFeedbackLEDPin, uint8_t aEnableLEDFeedback)
Enable blinking of feedback LED (LED_BUILTIN is taken as default) on IR sending and receiving Cannot ...
Definition: IRFeedbackLED.hpp:56
SHARP
@ SHARP
Definition: IRProtocol.h:63