1 /* flasher for HomeMatic-devices supporting OTA updates
3 * Copyright (c) 2014 Michael Gernoth <michael@gernoth.net>
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
32 #include <sys/types.h>
36 #include <libusb-1.0/libusb.h>
53 enum message_type message_type
;
58 static int parse_hmcfgusb(uint8_t *buf
, int buf_len
, void *data
)
60 struct recv_data
*rdata
= data
;
68 ((buf
[0x11] == ((hmid
>> 16) & 0xff)) &&
69 (buf
[0x12] == ((hmid
>> 8) & 0xff)) &&
70 (buf
[0x13] == (hmid
& 0xff)))) {
71 memset(rdata
->message
, 0, sizeof(rdata
->message
));
72 memcpy(rdata
->message
, buf
+ 0x0d, buf
[0x0d] + 1);
73 rdata
->message_type
= MESSAGE_TYPE_E
;
77 memset(rdata
->message
, 0, sizeof(rdata
->message
));
78 memcpy(rdata
->message
, buf
+ 0x0e, buf
[0x0e] + 1);
79 rdata
->status
= (buf
[5] << 8) | buf
[6];
80 rdata
->message_type
= MESSAGE_TYPE_R
;
83 rdata
->speed
= buf
[1];
95 int send_hm_message(struct hmcfgusb_dev
*dev
, struct recv_data
*rdata
, uint8_t *msg
)
97 static uint32_t id
= 1;
102 if (gettimeofday(&tv
, NULL
) == -1) {
103 perror("gettimeofay");
107 memset(out
, 0, sizeof(out
));
110 out
[1] = (id
>> 24) & 0xff;
111 out
[2] = (id
>> 16) & 0xff;
112 out
[3] = (id
>> 8) & 0xff;
115 out
[11] = (tv
.tv_usec
>> 24) & 0xff;
116 out
[12] = (tv
.tv_usec
>> 16) & 0xff;
117 out
[13] = (tv
.tv_usec
>> 8) & 0xff;
118 out
[14] = tv
.tv_usec
& 0xff;
121 memcpy(&out
[0x0f], msg
, msg
[0] + 1);
123 memset(rdata
, 0, sizeof(struct recv_data
));
124 hmcfgusb_send(dev
, out
, sizeof(out
), 2);
127 if (rdata
->message_type
== MESSAGE_TYPE_R
) {
128 if (((rdata
->status
& 0xff) == 0x01) ||
129 ((rdata
->status
& 0xff) == 0x02)) {
132 fprintf(stderr
, "\n\nInvalid status: %04x\n\n", rdata
->status
);
137 pfd
= hmcfgusb_poll(dev
, 1);
138 if ((pfd
< 0) && errno
) {
139 if (errno
!= ETIMEDOUT
) {
140 perror("\n\nhmcfgusb_poll");
150 static int switch_speed(struct hmcfgusb_dev
*dev
, struct recv_data
*rdata
, uint8_t speed
)
155 printf("Entering %uk-mode\n", speed
);
157 memset(out
, 0, sizeof(out
));
161 hmcfgusb_send(dev
, out
, sizeof(out
), 2);
165 pfd
= hmcfgusb_poll(dev
, 1);
166 if ((pfd
< 0) && errno
) {
167 if (errno
!= ETIMEDOUT
) {
168 perror("\n\nhmcfgusb_poll");
172 if (rdata
->speed
== speed
)
179 int main(int argc
, char **argv
)
181 const char twiddlie
[] = { '-', '\\', '|', '/' };
182 const uint8_t switch_msg
[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 };
183 struct hmcfgusb_dev
*dev
;
184 struct recv_data rdata
;
198 printf("HomeMatic OTA flasher version " VERSION
"\n\n");
202 fprintf(stderr
, "Missing firmware filename!\n\n");
205 fprintf(stderr
, "Missing serial!\n\n");
207 fprintf(stderr
, "Syntax: %s firmware.eq3 SERIALNUMBER\n\n", argv
[0]);
211 fw
= firmware_read_firmware(argv
[1], debug
);
215 hmcfgusb_set_debug(debug
);
217 memset(&rdata
, 0, sizeof(rdata
));
219 dev
= hmcfgusb_init(parse_hmcfgusb
, &rdata
);
221 fprintf(stderr
, "Can't initialize HM-CFG-USB\n");
225 if (dev
->bootloader
) {
226 fprintf(stderr
, "\nHM-CFG-USB not in bootloader mode, aborting!\n");
230 printf("\nHM-CFG-USB opened\n\n");
232 if (!switch_speed(dev
, &rdata
, 10)) {
233 fprintf(stderr
, "Can't switch speed!\n");
237 printf("Waiting for device with serial %s\n", argv
[2]);
241 pfd
= hmcfgusb_poll(dev
, 1);
242 if ((pfd
< 0) && errno
) {
243 if (errno
!= ETIMEDOUT
) {
244 perror("\n\nhmcfgusb_poll");
249 if ((rdata
.message
[LEN
] == 0x14) && /* Length */
250 (rdata
.message
[MSGID
] == 0x00) && /* Message ID */
251 (rdata
.message
[CTL
] == 0x00) && /* Control Byte */
252 (rdata
.message
[TYPE
] == 0x10) && /* Messagte type: Information */
253 (DST(rdata
.message
) == 0x000000) && /* Broadcast */
254 (rdata
.message
[PAYLOAD
] == 0x00) && /* FUP? */
255 (rdata
.message
[PAYLOAD
+2] == 'E') &&
256 (rdata
.message
[PAYLOAD
+3] == 'Q')) {
257 if (!strncmp((char*)&(rdata
.message
[0x0b]), argv
[2], 10)) {
258 hmid
= SRC(rdata
.message
);
264 printf("Device with serial %s (hmid: %06x) entered firmware-update-mode\n", argv
[2], hmid
);
266 printf("Adding HMID\n");
268 memset(out
, 0, sizeof(out
));
270 out
[1] = (hmid
>> 16) & 0xff;
271 out
[2] = (hmid
>> 8) & 0xff;
272 out
[3] = hmid
& 0xff;
274 hmcfgusb_send(dev
, out
, sizeof(out
), 2);
278 printf("Initiating remote switch to 100k\n");
280 memset(out
, 0, sizeof(out
));
282 out
[MSGID
] = msgid
++;
285 SET_SRC(out
, 0x000000);
288 memcpy(&out
[PAYLOAD
], switch_msg
, sizeof(switch_msg
));
289 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(switch_msg
));
291 if (!send_hm_message(dev
, &rdata
, out
)) {
295 if (!switch_speed(dev
, &rdata
, 100)) {
296 fprintf(stderr
, "Can't switch speed!\n");
300 printf("Has the device switched?\n");
302 memset(out
, 0, sizeof(out
));
304 out
[MSGID
] = msgid
++;
307 SET_SRC(out
, 0x000000);
310 memcpy(&out
[PAYLOAD
], switch_msg
, sizeof(switch_msg
));
311 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(switch_msg
));
315 if (send_hm_message(dev
, &rdata
, out
)) {
316 /* A0A02000221B9AD00000000 */
326 if (!switch_speed(dev
, &rdata
, 10)) {
327 fprintf(stderr
, "Can't switch speed!\n");
331 } while ((!switched
) && (switchcnt
--));
336 printf("Flashing %d blocks", fw
->fw_blocks
);
340 printf(": %04u/%04u %c", 0, fw
->fw_blocks
, twiddlie
[0]);
344 for (block
= 0; block
< fw
->fw_blocks
; block
++) {
347 len
= fw
->fw
[block
][2] << 8;
348 len
|= fw
->fw
[block
][3];
350 pos
= &(fw
->fw
[block
][2]);
352 len
+= 2; /* length */
355 hexdump(pos
, len
, "F> ");
368 if ((len
- (pos
- &(fw
->fw
[block
][2]))) < payloadlen
)
369 payloadlen
= (len
- (pos
- &(fw
->fw
[block
][2])));
371 if (((pos
+ payloadlen
) - &(fw
->fw
[block
][2])) == len
)
374 memset(&rdata
, 0, sizeof(rdata
));
376 memset(out
, 0, sizeof(out
));
382 SET_SRC(out
, 0x000000);
385 memcpy(&out
[PAYLOAD
], pos
, payloadlen
);
386 SET_LEN_FROM_PAYLOADLEN(out
, payloadlen
);
388 if (send_hm_message(dev
, &rdata
, out
)) {
391 pos
= &(fw
->fw
[block
][2]);
394 fprintf(stderr
, "\nToo many errors, giving up!\n");
397 printf("Flashing %d blocks: %04u/%04u %c", fw
->fw_blocks
, block
+ 1, fw
->fw_blocks
, twiddlie
[msgnum
% sizeof(twiddlie
)]);
404 printf("\b\b\b\b\b\b\b\b\b\b\b%04u/%04u %c",
405 block
+ 1, fw
->fw_blocks
, twiddlie
[msgnum
% sizeof(twiddlie
)]);
408 } while((pos
- &(fw
->fw
[block
][2])) < len
);
416 if (!switch_speed(dev
, &rdata
, 10)) {
417 fprintf(stderr
, "Can't switch speed!\n");
421 printf("Waiting for device to reboot\n");
426 pfd
= hmcfgusb_poll(dev
, 1);
427 if ((pfd
< 0) && errno
) {
428 if (errno
!= ETIMEDOUT
) {
429 perror("\n\nhmcfgusb_poll");
433 if (rdata
.message_type
== MESSAGE_TYPE_E
) {
438 if (rdata
.message_type
== MESSAGE_TYPE_E
) {
439 printf("Device rebooted\n");