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).
This commit is contained in:
Benjamin Larsson
2026-07-18 20:03:43 +02:00
parent 4e127c7d30
commit 23fbfead7b
3 changed files with 32 additions and 37 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
};