Skip to content

Commit

Permalink
Remove the use of USECPERTICKs from the library. (#287)
Browse files Browse the repository at this point in the history
* Remove the use of USECPERTICKs from the library.
Store and measure everything in usecs to similify things and improve timing accuracy.
Reduce excess to 50us from 100us.
Adjustments to RC-MM decoding to handle small measurements better.
Remove calcTick(s) as it is pretty redundant now.

* Re-add a tick of-sorts. Allow for longer capture times.
- Turns out there are some protocols out there that have >65ms gaps in their protocols, so we should support that. Make the tick factor a nice power of 2 for simplicty. Allows upto 130ms gap to be captured.
- Handly converting of the capture buffer into a sendRaw() compatible array. i.e. max values are UINT16_MAX, but the usecs due to the tick factor can be much larger than can be stored. Thus use a '0' encoding to glue these records togther instead of making the array data type bigger.
  • Loading branch information
crankyoldgit authored Aug 4, 2017
1 parent af1d2a8 commit 8dd05c0
Show file tree
Hide file tree
Showing 21 changed files with 146 additions and 151 deletions.
4 changes: 2 additions & 2 deletions examples/IRrecvDump/IRrecvDump.ino
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ void dump(decode_results *results) {
if (i % 100 == 0)
yield(); // Preemptive yield every 100th entry to feed the WDT.
if (i & 1) {
Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
Serial.print(results->rawbuf[i] * RAWTICK, DEC);
} else {
Serial.write('-');
Serial.print((uint32_t) results->rawbuf[i] * USECPERTICK, DEC);
Serial.print((uint32_t) results->rawbuf[i] * RAWTICK, DEC);
}
Serial.print(" ");
}
Expand Down
52 changes: 30 additions & 22 deletions examples/IRrecvDumpV2/IRrecvDumpV2.ino
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ void dumpInfo(decode_results *results) {
Serial.println(" bits)");
}

uint16_t getCookedLength(decode_results *results) {
uint16_t length = results->rawlen - 1;
for (uint16_t i = 0; i < results->rawlen - 1; i++) {
uint32_t usecs = results->rawbuf[i] * RAWTICK;
// Add two extra entries for multiple larger than UINT16_MAX it is.
length += (usecs / UINT16_MAX) * 2;
}
return length;
}

// Dump out the decode_results structure.
//
void dumpRaw(decode_results *results) {
Expand All @@ -105,24 +115,17 @@ void dumpRaw(decode_results *results) {
Serial.print(results->rawlen - 1, DEC);
Serial.println("]: ");

for (uint16_t i = 1; i < results->rawlen; i++) {
for (uint16_t i = 1; i < results->rawlen; i++) {
if (i % 100 == 0)
yield(); // Preemptive yield every 100th entry to feed the WDT.
uint32_t x = results->rawbuf[i] * USECPERTICK;
if (!(i & 1)) { // even
if (i % 2 == 0) { // even
Serial.print("-");
if (x < 1000) Serial.print(" ");
if (x < 100) Serial.print(" ");
Serial.print(x, DEC);
} else { // odd
Serial.print(" ");
Serial.print("+");
if (x < 1000) Serial.print(" ");
if (x < 100) Serial.print(" ");
Serial.print(x, DEC);
if (i < results->rawlen - 1)
Serial.print(", "); // ',' not needed for last one
Serial.print(" +");
}
Serial.printf("%6d", results->rawbuf[i] * RAWTICK);
if (i < results->rawlen - 1)
Serial.print(", "); // ',' not needed for last one
if (!(i % 8)) Serial.println("");
}
Serial.println(""); // Newline
Expand All @@ -132,17 +135,22 @@ void dumpRaw(decode_results *results) {
//
void dumpCode(decode_results *results) {
// Start declaration
Serial.print("uint16_t "); // variable type
Serial.print("uint16_t "); // variable type
Serial.print("rawData["); // array name
Serial.print(results->rawlen - 1, DEC); // array size
Serial.print(getCookedLength(results), DEC); // array size
Serial.print("] = {"); // Start declaration

// Dump data
for (uint16_t i = 1; i < results->rawlen; i++) {
Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
uint32_t usecs;
for (usecs = results->rawbuf[i] * RAWTICK;
usecs > UINT16_MAX;
usecs -= UINT16_MAX)
Serial.printf("%d, 0", UINT16_MAX);
Serial.print(usecs, DEC);
if (i < results->rawlen - 1)
Serial.print(","); // ',' not needed on last one
if (!(i & 1)) Serial.print(" ");
Serial.print(", "); // ',' not needed on last one
if (i % 2 == 0) Serial.print(" "); // Extra if it was even.
}

// End declaration
Expand All @@ -152,7 +160,7 @@ void dumpCode(decode_results *results) {
Serial.print(" // ");
encoding(results);
Serial.print(" ");
serialPrintUint64(results->value, 16);
serialPrintUint64(results->value, HEX);

// Newline
Serial.println("");
Expand All @@ -163,16 +171,16 @@ void dumpCode(decode_results *results) {
// NOTE: It will ignore the atypical case when a message has been decoded
// but the address & the command are both 0.
if (results->address > 0 || results->command > 0) {
Serial.print("uint32_t address = 0x");
Serial.print("uint32_t address = 0x");
Serial.print(results->address, HEX);
Serial.println(";");
Serial.print("uint32_t command = 0x");
Serial.print("uint32_t command = 0x");
Serial.print(results->command, HEX);
Serial.println(";");
}

// All protocols have data
Serial.print("uint64_t data = 0x");
Serial.print("uint64_t data = 0x");
serialPrintUint64(results->value, 16);
Serial.println(";");
}
Expand Down
85 changes: 45 additions & 40 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ static void ICACHE_RAM_ATTR gpio_intr() {
irparams.rawbuf[rawlen] = 1;
} else {
if (now < start)
irparams.rawbuf[rawlen] = (0xFFFFFFFF - start + now) / USECPERTICK + 1;
irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / RAWTICK;
else
irparams.rawbuf[rawlen] = (now - start) / USECPERTICK + 1;
irparams.rawbuf[rawlen] = (now - start) / RAWTICK;
}
irparams.rawlen++;

Expand Down Expand Up @@ -369,8 +369,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
// Nr. of ticks.
uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance) {
// max() used to ensure the result can't drop below 0 before the cast.
return((uint32_t) std::max((int32_t) (
usecs * (1.0 - tolerance/100.0) / USECPERTICK), 0));
return((uint32_t) std::max((int32_t) (usecs * (1.0 - tolerance / 100.0)), 0));
}

// Calculate the upper bound of the nr. of ticks.
Expand All @@ -381,104 +380,110 @@ uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance) {
// Returns:
// Nr. of ticks.
uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance) {
return((uint32_t) usecs * (1.0 + tolerance/100.0) / USECPERTICK + 1);
return((uint32_t) (usecs * (1.0 + tolerance / 100.0)) + 1);
}

// Check if we match a pulse(measured_ticks) with the desired_us within
// Check if we match a pulse(measured) with the desired within
// +/-tolerance percent.
//
// Args:
// measured_ticks: The recorded period of the signal pulse.
// desired_us: The expected period (in useconds) we are matching against.
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::match(uint32_t measured_ticks, uint32_t desired_us,
bool IRrecv::match(uint32_t measured, uint32_t desired,
uint8_t tolerance) {
measured *= RAWTICK; // Convert to uSecs.
DPRINT("Matching: ");
DPRINT(ticksLow(desired_us, tolerance));
DPRINT(ticksLow(desired, tolerance));
DPRINT(" <= ");
DPRINT(measured_ticks);
DPRINT(measured);
DPRINT(" <= ");
DPRINTLN(ticksHigh(desired_us, tolerance));
return (measured_ticks >= ticksLow(desired_us, tolerance) &&
measured_ticks <= ticksHigh(desired_us, tolerance));
DPRINTLN(ticksHigh(desired, tolerance));
return (measured >= ticksLow(desired, tolerance) &&
measured <= ticksHigh(desired, tolerance));
}


// Check if we match a pulse(measured_ticks) of at least desired_us within
// Check if we match a pulse(measured) of at least desired within
// +/-tolerance percent.
//
// Args:
// measured_ticks: The recorded period of the signal pulse.
// desired_us: The expected period (in useconds) we are matching against.
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchAtLeast(uint32_t measured_ticks, uint32_t desired_us,
bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
uint8_t tolerance) {
measured *= RAWTICK; // Convert to uSecs.
DPRINT("Matching ATLEAST ");
DPRINT(measured_ticks * USECPERTICK);
DPRINT(measured);
DPRINT(" vs ");
DPRINT(desired_us);
DPRINT(desired);
DPRINT(". Matching: ");
DPRINT(measured_ticks);
DPRINT(measured);
DPRINT(" >= ");
DPRINT(ticksLow(std::min(desired_us, TIMEOUT_MS * 1000), tolerance));
DPRINT(ticksLow(std::min(desired, TIMEOUT_MS * 1000), tolerance));
DPRINT(" [min(");
DPRINT(ticksLow(desired_us, tolerance));
DPRINT(ticksLow(desired, tolerance));
DPRINT(", ");
DPRINT(ticksLow(TIMEOUT_MS * 1000, tolerance));
DPRINTLN(")]");
// We really should never get a value of 0, except as the last value
// in the buffer. If that is the case, then assume infinity and return true.
if (measured_ticks == 0) return true;
return measured_ticks >= ticksLow(std::min(desired_us, TIMEOUT_MS * 1000),
tolerance);
if (measured == 0) return true;
return measured >= ticksLow(std::min(desired, TIMEOUT_MS * 1000),
tolerance);
}

// Check if we match a mark signal(measured_ticks) with the desired_us within
// Check if we match a mark signal(measured) with the desired within
// +/-tolerance percent, after an expected is excess is added.
//
// Args:
// measured_ticks: The recorded period of the signal pulse.
// desired_us: The expected period (in useconds) we are matching against.
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
// excess: Nr. of useconds.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchMark(uint32_t measured_ticks, uint32_t desired_us,
bool IRrecv::matchMark(uint32_t measured, uint32_t desired,
uint8_t tolerance, int16_t excess) {
DPRINT("Matching MARK ");
DPRINT(measured_ticks * USECPERTICK);
DPRINT(measured * RAWTICK);
DPRINT(" vs ");
DPRINT(desired_us);
DPRINT(desired);
DPRINT(" + ");
DPRINT(excess);
DPRINT(". ");
return match(measured_ticks, desired_us + excess, tolerance);
return match(measured, desired + excess, tolerance);
}

// Check if we match a space signal(measured_ticks) with the desired_us within
// Check if we match a space signal(measured) with the desired within
// +/-tolerance percent, after an expected is excess is removed.
//
// Args:
// measured_ticks: The recorded period of the signal pulse.
// desired_us: The expected period (in useconds) we are matching against.
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
// excess: Nr. of useconds.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchSpace(uint32_t measured_ticks, uint32_t desired_us,
bool IRrecv::matchSpace(uint32_t measured, uint32_t desired,
uint8_t tolerance, int16_t excess) {
DPRINT("Matching SPACE ");
DPRINT(measured_ticks * USECPERTICK);
DPRINT(measured * RAWTICK);
DPRINT(" vs ");
DPRINT(desired_us);
DPRINT(desired);
DPRINT(" - ");
DPRINT(excess);
DPRINT(". ");
return match(measured_ticks, desired_us - excess, tolerance);
return match(measured, desired - excess, tolerance);
}

/* -----------------------------------------------------------------------
Expand Down
20 changes: 13 additions & 7 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#define OFFSET_START 1U // Usual rawbuf entry to start processing from.
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100U
#define MARK_EXCESS 50U
#define RAWBUF 100U // Default length of raw capture buffer
#define REPEAT UINT64_MAX
// receiver states
Expand All @@ -29,8 +29,14 @@
#define STATE_SPACE 4U
#define STATE_STOP 5U
#define TOLERANCE 25U // default percent tolerance in measurements
#define USECPERTICK 50U // microseconds per clock interrupt tick
#define TIMEOUT_MS 15U // How long before we give up wait for more data.
#define RAWTICK 2U // Capture tick to uSec factor.
// How long (ms) before we give up wait for more data?
// Don't exceed 130ms (RAWTICK * UINT16_MAX uSeconds) without a good reason.
// That is the capture buffers maximum value size. (UINT16_MAX / RAWTICK)
// Typically messages/protocols tend to repeat around the 100ms timeframe,
// thus we should timeout before that to give us some time to try to decode
// before we need to start capturing a possible new message.
#define TIMEOUT_MS 90U // In MilliSeconds. (Historic default was 15ms)

// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
#define FNV_PRIME_32 16777619UL
Expand Down Expand Up @@ -93,13 +99,13 @@ class IRrecv {
int16_t compare(uint16_t oldval, uint16_t newval);
uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = TOLERANCE);
uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = TOLERANCE);
bool match(uint32_t measured_ticks, uint32_t desired_us,
bool match(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE);
bool matchAtLeast(uint32_t measured_ticks, uint32_t desired_us,
bool matchAtLeast(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE);
bool matchMark(uint32_t measured_ticks, uint32_t desired_us,
bool matchMark(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS);
bool matchSpace(uint32_t measured_ticks, uint32_t desired_us,
bool matchSpace(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS);
match_result_t matchData(volatile uint16_t *data_ptr, uint16_t nbits,
uint16_t onemark, uint32_t onespace,
Expand Down
11 changes: 0 additions & 11 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,3 @@ void serialPrintUint64(uint64_t input, uint8_t base) {
Serial.print(str);
#endif
}

// Calculate the tick time in uSeconds based on the input time & factor.
//
// Args:
// input: Nr. of capture ticks.
// factor: Nr. of multiples of the common tick divisor the input should be.
// Returns:
// A uint32_t containing the common tick time in uSeconds.
uint32_t calcTickTime(uint16_t input, uint16_t factor) {
return (input * USECPERTICK) / factor;
}
1 change: 0 additions & 1 deletion src/IRutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@

uint64_t reverseBits(uint64_t input, uint16_t nbits);
void serialPrintUint64(uint64_t input, uint8_t base);
uint32_t calcTickTime(uint16_t input, uint16_t factor);

#endif // IRUTILS_H_
7 changes: 3 additions & 4 deletions src/ir_Coolix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,11 @@ bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits,
// Header
if (!matchMark(results->rawbuf[offset], COOLIX_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = calcTickTime(results->rawbuf[offset++],
COOLIX_HDR_MARK_TICKS);
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / COOLIX_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], COOLIX_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = calcTickTime(results->rawbuf[offset++],
COOLIX_HDR_SPACE_TICKS);
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
COOLIX_HDR_SPACE_TICKS;

// Data
// Twice as many bits as there are normal plus inverted bits.
Expand Down
8 changes: 4 additions & 4 deletions src/ir_Denon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) {
// Header
if (!matchMark(results->rawbuf[offset], DENON_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = calcTickTime(results->rawbuf[offset++],
DENON_HDR_MARK_TICKS);
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
DENON_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], DENON_HDR_SPACE)) return false;
uint32_t s_tick = calcTickTime(results->rawbuf[offset++],
DENON_HDR_SPACE_TICKS);
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
DENON_HDR_SPACE_TICKS;

// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
Expand Down
6 changes: 2 additions & 4 deletions src/ir_Dish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,10 @@ bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) {
// Header
if (!match(results->rawbuf[offset], DISH_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = calcTickTime(results->rawbuf[offset++],
DISH_HDR_MARK_TICKS);
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], DISH_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = calcTickTime(results->rawbuf[offset++],
DISH_HDR_SPACE_TICKS);
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_SPACE_TICKS;

// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
Expand Down
Loading

0 comments on commit 8dd05c0

Please sign in to comment.