From e12e9eaac8c3851770b09de7d2f398565f180940 Mon Sep 17 00:00:00 2001 From: Ken Shirriff Date: Fri, 22 Jan 2010 23:26:54 -0800 Subject: [PATCH] Add "hash encoding" to generate a value for unknown encodings. For an unknown encoding, an arbitrary 32-bit value will be generated. --- IRremote.cpp | 63 +++++++++++++++++++++++++++--- IRremote.h | 3 ++ examples/IRrecvDump/IRrecvDump.pde | 34 ++++++++-------- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/IRremote.cpp b/IRremote.cpp index bb6083e..236737d 100644 --- a/IRremote.cpp +++ b/IRremote.cpp @@ -368,11 +368,10 @@ int IRrecv::decode(decode_results *results) { if (decodeRC6(results)) { return DECODED; } - if (results->rawlen >= 6) { - // Only return raw buffer if at least 6 bits - results->decode_type = UNKNOWN; - results->bits = 0; - results->value = 0; + // decodeHash returns a hash on any input. + // Thus, it needs to be last in the list. + // If you add any decodes, add them before this. + if (decodeHash(results)) { return DECODED; } // Throw away and start over @@ -599,3 +598,57 @@ long IRrecv::decodeRC6(decode_results *results) { results->decode_type = RC6; return DECODED; } + +/* ----------------------------------------------------------------------- + * hashdecode - decode an arbitrary IR code. + * Instead of decoding using a standard encoding scheme + * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value. + * + * The algorithm: look at the sequence of MARK signals, and see if each one + * is shorter (0), the same length (1), or longer (2) than the previous. + * Do the same with the SPACE signals. Hszh the resulting sequence of 0's, + * 1's, and 2's to a 32-bit value. This will give a unique value for each + * different code (probably), for most code systems. + * + * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html + */ + +// Compare two tick values, returning 0 if newval is shorter, +// 1 if newval is equal, and 2 if newval is longer +// Use a tolerance of 20% +int IRrecv::compare(unsigned int oldval, unsigned int newval) { + if (newval < oldval * .8) { + return 0; + } + else if (oldval < newval * .8) { + return 2; + } + else { + return 1; + } +} + +// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param +#define FNV_PRIME_32 16777619 +#define FNV_BASIS_32 2166136261 + +/* Converts the raw code values into a 32-bit hash code. + * Hopefully this code is unique for each button. + * This isn't a "real" decoding, just an arbitrary value. + */ +long IRrecv::decodeHash(decode_results *results) { + // Require at least 6 samples to prevent triggering on noise + if (results->rawlen < 6) { + return ERR; + } + long hash = FNV_BASIS_32; + for (int i = 1; i+2 < results->rawlen; i++) { + int value = compare(results->rawbuf[i], results->rawbuf[i+2]); + // Add value into the hash + hash = (hash * FNV_PRIME_32) ^ value; + } + results->value = hash; + results->bits = 32; + results->decode_type = UNKNOWN; + return DECODED; +} diff --git a/IRremote.h b/IRremote.h index 35fb445..f5e7a7b 100644 --- a/IRremote.h +++ b/IRremote.h @@ -56,6 +56,9 @@ private: long decodeSony(decode_results *results); long decodeRC5(decode_results *results); long decodeRC6(decode_results *results); + long decodeHash(decode_results *results); + int compare(unsigned int oldval, unsigned int newval); + } ; diff --git a/examples/IRrecvDump/IRrecvDump.pde b/examples/IRrecvDump/IRrecvDump.pde index ad3c599..93495b7 100644 --- a/examples/IRrecvDump/IRrecvDump.pde +++ b/examples/IRrecvDump/IRrecvDump.pde @@ -28,26 +28,24 @@ void setup() void dump(decode_results *results) { int count = results->rawlen; if (results->decode_type == UNKNOWN) { - Serial.println("Could not decode message"); + Serial.print("Unknown encoding: "); } - else { - if (results->decode_type == NEC) { - Serial.print("Decoded NEC: "); - } - else if (results->decode_type == SONY) { - Serial.print("Decoded SONY: "); - } - else if (results->decode_type == RC5) { - Serial.print("Decoded RC5: "); - } - else if (results->decode_type == RC6) { - Serial.print("Decoded RC6: "); - } - Serial.print(results->value, HEX); - Serial.print(" ("); - Serial.print(results->bits, DEC); - Serial.println(" bits)"); + else if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); Serial.print("Raw ("); Serial.print(count, DEC); Serial.print("): ");