Bugfixes
[rtl-433.git] / src / devices / rubicson.c
1 #include "rtl_433.h"
2 #include "data.h"
3 #include "util.h"
4 /* Currently this can decode the temperature and id from Rubicson sensors
5  *
6  * the sensor sends 36 bits 12 times pwm modulated
7  * the data is grouped into 9 nibles
8  * [id0] [id1], [bat|unk1|chan1|chan2] [temp0], [temp1] [temp2], [F] [crc1], [crc2]
9  *
10  * The id changes when the battery is changed in the sensor.
11  * bat bit is 1 if battery is ok, 0 if battery is low
12  * chan1 and chan2 forms a 2bit value for the used channel
13  * unk1 is always 0 probably unused
14  * temp is 12 bit signed scaled by 10
15  * F is always 0xf
16  * crc1 and crc2 forms a 8-bit crc
17  *
18  * The sensor can be bought at Kjell&Co
19  */
20
21
22 /* Working routine for checking the crc, lots of magic but it works */
23
24 //static uint8_t rp[] = {0xb8, 0x80, 0xea, 0xfe, 0x80};
25 static uint8_t rp[] = {0xea, 0x8f, 0x6a, 0xfa, 0x50};
26
27 int rubicson_crc_check(bitrow_t *bb) {
28     uint8_t crc, w;
29     uint8_t diff[9];
30     int i, ret;
31
32     // diff against ref packet
33
34     diff[0] = rp[0]^bb[1][0];
35     diff[1] = rp[1]^bb[1][1];
36     diff[2] = rp[2]^bb[1][2];
37     diff[3] = rp[3]^bb[1][3];
38     diff[4] = rp[4]^bb[1][4];
39
40 //    fprintf(stdout, "%02x %02x %02x %02x %02x\n",rp[0],rp[1],rp[2],rp[3],rp[4]);
41 //    fprintf(stdout, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]);
42 //    fprintf(stdout, "%02x %02x %02x %02x %02x\n",diff[0],diff[1],diff[2],diff[3],diff[4]);
43
44     for (crc = 0, w = 0xf1, i = 0; i<7 ; i++){
45         uint8_t c = diff[i/2];
46         unsigned digit = (i&1) ? c&0xF : (c&0xF0)>>4;
47         unsigned j;
48         for (j=4; j-->0; ) {
49             if ((digit >> j) & 1)
50                 crc ^= w;
51             w = (w >> 1) ^ ((w & 1) ? 0x98: 0);
52         }
53     }
54     if (crc == (((diff[3]<<4)&0xF0) | (diff[4]>>4)))
55 //      printf ("\ncrc ok: %x\n", crc);
56         ret = 1;
57     else
58 //      printf ("\ncrc fail: %x\n", crc);
59         ret = 0;
60
61         return ret;
62 };
63
64 static int rubicson_callback(bitbuffer_t *bitbuffer) {
65     bitrow_t *bb = bitbuffer->bb;
66     int temperature_before_dec;
67     int temperature_after_dec, i;
68     int16_t temp;
69     int8_t rh, csum, csum_calc, sum=0;
70     unsigned bits = bitbuffer->bits_per_row[0];
71     data_t *data;
72
73     char time_str[LOCAL_TIME_BUFLEN];
74     uint8_t channel;
75     uint8_t sensor_id;
76     uint8_t battery;
77     float temp_c;
78
79     if (!(bits == 36))
80         return 0;
81
82     if (rubicson_crc_check(bb)) {
83         local_time_str(0, time_str);
84
85         /* Nible 3,4,5 contains 12 bits of temperature
86          * The temerature is signed and scaled by 10 */
87         temp = (int16_t)((uint16_t)(bb[0][1] << 12) | (bb[0][2] << 4));
88         temp = temp >> 4;
89
90         channel = ((bb[0][1]&0x30)>>4)+1;
91         battery = (bb[0][1]&0x80);
92         sensor_id = bb[0][0];
93         temp_c = (float) temp / 10.0;
94
95         data = data_make("time",         "",            DATA_STRING, time_str,
96                         "model",         "",            DATA_STRING, "Rubicson Temperature Sensor",
97                         "id",            "House Code",  DATA_INT,    sensor_id,
98                         "channel",       "Channel",     DATA_INT,    channel,
99                         "battery",       "Battery",     DATA_STRING, battery ? "OK" : "LOW",
100                         "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
101                         "crc",           "CRC",         DATA_STRING, "OK",
102                         NULL);
103         data_acquired_handler(data);
104
105         return 1;
106     }
107     return 0;
108 }
109
110 static char *output_fields[] = {
111         "time",
112         "model",
113         "id",
114         "channel",
115         "battery",
116         "temperature_C",
117         "crc",
118         NULL
119 };
120
121
122 // timings based on samp_rate=1024000
123 r_device rubicson = {
124     .name           = "Rubicson Temperature Sensor",
125     .modulation     = OOK_PULSE_PPM_RAW,
126     .short_limit    = 488+970,      // Gaps:  Short 976µs, Long 1940µs, Sync 4000µs
127     .long_limit     = 970+2000,     // Pulse: 500µs (Initial pulse in each package is 388µs)
128     .reset_limit    = 4800,             // Two initial pulses and a gap of 9120µs is filtered out
129     .json_callback  = &rubicson_callback,
130     .disabled       = 0,
131     .demod_arg      = 0,
132     .fields         = output_fields,
133 };
134