hmsniff: add two more message types
[hmcfgusb] / hmsniff.c
CommitLineData
d57fdaf6
MG
1/* HM-sniffer for HM-CFG-USB
2 *
7ba4ea19 3 * Copyright (c) 2013-16 Michael Gernoth <michael@gernoth.net>
d57fdaf6
MG
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <stdint.h>
28#include <string.h>
29#include <strings.h>
30#include <poll.h>
31#include <errno.h>
cd45e4af 32#include <time.h>
e2776af8 33#include <sys/time.h>
d57fdaf6
MG
34#include <libusb-1.0/libusb.h>
35
c44f15b8 36#include "version.h"
d57fdaf6
MG
37#include "hexdump.h"
38#include "hmcfgusb.h"
39
cd45e4af
MG
40static int verbose = 0;
41
d57fdaf6 42/* See HMConfig.pm */
cd45e4af 43char *hm_message_types(uint8_t type, uint8_t subtype)
d57fdaf6
MG
44{
45 switch(type) {
46 case 0x00:
47 return "Device Info";
48 break;
49 case 0x01:
50 return "Configuration";
51 break;
52 case 0x02:
cd45e4af
MG
53 if (subtype >= 0x80 && subtype <= 0x8f) {
54 return "NACK";
55 } else if (subtype == 0x01) {
56 return "ACKinfo";
57 } else if (subtype == 0x04) {
58 return "AESrequest";
59 }
60 return "ACK";
d57fdaf6
MG
61 break;
62 case 0x03:
cd45e4af 63 return "AESreply";
d57fdaf6
MG
64 break;
65 case 0x04:
cd45e4af 66 return "AESkey";
d57fdaf6
MG
67 break;
68 case 0x10:
69 return "Information";
70 break;
71 case 0x11:
72 return "SET";
73 break;
74 case 0x12:
75 return "HAVE_DATA";
76 break;
77 case 0x3e:
78 return "Switch";
79 break;
80 case 0x3f:
81 return "Timestamp";
82 break;
83 case 0x40:
84 return "Remote";
85 break;
86 case 0x41:
87 return "Sensor";
88 break;
89 case 0x53:
90 return "Water sensor";
91 break;
e728a6f8
MG
92 case 0x54:
93 return "Gas sensor";
94 break;
d57fdaf6
MG
95 case 0x58:
96 return "Climate event";
97 break;
cd45e4af
MG
98 case 0x5a:
99 return "Thermal control";
100 break;
920d34e0 101 case 0x5e:
e728a6f8 102 case 0x5f:
920d34e0
MG
103 return "Power event";
104 break;
d57fdaf6
MG
105 case 0x70:
106 return "Weather event";
107 break;
84daa92b
MG
108 case 0xca:
109 return "Firmware";
110 break;
111 case 0xcb:
112 return "Rf configuration";
113 break;
d57fdaf6
MG
114 default:
115 return "?";
116 break;
117 }
118}
119
120static void dissect_hm(uint8_t *buf, int len)
121{
e2776af8
MG
122 struct timeval tv;
123 struct tm *tmp;
124 char ts[32];
cd45e4af 125 static int count = 0;
d57fdaf6
MG
126 int i;
127
e2776af8
MG
128 gettimeofday(&tv, NULL);
129 tmp = localtime(&tv.tv_sec);
130 memset(ts, 0, sizeof(ts));
131 strftime(ts, sizeof(ts)-1, "%Y-%m-%d %H:%M:%S", tmp);
e2776af8 132
cd45e4af
MG
133 if (verbose) {
134 printf("%s.%06ld: ", ts, tv.tv_usec);
135
136 for (i = 0; i < len; i++) {
137 printf("%02X", buf[i]);
138 }
139 printf("\n");
140 printf("Packet information:\n");
141 printf("\tLength: %u\n", buf[0]);
142 printf("\tMessage ID: %u\n", buf[1]);
143 printf("\tSender: %02x%02x%02x\n", buf[4], buf[5], buf[6]);
144 printf("\tReceiver: %02x%02x%02x\n", buf[7], buf[8], buf[9]);
145 printf("\tControl Byte: 0x%02x\n", buf[2]);
146 printf("\t\tFlags: ");
147 if (buf[2] & (1 << 0)) printf("WAKEUP ");
148 if (buf[2] & (1 << 1)) printf("WAKEMEUP ");
149 if (buf[2] & (1 << 2)) printf("CFG ");
150 if (buf[2] & (1 << 3)) printf("? ");
151 if (buf[2] & (1 << 4)) printf("BURST ");
152 if (buf[2] & (1 << 5)) printf("BIDI ");
153 if (buf[2] & (1 << 6)) printf("RPTED ");
154 if (buf[2] & (1 << 7)) printf("RPTEN ");
155 printf("\n");
156 printf("\tMessage type: %s (0x%02x 0x%02x)\n", hm_message_types(buf[3], buf[10]), buf[3], buf[10]);
157 printf("\tMessage: ");
158 for (i = 10; i < len; i++) {
159 printf("%02X", buf[i]);
160 }
161 printf("\n");
162
163 printf("\n");
164 } else {
165 if (!(count++ % 20))
166 printf(" LL NR FL CM sender recvr payload\n");
920d34e0 167
cd45e4af
MG
168 printf("%s.%03ld: %02X %02X %02X %02X %02X%02X%02X %02X%02X%02X ",
169 ts, tv.tv_usec/1000,
170 buf[0], buf[1], buf[2], buf[3],
171 buf[4], buf[5], buf[6],
172 buf[7], buf[8], buf[9]);
173
174 for (i = 10; i < len; i++) {
175 printf("%02X", buf[i]);
176 }
177 printf("%s(%s)\n", (i>10)?" ":"", hm_message_types(buf[3], buf[10]));
d57fdaf6 178 }
d57fdaf6
MG
179}
180
885a84e3
MG
181struct recv_data {
182 int wrong_hmid;
183};
184
4371275b 185static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
d57fdaf6 186{
885a84e3
MG
187 struct recv_data *rdata = data;
188
d57fdaf6 189 if (buf_len < 1)
4371275b 190 return 1;
d57fdaf6
MG
191
192 switch(buf[0]) {
193 case 'E':
194 dissect_hm(buf + 13, buf[13] + 1);
195 break;
196 case 'H':
885a84e3
MG
197 if ((buf[27] != 0x00) ||
198 (buf[28] != 0x00) ||
199 (buf[29] != 0x00)) {
200 printf("hmId is currently set to: %02x%02x%02x\n", buf[27], buf[28], buf[29]);
201 rdata->wrong_hmid = 1;
202 }
203 break;
d57fdaf6
MG
204 case 'R':
205 case 'I':
84daa92b 206 case 'G':
d57fdaf6
MG
207 break;
208 default:
209 hexdump(buf, buf_len, "Unknown> ");
210 break;
211 }
4371275b
MG
212
213 return 1;
d57fdaf6
MG
214}
215
cd45e4af
MG
216void hmsniff_syntax(char *prog)
217{
218 fprintf(stderr, "Syntax: %s options\n\n", prog);
219 fprintf(stderr, "Possible options:\n");
84daa92b 220 fprintf(stderr, "\t-f\t\tfast (100k/firmware update) mode\n");
f51714be 221 fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n");
cd45e4af
MG
222 fprintf(stderr, "\t-v\t\tverbose mode\n");
223 fprintf(stderr, "\t-V\t\tshow version (" VERSION ")\n");
224
225}
226
d57fdaf6
MG
227int main(int argc, char **argv)
228{
229 struct hmcfgusb_dev *dev;
885a84e3 230 struct recv_data rdata;
f51714be 231 char *serial = NULL;
d57fdaf6 232 int quit = 0;
84daa92b
MG
233 int speed = 10;
234 uint8_t speed_buf[2];
cd45e4af
MG
235 int opt;
236
f51714be 237 while((opt = getopt(argc, argv, "fS:vV")) != -1) {
cd45e4af 238 switch (opt) {
84daa92b
MG
239 case 'f':
240 speed = 100;
241 break;
f51714be
MG
242 case 'S':
243 serial = optarg;
244 break;
cd45e4af
MG
245 case 'v':
246 verbose = 1;
247 break;
248 case 'V':
249 printf("hmsniff " VERSION "\n");
7ba4ea19 250 printf("Copyright (c) 2013-16 Michael Gernoth\n\n");
cd45e4af
MG
251 exit(EXIT_SUCCESS);
252 case 'h':
253 case ':':
254 case '?':
255 default:
256 hmsniff_syntax(argv[0]);
257 exit(EXIT_FAILURE);
258 break;
259 }
260 }
d57fdaf6
MG
261
262 hmcfgusb_set_debug(0);
263
885a84e3
MG
264 do {
265 memset(&rdata, 0, sizeof(rdata));
266 rdata.wrong_hmid = 0;
d57fdaf6 267
f51714be 268 dev = hmcfgusb_init(parse_hmcfgusb, &rdata, serial);
885a84e3
MG
269 if (!dev) {
270 fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n");
271 sleep(1);
272 continue;
273 }
274 printf("HM-CFG-USB opened!\n");
d57fdaf6 275
6262005e 276 hmcfgusb_send_null_frame(dev, 1);
885a84e3 277 hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
d57fdaf6 278
84daa92b
MG
279 hmcfgusb_send_null_frame(dev, 1);
280 speed_buf[0] = 'G';
281 speed_buf[1] = speed;
282 hmcfgusb_send(dev, speed_buf, 2, 1);
283
885a84e3
MG
284 while(!quit) {
285 int fd;
286
287 if (rdata.wrong_hmid) {
288 printf("changing hmId to 000000, this might reboot the device!\n");
289 hmcfgusb_send(dev, (unsigned char*)"A\00\00\00", 4, 1);
290 rdata.wrong_hmid = 0;
291 hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
292 }
3b35a8c1 293 fd = hmcfgusb_poll(dev, 1000);
885a84e3
MG
294 if (fd >= 0) {
295 fprintf(stderr, "activity on unknown fd %d!\n", fd);
296 continue;
297 } else if (fd == -1) {
298 if (errno) {
1e79d00a
MG
299 if (errno != ETIMEDOUT) {
300 perror("hmcfgusb_poll");
301 break;
302 } else {
303 /* periodically wakeup the device */
304 hmcfgusb_send_null_frame(dev, 1);
305 }
885a84e3 306 }
d57fdaf6
MG
307 }
308 }
d57fdaf6 309
885a84e3
MG
310 hmcfgusb_close(dev);
311 } while (!quit);
312
018f85fa
MG
313 hmcfgusb_exit();
314
d57fdaf6
MG
315 return EXIT_SUCCESS;
316}
Impressum, Datenschutz