adding log command to daemon
[hmcfgusb] / flash-ota.c
CommitLineData
25870f58
MG
1/* flasher for HomeMatic-devices supporting OTA updates
2 *
3 * Copyright (c) 2014 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/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <sys/time.h>
36#include <libusb-1.0/libusb.h>
37
38#include "hexdump.h"
39#include "firmware.h"
40#include "hm.h"
41#include "version.h"
42#include "hmcfgusb.h"
47ea478b
MG
43#include "culfw.h"
44#include "util.h"
25870f58 45
2d1f08ac
MG
46#define MAX_RETRIES 5
47
47ea478b
MG
48extern char *optarg;
49
25870f58 50uint32_t hmid = 0;
558a94bb 51uint32_t my_hmid = 0;
25870f58 52
47ea478b
MG
53enum device_type {
54 DEVICE_TYPE_HMCFGUSB,
55 DEVICE_TYPE_CULFW,
56};
57
58struct ota_dev {
59 int type;
60 struct hmcfgusb_dev *hmcfgusb;
61 struct culfw_dev *culfw;
62};
63
25870f58 64enum message_type {
47ea478b
MG
65 MESSAGE_TYPE_E = 1,
66 MESSAGE_TYPE_R = 2,
25870f58
MG
67};
68
69struct recv_data {
70 uint8_t message[64];
71 enum message_type message_type;
72 uint16_t status;
73 int speed;
a65c08fc 74 uint16_t version;
25870f58
MG
75};
76
77static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
78{
79 struct recv_data *rdata = data;
80
81 if (buf_len < 1)
82 return 1;
83
84 switch (buf[0]) {
85 case 'E':
86 if ((!hmid) ||
87 ((buf[0x11] == ((hmid >> 16) & 0xff)) &&
88 (buf[0x12] == ((hmid >> 8) & 0xff)) &&
89 (buf[0x13] == (hmid & 0xff)))) {
90 memset(rdata->message, 0, sizeof(rdata->message));
91 memcpy(rdata->message, buf + 0x0d, buf[0x0d] + 1);
92 rdata->message_type = MESSAGE_TYPE_E;
93 }
94 break;
95 case 'R':
96 memset(rdata->message, 0, sizeof(rdata->message));
97 memcpy(rdata->message, buf + 0x0e, buf[0x0e] + 1);
98 rdata->status = (buf[5] << 8) | buf[6];
99 rdata->message_type = MESSAGE_TYPE_R;
100 break;
101 case 'G':
102 rdata->speed = buf[1];
103 break;
865d5b4c 104 case 'H':
a65c08fc 105 rdata->version = (buf[11] << 8) | buf[12];
558a94bb 106 my_hmid = (buf[0x1b] << 16) | (buf[0x1c] << 8) | buf[0x1d];
865d5b4c 107 break;
25870f58
MG
108 default:
109 break;
110 }
111
112 if (buf_len != 1)
113 return 1;
114
115 return 1;
116}
117
47ea478b
MG
118static int parse_culfw(uint8_t *buf, int buf_len, void *data)
119{
120 struct recv_data *rdata = data;
121 int pos = 0;
122
123 memset(rdata, 0, sizeof(struct recv_data));
124
125 if (buf_len <= 3)
126 return 0;
127
a65c08fc
MG
128 switch(buf[0]) {
129 case 'A':
130 if (buf[1] == 's')
131 return 0;
132
133 while(validate_nibble(buf[(pos * 2) + 1]) &&
134 validate_nibble(buf[(pos * 2) + 2]) &&
135 (pos + 1 < buf_len)) {
136 rdata->message[pos] = ascii_to_nibble(buf[(pos * 2) + 1]) << 4;
137 rdata->message[pos] |= ascii_to_nibble(buf[(pos * 2) + 2]);
138 pos++;
139 }
47ea478b 140
a65c08fc
MG
141 if (hmid && (SRC(rdata->message) != hmid))
142 return 0;
47ea478b 143
a65c08fc
MG
144 rdata->message_type = MESSAGE_TYPE_E;
145 break;
146 case 'V':
147 {
148 uint8_t v;
149 char *s;
150 char *e;
151
152 s = ((char*)buf) + 2;
153 e = strchr(s, '.');
154 if (!e) {
155 fprintf(stderr, "Unknown response from CUL: %s", buf);
156 return 0;
157 }
158 *e = '\0';
159 v = atoi(s);
160 rdata->version = v << 8;
161
162 s = e + 1;
163 e = strchr(s, ' ');
164 if (!e) {
165 fprintf(stderr, "Unknown response from CUL: %s", buf);
166 return 0;
167 }
168 *e = '\0';
169 v = atoi(s);
170 rdata->version |= v;
171 }
172 break;
173 default:
174 fprintf(stderr, "Unknown response from CUL: %s", buf);
175 return 0;
176 break;
47ea478b
MG
177 }
178
47ea478b
MG
179 return 1;
180}
181
182int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
25870f58
MG
183{
184 static uint32_t id = 1;
185 struct timeval tv;
186 uint8_t out[0x40];
187 int pfd;
188
47ea478b
MG
189 switch(dev->type) {
190 case DEVICE_TYPE_HMCFGUSB:
191 if (gettimeofday(&tv, NULL) == -1) {
192 perror("gettimeofay");
193 return 0;
194 }
25870f58 195
47ea478b 196 memset(out, 0, sizeof(out));
25870f58 197
47ea478b
MG
198 out[0] = 'S';
199 out[1] = (id >> 24) & 0xff;
200 out[2] = (id >> 16) & 0xff;
201 out[3] = (id >> 8) & 0xff;
202 out[4] = id & 0xff;
203 out[10] = 0x01;
204 out[11] = (tv.tv_usec >> 24) & 0xff;
205 out[12] = (tv.tv_usec >> 16) & 0xff;
206 out[13] = (tv.tv_usec >> 8) & 0xff;
207 out[14] = tv.tv_usec & 0xff;
208
209 memcpy(&out[0x0f], msg, msg[0] + 1);
210
211 memset(rdata, 0, sizeof(struct recv_data));
212 hmcfgusb_send(dev->hmcfgusb, out, sizeof(out), 1);
213
214 while (1) {
215 if (rdata->message_type == MESSAGE_TYPE_R) {
216 if (((rdata->status & 0xff) == 0x01) ||
217 ((rdata->status & 0xff) == 0x02)) {
218 break;
219 } else {
220 if ((rdata->status & 0xff00) == 0x0400) {
221 fprintf(stderr, "\nOut of credits!\n");
222 } else if ((rdata->status & 0xff) == 0x08) {
223 fprintf(stderr, "\nMissing ACK!\n");
224 } else {
225 fprintf(stderr, "\nInvalid status: %04x\n", rdata->status);
226 }
227 return 0;
228 }
229 }
230 errno = 0;
3b35a8c1 231 pfd = hmcfgusb_poll(dev->hmcfgusb, 1000);
47ea478b
MG
232 if ((pfd < 0) && errno) {
233 if (errno != ETIMEDOUT) {
234 perror("\n\nhmcfgusb_poll");
235 exit(EXIT_FAILURE);
236 }
237 }
238 }
239 break;
240 case DEVICE_TYPE_CULFW:
241 {
cda22024 242 char buf[256];
47ea478b
MG
243 int i;
244
245 memset(buf, 0, sizeof(buf));
246 buf[0] = 'A';
247 buf[1] = 's';
248 for (i = 0; i < msg[0] + 1; i++) {
249 buf[2 + (i * 2)] = nibble_to_ascii((msg[i] >> 4) & 0xf);
250 buf[2 + (i * 2) + 1] = nibble_to_ascii(msg[i] & 0xf);
251 }
252 buf[2 + (i * 2) ] = '\r';
253 buf[2 + (i * 2) + 1] = '\n';
25870f58 254
47ea478b
MG
255 memset(rdata, 0, sizeof(struct recv_data));
256 if (culfw_send(dev->culfw, buf, 2 + (i * 2) + 1) == 0) {
257 fprintf(stderr, "culfw_send failed!\n");
258 exit(EXIT_FAILURE);
259 }
25870f58 260
47ea478b 261 if (msg[CTL] & 0x20) {
9718f9fa 262 int cnt = 3;
47ea478b
MG
263 int pfd;
264 do {
265 errno = 0;
3b35a8c1 266 pfd = culfw_poll(dev->culfw, 200);
47ea478b
MG
267 if ((pfd < 0) && errno) {
268 if (errno != ETIMEDOUT) {
9dcbf605 269 perror("\n\nculfw_poll");
47ea478b
MG
270 exit(EXIT_FAILURE);
271 }
272 }
273 if (rdata->message_type == MESSAGE_TYPE_E) {
274 break;
275 }
276 } while(cnt--);
9718f9fa
MG
277
278 if (cnt == -1) {
279 fprintf(stderr, "\nMissing ACK!\n");
280 return 0;
281 }
2d1f08ac 282 }
25870f58 283 }
47ea478b 284 break;
25870f58
MG
285 }
286
287 id++;
288 return 1;
289}
290
47ea478b 291static int switch_speed(struct ota_dev *dev, struct recv_data *rdata, uint8_t speed)
da4ab971
MG
292{
293 uint8_t out[0x40];
294 int pfd;
295
296 printf("Entering %uk-mode\n", speed);
297
47ea478b
MG
298 switch(dev->type) {
299 case DEVICE_TYPE_HMCFGUSB:
300 memset(out, 0, sizeof(out));
301 out[0] = 'G';
302 out[1] = speed;
303
304 hmcfgusb_send(dev->hmcfgusb, out, sizeof(out), 1);
305
306 while (1) {
307 errno = 0;
3b35a8c1 308 pfd = hmcfgusb_poll(dev->hmcfgusb, 1000);
47ea478b
MG
309 if ((pfd < 0) && errno) {
310 if (errno != ETIMEDOUT) {
311 perror("\n\nhmcfgusb_poll");
312 exit(EXIT_FAILURE);
313 }
314 }
315 if (rdata->speed == speed)
316 break;
317 }
318 break;
319 case DEVICE_TYPE_CULFW:
320 if (speed == 100) {
321 return culfw_send(dev->culfw, "AR\r\n", 4);
322 } else {
323 return culfw_send(dev->culfw, "Ar\r\n", 4);
da4ab971 324 }
da4ab971
MG
325 break;
326 }
327
328 return 1;
329}
330
47ea478b
MG
331void flash_ota_syntax(char *prog)
332{
333 fprintf(stderr, "Syntax: %s parameters options\n\n", prog);
334 fprintf(stderr, "Mandatory parameters:\n");
335 fprintf(stderr, "\t-f firmware.eq3\tfirmware file to flash\n");
336 fprintf(stderr, "\t-s SERIAL\tserial of device to flash\n");
337 fprintf(stderr, "\nPossible options:\n");
338 fprintf(stderr, "\t-c device\tenable CUL-mode with CUL at path \"device\"\n");
339 fprintf(stderr, "\t-b bps\t\tuse CUL with speed \"bps\" (default: %u)\n", DEFAULT_CUL_BPS);
340 fprintf(stderr, "\t-h\t\tthis help\n");
341}
342
25870f58
MG
343int main(int argc, char **argv)
344{
345 const char twiddlie[] = { '-', '\\', '|', '/' };
f0ed61cc 346 const uint8_t cc1101_regs[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 };
47ea478b
MG
347 char *fw_file = NULL;
348 char *serial = NULL;
349 char *culfw_dev = NULL;
350 unsigned int bps = DEFAULT_CUL_BPS;
351 struct ota_dev dev;
25870f58
MG
352 struct recv_data rdata;
353 uint8_t out[0x40];
354 uint8_t *pos;
355 uint8_t msgid = 0x1;
356 uint16_t len;
357 struct firmware *fw;
358 int block;
359 int pfd;
360 int debug = 0;
361 int cnt;
da4ab971 362 int switchcnt = 0;
25870f58
MG
363 int msgnum = 0;
364 int switched = 0;
47ea478b 365 int opt;
25870f58
MG
366
367 printf("HomeMatic OTA flasher version " VERSION "\n\n");
368
d5cdafda 369 while((opt = getopt(argc, argv, "b:c:f:hs:")) != -1) {
47ea478b
MG
370 switch (opt) {
371 case 'b':
372 bps = atoi(optarg);
373 break;
374 case 'c':
375 culfw_dev = optarg;
376 break;
377 case 'f':
378 fw_file = optarg;
379 break;
380 case 's':
381 serial = optarg;
382 break;
383 case 'h':
384 case ':':
385 case '?':
386 default:
387 flash_ota_syntax(argv[0]);
388 exit(EXIT_FAILURE);
389 break;
25870f58 390
47ea478b
MG
391 }
392 }
25870f58 393
47ea478b
MG
394 if (!fw_file || !serial) {
395 flash_ota_syntax(argv[0]);
25870f58
MG
396 exit(EXIT_FAILURE);
397 }
398
47ea478b 399 fw = firmware_read_firmware(fw_file, debug);
25870f58
MG
400 if (!fw)
401 exit(EXIT_FAILURE);
402
25870f58 403 memset(&rdata, 0, sizeof(rdata));
47ea478b 404 memset(&dev, 0, sizeof(struct ota_dev));
25870f58 405
47ea478b 406 if (culfw_dev) {
a65c08fc 407 printf("Opening culfw-device at path %s with speed %u\n", culfw_dev, bps);
47ea478b
MG
408 dev.culfw = culfw_init(culfw_dev, bps, parse_culfw, &rdata);
409 if (!dev.culfw) {
410 fprintf(stderr, "Can't initialize CUL at %s with rate %u\n", culfw_dev, bps);
411 exit(EXIT_FAILURE);
412 }
413 dev.type = DEVICE_TYPE_CULFW;
a65c08fc
MG
414
415 printf("Requesting firmware-version\n");
416 culfw_send(dev.culfw, "\r\n", 2);
417 culfw_flush(dev.culfw);
418
419 while (1) {
420 culfw_send(dev.culfw, "V\r\n", 3);
421
422 errno = 0;
3b35a8c1 423 pfd = culfw_poll(dev.culfw, 1000);
a65c08fc
MG
424 if ((pfd < 0) && errno) {
425 if (errno != ETIMEDOUT) {
426 perror("\n\nhmcfgusb_poll");
427 exit(EXIT_FAILURE);
428 }
429 }
430 if (rdata.version)
431 break;
432 }
433
434 printf("culfw-device firmware version: %u.%02u\n",
435 (rdata.version >> 8) & 0xff,
436 rdata.version & 0xff);
437
57b387ce
MG
438 if (rdata.version < 0x013a) {
439 fprintf(stderr, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n");
a65c08fc 440 exit(EXIT_FAILURE);
a65c08fc 441 }
47ea478b
MG
442 } else {
443 hmcfgusb_set_debug(debug);
25870f58 444
47ea478b
MG
445 dev.hmcfgusb = hmcfgusb_init(parse_hmcfgusb, &rdata);
446 if (!dev.hmcfgusb) {
447 fprintf(stderr, "Can't initialize HM-CFG-USB\n");
448 exit(EXIT_FAILURE);
449 }
450 dev.type = DEVICE_TYPE_HMCFGUSB;
2d1f08ac 451
47ea478b 452 printf("\nRebooting HM-CFG-USB to avoid running out of credits\n\n");
2d1f08ac 453
47ea478b
MG
454 if (!dev.hmcfgusb->bootloader) {
455 printf("HM-CFG-USB not in bootloader mode, entering bootloader.\n");
456 hmcfgusb_enter_bootloader(dev.hmcfgusb);
457 printf("Waiting for device to reappear...\n");
2d1f08ac 458
47ea478b
MG
459 do {
460 if (dev.hmcfgusb) {
461 hmcfgusb_close(dev.hmcfgusb);
462 }
463 sleep(1);
464 } while (((dev.hmcfgusb = hmcfgusb_init(parse_hmcfgusb, &rdata)) == NULL) || (!dev.hmcfgusb->bootloader));
465 }
2d1f08ac 466
47ea478b
MG
467 if (dev.hmcfgusb->bootloader) {
468 printf("HM-CFG-USB in bootloader mode, rebooting\n");
469 hmcfgusb_leave_bootloader(dev.hmcfgusb);
25870f58 470
47ea478b
MG
471 do {
472 if (dev.hmcfgusb) {
473 hmcfgusb_close(dev.hmcfgusb);
474 }
475 sleep(1);
476 } while (((dev.hmcfgusb = hmcfgusb_init(parse_hmcfgusb, &rdata)) == NULL) || (dev.hmcfgusb->bootloader));
477 }
25870f58 478
47ea478b 479 printf("\n\nHM-CFG-USB opened\n\n");
865d5b4c 480
47ea478b
MG
481 memset(out, 0, sizeof(out));
482 out[0] = 'K';
483 hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
484
485 while (1) {
486 errno = 0;
3b35a8c1 487 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
47ea478b
MG
488 if ((pfd < 0) && errno) {
489 if (errno != ETIMEDOUT) {
490 perror("\n\nhmcfgusb_poll");
491 exit(EXIT_FAILURE);
492 }
865d5b4c 493 }
a65c08fc 494 if (rdata.version)
47ea478b 495 break;
865d5b4c 496 }
865d5b4c 497
a65c08fc
MG
498 if (rdata.version < 0x3c7) {
499 fprintf(stderr, "HM-CFG-USB firmware too low: %u < 967\n", rdata.version);
47ea478b
MG
500 exit(EXIT_FAILURE);
501 }
865d5b4c 502
a65c08fc 503 printf("HM-CFG-USB firmware version: %u\n", rdata.version);
47ea478b 504 }
865d5b4c 505
47ea478b 506 if (!switch_speed(&dev, &rdata, 10)) {
da4ab971
MG
507 fprintf(stderr, "Can't switch speed!\n");
508 exit(EXIT_FAILURE);
25870f58
MG
509 }
510
47ea478b 511 printf("Waiting for device with serial %s\n", serial);
25870f58
MG
512
513 while (1) {
0edcd7f2 514 errno = 0;
47ea478b 515 switch (dev.type) {
47ea478b 516 case DEVICE_TYPE_CULFW:
3b35a8c1 517 pfd = culfw_poll(dev.culfw, 1000);
47ea478b
MG
518 break;
519 case DEVICE_TYPE_HMCFGUSB:
520 default:
3b35a8c1 521 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
47ea478b
MG
522 break;
523 }
524
25870f58
MG
525 if ((pfd < 0) && errno) {
526 if (errno != ETIMEDOUT) {
47ea478b 527 perror("\n\npoll");
25870f58
MG
528 exit(EXIT_FAILURE);
529 }
530 }
531
532 if ((rdata.message[LEN] == 0x14) && /* Length */
533 (rdata.message[MSGID] == 0x00) && /* Message ID */
534 (rdata.message[CTL] == 0x00) && /* Control Byte */
535 (rdata.message[TYPE] == 0x10) && /* Messagte type: Information */
536 (DST(rdata.message) == 0x000000) && /* Broadcast */
47ea478b
MG
537 (rdata.message[PAYLOAD] == 0x00)) { /* FUP? */
538 if (!strncmp((char*)&(rdata.message[0x0b]), serial, 10)) {
25870f58
MG
539 hmid = SRC(rdata.message);
540 break;
541 }
542 }
543 }
544
47ea478b 545 printf("Device with serial %s (hmid: %06x) entered firmware-update-mode\n", serial, hmid);
25870f58 546
47ea478b
MG
547 if (dev.type == DEVICE_TYPE_HMCFGUSB) {
548 printf("Adding HMID\n");
25870f58 549
47ea478b
MG
550 memset(out, 0, sizeof(out));
551 out[0] = '+';
552 out[1] = (hmid >> 16) & 0xff;
553 out[2] = (hmid >> 8) & 0xff;
554 out[3] = hmid & 0xff;
25870f58 555
47ea478b
MG
556 hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
557 }
25870f58 558
da4ab971 559 switchcnt = 3;
25870f58
MG
560 do {
561 printf("Initiating remote switch to 100k\n");
562
563 memset(out, 0, sizeof(out));
564
565 out[MSGID] = msgid++;
566 out[CTL] = 0x00;
567 out[TYPE] = 0xCB;
558a94bb 568 SET_SRC(out, my_hmid);
25870f58
MG
569 SET_DST(out, hmid);
570
f0ed61cc
MG
571 memcpy(&out[PAYLOAD], cc1101_regs, sizeof(cc1101_regs));
572 SET_LEN_FROM_PAYLOADLEN(out, sizeof(cc1101_regs));
25870f58 573
47ea478b 574 if (!send_hm_message(&dev, &rdata, out)) {
25870f58
MG
575 exit(EXIT_FAILURE);
576 }
577
47ea478b 578 if (!switch_speed(&dev, &rdata, 100)) {
da4ab971
MG
579 fprintf(stderr, "Can't switch speed!\n");
580 exit(EXIT_FAILURE);
25870f58
MG
581 }
582
583 printf("Has the device switched?\n");
584
585 memset(out, 0, sizeof(out));
586
587 out[MSGID] = msgid++;
588 out[CTL] = 0x20;
589 out[TYPE] = 0xCB;
558a94bb 590 SET_SRC(out, my_hmid);
25870f58
MG
591 SET_DST(out, hmid);
592
f0ed61cc
MG
593 memcpy(&out[PAYLOAD], cc1101_regs, sizeof(cc1101_regs));
594 SET_LEN_FROM_PAYLOADLEN(out, sizeof(cc1101_regs));
25870f58
MG
595
596 cnt = 3;
597 do {
47ea478b 598 if (send_hm_message(&dev, &rdata, out)) {
25870f58
MG
599 /* A0A02000221B9AD00000000 */
600 switched = 1;
601 break;
25870f58
MG
602 }
603 } while (cnt--);
604
605 if (!switched) {
da4ab971 606 printf("No!\n");
25870f58 607
47ea478b 608 if (!switch_speed(&dev, &rdata, 10)) {
da4ab971
MG
609 fprintf(stderr, "Can't switch speed!\n");
610 exit(EXIT_FAILURE);
25870f58
MG
611 }
612 }
da4ab971 613 } while ((!switched) && (switchcnt--));
25870f58 614
268d2cc6
MG
615 if (!switched) {
616 fprintf(stderr, "Too many errors, giving up!\n");
617 exit(EXIT_FAILURE);
618 }
25870f58 619
da4ab971 620 printf("Yes!\n");
25870f58
MG
621
622 printf("Flashing %d blocks", fw->fw_blocks);
623 if (debug) {
624 printf("\n");
625 } else {
626 printf(": %04u/%04u %c", 0, fw->fw_blocks, twiddlie[0]);
627 fflush(stdout);
628 }
629
630 for (block = 0; block < fw->fw_blocks; block++) {
631 int first;
632
633 len = fw->fw[block][2] << 8;
634 len |= fw->fw[block][3];
635
636 pos = &(fw->fw[block][2]);
637
638 len += 2; /* length */
639
640 if (debug)
641 hexdump(pos, len, "F> ");
642
643 first = 1;
644 cnt = 0;
645 do {
646 int payloadlen = 35;
647 int ack = 0;
648
649 if (first) {
650 payloadlen = 37;
651 first = 0;
652 }
653
654 if ((len - (pos - &(fw->fw[block][2]))) < payloadlen)
655 payloadlen = (len - (pos - &(fw->fw[block][2])));
656
657 if (((pos + payloadlen) - &(fw->fw[block][2])) == len)
658 ack = 1;
659
660 memset(&rdata, 0, sizeof(rdata));
661
662 memset(out, 0, sizeof(out));
663
da4ab971 664 out[MSGID] = msgid;
25870f58
MG
665 if (ack)
666 out[CTL] = 0x20;
667 out[TYPE] = 0xCA;
558a94bb 668 SET_SRC(out, my_hmid);
25870f58
MG
669 SET_DST(out, hmid);
670
671 memcpy(&out[PAYLOAD], pos, payloadlen);
672 SET_LEN_FROM_PAYLOADLEN(out, payloadlen);
673
47ea478b 674 if (send_hm_message(&dev, &rdata, out)) {
25870f58
MG
675 pos += payloadlen;
676 } else {
677 pos = &(fw->fw[block][2]);
678 cnt++;
2d1f08ac 679 if (cnt == MAX_RETRIES) {
25870f58
MG
680 fprintf(stderr, "\nToo many errors, giving up!\n");
681 exit(EXIT_FAILURE);
682 } else {
683 printf("Flashing %d blocks: %04u/%04u %c", fw->fw_blocks, block + 1, fw->fw_blocks, twiddlie[msgnum % sizeof(twiddlie)]);
684 }
685 }
686
687 msgnum++;
688
689 if (!debug) {
690 printf("\b\b\b\b\b\b\b\b\b\b\b%04u/%04u %c",
691 block + 1, fw->fw_blocks, twiddlie[msgnum % sizeof(twiddlie)]);
692 fflush(stdout);
693 }
694 } while((pos - &(fw->fw[block][2])) < len);
da4ab971 695 msgid++;
25870f58
MG
696 }
697
698 firmware_free(fw);
699
da4ab971 700 printf("\n");
25870f58 701
47ea478b 702 if (!switch_speed(&dev, &rdata, 10)) {
da4ab971
MG
703 fprintf(stderr, "Can't switch speed!\n");
704 exit(EXIT_FAILURE);
25870f58
MG
705 }
706
707 printf("Waiting for device to reboot\n");
708
709 cnt = 10;
710 do {
711 errno = 0;
47ea478b
MG
712 switch(dev.type) {
713 case DEVICE_TYPE_CULFW:
3b35a8c1 714 pfd = culfw_poll(dev.culfw, 1000);
47ea478b
MG
715 break;
716 case DEVICE_TYPE_HMCFGUSB:
717 default:
3b35a8c1 718 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
47ea478b
MG
719 break;
720 }
25870f58
MG
721 if ((pfd < 0) && errno) {
722 if (errno != ETIMEDOUT) {
9dcbf605 723 perror("\n\npoll");
25870f58
MG
724 exit(EXIT_FAILURE);
725 }
726 }
727 if (rdata.message_type == MESSAGE_TYPE_E) {
728 break;
729 }
730 } while(cnt--);
731
732 if (rdata.message_type == MESSAGE_TYPE_E) {
733 printf("Device rebooted\n");
734 }
735
47ea478b
MG
736 switch(dev.type) {
737 case DEVICE_TYPE_HMCFGUSB:
738 hmcfgusb_close(dev.hmcfgusb);
739 break;
740 case DEVICE_TYPE_CULFW:
741 culfw_close(dev.culfw);
742 break;
743 }
25870f58
MG
744
745 return EXIT_SUCCESS;
746}
Impressum, Datenschutz