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