8000 Add space_enc decoding. · RemoteControl/Arduino-IRremote@d424e34 · GitHub
[go: up one dir, main page]

Skip to content

Commit d424e34

Browse files
committed
Add space_enc decoding.
This code will decode an arbitrary code that uses different mark widths or space widths to encode bits.
1 parent eecd3d6 commit d424e34

File tree

3 files changed

+258
-0
lines changed

3 files changed

+258
-0
lines changed

IRremote.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,29 @@
2020
// #define DEBUG
2121
// #define TEST
2222

23+
// Information on a generic space encoding code
24+
class space_enc_data {
25+
public:
26+
int headerMark; // Mark time for header in us
27+
int headerSpace; // Space time for header in us
28+
int mark0; // Mark time in us for 0 bit
29+
int space0; // Space time in us for 0 bit
30+
int mark1; // Mark time in us for 1 bit
31+
int space1; // Space time in us for 1 bit
32+
int trailer; // Trailer mark time in us or 0
33+
int frequency; // Not used by IRrecv
34+
};
35+
2336
// Results returned from the decoder
37+
2438
class decode_results {
2539
public:
2640
int decode_type; // NEC, SONY, RC5, UNKNOWN
2741
unsigned long value; // Decoded value
2842
int bits; // Number of bits in decoded value
2943
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
3044
int rawlen; // Number of records in rawbuf.
45+
class space_enc_data spaceEncData;
3146
};
3247

3348
// Values for decode_type
@@ -37,6 +52,7 @@ class decode_results {
3752
#define RC6 4
3853
#define DISH 5
3954
#define SHARP 6
55+
#define SPACE_ENC 7 // Generic space encoding
4056
#define UNKNOWN -1
4157

4258
// Decoded value for NEC when a repeat code is received
@@ -53,6 +69,7 @@ class IRrecv
5369
private:
5470
// These are called by decode
5571
int getRClevel(decode_results *results, int *offset, int *used, int t1);
72+
long decodeSpaceEnc(decode_results *results);
5673
long decodeNEC(decode_results *results);
5774
long decodeSony(decode_results *results);
5875
long decodeRC5(decode_results *results);

IRremoteRecv.cpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ int IRrecv::decode(decode_results *results) {
154154
if (irparams.rcvstate != STATE_STOP) {
155155
return ERR;
156156
}
157+
#ifdef DEBUG
158+
Serial.println("Attempting SPACE_ENC decode");
159+
#endif
160+
if (decodeSpaceEnc(results)) {
161+
return DECODED;
162+
}
157163
#ifdef DEBUG
158164
Serial.println("Attempting NEC decode");
159165
#endif
@@ -189,6 +195,191 @@ int IRrecv::decode(decode_results *results) {
189195
return ERR;
190196
}
191197

198+
// Decoding a generic space encoded signal is a bit tricky.
199+
// We assume one of two cases:
200+
// a) a 0 is a mark and a short space, and a 1 is a mark and a long space (spaceVaries), or
201+
// b) a 0 is a short mark and a space, and a 1 is a long mark and a space (markVaries)
202+
// The NEC code is an example of varying space, and the Sony code is an example of varying mark.
203+
//
204+
// We assume that if the space varies, there is a trailing mark (so you can tell when the last space ends),
205+
// but if the mark varies then the last mark is part of the last bit, but the last space is very long.
206+
//
207+
// To decode, the first step is to find the shortest and longest marks and spaces (excluding headers and trailers).
208+
// Then see if the marks or spaces vary. (If both, probably RC5/6 so quit.)
209+
// Loop through all the mark/space pairs to see if it is a 1 or a 0.
210+
// Finally, fill in the results.
211+
//
212+
// The code is somewhat long and confusing because it is generic and handles both cases.
213+
//
214+
long IRrecv::decodeSpaceEnc(decode_results *results) {
215+
if (irparams.rawlen < 10) {
216+
// Don't have a reasonable number of bits to decode.
217+
return ERR;
218+
}
219+
unsigned int minMark = 999999;
220+
unsigned int maxMark = 0;
221+
unsigned int minSpace = 999999;
222+
unsigned int maxSpace = 0;
223+
// Compute the minimum and maximum mark and space durations, ignoring
224+
// header and trailer.
225+
// start with entry 3, skipping first space and two header elements
226+
// skip the last space and mark in case they are a trailer
227+
for (int i = 3; i < irparams.rawlen-2; i += 2) {
228+
if (results->rawbuf[i] < minMark) {
229+
minMark = results->rawbuf[i];
230+
} else if (results->rawbuf[i] > maxMark) {
231+
maxMark = results->rawbuf[i];
232+
}
233+
if (results->rawbuf[i+1] < minSpace) {
234+
minSpace = results->rawbuf[i+1];
235+
} else if (results->rawbuf[i+1] > maxSpace) {
236+
maxSpace = results->rawbuf[i+1];
237+
}
238+
}
239+
maxMark *= USECPERTICK;
240+
maxSpace *= USECPERTICK;
241+
// The second argument is us, the first is ticks, so need to multiply the second
242+
// markVaries is true if there are two different mark values
243+
// spaceVaries is true if there are two different space values
244+
int markVaries = !MATCH(minMark, maxMark);
245+
int spaceVaries = !MATCH(minSpace, maxSpace);
246+
minMark *= USECPERTICK;
247+
minSpace *= USECPERTICK;
248+
#ifdef DEBUG
249+
Serial.print("min mark: ");
250+
Serial.println(minMark, DEC);
251+
Serial.print("max mark: ");
252+
Serial.println(maxMark, DEC);
253+
Serial.print("min space: ");
254+
Serial.println(minSpace, DEC);
255+
Serial.print("max space: ");
256+
Serial.println(maxSpace, DEC);
257+
#endif
258+
// Only one of these can vary for SPACE_ENC
259+
if (markVaries == spaceVaries) {
260+
return ERR;
261+
}
262+
// Subtract 4 entries: space, 2 for header, 1 for trailer
263+
int nbits = (irparams.rawlen-4) / 2;
264+
// Clean up the non-varying value by averaging the min and max
265+
// They will probably be slightly different due to random fluctuations
266+
// so the average is probably best to use.
267+
if (markVaries) {
268+
minSpace = (minSpace + maxSpace) / 2;
269+
maxSpace = minSpace;
270+
nbits += 1; // Last mark is a bit, not a trailer
271+
results->spaceEncData.trailer = 0;
272+
} else {
273+
minMark = (minMark + maxMark) / 2;
274+
maxMark = minMark;
275+
// If space varies, need a trailer to delimit the last space
276+
results->spaceEncData.trailer = results->rawbuf[irparams.rawlen-1] * USECPERTICK;
277+
}
278+
#ifdef DEBUG
279+
Serial.print("nbits: ");
280+
Serial.println(nbits);
281+
Serial.print("markVaries: ");
282+
Serial.println(markVaries);
283+
Serial.print("spaceVaries: ");
284+
Serial.println(spaceVaries);
285+
Serial.print("rawlen: ");
286+
Serial.println(irparams.rawlen);
287+
#endif
288+
289+
// Now loop through the data and determine the bit values.
290+
291+
long data = 0;
292+
int offset = 3; // Offset into rawbuf; skip the header
293+
if (markVaries) {
294+
// The decode loop where the mark width determines the bit value
295+
for (int i=0; i < nbits-1; i++) {
296+
data <<= 1;
297+
// Check the mark and determine the bit
298+
unsigned int markVal = results->rawbuf[offset++];
299+
if (MATCH(markVal, minMark)) {
300+
// 0 bit
301+
} else if (MATCH(markVal, maxMark)) {
302+
data |= 1; // 1 bit
303+
} else {
304+
// The mark is no good.
305+
return ERR;
306+
}
307+
// Check that the space is okay
308+
unsigned int spaceVal = results->rawbuf[offset++];
309+
if (!MATCH(spaceVal, minSpace)) {
310+
// The space is no good
311+
return ERR;
312+
}
313+
}
314+
// Process the last bit specially because it's just a mark without a space
315+
// (because the transmission has to end with a mark).
316+
// If it makes sense as a bit, treat it as a bit, otherwise treat it as a
317+
// trailer.
318+
unsigned int markVal = results->rawbuf[offset++];
319+
if (MATCH(markVal, minMark)) {
320+
// 0 bit
321+
data <<= 1;
322+
} else if (MATCH(markVal, maxMark)) {
323+
data <<= 1;
324+
data |= 1; // 1 bit
325+
} else {
326+
// Guess the last mark was just a trailer after all
327+
nbits--;
328+
results->spaceEncData.trailer = results->rawbuf[irparams.rawlen-1] * USECPERTICK;
329+
}
330+
} else {
331+
332+
// The decode loop where the space width determines the bit value
333+
for (int i=0; i & F438 lt; nbits; i++) {
334+
data <<= 1; // Shift the data over for the next bit
335+
// Check that the mark is okay
336+
unsigned int markVal = results->rawbuf[offset++];
337+
if (!MATCH(markVal, minMark)) {
338+
return ERR;
339+
}
340+
// Check the space and determine the bit
341+
unsigned int spaceVal = results->rawbuf[offset++];
342+
if (MATCH(spaceVal, minSpace)) {
343+
// 0 bit
344+
} else if (MATCH(spaceVal, maxSpace)) {
345+
data |= 1; // 1 bit
346+
} else {
347+
return ERR;
348+
}
349+
}
350+
}
351+
352+
// Finally, save the results
353+
354+
results->spaceEncData.headerMark = results->rawbuf[1] * USECPERTICK;
355+
results->spaceEncData.headerSpace = results->rawbuf[2] * USECPERTICK;
356+
results->spaceEncData.mark0 = minMark;
357+
results->spaceEncData.space0 = minSpace;
358+
results->spaceEncData.mark1 = maxMark;
359+
results->spaceEncData.space1 = maxSpace;
360+
results->spaceEncData.frequency = 0; // Don't know
361+
results->bits = nbits;
362+
results->value = data;
363+
results->decode_type = SPACE_ENC;
364+
#ifdef DEBUG
365+
Serial.print("headerMark: ");
366+
Serial.println(results->spaceEncData.headerMark, DEC);
367+
Serial.print("headerSpace: ");
368+
Serial.println(results->spaceEncData.headerSpace, DEC);
369+
Serial.print("mark0: ");
370+
Serial.println(results->spaceEncData.mark0, DEC);
371+
Serial.print("space0: ");
372+
Serial.println(results->spaceEncData.space0, DEC);
373+
Serial.print("mark1: ");
374+
Serial.println(results->spaceEncData.mark1, DEC);
375+
Serial.print("space1: ");
376+
Serial.println(results->spaceEncData.space1, DEC);
377+
Serial.print("trailer: ");
378+
Serial.println(results->spaceEncData.trailer, DEC);
379+
#endif
380+
return SPACE_ENC;
381+
}
382+
192383
long IRrecv::decodeNEC(decode_results *results) {
193384
long data = 0;
194385
int offset = 1; // Skip first space

examples/IRrecvDump/IRrecvDump.pde

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,17 @@ void dump(decode_results *results) {
4242
else if (results->decode_type == RC6) {
4343
Serial.print("Decoded RC6: ");
4444
}
45+
else if (results->decode_type == SPACE_ENC) {
46+
Serial.print("Decoded SPACE_ENC: ");
47+
}
4548
Serial.print(results->value, HEX);
4649
Serial.print(" (");
4750
Serial.print(results->bits, DEC);
4851
Serial.println(" bits)");
4952
Serial.print("Raw (");
5053
Serial.print(count, DEC);
5154
Serial.print("): ");
55+
printSonyData(results);
5256

5357
for (int i = 0; i < count; i++) {
5458
if ((i % 2) == 1) {
@@ -62,6 +66,52 @@ void dump(decode_results *results) {
6266
Serial.println("");
6367
}
6468

69+
// Helper function for displaying Sony information.
70+
// Takes the bottom nbits bits from value, reverses them,
71+
// and returns the result.
72+
unsigned long reverseBits(unsigned long value, int nbits) {
73+
unsigned long result = 0;
74+
// The idea is that mask starts at the leftmost position and moves right.
75+
// We look at the rightmost bit of value and move left.
76+
// If the bit in value is set, then set the opposite bit in result using mask.
77+
unsigned long mask = 1 << (nbits-1);
78+
for (int i = 0; i < nbits; i++) {
79+
if (value & 1) {
80+
result |= mask;
81+
}
82+
value >>= 1;
83+
mask >>= 1;
84+
}
85+
return result;
86+
}
87+
88+
// If this looks like a Sony code, extract and print the various fields
89+
// after reversing the bits.
90+
// See http://www.hifi-remote.com/sony/ for more information on these codes.
91+
92+
void printSonyData(decode_results *results) {
93+
if (results->bits == 12) {
94+
// 7 command bits, 5 device bits
95+
Serial.print("device: ");
96+
Serial.print(reverseBits(results->value, 5), DEC);
97+
Serial.print(", command: ");
98+
Serial.println(reverseBits(results->value >> 5, 7), DEC);
99+
} else if (results->bits == 15) {
100+
// 7 command bits, 8 device bits
101+
Serial.print("device: ");
102+
Serial.print(reverseBits(results->value, 8), DEC);
103+
Serial.print(", command: ");
104+
Serial.println(reverseBits(results->value >> 8, 7), DEC);
105+
} else if (results->bits == 20) {
106+
// 7 command bits, 5 device bits, 8 extended device bits
107+
Serial.print("device: ");
108+
Serial.print(reverseBits(results->value >> 8, 5), DEC);
109+
Serial.print(".");
110+
Serial.print(reverseBits(results->value, 8), DEC);
111+
Serial.print(", command: ");
112+
Serial.println(reverseBits(results->value >> 13, 7), DEC);
113+
}
114+
}
65115

66116
void loop() {
67117
if (irrecv.decode(&results)) {

0 commit comments

Comments
 (0)
0