X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/blobdiff_plain/3e34d2cea8844557376669f4782f07f5085253c9..4fd904dfbdea0d4bc3dd901a5feb9338ffa4e25d:/hmuartlgw.c?ds=sidebyside diff --git a/hmuartlgw.c b/hmuartlgw.c index ccb5dbc..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 @@ -39,7 +39,7 @@ #define HMUARTLGW_INIT_TIMEOUT 10000 -#define HMUARTLGW_SETTLE_TIME 2 +#define HMUARTLGW_SETTLE_TIME 1 static int debug = 0; @@ -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; @@ -106,7 +179,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 +189,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 +199,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; } @@ -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 > ");