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> 
  44 #include "hmuartlgw.h" 
  48 #define NORMAL_MAX_PAYLOAD      37 
  49 #define LOWER_MAX_PAYLOAD       17 
  55 uint8_t key
[16] = {0}; 
  58 /* Maximum payloadlen supported by IO */ 
  59 uint32_t max_payloadlen 
= NORMAL_MAX_PAYLOAD
; 
  66 enum hmuartlgw_state 
{ 
  67         HMUARTLGW_STATE_GET_HMID
, 
  68         HMUARTLGW_STATE_GET_FIRMWARE
, 
  69         HMUARTLGW_STATE_GET_CREDITS
, 
  71         HMUARTLGW_STATE_WAIT_APP
, 
  72         HMUARTLGW_STATE_ACK_APP
, 
  77         enum message_type message_type
; 
  82         enum hmuartlgw_state uartlgw_state
; 
  83         uint8_t uartlgw_version
[3]; 
  86 static int parse_hmcfgusb(uint8_t *buf
, int buf_len
, void *data
) 
  88         struct recv_data 
*rdata 
= data
; 
  96                             ((buf
[0x11] == ((hmid 
>> 16) & 0xff)) && 
  97                             (buf
[0x12] == ((hmid 
>> 8) & 0xff)) && 
  98                             (buf
[0x13] == (hmid 
& 0xff)))) { 
  99                                 memset(rdata
->message
, 0, sizeof(rdata
->message
)); 
 100                                 memcpy(rdata
->message
, buf 
+ 0x0d, buf
[0x0d] + 1); 
 101                                 rdata
->message_type 
= MESSAGE_TYPE_E
; 
 105                         memset(rdata
->message
, 0, sizeof(rdata
->message
)); 
 106                         memcpy(rdata
->message
, buf 
+ 0x0e, buf
[0x0e] + 1); 
 107                         rdata
->status 
= (buf
[5] << 8) | buf
[6]; 
 108                         rdata
->message_type 
= MESSAGE_TYPE_R
; 
 111                         rdata
->speed 
= buf
[1]; 
 114                         rdata
->version 
= (buf
[11] << 8) | buf
[12]; 
 115                         rdata
->credits 
= buf
[36]; 
 116                         my_hmid 
= (buf
[0x1b] << 16) | (buf
[0x1c] << 8) | buf
[0x1d]; 
 128 static int parse_culfw(uint8_t *buf
, int buf_len
, void *data
) 
 130         struct recv_data 
*rdata 
= data
; 
 133         memset(rdata
, 0, sizeof(struct recv_data
)); 
 143                         while(validate_nibble(buf
[(pos 
* 2) + 1]) && 
 144                               validate_nibble(buf
[(pos 
* 2) + 2]) && 
 145                               (pos 
+ 1 < buf_len
)) { 
 146                                 rdata
->message
[pos
] = ascii_to_nibble(buf
[(pos 
* 2) + 1]) << 4; 
 147                                 rdata
->message
[pos
] |= ascii_to_nibble(buf
[(pos 
* 2) + 2]); 
 151                         if (hmid 
&& (SRC(rdata
->message
) != hmid
)) 
 154                         rdata
->message_type 
= MESSAGE_TYPE_E
; 
 162                                 s 
= ((char*)buf
) + 2; 
 165                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 170                                 rdata
->version 
= v 
<< 8; 
 175                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 188                                 if (!strcmp(s
, "a-culfw")) { 
 189                                         rdata
->version 
= 0xffff; 
 195                                 if (!strncmp((char*)buf
, "ERR:CCA", 7)) { 
 196                                         fprintf(stderr
, "CCA didn't complete, too much traffic\n"); 
 201                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 209 static int parse_hmuartlgw(enum hmuartlgw_dst dst
, uint8_t *buf
, int buf_len
, void *data
) 
 211         struct recv_data 
*rdata 
= data
; 
 213         if (dst 
== HMUARTLGW_OS
) { 
 214                 switch (rdata
->uartlgw_state
) { 
 215                         case HMUARTLGW_STATE_GET_FIRMWARE
: 
 216                                 if (buf
[0] == HMUARTLGW_OS_ACK
) { 
 217                                         rdata
->uartlgw_version
[0] = buf
[5]; 
 218                                         rdata
->uartlgw_version
[1] = buf
[6]; 
 219                                         rdata
->uartlgw_version
[2] = buf
[7]; 
 220                                         rdata
->uartlgw_state 
= HMUARTLGW_STATE_DONE
; 
 223                         case HMUARTLGW_STATE_GET_CREDITS
: 
 224                                 if (buf
[0] == HMUARTLGW_OS_ACK
) { 
 225                                         rdata
->credits 
= buf
[2] / 2; 
 226                                         rdata
->uartlgw_state 
= HMUARTLGW_STATE_DONE
; 
 236                 case HMUARTLGW_APP_ACK
: 
 237                         if (rdata
->uartlgw_state 
== HMUARTLGW_STATE_GET_HMID
) { 
 238                                 my_hmid 
= (buf
[4] << 16) | (buf
[5] << 8) | buf
[6]; 
 241                         rdata
->status 
= buf
[1]; 
 242                         rdata
->message_type 
= MESSAGE_TYPE_R
; 
 243                         rdata
->uartlgw_state 
= HMUARTLGW_STATE_ACK_APP
; 
 245                         hexdump(buf
, buf_len
, "ACK Status: "); 
 249                 case HMUARTLGW_APP_RECV
: 
 251                             ((buf
[7] == ((hmid 
>> 16) & 0xff)) && 
 252                             (buf
[8] == ((hmid 
>> 8) & 0xff)) && 
 253                             (buf
[9] == (hmid 
& 0xff)))) { 
 254                                 memset(rdata
->message
, 0, sizeof(rdata
->message
)); 
 255                                 memcpy(rdata
->message 
+ 1, buf 
+ 4, buf_len 
- 4); 
 256                                 rdata
->message
[LEN
] = buf_len 
- 4; 
 257                                 rdata
->message_type 
= MESSAGE_TYPE_E
; 
 267 int send_wait_hmuartlgw(struct hm_dev 
*dev
, struct recv_data 
*rdata
, uint8_t *data
, int data_len
, 
 268                         enum hmuartlgw_dst dst
, enum hmuartlgw_state srcstate
, 
 269                         enum hmuartlgw_state dststate
) 
 274                 rdata
->uartlgw_state 
= srcstate
; 
 275                 hmuartlgw_send(dev
->hmuartlgw
, data
, data_len
, dst
); 
 276                 do { hmuartlgw_poll(dev
->hmuartlgw
, 500); } while (rdata
->uartlgw_state 
!= dststate
); 
 277                 if (rdata
->status 
!= HMUARTLGW_ACK_EINPROGRESS
) 
 281         if (rdata
->status 
== HMUARTLGW_ACK_EINPROGRESS
) { 
 282                 fprintf(stderr
, "IO thinks it is busy, you might have to reset it!\n"); 
 289 int send_hm_message(struct hm_dev 
*dev
, struct recv_data 
*rdata
, uint8_t *msg
) 
 291         static uint32_t id 
= 1; 
 297                 case DEVICE_TYPE_HMCFGUSB
: 
 298                         if (gettimeofday(&tv
, NULL
) == -1) { 
 299                                 perror("gettimeofay"); 
 303                         memset(out
, 0, sizeof(out
)); 
 306                         out
[1] = (id 
>> 24) & 0xff; 
 307                         out
[2] = (id 
>> 16) & 0xff; 
 308                         out
[3] = (id 
>> 8) & 0xff; 
 311                         out
[11] = (tv
.tv_usec 
>> 24) & 0xff; 
 312                         out
[12] = (tv
.tv_usec 
>> 16) & 0xff; 
 313                         out
[13] = (tv
.tv_usec 
>> 8) & 0xff; 
 314                         out
[14] = tv
.tv_usec 
& 0xff; 
 316                         memcpy(&out
[0x0f], msg
, msg
[0] + 1); 
 318                         memset(rdata
, 0, sizeof(struct recv_data
)); 
 319                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 322                                 if (rdata
->message_type 
== MESSAGE_TYPE_R
) { 
 323                                         if (((rdata
->status 
& 0xdf) == 0x01) || 
 324                                             ((rdata
->status 
& 0xdf) == 0x02)) { 
 327                                                 if ((rdata
->status 
& 0xff00) == 0x0400) { 
 328                                                         fprintf(stderr
, "\nOut of credits!\n"); 
 329                                                 } else if ((rdata
->status 
& 0xff) == 0x08) { 
 330                                                         fprintf(stderr
, "\nMissing ACK!\n"); 
 331                                                 } else if ((rdata
->status 
& 0xff) == 0x30) { 
 332                                                         fprintf(stderr
, "\nUnknown AES-key requested!\n"); 
 334                                                         fprintf(stderr
, "\nInvalid status: %04x\n", rdata
->status
); 
 340                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 341                                 if ((pfd 
< 0) && errno
) { 
 342                                         if (errno 
!= ETIMEDOUT
) { 
 343                                                 perror("\n\nhmcfgusb_poll"); 
 349                 case DEVICE_TYPE_CULFW
: 
 354                                 memset(buf
, 0, sizeof(buf
)); 
 357                                 for (i 
= 0; i 
< msg
[0] + 1; i
++) { 
 358                                         buf
[2 + (i 
* 2)] = nibble_to_ascii((msg
[i
] >> 4) & 0xf); 
 359                                         buf
[2 + (i 
* 2) + 1] = nibble_to_ascii(msg
[i
] & 0xf); 
 361                                 buf
[2 + (i 
* 2) ] = '\r'; 
 362                                 buf
[2 + (i 
* 2) + 1] = '\n'; 
 364                                 memset(rdata
, 0, sizeof(struct recv_data
)); 
 365                                 if (culfw_send(dev
->culfw
, buf
, 2 + (i 
* 2) + 1) == 0) { 
 366                                         fprintf(stderr
, "culfw_send failed!\n"); 
 370                                 if (msg
[CTL
] & 0x20) { 
 375                                                 pfd 
= culfw_poll(dev
->culfw
, 200); 
 376                                                 if ((pfd 
< 0) && errno
) { 
 377                                                         if (errno 
!= ETIMEDOUT
) { 
 378                                                                 perror("\n\nculfw_poll"); 
 382                                                 if (rdata
->message_type 
== MESSAGE_TYPE_E
) { 
 383                                                         if (rdata
->message
[TYPE
] == 0x02) { 
 384                                                                 if (rdata
->message
[PAYLOAD
] == 0x04) { 
 386                                                                         uint8_t challenge
[6]; 
 390                                                                         req_kNo 
= rdata
->message
[rdata
->message
[LEN
]] / 2; 
 391                                                                         memcpy(challenge
, &(rdata
->message
[PAYLOAD
+1]), 6); 
 393                                                                         if (req_kNo 
!= kNo
) { 
 394                                                                                 fprintf(stderr
, "AES request for unknown key %d!\n", req_kNo
); 
 396                                                                                 resp 
= hm_sign(key
, challenge
, msg
, NULL
, respbuf
); 
 400                                                                                         memset(rbuf
, 0, sizeof(rbuf
)); 
 401                                                                                         rbuf
[MSGID
] = rdata
->message
[MSGID
]; 
 402                                                                                         rbuf
[CTL
] = rdata
->message
[CTL
]; 
 404                                                                                         SET_SRC(rbuf
, DST(rdata
->message
)); 
 405                                                                                         SET_DST(rbuf
, SRC(rdata
->message
)); 
 406                                                                                         memcpy(&(rbuf
[PAYLOAD
]), resp
, 16); 
 407                                                                                         SET_LEN_FROM_PAYLOADLEN(rbuf
, 16); 
 409                                                                                         usleep(110000); /* Determined by a fair dice roll */ 
 410                                                                                         return send_hm_message(dev
, rdata
, rbuf
); 
 413                                                                 } else if (rdata
->message
[PAYLOAD
] >= 0x80 && rdata
->message
[PAYLOAD
] <= 0x8f) { 
 414                                                                         fprintf(stderr
, "NACK\n"); 
 415                                                                 } else {        /* ACK or ACKinfo */ 
 419                                                                 fprintf(stderr
, "Unexpected message received: "); 
 420                                                                 for (i 
= 0; i 
< rdata
->message
[LEN
]; i
++) { 
 421                                                                         fprintf(stderr
, "%02x", rdata
->message
[i
+1]); 
 423                                                                 fprintf(stderr
, "\n"); 
 429                                                 fprintf(stderr
, "\nMissing ACK!\n"); 
 435                 case DEVICE_TYPE_HMUARTLGW
: 
 436                         memset(out
, 0, sizeof(out
)); 
 438                         out
[0] = HMUARTLGW_APP_SEND
; 
 441                         out
[3] = (msg
[CTL
] & 0x10) ? 0x01 : 0x00; /* Burst?! */ 
 442                         memcpy(&out
[4], &msg
[1], msg
[0]); 
 444                         memset(rdata
, 0, sizeof(struct recv_data
)); 
 445                         hmuartlgw_send(dev
->hmuartlgw
, out
, msg
[0] + 4, HMUARTLGW_APP
); 
 448                                 if (rdata
->message_type 
== MESSAGE_TYPE_R
) { 
 449                                         if ((rdata
->status 
== 0x02) || 
 450                                             (rdata
->status 
== 0x03) || 
 451                                             (rdata
->status 
== 0x0c)) { 
 454                                                 if (rdata
->status 
== 0x0d) { 
 455                                                         fprintf(stderr
, "\nAES handshake failed!\n"); 
 456                                                 } else if (rdata
->status 
== 0x04 || rdata
->status 
== 0x06) { 
 457                                                         fprintf(stderr
, "\nMissing ACK!\n"); 
 459                                                         fprintf(stderr
, "\nInvalid status: %04x\n", rdata
->status
); 
 465                                 pfd 
= hmuartlgw_poll(dev
->hmuartlgw
, 1000); 
 466                                 if ((pfd 
< 0) && errno
) { 
 467                                         if (errno 
!= ETIMEDOUT
) { 
 468                                                 perror("\n\nhmcfgusb_poll"); 
 480 static int switch_speed(struct hm_dev 
*dev
, struct recv_data 
*rdata
, uint8_t speed
) 
 485         printf("Entering %uk-mode\n", speed
); 
 488                 case DEVICE_TYPE_HMCFGUSB
: 
 489                         memset(out
, 0, sizeof(out
)); 
 493                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 497                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 498                                 if ((pfd 
< 0) && errno
) { 
 499                                         if (errno 
!= ETIMEDOUT
) { 
 500                                                 perror("\n\nhmcfgusb_poll"); 
 504                                 if (rdata
->speed 
== speed
) 
 508                 case DEVICE_TYPE_CULFW
: 
 510                                 return culfw_send(dev
->culfw
, "AR\r\n", 4); 
 512                                 return culfw_send(dev
->culfw
, "Ar\r\n", 4); 
 515                 case DEVICE_TYPE_HMUARTLGW
: 
 517                                 out
[0] = HMUARTLGW_OS_UPDATE_MODE
; 
 520                                 hmuartlgw_send(dev
->hmuartlgw
, out
, 3, HMUARTLGW_OS
); 
 522                                 out
[0] = HMUARTLGW_OS_NORMAL_MODE
; 
 523                                 hmuartlgw_send(dev
->hmuartlgw
, out
, 1, HMUARTLGW_OS
); 
 531 void flash_ota_syntax(char *prog
) 
 533         fprintf(stderr
, "Syntax: %s parameters options\n\n", prog
); 
 534         fprintf(stderr
, "Mandatory parameters:\n"); 
 535         fprintf(stderr
, "\t-f firmware.eq3\tfirmware file to flash\n"); 
 536         fprintf(stderr
, "\t-s SERIAL\tserial of device to flash (optional when using -D)\n"); 
 537         fprintf(stderr
, "\nOptional parameters:\n"); 
 538         fprintf(stderr
, "\t-c device\tenable CUL-mode with CUL at path \"device\"\n"); 
 539         fprintf(stderr
, "\t-b bps\t\tuse CUL with speed \"bps\" (default: %u)\n", DEFAULT_CUL_BPS
); 
 540         fprintf(stderr
, "\t-l\t\tlower payloadlen (required for devices with little RAM, e.g. CUL v2 and CUL v4)\n"); 
 541         fprintf(stderr
, "\t-S serial\tuse HM-CFG-USB with given serial\n"); 
 542         fprintf(stderr
, "\t-U device\tuse HM-MOD-UART on given device\n"); 
 543         fprintf(stderr
, "\t-h\t\tthis help\n"); 
 544         fprintf(stderr
, "\nOptional parameters for automatically sending device to bootloader\n"); 
 545         fprintf(stderr
, "\t-C\t\tHMID of central (3 hex-bytes, no prefix, e.g. ABCDEF)\n"); 
 546         fprintf(stderr
, "\t-D\t\tHMID of device (3 hex-bytes, no prefix, e.g. 123456)\n"); 
 547         fprintf(stderr
, "\t-K\t\tKNO:KEY AES key-number and key (hex) separated by colon (Fhem hmKey attribute)\n"); 
 550 int main(int argc
, char **argv
) 
 552         const char twiddlie
[] = { '-', '\\', '|', '/' }; 
 553         const uint8_t cc1101_regs
[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 }; 
 554         char *fw_file 
= NULL
; 
 556         char *culfw_dev 
= NULL
; 
 558         unsigned int bps 
= DEFAULT_CUL_BPS
; 
 560         struct recv_data rdata
; 
 566         char *hmcfgusb_serial 
= NULL
; 
 577         printf("HomeMatic OTA flasher version " VERSION 
"\n\n"); 
 579         while((opt 
= getopt(argc
, argv
, "b:c:f:hls:C:D:K:S:U:")) != -1) { 
 591                                 printf("Reducing payload-len from %d to %d\n", max_payloadlen
, LOWER_MAX_PAYLOAD
); 
 592                                 max_payloadlen 
= LOWER_MAX_PAYLOAD
; 
 598                                 my_hmid 
= strtoul(optarg
, &endptr
, 16); 
 599                                 if (*endptr 
!= '\0') { 
 600                                         fprintf(stderr
, "Invalid central HMID!\n\n"); 
 601                                         flash_ota_syntax(argv
[0]); 
 606                                 hmid 
= strtoul(optarg
, &endptr
, 16); 
 607                                 if (*endptr 
!= '\0') { 
 608                                         fprintf(stderr
, "Invalid device HMID!\n\n"); 
 609                                         flash_ota_syntax(argv
[0]); 
 614                                 kNo 
= strtoul(optarg
, &endptr
, 10); 
 615                                 if (*endptr 
!= ':') { 
 616                                         fprintf(stderr
, "Invalid key number!\n\n"); 
 617                                         flash_ota_syntax(argv
[0]); 
 621                                 for (cnt 
= 0; cnt 
< 16; cnt
++) { 
 622                                         if (*endptr 
== '\0' || *(endptr
+1) == '\0' || 
 623                                             !validate_nibble(*endptr
) || 
 624                                             !validate_nibble(*(endptr
+1))) { 
 625                                                 fprintf(stderr
, "Invalid key!\n\n"); 
 626                                                 flash_ota_syntax(argv
[0]); 
 629                                         key
[cnt
] = ascii_to_nibble(*endptr
) << 4 | ascii_to_nibble(*(endptr
+1)); 
 634                                 hmcfgusb_serial 
= optarg
; 
 643                                 flash_ota_syntax(argv
[0]); 
 650         if (!fw_file 
|| (!serial 
&& !hmid
)) { 
 651                 flash_ota_syntax(argv
[0]); 
 655         fw 
= firmware_read_firmware(fw_file
, debug
); 
 659         memset(&rdata
, 0, sizeof(rdata
)); 
 660         memset(&dev
, 0, sizeof(struct hm_dev
)); 
 663                 printf("Opening culfw-device at path %s with speed %u\n", culfw_dev
, bps
); 
 664                 dev
.culfw 
= culfw_init(culfw_dev
, bps
, parse_culfw
, &rdata
); 
 666                         fprintf(stderr
, "Can't initialize CUL at %s with rate %u\n", culfw_dev
, bps
); 
 669                 dev
.type 
= DEVICE_TYPE_CULFW
; 
 671                 printf("Requesting firmware version\n"); 
 672                 culfw_send(dev
.culfw
, "\r\n", 2); 
 673                 culfw_flush(dev
.culfw
); 
 676                         culfw_send(dev
.culfw
, "V\r\n", 3); 
 679                         pfd 
= culfw_poll(dev
.culfw
, 1000); 
 680                         if ((pfd 
< 0) && errno
) { 
 681                                 if (errno 
!= ETIMEDOUT
) { 
 682                                         perror("\n\nhmcfgusb_poll"); 
 690                 printf("culfw-device firmware version: "); 
 691                 if (rdata
.version 
!= 0xffff) { 
 693                                 (rdata
.version 
>> 8) & 0xff, 
 694                                 rdata
.version 
& 0xff); 
 699                 if (rdata
.version 
< 0x013a) { 
 700                         fprintf(stderr
, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n"); 
 704                 uint32_t new_hmid 
= my_hmid
; 
 706                 hmuartlgw_set_debug(debug
); 
 707                 hmuartlgw_set_debug(1); 
 709                 dev
.hmuartlgw 
= hmuart_init(uart
, parse_hmuartlgw
, &rdata
); 
 710                 if (!dev
.hmuartlgw
) { 
 711                         fprintf(stderr
, "Can't initialize HM-MOD-UART\n"); 
 714                 dev
.type 
= DEVICE_TYPE_HMUARTLGW
; 
 716                 out
[0] = HMUARTLGW_APP_GET_HMID
; 
 717                 send_wait_hmuartlgw(&dev
, &rdata
, out
, 1, HMUARTLGW_APP
, HMUARTLGW_STATE_GET_HMID
, HMUARTLGW_STATE_ACK_APP
); 
 719                 out
[0] = HMUARTLGW_OS_GET_FIRMWARE
; 
 720                 send_wait_hmuartlgw(&dev
, &rdata
, out
, 1, HMUARTLGW_OS
, HMUARTLGW_STATE_GET_FIRMWARE
, HMUARTLGW_STATE_DONE
); 
 722                 out
[0] = HMUARTLGW_OS_GET_CREDITS
; 
 723                 send_wait_hmuartlgw(&dev
, &rdata
, out
, 1, HMUARTLGW_OS
, HMUARTLGW_STATE_GET_CREDITS
, HMUARTLGW_STATE_DONE
); 
 725                 printf("HM-MOD-UART firmware version: %u.%u.%u, used credits: %u%%\n", 
 726                         rdata
.uartlgw_version
[0], 
 727                         rdata
.uartlgw_version
[1], 
 728                         rdata
.uartlgw_version
[2], 
 731                 if (rdata
.credits 
>= 40) { 
 732                         printf("\nRebooting HM-MOD-UART to avoid running out of credits\n"); 
 734                         hmuartlgw_enter_bootloader(dev
.hmuartlgw
); 
 735                         hmuartlgw_enter_app(dev
.hmuartlgw
); 
 738                 printf("\nHM-MOD-UART opened\n\n"); 
 740                 if (new_hmid 
&& (my_hmid 
!= new_hmid
)) { 
 741                         printf("Changing hmid from %06x to %06x\n", my_hmid
, new_hmid
); 
 743                         out
[0] = HMUARTLGW_APP_SET_HMID
; 
 744                         out
[1] = (new_hmid 
>> 16) & 0xff; 
 745                         out
[2] = (new_hmid 
>> 8) & 0xff; 
 746                         out
[3] = new_hmid 
& 0xff; 
 747                         send_wait_hmuartlgw(&dev
, &rdata
, out
, 4, HMUARTLGW_APP
, HMUARTLGW_STATE_WAIT_APP
, HMUARTLGW_STATE_ACK_APP
); 
 753                         printf("Setting AES-key\n"); 
 755                         memset(out
, 0, sizeof(out
)); 
 756                         out
[0] = HMUARTLGW_APP_SET_CURRENT_KEY
; 
 757                         memcpy(&(out
[1]), key
, 16); 
 759                         send_wait_hmuartlgw(&dev
, &rdata
, out
, 18, HMUARTLGW_APP
, HMUARTLGW_STATE_WAIT_APP
, HMUARTLGW_STATE_ACK_APP
); 
 761                         memset(out
, 0, sizeof(out
)); 
 762                         out
[0] = HMUARTLGW_APP_SET_OLD_KEY
; 
 763                         memcpy(&(out
[1]), key
, 16); 
 765                         send_wait_hmuartlgw(&dev
, &rdata
, out
, 18, HMUARTLGW_APP
, HMUARTLGW_STATE_WAIT_APP
, HMUARTLGW_STATE_ACK_APP
); 
 768                 uint32_t new_hmid 
= my_hmid
; 
 770                 hmcfgusb_set_debug(debug
); 
 772                 dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
); 
 774                         fprintf(stderr
, "Can't initialize HM-CFG-USB\n"); 
 777                 dev
.type 
= DEVICE_TYPE_HMCFGUSB
; 
 779                 memset(out
, 0, sizeof(out
)); 
 781                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 785                         pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 786                         if ((pfd 
< 0) && errno
) { 
 787                                 if (errno 
!= ETIMEDOUT
) { 
 788                                         perror("\n\nhmcfgusb_poll"); 
 796                 if (rdata
.version 
< 0x3c7) { 
 797                         fprintf(stderr
, "HM-CFG-USB firmware too low: %u < 967\n", rdata
.version
); 
 801                 printf("HM-CFG-USB firmware version: %u, used credits: %u%%\n", rdata
.version
, rdata
.credits
); 
 803                 if (rdata
.credits 
>= 40) { 
 804                         printf("\nRebooting HM-CFG-USB to avoid running out of credits\n\n"); 
 806                         if (!dev
.hmcfgusb
->bootloader
) { 
 807                                 printf("HM-CFG-USB not in bootloader mode, entering bootloader.\n"); 
 808                                 printf("Waiting for device to reappear...\n"); 
 812                                                 if (!dev
.hmcfgusb
->bootloader
) 
 813                                                         hmcfgusb_enter_bootloader(dev
.hmcfgusb
); 
 814                                                 hmcfgusb_close(dev
.hmcfgusb
); 
 817                                 } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
)) == NULL
) || (!dev
.hmcfgusb
->bootloader
)); 
 820                         if (dev
.hmcfgusb
->bootloader
) { 
 821                                 printf("HM-CFG-USB in bootloader mode, rebooting\n"); 
 825                                                 if (dev
.hmcfgusb
->bootloader
) 
 826                                                         hmcfgusb_leave_bootloader(dev
.hmcfgusb
); 
 827                                                 hmcfgusb_close(dev
.hmcfgusb
); 
 830                                 } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
, hmcfgusb_serial
)) == NULL
) || (dev
.hmcfgusb
->bootloader
)); 
 834                 printf("\n\nHM-CFG-USB opened\n\n"); 
 836                 if (new_hmid 
&& (my_hmid 
!= new_hmid
)) { 
 837                         printf("Changing hmid from %06x to %06x\n", my_hmid
, new_hmid
); 
 839                         memset(out
, 0, sizeof(out
)); 
 841                         out
[1] = (new_hmid 
>> 16) & 0xff; 
 842                         out
[2] = (new_hmid 
>> 8) & 0xff; 
 843                         out
[3] = new_hmid 
& 0xff; 
 845                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 851                         printf("Setting AES-key\n"); 
 853                         memset(out
, 0, sizeof(out
)); 
 857                         out
[3] = sizeof(key
); 
 858                         memcpy(&(out
[4]), key
, sizeof(key
)); 
 859                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 861                         memset(out
, 0, sizeof(out
)); 
 866                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 868                         memset(out
, 0, sizeof(out
)); 
 873                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 877         if (!switch_speed(&dev
, &rdata
, 10)) { 
 878                 fprintf(stderr
, "Can't switch speed!\n"); 
 882         if (hmid 
&& my_hmid
) { 
 884                         case DEVICE_TYPE_HMCFGUSB
: 
 885                                 printf("Adding HMID\n"); 
 887                                 memset(out
, 0, sizeof(out
)); 
 889                                 out
[1] = (hmid 
>> 16) & 0xff; 
 890                                 out
[2] = (hmid 
>> 8) & 0xff; 
 891                                 out
[3] = hmid 
& 0xff; 
 893                                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 895                         case DEVICE_TYPE_HMUARTLGW
: 
 896                                 printf("Adding HMID\n"); 
 898                                 memset(out
, 0, sizeof(out
)); 
 899                                 out
[0] = HMUARTLGW_APP_ADD_PEER
; 
 900                                 out
[1] = (hmid 
>> 16) & 0xff; 
 901                                 out
[2] = (hmid 
>> 8) & 0xff; 
 902                                 out
[3] = hmid 
& 0xff; 
 903                                 out
[4] = (kNo 
> 0) ? kNo 
: 0x00; /* KeyIndex */ 
 904                                 out
[5] = 0x00; /* WakeUp? */ 
 905                                 out
[6] = 0x00; /* WakeUp? */ 
 907                                 send_wait_hmuartlgw(&dev
, &rdata
, out
, 7, HMUARTLGW_APP
, HMUARTLGW_STATE_WAIT_APP
, HMUARTLGW_STATE_ACK_APP
); 
 911                 printf("Sending device with hmid %06x to bootloader\n", hmid
); 
 914                 SET_SRC(out
, my_hmid
); 
 917                 SET_LEN_FROM_PAYLOADLEN(out
, 1); 
 921                         out
[MSGID
] = msgid
++; 
 922                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 927                         printf("Failed to send device to bootloader, please enter bootloader manually.\n"); 
 932                 printf("Waiting for device with serial %s\n", serial
); 
 934                 printf("Waiting for device with HMID %06x\n", hmid
); 
 940                         case DEVICE_TYPE_CULFW
: 
 941                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
 943                         case DEVICE_TYPE_HMCFGUSB
: 
 944                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 946                         case DEVICE_TYPE_HMUARTLGW
: 
 947                                 pfd 
= hmuartlgw_poll(dev
.hmuartlgw
, 1000); 
 954                 if ((pfd 
< 0) && errno
) { 
 955                         if (errno 
!= ETIMEDOUT
) { 
 961                 if ((rdata
.message
[LEN
] == 0x14) && /* Length */ 
 962                     (rdata
.message
[MSGID
] == 0x00) && /* Message ID */ 
 963                     (rdata
.message
[CTL
] == 0x00) && /* Control Byte */ 
 964                     (rdata
.message
[TYPE
] == 0x10) && /* Messagte type: Information */ 
 965                     (DST(rdata
.message
) == 0x000000) && /* Broadcast */ 
 966                     (rdata
.message
[PAYLOAD
] == 0x00)) { /* FUP? */ 
 967                         if (serial 
&& !strncmp((char*)&(rdata
.message
[0x0b]), serial
, 10)) { 
 968                                 hmid 
= SRC(rdata
.message
); 
 970                         } else if (!serial 
&& SRC(rdata
.message
) == hmid
) { 
 971                                 serial 
= (char*)&(rdata
.message
[0x0b]); 
 977         printf("Device with serial %s (HMID: %06x) entered firmware-update-mode\n", serial
, hmid
); 
 980                 case DEVICE_TYPE_HMCFGUSB
: 
 981                         printf("Adding HMID\n"); 
 983                         memset(out
, 0, sizeof(out
)); 
 985                         out
[1] = (hmid 
>> 16) & 0xff; 
 986                         out
[2] = (hmid 
>> 8) & 0xff; 
 987                         out
[3] = hmid 
& 0xff; 
 989                         hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 991                 case DEVICE_TYPE_HMUARTLGW
: 
 992                         printf("Adding HMID\n"); 
 994                         memset(out
, 0, sizeof(out
)); 
 995                         out
[0] = HMUARTLGW_APP_ADD_PEER
; 
 996                         out
[1] = (hmid 
>> 16) & 0xff; 
 997                         out
[2] = (hmid 
>> 8) & 0xff; 
 998                         out
[3] = hmid 
& 0xff; 
 999                         out
[4] = 0x00; /* KeyIndex */ 
1000                         out
[5] = 0x00; /* WakeUp? */ 
1001                         out
[6] = 0x00; /* WakeUp? */ 
1003                         send_wait_hmuartlgw(&dev
, &rdata
, out
, 7, HMUARTLGW_APP
, HMUARTLGW_STATE_WAIT_APP
, HMUARTLGW_STATE_ACK_APP
); 
1010                 printf("Initiating remote switch to 100k\n"); 
1012                 memset(out
, 0, sizeof(out
)); 
1014                 out
[MSGID
] = msgid
++; 
1017                 SET_SRC(out
, my_hmid
); 
1020                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
1021                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
1023                 if (!send_hm_message(&dev
, &rdata
, out
)) { 
1027                 if (!switch_speed(&dev
, &rdata
, 100)) { 
1028                         fprintf(stderr
, "Can't switch speed!\n"); 
1032                 printf("Has the device switched?\n"); 
1034                 memset(out
, 0, sizeof(out
)); 
1036                 out
[MSGID
] = msgid
++; 
1039                 SET_SRC(out
, my_hmid
); 
1042                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
1043                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
1047                         if (send_hm_message(&dev
, &rdata
, out
)) { 
1048                                 /* A0A02000221B9AD00000000 */ 
1057                         if (!switch_speed(&dev
, &rdata
, 10)) { 
1058                                 fprintf(stderr
, "Can't switch speed!\n"); 
1062         } while ((!switched
) && (switchcnt
--)); 
1065                 fprintf(stderr
, "Too many errors, giving up!\n"); 
1071         printf("Flashing %d blocks", fw
->fw_blocks
); 
1075                 printf(": %04u/%04u %c", 0, fw
->fw_blocks
, twiddlie
[0]); 
1079         for (block 
= 0; block 
< fw
->fw_blocks
; block
++) { 
1082                 len 
= fw
->fw
[block
][2] << 8; 
1083                 len 
|= fw
->fw
[block
][3]; 
1085                 pos 
= &(fw
->fw
[block
][2]); 
1087                 len 
+= 2; /* length */ 
1090                         hexdump(pos
, len
, "F> "); 
1095                         int payloadlen 
= max_payloadlen 
- 2; 
1099                                 payloadlen 
= max_payloadlen
; 
1103                         if ((len 
- (pos 
- &(fw
->fw
[block
][2]))) < payloadlen
) 
1104                                 payloadlen 
= (len 
- (pos 
- &(fw
->fw
[block
][2]))); 
1106                         if (((pos 
+ payloadlen
) - &(fw
->fw
[block
][2])) == len
) 
1109                         memset(&rdata
, 0, sizeof(rdata
)); 
1111                         memset(out
, 0, sizeof(out
)); 
1117                         SET_SRC(out
, my_hmid
); 
1120                         memcpy(&out
[PAYLOAD
], pos
, payloadlen
); 
1121                         SET_LEN_FROM_PAYLOADLEN(out
, payloadlen
); 
1123                         if (send_hm_message(&dev
, &rdata
, out
)) { 
1126                                 pos 
= &(fw
->fw
[block
][2]); 
1128                                 if (cnt 
== MAX_RETRIES
) { 
1129                                         fprintf(stderr
, "\nToo many errors, giving up!\n"); 
1132                                         printf("Flashing %d blocks: %04u/%04u %c", fw
->fw_blocks
, block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
1139                                 printf("\b\b\b\b\b\b\b\b\b\b\b%04u/%04u %c", 
1140                                         block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
1143                 } while((pos 
- &(fw
->fw
[block
][2])) < len
); 
1151         if (!switch_speed(&dev
, &rdata
, 10)) { 
1152                 fprintf(stderr
, "Can't switch speed!\n"); 
1156         printf("Waiting for device to reboot\n"); 
1157         rdata
.message_type 
= MESSAGE_TYPE_R
; 
1160         if (dev
.type 
== DEVICE_TYPE_HMUARTLGW
) 
1161                 cnt 
= 200; /* FIXME */ 
1165                         case DEVICE_TYPE_CULFW
: 
1166                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
1168                         case DEVICE_TYPE_HMCFGUSB
: 
1169                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
1171                         case DEVICE_TYPE_HMUARTLGW
: 
1172                                 pfd 
= hmuartlgw_poll(dev
.hmuartlgw
, 1000); 
1178                 if ((pfd 
< 0) && errno
) { 
1179                         if (errno 
!= ETIMEDOUT
) { 
1184                 if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
1189         if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
1190                 printf("Device rebooted\n"); 
1194                 case DEVICE_TYPE_HMCFGUSB
: 
1195                         hmcfgusb_close(dev
.hmcfgusb
); 
1198                 case DEVICE_TYPE_CULFW
: 
1199                         culfw_close(dev
.culfw
); 
1203         return EXIT_SUCCESS
;