]> git.zerfleddert.de Git - hmcfgusb/blobdiff - hmuartlgw.c
Cleanup: Use correct format string
[hmcfgusb] / hmuartlgw.c
index 2e6757a4720ed68ee34ab9cc4de2f06590b83033..9335c44e779d162bf8cd1abc000edfa776ec02c7 100644 (file)
@@ -1,6 +1,6 @@
 /* HM-MOD-UART/HM-LGW-O-TW-W-EU driver
  *
- * Copyright (c) 2016 Michael Gernoth <michael@gernoth.net>
+ * Copyright (c) 2016-17 Michael Gernoth <michael@gernoth.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -48,13 +48,17 @@ enum hmuartlgw_state {
        HMUARTLGW_ENTER_BOOTLOADER,
        HMUARTLGW_ENTER_BOOTLOADER_ACK,
        HMUARTLGW_BOOTLOADER,
+       HMUARTLGW_HMIP_BOOTLOADER,
        HMUARTLGW_ENTER_APPLICATION,
        HMUARTLGW_ENTER_APPLICATION_ACK,
        HMUARTLGW_APPLICATION,
+       HMUARTLGW_DUAL_APPLICATION,
+       HMUARTLGW_HMIP_APPLICATION,
 };
 
 struct recv_data {
        enum hmuartlgw_state state;
+       struct hmuartlgw_dev *dev;
 };
 
 
@@ -91,6 +95,75 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
        }
 #endif
 
+       /* Minimally handle DualCopro-Firmware */
+       if (dst == HMUARTLGW_DUAL) {
+               if ((buf_len == 14) && (buf[0] == 0x00) && !strncmp(((char*)buf)+1, "DualCoPro_App", 13)) {
+                       rdata->state = HMUARTLGW_DUAL_APPLICATION;
+                       return 1;
+               }
+
+               switch (rdata->state) {
+                       case HMUARTLGW_QUERY_APPSTATE:
+                               if ((buf[0] == 0x05) && (buf[1] == 0x01)) {
+                                       if (!strncmp(((char*)buf)+2, "DualCoPro_App", 13)) {
+                                               rdata->state = HMUARTLGW_DUAL_APPLICATION;
+                                               return 1;
+                                       } else if (!strncmp(((char*)buf)+2, "HMIP_TRX_App", 12)) {
+                                               rdata->state = HMUARTLGW_HMIP_APPLICATION;
+                                               return 1;
+                                       } else if (!strncmp(((char*)buf)+2, "HMIP_TRX_Bl", 11)) {
+                                               rdata->state = HMUARTLGW_HMIP_BOOTLOADER;
+                                               return 1;
+                                       }
+                               }
+                               break;
+                       case HMUARTLGW_ENTER_BOOTLOADER:
+                               if ((buf_len == 2) &&
+                                   (buf[0] == 0x05) &&
+                                   (buf[1] == 0x01)) {
+                                       rdata->state = HMUARTLGW_ENTER_BOOTLOADER_ACK;
+                                       return 1;
+                               }
+                               break;
+                       default:
+                               fprintf(stderr, "Don't know how to handle this state (%d) for unsupported firmware, giving up!\n", rdata->state);
+                               exit(1);
+                               break;
+               }
+
+               return 0;
+       }
+
+       /* Re-send commands for DualCopro Firmware */
+       if (dst == HMUARTLGW_DUAL_ERR) {
+               uint8_t buf[128] = { 0 };
+
+               switch(rdata->state) {
+                       case HMUARTLGW_QUERY_APPSTATE:
+                               if (debug) {
+                                       printf("Re-sending appstate-query for new firmare\n");
+                               }
+
+                               buf[0] = HMUARTLGW_DUAL_GET_APP;
+                               hmuartlgw_send(rdata->dev, buf, 1, HMUARTLGW_DUAL);
+                               break;
+                       case HMUARTLGW_ENTER_BOOTLOADER:
+                               if (debug) {
+                                       printf("Re-sending switch to bootloader for new firmare\n");
+                               }
+
+                               buf[0] = HMUARTLGW_DUAL_CHANGE_APP;
+                               hmuartlgw_send(rdata->dev, buf, 1, HMUARTLGW_DUAL);
+                               break;
+                       default:
+                               fprintf(stderr, "Don't know how to handle this error-state (%d) for unsupported firmware, giving up!\n", rdata->state);
+                               exit(1);
+                               break;
+               }
+
+               return 0;
+       }
+
        if (dst != HMUARTLGW_OS)
                return 0;
 
@@ -139,10 +212,16 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
                        break;
        }
 
+       /* Try to query current app in case we might be in the DUAL/HMIP-Bootloader */
+       if ((buf[0] == HMUARTLGW_OS_ACK) && (buf[1] == 0x03)) {
+               buf[0] = HMUARTLGW_DUAL_GET_APP;
+               hmuartlgw_send(rdata->dev, buf, 1, HMUARTLGW_DUAL);
+       }
+
         return 1;
 }
 
-struct hmuartlgw_dev *hmuart_init(char *device, hmuartlgw_cb_fn cb, void *data)
+struct hmuartlgw_dev *hmuart_init(char *device, hmuartlgw_cb_fn cb, void *data, int app)
 {
        struct hmuartlgw_dev *dev = NULL;
        struct termios oldtio, tio;
@@ -191,7 +270,11 @@ struct hmuartlgw_dev *hmuart_init(char *device, hmuartlgw_cb_fn cb, void *data)
 
        hmuartlgw_flush(dev);
 
-       hmuartlgw_enter_app(dev);
+       if (app) {
+               hmuartlgw_enter_app(dev);
+       } else {
+               hmuartlgw_enter_bootloader(dev);
+       }
 
        dev->cb = cb;
        dev->cb_data = data;
@@ -218,30 +301,43 @@ void hmuartlgw_enter_bootloader(struct hmuartlgw_dev *dev)
        void *cb_data_old = dev->cb_data;
        struct recv_data rdata = { 0 };
        uint8_t buf[128] = { 0 };
+       int ret;
 
        if (debug) {
                fprintf(stderr, "Entering bootloader\n");
        }
 
-       buf[0] = HMUARTLGW_OS_CHANGE_APP;
-
        dev->cb = hmuartlgw_init_parse;
        dev->cb_data = &rdata;
 
+       rdata.dev = dev;
        rdata.state = HMUARTLGW_QUERY_APPSTATE;
        buf[0] = HMUARTLGW_OS_GET_APP;
        hmuartlgw_send(dev, buf, 1, HMUARTLGW_OS);
        do {
-               hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+               errno = 0;
+               ret = hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+               if (ret == -1 && errno == ETIMEDOUT) {
+                       fprintf(stderr, "Communication with the module timed out, is the serial port configured correctly?\n");
+                       exit(1);
+               }
        } while (rdata.state == HMUARTLGW_QUERY_APPSTATE);
 
-       if (rdata.state != HMUARTLGW_BOOTLOADER) {
+       if ((rdata.state != HMUARTLGW_BOOTLOADER) &&
+           (rdata.state != HMUARTLGW_HMIP_BOOTLOADER)) {
+               rdata.dev = dev;
                rdata.state = HMUARTLGW_ENTER_BOOTLOADER;
                buf[0] = HMUARTLGW_OS_CHANGE_APP;
                hmuartlgw_send(dev, buf, 1, HMUARTLGW_OS);
                do {
-                       hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
-               } while (rdata.state != HMUARTLGW_BOOTLOADER);
+                       errno = 0;
+                       ret = hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+                       if (ret == -1 && errno == ETIMEDOUT) {
+                               fprintf(stderr, "Communication with the module timed out, is the serial port configured correctly?\n");
+                               exit(1);
+                       }
+               } while ((rdata.state != HMUARTLGW_BOOTLOADER) &&
+                        (rdata.state != HMUARTLGW_HMIP_BOOTLOADER));
 
                printf("Waiting for bootloader to settle...\n");
                sleep(HMUARTLGW_SETTLE_TIME);
@@ -257,6 +353,7 @@ void hmuartlgw_enter_app(struct hmuartlgw_dev *dev)
        void *cb_data_old = dev->cb_data;
        struct recv_data rdata = { 0 };
        uint8_t buf[128] = { 0 };
+       int ret;
 
        if (debug) {
                fprintf(stderr, "Entering application\n");
@@ -265,25 +362,47 @@ void hmuartlgw_enter_app(struct hmuartlgw_dev *dev)
        dev->cb = hmuartlgw_init_parse;
        dev->cb_data = &rdata;
 
+       rdata.dev = dev;
        rdata.state = HMUARTLGW_QUERY_APPSTATE;
        buf[0] = HMUARTLGW_OS_GET_APP;
        hmuartlgw_send(dev, buf, 1, HMUARTLGW_OS);
        do {
-               hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+               errno = 0;
+               ret = hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+               if (ret == -1 && errno == ETIMEDOUT) {
+                       fprintf(stderr, "Communication with the module timed out, is the serial port configured correctly?\n");
+                       exit(1);
+               }
        } while (rdata.state == HMUARTLGW_QUERY_APPSTATE);
 
-       if (rdata.state != HMUARTLGW_APPLICATION) {
+       if ((rdata.state != HMUARTLGW_APPLICATION) &&
+           (rdata.state != HMUARTLGW_DUAL_APPLICATION)) {
+               rdata.dev = dev;
                rdata.state = HMUARTLGW_ENTER_APPLICATION;
                buf[0] = HMUARTLGW_OS_CHANGE_APP;
                hmuartlgw_send(dev, buf, 1, HMUARTLGW_OS);
                do {
-                       hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
-               } while (rdata.state != HMUARTLGW_APPLICATION);
+                       errno = 0;
+                       ret = hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
+                       if (ret == -1 && errno == ETIMEDOUT) {
+                               fprintf(stderr, "Communication with the module timed out, is the serial port configured correctly?\n");
+                               exit(1);
+                       }
+               } while ((rdata.state != HMUARTLGW_APPLICATION) &&
+                        (rdata.state != HMUARTLGW_DUAL_APPLICATION));
 
-               printf("Waiting for application to settle...\n");
-               sleep(HMUARTLGW_SETTLE_TIME);
+               if (rdata.state == HMUARTLGW_APPLICATION) {
+                       printf("Waiting for application to settle...\n");
+                       sleep(HMUARTLGW_SETTLE_TIME);
+               }
        }
 
+       if (rdata.state == HMUARTLGW_DUAL_APPLICATION) {
+               fprintf(stderr, "Unsupported firmware, please install HM-only firmware!\n");
+               exit(1);
+       }
+
+
        dev->cb = cb_old;
        dev->cb_data = cb_data_old;
 }
@@ -329,7 +448,7 @@ int hmuartlgw_send_raw(struct hmuartlgw_dev *dev, uint8_t *frame, int framelen)
 int hmuartlgw_send(struct hmuartlgw_dev *dev, uint8_t *cmd, int cmdlen, enum hmuartlgw_dst dst)
 {
        static uint8_t cnt = 0;
-       uint8_t frame[1024] = { 0 };
+       uint8_t frame[4096] = { 0 };
        uint16_t crc;
 
        frame[0] = 0xfd;
@@ -413,10 +532,8 @@ int hmuartlgw_poll(struct hmuartlgw_dev *dev, int timeout)
                return -1;
        }
 
-       crc = crc16(dev->buf, dev->pos - 2);
-       if ((((crc >> 8) & 0xff) == dev->buf[dev->pos - 2]) &&
-                       ((crc & 0xff) == dev->buf[dev->pos - 1])) {
-
+       crc = crc16(dev->buf, dev->pos);
+       if (crc == 0x0000) {
                if (debug)
                        hexdump(dev->buf, dev->pos, "UARTLGW > ");
 
Impressum, Datenschutz