From: Michael Gernoth <michael@gernoth.net>
Date: Wed, 8 Feb 2017 22:01:53 +0000 (+0100)
Subject: hmuartlgw: Add minimal support for DualCoPro-firmware
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/commitdiff_plain/70faa2739b0dbfdf06ece20ba5171b895f0000be?ds=inline

hmuartlgw: Add minimal support for DualCoPro-firmware

This allows flashing back from DualCoPro- to HM-only-firmware.
---

diff --git a/hmuartlgw.c b/hmuartlgw.c
index 2fa755c..52aa2a4 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 <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
@@ -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;
 
@@ -227,11 +292,10 @@ void hmuartlgw_enter_bootloader(struct hmuartlgw_dev *dev)
 		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);
@@ -240,6 +304,7 @@ void hmuartlgw_enter_bootloader(struct hmuartlgw_dev *dev)
 	} 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);
@@ -269,6 +334,7 @@ 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);
@@ -276,18 +342,29 @@ void hmuartlgw_enter_app(struct hmuartlgw_dev *dev)
 		hmuartlgw_poll(dev, HMUARTLGW_INIT_TIMEOUT);
 	} 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);
+		} 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;
 }
diff --git a/hmuartlgw.h b/hmuartlgw.h
index 9b32428..388d01e 100644
--- a/hmuartlgw.h
+++ b/hmuartlgw.h
@@ -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
@@ -47,11 +47,16 @@
 #define HMUARTLGW_APP_SET_OLD_KEY	0x0F	/* key index */
 #define HMUARTLGW_APP_DEFAULT_HMID	0x10
 
+#define HMUARTLGW_DUAL_GET_APP		0x01
+#define HMUARTLGW_DUAL_CHANGE_APP	0x02
+
 #define HMUARTLGW_ACK_EINPROGRESS	0x08
 
 enum hmuartlgw_dst {
 	HMUARTLGW_OS = 0,
 	HMUARTLGW_APP = 1,
+	HMUARTLGW_DUAL = 0xfe,
+	HMUARTLGW_DUAL_ERR = 0xff,
 };
 
 typedef int (*hmuartlgw_cb_fn)(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data);
diff --git a/version.h b/version.h
index dc788d8..cd8d17a 100644
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define VERSION	"0.103"
+#define VERSION	"0.103-git"