Skip to content

Commit 3a11811

Browse files
committed
sendNEC() and sendNEC2() now accepts 16 bit command to better map to NEXext protocol found in IRDB databases. ir_DistanceWidthProtocol() now decodes up to 10 ms mark or spaces if RAM is bigger than 2 k.
1 parent dee20d1 commit 3a11811

File tree

6 files changed

+109
-35
lines changed

6 files changed

+109
-35
lines changed

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
The latest version may not be released!
33
See also the commit log at github: https://github.com/Arduino-IRremote/Arduino-IRremote/commits/master
44

5+
# 4.3.3
6+
- sendNEC() and sendNEC2() now accepts 16 bit command to better map to NEXext protocol found in IRDB databases.
7+
- ir_DistanceWidthProtocol() now decodes up to 10 ms mark or spaces if RAM is bigger than 2 k.
8+
59
# 4.3.2
610
- Added sendSonyMSB(unsigned long data, int nbits) as a clone of sendSony(unsigned long data, int nbits) to be more consistent.
711
- Added sendSamsungMSB(unsigned long data, int nbits) as a clone of sendSAMSUNG(unsigned long data, int nbits) to be more consistent.

examples/AllProtocolsOnLCD/AllProtocolsOnLCD.ino

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@
4040
# if (defined(RAMEND) && RAMEND <= 0x4FF) || (defined(RAMSIZE) && RAMSIZE < 0x4FF)
4141
#define RAW_BUFFER_LENGTH 180
4242
# elif (defined(RAMEND) && RAMEND <= 0x8FF) || (defined(RAMSIZE) && RAMSIZE < 0x8FF)
43-
#define RAW_BUFFER_LENGTH 600
43+
#define RAW_BUFFER_LENGTH 520
44+
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 200 // The decoder accepts mark or space durations up to 200 * 50 (MICROS_PER_TICK) = 10 milliseconds
4445
# else
4546
#define RAW_BUFFER_LENGTH 750
47+
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 400 // The decoder accepts mark or space durations up to 400 * 50 (MICROS_PER_TICK) = 20 milliseconds
4648
# endif
4749
#endif
4850

src/IRReceive.hpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ bool IRrecv::decodePulseDistanceWidthData(PulseDistanceWidthProtocolConstants *a
856856
* Static variables for the getBiphaselevel function
857857
*/
858858
uint_fast8_t sBiphaseDecodeRawbuffOffset; // Index into raw timing array
859-
uint16_t sBiphaseCurrentTimingIntervals; // 1, 2 or 3. Number of aBiphaseTimeUnit intervals of the current rawbuf[sBiphaseDecodeRawbuffOffset] timing.
859+
uint16_t sBiphaseCurrentTimingIntervals; // 1, 2 or 3. Number of aBiphaseTimeUnit intervals of the current rawbuf[sBiphaseDecodeRawbuffOffset] timing.
860860
uint_fast8_t sBiphaseUsedTimingIntervals; // Number of already used intervals of sCurrentTimingIntervals.
861861
uint16_t sBiphaseTimeUnit;
862862

@@ -1276,6 +1276,51 @@ void IRrecv::printDistanceWidthTimingInfo(Print *aSerial, DistanceWidthTimingInf
12761276
aSerial->print(aDistanceWidthTimingInfo->ZeroSpaceMicros);
12771277
}
12781278

1279+
/*
1280+
* Get maximum of mark ticks in rawDataPtr.
1281+
* Skip leading start and trailing stop bit.
1282+
*/
1283+
uint8_t IRrecv::getMaximumMarkTicksFromRawData() {
1284+
uint8_t tMaximumTick = 0;
1285+
for (IRRawlenType i = 3; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1286+
auto tTick = decodedIRData.rawDataPtr->rawbuf[i];
1287+
if (tMaximumTick < tTick) {
1288+
tMaximumTick = tTick;
1289+
}
1290+
}
1291+
return tMaximumTick;
1292+
}
1293+
uint8_t IRrecv::getMaximumSpaceTicksFromRawData() {
1294+
uint8_t tMaximumTick = 0;
1295+
for (IRRawlenType i = 4; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1296+
auto tTick = decodedIRData.rawDataPtr->rawbuf[i];
1297+
if (tMaximumTick < tTick) {
1298+
tMaximumTick = tTick;
1299+
}
1300+
}
1301+
return tMaximumTick;
1302+
}
1303+
1304+
/*
1305+
* The optimizing compiler internally generates this function, if getMaximumMarkTicksFromRawData() and getMaximumSpaceTicksFromRawData() is used.
1306+
*/
1307+
uint8_t IRrecv::getMaximumTicksFromRawData(bool aSearchSpaceInsteadOfMark) {
1308+
uint8_t tMaximumTick = 0;
1309+
IRRawlenType i;
1310+
if (aSearchSpaceInsteadOfMark) {
1311+
i = 4;
1312+
} else {
1313+
i = 3;
1314+
}
1315+
for (; i < decodedIRData.rawlen - 2; i += 2) { // Skip leading start and trailing stop bit.
1316+
auto tTick = decodedIRData.rawDataPtr->rawbuf[i];
1317+
if (tMaximumTick < tTick) {
1318+
tMaximumTick = tTick;
1319+
}
1320+
}
1321+
return tMaximumTick;
1322+
}
1323+
12791324
uint32_t IRrecv::getTotalDurationOfRawData() {
12801325
uint16_t tSumOfDurationTicks = 0;
12811326

src/IRremoteInt.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ class IRrecv {
225225
void printIRResultMinimal(Print *aSerial);
226226
void printIRResultRawFormatted(Print *aSerial, bool aOutputMicrosecondsInsteadOfTicks = true);
227227
void printIRResultAsCVariables(Print *aSerial);
228+
uint8_t getMaximumMarkTicksFromRawData();
229+
uint8_t getMaximumSpaceTicksFromRawData();
230+
uint8_t getMaximumTicksFromRawData(bool aSearchSpaceInsteadOfMark);
228231
uint32_t getTotalDurationOfRawData();
229232

230233
/*
@@ -524,8 +527,8 @@ class IRsend {
524527

525528
void sendNECRepeat();
526529
uint32_t computeNECRawDataAndChecksum(uint16_t aAddress, uint16_t aCommand);
527-
void sendNEC(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats);
528-
void sendNEC2(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats);
530+
void sendNEC(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats);
531+
void sendNEC2(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats);
529532
void sendNECRaw(uint32_t aRawData, int_fast8_t aNumberOfRepeats = NO_REPEATS);
530533
// NEC variants
531534
void sendOnkyo(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats);

src/ir_DistanceWidthProtocol.hpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
* ir_DistanceWidthProtocol.hpp
33
*
44
* Contains only the decoder functions for universal pulse width or pulse distance protocols!
5-
* The send functions are used by almost all protocols and therefore in IRSend.hh.
5+
* The send functions are used by almost all protocols and are therefore located in IRSend.hpp.
6+
*
7+
* If RAM is not more than 2k, the decoder only accepts mark or space durations up to 50 * 50 (MICROS_PER_TICK) = 2500 microseconds
8+
* to save RAM space, otherwise it accepts durations up to 10 ms.
69
*
710
* This decoder tries to decode a pulse distance or pulse distance width with constant period (or pulse width - not enabled yet) protocol.
811
* 1. Analyze all space and mark length
@@ -31,7 +34,7 @@
3134
************************************************************************************
3235
* MIT License
3336
*
34-
* Copyright (c) 2022-2023 Armin Joachimsmeyer
37+
* Copyright (c) 2022-2024 Armin Joachimsmeyer
3538
*
3639
* Permission is hereby granted, free of charge, to any person obtaining a copy
3740
* of this software and associated documentation files (the "Software"), to deal
@@ -65,8 +68,13 @@
6568
//#define LOCAL_DEBUG // This enables debug output only for this file
6669
#endif
6770

68-
// accept durations up to 50 * 50 (MICROS_PER_TICK) 2500 microseconds
69-
#define DURATION_ARRAY_SIZE 50
71+
#if !defined(DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE)
72+
# if (defined(RAMEND) && RAMEND <= 0x8FF) || (defined(RAMSIZE) && RAMSIZE < 0x8FF)
73+
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 50 // To save program space, the decoder only accepts mark or space durations up to 50 * 50 (MICROS_PER_TICK) = 2500 microseconds
74+
# else
75+
#define DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE 200 // The decoder accepts mark or space durations up to 200 * 50 (MICROS_PER_TICK) = 10 milliseconds
76+
# endif
77+
#endif
7078

7179
// Switch the decoding according to your needs
7280
//#define USE_MSB_DECODING_FOR_DISTANCE_DECODER // If active, it resembles LG, otherwise LSB first as most other protocols e.g. NEC and Kaseikyo/Panasonic
@@ -148,9 +156,15 @@ bool aggregateArrayCounts(uint8_t aArray[], uint8_t aMaxIndex, uint8_t *aShortIn
148156
* 2. Decide if we have an pulse width or distance protocol
149157
* 3. Try to decode with the mark and space data found in step 1
150158
* No data and address decoding, only raw data as result.
159+
*
160+
* calloc() version is 700 bytes larger :-(
151161
*/
152162
bool IRrecv::decodeDistanceWidth() {
153-
uint8_t tDurationArray[DURATION_ARRAY_SIZE]; // For up to 49 ticks / 2450 us
163+
/*
164+
* Array for up to 49 ticks / 2500 us (or 199 ticks / 10 ms us if RAM > 2k)
165+
* 0 tick covers mark or space durations from 0 to 49 us, and 49 ticks from 2450 to 2499 us
166+
*/
167+
uint8_t tDurationArray[DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE];
154168

155169
/*
156170
* Accept only protocols with at least 8 bits
@@ -164,16 +178,16 @@ bool IRrecv::decodeDistanceWidth() {
164178
}
165179

166180
// Reset duration array
167-
memset(tDurationArray, 0, DURATION_ARRAY_SIZE);
181+
memset(tDurationArray, 0, DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE);
168182

169183
uint8_t tIndexOfMaxDuration = 0;
170184
/*
171-
* Count number of mark durations up to 49 ticks. Skip leading start and trailing stop bit.
185+
* Count number of mark durations. Skip leading start and trailing stop bit.
172186
*/
173187
for (IRRawlenType i = 3; i < decodedIRData.rawlen - 2; i += 2) {
174188
auto tDurationTicks = decodedIRData.rawDataPtr->rawbuf[i];
175-
if (tDurationTicks < DURATION_ARRAY_SIZE) {
176-
tDurationArray[tDurationTicks]++; // count duration if less than DURATION_ARRAY_SIZE (50)
189+
if (tDurationTicks < DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE) {
190+
tDurationArray[tDurationTicks]++; // count duration if less than DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE
177191
if (tIndexOfMaxDuration < tDurationTicks) {
178192
tIndexOfMaxDuration = tDurationTicks;
179193
}
@@ -183,7 +197,7 @@ bool IRrecv::decodeDistanceWidth() {
183197
Serial.print(F("Mark "));
184198
Serial.print(tDurationTicks * MICROS_PER_TICK);
185199
Serial.print(F(" is longer than maximum "));
186-
Serial.print(DURATION_ARRAY_SIZE * MICROS_PER_TICK);
200+
Serial.print(DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE * MICROS_PER_TICK);
187201
Serial.print(F(" us. Index="));
188202
Serial.println(i);
189203
#endif
@@ -211,15 +225,15 @@ bool IRrecv::decodeDistanceWidth() {
211225
}
212226

213227
// Reset duration array
214-
memset(tDurationArray, 0, DURATION_ARRAY_SIZE);
228+
memset(tDurationArray, 0, DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE);
215229

216230
/*
217231
* Count number of space durations. Skip leading start and trailing stop bit.
218232
*/
219233
tIndexOfMaxDuration = 0;
220234
for (IRRawlenType i = 4; i < decodedIRData.rawlen - 2; i += 2) {
221235
auto tDurationTicks = decodedIRData.rawDataPtr->rawbuf[i];
222-
if (tDurationTicks < DURATION_ARRAY_SIZE) {
236+
if (tDurationTicks < DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE) {
223237
tDurationArray[tDurationTicks]++;
224238
if (tIndexOfMaxDuration < tDurationTicks) {
225239
tIndexOfMaxDuration = tDurationTicks;
@@ -230,7 +244,7 @@ bool IRrecv::decodeDistanceWidth() {
230244
Serial.print(F("Space "));
231245
Serial.print(tDurationTicks * MICROS_PER_TICK);
232246
Serial.print(F(" is longer than maximum "));
233-
Serial.print(DURATION_ARRAY_SIZE * MICROS_PER_TICK);
247+
Serial.print(DISTANCE_WIDTH_DECODER_DURATION_ARRAY_SIZE * MICROS_PER_TICK);
234248
Serial.print(F(" us. Index="));
235249
Serial.println(i);
236250
#endif

src/ir_NEC.hpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@
7171
*/
7272
// http://www.hifi-remote.com/wiki/index.php/NEC
7373
// https://www.sbprojects.net/knowledge/ir/nec.php
74-
// NEC: LSB first, <start bit><address:16> (or <address:8><inverted address:8>) <command:8><inverted command:8><stop bit>.
75-
// ONKYO like NEC but 16 independent address and command bits: <start bit><address:16><command:16><stop bit>
74+
// NEC: LSB first, <start bit><address:16> (or <address:8><inverted address:8>) <command:16><command:8><inverted command:8><stop bit>.
75+
// ONKYO: like NEC but force to 16 independent address and 16 bit command bits: <start bit><address:16><command:16><stop bit>
7676
// Standard NEC sends a special fixed repeat frame.
77-
// NEC2 sends the same full frame after the 110 ms. I have a DVD remote with NEC2.
77+
// NEC2: like NEC, but for repeat, the same full frame is sent after the 110 ms. I have a DVD remote with NEC2.
7878
// NEC and NEC 2 only differ in the repeat frames, so the protocol can only be detected correctly after the first repeat.
7979
// PIONEER (not implemented) is NEC2 with 40 kHz
8080
//
@@ -150,6 +150,13 @@ void sendNECSpecialRepeat() {
150150
IrSender.mark(NEC_BIT_MARK); // + 560
151151
}
152152

153+
/**
154+
* Convert 16 bit address and 16 bit command to 32 bit NECRaw data
155+
* If we get a command < 0x100, we send command and then ~command
156+
* If we get an address < 0x100, we send 8 bit address and then ~address
157+
* !!! Be aware, that this is flexible, but makes it impossible to send e.g. 0x0042 as 16 bit value!!!
158+
* To force send 16 bit address, use: sendOnkyo().
159+
*/
153160
uint32_t IRsend::computeNECRawDataAndChecksum(uint16_t aAddress, uint16_t aCommand) {
154161
LongUnion tRawData;
155162

@@ -173,21 +180,11 @@ uint32_t IRsend::computeNECRawDataAndChecksum(uint16_t aAddress, uint16_t aComma
173180
* There is NO delay after the last sent repeat!
174181
* @param aNumberOfRepeats If < 0 then only a special NEC repeat frame will be sent by calling NECProtocolConstants.SpecialSendRepeatFunction().
175182
*/
176-
void IRsend::sendNEC(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats) {
183+
void IRsend::sendNEC(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
177184
sendPulseDistanceWidth(&NECProtocolConstants, computeNECRawDataAndChecksum(aAddress, aCommand), NEC_BITS, aNumberOfRepeats);
178185
}
179186

180-
/*
181-
* NEC2 Send frame and repeat the frame for each requested repeat
182-
* There is NO delay after the last sent repeat!
183-
* @param aNumberOfRepeats If < 0 then nothing is sent.
184-
*/
185-
void IRsend::sendNEC2(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats) {
186-
sendPulseDistanceWidth(&NEC2ProtocolConstants, computeNECRawDataAndChecksum(aAddress, aCommand), NEC_BITS, aNumberOfRepeats);
187-
}
188-
189-
/*
190-
* Repeat commands should be sent in a 110 ms raster.
187+
/**
191188
* There is NO delay after the last sent repeat!
192189
* @param aNumberOfRepeats If < 0 then only a special repeat frame without leading and trailing space
193190
* will be sent by calling NECProtocolConstants.SpecialSendRepeatFunction().
@@ -196,8 +193,17 @@ void IRsend::sendOnkyo(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumber
196193
sendPulseDistanceWidth(&NECProtocolConstants, (uint32_t) aCommand << 16 | aAddress, NEC_BITS, aNumberOfRepeats);
197194
}
198195

199-
/*
200-
* Repeat commands should be sent in a 110 ms raster.
196+
/**
197+
* NEC2 Send frame !!! and repeat the frame for each requested repeat !!!
198+
* There is NO delay after the last sent repeat!
199+
* @param aNumberOfRepeats If < 0 then nothing is sent.
200+
*/
201+
void IRsend::sendNEC2(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats) {
202+
sendPulseDistanceWidth(&NEC2ProtocolConstants, computeNECRawDataAndChecksum(aAddress, aCommand), NEC_BITS, aNumberOfRepeats);
203+
}
204+
205+
/**
206+
* Apple: Send NEC with fixed 16 bit Apple address 0x87EE.
201207
* There is NO delay after the last sent repeat!
202208
* https://en.wikipedia.org/wiki/Apple_Remote
203209
* https://gist.github.com/darconeous/4437f79a34e3b6441628
@@ -217,7 +223,7 @@ void IRsend::sendApple(uint8_t aDeviceId, uint8_t aCommand, int_fast8_t aNumberO
217223
sendPulseDistanceWidth(&NECProtocolConstants, tRawData.ULong, NEC_BITS, aNumberOfRepeats);
218224
}
219225

220-
/*
226+
/**
221227
* Sends NEC protocol
222228
* @param aNumberOfRepeats If < 0 then only a special repeat frame without leading and trailing space
223229
* will be sent by calling NECProtocolConstants.SpecialSendRepeatFunction().

0 commit comments

Comments
 (0)