Bugfixes
[rtl-433.git] / src / devices / hideki.c
1 #include "rtl_433.h"
2 #include "pulse_demod.h"
3 #include "util.h"
4 #include "data.h"
5
6 #define HIDEKI_BYTES_PER_ROW 14
7
8 //    11111001 0  11110101 0  01110011 1 01111010 1  11001100 0  01000011 1  01000110 1  00111111  0 00001001 0  00010111 0
9 //    SYNC+HEAD P   RC cha P           P     Nr.? P   .1° 1°  P   10°  BV P   1%  10% P  ????SYNC    -------Check?------- P
10
11 //TS04:
12 //    00000000  11111111  22222222  33333333  44444444  55555555  66666666  77777777  88888888 99999999
13 //    SYNC+HEAD cha   RC                Nr.?    1° .1°  VB   10°   10%  1%  SYNC????  -----Check?------
14
15 //Wind:
16 //    00000000  11111111  22222222  33333333  44444444  55555555  66666666  77777777  88888888 99999999 AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
17 //    SYNC+HEAD cha   RC                Nr.?    1° .1°  VB   10°    1° .1°  VB   10°  .1mh 1mh  ?? 10mh   ????    w°  ??    ????     ????
18
19 enum sensortypes { HIDEKI_UNKNOWN, HIDEKI_TS04, HIDEKI_WIND, HIDEKI_RAIN };
20
21 static int hideki_ts04_callback(bitbuffer_t *bitbuffer) {
22     bitrow_t *bb = bitbuffer->bb;
23     uint8_t *b = bb[0];//TODO: handle the 3 row, need change in PULSE_CLOCK decoding
24
25     char time_str[LOCAL_TIME_BUFLEN];
26     data_t *data;
27     local_time_str(0, time_str);
28
29     uint8_t packet[HIDEKI_BYTES_PER_ROW];
30     int sensortype = HIDEKI_WIND; // default for 14 valid bytes
31     uint8_t channel, humidity, rc, battery_ok;
32     int temp, wind_strength, wind_direction, rain_units;
33
34     // Transform the incoming data:
35     //  * change endianness
36     //  * toggle each bits
37     //  * Remove (and check) parity bit
38     // TODO this may be factorise as a bitbuffer method (as for bitbuffer_manchester_decode)
39     for(int i=0; i<HIDEKI_BYTES_PER_ROW; i++){
40         unsigned int offset = i/8;
41         packet[i] = b[i+offset] << (i%8);
42         packet[i] |= b[i+offset+1] >> (8 - i%8);
43         // reverse as it is litle endian...
44         packet[i] = reverse8(packet[i]);
45         // toggle each bit
46         packet[i] ^= 0xFF;
47         // check parity
48         uint8_t parity = ((b[i+offset+1] >> (7 - i%8)) ^ 0xFF) & 0x01;
49         if(parity != byteParity(packet[i]))
50         {
51             if (i == 10) {
52                 sensortype = HIDEKI_TS04;
53                 break;
54             }
55             if (i == 9) {
56                 sensortype = HIDEKI_RAIN;
57                 break;
58             }
59             return 0;
60         }
61     }
62
63     // Read data
64     if(packet[0] == 0x9f){ //Note: it may exist other valid id
65         channel = (packet[1] >> 5) & 0x0F;
66         if(channel >= 5) channel -= 1;
67         rc = packet[1] & 0x0F;
68         temp = (packet[5] & 0x0F) * 100 + ((packet[4] & 0xF0) >> 4) * 10 + (packet[4] & 0x0F);
69         if(((packet[5]>>7) & 0x01) == 0){
70             temp = -temp;
71         }
72         battery_ok = (packet[5]>>6) & 0x01;
73         if (sensortype == HIDEKI_TS04) {
74             humidity = ((packet[6] & 0xF0) >> 4) * 10 + (packet[6] & 0x0F);
75             data = data_make("time",          "",              DATA_STRING, time_str,
76                              "model",         "",              DATA_STRING, "HIDEKI TS04 sensor",
77                              "rc",            "Rolling Code",  DATA_INT, rc,
78                              "channel",       "Channel",       DATA_INT, channel,
79                              "battery",       "Battery",       DATA_STRING, battery_ok ? "OK": "LOW",
80                              "temperature_C", "Temperature",   DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp/10.f,
81                              "humidity",      "Humidity",      DATA_FORMAT, "%u %%", DATA_INT, humidity,
82                              NULL);
83             data_acquired_handler(data);
84             return 1;
85         }
86         if (sensortype == HIDEKI_WIND) {
87             const uint8_t wd[] = { 0, 15, 13, 14, 9, 10, 12, 11, 1, 2, 4, 3, 8, 7, 5, 6 };
88             wind_direction = wd[((packet[11] & 0xF0) >> 4)] * 225;
89             wind_strength = (packet[9] & 0x0F) * 100 + ((packet[8] & 0xF0) >> 4) * 10 + (packet[8] & 0x0F);
90             data = data_make("time",          "",              DATA_STRING, time_str,
91                              "model",         "",              DATA_STRING, "HIDEKI Wind sensor",
92                              "rc",            "Rolling Code",  DATA_INT, rc,
93                              "channel",       "Channel",       DATA_INT, channel,
94                              "battery",       "Battery",       DATA_STRING, battery_ok ? "OK": "LOW",
95                              "temperature_C", "Temperature",   DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp/10.f,
96                              "windstrength",  "Wind Strength", DATA_FORMAT, "%.02f km/h", DATA_DOUBLE, wind_strength*0.160934f,
97                              "winddirection", "Direction",     DATA_FORMAT, "%.01f °", DATA_DOUBLE, wind_direction/10.f,
98                              NULL);
99             data_acquired_handler(data);
100             return 1;
101         }
102         if (sensortype == HIDEKI_RAIN) {
103             rain_units = (packet[5] << 8) + packet[4];
104             battery_ok = (packet[2]>>6) & 0x01;
105             data = data_make("time",          "",              DATA_STRING, time_str,
106                              "model",         "",              DATA_STRING, "HIDEKI Rain sensor",
107                              "rc",            "Rolling Code",  DATA_INT, rc,
108                              "channel",       "Channel",       DATA_INT, channel,
109                              "battery",       "Battery",       DATA_STRING, battery_ok ? "OK": "LOW",
110                              "rain",          "Rain",          DATA_FORMAT, "%.01f mm", DATA_DOUBLE, rain_units*0.7f,
111                              NULL);
112             data_acquired_handler(data);
113             return 1;
114         }
115         return 0;
116     }
117     return 0;
118 }
119
120 PWM_Precise_Parameters hideki_ts04_clock_bits_parameters = {
121    .pulse_tolerance    = 60,
122    .pulse_sync_width    = 0,    // No sync bit used
123 };
124
125 static char *output_fields[] = {
126     "time",
127     "model",
128     "rc",
129     "channel",
130     "battery",
131     "temperature_C",
132     "humidity",
133     "windstrength",
134     "winddirection",
135     "rain",
136     NULL
137 };
138
139 r_device hideki_ts04 = {
140     .name           = "HIDEKI TS04 Temperature, Humidity, Wind and Rain Sensor",
141     .modulation     = OOK_PULSE_CLOCK_BITS,
142     .short_limit    = 520,
143     .long_limit     = 1040, // not used
144     .reset_limit    = 4000,
145     .json_callback  = &hideki_ts04_callback,
146     .disabled       = 0,
147     .demod_arg     = (uintptr_t)&hideki_ts04_clock_bits_parameters,
148     .fields         = output_fields,
149 };