diff --git a/README.md b/README.md
index 36747665..8397fdff 100644
--- a/README.md
+++ b/README.md
@@ -289,6 +289,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[203] Porsche Boxster/Cayman TPMS
[204] Jasco/GE Choice Alert Security Devices
[205] Telldus weather station FT0385R sensors
+ [206] LaCrosse TX34-IT rain gauge
* Disabled by default, use -R n or -G
diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf
index e30e4769..7e52a9fd 100644
--- a/conf/rtl_433.example.conf
+++ b/conf/rtl_433.example.conf
@@ -426,6 +426,7 @@ stop_after_successful_events false
protocol 203 # Porsche Boxster/Cayman TPMS
protocol 204 # Jasco/GE Choice Alert Security Devices
protocol 205 # Telldus weather station FT0385R sensors
+ protocol 206 # LaCrosse TX34-IT rain gauge
## Flex devices (command line option "-X")
diff --git a/src/devices/lacrosse_tx34.c b/src/devices/lacrosse_tx34.c
index d0a96523..314f767f 100644
--- a/src/devices/lacrosse_tx34.c
+++ b/src/devices/lacrosse_tx34.c
@@ -25,9 +25,9 @@ The LaCrosse "IT+" family share some specifications:
Frame format:
-------------
-| 1010 1010 | preamble (up to the first two bits may be lost)
+| 1010 1010 | preamble (some bits may be lost)
-------------
-| 0010 1101 | 0x2DD4: LaCrosse IT frame identifier
+| 0010 1101 | 0x2dd4: sync word
| 1101 0100 |
-------------
| MMMM DDDD | MMMM: sensor model (5 for rain gauge, 9 for thermo/hydro...)
@@ -35,7 +35,7 @@ Frame format:
| GGGG GGGG | N: new battery (on for about 420 minutes after startup)
| GGGG GGGG | W: weak battery (on when battery voltage < 2 volts)
------------- GGGGGGGGGGGGGGGG: bucket tipping counter
-| CCCC CCCC | CCCCCCCC: CRC8 on previous 4 bytes
+| CCCC CCCC | CCCCCCCC: CRC8 (poly 0x31 init 0x00) on previous 4 bytes
-------------
This decoder decodes generic LaCrosse IT+ frames and filters TX34 ones.
@@ -44,85 +44,61 @@ Could be merged with existing TX29 decoder... or not.
#include "decoder.h"
-#define LACROSSE_TX34_CRC_POLY 0x31
-#define LACROSSE_TX34_CRC_INIT 0x00
-#define LACROSSE_TX34_PREAMBLE_BITS 22
#define LACROSSE_TX34_ITMODEL 5
#define LACROSSE_TX34_PAYLOAD_BITS 40
#define LACROSSE_TX34_RAIN_FACTOR 0.222
static int lacrosse_tx34_callback(r_device *decoder, bitbuffer_t *bitbuffer)
{
- data_t *data;
- int row;
- uint8_t payload[5];
- uint8_t r_crc, c_crc;
- uint8_t sensor_id, new_bat, weak_bat;
- uint16_t rain_tick;
- float rain_mm;
- int events;
+ // 20 bits preamble (shifted left): 1010b 0x2DD4
+ uint8_t const preamble[] = {0xa2, 0xdd, 0x40};
- // 22 bits preamble (shifted left): 101010b 0x2DD4
- static const uint8_t preamble[] = {0xA8, 0xB7, 0x50};
-
- // process rows
- events = 0;
- for (row = 0; row <= bitbuffer->num_rows; ++row) {
+ // process all rows
+ int events = 0;
+ for (int row = 0; row < bitbuffer->num_rows; ++row) {
// search for preamble
- unsigned start_pos = bitbuffer_search(bitbuffer, row, 0, preamble,
- LACROSSE_TX34_PREAMBLE_BITS);
- if (start_pos == bitbuffer->bits_per_row[row])
+ unsigned start_pos = bitbuffer_search(bitbuffer, row, 0, preamble, 20) + 20;
+ if (start_pos + LACROSSE_TX34_PAYLOAD_BITS > bitbuffer->bits_per_row[row])
continue; // preamble not found
- unsigned payload_bits = bitbuffer->bits_per_row[row] - start_pos -
- LACROSSE_TX34_PREAMBLE_BITS;
- if (payload_bits < LACROSSE_TX34_PAYLOAD_BITS)
- continue; // probably truncated frame
- if (decoder->verbose)
- fprintf(stderr,
- "LaCrosse IT frame detected (%d bits payload)\n",
- payload_bits);
-
+ if (decoder->verbose > 1)
+ fprintf(stderr, "%s: LaCrosse IT frame detected\n", __func__);
// get payload
- bitbuffer_extract_bytes(bitbuffer, row,
- start_pos + LACROSSE_TX34_PREAMBLE_BITS,
- payload, LACROSSE_TX34_PAYLOAD_BITS);
+ uint8_t b[5];
+ bitbuffer_extract_bytes(bitbuffer, row, start_pos, b, LACROSSE_TX34_PAYLOAD_BITS);
// verify CRC
- r_crc = payload[4];
- c_crc = crc8(&payload[0], 4,
- LACROSSE_TX34_CRC_POLY, LACROSSE_TX34_CRC_INIT);
+ int r_crc = b[4];
+ int c_crc = crc8(b, 4, 0x31, 0x00);
if (r_crc != c_crc) {
// bad CRC: reject IT frame
if (decoder->verbose)
- fprintf(stderr,
- "LaCrosse IT frame bad CRC: calculated %02x, "
- "received %02x\n",
- c_crc, r_crc);
+ fprintf(stderr, "%s: LaCrosse IT frame bad CRC: calculated %02x, received %02x\n", __func__, c_crc, r_crc);
continue;
}
// check model
- if (((payload[0] & 0xF0) >> 4) != LACROSSE_TX34_ITMODEL)
+ if (((b[0] & 0xF0) >> 4) != LACROSSE_TX34_ITMODEL)
continue; // not a rain gauge...
// decode payload
- sensor_id = ((payload[0] & 0x0F) << 2) + (payload[1] >> 6);
- new_bat = (payload[1] & 0x20) >> 5;
- weak_bat = (payload[1] && 0x10) >> 4;
- rain_tick = (payload[2] << 8) + payload[3];
- rain_mm = rain_tick * LACROSSE_TX34_RAIN_FACTOR;
+ int sensor_id = ((b[0] & 0x0F) << 2) | (b[1] >> 6);
+ int new_batt = (b[1] & 0x20) >> 5;
+ int low_batt = (b[1] & 0x10) >> 4;
+ int rain_tick = (b[2] << 8) | b[3];
+ float rain_mm = rain_tick * LACROSSE_TX34_RAIN_FACTOR;
+
/* clang-format off */
- data = data_make(
- "model", "", DATA_STRING, "LaCrosse-TX34IT",
- "id", "", DATA_INT, sensor_id,
- "battery_ok", "Battery", DATA_INT, 1 - weak_bat,
- "newbattery", "New battery", DATA_INT, new_bat,
- "rain_mm", "Total rain", DATA_DOUBLE, rain_mm,
- "rain_raw", "Raw rain", DATA_INT, rain_tick,
- "mic", "Integrity", DATA_STRING, "CRC",
- NULL
- );
+ data_t *data = data_make(
+ "model", "", DATA_STRING, "LaCrosse-TX34IT",
+ "id", "", DATA_INT, sensor_id,
+ "battery_ok", "Battery", DATA_INT, !low_batt,
+ "newbattery", "New battery", DATA_INT, new_batt,
+ "rain_mm", "Total rain", DATA_DOUBLE, rain_mm,
+ "rain_raw", "Raw rain", DATA_INT, rain_tick,
+ "mic", "Integrity", DATA_STRING, "CRC",
+ NULL);
/* clang-format on */
+
decoder_output_data(decoder, data);
events++;
}
@@ -147,6 +123,5 @@ r_device lacrosse_tx34 = {
.long_width = 58,
.reset_limit = 4000,
.decode_fn = &lacrosse_tx34_callback,
- .disabled = 0,
.fields = output_fields,
};
diff --git a/src/devices/lacrosse_tx35.c b/src/devices/lacrosse_tx35.c
index 5f95b3da..8382c7c5 100644
--- a/src/devices/lacrosse_tx35.c
+++ b/src/devices/lacrosse_tx35.c
@@ -1,5 +1,5 @@
/** @file
- LaCrosse/StarMétéo/Conrad TX35 protocol.
+ LaCrosse/StarMeteo/Conrad TX35 protocol.
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
@@ -9,16 +9,16 @@
*/
/**
Generic decoder for LaCrosse "IT+" (instant transmission) protocol.
-Param device29or35 contain "29" or "35" depending of the device.
+Param device29or35 must be "29" or "35" depending of the device.
-LaCrosse/StarMétéo/Conrad TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity Sensors.
-LaCrosse/StarMétéo/Conrad TX29-IT, TFA Dostmann 30.3159.IT Temperature Sensors.
-Tune to 868240000Hz
+LaCrosse/StarMeteo/Conrad TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity Sensors.
+LaCrosse/StarMeteo/Conrad TX29-IT, TFA Dostmann 30.3159.IT Temperature Sensors.
+Found at 868240000Hz.
LaCrosse TX25U Temperature/Temperature Probe at 915 MHz
-Protocol
-========
+## Protocol
+
Example data : https://github.com/merbanan/rtl_433_tests/tree/master/tests/lacrosse/06/gfile-tx29.cu8
a a 2 d d 4 9 2 8 4 4 8 6 a e c
@@ -29,9 +29,9 @@ Example data : https://github.com/merbanan/rtl_433_tests/tree/master/tests/lacro
~~~~~~~~~ 1st byte
preamble, sequence 10B repeated 4 times (see below)
~~~~~~~~~~~~~~~~~~~ bytes 2 and 3
- brand identifier, always 0x2dd4
+ sync word of 0x2dd4
~~~~ 1st nibble of bytes 4
- datalength (always 9) in nibble, including this field and crc
+ sensor model (always 9)
~~~~ ~~ 2nd nibble of bytes 4 and 1st and 2nd bits of byte 5
Random device id (6 bits)
~ 3rd bits of byte 5
@@ -46,10 +46,10 @@ Example data : https://github.com/merbanan/rtl_433_tests/tree/master/tests/lacro
humidity, in%. If == 0x6a : no humidity sensor
If == 0x7d : temperature is actually second probe temperature channel
~~~~ ~~~~ byte 8
- crc8 of bytes
+ crc8 (poly 0x31 init 0x00) of bytes
+
+## Developer's comments
-Developer's comments
-====================
I have noticed that depending of the device, the message received has different length.
It seems some sensor send a long preamble (33 bits, 0 / 1 alternated), and some send only
six bits as the preamble. I own 3 sensors TX29, and two of them send a long preamble.
@@ -58,9 +58,9 @@ So this decoder synchronize on the following sequence:
1010 1000 1011 0111 0101 0010 01--
A 8 B 7 5 2 4
-- 0 - 5 : short preabmle [101010B]
-- 6 - 14 : brand identifier [2DD4h]
-- 15 - 19 : datalength [9]
+- 0 - 5 : short preamble [101010B]
+- 6 - 14 : sync word [2DD4h]
+- 15 - 19 : sensor model [9]
Short preamble example (sampling rate - 1Mhz):
https://github.com/merbanan/rtl_433_tests/tree/master/tests/lacrosse/06/gfile-tx29-short-preamble.cu8.
@@ -79,56 +79,46 @@ There's no way to distinguish between the TX35 and TX25U models
#define LACROSSE_TX29_NOHUMIDSENSOR 0x6a // Sensor do not support humidity
#define LACROSSE_TX25_PROBE_FLAG 0x7d // Humidity flag to indicate probe temperature channel
-#define LACROSSE_TX35_CRC_POLY 0x31
-#define LACROSSE_TX35_CRC_INIT 0x00
#define LACROSSE_TX29_MODEL 29 // Model number
#define LACROSSE_TX35_MODEL 35
static int lacrosse_it(r_device *decoder, bitbuffer_t *bitbuffer, int device29or35)
{
- data_t *data;
- int brow;
- uint8_t out[5];
- int r_crc, c_crc;
- int sensor_id, newbatt, battery_low;
- int humidity;
- float temp_c;
+ // 4 bits of preamble, sync word 2dd4, sensor model 9: 24 bit
+ uint8_t const preamble[] = {0xa2, 0xdd, 0x49};
+
int events = 0;
- static const uint8_t preamble[] = {
- 0xa8,
- 0xb7,
- 0x52,
- 0x40,
- };
-
- for (brow = 0; brow < bitbuffer->num_rows; ++brow) {
+ for (int row = 0; row < bitbuffer->num_rows; ++row) {
// Validate message and reject it as fast as possible : check for preamble
- unsigned int start_pos = bitbuffer_search(bitbuffer, brow, 0, preamble, 26);
+ unsigned int start_pos = bitbuffer_search(bitbuffer, row, 0, preamble, 24);
// no preamble detected, move to the next row
- if (start_pos == bitbuffer->bits_per_row[brow])
+ if (start_pos >= bitbuffer->bits_per_row[row])
continue; // DECODE_ABORT_EARLY
if (decoder->verbose)
- fprintf(stderr, "LaCrosse TX29/35 detected, buffer is %d bits length, device is TX%d\n", bitbuffer->bits_per_row[brow], device29or35);
+ fprintf(stderr, "%s: LaCrosse TX29/35 detected, buffer is %d bits length, device is TX%d\n", __func__, bitbuffer->bits_per_row[row], device29or35);
// remove preamble and keep only five octets
- bitbuffer_extract_bytes(bitbuffer, brow, start_pos+22, out, 40);
+ uint8_t b[5];
+ bitbuffer_extract_bytes(bitbuffer, row, start_pos + 20, b, 40);
- // Check message integrity (CRC/Checksum/parity)
- r_crc = out[4];
- c_crc = crc8(&out[0], 4, LACROSSE_TX35_CRC_POLY, LACROSSE_TX35_CRC_INIT);
+ // Check message integrity
+ int r_crc = b[4];
+ int c_crc = crc8(b, 4, 0x31, 0x00);
if (r_crc != c_crc) {
if (decoder->verbose)
- fprintf(stderr, "LaCrosse TX29/35 bad CRC: calculated %02x, received %02x\n", c_crc, r_crc);
+ fprintf(stderr, "%s: LaCrosse TX29/35 bad CRC: calculated %02x, received %02x\n", __func__, c_crc, r_crc);
// reject row
continue; // DECODE_FAIL_MIC
}
// message "envelope" has been validated, start parsing data
- sensor_id = ((out[0] & 0x0f) << 2) | (out[1] >> 6);
- temp_c = 10.0 * (out[1] & 0x0f) + 1.0 * ((out[2] >> 4) & 0x0f) + 0.1 * (out[2] & 0x0f) - 40.0;
- newbatt = (out[1] >> 5) & 1;
- battery_low = out[3] >> 7;
- humidity = out[3] & 0x7f;
+ int sensor_id = ((b[0] & 0x0f) << 2) | (b[1] >> 6);
+ float temp_c = 10.0 * (b[1] & 0x0f) + 1.0 * ((b[2] >> 4) & 0x0f) + 0.1 * (b[2] & 0x0f) - 40.0;
+ int new_batt = (b[1] >> 5) & 1;
+ int battery_low = b[3] >> 7;
+ int humidity = b[3] & 0x7f;
+
+ data_t *data;
if ((humidity == LACROSSE_TX29_NOHUMIDSENSOR) || (humidity == LACROSSE_TX25_PROBE_FLAG)) {
if (humidity == LACROSSE_TX25_PROBE_FLAG)
sensor_id += 0x40; // Change ID to distinguish between the main and probe channels
@@ -137,18 +127,19 @@ static int lacrosse_it(r_device *decoder, bitbuffer_t *bitbuffer, int device29or
"model", "", DATA_STRING, (device29or35 == 29 ? "LaCrosse-TX29IT" : "LaCrosse-TX35DTHIT"),
"id", "", DATA_INT, sensor_id,
"battery_ok", "Battery", DATA_INT, !battery_low,
- "newbattery", "NewBattery", DATA_INT, newbatt,
+ "newbattery", "NewBattery", DATA_INT, new_batt,
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */
- } else {
+ }
+ else {
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, (device29or35 == 29 ? "LaCrosse-TX29IT" : "LaCrosse-TX35DTHIT"),
"id", "", DATA_INT, sensor_id,
"battery_ok", "Battery", DATA_INT, !battery_low,
- "newbattery", "NewBattery", DATA_INT, newbatt,
+ "newbattery", "NewBattery", DATA_INT, new_batt,
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
"mic", "Integrity", DATA_STRING, "CRC",
@@ -181,36 +172,34 @@ static int lacrossetx35_callback(r_device *decoder, bitbuffer_t *bitbuffer)
}
static char *output_fields[] = {
- "model",
- "id",
- "battery_ok",
- "newbattery",
- "temperature_C",
- "humidity",
- "mic",
- NULL,
+ "model",
+ "id",
+ "battery_ok",
+ "newbattery",
+ "temperature_C",
+ "humidity",
+ "mic",
+ NULL,
};
// Receiver for the TX29 and TX25U device
r_device lacrosse_tx29 = {
- .name = "LaCrosse TX29IT, TFA Dostmann 30.3159.IT Temperature sensor",
- .modulation = FSK_PULSE_PCM,
- .short_width = 55, // 58 us for TX34-IT
- .long_width = 55, // 58 us for TX34-IT
- .reset_limit = 4000,
- .decode_fn = &lacrossetx29_callback,
- .disabled = 0,
- .fields = output_fields,
+ .name = "LaCrosse TX29IT, TFA Dostmann 30.3159.IT Temperature sensor",
+ .modulation = FSK_PULSE_PCM,
+ .short_width = 55, // 58 us for TX34-IT
+ .long_width = 55, // 58 us for TX34-IT
+ .reset_limit = 4000,
+ .decode_fn = &lacrossetx29_callback,
+ .fields = output_fields,
};
// Receiver for the TX35 device
r_device lacrosse_tx35 = {
- .name = "LaCrosse TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity sensor",
- .modulation = FSK_PULSE_PCM,
- .short_width = 105,
- .long_width = 105,
- .reset_limit = 4000,
- .decode_fn = &lacrossetx35_callback,
- .disabled = 0,
- .fields = output_fields,
+ .name = "LaCrosse TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity sensor",
+ .modulation = FSK_PULSE_PCM,
+ .short_width = 105,
+ .long_width = 105,
+ .reset_limit = 4000,
+ .decode_fn = &lacrossetx35_callback,
+ .fields = output_fields,
};
diff --git a/src/devices/m_bus.c b/src/devices/m_bus.c
index f7d27b72..81e15fd3 100644
--- a/src/devices/m_bus.c
+++ b/src/devices/m_bus.c
@@ -1146,6 +1146,7 @@ static int m_bus_mode_s_callback(r_device *decoder, bitbuffer_t *bitbuffer)
return 1;
}
+// NOTE: we'd need to add "value_types_tab X unit_names X n" fields
static char *output_fields[] = {
"model",
"mode",
diff --git a/vs15/rtl_433.vcxproj b/vs15/rtl_433.vcxproj
index dbac0e7e..1a0ebd94 100644
--- a/vs15/rtl_433.vcxproj
+++ b/vs15/rtl_433.vcxproj
@@ -263,6 +263,7 @@ COPY ..\..\libusb\MS64\dll\libusb*.dll $(TargetDir)
+
diff --git a/vs15/rtl_433.vcxproj.filters b/vs15/rtl_433.vcxproj.filters
index 87baba94..0edcfa9c 100644
--- a/vs15/rtl_433.vcxproj.filters
+++ b/vs15/rtl_433.vcxproj.filters
@@ -526,6 +526,9 @@
Source Files\devices
+
+ Source Files\devices
+
Source Files\devices