]> cvs.zerfleddert.de Git - hmcfgusb/blobdiff - hmuartlgw.c
hmland.init: try hmland-location from Fhem-wiki, too
[hmcfgusb] / hmuartlgw.c
index ccb5dbc5eed1e78922448174d6fb9b2b207650d3..b109b39dd478b04cf2380eb8f755e3d9f4137163 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
@@ -39,7 +39,7 @@
 
 #define HMUARTLGW_INIT_TIMEOUT 10000
 
-#define HMUARTLGW_SETTLE_TIME  2
+#define HMUARTLGW_SETTLE_TIME  1
 
 static int debug = 0;
 
@@ -51,10 +51,12 @@ enum hmuartlgw_state {
        HMUARTLGW_ENTER_APPLICATION,
        HMUARTLGW_ENTER_APPLICATION_ACK,
        HMUARTLGW_APPLICATION,
+       HMUARTLGW_DUAL_APPLICATION,
 };
 
 struct recv_data {
        enum hmuartlgw_state state;
+       struct hmuartlgw_dev *dev;
 };
 
 
@@ -91,6 +93,69 @@ 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;
+                                       }
+                               }
+                               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;
 
@@ -106,7 +171,7 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
 
        switch(rdata->state) {
                case HMUARTLGW_QUERY_APPSTATE:
-                       if ((buf[0] == 0x04) && (buf[1] == 0x02)) {
+                       if ((buf[0] == HMUARTLGW_OS_ACK) && (buf[1] == 0x02)) {
                                if (!strncmp(((char*)buf)+2, "Co_CPU_BL", 9)) {
                                        rdata->state = HMUARTLGW_BOOTLOADER;
                                } else if (!strncmp(((char*)buf)+2, "Co_CPU_App", 10)) {
@@ -116,7 +181,7 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
                        break;
                case HMUARTLGW_ENTER_BOOTLOADER:
                        if ((buf_len == 2) &&
-                           (buf[0] == 0x04) &&
+                           (buf[0] == HMUARTLGW_OS_ACK) &&
                            (buf[1] == 0x01)) {
                                rdata->state = HMUARTLGW_ENTER_BOOTLOADER_ACK;
                        }
@@ -126,7 +191,7 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
                        break;
                case HMUARTLGW_ENTER_APPLICATION:
                        if ((buf_len == 2) &&
-                           (buf[0] == 0x04) &&
+                           (buf[0] == HMUARTLGW_OS_ACK) &&
                            (buf[1] == 0x01)) {
                                rdata->state = HMUARTLGW_ENTER_APPLICATION_ACK;
                        }
@@ -142,7 +207,7 @@ static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_le
         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 +256,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,29 +287,40 @@ 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) {
+               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);
+                       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);
 
                printf("Waiting for bootloader to settle...\n");
@@ -257,6 +337,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 +346,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 +432,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 +516,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