1 /* flasher for HomeMatic-devices supporting OTA updates 
   3  * Copyright (c) 2014-16 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> 
  47 #define NORMAL_MAX_PAYLOAD      37 
  48 #define LOWER_MAX_PAYLOAD       17 
  54 uint8_t key
[16] = {0}; 
  57 /* Maximum payloadlen supported by IO */ 
  58 uint32_t max_payloadlen 
= NORMAL_MAX_PAYLOAD
; 
  67         struct hmcfgusb_dev 
*hmcfgusb
; 
  68         struct culfw_dev 
*culfw
; 
  78         enum message_type message_type
; 
  85 static int parse_hmcfgusb(uint8_t *buf
, int buf_len
, void *data
) 
  87         struct recv_data 
*rdata 
= data
; 
  95                             ((buf
[0x11] == ((hmid 
>> 16) & 0xff)) && 
  96                             (buf
[0x12] == ((hmid 
>> 8) & 0xff)) && 
  97                             (buf
[0x13] == (hmid 
& 0xff)))) { 
  98                                 memset(rdata
->message
, 0, sizeof(rdata
->message
)); 
  99                                 memcpy(rdata
->message
, buf 
+ 0x0d, buf
[0x0d] + 1); 
 100                                 rdata
->message_type 
= MESSAGE_TYPE_E
; 
 104                         memset(rdata
->message
, 0, sizeof(rdata
->message
)); 
 105                         memcpy(rdata
->message
, buf 
+ 0x0e, buf
[0x0e] + 1); 
 106                         rdata
->status 
= (buf
[5] << 8) | buf
[6]; 
 107                         rdata
->message_type 
= MESSAGE_TYPE_R
; 
 110                         rdata
->speed 
= buf
[1]; 
 113                         rdata
->version 
= (buf
[11] << 8) | buf
[12]; 
 114                         rdata
->credits 
= buf
[36]; 
 115                         my_hmid 
= (buf
[0x1b] << 16) | (buf
[0x1c] << 8) | buf
[0x1d]; 
 127 static int parse_culfw(uint8_t *buf
, int buf_len
, void *data
) 
 129         struct recv_data 
*rdata 
= data
; 
 132         memset(rdata
, 0, sizeof(struct recv_data
)); 
 142                         while(validate_nibble(buf
[(pos 
* 2) + 1]) && 
 143                               validate_nibble(buf
[(pos 
* 2) + 2]) && 
 144                               (pos 
+ 1 < buf_len
)) { 
 145                                 rdata
->message
[pos
] = ascii_to_nibble(buf
[(pos 
* 2) + 1]) << 4; 
 146                                 rdata
->message
[pos
] |= ascii_to_nibble(buf
[(pos 
* 2) + 2]); 
 150                         if (hmid 
&& (SRC(rdata
->message
) != hmid
)) 
 153                         rdata
->message_type 
= MESSAGE_TYPE_E
; 
 161                                 s 
= ((char*)buf
) + 2; 
 164                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 169                                 rdata
->version 
= v 
<< 8; 
 174                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 187                                 if (!strcmp(s
, "a-culfw")) { 
 188                                         rdata
->version 
= 0xffff; 
 194                                 if (!strncmp((char*)buf
, "ERR:CCA", 7)) { 
 195                                         fprintf(stderr
, "CCA didn't complete, too much traffic\n"); 
 200                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 208 int send_hm_message(struct ota_dev 
*dev
, struct recv_data 
*rdata
, uint8_t *msg
) 
 210         static uint32_t id 
= 1; 
 216                 case DEVICE_TYPE_HMCFGUSB
: 
 217                         if (gettimeofday(&tv
, NULL
) == -1) { 
 218                                 perror("gettimeofay"); 
 222                         memset(out
, 0, sizeof(out
)); 
 225                         out
[1] = (id 
>> 24) & 0xff; 
 226                         out
[2] = (id 
>> 16) & 0xff; 
 227                         out
[3] = (id 
>> 8) & 0xff; 
 230                         out
[11] = (tv
.tv_usec 
>> 24) & 0xff; 
 231                         out
[12] = (tv
.tv_usec 
>> 16) & 0xff; 
 232                         out
[13] = (tv
.tv_usec 
>> 8) & 0xff; 
 233                         out
[14] = tv
.tv_usec 
& 0xff; 
 235                         memcpy(&out
[0x0f], msg
, msg
[0] + 1); 
 237                         memset(rdata
, 0, sizeof(struct recv_data
)); 
 238                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 241                                 if (rdata
->message_type 
== MESSAGE_TYPE_R
) { 
 242                                         if (((rdata
->status 
& 0xdf) == 0x01) || 
 243                                             ((rdata
->status 
& 0xdf) == 0x02)) { 
 246                                                 if ((rdata
->status 
& 0xff00) == 0x0400) { 
 247                                                         fprintf(stderr
, "\nOut of credits!\n"); 
 248                                                 } else if ((rdata
->status 
& 0xff) == 0x08) { 
 249                                                         fprintf(stderr
, "\nMissing ACK!\n"); 
 250                                                 } else if ((rdata
->status 
& 0xff) == 0x30) { 
 251                                                         fprintf(stderr
, "\nUnknown AES-key requested!\n"); 
 253                                                         fprintf(stderr
, "\nInvalid status: %04x\n", rdata
->status
); 
 259                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 260                                 if ((pfd 
< 0) && errno
) { 
 261                                         if (errno 
!= ETIMEDOUT
) { 
 262                                                 perror("\n\nhmcfgusb_poll"); 
 268                 case DEVICE_TYPE_CULFW
: 
 273                                 memset(buf
, 0, sizeof(buf
)); 
 276                                 for (i 
= 0; i 
< msg
[0] + 1; i
++) { 
 277                                         buf
[2 + (i 
* 2)] = nibble_to_ascii((msg
[i
] >> 4) & 0xf); 
 278                                         buf
[2 + (i 
* 2) + 1] = nibble_to_ascii(msg
[i
] & 0xf); 
 280                                 buf
[2 + (i 
* 2) ] = '\r'; 
 281                                 buf
[2 + (i 
* 2) + 1] = '\n'; 
 283                                 memset(rdata
, 0, sizeof(struct recv_data
)); 
 284                                 if (culfw_send(dev
->culfw
, buf
, 2 + (i 
* 2) + 1) == 0) { 
 285                                         fprintf(stderr
, "culfw_send failed!\n"); 
 289                                 if (msg
[CTL
] & 0x20) { 
 294                                                 pfd 
= culfw_poll(dev
->culfw
, 200); 
 295                                                 if ((pfd 
< 0) && errno
) { 
 296                                                         if (errno 
!= ETIMEDOUT
) { 
 297                                                                 perror("\n\nculfw_poll"); 
 301                                                 if (rdata
->message_type 
== MESSAGE_TYPE_E
) { 
 302                                                         if (rdata
->message
[TYPE
] == 0x02) { 
 303                                                                 if (rdata
->message
[PAYLOAD
] == 0x04) { 
 305                                                                         uint8_t challenge
[6]; 
 309                                                                         req_kNo 
= rdata
->message
[rdata
->message
[LEN
]] / 2; 
 310                                                                         memcpy(challenge
, &(rdata
->message
[PAYLOAD
+1]), 6); 
 312                                                                         if (req_kNo 
!= kNo
) { 
 313                                                                                 fprintf(stderr
, "AES request for unknown key %d!\n", req_kNo
); 
 315                                                                                 resp 
= hm_sign(key
, challenge
, msg
, NULL
, respbuf
); 
 319                                                                                         memset(rbuf
, 0, sizeof(rbuf
)); 
 320                                                                                         rbuf
[MSGID
] = rdata
->message
[MSGID
]; 
 321                                                                                         rbuf
[CTL
] = rdata
->message
[CTL
]; 
 323                                                                                         SET_SRC(rbuf
, DST(rdata
->message
)); 
 324                                                                                         SET_DST(rbuf
, SRC(rdata
->message
)); 
 325                                                                                         memcpy(&(rbuf
[PAYLOAD
]), resp
, 16); 
 326                                                                                         SET_LEN_FROM_PAYLOADLEN(rbuf
, 16); 
 328                                                                                         usleep(110000); /* Determined by a fair dice roll */ 
 329                                                                                         return send_hm_message(dev
, rdata
, rbuf
); 
 332                                                                 } else if (rdata
->message
[PAYLOAD
] >= 0x80 && rdata
->message
[PAYLOAD
] <= 0x8f) { 
 333                                                                         fprintf(stderr
, "NACK\n"); 
 334                                                                 } else {        /* ACK or ACKinfo */ 
 338                                                                 fprintf(stderr
, "Unexpected message received: "); 
 339                                                                 for (i 
= 0; i 
< rdata
->message
[LEN
]; i
++) { 
 340                                                                         fprintf(stderr
, "%02x", rdata
->message
[i
+1]); 
 342                                                                 fprintf(stderr
, "\n"); 
 348                                                 fprintf(stderr
, "\nMissing ACK!\n"); 
 360 static int switch_speed(struct ota_dev 
*dev
, struct recv_data 
*rdata
, uint8_t speed
) 
 365         printf("Entering %uk-mode\n", speed
); 
 368                 case DEVICE_TYPE_HMCFGUSB
: 
 369                         memset(out
, 0, sizeof(out
)); 
 373                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 377                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 378                                 if ((pfd 
< 0) && errno
) { 
 379                                         if (errno 
!= ETIMEDOUT
) { 
 380                                                 perror("\n\nhmcfgusb_poll"); 
 384                                 if (rdata
->speed 
== speed
) 
 388                 case DEVICE_TYPE_CULFW
: 
 390                                 return culfw_send(dev
->culfw
, "AR\r\n", 4); 
 392                                 return culfw_send(dev
->culfw
, "Ar\r\n", 4); 
 400 void flash_ota_syntax(char *prog
) 
 402         fprintf(stderr
, "Syntax: %s parameters options\n\n", prog
); 
 403         fprintf(stderr
, "Mandatory parameters:\n"); 
 404         fprintf(stderr
, "\t-f firmware.eq3\tfirmware file to flash\n"); 
 405         fprintf(stderr
, "\t-s SERIAL\tserial of device to flash (optional when using -D)\n"); 
 406         fprintf(stderr
, "\nOptional parameters:\n"); 
 407         fprintf(stderr
, "\t-c device\tenable CUL-mode with CUL at path \"device\"\n"); 
 408         fprintf(stderr
, "\t-b bps\t\tuse CUL with speed \"bps\" (default: %u)\n", DEFAULT_CUL_BPS
); 
 409         fprintf(stderr
, "\t-l\t\tlower payloadlen (required for devices with little RAM, e.g. CUL v2 and CUL v4)\n"); 
 410         fprintf(stderr
, "\t-S serial\tuse HM-CFG-USB with given serial\n"); 
 411         fprintf(stderr
, "\t-h\t\tthis help\n"); 
 412         fprintf(stderr
, "\nOptional parameters for automatically sending device to bootloader\n"); 
 413         fprintf(stderr
, "\t-C\t\tHMID of central (3 hex-bytes, no prefix, e.g. ABCDEF)\n"); 
 414         fprintf(stderr
, "\t-D\t\tHMID of device (3 hex-bytes, no prefix, e.g. 123456)\n"); 
 415         fprintf(stderr
, "\t-K\t\tKNO:KEY AES key-number and key (hex) separated by colon (Fhem hmKey attribute)\n"); 
 418 int main(int argc
, char **argv
) 
 420         const char twiddlie
[] = { '-', '\\', '|', '/' }; 
 421         const uint8_t cc1101_regs
[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 }; 
 422         char *fw_file 
= NULL
; 
 424         char *culfw_dev 
= NULL
; 
 426         unsigned int bps 
= DEFAULT_CUL_BPS
; 
 428         struct recv_data rdata
; 
 434         char *hmcfgusb_serial 
= NULL
; 
 444         printf("HomeMatic OTA flasher version " VERSION 
"\n\n"); 
 446         while((opt 
= getopt(argc
, argv
, "b:c:f:hls:C:D:K:S:")) != -1) { 
 458                                 printf("Reducing payload-len from %d to %d\n", max_payloadlen
, LOWER_MAX_PAYLOAD
); 
 459                                 max_payloadlen 
= LOWER_MAX_PAYLOAD
; 
 465                                 my_hmid 
= strtoul(optarg
, &endptr
, 16); 
 466                                 if (*endptr 
!= '\0') { 
 467                                         fprintf(stderr
, "Invalid central HMID!\n\n"); 
 468                                         flash_ota_syntax(argv
[0]); 
 473                                 hmid 
= strtoul(optarg
, &endptr
, 16); 
 474                                 if (*endptr 
!= '\0') { 
 475                                         fprintf(stderr
, "Invalid device HMID!\n\n"); 
 476                                         flash_ota_syntax(argv
[0]); 
 481                                 kNo 
= strtoul(optarg
, &endptr
, 10); 
 482                                 if (*endptr 
!= ':') { 
 483                                         fprintf(stderr
, "Invalid key number!\n\n"); 
 484                                         flash_ota_syntax(argv
[0]); 
 488                                 for (cnt 
= 0; cnt 
< 16; cnt
++) { 
 489                                         if (*endptr 
== '\0' || *(endptr
+1) == '\0' || 
 490                                             !validate_nibble(*endptr
) || 
 491                                             !validate_nibble(*(endptr
+1))) { 
 492                                                 fprintf(stderr
, "Invalid key!\n\n"); 
 493                                                 flash_ota_syntax(argv
[0]); 
 496                                         key
[cnt
] = ascii_to_nibble(*endptr
) << 4 | ascii_to_nibble(*(endptr
+1)); 
 501                                 hmcfgusb_serial 
= optarg
; 
 507                                 flash_ota_syntax(argv
[0]); 
 514         if (!fw_file 
|| (!serial 
&& !hmid
)) { 
 515                 flash_ota_syntax(argv
[0]); 
 519         fw 
= firmware_read_firmware(fw_file
, debug
); 
 523         memset(&rdata
, 0, sizeof(rdata
)); 
 524         memset(&dev
, 0, sizeof(struct ota_dev
)); 
 527                 printf("Opening culfw-device at path %s with speed %u\n", culfw_dev
, bps
); 
 528                 dev
.culfw 
= culfw_init(culfw_dev
, bps
, parse_culfw
, &rdata
); 
 530                         fprintf(stderr
, "Can't initialize CUL at %s with rate %u\n", culfw_dev
, bps
); 
 533                 dev
.type 
= DEVICE_TYPE_CULFW
; 
 535                 printf("Requesting firmware version\n"); 
 536                 culfw_send(dev
.culfw
, "\r\n", 2); 
 537                 culfw_flush(dev
.culfw
); 
 540                         culfw_send(dev
.culfw
, "V\r\n", 3); 
 543                         pfd 
= culfw_poll(dev
.culfw
, 1000); 
 544                         if ((pfd 
< 0) && errno
) { 
 545                                 if (errno 
!= ETIMEDOUT
) { 
 546                                         perror("\n\nhmcfgusb_poll"); 
 554                 printf("culfw-device firmware version: "); 
 555                 if (rdata
.version 
!= 0xffff) { 
 557                                 (rdata
.version 
>> 8) & 0xff, 
 558                                 rdata
.version 
& 0xff); 
 563                 if (rdata
.version 
< 0x013a) { 
 564                         fprintf(stderr
, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n"); 
 568                 uint32_t new_hmid 
= my_hmid
; 
 570                 hmcfgusb_set_debug(debug
); 
 572                 dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
); 
 574                         fprintf(stderr
, "Can't initialize HM-CFG-USB\n"); 
 577                 dev
.type 
= DEVICE_TYPE_HMCFGUSB
; 
 579                 memset(out
, 0, sizeof(out
)); 
 581                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 585                         pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 586                         if ((pfd 
< 0) && errno
) { 
 587                                 if (errno 
!= ETIMEDOUT
) { 
 588                                         perror("\n\nhmcfgusb_poll"); 
 596                 if (rdata
.version 
< 0x3c7) { 
 597                         fprintf(stderr
, "HM-CFG-USB firmware too low: %u < 967\n", rdata
.version
); 
 601                 printf("HM-CFG-USB firmware version: %u, used credits: %u%%\n", rdata
.version
, rdata
.credits
); 
 603                 if (rdata
.credits 
>= 40) { 
 604                         printf("\nRebooting HM-CFG-USB to avoid running out of credits\n\n"); 
 606                         if (!dev
.hmcfgusb
->bootloader
) { 
 607                                 printf("HM-CFG-USB not in bootloader mode, entering bootloader.\n"); 
 608                                 printf("Waiting for device to reappear...\n"); 
 612                                                 if (!dev
.hmcfgusb
->bootloader
) 
 613                                                         hmcfgusb_enter_bootloader(dev
.hmcfgusb
); 
 614                                                 hmcfgusb_close(dev
.hmcfgusb
); 
 617                                 } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
)) == NULL
) || (!dev
.hmcfgusb
->bootloader
)); 
 620                         if (dev
.hmcfgusb
->bootloader
) { 
 621                                 printf("HM-CFG-USB in bootloader mode, rebooting\n"); 
 625                                                 if (dev
.hmcfgusb
->bootloader
) 
 626                                                         hmcfgusb_leave_bootloader(dev
.hmcfgusb
); 
 627                                                 hmcfgusb_close(dev
.hmcfgusb
); 
 630                                 } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
)) == NULL
) || (dev
.hmcfgusb
->bootloader
)); 
 634                 printf("\n\nHM-CFG-USB opened\n\n"); 
 636                 if (new_hmid 
&& (my_hmid 
!= new_hmid
)) { 
 637                         printf("Changing hmid from %06x to %06x\n", my_hmid
, new_hmid
); 
 639                         memset(out
, 0, sizeof(out
)); 
 641                         out
[1] = (new_hmid 
>> 16) & 0xff; 
 642                         out
[2] = (new_hmid 
>> 8) & 0xff; 
 643                         out
[3] = new_hmid 
& 0xff; 
 645                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 651                         printf("Setting AES-key\n"); 
 653                         memset(out
, 0, sizeof(out
)); 
 657                         out
[3] = sizeof(key
); 
 658                         memcpy(&(out
[4]), key
, sizeof(key
)); 
 659                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 661                         memset(out
, 0, sizeof(out
)); 
 666                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 668                         memset(out
, 0, sizeof(out
)); 
 673                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 677         if (!switch_speed(&dev
, &rdata
, 10)) { 
 678                 fprintf(stderr
, "Can't switch speed!\n"); 
 682         if (hmid 
&& my_hmid
) { 
 683                 printf("Sending device with hmid %06x to bootloader\n", hmid
); 
 686                 SET_SRC(out
, my_hmid
); 
 689                 SET_LEN_FROM_PAYLOADLEN(out
, 1); 
 693                         out
[MSGID
] = msgid
++; 
 694                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 699                         printf("Failed to send device to bootloader, please enter bootloader manually.\n"); 
 704                 printf("Waiting for device with serial %s\n", serial
); 
 706                 printf("Waiting for device with HMID %06x\n", hmid
); 
 712                         case DEVICE_TYPE_CULFW
: 
 713                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
 715                         case DEVICE_TYPE_HMCFGUSB
: 
 717                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 721                 if ((pfd 
< 0) && errno
) { 
 722                         if (errno 
!= ETIMEDOUT
) { 
 728                 if ((rdata
.message
[LEN
] == 0x14) && /* Length */ 
 729                     (rdata
.message
[MSGID
] == 0x00) && /* Message ID */ 
 730                     (rdata
.message
[CTL
] == 0x00) && /* Control Byte */ 
 731                     (rdata
.message
[TYPE
] == 0x10) && /* Messagte type: Information */ 
 732                     (DST(rdata
.message
) == 0x000000) && /* Broadcast */ 
 733                     (rdata
.message
[PAYLOAD
] == 0x00)) { /* FUP? */ 
 734                         if (serial 
&& !strncmp((char*)&(rdata
.message
[0x0b]), serial
, 10)) { 
 735                                 hmid 
= SRC(rdata
.message
); 
 737                         } else if (!serial 
&& SRC(rdata
.message
) == hmid
) { 
 738                                 serial 
= (char*)&(rdata
.message
[0x0b]); 
 744         printf("Device with serial %s (HMID: %06x) entered firmware-update-mode\n", serial
, hmid
); 
 746         if (dev
.type 
== DEVICE_TYPE_HMCFGUSB
) { 
 747                 printf("Adding HMID\n"); 
 749                 memset(out
, 0, sizeof(out
)); 
 751                 out
[1] = (hmid 
>> 16) & 0xff; 
 752                 out
[2] = (hmid 
>> 8) & 0xff; 
 753                 out
[3] = hmid 
& 0xff; 
 755                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 760                 printf("Initiating remote switch to 100k\n"); 
 762                 memset(out
, 0, sizeof(out
)); 
 764                 out
[MSGID
] = msgid
++; 
 767                 SET_SRC(out
, my_hmid
); 
 770                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
 771                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
 773                 if (!send_hm_message(&dev
, &rdata
, out
)) { 
 777                 if (!switch_speed(&dev
, &rdata
, 100)) { 
 778                         fprintf(stderr
, "Can't switch speed!\n"); 
 782                 printf("Has the device switched?\n"); 
 784                 memset(out
, 0, sizeof(out
)); 
 786                 out
[MSGID
] = msgid
++; 
 789                 SET_SRC(out
, my_hmid
); 
 792                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
 793                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
 797                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 798                                 /* A0A02000221B9AD00000000 */ 
 807                         if (!switch_speed(&dev
, &rdata
, 10)) { 
 808                                 fprintf(stderr
, "Can't switch speed!\n"); 
 812         } while ((!switched
) && (switchcnt
--)); 
 815                 fprintf(stderr
, "Too many errors, giving up!\n"); 
 821         printf("Flashing %d blocks", fw
->fw_blocks
); 
 825                 printf(": %04u/%04u %c", 0, fw
->fw_blocks
, twiddlie
[0]); 
 829         for (block 
= 0; block 
< fw
->fw_blocks
; block
++) { 
 832                 len 
= fw
->fw
[block
][2] << 8; 
 833                 len 
|= fw
->fw
[block
][3]; 
 835                 pos 
= &(fw
->fw
[block
][2]); 
 837                 len 
+= 2; /* length */ 
 840                         hexdump(pos
, len
, "F> "); 
 845                         int payloadlen 
= max_payloadlen 
- 2; 
 849                                 payloadlen 
= max_payloadlen
; 
 853                         if ((len 
- (pos 
- &(fw
->fw
[block
][2]))) < payloadlen
) 
 854                                 payloadlen 
= (len 
- (pos 
- &(fw
->fw
[block
][2]))); 
 856                         if (((pos 
+ payloadlen
) - &(fw
->fw
[block
][2])) == len
) 
 859                         memset(&rdata
, 0, sizeof(rdata
)); 
 861                         memset(out
, 0, sizeof(out
)); 
 867                         SET_SRC(out
, my_hmid
); 
 870                         memcpy(&out
[PAYLOAD
], pos
, payloadlen
); 
 871                         SET_LEN_FROM_PAYLOADLEN(out
, payloadlen
); 
 873                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 876                                 pos 
= &(fw
->fw
[block
][2]); 
 878                                 if (cnt 
== MAX_RETRIES
) { 
 879                                         fprintf(stderr
, "\nToo many errors, giving up!\n"); 
 882                                         printf("Flashing %d blocks: %04u/%04u %c", fw
->fw_blocks
, block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
 889                                 printf("\b\b\b\b\b\b\b\b\b\b\b%04u/%04u %c", 
 890                                         block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
 893                 } while((pos 
- &(fw
->fw
[block
][2])) < len
); 
 901         if (!switch_speed(&dev
, &rdata
, 10)) { 
 902                 fprintf(stderr
, "Can't switch speed!\n"); 
 906         printf("Waiting for device to reboot\n"); 
 912                         case DEVICE_TYPE_CULFW
: 
 913                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
 915                         case DEVICE_TYPE_HMCFGUSB
: 
 917                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 920                 if ((pfd 
< 0) && errno
) { 
 921                         if (errno 
!= ETIMEDOUT
) { 
 926                 if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
 931         if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
 932                 printf("Device rebooted\n"); 
 936                 case DEVICE_TYPE_HMCFGUSB
: 
 937                         hmcfgusb_close(dev
.hmcfgusb
); 
 940                 case DEVICE_TYPE_CULFW
: 
 941                         culfw_close(dev
.culfw
);