From 23fbfead7b22eacadf48ce8f38fc4dcccbcf4720 Mon Sep 17 00:00:00 2001 From: Benjamin Larsson Date: Sat, 18 Jul 2026 20:03:43 +0200 Subject: [PATCH] fordremote: dedupe repeats via bitbuffer_find_repeated_row, disable Each button press was reported once per repeat (typically 4x) because reset_limit (4000 us) was far shorter than the real packet gap between repeats (~52000 us, per the file's own preamble-gap comment), so every repeat arrived as its own separate bitbuffer/callback instead of one bitbuffer containing all of them. Raised reset_limit to bundle all repeats into a single call, then use bitbuffer_find_repeated_row (2 repeats min) to pick one representative row and report once. Disabled by default: doesn't decrypt the rolling code and the id/code field semantics are unconfirmed (per the file's own doc comment). --- README.md | 2 +- conf/rtl_433.example.conf | 2 +- src/devices/fordremote.c | 65 ++++++++++++++++++--------------------- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index dcee06ab..39cd1aba 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md). [90] Renault TPMS [91] inFactory, nor-tec, FreeTec NC-3982-913 temperature humidity sensor [92] FT-004-B Temperature Sensor - [93] Ford Car Key + [93]* Ford Car Key [94] Philips outdoor temperature sensor (type AJ3650) [95] Schrader TPMS EG53MA4, Saab, Opel, Vauxhall, Chevrolet [96] Nexa diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf index 708c563e..82f88826 100644 --- a/conf/rtl_433.example.conf +++ b/conf/rtl_433.example.conf @@ -332,7 +332,7 @@ convert si protocol 90 # Renault TPMS protocol 91 # inFactory, nor-tec, FreeTec NC-3982-913 temperature humidity sensor protocol 92 # FT-004-B Temperature Sensor - protocol 93 # Ford Car Key +# protocol 93 # Ford Car Key protocol 94 # Philips outdoor temperature sensor (type AJ3650) protocol 95 # Schrader TPMS EG53MA4, Saab, Opel, Vauxhall, Chevrolet protocol 96 # Nexa diff --git a/src/devices/fordremote.c b/src/devices/fordremote.c index 634e4e60..a5c64bfc 100644 --- a/src/devices/fordremote.c +++ b/src/devices/fordremote.c @@ -25,41 +25,35 @@ The output changed and the fields are very likely not as intended. static int fordremote_callback(r_device *decoder, bitbuffer_t *bitbuffer) { - data_t *data; - uint8_t *bytes; - int found = 0; - int device_id, code; - - // expect {1} {9} {1} preamble - for (int i = 3; i < bitbuffer->num_rows; i++) { - if (bitbuffer->bits_per_row[i] < 78) { - continue; // DECODE_ABORT_LENGTH - } - - // Validate preamble - if (bitbuffer->bits_per_row[i - 3] != 1 || bitbuffer->bits_per_row[i - 1] != 1 - || bitbuffer->bits_per_row[i - 2] != 9 || bitbuffer->bb[i - 2][0] != 0) { - continue; // DECODE_ABORT_EARLY - } - - decoder_log_bitbuffer(decoder, 1, __func__, bitbuffer, ""); - - bytes = bitbuffer->bb[i]; - device_id = (bytes[0] << 16) | (bytes[1] << 8) | bytes[2]; - code = bytes[7]; - - /* clang-format off */ - data = data_make( - "model", "model", DATA_STRING, "Ford-CarRemote", - "id", "device-id", DATA_INT, device_id, - "code", "data", DATA_INT, code, - NULL); - decoder_output_data(decoder, data); - /* clang-format on */ - - found++; + // find a 78 bit payload row repeated at least twice (real transmissions + // send several identical repeats; this reports each capture only once) + int r = bitbuffer_find_repeated_row(bitbuffer, 2, 78); + if (r < 3) { + return DECODE_ABORT_LENGTH; } - return found; + + // expect {1} {9} {1} preamble immediately before the payload row + if (bitbuffer->bits_per_row[r - 3] != 1 || bitbuffer->bits_per_row[r - 1] != 1 + || bitbuffer->bits_per_row[r - 2] != 9 || bitbuffer->bb[r - 2][0] != 0) { + return DECODE_ABORT_EARLY; + } + + decoder_log_bitbuffer(decoder, 1, __func__, bitbuffer, ""); + + uint8_t *bytes = bitbuffer->bb[r]; + int device_id = (bytes[0] << 16) | (bytes[1] << 8) | bytes[2]; + int code = bytes[7]; + + /* clang-format off */ + data_t *data = data_make( + "model", "model", DATA_STRING, "Ford-CarRemote", + "id", "device-id", DATA_INT, device_id, + "code", "data", DATA_INT, code, + NULL); + decoder_output_data(decoder, data); + /* clang-format on */ + + return 1; } static char const *const output_fields[] = { @@ -74,8 +68,9 @@ r_device const fordremote = { .modulation = OOK_PULSE_DMC, .short_width = 250, // half-bit width is 250 us .long_width = 500, // bit width is 500 us - .reset_limit = 4000, // sync gap is 3500 us, preamble gap is 38400 us, packet gap is 52000 us + .reset_limit = 55000, // sync gap is 3500 us, preamble gap is 38400 us, packet gap is 52000 us .tolerance = 50, .decode_fn = &fordremote_callback, .fields = output_fields, + .disabled = 1, // does not attempt to decrypt the rolling code, id/code semantics are unconfirmed };