Bugfixes
[rtl-433.git] / src / devices / calibeur.c
1 /* Shenzhen Calibeur Industries Co. Ltd Wireless Thermometer RF-104 Temperature/Humidity sensor
2  * aka Biltema Art. 84-056 (Sold in Denmark)
3  * aka ...
4  *
5  * NB. Only 3 unique sensors can be detected!
6  *
7  * Update (LED flash) each 2:53
8  *
9  * Pulse Width Modulation with fixed rate and startbit 
10  * Startbit     = 390 samples = 1560 µs
11  * Short pulse  = 190 samples =  760 µs = Logic 0
12  * Long pulse   = 560 samples = 2240 µs = Logic 1
13  * Pulse rate   = 740 samples = 2960 µs
14  * Burst length = 81000 samples = 324 ms
15  *
16  * Sequence of 5 times 21 bit separated by start bit (total of 111 pulses)
17  * S 21 S 21 S 21 S 21 S 21 S
18  * 
19  * Channel number is encoded into fractional temperature
20  * Temperature is oddly arranged and offset for negative temperatures = <6543210> - 41 C
21  * Allways an odd number of 1s (odd parity) 
22  *
23  * Encoding legend:
24  * f = fractional temperature + <ch no> * 10
25  * 0-6 = integer temperature + 41C
26  * p = parity
27  * H = Most significant bits of humidity [5:6]
28  * h = Least significant bits of humidity [0:4]
29  *
30  * LSB                 MSB
31  * ffffff45 01236pHH hhhhh Encoding
32 */
33 #include "rtl_433.h"
34 #include "util.h"
35 #include "data.h"
36
37 //static int calibeur_rf104_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) {
38 static int calibeur_rf104_callback(bitbuffer_t *bitbuffer) {
39         data_t *data;
40         char time_str[LOCAL_TIME_BUFLEN];
41
42         uint8_t ID;
43         float temperature;
44         float humidity;
45         bitrow_t *bb = bitbuffer->bb;
46
47         // Validate package (row [0] is empty due to sync bit)
48         if ((bitbuffer->bits_per_row[1] == 21)                  // Dont waste time on a long/short package
49          && (crc8(bb[1], 3, 0x80, 0) != 0)              // It should be odd parity
50          && (memcmp(bb[1], bb[2], 3) == 0)      // We want at least two messages in a row
51         )
52         {
53                 uint8_t bits;
54
55                 bits  = ((bb[1][0] & 0x80) >> 7);       // [0]
56                 bits |= ((bb[1][0] & 0x40) >> 5);       // [1]
57                 bits |= ((bb[1][0] & 0x20) >> 3);       // [2]
58                 bits |= ((bb[1][0] & 0x10) >> 1);       // [3]
59                 bits |= ((bb[1][0] & 0x08) << 1);       // [4]
60                 bits |= ((bb[1][0] & 0x04) << 3);       // [5]
61                 ID = bits / 10;
62                 temperature = (float)(bits % 10) / 10.0;
63
64                 bits  = ((bb[1][0] & 0x02) << 3);       // [4]
65                 bits |= ((bb[1][0] & 0x01) << 5);       // [5]
66                 bits |= ((bb[1][1] & 0x80) >> 7);       // [0]
67                 bits |= ((bb[1][1] & 0x40) >> 5);       // [1]
68                 bits |= ((bb[1][1] & 0x20) >> 3);       // [2]
69                 bits |= ((bb[1][1] & 0x10) >> 1);       // [3]
70                 bits |= ((bb[1][1] & 0x08) << 3);       // [6]
71                 temperature += (float)bits - 41.0;
72
73                 bits  = ((bb[1][1] & 0x02) << 4);       // [5]
74                 bits |= ((bb[1][1] & 0x01) << 6);       // [6]
75                 bits |= ((bb[1][2] & 0x80) >> 7);       // [0]
76                 bits |= ((bb[1][2] & 0x40) >> 5);       // [1]
77                 bits |= ((bb[1][2] & 0x20) >> 3);       // [2]
78                 bits |= ((bb[1][2] & 0x10) >> 1);       // [3]
79                 bits |= ((bb[1][2] & 0x08) << 1);       // [4]
80                 humidity = bits;
81
82                 local_time_str(0, time_str);
83                 data = data_make("time",          "",            DATA_STRING, time_str,
84                                                 "model",         "",            DATA_STRING, "Calibeur RF-104",
85                                                 "id",            "ID",          DATA_INT, ID,
86                                                 "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temperature,
87                                                 "humidity",      "Humidity",    DATA_FORMAT, "%2.0f %%", DATA_DOUBLE, humidity,
88                                                 NULL);
89                 data_acquired_handler(data);
90                 return 1;
91         }
92         return 0;
93 }
94
95 static char *output_fields[] = {
96         "time",
97         "model",
98         "id",
99         "temperature_C",
100         "humidity",
101         NULL
102 };
103
104 r_device calibeur_RF104 = {
105         .name           = "Calibeur RF-104 Sensor",
106         .modulation     = OOK_PULSE_PWM_TERNARY,
107         .short_limit    = 1160, // Short pulse 760µs, Startbit 1560µs, Long pulse 2240µs
108         .long_limit     = 1900, // Maximum pulse period (long pulse + fixed gap)
109         .reset_limit    = 3200, // Longest gap (2960-760µs)
110         .json_callback  = &calibeur_rf104_callback,
111         .disabled       = 0,
112         .demod_arg      = 1             // Startbit is middle bit
113 };