]> cvs.zerfleddert.de Git - hmcfgusb/blob - flash-ota.c
Merge pull request #1 from bullshit/debian
[hmcfgusb] / flash-ota.c
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"
43 #include "culfw.h"
44 #include "util.h"
45
46 #define MAX_RETRIES 5
47
48 extern char *optarg;
49
50 uint32_t hmid = 0;
51 uint32_t my_hmid = 0;
52
53 enum device_type {
54 DEVICE_TYPE_HMCFGUSB,
55 DEVICE_TYPE_CULFW,
56 };
57
58 struct ota_dev {
59 int type;
60 struct hmcfgusb_dev *hmcfgusb;
61 struct culfw_dev *culfw;
62 };
63
64 enum message_type {
65 MESSAGE_TYPE_E = 1,
66 MESSAGE_TYPE_R = 2,
67 };
68
69 struct recv_data {
70 uint8_t message[64];
71 enum message_type message_type;
72 uint16_t status;
73 int speed;
74 uint16_t version;
75 };
76
77 static 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;
104 case 'H':
105 rdata->version = (buf[11] << 8) | buf[12];
106 my_hmid = (buf[0x1b] << 16) | (buf[0x1c] << 8) | buf[0x1d];
107 break;
108 default:
109 break;
110 }
111
112 if (buf_len != 1)
113 return 1;
114
115 return 1;
116 }
117
118 static 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
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 }
140
141 if (hmid && (SRC(rdata->message) != hmid))
142 return 0;
143
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;
177 }
178
179 return 1;
180 }
181
182 int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
183 {
184 static uint32_t id = 1;
185 struct timeval tv;
186 uint8_t out[0x40];
187 int pfd;
188
189 switch(dev->type) {
190 case DEVICE_TYPE_HMCFGUSB:
191 if (gettimeofday(&tv, NULL) == -1) {
192 perror("gettimeofay");
193 return 0;
194 }
195
196 memset(out, 0, sizeof(out));
197
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;
231 pfd = hmcfgusb_poll(dev->hmcfgusb, 1000);
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 {
242 char buf[256];
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';
254
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 }
260
261 if (msg[CTL] & 0x20) {
262 int cnt = 3;
263 int pfd;
264 do {
265 errno = 0;
266 pfd = culfw_poll(dev->culfw, 200);
267 if ((pfd < 0) && errno) {
268 if (errno != ETIMEDOUT) {
269 perror("\n\nculfw_poll");
270 exit(EXIT_FAILURE);
271 }
272 }
273 if (rdata->message_type == MESSAGE_TYPE_E) {
274 break;
275 }
276 } while(cnt--);
277
278 if (cnt == -1) {
279 fprintf(stderr, "\nMissing ACK!\n");
280 return 0;
281 }
282 }
283 }
284 break;
285 }
286
287 id++;
288 return 1;
289 }
290
291 static int switch_speed(struct ota_dev *dev, struct recv_data *rdata, uint8_t speed)
292 {
293 uint8_t out[0x40];
294 int pfd;
295
296 printf("Entering %uk-mode\n", speed);
297
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;
308 pfd = hmcfgusb_poll(dev->hmcfgusb, 1000);
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);
324 }
325 break;
326 }
327
328 return 1;
329 }
330
331 void 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
343 int main(int argc, char **argv)
344 {
345 const char twiddlie[] = { '-', '\\', '|', '/' };
346 const uint8_t cc1101_regs[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 };
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;
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;
362 int switchcnt = 0;
363 int msgnum = 0;
364 int switched = 0;
365 int opt;
366
367 printf("HomeMatic OTA flasher version " VERSION "\n\n");
368
369 while((opt = getopt(argc, argv, "b:c:f:hs:")) != -1) {
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;
390
391 }
392 }
393
394 if (!fw_file || !serial) {
395 flash_ota_syntax(argv[0]);
396 exit(EXIT_FAILURE);
397 }
398
399 fw = firmware_read_firmware(fw_file, debug);
400 if (!fw)
401 exit(EXIT_FAILURE);
402
403 memset(&rdata, 0, sizeof(rdata));
404 memset(&dev, 0, sizeof(struct ota_dev));
405
406 if (culfw_dev) {
407 printf("Opening culfw-device at path %s with speed %u\n", culfw_dev, bps);
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;
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;
423 pfd = culfw_poll(dev.culfw, 1000);
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
438 if (rdata.version < 0x013a) {
439 fprintf(stderr, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n");
440 exit(EXIT_FAILURE);
441 }
442 } else {
443 hmcfgusb_set_debug(debug);
444
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;
451
452 printf("\nRebooting HM-CFG-USB to avoid running out of credits\n\n");
453
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");
458
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 }
466
467 if (dev.hmcfgusb->bootloader) {
468 printf("HM-CFG-USB in bootloader mode, rebooting\n");
469 hmcfgusb_leave_bootloader(dev.hmcfgusb);
470
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 }
478
479 printf("\n\nHM-CFG-USB opened\n\n");
480
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;
487 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
488 if ((pfd < 0) && errno) {
489 if (errno != ETIMEDOUT) {
490 perror("\n\nhmcfgusb_poll");
491 exit(EXIT_FAILURE);
492 }
493 }
494 if (rdata.version)
495 break;
496 }
497
498 if (rdata.version < 0x3c7) {
499 fprintf(stderr, "HM-CFG-USB firmware too low: %u < 967\n", rdata.version);
500 exit(EXIT_FAILURE);
501 }
502
503 printf("HM-CFG-USB firmware version: %u\n", rdata.version);
504 }
505
506 if (!switch_speed(&dev, &rdata, 10)) {
507 fprintf(stderr, "Can't switch speed!\n");
508 exit(EXIT_FAILURE);
509 }
510
511 printf("Waiting for device with serial %s\n", serial);
512
513 while (1) {
514 errno = 0;
515 switch (dev.type) {
516 case DEVICE_TYPE_CULFW:
517 pfd = culfw_poll(dev.culfw, 1000);
518 break;
519 case DEVICE_TYPE_HMCFGUSB:
520 default:
521 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
522 break;
523 }
524
525 if ((pfd < 0) && errno) {
526 if (errno != ETIMEDOUT) {
527 perror("\n\npoll");
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 */
537 (rdata.message[PAYLOAD] == 0x00)) { /* FUP? */
538 if (!strncmp((char*)&(rdata.message[0x0b]), serial, 10)) {
539 hmid = SRC(rdata.message);
540 break;
541 }
542 }
543 }
544
545 printf("Device with serial %s (hmid: %06x) entered firmware-update-mode\n", serial, hmid);
546
547 if (dev.type == DEVICE_TYPE_HMCFGUSB) {
548 printf("Adding HMID\n");
549
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;
555
556 hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
557 }
558
559 switchcnt = 3;
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;
568 SET_SRC(out, my_hmid);
569 SET_DST(out, hmid);
570
571 memcpy(&out[PAYLOAD], cc1101_regs, sizeof(cc1101_regs));
572 SET_LEN_FROM_PAYLOADLEN(out, sizeof(cc1101_regs));
573
574 if (!send_hm_message(&dev, &rdata, out)) {
575 exit(EXIT_FAILURE);
576 }
577
578 if (!switch_speed(&dev, &rdata, 100)) {
579 fprintf(stderr, "Can't switch speed!\n");
580 exit(EXIT_FAILURE);
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;
590 SET_SRC(out, my_hmid);
591 SET_DST(out, hmid);
592
593 memcpy(&out[PAYLOAD], cc1101_regs, sizeof(cc1101_regs));
594 SET_LEN_FROM_PAYLOADLEN(out, sizeof(cc1101_regs));
595
596 cnt = 3;
597 do {
598 if (send_hm_message(&dev, &rdata, out)) {
599 /* A0A02000221B9AD00000000 */
600 switched = 1;
601 break;
602 }
603 } while (cnt--);
604
605 if (!switched) {
606 printf("No!\n");
607
608 if (!switch_speed(&dev, &rdata, 10)) {
609 fprintf(stderr, "Can't switch speed!\n");
610 exit(EXIT_FAILURE);
611 }
612 }
613 } while ((!switched) && (switchcnt--));
614
615 if (!switched) {
616 fprintf(stderr, "Too many errors, giving up!\n");
617 exit(EXIT_FAILURE);
618 }
619
620 printf("Yes!\n");
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
664 out[MSGID] = msgid;
665 if (ack)
666 out[CTL] = 0x20;
667 out[TYPE] = 0xCA;
668 SET_SRC(out, my_hmid);
669 SET_DST(out, hmid);
670
671 memcpy(&out[PAYLOAD], pos, payloadlen);
672 SET_LEN_FROM_PAYLOADLEN(out, payloadlen);
673
674 if (send_hm_message(&dev, &rdata, out)) {
675 pos += payloadlen;
676 } else {
677 pos = &(fw->fw[block][2]);
678 cnt++;
679 if (cnt == MAX_RETRIES) {
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);
695 msgid++;
696 }
697
698 firmware_free(fw);
699
700 printf("\n");
701
702 if (!switch_speed(&dev, &rdata, 10)) {
703 fprintf(stderr, "Can't switch speed!\n");
704 exit(EXIT_FAILURE);
705 }
706
707 printf("Waiting for device to reboot\n");
708
709 cnt = 10;
710 do {
711 errno = 0;
712 switch(dev.type) {
713 case DEVICE_TYPE_CULFW:
714 pfd = culfw_poll(dev.culfw, 1000);
715 break;
716 case DEVICE_TYPE_HMCFGUSB:
717 default:
718 pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
719 break;
720 }
721 if ((pfd < 0) && errno) {
722 if (errno != ETIMEDOUT) {
723 perror("\n\npoll");
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
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 }
744
745 return EXIT_SUCCESS;
746 }
Impressum, Datenschutz