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-2025 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)
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 
60 #if !defined(NO_LED_SEND_FEEDBACK_CODE)
61 #define LED_SEND_FEEDBACK_CODE // Resolve the double negative
62 #endif
63 
68 // The sender instance
70 
71 IRsend::IRsend() { // @suppress("Class members should be properly initialized")
72 #if !defined(IR_SEND_PIN)
73  sendPin = 0;
74 #endif
75 }
76 
77 /******************************************************************************************************************
78  * LED feedback is always enabled for sending. It can only be disabled by using the macro NO_LED_SEND_FEEDBACK_CODE
79  *****************************************************************************************************************/
80 #if defined(IR_SEND_PIN)
81 
84 void IRsend::begin(){
85 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
86  pinModeFast(_IR_TIMING_TEST_PIN, OUTPUT);
87 #endif
88 }
89 
94 void IRsend::begin(uint_fast8_t aFeedbackLEDPin) {
95  setLEDFeedbackPin(aFeedbackLEDPin);
96 }
97 
98 #else // defined(IR_SEND_PIN)
99 IRsend::IRsend(uint_fast8_t aSendPin) { // @suppress("Class members should be properly initialized")
100  sendPin = aSendPin;
101 }
102 
107 void IRsend::begin(uint_fast8_t aSendPin) {
108  sendPin = aSendPin;
109 }
110 
111 void IRsend::setSendPin(uint_fast8_t aSendPin) {
112  sendPin = aSendPin;
113 }
114 
120 void IRsend::begin(uint_fast8_t aSendPin, uint_fast8_t aFeedbackLEDPin) {
121 #if defined(IR_SEND_PIN)
122  (void) aSendPin; // for backwards compatibility
123 #else
124  sendPin = aSendPin;
125 #endif
126 
127 #if defined(LED_SEND_FEEDBACK_CODE)
128  setLEDFeedbackPin(aFeedbackLEDPin);
129 #else
130  (void) aFeedbackLEDPin;
131 #endif
132 }
133 #endif // defined(IR_SEND_PIN)
134 
135 // Deprecated
136 void IRsend::begin(uint_fast8_t aSendPin, bool aEnableLEDFeedback, uint_fast8_t aFeedbackLEDPin) {
137  (void) aEnableLEDFeedback;
138  begin(aSendPin, aFeedbackLEDPin);
139 }
140 
153 size_t IRsend::write(IRData *aIRSendData, int_fast8_t aNumberOfRepeats) {
154 
155  auto tProtocol = aIRSendData->protocol;
156  auto tAddress = aIRSendData->address;
157  auto tCommand = aIRSendData->command;
158  bool tIsRepeat = (aIRSendData->flags & IRDATA_FLAGS_IS_REPEAT);
159  if (tIsRepeat) {
160  aNumberOfRepeats = -1; // if aNumberOfRepeats < 0 then only a special repeat frame will be sent
161  }
162 // switch (tProtocol) { // 26 bytes bigger than if, else if, else
163 // case NEC:
164 // sendNEC(tAddress, tCommand, aNumberOfRepeats, tSendRepeat);
165 // break;
166 // case SAMSUNG:
167 // sendSamsung(tAddress, tCommand, aNumberOfRepeats);
168 // break;
169 // case SONY:
170 // sendSony(tAddress, tCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
171 // break;
172 // case PANASONIC:
173 // sendPanasonic(tAddress, tCommand, aNumberOfRepeats);
174 // break;
175 // case DENON:
176 // sendDenon(tAddress, tCommand, aNumberOfRepeats);
177 // break;
178 // case SHARP:
179 // sendSharp(tAddress, tCommand, aNumberOfRepeats);
180 // break;
181 // case JVC:
182 // sendJVC((uint8_t) tAddress, (uint8_t) tCommand, aNumberOfRepeats); // casts are required to specify the right function
183 // break;
184 // case RC5:
185 // sendRC5(tAddress, tCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
186 // break;
187 // case RC6:
188 // // No toggle for repeats// sendRC6(tAddress, tCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
189 // break;
190 // default:
191 // break;
192 // }
193 
194  /*
195  * Order of protocols is in guessed relevance :-)
196  */
197  if (tProtocol == NEC) {
198  sendNEC(tAddress, tCommand, aNumberOfRepeats);
199 
200  } else if (tProtocol == SAMSUNG) {
201  sendSamsung(tAddress, tCommand, aNumberOfRepeats);
202 
203  } else if (tProtocol == SAMSUNG48) {
204  sendSamsung48(tAddress, tCommand, aNumberOfRepeats);
205 
206  } else if (tProtocol == SAMSUNGLG) {
207  sendSamsungLG(tAddress, tCommand, aNumberOfRepeats);
208 
209  } else if (tProtocol == SONY) {
210  sendSony(tAddress, tCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
211 
212  } else if (tProtocol == PANASONIC) {
213  sendPanasonic(tAddress, tCommand, aNumberOfRepeats);
214 
215  } else if (tProtocol == DENON) {
216  sendDenon(tAddress, tCommand, aNumberOfRepeats);
217 
218  } else if (tProtocol == SHARP) {
219  sendSharp(tAddress, tCommand, aNumberOfRepeats);
220 
221  } else if (tProtocol == LG) {
222  sendLG(tAddress, tCommand, aNumberOfRepeats);
223 
224  } else if (tProtocol == JVC) {
225  sendJVC((uint8_t) tAddress, (uint8_t) tCommand, aNumberOfRepeats); // casts are required to specify the right function
226 
227  } else if (tProtocol == RC5) {
228  sendRC5(tAddress, tCommand, aNumberOfRepeats, !tIsRepeat); // No toggle for repeats
229 
230  } else if (tProtocol == RC6) {
231  sendRC6(tAddress, tCommand, aNumberOfRepeats, !tIsRepeat); // No toggle for repeats
232 
233  } else if (tProtocol == KASEIKYO_JVC) {
234  sendKaseikyo_JVC(tAddress, tCommand, aNumberOfRepeats);
235 
236  } else if (tProtocol == KASEIKYO_DENON) {
237  sendKaseikyo_Denon(tAddress, tCommand, aNumberOfRepeats);
238 
239  } else if (tProtocol == KASEIKYO_SHARP) {
240  sendKaseikyo_Sharp(tAddress, tCommand, aNumberOfRepeats);
241 
242  } else if (tProtocol == KASEIKYO_MITSUBISHI) {
243  sendKaseikyo_Mitsubishi(tAddress, tCommand, aNumberOfRepeats);
244 
245  } else if (tProtocol == NEC2) {
246  sendNEC2(tAddress, tCommand, aNumberOfRepeats);
247 
248  } else if (tProtocol == ONKYO) {
249  sendOnkyo(tAddress, tCommand, aNumberOfRepeats);
250 
251  } else if (tProtocol == APPLE) {
252  sendApple(tAddress, tCommand, aNumberOfRepeats);
253 
254 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
255  } else if (tProtocol == BOSEWAVE) {
256  sendBoseWave(tCommand, aNumberOfRepeats);
257 
258  } else if (tProtocol == MAGIQUEST) {
259  // we have a 32 bit ID/address
260  sendMagiQuest(aIRSendData->decodedRawData, tCommand);
261 
262  } else if (tProtocol == FAST) {
263  // We have only 8 bit command
264  sendFAST(tCommand, aNumberOfRepeats);
265 
266  } else if (tProtocol == LEGO_PF) {
267  sendLegoPowerFunctions(tAddress, tCommand, tCommand >> 4, tIsRepeat); // send 5 autorepeats
268 #endif
269 
270  } else {
271  return 0; // Not supported by write. E.g for BANG_OLUFSEN
272  }
273  return 1;
274 }
275 
281 size_t IRsend::write(decode_type_t aProtocol, uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
282 
283 // switch (aProtocol) { // 26 bytes bigger than if, else if, else
284 // case NEC:
285 // sendNEC(aAddress, aCommand, aNumberOfRepeats, tSendRepeat);
286 // break;
287 // case SAMSUNG:
288 // sendSamsung(aAddress, aCommand, aNumberOfRepeats);
289 // break;
290 // case SONY:
291 // sendSony(aAddress, aCommand, aNumberOfRepeats, aIRSendData->numberOfBits);
292 // break;
293 // case PANASONIC:
294 // sendPanasonic(aAddress, aCommand, aNumberOfRepeats);
295 // break;
296 // case DENON:
297 // sendDenon(aAddress, aCommand, aNumberOfRepeats);
298 // break;
299 // case SHARP:
300 // sendSharp(aAddress, aCommand, aNumberOfRepeats);
301 // break;
302 // case JVC:
303 // sendJVC((uint8_t) aAddress, (uint8_t) aCommand, aNumberOfRepeats); // casts are required to specify the right function
304 // break;
305 // case RC5:
306 // sendRC5(aAddress, aCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
307 // break;
308 // case RC6:
309 // // No toggle for repeats// sendRC6(aAddress, aCommand, aNumberOfRepeats, !tSendRepeat); // No toggle for repeats
310 // break;
311 // default:
312 // break;
313 // }
314 
315  /*
316  * Order of protocols is in guessed relevance :-)
317  */
318  if (aProtocol == NEC) {
319  sendNEC(aAddress, aCommand, aNumberOfRepeats);
320 
321  } else if (aProtocol == SAMSUNG) {
323 
324  } else if (aProtocol == SAMSUNG48) {
326 
327  } else if (aProtocol == SAMSUNGLG) {
329 
330  } else if (aProtocol == SONY) {
332 
333  } else if (aProtocol == PANASONIC) {
335 
336  } else if (aProtocol == DENON) {
337  sendDenon(aAddress, aCommand, aNumberOfRepeats);
338 
339  } else if (aProtocol == SHARP) {
340  sendSharp(aAddress, aCommand, aNumberOfRepeats);
341 
342  } else if (aProtocol == LG) {
343  sendLG(aAddress, aCommand, aNumberOfRepeats);
344 
345  } else if (aProtocol == JVC) {
346  sendJVC((uint8_t) aAddress, (uint8_t) aCommand, aNumberOfRepeats); // casts are required to specify the right function
347 
348  } else if (aProtocol == RC5) {
349  sendRC5(aAddress, aCommand, aNumberOfRepeats, (aNumberOfRepeats > 0)); // No toggle for repeats
350 
351  } else if (aProtocol == RC6) {
352  sendRC6(aAddress, aCommand, aNumberOfRepeats, (aNumberOfRepeats > 0)); // No toggle for repeats
353 
354  } else if (aProtocol == KASEIKYO_JVC) {
356 
357  } else if (aProtocol == KASEIKYO_DENON) {
359 
360  } else if (aProtocol == KASEIKYO_SHARP) {
362 
363  } else if (aProtocol == KASEIKYO_MITSUBISHI) {
365 
366  } else if (aProtocol == NEC2) {
367  sendNEC2(aAddress, aCommand, aNumberOfRepeats);
368 
369  } else if (aProtocol == ONKYO) {
370  sendOnkyo(aAddress, aCommand, aNumberOfRepeats);
371 
372  } else if (aProtocol == APPLE) {
373  sendApple(aAddress, aCommand, aNumberOfRepeats);
374 
375 #if !defined(EXCLUDE_EXOTIC_PROTOCOLS)
376  } else if (aProtocol == BOSEWAVE) {
378 
379  } else if (aProtocol == FAST) {
380  // We have only 8 bit command
382 
383  } else if (aProtocol == LEGO_PF) {
384  sendLegoPowerFunctions(aAddress, aCommand, aCommand >> 4, (aNumberOfRepeats < 0)); // send 5 autorepeats, except for dedicated repeats
385 #endif
386 
387  } else {
388  return 0; // Not supported by write. E.g for BANG_OLUFSEN
389  }
390  return 1;
391 }
392 
393 /**********************************************************************************************************************
394  * SendRaw functions
395  **********************************************************************************************************************/
396 
401 void IRsend::sendRaw(const uint16_t aBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
402 // Set IR carrier frequency
403  enableIROut(aIRFrequencyKilohertz);
404 
405  /*
406  * Raw data starts with a mark.
407  */
408  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
409  if (i & 1) {
410  // Odd
411  space(aBufferWithMicroseconds[i]);
412  } else {
413  mark(aBufferWithMicroseconds[i]);
414  }
415  }
416 }
417 /*
418  * Version with repeat
419  * @param aRepeatPeriodMillis - Time between start of two frames. Thus independent from frame length.
420  */
421 void IRsend::sendRaw(const uint16_t aBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz,
422  uint_fast16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
423 
424  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
425  while (tNumberOfCommands > 0) {
426  unsigned long tStartOfFrameMillis = millis();
427  sendRaw(aBufferWithMicroseconds, aLengthOfBuffer, aIRFrequencyKilohertz);
428 
429  tNumberOfCommands--;
430 
431  // skip last delay!
432  if (tNumberOfCommands > 0) {
433  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
434  /*
435  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
436  */
437  if (aRepeatPeriodMillis > tCurrentFrameDurationMillis) {
438  delay(aRepeatPeriodMillis - tCurrentFrameDurationMillis);
439  }
440  }
441  }
442 }
443 
448 void IRsend::sendRaw(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
449 // Set IR carrier frequency
450  enableIROut(aIRFrequencyKilohertz);
451 
452  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
453  if (i & 1) {
454  // Odd
455  space(aBufferWithTicks[i] * MICROS_PER_TICK);
456  } else {
457  mark(aBufferWithTicks[i] * MICROS_PER_TICK);
458  }
459  }
460 }
461 void IRsend::sendRaw(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz,
462  uint_fast16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
463 
464  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
465  while (tNumberOfCommands > 0) {
466  unsigned long tStartOfFrameMillis = millis();
467  sendRaw(aBufferWithTicks, aLengthOfBuffer, aIRFrequencyKilohertz);
468 
469  tNumberOfCommands--;
470 
471  // skip last delay!
472  if (tNumberOfCommands > 0) {
473  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
474  /*
475  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
476  */
477  if (aRepeatPeriodMillis > tCurrentFrameDurationMillis) {
478  delay(aRepeatPeriodMillis - tCurrentFrameDurationMillis);
479  }
480  }
481  }
482 }
483 
488 void IRsend::sendRaw_P(const uint16_t aPGMBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer,
489  uint_fast8_t aIRFrequencyKilohertz) {
490 #if !defined(__AVR__)
491  sendRaw(aPGMBufferWithMicroseconds, aLengthOfBuffer, aIRFrequencyKilohertz); // Let the function work for non AVR platforms
492 #else
493 // Set IR carrier frequency
494  enableIROut(aIRFrequencyKilohertz);
495  /*
496  * Raw data starts with a mark
497  */
498 # if defined(LOCAL_DEBUG)
499  // If the PROGMEM array is defined in the function, the C-compiler uses a wrong address :-(. sizeof() works.
500  Serial.print(F("aPGMBufferWithMicroseconds=0x"));
501  Serial.println((uint16_t)aPGMBufferWithMicroseconds,HEX);
502 #endif
503 
504  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
505  uint16_t duration = pgm_read_word(&aPGMBufferWithMicroseconds[i]);
506 // uint16_t duration = pgm_read_word(aPGMBufferWithMicroseconds); // is equivalent for the compiler
507  if (i & 1) {
508  // Odd
509  space(duration);
510 # if defined(LOCAL_DEBUG)
511  Serial.print(F("S="));
512 # endif
513  } else {
514  mark(duration);
515 # if defined(LOCAL_DEBUG)
516  Serial.print(F("M="));
517 # endif
518  }
519 # if defined(LOCAL_DEBUG)
520  Serial.println(duration);
521 # endif
522  }
523 #endif
524 }
525 
526 void IRsend::sendRaw_P(const uint16_t aPGMBufferWithMicroseconds[], uint_fast16_t aLengthOfBuffer,
527  uint_fast8_t aIRFrequencyKilohertz, uint_fast16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
528 
529  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
530  while (tNumberOfCommands > 0) {
531  unsigned long tStartOfFrameMillis = millis();
532  sendRaw_P(aPGMBufferWithMicroseconds, aLengthOfBuffer, aIRFrequencyKilohertz);
533 
534  tNumberOfCommands--;
535 
536  // skip last delay!
537  if (tNumberOfCommands > 0) {
538  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
539  /*
540  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
541  */
542  if (aRepeatPeriodMillis > tCurrentFrameDurationMillis) {
543  delay(aRepeatPeriodMillis - tCurrentFrameDurationMillis);
544  }
545  }
546  }
547 }
548 
553 void IRsend::sendRaw_P(const uint8_t aPGMBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz) {
554 #if !defined(__AVR__)
555  sendRaw(aPGMBufferWithTicks, aLengthOfBuffer, aIRFrequencyKilohertz); // Let the function work for non AVR platforms
556 #else
557 // Set IR carrier frequency
558  enableIROut(aIRFrequencyKilohertz);
559 
560  for (uint_fast16_t i = 0; i < aLengthOfBuffer; i++) {
561  uint16_t duration = pgm_read_byte(&aPGMBufferWithTicks[i]) * (uint_fast16_t) MICROS_PER_TICK;
562  if (i & 1) {
563  // Odd
564  space(duration);
565 # if defined(LOCAL_DEBUG)
566  Serial.print(F("S="));
567 # endif
568  } else {
569  mark(duration);
570 # if defined(LOCAL_DEBUG)
571  Serial.print(F("M="));
572 # endif
573  }
574 # if defined(LOCAL_DEBUG)
575  Serial.println(duration);
576 # endif
577  }
578 #endif
579 }
580 void IRsend::sendRaw_P(const uint8_t aPGMBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz,
581  uint_fast16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
582 
583  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
584  while (tNumberOfCommands > 0) {
585  unsigned long tStartOfFrameMillis = millis();
586  sendRaw_P(aPGMBufferWithTicks, aLengthOfBuffer, aIRFrequencyKilohertz);
587 
588  tNumberOfCommands--;
589 
590  // skip last delay!
591  if (tNumberOfCommands > 0) {
592  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
593  /*
594  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
595  */
596  if (aRepeatPeriodMillis > tCurrentFrameDurationMillis) {
597  delay(aRepeatPeriodMillis - tCurrentFrameDurationMillis);
598  }
599  }
600  }
601 }
602 
603 /**********************************************************************************************************************
604  * Core send function
605  **********************************************************************************************************************/
614 void IRsend::sendPulseDistanceWidthData(uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros,
615  uint16_t aZeroSpaceMicros, IRRawDataType aData, uint_fast8_t aNumberOfBits, uint8_t aFlags) {
616 
617 #if defined(LOCAL_DEBUG)
618  Serial.print(aData, HEX);
619  Serial.print('|');
620  Serial.println(aNumberOfBits);
621  Serial.flush();
622 #endif
623 
624  // For MSBFirst, send data from MSB to LSB until mask bit is shifted out
625  IRRawDataType tMask = 1ULL << (aNumberOfBits - 1);
626  for (uint_fast8_t i = aNumberOfBits; i > 0; i--) {
627  if (((aFlags & PROTOCOL_IS_MSB_MASK) && (aData & tMask)) || (!(aFlags & PROTOCOL_IS_MSB_MASK) && (aData & 1))) {
628 #if defined(LOCAL_TRACE)
629  Serial.print('1');
630 #endif
631  mark(aOneMarkMicros);
632  space(aOneSpaceMicros);
633  } else {
634 #if defined(LOCAL_TRACE)
635  Serial.print('0');
636 #endif
637  mark(aZeroMarkMicros);
638  space(aZeroSpaceMicros);
639  }
640  if (aFlags & PROTOCOL_IS_MSB_MASK) {
641  tMask >>= 1;
642  } else {
643  aData >>= 1;
644  }
645  }
646  /*
647  * Stop bit is sent for all pulse distance protocols i.e. aOneSpaceMicros != aZeroSpaceMicros.
648  * Therefore it is not sent for Sony :-)
649  * For sending from an array, no intermediate stop bit must be sent for all but last data chunk.
650  */
651  if ((!(aFlags & SUPPRESS_STOP_BIT)) && (abs(aOneSpaceMicros - aZeroSpaceMicros) > (aOneSpaceMicros / 4))) {
652  // Send stop bit here
653 #if defined(LOCAL_TRACE)
654  Serial.print('S');
655 #endif
656  mark(aOneMarkMicros); // Use aOneMarkMicros for stop bits. This seems to be correct for all protocols :-)
657  }
658 #if defined(LOCAL_TRACE)
659  Serial.println();
660 #endif
661 }
662 
663 /**********************************************************************************************************************
664  * Stubs for core send function with PulseDistanceWidthProtocolConstants parameter
665  **********************************************************************************************************************/
666 
676  uint_fast8_t aNumberOfBits) {
677 
679  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
680  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, aData, aNumberOfBits, aProtocolConstants->Flags);
681 }
682 
684  uint_fast8_t aNumberOfBits) {
685 
686  PulseDistanceWidthProtocolConstants tTemporaryPulseDistanceWidthProtocolConstants;
687  memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
688  sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
689  sendPulseDistanceWidthData(&tTemporaryPulseDistanceWidthProtocolConstants, aData, aNumberOfBits);
690 }
691 
692 /**********************************************************************************************************************
693  * Send functions with detailed parameters
694  **********************************************************************************************************************/
695 
706 void IRsend::sendPulseDistanceWidth(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
707  uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, IRRawDataType aData,
708  uint_fast8_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats,
709  void (*aSpecialSendRepeatFunction)()) {
710 
711  if (aNumberOfRepeats < 0) {
712  if (aSpecialSendRepeatFunction != nullptr) {
713  aSpecialSendRepeatFunction();
714  return;
715  } else {
716  aNumberOfRepeats = 0; // send a plain frame as repeat
717  }
718  }
719 
720  // Set IR carrier frequency
721  enableIROut(aFrequencyKHz);
722 
723  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
724  while (tNumberOfCommands > 0) {
725  unsigned long tStartOfFrameMillis = millis();
726 
727  if (tNumberOfCommands < ((uint_fast8_t) aNumberOfRepeats + 1) && aSpecialSendRepeatFunction != nullptr) {
728  // send special repeat
729  aSpecialSendRepeatFunction();
730  } else {
731  // Header and regular frame
732  mark(aHeaderMarkMicros);
733  space(aHeaderSpaceMicros);
734  sendPulseDistanceWidthData(aOneMarkMicros, aOneSpaceMicros, aZeroMarkMicros, aZeroSpaceMicros, aData, aNumberOfBits,
735  aFlags);
736  }
737 
738  tNumberOfCommands--;
739  // skip last delay!
740  if (tNumberOfCommands > 0) {
741  /*
742  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
743  */
744  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
745  if (aRepeatPeriodMillis > tFrameDurationMillis) {
746  delay(aRepeatPeriodMillis - tFrameDurationMillis);
747  }
748  }
749  }
750 }
751 
752 void IRsend::sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
753  uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
754  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
755  int_fast8_t aNumberOfRepeats) {
756 
757  // Set IR carrier frequency
758  enableIROut(aFrequencyKHz);
759 
760  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
761  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
762 
763 #if defined(LOCAL_DEBUG)
764  // fist data
765  Serial.print(F("Data[0]=0x"));
766  Serial.print(aDecodedRawDataArray[0], HEX);
767  if (tNumberOf32Or64BitChunks > 1) {
768  Serial.print(F(" Data[1]=0x"));
769  Serial.print(aDecodedRawDataArray[1], HEX);
770  }
771  Serial.print(F(" #="));
772  Serial.println(aNumberOfBits);
773  Serial.flush();
774 #endif
775 
776  while (tNumberOfCommands > 0) {
777  unsigned long tStartOfFrameMillis = millis();
778 
779  // Header
780  mark(aHeaderMarkMicros);
781  space(aHeaderSpaceMicros);
782 
783  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
784  uint8_t tNumberOfBitsForOneSend;
785 
786  // Manage stop bit
787  uint8_t tFlags;
788  if (i == (tNumberOf32Or64BitChunks - 1)) {
789  // End of data
790  tNumberOfBitsForOneSend = aNumberOfBits;
791  tFlags = aFlags;
792  } else {
793  // intermediate data
794  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
795  tFlags = aFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
796  }
797 
798  sendPulseDistanceWidthData(aOneMarkMicros, aOneSpaceMicros, aZeroMarkMicros, aZeroSpaceMicros, aDecodedRawDataArray[i],
799  tNumberOfBitsForOneSend, tFlags);
800  aNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
801  }
802 
803  tNumberOfCommands--;
804  // skip last delay!
805  if (tNumberOfCommands > 0) {
806  /*
807  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
808  */
809  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
810  if (aRepeatPeriodMillis > tFrameDurationMillis) {
811  delay(aRepeatPeriodMillis - tFrameDurationMillis);
812  }
813  }
814  }
815 }
816 
817 void IRsend::sendPulseDistanceWidthFromPGMArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
818  uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
819  IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
820  int_fast8_t aNumberOfRepeats) {
821 
822  // Set IR carrier frequency
823  enableIROut(aFrequencyKHz);
824 
825  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
826  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
827 
828 #if defined(LOCAL_DEBUG)
829  // fist data
830  Serial.print(F("Data[0]=0x"));
831  Serial.print(aDecodedRawDataPGMArray[0], HEX);
832  if (tNumberOf32Or64BitChunks > 1) {
833  Serial.print(F(" Data[1]=0x"));
834  Serial.print(aDecodedRawDataPGMArray[1], HEX);
835  }
836  Serial.print(F(" #="));
837  Serial.println(aNumberOfBits);
838  Serial.flush();
839 #endif
840 
841  while (tNumberOfCommands > 0) {
842  unsigned long tStartOfFrameMillis = millis();
843 
844  // Header
845  mark(aHeaderMarkMicros);
846  space(aHeaderSpaceMicros);
847 
848  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
849  uint8_t tNumberOfBitsForOneSend;
850 
851  // Manage stop bit
852  uint8_t tFlags;
853  if (i == (tNumberOf32Or64BitChunks - 1)) {
854  // End of data
855  tNumberOfBitsForOneSend = aNumberOfBits;
856  tFlags = aFlags;
857  } else {
858  // intermediate data
859  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
860  tFlags = aFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
861  }
862 
863  IRRawDataType tDecodedRawData;
864 #if (__INT_WIDTH__ < 32)
865  tDecodedRawData = pgm_read_dword(&aDecodedRawDataPGMArray[i]); // pgm_read_dword reads 32 bit on AVR
866 #else
867  tDecodedRawData = aDecodedRawDataPGMArray[i]; // assume non Harvard architecture here
868 #endif
869  sendPulseDistanceWidthData(aOneMarkMicros, aOneSpaceMicros, aZeroMarkMicros, aZeroSpaceMicros, tDecodedRawData,
870  tNumberOfBitsForOneSend, tFlags);
871  aNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
872  }
873 
874  tNumberOfCommands--;
875  // skip last delay!
876  if (tNumberOfCommands > 0) {
877  /*
878  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
879  */
880  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
881  if (aRepeatPeriodMillis > tFrameDurationMillis) {
882  delay(aRepeatPeriodMillis - tFrameDurationMillis);
883  }
884  }
885  }
886 }
887 
888 /**********************************************************************************************************************
889  * Stubs for send functions
890  **********************************************************************************************************************/
891 
899 void IRsend::sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, DistanceWidthTimingInfoStruct *aDistanceWidthTimingInfo,
900  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis,
901  int_fast8_t aNumberOfRepeats) {
902  sendPulseDistanceWidthFromArray(aFrequencyKHz, aDistanceWidthTimingInfo->HeaderMarkMicros,
903  aDistanceWidthTimingInfo->HeaderSpaceMicros, aDistanceWidthTimingInfo->OneMarkMicros,
904  aDistanceWidthTimingInfo->OneSpaceMicros, aDistanceWidthTimingInfo->ZeroMarkMicros,
905  aDistanceWidthTimingInfo->ZeroSpaceMicros, aDecodedRawDataArray, aNumberOfBits, aFlags, aRepeatPeriodMillis,
907 }
908 
909 void IRsend::sendPulseDistanceWidthFromArray_P(uint_fast8_t aFrequencyKHz,
910  DistanceWidthTimingInfoStruct const *aDistanceWidthTimingInfoPGM, IRRawDataType *aDecodedRawDataArray,
911  uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats) {
912 
913  DistanceWidthTimingInfoStruct tTemporaryDistanceWidthTimingInfo;
914  memcpy_P(&tTemporaryDistanceWidthTimingInfo, aDistanceWidthTimingInfoPGM, sizeof(tTemporaryDistanceWidthTimingInfo));
915  sendPulseDistanceWidthFromArray(aFrequencyKHz, &tTemporaryDistanceWidthTimingInfo, aDecodedRawDataArray, aNumberOfBits, aFlags,
916  aRepeatPeriodMillis, aNumberOfRepeats);
917 }
918 
919 /**********************************************************************************************************************
920  * Send functions with PulseDistanceWidthProtocolConstants parameter
921  **********************************************************************************************************************/
931  uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
932 
933 #if defined(LOCAL_DEBUG)
934  Serial.print(F("Data=0x"));
935  Serial.print(aData, HEX);
936  Serial.print(F(" #="));
937  Serial.println(aNumberOfBits);
938  Serial.flush();
939 #endif
940 
941  if (aNumberOfRepeats < 0) {
942  if (aProtocolConstants->SpecialSendRepeatFunction != nullptr) {
943  /*
944  * Send only a special repeat and return
945  */
946  aProtocolConstants->SpecialSendRepeatFunction();
947  return;
948  } else {
949  // Send only one plain frame (as repeat)
950  aNumberOfRepeats = 0;
951  }
952  }
953 
954  // Set IR carrier frequency
955  enableIROut(aProtocolConstants->FrequencyKHz);
956 
957  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
958  while (tNumberOfCommands > 0) {
959  unsigned long tStartOfFrameMillis = millis();
960 
961  if (tNumberOfCommands < ((uint_fast8_t) aNumberOfRepeats + 1) && aProtocolConstants->SpecialSendRepeatFunction != nullptr) {
962  // send special repeat, if specified and we are not in the first loop
963  aProtocolConstants->SpecialSendRepeatFunction();
964  } else {
965  /*
966  * Send Header and regular frame
967  */
968  mark(aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros);
969  space(aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros);
970  sendPulseDistanceWidthData(aProtocolConstants, aData, aNumberOfBits);
971  }
972 
973  tNumberOfCommands--;
974 
975  // skip last delay!
976  if (tNumberOfCommands > 0) {
977  auto tCurrentFrameDurationMillis = millis() - tStartOfFrameMillis;
978  /*
979  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
980  */
981  if (aProtocolConstants->RepeatPeriodMillis > tCurrentFrameDurationMillis) {
982  delay(aProtocolConstants->RepeatPeriodMillis - tCurrentFrameDurationMillis);
983  }
984  }
985  }
986 }
987 
998  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
999 
1000 // Calling sendPulseDistanceWidthFromArray() costs 68 bytes program memory compared to the implementation below
1001 // sendPulseDistanceWidthFromArray(aProtocolConstants->FrequencyKHz, aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros,
1002 // aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros,
1003 // aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
1004 // aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros,
1005 // aDecodedRawDataArray, aNumberOfBits, aProtocolConstants->Flags, aProtocolConstants->RepeatPeriodMillis,
1006 // aNumberOfRepeats);
1007  // Set IR carrier frequency
1008  enableIROut(aProtocolConstants->FrequencyKHz);
1009 
1010  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
1011 
1012 #if defined(LOCAL_DEBUG)
1013  // fist data
1014  Serial.print(F("Data[0]=0x"));
1015  Serial.print(aDecodedRawDataArray[0], HEX);
1016  if (tNumberOf32Or64BitChunks > 1) {
1017  Serial.print(F(" Data[1]=0x"));
1018  Serial.print(aDecodedRawDataArray[1], HEX);
1019  }
1020  Serial.print(F(" #="));
1021  Serial.println(aNumberOfBits);
1022  Serial.flush();
1023 #endif
1024 
1025  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
1026  while (tNumberOfCommands > 0) {
1027  auto tStartOfFrameMillis = millis();
1028  auto tNumberOfBits = aNumberOfBits; // refresh value for repeats
1029 
1030  // Header
1031  mark(aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros);
1032  space(aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros);
1033  uint8_t tOriginalFlags = aProtocolConstants->Flags;
1034 
1035  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
1036  uint8_t tNumberOfBitsForOneSend;
1037 
1038  uint8_t tFlags;
1039  if (i == (tNumberOf32Or64BitChunks - 1)) {
1040  // End of data
1041  tNumberOfBitsForOneSend = tNumberOfBits;
1042  tFlags = tOriginalFlags;
1043  } else {
1044  // intermediate data
1045  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
1046  tFlags = tOriginalFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
1047  }
1048 
1050  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
1051  aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
1052  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, aDecodedRawDataArray[i], tNumberOfBitsForOneSend,
1053  tFlags);
1054  tNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
1055  }
1056 
1057  tNumberOfCommands--;
1058  // skip last delay!
1059  if (tNumberOfCommands > 0) {
1060  /*
1061  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
1062  */
1063  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
1064  if (aProtocolConstants->RepeatPeriodMillis > tFrameDurationMillis) {
1065  delay(aProtocolConstants->RepeatPeriodMillis - tFrameDurationMillis);
1066  }
1067  }
1068  }
1069 }
1070 
1072  IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1073 
1074 // Calling sendPulseDistanceWidthFromArray() costs 68 bytes program memory compared to the implementation below
1075 // sendPulseDistanceWidthFromArray(aProtocolConstants->FrequencyKHz, aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros,
1076 // aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros,
1077 // aProtocolConstants->DistanceWidthTimingInfo.OneMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
1078 // aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros, aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros,
1079 // aDecodedRawDataArray, aNumberOfBits, aProtocolConstants->Flags, aProtocolConstants->RepeatPeriodMillis,
1080 // aNumberOfRepeats);
1081  // Set IR carrier frequency
1082  enableIROut(aProtocolConstants->FrequencyKHz);
1083 
1084  uint_fast8_t tNumberOf32Or64BitChunks = ((aNumberOfBits - 1) / BITS_IN_RAW_DATA_TYPE) + 1;
1085 
1086 #if defined(LOCAL_DEBUG)
1087  // fist data
1088  Serial.print(F("Data[0]=0x"));
1089  Serial.print(aDecodedRawDataPGMArray[0], HEX);
1090  if (tNumberOf32Or64BitChunks > 1) {
1091  Serial.print(F(" Data[1]=0x"));
1092  Serial.print(aDecodedRawDataPGMArray[1], HEX);
1093  }
1094  Serial.print(F(" #="));
1095  Serial.println(aNumberOfBits);
1096  Serial.flush();
1097 #endif
1098 
1099  uint_fast8_t tNumberOfCommands = aNumberOfRepeats + 1;
1100  while (tNumberOfCommands > 0) {
1101  auto tStartOfFrameMillis = millis();
1102  auto tNumberOfBits = aNumberOfBits; // refresh value for repeats
1103 
1104  // Header
1105  mark(aProtocolConstants->DistanceWidthTimingInfo.HeaderMarkMicros);
1106  space(aProtocolConstants->DistanceWidthTimingInfo.HeaderSpaceMicros);
1107  uint8_t tOriginalFlags = aProtocolConstants->Flags;
1108 
1109  for (uint_fast8_t i = 0; i < tNumberOf32Or64BitChunks; ++i) {
1110  uint8_t tNumberOfBitsForOneSend;
1111 
1112  uint8_t tFlags;
1113  if (i == (tNumberOf32Or64BitChunks - 1)) {
1114  // End of data
1115  tNumberOfBitsForOneSend = tNumberOfBits;
1116  tFlags = tOriginalFlags;
1117  } else {
1118  // intermediate data
1119  tNumberOfBitsForOneSend = BITS_IN_RAW_DATA_TYPE;
1120  tFlags = tOriginalFlags | SUPPRESS_STOP_BIT; // No stop bit for leading data
1121  }
1122 
1123  IRRawDataType tDecodedRawData;
1124 #if (__INT_WIDTH__ < 32)
1125  tDecodedRawData = pgm_read_dword(&aDecodedRawDataPGMArray[i]); // pgm_read_dword reads 32 bit on AVR
1126 #else
1127  tDecodedRawData = aDecodedRawDataPGMArray[i]; // assume non Harvard architecture here
1128 #endif
1130  aProtocolConstants->DistanceWidthTimingInfo.OneSpaceMicros,
1131  aProtocolConstants->DistanceWidthTimingInfo.ZeroMarkMicros,
1132  aProtocolConstants->DistanceWidthTimingInfo.ZeroSpaceMicros, tDecodedRawData, tNumberOfBitsForOneSend, tFlags);
1133  tNumberOfBits -= BITS_IN_RAW_DATA_TYPE;
1134  }
1135 
1136  tNumberOfCommands--;
1137  // skip last delay!
1138  if (tNumberOfCommands > 0) {
1139  /*
1140  * Check and fallback for wrong RepeatPeriodMillis parameter. I.e the repeat period must be greater than each frame duration.
1141  */
1142  auto tFrameDurationMillis = millis() - tStartOfFrameMillis;
1143  if (aProtocolConstants->RepeatPeriodMillis > tFrameDurationMillis) {
1144  delay(aProtocolConstants->RepeatPeriodMillis - tFrameDurationMillis);
1145  }
1146  }
1147  }
1148 }
1149 
1150 /**********************************************************************************************************************
1151  * Stubs for send functions with PulseDistanceWidthProtocolConstants parameter
1152  **********************************************************************************************************************/
1153 
1155  IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1156 
1157  PulseDistanceWidthProtocolConstants tTemporaryPulseDistanceWidthProtocolConstants;
1158  memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1159  sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1160  sendPulseDistanceWidthFromArray(&tTemporaryPulseDistanceWidthProtocolConstants, aDecodedRawDataArray, aNumberOfBits,
1162 }
1164  IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1165 
1166  PulseDistanceWidthProtocolConstants tTemporaryPulseDistanceWidthProtocolConstants;
1167  memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1168  sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1169  sendPulseDistanceWidthFromPGMArray(&tTemporaryPulseDistanceWidthProtocolConstants, aDecodedRawDataPGMArray, aNumberOfBits,
1171 }
1172 
1174  uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats) {
1175  PulseDistanceWidthProtocolConstants tTemporaryPulseDistanceWidthProtocolConstants;
1176  memcpy_P(&tTemporaryPulseDistanceWidthProtocolConstants, aProtocolConstantsPGM,
1177  sizeof(tTemporaryPulseDistanceWidthProtocolConstants));
1178  sendPulseDistanceWidth(&tTemporaryPulseDistanceWidthProtocolConstants, aData, aNumberOfBits, aNumberOfRepeats);
1179 }
1180 
1193 void IRsend::sendBiphaseData(uint16_t aBiphaseTimeUnit, uint32_t aData, uint_fast8_t aNumberOfBits, bool aSendStartBit) {
1194 
1195  IR_TRACE_PRINT(F("0x"));
1196  IR_TRACE_PRINT(aData, HEX);
1197 
1198 #if defined(LOCAL_TRACE)
1199  Serial.print('S');
1200 #endif
1201 
1202 // Data - Biphase code MSB first
1203 // prepare for start with sending the start bit, which is 1
1204  uint32_t tMask;
1205  uint_fast8_t tLastBitValue;
1206  bool tNextBitIsOne;
1207  uint8_t tBitsToSend; // total number of bits to send including start bit if specified
1208 
1209  // Data - Biphase code MSB first
1210  tMask = 1UL << aNumberOfBits; // mask is now set for the virtual start bit
1211  if (aSendStartBit) {
1212  tBitsToSend = aNumberOfBits + 1; // +1 for additional start bit
1213  // prepare for start with sending the start bit, which is 1
1214  tNextBitIsOne = 1; // Start bit is a 1, value is copied to tCurrentBitIsOne
1215  tLastBitValue = 0; // Force to send the mark if tNextBitIsOne is 0 (which it is not here). Does not increase code size :-).
1216  } else {
1217  // prepare to send only the data which may start with a 0 or 1 (e.g. after a defined pause or header when no additional start bit is needed)
1218  tMask = 1UL >> 1; // mask is now set for the MSB of data
1219  tBitsToSend = aNumberOfBits;
1220  tNextBitIsOne = ((aData & tMask) != 0) ? 1 : 0; // Value is copied to tCurrentBitIsOne
1221  tLastBitValue = 0; // Force to send the mark if tNextBitIsOne is 0
1222  }
1223 
1224  // now send all bits
1225  for (uint_fast8_t i = tBitsToSend; i > 0; i--) {
1226  bool tCurrentBitIsOne = tNextBitIsOne;
1227  tMask >>= 1;
1228  tNextBitIsOne = ((aData & tMask) != 0) || (i == 1); // true for last bit to avoid extension of mark
1229  if (tCurrentBitIsOne) {
1230 #if defined(LOCAL_TRACE)
1231  Serial.print('1');
1232 #endif
1233  space(aBiphaseTimeUnit);
1234  if (tNextBitIsOne) {
1235  mark(aBiphaseTimeUnit); // if next bit is 1 send a single mark
1236  } else {
1237  // if next bit is 0, extend the current mark in order to generate a continuous signal without short breaks
1238  mark(2 * aBiphaseTimeUnit);
1239  }
1240  tLastBitValue = 1;
1241 
1242  } else {
1243 #if defined(LOCAL_TRACE)
1244  Serial.print('0');
1245 #endif
1246  if (tLastBitValue == 0) {
1247  mark(aBiphaseTimeUnit); // if next bit is 1 send a single mark
1248  }
1249  space(aBiphaseTimeUnit);
1250  tLastBitValue = 0;
1251  }
1252  }
1253  IR_TRACE_PRINTLN();
1254 }
1255 
1271 void IRsend::mark(uint16_t aMarkMicros) {
1272 
1273 #if defined(SEND_PWM_BY_TIMER) || defined(USE_NO_SEND_PWM)
1274 # if defined(LED_SEND_FEEDBACK_CODE)
1275  setFeedbackLED(true);
1276 # endif
1277 #endif
1278 
1279 #if defined(SEND_PWM_BY_TIMER)
1280  /*
1281  * Generate hardware PWM signal
1282  */
1283  enableSendPWMByTimer(); // Enable timer or ledcWrite() generated PWM output
1284  customDelayMicroseconds(aMarkMicros);
1285  IRLedOff(); // disables hardware PWM and manages feedback LED
1286  return;
1287 
1288 #elif defined(USE_NO_SEND_PWM)
1289  /*
1290  * Here we generate no carrier PWM, just simulate an active low receiver signal.
1291  */
1292 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1293  // Here we have no hardware supported Open Drain outputs, so we must mimicking it
1294  pinModeFast(sendPin, OUTPUT); // active state for mimicking open drain
1295 # 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
1296  digitalWriteFast(sendPin, HIGH); // Set output to active high.
1297 # else
1298  digitalWriteFast(sendPin, LOW); // Set output to active low.
1299 # endif
1300 
1301  customDelayMicroseconds(aMarkMicros);
1302  IRLedOff();
1303 # if defined(LED_SEND_FEEDBACK_CODE)
1304  setFeedbackLED(false);
1305  return;
1306 # endif
1307 
1308 #else // defined(SEND_PWM_BY_TIMER)
1309 
1310  unsigned long tMicrosOfEndOfNextPWMPause = micros();
1311 # if defined(LED_SEND_FEEDBACK_CODE)
1312  unsigned long tStartMicros = tMicrosOfEndOfNextPWMPause + (136 / CLOCKS_PER_MICRO); // To compensate for call duration and activating of LED
1313  bool tFeedbackLedIsActive = false;
1314 #else
1315  unsigned long tStartMicros = tMicrosOfEndOfNextPWMPause + (112 / CLOCKS_PER_MICRO); // To compensate for call duration - 112 is an empirical value
1316 #endif
1317 
1318  /***************************************************************************************************
1319  * Generate the IR PWM with 30% duty cycle with a frequency of e.g. 38 kHz by software / bit banging
1320  **************************************************************************************************/
1321  do {
1322 // digitalToggleFast(_IR_TIMING_TEST_PIN);
1323  /*****************************************
1324  * Output the PWM pulse - IR LED is active
1325  ****************************************/
1326  noInterrupts(); // do not let interrupts extend the short on period
1327 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1328 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1329  if (__builtin_constant_p(sendPin)) {
1330  digitalWriteFast(sendPin, LOW); // set output to active low. Also applicable for pin with mode OUTPUT_OPEN_DRAIN :-)
1331  } else {
1332  digitalWrite(sendPin, LOW);
1333  }
1334 # else
1335  pinModeFast(sendPin, OUTPUT); // active state for mimicking open drain
1336 # endif
1337 # else
1338  // 3.5 us from FeedbackLed on to pin setting. 5.7 us from call of mark() to pin setting incl. setting of feedback pin.
1339  // 4.3 us from do{ to pin setting if sendPin is no constant
1340  // check must be here because of MegaTinyCore and its badArg() check
1341  if (__builtin_constant_p(sendPin)) {
1342  digitalWriteFast(sendPin, HIGH);
1343  } else {
1344  digitalWrite(sendPin, HIGH);
1345  }
1346 # endif
1347  /*
1348  * Timing for the on time of the e.g. 38 kHz signal.
1349  * On time is 8 us for 30% duty cycle. This is normally implemented by a blocking wait.
1350  */
1351  delayMicroseconds (periodOnTimeMicros);
1352 
1353  /*******************************************
1354  * Output the PWM pause - IR LED is inactive
1355  ******************************************/
1356 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1357 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1358  if (__builtin_constant_p(sendPin)) {
1359  digitalWriteFast(sendPin, HIGH); // Set output to inactive high. Also applicable for pin with mode OUTPUT_OPEN_DRAIN
1360  } else {
1361  digitalWrite(sendPin, HIGH);
1362  }
1363 # else
1364  pinModeFast(sendPin, INPUT); // to mimic the open drain inactive state
1365 # endif
1366 
1367 # else
1368  if (__builtin_constant_p(sendPin)) {
1369  digitalWriteFast(sendPin, LOW);
1370  } else {
1371  digitalWrite(sendPin, LOW);
1372  }
1373 # endif
1374  /*
1375  * Enable interrupts at start of the longer off period. Required at least to keep micros correct.
1376  * If receive interrupt is still active, it takes 3.4 us from now until receive ISR is active (for 7 us + pop's)
1377  */
1378  interrupts();
1379 
1380 # if defined(LED_SEND_FEEDBACK_CODE)
1381  /*
1382  * Delayed call of setFeedbackLED() to get better startup timing, especially required for consecutive marks
1383  */
1384  if (!tFeedbackLedIsActive) {
1385  tFeedbackLedIsActive = true; // do it only once
1386  setFeedbackLED(true);
1387  }
1388 # endif
1389  /********************************************************************************************************************************
1390  * Check for end of the PWM pause with micros() < tMicrosOfEndOfNextPWMPause.
1391  * This generates the timing for the transmit frequency e.g. 38 kHz
1392  * Measured delta between pause duration values are 8 us for a 16 MHz Uno (from 15 to 23), if interrupts are disabled below
1393  * Minimal pause duration is 5.2 us
1394  *******************************************************************************************************************************/
1395  tMicrosOfEndOfNextPWMPause += periodTimeMicros;
1396 #if defined(__AVR__) // micros() for STM sometimes give decreasing values if interrupts are disabled. See https://github.com/stm32duino/Arduino_Core_STM32/issues/1680
1397  noInterrupts(); // disable interrupts (especially the 20 us receive interrupts) only at start of the PWM pause. Otherwise it may extend the pause too much.
1398 #endif
1399  unsigned long tMicros;
1400  do {
1401 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1402  digitalWriteFast(_IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
1403 #endif
1404  /*
1405  * For AVR @16MHz we have only 4 us resolution.
1406  * The duration of the micros() call itself is 3 us.
1407  * It takes 0.9 us from signal going low to here.
1408  * The rest of the loop takes 1.2 us
1409  */
1410 #if defined(_IR_MEASURE_TIMING) && defined(_IR_TIMING_TEST_PIN)
1411  digitalWriteFast(_IR_TIMING_TEST_PIN, LOW); // 2 clock cycles
1412 #endif
1413 
1414  /*************************************************
1415  * Check for end of mark duration / PWM generation
1416  ************************************************/
1417  tMicros = micros();
1418  uint16_t tDeltaMicros = tMicros - tStartMicros;
1419  // reset feedback led in the last pause before end
1420 // tDeltaMicros += (160 / CLOCKS_PER_MICRO); // adding this once increases program size, so do it below !
1421  if (tDeltaMicros >= aMarkMicros) {
1422 #if defined(LED_SEND_FEEDBACK_CODE)
1423  setFeedbackLED(false);
1424 #endif
1425 #if defined(__AVR__)
1426  interrupts();
1427 #endif
1428  return;
1429  }
1430  } while (tMicros < tMicrosOfEndOfNextPWMPause); // = End of one PWM period
1431  } while (true);
1432 # endif
1433 }
1434 
1441 #if defined(SEND_PWM_BY_TIMER)
1442  disableSendPWMByTimer(); // Disable PWM output
1443 #elif defined(USE_NO_SEND_PWM)
1444 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && !defined(OUTPUT_OPEN_DRAIN)
1445  digitalWriteFast(sendPin, LOW); // prepare for all next active states.
1446  pinModeFast(sendPin, INPUT);// inactive state for open drain
1447 # 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
1448  digitalWriteFast(sendPin, LOW); // Set output to inactive low.
1449 # else
1450  digitalWriteFast(sendPin, HIGH); // Set output to inactive high.
1451 # endif
1452 #else
1453 # if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) || defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1454 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN) || defined(OUTPUT_OPEN_DRAIN)
1455  if (__builtin_constant_p(sendPin)) {
1456  digitalWriteFast(sendPin, HIGH); // set output to inactive high.
1457  } else {
1458  digitalWrite(sendPin, HIGH);
1459  }
1460 # else
1461  pinModeFast(sendPin, INPUT); // inactive state to mimic open drain
1462 # endif
1463 # else
1464  if (__builtin_constant_p(sendPin)) {
1465  digitalWriteFast(sendPin, LOW); // set output to active low.
1466  } else {
1467  digitalWrite(sendPin, LOW);
1468  }
1469 # endif
1470 #endif
1471 
1472 #if defined(LED_SEND_FEEDBACK_CODE)
1473  setFeedbackLED(false);
1474 #endif
1475 }
1476 
1482 void IRsend::space(uint16_t aSpaceMicros) {
1483  customDelayMicroseconds(aSpaceMicros);
1484 }
1485 
1490 void IRsend::customDelayMicroseconds(unsigned long aMicroseconds) {
1491 #if defined(ESP32) || defined(ESP8266)
1492  // from https://github.com/crankyoldgit/IRremoteESP8266/blob/00b27cc7ea2e7ac1e48e91740723c805a38728e0/src/IRsend.cpp#L123
1493  // Invoke a delay(), where possible, to avoid triggering the WDT.
1494  // see https://github.com/Arduino-IRremote/Arduino-IRremote/issues/1114 for the reason of checking for > 16383)
1495  // delayMicroseconds() is only accurate to 16383 us. Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
1496  if (aMicroseconds > 16383) {
1497  delay(aMicroseconds / 1000UL); // Delay for as many whole milliseconds as we can.
1498  // Delay the remaining sub-millisecond.
1499  delayMicroseconds(static_cast<uint16_t>(aMicroseconds % 1000UL));
1500  } else {
1501  delayMicroseconds(aMicroseconds);
1502  }
1503 #else
1504 
1505 # if defined(__AVR__)
1506  unsigned long start = micros() - (64 / clockCyclesPerMicrosecond()); // - (64 / clockCyclesPerMicrosecond()) for reduced resolution and additional overhead
1507 # else
1508  unsigned long start = micros();
1509 # endif
1510 // overflow invariant comparison :-)
1511  while (micros() - start < aMicroseconds) {
1512  }
1513 #endif
1514 }
1515 
1522 void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
1523 #if defined(SEND_PWM_BY_TIMER)
1524  timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
1525 
1526 #elif defined(USE_NO_SEND_PWM)
1527  (void) aFrequencyKHz;
1528 
1529 #else
1530  periodTimeMicros = (1000U + (aFrequencyKHz / 2)) / aFrequencyKHz; // rounded value -> 26 for 38.46 kHz, 27 for 37.04 kHz, 25 for 40 kHz.
1531 # if defined(IR_SEND_PIN)
1532  periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50) / 100U); // +50 for rounding -> 830/100 for 30% and 16 MHz
1533 # else
1534 // Heuristics! We require a nanosecond correction for "slow" digitalWrite() functions
1535  periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50 - (PULSE_CORRECTION_NANOS / 10)) / 100U); // +50 for rounding -> 530/100 for 30% and 16 MHz
1536 # endif
1537 #endif // defined(SEND_PWM_BY_TIMER)
1538 
1539 #if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && defined(OUTPUT_OPEN_DRAIN) // the mode INPUT for mimicking open drain is set at IRLedOff()
1540 # if defined(IR_SEND_PIN)
1541  pinModeFast(IR_SEND_PIN, OUTPUT_OPEN_DRAIN);
1542 # else
1543  pinModeFast(sendPin, OUTPUT_OPEN_DRAIN);
1544 # endif
1545 #else
1546 
1547 // For Non AVR platforms pin mode for SEND_PWM_BY_TIMER must be handled by the timerConfigForSend() function
1548 // 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);
1549 # if defined(__AVR__) || !defined(SEND_PWM_BY_TIMER)
1550 # if defined(IR_SEND_PIN)
1551  pinModeFast(IR_SEND_PIN, OUTPUT);
1552 # else
1553  if (__builtin_constant_p(sendPin)) {
1554  pinModeFast(sendPin, OUTPUT);
1555  } else {
1556  pinMode(sendPin, OUTPUT);
1557  }
1558 # endif
1559 # endif
1560 #endif // defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
1561 }
1562 
1563 #if defined(SEND_PWM_BY_TIMER)
1564 // Used for Bang&Olufsen
1565 void IRsend::enableHighFrequencyIROut(uint_fast16_t aFrequencyKHz) {
1566  timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
1567  // For Non AVR platforms pin mode for SEND_PWM_BY_TIMER must be handled by the timerConfigForSend() function
1568  // 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);
1569 # if defined(__AVR__)
1570 # if defined(IR_SEND_PIN)
1571  pinModeFast(IR_SEND_PIN, OUTPUT);
1572 # else
1573  pinModeFast(sendPin, OUTPUT);
1574 # endif
1575 # endif
1576 }
1577 #endif
1578 
1580  return PULSE_CORRECTION_NANOS;
1581 }
1582 
1584 #if defined(_IR_MEASURE_TIMING)
1585 #undef _IR_MEASURE_TIMING
1586 #endif
1587 #if defined(LOCAL_TRACE)
1588 #undef LOCAL_TRACE
1589 #endif
1590 #if defined(LOCAL_DEBUG)
1591 #undef LOCAL_DEBUG
1592 #endif
1593 #endif // _IR_SEND_HPP
IRData::address
uint16_t address
Decoded address, Distance protocol (tMarkTicksLong (if tMarkTicksLong == 0, then tMarkTicksShort) << ...
Definition: IRremoteInt.h:152
SUPPRESS_STOP_BIT
#define SUPPRESS_STOP_BIT
Definition: IRProtocol.h:177
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:207
BITS_IN_RAW_DATA_TYPE
#define BITS_IN_RAW_DATA_TYPE
Definition: IRremoteInt.h:106
ONKYO
@ ONKYO
Definition: IRProtocol.h:104
DistanceWidthTimingInfoStruct::HeaderMarkMicros
uint16_t HeaderMarkMicros
Definition: IRProtocol.h:135
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:212
IRsend::sendMagiQuest
void sendMagiQuest(uint32_t aWandId, uint16_t aMagnitude)
Definition: ir_MagiQuest.hpp:122
KASEIKYO_DENON
@ KASEIKYO_DENON
Definition: IRProtocol.h:107
setLEDFeedbackPin
void setLEDFeedbackPin(uint8_t aFeedbackLEDPin)
Definition: IRFeedbackLED.hpp:53
setFeedbackLED
void setFeedbackLED(bool aSwitchLedOn)
Flash LED while receiving or sending IR data.
Definition: IRFeedbackLED.hpp:82
JVC
@ JVC
Definition: IRProtocol.h:99
IRData::numberOfBits
uint16_t numberOfBits
Number of bits received for data (address + command + parity) - to determine protocol length if diffe...
Definition: IRremoteInt.h:161
IRsend::aNumberOfRepeats
void int_fast8_t aNumberOfRepeats
Definition: IRremoteInt.h:538
IRsend::sendPin
uint8_t sendPin
Definition: IRremoteInt.h:733
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:93
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:108
FAST
@ FAST
Definition: IRProtocol.h:125
IRsend::setSendPin
void setSendPin(uint_fast8_t aSendPin)
Definition: IRSend.hpp:111
pinModeFast
#define pinModeFast
Definition: digitalWriteFast.h:383
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:347
PULSE_CORRECTION_NANOS
#define PULSE_CORRECTION_NANOS
Define to disable carrier PWM generation in software and use (restricted) hardware PWM.
Definition: IRremote.hpp:191
IRsend::sendPulseDistanceWidth_P
void sendPulseDistanceWidth_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Definition: IRSend.hpp:1173
IRsend::mark
void mark(uint16_t aMarkMicros)
Sends an IR mark for the specified number of microseconds.
Definition: IRSend.hpp:1271
SONY
@ SONY
Definition: IRProtocol.h:118
KASEIKYO_JVC
@ KASEIKYO_JVC
Definition: IRProtocol.h:109
PulseDistanceWidthProtocolConstants::SpecialSendRepeatFunction
void(* SpecialSendRepeatFunction)()
Definition: IRProtocol.h:167
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:237
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:411
IRDATA_FLAGS_IS_REPEAT
#define IRDATA_FLAGS_IS_REPEAT
The gap between the preceding frame is as smaller than the maximum gap expected for a repeat....
Definition: IRProtocol.h:147
decode_type_t
decode_type_t
An enum consisting of all supported formats.
Definition: IRProtocol.h:93
IRsend::sendPulseDistanceWidthFromPGMArray
void sendPulseDistanceWidthFromPGMArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros, uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros, IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, uint8_t aFlags, uint16_t aRepeatPeriodMillis, int_fast8_t aNumberOfRepeats)
Definition: IRSend.hpp:817
IRsend::sendRaw_P
void sendRaw_P(const uint8_t aPGMBufferWithTicks[], 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:553
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:1490
IRsend::sendPulseDistanceWidth
void sendPulseDistanceWidth(PulseDistanceWidthProtocolConstants *aProtocolConstants, IRRawDataType aData, uint_fast8_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Sends PulseDistance frames and repeats.
Definition: IRSend.hpp:930
IRsend::IRsend
IRsend()
Definition: IRSend.hpp:71
SAMSUNG
@ SAMSUNG
Definition: IRProtocol.h:114
BOSEWAVE
@ BOSEWAVE
Definition: IRProtocol.h:121
DistanceWidthTimingInfoStruct::OneSpaceMicros
uint16_t OneSpaceMicros
Definition: IRProtocol.h:138
IRData::decodedRawData
IRRawDataType decodedRawData
Up to 32/64 bit decoded raw data, to be used for send<protocol>Raw functions.
Definition: IRremoteInt.h:155
IRsend
Main class for sending IR signals.
Definition: IRremoteInt.h:516
DistanceWidthTimingInfoStruct::ZeroMarkMicros
uint16_t ZeroMarkMicros
Definition: IRProtocol.h:139
IR_TRACE_PRINT
#define IR_TRACE_PRINT(...)
Definition: IRremoteInt.h:197
MAGIQUEST
@ MAGIQUEST
Definition: IRProtocol.h:123
NEC2
@ NEC2
Definition: IRProtocol.h:103
PulseDistanceWidthProtocolConstants::Flags
uint8_t Flags
Definition: IRProtocol.h:165
IRsend::sendDenon
void sendDenon(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint8_t aSendSharpFrameMarker=0)
Definition: ir_Denon.hpp:131
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:175
DistanceWidthTimingInfoStruct
Definition: IRProtocol.h:134
IRsend::sendRaw
void sendRaw(const uint8_t aBufferWithTicks[], uint_fast16_t aLengthOfBuffer, uint_fast8_t aIRFrequencyKilohertz)
Sends an 8 byte tick timing array to save program memory.
Definition: IRSend.hpp:448
PulseDistanceWidthProtocolConstants
Definition: IRProtocol.h:161
IRsend::sendPulseDistanceWidthData_P
void sendPulseDistanceWidthData_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, IRRawDataType aData, uint_fast8_t aNumberOfBits)
Definition: IRSend.hpp:683
PANASONIC
@ PANASONIC
Definition: IRProtocol.h:105
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:136
IRData
Data structure for the user application, available as decodedIRData.
Definition: IRremoteInt.h:150
IR_SEND_PIN
#define IR_SEND_PIN
Definition: TinyIRSender.hpp:67
IRData::flags
uint8_t flags
IRDATA_FLAGS_IS_REPEAT, IRDATA_FLAGS_WAS_OVERFLOW etc. See IRDATA_FLAGS_* definitions above.
Definition: IRremoteInt.h:162
IRsend::sendSamsungLG
void sendSamsungLG(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Samsung.hpp:149
DistanceWidthTimingInfoStruct::OneMarkMicros
uint16_t OneMarkMicros
Definition: IRProtocol.h:137
IRsend::sendSharp
void sendSharp(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats)
Definition: ir_Denon.hpp:116
IRsend::sendPulseDistanceWidthFromPGMArray_P
void sendPulseDistanceWidthFromPGMArray_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, IRRawDataType const *aDecodedRawDataPGMArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Definition: IRSend.hpp:1163
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:107
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:182
IRsend::periodOnTimeMicros
uint16_t periodOnTimeMicros
Definition: IRremoteInt.h:736
IRData::command
uint16_t command
Decoded command, Distance protocol (tMarkTicksShort << 8) | tSpaceTicksShort.
Definition: IRremoteInt.h:153
IRsend::sendFAST
void sendFAST(uint8_t aCommand, int_fast8_t aNumberOfRepeats)
The FAST protocol repeats by skipping the header mark and space -> this leads to a poor repeat detect...
Definition: ir_FAST.hpp:77
NEC
@ NEC
Definition: IRProtocol.h:102
IRsend::sendBiphaseData
void sendBiphaseData(uint16_t aBiphaseTimeUnit, uint32_t aData, uint_fast8_t aNumberOfBits, bool aSendStartBit=true)
Sends Biphase (Manchester) coded data MSB first This function concatenates two marks to one longer ma...
Definition: IRSend.hpp:1193
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:97
IRsend::getPulseCorrectionNanos
uint16_t getPulseCorrectionNanos()
Definition: IRSend.hpp:1579
LEGO_PF
@ LEGO_PF
Definition: IRProtocol.h:122
DistanceWidthTimingInfoStruct::ZeroSpaceMicros
uint16_t ZeroSpaceMicros
Definition: IRProtocol.h:140
IRRawDataType
uint32_t IRRawDataType
Definition: IRremoteInt.h:105
IR_TRACE_PRINTLN
#define IR_TRACE_PRINTLN(...)
Definition: IRremoteInt.h:198
KASEIKYO_MITSUBISHI
@ KASEIKYO_MITSUBISHI
Definition: IRProtocol.h:110
IRsend::sendPulseDistanceWidthFromArray_P
void sendPulseDistanceWidthFromArray_P(PulseDistanceWidthProtocolConstants const *aProtocolConstantsPGM, IRRawDataType *aDecodedRawDataArray, uint16_t aNumberOfBits, int_fast8_t aNumberOfRepeats)
Definition: IRSend.hpp:1154
DENON
@ DENON
Definition: IRProtocol.h:98
enableSendPWMByTimer
void enableSendPWMByTimer()
Enables output of the PWM signal of the timer at the timer pin.
Definition: IRTimer.hpp:142
IrSender
IRsend IrSender
Definition: IRSend.hpp:69
IR_SEND_DUTY_CYCLE_PERCENT
#define IR_SEND_DUTY_CYCLE_PERCENT
Duty cycle in percent for sent signals.
Definition: IRremote.hpp:199
SIRCS_12_PROTOCOL
#define SIRCS_12_PROTOCOL
Definition: IRProtocol.h:130
RC5
@ RC5
Definition: IRProtocol.h:111
PulseDistanceWidthProtocolConstants::DistanceWidthTimingInfo
DistanceWidthTimingInfoStruct DistanceWidthTimingInfo
Definition: IRProtocol.h:164
IRsend::periodTimeMicros
uint16_t periodTimeMicros
Definition: IRremoteInt.h:735
IRsend::space
static void space(uint16_t aSpaceMicros)
Sends an IR space for the specified number of microseconds.
Definition: IRSend.hpp:1482
IRsend::sendRC5
void sendRC5(uint8_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, bool aEnableAutomaticToggle=true)
Definition: ir_RC5_RC6.hpp:161
disableSendPWMByTimer
void disableSendPWMByTimer()
Disables output of the PWM signal of the timer at the timer pin and set it to inactive.
Definition: IRTimer.hpp:147
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:200
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
PROTOCOL_IS_MSB_MASK
#define PROTOCOL_IS_MSB_MASK
Definition: IRProtocol.h:180
RC6
@ RC6
Definition: IRProtocol.h:112
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:1440
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:752
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:675
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:191
PulseDistanceWidthProtocolConstants::RepeatPeriodMillis
unsigned int RepeatPeriodMillis
Definition: IRProtocol.h:166
IRsend::sendLegoPowerFunctions
void sendLegoPowerFunctions(uint8_t aChannel, uint8_t tCommand, uint8_t aMode, bool aDoSend5Times=true)
Definition: ir_Lego.hpp:117
IRsend::write
size_t write(decode_type_t aProtocol, uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats=NO_REPEATS)
Interprets and sends a IRData structure.
Definition: IRSend.hpp:153
SAMSUNGLG
@ SAMSUNGLG
Definition: IRProtocol.h:115
IRData::protocol
decode_type_t protocol
UNKNOWN, NEC, SONY, RC5, PULSE_DISTANCE, ...
Definition: IRremoteInt.h:151
SAMSUNG48
@ SAMSUNG48
Definition: IRProtocol.h:116
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:163
DistanceWidthTimingInfoStruct::HeaderSpaceMicros
uint16_t HeaderSpaceMicros
Definition: IRProtocol.h:136
IRsend::aCommand
void aCommand
Definition: IRremoteInt.h:627
LG
@ LG
Definition: IRProtocol.h:100
IRsend::enableIROut
void enableIROut(uint_fast8_t aFrequencyKHz)
Enables IR output.
Definition: IRSend.hpp:1522
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
SHARP
@ SHARP
Definition: IRProtocol.h:117