/* 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
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;
};
}
#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;
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;
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;
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);
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");
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;
}
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;
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 > ");