X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/blobdiff_plain/b1d2ccc2e0f45169d6dda672c80a5aaf4770e7a3..915b783358b0f140fe44d0aeb4295a071f4e0054:/hmuartlgw.c diff --git a/hmuartlgw.c b/hmuartlgw.c index 4c274cf..9335c44 100644 --- a/hmuartlgw.c +++ b/hmuartlgw.c @@ -1,6 +1,6 @@ /* HM-MOD-UART/HM-LGW-O-TW-W-EU driver * - * Copyright (c) 2016 Michael Gernoth + * Copyright (c) 2016-17 Michael Gernoth * * 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;