1 /* flasher for HomeMatic-devices supporting OTA updates 
   3  * Copyright (c) 2014 Michael Gernoth <michael@gernoth.net> 
   5  * Permission is hereby granted, free of charge, to any person obtaining a copy 
   6  * of this software and associated documentation files (the "Software"), to 
   7  * deal in the Software without restriction, including without limitation the 
   8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
   9  * sell copies of the Software, and to permit persons to whom the Software is 
  10  * furnished to do so, subject to the following conditions: 
  12  * The above copyright notice and this permission notice shall be included in 
  13  * all copies or substantial portions of the Software. 
  15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
  18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
  20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
  32 #include <sys/types.h> 
  36 #include <libusb-1.0/libusb.h> 
  60         struct hmcfgusb_dev 
*hmcfgusb
; 
  61         struct culfw_dev 
*culfw
; 
  71         enum message_type message_type
; 
  77 static int parse_hmcfgusb(uint8_t *buf
, int buf_len
, void *data
) 
  79         struct recv_data 
*rdata 
= data
; 
  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
; 
  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
; 
 102                         rdata
->speed 
= buf
[1]; 
 105                         rdata
->version 
= (buf
[11] << 8) | buf
[12]; 
 106                         my_hmid 
= (buf
[0x1b] << 16) | (buf
[0x1c] << 8) | buf
[0x1d]; 
 118 static int parse_culfw(uint8_t *buf
, int buf_len
, void *data
) 
 120         struct recv_data 
*rdata 
= data
; 
 123         memset(rdata
, 0, sizeof(struct recv_data
)); 
 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]); 
 141                         if (hmid 
&& (SRC(rdata
->message
) != hmid
)) 
 144                         rdata
->message_type 
= MESSAGE_TYPE_E
; 
 152                                 s 
= ((char*)buf
) + 2; 
 155                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 160                                 rdata
->version 
= v 
<< 8; 
 165                                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 174                         fprintf(stderr
, "Unknown response from CUL: %s", buf
); 
 182 int send_hm_message(struct ota_dev 
*dev
, struct recv_data 
*rdata
, uint8_t *msg
) 
 184         static uint32_t id 
= 1; 
 190                 case DEVICE_TYPE_HMCFGUSB
: 
 191                         if (gettimeofday(&tv
, NULL
) == -1) { 
 192                                 perror("gettimeofay"); 
 196                         memset(out
, 0, sizeof(out
)); 
 199                         out
[1] = (id 
>> 24) & 0xff; 
 200                         out
[2] = (id 
>> 16) & 0xff; 
 201                         out
[3] = (id 
>> 8) & 0xff; 
 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; 
 209                         memcpy(&out
[0x0f], msg
, msg
[0] + 1); 
 211                         memset(rdata
, 0, sizeof(struct recv_data
)); 
 212                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 215                                 if (rdata
->message_type 
== MESSAGE_TYPE_R
) { 
 216                                         if (((rdata
->status 
& 0xff) == 0x01) || 
 217                                             ((rdata
->status 
& 0xff) == 0x02)) { 
 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"); 
 225                                                         fprintf(stderr
, "\nInvalid status: %04x\n", rdata
->status
); 
 231                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 232                                 if ((pfd 
< 0) && errno
) { 
 233                                         if (errno 
!= ETIMEDOUT
) { 
 234                                                 perror("\n\nhmcfgusb_poll"); 
 240                 case DEVICE_TYPE_CULFW
: 
 245                                 memset(buf
, 0, sizeof(buf
)); 
 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); 
 252                                 buf
[2 + (i 
* 2) ] = '\r'; 
 253                                 buf
[2 + (i 
* 2) + 1] = '\n'; 
 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"); 
 261                                 if (msg
[CTL
] & 0x20) { 
 266                                                 pfd 
= culfw_poll(dev
->culfw
, 200); 
 267                                                 if ((pfd 
< 0) && errno
) { 
 268                                                         if (errno 
!= ETIMEDOUT
) { 
 269                                                                 perror("\n\nculfw_poll"); 
 273                                                 if (rdata
->message_type 
== MESSAGE_TYPE_E
) { 
 279                                                 fprintf(stderr
, "\nMissing ACK!\n"); 
 291 static int switch_speed(struct ota_dev 
*dev
, struct recv_data 
*rdata
, uint8_t speed
) 
 296         printf("Entering %uk-mode\n", speed
); 
 299                 case DEVICE_TYPE_HMCFGUSB
: 
 300                         memset(out
, 0, sizeof(out
)); 
 304                         hmcfgusb_send(dev
->hmcfgusb
, out
, sizeof(out
), 1); 
 308                                 pfd 
= hmcfgusb_poll(dev
->hmcfgusb
, 1000); 
 309                                 if ((pfd 
< 0) && errno
) { 
 310                                         if (errno 
!= ETIMEDOUT
) { 
 311                                                 perror("\n\nhmcfgusb_poll"); 
 315                                 if (rdata
->speed 
== speed
) 
 319                 case DEVICE_TYPE_CULFW
: 
 321                                 return culfw_send(dev
->culfw
, "AR\r\n", 4); 
 323                                 return culfw_send(dev
->culfw
, "Ar\r\n", 4); 
 331 void flash_ota_syntax(char *prog
) 
 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"); 
 343 int main(int argc
, char **argv
) 
 345         const char twiddlie
[] = { '-', '\\', '|', '/' }; 
 346         const uint8_t cc1101_regs
[] = { 0x10, 0x5B, 0x11, 0xF8, 0x15, 0x47 }; 
 347         char *fw_file 
= NULL
; 
 349         char *culfw_dev 
= NULL
; 
 350         unsigned int bps 
= DEFAULT_CUL_BPS
; 
 352         struct recv_data rdata
; 
 367         printf("HomeMatic OTA flasher version " VERSION 
"\n\n"); 
 369         while((opt 
= getopt(argc
, argv
, "b:c:f:hs:")) != -1) { 
 387                                 flash_ota_syntax(argv
[0]); 
 394         if (!fw_file 
|| !serial
) { 
 395                 flash_ota_syntax(argv
[0]); 
 399         fw 
= firmware_read_firmware(fw_file
, debug
); 
 403         memset(&rdata
, 0, sizeof(rdata
)); 
 404         memset(&dev
, 0, sizeof(struct ota_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
); 
 410                         fprintf(stderr
, "Can't initialize CUL at %s with rate %u\n", culfw_dev
, bps
); 
 413                 dev
.type 
= DEVICE_TYPE_CULFW
; 
 415                 printf("Requesting firmware-version\n"); 
 416                 culfw_send(dev
.culfw
, "\r\n", 2); 
 417                 culfw_flush(dev
.culfw
); 
 420                         culfw_send(dev
.culfw
, "V\r\n", 3); 
 423                         pfd 
= culfw_poll(dev
.culfw
, 1000); 
 424                         if ((pfd 
< 0) && errno
) { 
 425                                 if (errno 
!= ETIMEDOUT
) { 
 426                                         perror("\n\nhmcfgusb_poll"); 
 434                 printf("culfw-device firmware version: %u.%02u\n",  
 435                         (rdata
.version 
>> 8) & 0xff, 
 436                         rdata
.version 
& 0xff); 
 438                 if (rdata
.version 
< 0x013a) { 
 439                         fprintf(stderr
, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n"); 
 443                 hmcfgusb_set_debug(debug
); 
 445                 dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
); 
 447                         fprintf(stderr
, "Can't initialize HM-CFG-USB\n"); 
 450                 dev
.type 
= DEVICE_TYPE_HMCFGUSB
; 
 452                 printf("\nRebooting HM-CFG-USB to avoid running out of credits\n\n"); 
 454                 if (!dev
.hmcfgusb
->bootloader
) { 
 455                         printf("HM-CFG-USB not in bootloader mode, entering bootloader.\n"); 
 456                         printf("Waiting for device to reappear...\n"); 
 460                                         if (!dev
.hmcfgusb
->bootloader
) 
 461                                                 hmcfgusb_enter_bootloader(dev
.hmcfgusb
); 
 462                                         hmcfgusb_close(dev
.hmcfgusb
); 
 465                         } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
)) == NULL
) || (!dev
.hmcfgusb
->bootloader
)); 
 468                 if (dev
.hmcfgusb
->bootloader
) { 
 469                         printf("HM-CFG-USB in bootloader mode, rebooting\n"); 
 473                                         if (dev
.hmcfgusb
->bootloader
) 
 474                                                 hmcfgusb_leave_bootloader(dev
.hmcfgusb
); 
 475                                         hmcfgusb_close(dev
.hmcfgusb
); 
 478                         } while (((dev
.hmcfgusb 
= hmcfgusb_init(parse_hmcfgusb
, &rdata
)) == NULL
) || (dev
.hmcfgusb
->bootloader
)); 
 481                 printf("\n\nHM-CFG-USB opened\n\n"); 
 483                 memset(out
, 0, sizeof(out
)); 
 485                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 489                         pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 490                         if ((pfd 
< 0) && errno
) { 
 491                                 if (errno 
!= ETIMEDOUT
) { 
 492                                         perror("\n\nhmcfgusb_poll"); 
 500                 if (rdata
.version 
< 0x3c7) { 
 501                         fprintf(stderr
, "HM-CFG-USB firmware too low: %u < 967\n", rdata
.version
); 
 505                 printf("HM-CFG-USB firmware version: %u\n", rdata
.version
); 
 508         if (!switch_speed(&dev
, &rdata
, 10)) { 
 509                 fprintf(stderr
, "Can't switch speed!\n"); 
 513         printf("Waiting for device with serial %s\n", serial
); 
 518                         case DEVICE_TYPE_CULFW
: 
 519                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
 521                         case DEVICE_TYPE_HMCFGUSB
: 
 523                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 527                 if ((pfd 
< 0) && errno
) { 
 528                         if (errno 
!= ETIMEDOUT
) { 
 534                 if ((rdata
.message
[LEN
] == 0x14) && /* Length */ 
 535                     (rdata
.message
[MSGID
] == 0x00) && /* Message ID */ 
 536                     (rdata
.message
[CTL
] == 0x00) && /* Control Byte */ 
 537                     (rdata
.message
[TYPE
] == 0x10) && /* Messagte type: Information */ 
 538                     (DST(rdata
.message
) == 0x000000) && /* Broadcast */ 
 539                     (rdata
.message
[PAYLOAD
] == 0x00)) { /* FUP? */ 
 540                         if (!strncmp((char*)&(rdata
.message
[0x0b]), serial
, 10)) { 
 541                                 hmid 
= SRC(rdata
.message
); 
 547         printf("Device with serial %s (hmid: %06x) entered firmware-update-mode\n", serial
, hmid
); 
 549         if (dev
.type 
== DEVICE_TYPE_HMCFGUSB
) { 
 550                 printf("Adding HMID\n"); 
 552                 memset(out
, 0, sizeof(out
)); 
 554                 out
[1] = (hmid 
>> 16) & 0xff; 
 555                 out
[2] = (hmid 
>> 8) & 0xff; 
 556                 out
[3] = hmid 
& 0xff; 
 558                 hmcfgusb_send(dev
.hmcfgusb
, out
, sizeof(out
), 1); 
 563                 printf("Initiating remote switch to 100k\n"); 
 565                 memset(out
, 0, sizeof(out
)); 
 567                 out
[MSGID
] = msgid
++; 
 570                 SET_SRC(out
, my_hmid
); 
 573                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
 574                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
 576                 if (!send_hm_message(&dev
, &rdata
, out
)) { 
 580                 if (!switch_speed(&dev
, &rdata
, 100)) { 
 581                         fprintf(stderr
, "Can't switch speed!\n"); 
 585                 printf("Has the device switched?\n"); 
 587                 memset(out
, 0, sizeof(out
)); 
 589                 out
[MSGID
] = msgid
++; 
 592                 SET_SRC(out
, my_hmid
); 
 595                 memcpy(&out
[PAYLOAD
], cc1101_regs
, sizeof(cc1101_regs
)); 
 596                 SET_LEN_FROM_PAYLOADLEN(out
, sizeof(cc1101_regs
)); 
 600                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 601                                 /* A0A02000221B9AD00000000 */ 
 610                         if (!switch_speed(&dev
, &rdata
, 10)) { 
 611                                 fprintf(stderr
, "Can't switch speed!\n"); 
 615         } while ((!switched
) && (switchcnt
--)); 
 618                 fprintf(stderr
, "Too many errors, giving up!\n"); 
 624         printf("Flashing %d blocks", fw
->fw_blocks
); 
 628                 printf(": %04u/%04u %c", 0, fw
->fw_blocks
, twiddlie
[0]); 
 632         for (block 
= 0; block 
< fw
->fw_blocks
; block
++) { 
 635                 len 
= fw
->fw
[block
][2] << 8; 
 636                 len 
|= fw
->fw
[block
][3]; 
 638                 pos 
= &(fw
->fw
[block
][2]); 
 640                 len 
+= 2; /* length */ 
 643                         hexdump(pos
, len
, "F> "); 
 656                         if ((len 
- (pos 
- &(fw
->fw
[block
][2]))) < payloadlen
) 
 657                                 payloadlen 
= (len 
- (pos 
- &(fw
->fw
[block
][2]))); 
 659                         if (((pos 
+ payloadlen
) - &(fw
->fw
[block
][2])) == len
) 
 662                         memset(&rdata
, 0, sizeof(rdata
)); 
 664                         memset(out
, 0, sizeof(out
)); 
 670                         SET_SRC(out
, my_hmid
); 
 673                         memcpy(&out
[PAYLOAD
], pos
, payloadlen
); 
 674                         SET_LEN_FROM_PAYLOADLEN(out
, payloadlen
); 
 676                         if (send_hm_message(&dev
, &rdata
, out
)) { 
 679                                 pos 
= &(fw
->fw
[block
][2]); 
 681                                 if (cnt 
== MAX_RETRIES
) { 
 682                                         fprintf(stderr
, "\nToo many errors, giving up!\n"); 
 685                                         printf("Flashing %d blocks: %04u/%04u %c", fw
->fw_blocks
, block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
 692                                 printf("\b\b\b\b\b\b\b\b\b\b\b%04u/%04u %c", 
 693                                         block 
+ 1, fw
->fw_blocks
, twiddlie
[msgnum 
% sizeof(twiddlie
)]); 
 696                 } while((pos 
- &(fw
->fw
[block
][2])) < len
); 
 704         if (!switch_speed(&dev
, &rdata
, 10)) { 
 705                 fprintf(stderr
, "Can't switch speed!\n"); 
 709         printf("Waiting for device to reboot\n"); 
 715                         case DEVICE_TYPE_CULFW
: 
 716                                 pfd 
= culfw_poll(dev
.culfw
, 1000); 
 718                         case DEVICE_TYPE_HMCFGUSB
: 
 720                                 pfd 
= hmcfgusb_poll(dev
.hmcfgusb
, 1000); 
 723                 if ((pfd 
< 0) && errno
) { 
 724                         if (errno 
!= ETIMEDOUT
) { 
 729                 if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
 734         if (rdata
.message_type 
== MESSAGE_TYPE_E
) { 
 735                 printf("Device rebooted\n"); 
 739                 case DEVICE_TYPE_HMCFGUSB
: 
 740                         hmcfgusb_close(dev
.hmcfgusb
); 
 743                 case DEVICE_TYPE_CULFW
: 
 744                         culfw_close(dev
.culfw
);