diff --git a/README.md b/README.md index 06b3ab32..830f1799 100644 --- a/README.md +++ b/README.md @@ -452,6 +452,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md). [362] Jansite TPMS TY588-EU2 [363] Oregon Scientific WMR500 weather station [364] Elsner Solexa 230V + [365] Mercedes Benz Sprinter 4500 TPMS sensor * Disabled by default, use -R n or a conf file to enable diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf index c1d81e3f..7ba0d621 100644 --- a/conf/rtl_433.example.conf +++ b/conf/rtl_433.example.conf @@ -604,6 +604,7 @@ convert si protocol 362 # Jansite TPMS TY588-EU2 protocol 363 # Oregon Scientific WMR500 weather station protocol 364 # Elsner Solexa 230V + protocol 365 # Mercedes Benz Sprinter 4500 TPMS sensor ## Flex devices (command line option "-X") diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h index 93155e1e..c0a78d16 100644 --- a/include/rtl_433_devices.h +++ b/include/rtl_433_devices.h @@ -372,6 +372,7 @@ DECL(tpms_jansite_ty588) \ DECL(oregon_scientific_wmr500) \ DECL(elsner_solexa) \ + DECL(tpms_mercedes_benz) \ /* Add new decoders here. */ #define DECL(name) extern r_device const name; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4566800..3e5e3377 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -329,6 +329,7 @@ add_library(r_433 STATIC devices/tpms_jansite_ty468.c devices/tpms_jansite_ty588.c devices/tpms_kia.c + devices/tpms_mercedes_benz.c devices/tpms_nissan.c devices/tpms_pmv107j.c devices/tpms_porsche.c diff --git a/src/devices/tpms_mercedes_benz.c b/src/devices/tpms_mercedes_benz.c new file mode 100644 index 00000000..ad2707aa --- /dev/null +++ b/src/devices/tpms_mercedes_benz.c @@ -0,0 +1,120 @@ +/** @file + Mercedes Benz Sprinter TPMS data. + + Copyright (C) 2026 Bruno OCTAU (ProfBoc75) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ +/** +Mercedes Benz Sprinter TPMS data. + +issue #3539: +- 2025 Mercedes Benz Sprinter 4500 TPMS sensor +- Signal is FSK MC and pulse width 25us. +- Preamble {12} 0x002 or 0xff2 + +Data Layout: + + Preamble Byte 0 1 2 3 4 5 6 7 8 9 + 002 or ff2 ST II II II II PP TT CC FF XX + +- ST: {8} Family/state byte, observed as 0x83 while stationary and 0xa3 while + moving. These capture-derived values are not known to be exhaustive. +- II: {32} ID / Serial number +- PP: {8} Pressure, PSI, scale 2.75 +- TT: {8} Temperature, C, offset 51 +- CC: {8} Counter, increase by 1 each message +- FF: {8} Status, observed as 0x6b, 0xe9, or 0xea +- XX: {8} CRC-8 of the previous 9 bytes, poly 0x2f, init 0xaa, final XOR 0x00 + +*/ + +#include "decoder.h" + +static int tpms_mercedes_benz_decode(r_device *decoder, bitbuffer_t *bitbuffer) +{ + uint8_t const preamble[] = {0x00,0x20}; // 12 bit , 0x002 + uint8_t b[10]; + + if (bitbuffer->num_rows != 1) { + decoder_logf(decoder, 2, __func__, "row error"); + return DECODE_ABORT_EARLY; + } + + int pos = bitbuffer_search(bitbuffer, 0, 0, preamble, 12); + if (pos >= bitbuffer->bits_per_row[0]) { + decoder_logf(decoder, 2, __func__, "Preamble 0x002 not found"); + return DECODE_ABORT_EARLY; + } + + if (bitbuffer->bits_per_row[0] < 80) { + decoder_logf(decoder, 1, __func__, "Too short"); + return DECODE_ABORT_LENGTH; + } + + pos += 12; + bitbuffer_extract_bytes(bitbuffer, 0, pos, b, 80); + + decoder_log_bitrow(decoder, 2, __func__, b, 80, "MSG"); + + if (crc8(b, 10, 0x2f, 0xaa)) { + decoder_logf(decoder, 1, __func__, "crc error, expected %02x, calculated %02x", b[9], crc8(b, 9, 0x2f, 0xaa)); + return DECODE_FAIL_MIC; // crc mismatch + } + + if (b[0] != 0x83 && b[0] != 0xa3) { + decoder_logf(decoder, 1, __func__, "unexpected family/state byte %02x", b[0]); + return DECODE_FAIL_SANITY; + } + + char id_str[4 * 2 + 1]; + snprintf(id_str, sizeof(id_str), "%02x%02x%02x%02x", b[1], b[2], b[3], b[4]); + float pressure_PSI = b[5] / 2.75f; + int temperature_C = b[6] - 51; + int counter = b[7] & 0x1f; + int flags1 = b[7] >> 5; + int flags2 = b[8]; + + /* clang-format off */ + data_t *data = data_make( + "model", "", DATA_STRING, "MercedesBenz-Sprinter", + "type", "", DATA_STRING, "TPMS", + "id", "", DATA_STRING, id_str, + "pressure_PSI", "Pressure", DATA_FORMAT, "%.1f PSI", DATA_DOUBLE, (double)pressure_PSI, + "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, (double)temperature_C, + "counter", "Counter", DATA_INT, counter, + "flags1", "Flags 1", DATA_FORMAT, "0b%03b", DATA_INT, flags1, + "flags2", "Flags 2", DATA_INT, flags2, + "mic", "Integrity", DATA_STRING, "CRC", + NULL); + /* clang-format on */ + + decoder_output_data(decoder, data); + return 1; +} + +static char const *const output_fields[] = { + "model", + "type", + "id", + "pressure_PSI", + "temperature_C", + "counter", + "flags1", + "flags2", + "mic", + NULL, +}; + +r_device const tpms_mercedes_benz = { + .name = "Mercedes Benz Sprinter 4500 TPMS sensor", + .modulation = FSK_PULSE_MANCHESTER_ZEROBIT, + .short_width = 25, + .long_width = 25, + .reset_limit = 2000, + .decode_fn = &tpms_mercedes_benz_decode, + .fields = output_fields, +};