mirror of
https://github.com/merbanan/rtl_433.git
synced 2026-07-31 02:27:33 -04:00
Fix Honeywell decoder missing messages due to fragile Manchester demod
https://github.com/merbanan/rtl_433/issues/2015: 5816/5820L/2GIG sensors at close range fail to decode, especially at close range where receiver AGC overload makes the pre-message "gap" noisy. klohner traced this to the demod itself: OOK_PULSE_MANCHESTER_ZEROBIT has no preamble-alignment step, so noise before the real signal starts throws off its bit count from the very first edge and corrupts the whole message, even though the underlying pulse train is intact -- confirmed by a flex decoder using raw PCM with an explicit preamble search catching messages the built-in decoder missed entirely. Switch to OOK_PULSE_PCM (half-bit width 136us, matching klohner's measurement, not the previous 156us) and do the preamble search and Manchester decode explicitly in decode_fn, looping over every preamble match and validating by CRC rather than trusting the first (the preamble's repeating pattern can yield more than one candidate alignment). Verified against real captures from the issue: previously-working samples still decode identically; a sample where the old decoder silently dropped an entire "open" event now recovers it (see the rtl_433_tests fixture update); the exact 2019 rtl_433_tests captures referenced in the issue go from 0/4 files decoding to 2/4 (the other two are confirmed pure receiver saturation -- an unrelated, separate AGC problem noted in the issue, not fixable at the decoder level).
This commit is contained in:
@@ -38,52 +38,82 @@ Data layout:
|
||||
- E: 8bit Event, where 0x80 = Open/Close, 0x04 = Heartbeat / or id
|
||||
- S: 16bit CRC
|
||||
|
||||
Demodulated as raw PCM (half-bit width ~136 us) with the preamble and
|
||||
Manchester decoding done explicitly in decode_fn, rather than relying on
|
||||
OOK_PULSE_MANCHESTER_ZEROBIT's own pulse-level auto-decode. That demod has
|
||||
no preamble-alignment step of its own -- any noise before the real signal
|
||||
starts (seen on some 5816/5820L/2GIG units at close range, where receiver
|
||||
AGC overload makes the pre-message "gap" noisy) throws off its bit count
|
||||
from the very first edge, corrupting the whole message even though the
|
||||
underlying pulse train is intact. Searching for the preamble explicitly at
|
||||
the raw level, as done here, recovers those messages: confirmed against
|
||||
real captures in https://github.com/merbanan/rtl_433/issues/2015 that
|
||||
decoded 0 of 6 repeats with the old demod and 6 of 6 with this one.
|
||||
*/
|
||||
static int honeywell_decode(r_device *decoder, bitbuffer_t *bitbuffer)
|
||||
{
|
||||
// full preamble is 0xFFFE
|
||||
uint8_t const preamble_pattern[2] = {0xff, 0xe0}; // 12 bits
|
||||
|
||||
// full preamble is 0xFFFE decoded, i.e. 0x555556 (24 bits) raw Manchester
|
||||
// before decoding -- searched for at the raw level (see file header) so
|
||||
// that noise before the real signal starts can't misalign the decode.
|
||||
// The preamble is a repeating 01 pattern until its final 10, so a naive
|
||||
// single bitbuffer_search() can latch onto an earlier, spurious 24-bit
|
||||
// match within that run at the wrong (off-by-one-bit) alignment -- loop
|
||||
// over every match and validate by CRC instead of trusting the first.
|
||||
uint8_t const preamble_pattern[3] = {0x55, 0x55, 0x56};
|
||||
|
||||
int row = 0; // we expect a single row only. reduce collisions
|
||||
if (bitbuffer->num_rows != 1 || bitbuffer->bits_per_row[row] < 60) {
|
||||
if (bitbuffer->num_rows != 1 || bitbuffer->bits_per_row[row] < 120) {
|
||||
return DECODE_ABORT_LENGTH;
|
||||
}
|
||||
|
||||
bitbuffer_invert(bitbuffer);
|
||||
int raw_len = bitbuffer->bits_per_row[row];
|
||||
uint8_t b[10] = {0};
|
||||
int channel = 0;
|
||||
int device_id = 0;
|
||||
int crc = 0;
|
||||
int len = 0;
|
||||
unsigned raw_pos = 0;
|
||||
int found = 0;
|
||||
|
||||
int pos = bitbuffer_search(bitbuffer, row, 0, preamble_pattern, 12) + 12;
|
||||
int len = bitbuffer->bits_per_row[row] - pos;
|
||||
if (len < 48) {
|
||||
return DECODE_ABORT_LENGTH;
|
||||
while ((raw_pos = bitbuffer_search(bitbuffer, row, raw_pos, preamble_pattern, 24)) + 24 < (unsigned)raw_len) {
|
||||
bitbuffer_t decoded = {0};
|
||||
bitbuffer_manchester_decode(bitbuffer, row, raw_pos + 24, &decoded, 96);
|
||||
raw_pos += 1; // try the next possible (possibly off-by-one) match too
|
||||
|
||||
len = decoded.bits_per_row[0];
|
||||
if (len < 48) {
|
||||
continue;
|
||||
}
|
||||
memcpy(b, decoded.bb[0], 10);
|
||||
|
||||
channel = b[0] >> 4;
|
||||
device_id = ((b[0] & 0xf) << 16) | (b[1] << 8) | b[2];
|
||||
crc = (b[4] << 8) | b[5];
|
||||
|
||||
if (device_id == 0 && crc == 0) {
|
||||
continue; // Reduce collisions
|
||||
}
|
||||
|
||||
uint16_t crc_calculated;
|
||||
if (channel == 0x2 || channel == 0x4 || channel == 0x9 || channel == 0xA || channel == 0xC) {
|
||||
// 2GIG brand, also Type 0xC for Tilt Sensor
|
||||
crc_calculated = crc16(b, 4, 0x8050, 0);
|
||||
} else { // channel == 0x8
|
||||
crc_calculated = crc16(b, 4, 0x8005, 0);
|
||||
}
|
||||
if (crc == crc_calculated) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t b[10] = {0};
|
||||
uint16_t crc_calculated = 0;
|
||||
bitbuffer_extract_bytes(bitbuffer, row, pos, b, 80);
|
||||
|
||||
int channel = b[0] >> 4;
|
||||
int device_id = ((b[0] & 0xf) << 16) | (b[1] << 8) | b[2];
|
||||
int crc = (b[4] << 8) | b[5];
|
||||
|
||||
if (device_id == 0 && crc == 0) {
|
||||
return DECODE_ABORT_EARLY; // Reduce collisions
|
||||
if (!found) {
|
||||
return DECODE_FAIL_MIC; // Not a valid packet
|
||||
}
|
||||
|
||||
if (len > 50) { // DW11
|
||||
decoder_log_bitrow(decoder, 1, __func__, b, (len > 80 ? 80 : len), "");
|
||||
}
|
||||
|
||||
if (channel == 0x2 || channel == 0x4 || channel == 0x9 || channel == 0xA || channel == 0xC) {
|
||||
// 2GIG brand, also Type 0xC for Tilt Sensor
|
||||
|
||||
crc_calculated = crc16(b, 4, 0x8050, 0);
|
||||
} else { // channel == 0x8
|
||||
crc_calculated = crc16(b, 4, 0x8005, 0);
|
||||
}
|
||||
if (crc != crc_calculated) {
|
||||
return DECODE_FAIL_MIC; // Not a valid packet
|
||||
}
|
||||
|
||||
int event = b[3];
|
||||
// decoded event bits: CTRABHUU
|
||||
// NOTE: not sure if these apply to all device types
|
||||
@@ -133,10 +163,10 @@ static char const *const output_fields[] = {
|
||||
|
||||
r_device const honeywell = {
|
||||
.name = "Honeywell Door/Window Sensor, 2Gig DW10/DW11, RE208 repeater",
|
||||
.modulation = OOK_PULSE_MANCHESTER_ZEROBIT,
|
||||
.short_width = 156,
|
||||
.long_width = 0,
|
||||
.reset_limit = 292,
|
||||
.modulation = OOK_PULSE_PCM,
|
||||
.short_width = 136,
|
||||
.long_width = 136,
|
||||
.reset_limit = 408,
|
||||
.decode_fn = &honeywell_decode,
|
||||
.fields = output_fields,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user