Bugfixes
[rtl-433.git] / src / devices / lacrosse_TX141TH_Bv2.c
1 /* LaCrosse Color Forecast Station (model C85845), or other LaCrosse product 
2  * utilizing the remote temperature/humidity sensor TX141TH-Bv2 transmitting
3  * in the 433.92 MHz band. Product pages:
4  * http://www.lacrossetechnology.com/c85845-color-weather-station/
5  * http://www.lacrossetechnology.com/tx141th-bv2-temperature-humidity-sensor
6  *
7  * The TX141TH-Bv2 protocol is OOK modulated PWM with fixed period of 625 us
8  * for data bits, preambled by four long startbit pulses of fixed period equal
9  * to ~1666 us. Hence, it is similar to Bresser Thermo-/Hygro-Sensor 3CH (bresser_3ch.c
10  * included in this source code) with the exception that OOK_PULSE_PWM_TERNARY
11  * modulation type is technically more correct than OOK_PULSE_PWM_RAW.
12  *
13  * A single data packet looks as follows:
14  * 1) preamble - 833 us high followed by 833 us low, repeated 4 times:
15  *  ----      ----      ----      ----
16  * |    |    |    |    |    |    |    |
17  *       ----      ----      ----      ----
18  * 2) a train of 40 data pulses with fixed 625 us period follows immediately:
19  *  ---    --     --     ---    ---    --     ---
20  * |   |  |  |   |  |   |   |  |   |  |  |   |   |
21  *      --    ---    ---     --     --    ---     -- ....
22  * A logical 1 is 417 us of high followed by 208 us of low.
23  * A logical 0 is 208 us of high followed by 417 us of low.
24  * Thus, in the pictorial example above the bits are 1 0 0 1 1 0 1 ....
25  *
26  * The TX141TH-Bv2 sensor sends 12 of identical packets, one immediately following 
27  * the other, in a single burst. These 12-packet bursts repeat every 50 seconds. At 
28  * the end of the last packet there are two 833 us pulses ("post-amble"?).
29  *
30  * The data is grouped in 5 bytes / 10 nybbles
31  * [id] [id] [flags] [temp] [temp] [temp] [humi] [humi] [chk] [chk]
32  *
33  * The "id" is an 8 bit random integer generated when the sensor powers up for the 
34  * first time; "flags" are 4 bits for battery low indicator, test button press, 
35  * and channel; "temp" is 12 bit unsigned integer which encodes temperature in degrees
36  * Celsius as follows:
37  * temp_c = temp/10 - 50 
38  * to account for the -40 C -- 60 C range; "humi" is 8 bit integer indicating 
39  * relative humidity in %. The method of calculating "chk", the presumed 8-bit checksum
40  * remains a complete mystery at the moment of this writing, and I am not totally sure 
41  * if the last is any kind of CRC. I've run reveng 1.4.4 on exemplary data with all
42  * available CRC algorithms and found no match. Be my guest if you want to
43  * solve it - for example, if you figure out why the following two pairs have identical
44  * checksums you'll become a hero:
45  *
46  * 0x87 0x02 0x3c 0x3b 0xe1
47  * 0x87 0x02 0x7d 0x37 0xe1
48  *
49  * 0x87 0x01 0xc3 0x31 0xd8
50  * 0x87 0x02 0x28 0x37 0xd8
51  *
52  * Developer's comment 1: because of our choice of the OOK_PULSE_PWM_TERNARY type, the input
53  * array of bits will look like this:
54  * bitbuffer:: Number of rows: 25
55  *  [00] {0} :
56  *  [01] {0} :
57  *  [02] {0} :
58  *  [03] {0} :
59  *  [04] {40} 87 02 67 39 f6
60  *  [05] {0} :
61  *  [06] {0} :
62  *  [07] {0} :
63  *  [08] {40} 87 02 67 39 f6
64  *  [09] {0} :
65  *  [10] {0} :
66  *  [11] {0} :
67  *  [12] {40} 87 02 67 39 f6
68  *  [13] {0} :
69  *  [14] {0} :
70  *  [15] {0} :
71  *  [16] {40} 87 02 67 39 f6
72  *  [17] {0} :
73  *  [18] {0} :
74  *  [19] {0} :
75  *  [20] {40} 87 02 67 39 f6
76  *  [21] {0} :
77  *  [22] {0} :
78  *  [23] {0} :
79  *  [24] {280} 87 02 67 39 f6 87 02 67 39 f6 87 02 67 39 f6 87 02 67 39 f6 87 02 67 39 f6 87 02 67 39 f6 87 02 67 39 f6
80  * which is a direct consequence of two factors: (1) pulse_demod_pwm_ternary() always assuming
81  * only one startbit, and (2) bitbuffer_add_row() not adding rows beyond BITBUF_ROWS. This is
82  * OK because the data is clearly processable and the unique pattern minimizes the chance of
83  * confusion with other sensors, particularly Bresser 3CH.
84  *
85  * Developer's comment 2: with unknown CRC (see above) the obvious way of checking the data
86  * integrity is making use of the 12 packet repetition. In principle, transmission errors are
87  * be relatively rare, thus the most frequent packet (statistical mode) should represent
88  * the true data. Therefore, in the fisrt part of the callback routine the mode is determined
89  * for the first 4 bytes of the data compressed into a single 32-bit integer. Since the packet
90  * count is small, no sophisticated mode algorithm is necessary; a simple array of <data,count>
91  * structures is sufficient. The added bonus is that relative count enables us to determine
92  * the quality of radio transmission.
93  *
94  * Copyright (C) 2017 Robert Fraczkiewicz   (aromring@gmail.com)
95  * This program is free software; you can redistribute it and/or modify
96  * it under the terms of the GNU General Public License as published by
97  * the Free Software Foundation; either version 2 of the License, or
98  * (at your option) any later version.
99  *
100  */
101 #include "data.h"
102 #include "rtl_433.h"
103 #include "util.h"
104
105 #define LACROSSE_TX141TH_BITLEN 40
106 #define LACROSSE_TX141TH_BYTELEN 5  // = LACROSSE_TX141TH_BITLEN / 8
107 #define LACROSSE_TX141TH_PACKETCOUNT 12
108
109 typedef struct {
110     int32_t     data;   // First 4 data bytes compressed into 32-bit integer
111     int8_t count;       // Count
112 } data_and_count;
113
114 static int lacrosse_tx141th_bv2_callback(bitbuffer_t *bitbuffer) {
115         bitrow_t *bb = bitbuffer->bb;
116         data_t *data;
117         char time_str[LOCAL_TIME_BUFLEN];
118     local_time_str(0, time_str);
119         int i,j,k,nbytes,npacket,kmax;
120     uint8_t id=0,status=0,battery_low=0,test=0,humidity=0,maxcount;
121     uint16_t temp_raw=0;
122     float temp_f=0.0;
123     data_and_count dnc[LACROSSE_TX141TH_PACKETCOUNT] = {0};
124     
125     if (debug_output) {
126         bitbuffer_print(bitbuffer);
127     }
128     
129     npacket=0; // Number of unique packets
130     for(i=0; i<BITBUF_ROWS; ++i) {
131         j=bitbuffer->bits_per_row[i];
132         if(j>=LACROSSE_TX141TH_BITLEN) {
133             nbytes=j/8;
134             for(j=0;j<nbytes;j+=LACROSSE_TX141TH_BYTELEN) {
135                 uint32_t *d=(uint32_t *)(bb[i]+j);
136                 uint8_t not_found=1;
137                 for(k=0;k<npacket;++k) {
138                     if(*d==dnc[k].data) {
139                         ++(dnc[k].count);
140                         not_found=0;
141                         break;
142                     }
143                 }
144                 if(not_found) {
145                     dnc[npacket].data=*d;
146                     dnc[npacket].count=1;
147                     if(npacket+1<LACROSSE_TX141TH_PACKETCOUNT) ++npacket;
148                 }
149             }
150         }
151     }
152  
153     if (debug_output) {
154         fprintf(stderr, "%d unique packet(s)\n", npacket);
155         for(k=0;k<npacket;++k) {
156             fprintf(stderr, "%08x \t %d \n", dnc[k].data,dnc[k].count);
157         }
158     }
159
160     // Find the most frequent data packet, if necessary
161     kmax=0;
162     maxcount=0;
163     if(npacket>1) {
164         for(k=0;k<npacket;++k) {
165             if(dnc[k].count>maxcount) {
166                 maxcount=dnc[k].count;
167                 kmax=k;
168             }
169         }
170     }
171     
172     // Unpack the data bytes back to eliminate dependence on the platform endiannes!
173     uint8_t *bytes=(uint8_t*)(&(dnc[kmax].data));
174     id=bytes[0];
175     status=bytes[1];
176     battery_low=(status & 0x80) >> 7;
177     test=(status & 0x40) >> 6;
178     temp_raw=((status & 0x0F) << 8) + bytes[2];
179     temp_f = 9.0*((float)temp_raw)/50.0-58.0; // Temperature in F
180     humidity = bytes[3];
181
182     if (0==id || 0==humidity || humidity > 100 || temp_f < -40.0 || temp_f > 140.0) {
183         if (debug_output) {
184             fprintf(stderr, "LaCrosse TX141TH-Bv2 data error\n");
185         }
186         return 0;
187     }
188
189     data = data_make("time",    "Date and time", DATA_STRING,    time_str,
190                      "temperature", "Temperature in deg F", DATA_FORMAT, "%.2f F", DATA_DOUBLE, temp_f,
191                      "humidity",    "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
192                      "id",      "Sensor ID",  DATA_FORMAT, "%02x", DATA_INT, id,
193                      "model",   "", DATA_STRING,    "LaCrosse TX141TH-Bv2 sensor",
194                      "battery", "Battery",  DATA_STRING, battery_low ? "LOW" : "OK",
195                      "test",    "Test?",  DATA_STRING, test ? "Yes" : "No",
196                       NULL);
197     data_acquired_handler(data);
198         
199     return 1; 
200         
201 }
202
203 static char *output_fields[] = {
204         "time",
205         "temperature",
206         "humidity",
207         "id",
208         "model",
209         "battery",
210         "test",
211         NULL
212 };
213
214 r_device lacrosse_TX141TH_Bv2 = {
215   .name          = "LaCrosse TX141TH-Bv2 sensor",
216   .modulation    = OOK_PULSE_PWM_TERNARY,
217   .short_limit   = 312,     // short pulse is ~208 us, long pulse is ~417 us
218   .long_limit    = 625,     // long gap (with short pulse) is ~417 us, sync gap is ~833 us
219   .reset_limit   = 1500,   // maximum gap is 1250 us (long gap + longer sync gap on last repeat)
220   .json_callback = &lacrosse_tx141th_bv2_callback,
221   .disabled      = 0,
222   .demod_arg     = 2,       // Longest pulses are startbits
223   .fields        = output_fields,
224 };
225