]> git.zerfleddert.de Git - hmcfgusb/blob - hmsniff.c
hmland: handle commands spanning packet-boundaries
[hmcfgusb] / hmsniff.c
1 /* HM-sniffer for HM-CFG-USB
2 *
3 * Copyright (c) 2013 Michael Gernoth <michael@gernoth.net>
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>
32 #include <sys/time.h>
33 #include <libusb-1.0/libusb.h>
34
35 #include "version.h"
36 #include "hexdump.h"
37 #include "hmcfgusb.h"
38
39 /* See HMConfig.pm */
40 char *hm_message_types(uint8_t type)
41 {
42 switch(type) {
43 case 0x00:
44 return "Device Info";
45 break;
46 case 0x01:
47 return "Configuration";
48 break;
49 case 0x02:
50 return "Acknowledge";
51 break;
52 case 0x03:
53 return "AES";
54 break;
55 case 0x04:
56 return "AES-Key";
57 break;
58 case 0x10:
59 return "Information";
60 break;
61 case 0x11:
62 return "SET";
63 break;
64 case 0x12:
65 return "HAVE_DATA";
66 break;
67 case 0x3e:
68 return "Switch";
69 break;
70 case 0x3f:
71 return "Timestamp";
72 break;
73 case 0x40:
74 return "Remote";
75 break;
76 case 0x41:
77 return "Sensor";
78 break;
79 case 0x53:
80 return "Water sensor";
81 break;
82 case 0x58:
83 return "Climate event";
84 break;
85 case 0x70:
86 return "Weather event";
87 break;
88 default:
89 return "?";
90 break;
91 }
92 }
93
94 static void dissect_hm(uint8_t *buf, int len)
95 {
96 struct timeval tv;
97 struct tm *tmp;
98 char ts[32];
99 int i;
100
101 gettimeofday(&tv, NULL);
102 tmp = localtime(&tv.tv_sec);
103 memset(ts, 0, sizeof(ts));
104 strftime(ts, sizeof(ts)-1, "%Y-%m-%d %H:%M:%S", tmp);
105 printf("%s.%06ld: ", ts, tv.tv_usec);
106
107 for (i = 0; i < len; i++) {
108 printf("%02X", buf[i]);
109 }
110 printf("\n");
111 printf("Packet information:\n");
112 printf("\tLength: %u\n", buf[0]);
113 printf("\tMessage ID: %u\n", buf[1]);
114 printf("\tSender: %02x%02x%02x\n", buf[4], buf[5], buf[6]);
115 printf("\tReceiver: %02x%02x%02x\n", buf[7], buf[8], buf[9]);
116 printf("\tControl Byte: 0x%02x\n", buf[2]);
117 printf("\t\tFlags: ");
118 if (buf[2] & (1 << 0)) printf("WAKEUP ");
119 if (buf[2] & (1 << 1)) printf("WAKEMEUP ");
120 if (buf[2] & (1 << 2)) printf("CFG ");
121 if (buf[2] & (1 << 3)) printf("? ");
122 if (buf[2] & (1 << 4)) printf("BURST ");
123 if (buf[2] & (1 << 5)) printf("BIDI ");
124 if (buf[2] & (1 << 6)) printf("RPTED ");
125 if (buf[2] & (1 << 7)) printf("RPTEN ");
126 printf("\n");
127 printf("\tMessage type: %s (0x%02x)\n", hm_message_types(buf[3]), buf[3]);
128 printf("\tMesage: ");
129 for (i = 10; i < len; i++) {
130 printf("%02X", buf[i]);
131 }
132 printf("\n");
133
134 printf("\n");
135
136 }
137
138 struct recv_data {
139 int wrong_hmid;
140 };
141
142 static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
143 {
144 struct recv_data *rdata = data;
145
146 if (buf_len < 1)
147 return 1;
148
149 switch(buf[0]) {
150 case 'E':
151 dissect_hm(buf + 13, buf[13] + 1);
152 break;
153 case 'H':
154 if ((buf[27] != 0x00) ||
155 (buf[28] != 0x00) ||
156 (buf[29] != 0x00)) {
157 printf("hmId is currently set to: %02x%02x%02x\n", buf[27], buf[28], buf[29]);
158 rdata->wrong_hmid = 1;
159 }
160 break;
161 case 'R':
162 case 'I':
163 break;
164 default:
165 hexdump(buf, buf_len, "Unknown> ");
166 break;
167 }
168
169 return 1;
170 }
171
172 int main(int argc, char **argv)
173 {
174 struct hmcfgusb_dev *dev;
175 struct recv_data rdata;
176 int quit = 0;
177
178 hmcfgusb_set_debug(0);
179
180 do {
181 memset(&rdata, 0, sizeof(rdata));
182 rdata.wrong_hmid = 0;
183
184 dev = hmcfgusb_init(parse_hmcfgusb, &rdata);
185 if (!dev) {
186 fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n");
187 sleep(1);
188 continue;
189 }
190 printf("HM-CFG-USB opened!\n");
191
192 hmcfgusb_send_null_frame(dev, 1);
193 hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
194
195 while(!quit) {
196 int fd;
197
198 if (rdata.wrong_hmid) {
199 printf("changing hmId to 000000, this might reboot the device!\n");
200 hmcfgusb_send(dev, (unsigned char*)"A\00\00\00", 4, 1);
201 rdata.wrong_hmid = 0;
202 hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
203 }
204 fd = hmcfgusb_poll(dev, 1000);
205 if (fd >= 0) {
206 fprintf(stderr, "activity on unknown fd %d!\n", fd);
207 continue;
208 } else if (fd == -1) {
209 if (errno) {
210 if (errno != ETIMEDOUT) {
211 perror("hmcfgusb_poll");
212 break;
213 } else {
214 /* periodically wakeup the device */
215 hmcfgusb_send_null_frame(dev, 1);
216 }
217 }
218 }
219 }
220
221 hmcfgusb_close(dev);
222 } while (!quit);
223
224 return EXIT_SUCCESS;
225 }
Impressum, Datenschutz