]> git.zerfleddert.de Git - hmcfgusb/commitdiff
hmuartlgw: add initial support for HM-MOD-UART
authorMichael Gernoth <michael@gernoth.net>
Fri, 3 Jun 2016 18:05:34 +0000 (20:05 +0200)
committerMichael Gernoth <michael@gernoth.net>
Fri, 3 Jun 2016 18:05:34 +0000 (20:05 +0200)
The RPi module is now supported in hmsniff and flash-ota.

.gitignore
Makefile
flash-ota.c
hm.h
hmsniff.c
hmuartlgw.c [new file with mode: 0644]
hmuartlgw.h [new file with mode: 0644]
reset-hmmoduart.sh [new file with mode: 0755]

index df1fea60fdc8e9c80e0b4c4dc62e6a0a1a7c73cd..e1e2a29e0e40c9e95f97a87e5e4998d2b5b93727 100644 (file)
@@ -20,6 +20,8 @@ hmland.o
 hmsniff
 hmsniff.d
 hmsniff.o
 hmsniff
 hmsniff.d
 hmsniff.o
+hmuartlgw.d
+hmuartlgw.o
 util.d
 util.o
 *.enc
 util.d
 util.o
 *.enc
index 0cf13bd31b91a9bec1d7eec15bc8e366f46464df..1a29116d81e0e179fe88b3031592275c08e34e0f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,9 +7,9 @@ LDLIBS=-lusb-1.0 -lrt
 CC=gcc
 
 HMLAN_OBJS=hmcfgusb.o hmland.o util.o
 CC=gcc
 
 HMLAN_OBJS=hmcfgusb.o hmland.o util.o
-HMSNIFF_OBJS=hmcfgusb.o hmsniff.o
+HMSNIFF_OBJS=hmcfgusb.o hmuartlgw.o hmsniff.o
 FLASH_HMCFGUSB_OBJS=hmcfgusb.o firmware.o util.o flash-hmcfgusb.o
 FLASH_HMCFGUSB_OBJS=hmcfgusb.o firmware.o util.o flash-hmcfgusb.o
-FLASH_OTA_OBJS=hmcfgusb.o culfw.o firmware.o util.o flash-ota.o hm.o aes.o
+FLASH_OTA_OBJS=hmcfgusb.o culfw.o hmuartlgw.o firmware.o util.o flash-ota.o hm.o aes.o
 
 OBJS=$(HMLAN_OBJS) $(HMSNIFF_OBJS) $(FLASH_HMCFGUSB_OBJS) $(FLASH_OTA_OBJS)
 
 
 OBJS=$(HMLAN_OBJS) $(HMSNIFF_OBJS) $(FLASH_HMCFGUSB_OBJS) $(FLASH_OTA_OBJS)
 
index 7291e173bc6370dada2af02961947f1051ef8958..2625209af7c9bc9897b5d63ac8dc80375927cccc 100644 (file)
@@ -41,6 +41,7 @@
 #include "version.h"
 #include "hmcfgusb.h"
 #include "culfw.h"
 #include "version.h"
 #include "hmcfgusb.h"
 #include "culfw.h"
+#include "hmuartlgw.h"
 #include "util.h"
 
 #define MAX_RETRIES            5
 #include "util.h"
 
 #define MAX_RETRIES            5
@@ -57,22 +58,20 @@ int32_t kNo = -1;
 /* Maximum payloadlen supported by IO */
 uint32_t max_payloadlen = NORMAL_MAX_PAYLOAD;
 
 /* Maximum payloadlen supported by IO */
 uint32_t max_payloadlen = NORMAL_MAX_PAYLOAD;
 
-enum device_type {
-       DEVICE_TYPE_HMCFGUSB,
-       DEVICE_TYPE_CULFW,
-};
-
-struct ota_dev {
-       int type;
-       struct hmcfgusb_dev *hmcfgusb;
-       struct culfw_dev *culfw;
-};
-
 enum message_type {
        MESSAGE_TYPE_E = 1,
        MESSAGE_TYPE_R = 2,
 };
 
 enum message_type {
        MESSAGE_TYPE_E = 1,
        MESSAGE_TYPE_R = 2,
 };
 
+enum hmuartlgw_state {
+       HMUARTLGW_STATE_GET_HMID,
+       HMUARTLGW_STATE_GET_FIRMWARE,
+       HMUARTLGW_STATE_GET_CREDITS,
+       HMUARTLGW_STATE_DONE,
+       HMUARTLGW_STATE_WAIT_APP,
+       HMUARTLGW_STATE_ACK_APP,
+};
+
 struct recv_data {
        uint8_t message[64];
        enum message_type message_type;
 struct recv_data {
        uint8_t message[64];
        enum message_type message_type;
@@ -80,6 +79,8 @@ struct recv_data {
        int speed;
        uint16_t version;
        uint8_t credits;
        int speed;
        uint16_t version;
        uint8_t credits;
+       enum hmuartlgw_state uartlgw_state;
+       uint8_t uartlgw_version[3];
 };
 
 static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
 };
 
 static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
@@ -205,7 +206,65 @@ static int parse_culfw(uint8_t *buf, int buf_len, void *data)
        return 1;
 }
 
        return 1;
 }
 
-int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
+static int parse_hmuartlgw(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data)
+{
+       struct recv_data *rdata = data;
+
+       if (dst == HMUARTLGW_OS) {
+               switch (rdata->uartlgw_state) {
+                       case HMUARTLGW_STATE_GET_FIRMWARE:
+                               if (buf[0] == HMUARTLGW_OS_ACK) {
+                                       rdata->uartlgw_version[0] = buf[5];
+                                       rdata->uartlgw_version[1] = buf[6];
+                                       rdata->uartlgw_version[2] = buf[7];
+                                       rdata->uartlgw_state = HMUARTLGW_STATE_DONE;
+                               }
+                               break;
+                       case HMUARTLGW_STATE_GET_CREDITS:
+                               if (buf[0] == HMUARTLGW_OS_ACK) {
+                                       rdata->credits = buf[2] / 2;
+                                       rdata->uartlgw_state = HMUARTLGW_STATE_DONE;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+               return 0;
+       }
+
+       switch(buf[0]) {
+               case HMUARTLGW_APP_ACK:
+                       if (rdata->uartlgw_state == HMUARTLGW_STATE_GET_HMID) {
+                               my_hmid = (buf[4] << 16) | (buf[5] << 8) | buf[6];
+                       }
+
+                       rdata->status = buf[1];
+                       rdata->message_type = MESSAGE_TYPE_R;
+                       rdata->uartlgw_state = HMUARTLGW_STATE_ACK_APP;
+#if 0
+                       hexdump(buf, buf_len, "ACK Status: ");
+#endif
+
+                       break;
+               case HMUARTLGW_APP_RECV:
+                       if ((!hmid) ||
+                           ((buf[7] == ((hmid >> 16) & 0xff)) &&
+                           (buf[8] == ((hmid >> 8) & 0xff)) &&
+                           (buf[9] == (hmid & 0xff)))) {
+                               memset(rdata->message, 0, sizeof(rdata->message));
+                               memcpy(rdata->message + 1, buf + 4, buf_len - 4);
+                               rdata->message[LEN] = buf_len - 4;
+                               rdata->message_type = MESSAGE_TYPE_E;
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       return 1;
+}
+
+int send_hm_message(struct hm_dev *dev, struct recv_data *rdata, uint8_t *msg)
 {
        static uint32_t id = 1;
        struct timeval tv;
 {
        static uint32_t id = 1;
        struct timeval tv;
@@ -351,13 +410,52 @@ int send_hm_message(struct ota_dev *dev, struct recv_data *rdata, uint8_t *msg)
                                }
                        }
                        break;
                                }
                        }
                        break;
+               case DEVICE_TYPE_HMUARTLGW:
+                       memset(out, 0, sizeof(out));
+
+                       out[0] = HMUARTLGW_APP_SEND;
+                       out[1] = 0x00;
+                       out[2] = 0x00;
+                       out[3] = (msg[CTL] & 0x10) ? 0x01 : 0x00; /* Burst?! */
+                       memcpy(&out[4], &msg[1], msg[0]);
+
+                       memset(rdata, 0, sizeof(struct recv_data));
+                       hmuartlgw_send(dev->hmuartlgw, out, msg[0] + 4, HMUARTLGW_APP);
+
+                       while (1) {
+                               if (rdata->message_type == MESSAGE_TYPE_R) {
+                                       if ((rdata->status == 0x02) ||
+                                           (rdata->status == 0x03) ||
+                                           (rdata->status == 0x0c)) {
+                                               break;
+                                       } else {
+                                               if (rdata->status == 0x0d) {
+                                                       fprintf(stderr, "\nAES handshake failed!\n");
+                                               } else if (rdata->status == 0x04 || rdata->status == 0x06) {
+                                                       fprintf(stderr, "\nMissing ACK!\n");
+                                               } else {
+                                                       fprintf(stderr, "\nInvalid status: %04x\n", rdata->status);
+                                               }
+                                               return 0;
+                                       }
+                               }
+                               errno = 0;
+                               pfd = hmuartlgw_poll(dev->hmuartlgw, 1000);
+                               if ((pfd < 0) && errno) {
+                                       if (errno != ETIMEDOUT) {
+                                               perror("\n\nhmcfgusb_poll");
+                                               exit(EXIT_FAILURE);
+                                       }
+                               }
+                       }
+                       break;
        }
 
        id++;
        return 1;
 }
 
        }
 
        id++;
        return 1;
 }
 
-static int switch_speed(struct ota_dev *dev, struct recv_data *rdata, uint8_t speed)
+static int switch_speed(struct hm_dev *dev, struct recv_data *rdata, uint8_t speed)
 {
        uint8_t out[0x40];
        int pfd;
 {
        uint8_t out[0x40];
        int pfd;
@@ -392,6 +490,17 @@ static int switch_speed(struct ota_dev *dev, struct recv_data *rdata, uint8_t sp
                                return culfw_send(dev->culfw, "Ar\r\n", 4);
                        }
                        break;
                                return culfw_send(dev->culfw, "Ar\r\n", 4);
                        }
                        break;
+               case DEVICE_TYPE_HMUARTLGW:
+                       if (speed == 100) {
+                               out[0] = HMUARTLGW_OS_UPDATE_MODE;
+                               out[1] = 0xe9;
+                               out[2] = 0xca;
+                               hmuartlgw_send(dev->hmuartlgw, out, 3, HMUARTLGW_OS);
+                       } else {
+                               out[0] = HMUARTLGW_OS_NORMAL_MODE;
+                               hmuartlgw_send(dev->hmuartlgw, out, 1, HMUARTLGW_OS);
+                       }
+                       break;
        }
 
        return 1;
        }
 
        return 1;
@@ -408,6 +517,7 @@ void flash_ota_syntax(char *prog)
        fprintf(stderr, "\t-b bps\t\tuse CUL with speed \"bps\" (default: %u)\n", DEFAULT_CUL_BPS);
        fprintf(stderr, "\t-l\t\tlower payloadlen (required for devices with little RAM, e.g. CUL v2 and CUL v4)\n");
        fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n");
        fprintf(stderr, "\t-b bps\t\tuse CUL with speed \"bps\" (default: %u)\n", DEFAULT_CUL_BPS);
        fprintf(stderr, "\t-l\t\tlower payloadlen (required for devices with little RAM, e.g. CUL v2 and CUL v4)\n");
        fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n");
+       fprintf(stderr, "\t-U device\tuse HM-MOD-UART on given device\n");
        fprintf(stderr, "\t-h\t\tthis help\n");
        fprintf(stderr, "\nOptional parameters for automatically sending device to bootloader\n");
        fprintf(stderr, "\t-C\t\tHMID of central (3 hex-bytes, no prefix, e.g. ABCDEF)\n");
        fprintf(stderr, "\t-h\t\tthis help\n");
        fprintf(stderr, "\nOptional parameters for automatically sending device to bootloader\n");
        fprintf(stderr, "\t-C\t\tHMID of central (3 hex-bytes, no prefix, e.g. ABCDEF)\n");
@@ -424,7 +534,7 @@ int main(int argc, char **argv)
        char *culfw_dev = NULL;
        char *endptr = NULL;
        unsigned int bps = DEFAULT_CUL_BPS;
        char *culfw_dev = NULL;
        char *endptr = NULL;
        unsigned int bps = DEFAULT_CUL_BPS;
-       struct ota_dev dev;
+       struct hm_dev dev;
        struct recv_data rdata;
        uint8_t out[0x40];
        uint8_t *pos;
        struct recv_data rdata;
        uint8_t out[0x40];
        uint8_t *pos;
@@ -432,6 +542,7 @@ int main(int argc, char **argv)
        uint16_t len;
        struct firmware *fw;
        char *hmcfgusb_serial = NULL;
        uint16_t len;
        struct firmware *fw;
        char *hmcfgusb_serial = NULL;
+       char *uart = NULL;
        int block;
        int pfd;
        int debug = 0;
        int block;
        int pfd;
        int debug = 0;
@@ -443,7 +554,7 @@ int main(int argc, char **argv)
 
        printf("HomeMatic OTA flasher version " VERSION "\n\n");
 
 
        printf("HomeMatic OTA flasher version " VERSION "\n\n");
 
-       while((opt = getopt(argc, argv, "b:c:f:hls:C:D:K:S:")) != -1) {
+       while((opt = getopt(argc, argv, "b:c:f:hls:C:D:K:S:U:")) != -1) {
                switch (opt) {
                        case 'b':
                                bps = atoi(optarg);
                switch (opt) {
                        case 'b':
                                bps = atoi(optarg);
@@ -500,6 +611,9 @@ int main(int argc, char **argv)
                        case 'S':
                                hmcfgusb_serial = optarg;
                                break;
                        case 'S':
                                hmcfgusb_serial = optarg;
                                break;
+                       case 'U':
+                               uart = optarg;
+                               break;
                        case 'h':
                        case ':':
                        case '?':
                        case 'h':
                        case ':':
                        case '?':
@@ -521,7 +635,7 @@ int main(int argc, char **argv)
                exit(EXIT_FAILURE);
 
        memset(&rdata, 0, sizeof(rdata));
                exit(EXIT_FAILURE);
 
        memset(&rdata, 0, sizeof(rdata));
-       memset(&dev, 0, sizeof(struct ota_dev));
+       memset(&dev, 0, sizeof(struct hm_dev));
 
        if (culfw_dev) {
                printf("Opening culfw-device at path %s with speed %u\n", culfw_dev, bps);
 
        if (culfw_dev) {
                printf("Opening culfw-device at path %s with speed %u\n", culfw_dev, bps);
@@ -564,6 +678,95 @@ int main(int argc, char **argv)
                        fprintf(stderr, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n");
                        exit(EXIT_FAILURE);
                }
                        fprintf(stderr, "\nThis version does _not_ support firmware upgrade mode, you need at least 1.58!\n");
                        exit(EXIT_FAILURE);
                }
+       } else if (uart) {
+               uint32_t new_hmid = my_hmid;
+
+               hmuartlgw_set_debug(debug);
+
+               dev.hmuartlgw = hmuart_init(uart, parse_hmuartlgw, &rdata);
+               if (!dev.hmuartlgw) {
+                       fprintf(stderr, "Can't initialize HM-MOD-UART\n");
+                       exit(EXIT_FAILURE);
+               }
+               dev.type = DEVICE_TYPE_HMUARTLGW;
+
+               out[0] = HMUARTLGW_APP_GET_HMID;
+               do {
+                       rdata.uartlgw_state = HMUARTLGW_STATE_GET_HMID;
+                       hmuartlgw_send(dev.hmuartlgw, out, 1, HMUARTLGW_APP);
+                       do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+               } while (rdata.status == 0x08);
+
+               out[0] = HMUARTLGW_OS_GET_FIRMWARE;
+               do {
+                       rdata.uartlgw_state = HMUARTLGW_STATE_GET_FIRMWARE;
+                       hmuartlgw_send(dev.hmuartlgw, out, 1, HMUARTLGW_OS);
+                       do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_DONE);
+               } while (rdata.status == 0x08);
+
+               out[0] = HMUARTLGW_OS_GET_CREDITS;
+               do {
+                       rdata.uartlgw_state = HMUARTLGW_STATE_GET_CREDITS;
+                       hmuartlgw_send(dev.hmuartlgw, out, 1, HMUARTLGW_OS);
+                       do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_DONE);
+               } while (rdata.status == 0x08);
+
+               printf("HM-MOD-UART firmware version: %u.%u.%u, used credits: %u%%\n",
+                       rdata.uartlgw_version[0],
+                       rdata.uartlgw_version[1],
+                       rdata.uartlgw_version[2],
+                       rdata.credits);
+
+               if (rdata.credits >= 40) {
+                       printf("\nRebooting HM-MOD-UART to avoid running out of credits\n");
+
+                       hmuartlgw_enter_bootloader(dev.hmuartlgw);
+                       hmuartlgw_enter_app(dev.hmuartlgw);
+               }
+
+               printf("\nHM-MOD-UART opened\n\n");
+
+               if (new_hmid && (my_hmid != new_hmid)) {
+                       printf("Changing hmid from %06x to %06x\n", my_hmid, new_hmid);
+
+                       out[0] = HMUARTLGW_APP_SET_HMID;
+                       out[1] = (new_hmid >> 16) & 0xff;
+                       out[2] = (new_hmid >> 8) & 0xff;
+                       out[3] = new_hmid & 0xff;
+                       do {
+                               rdata.uartlgw_state = HMUARTLGW_STATE_WAIT_APP;
+                               hmuartlgw_send(dev.hmuartlgw, out, 4, HMUARTLGW_APP);
+                               do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+                       } while (rdata.status == 0x08);
+
+                       my_hmid = new_hmid;
+               }
+
+               if (kNo > 0) {
+                       printf("Setting AES-key\n");
+
+                       memset(out, 0, sizeof(out));
+                       out[0] = HMUARTLGW_APP_SET_CURRENT_KEY;
+                       memcpy(&(out[1]), key, 16);
+                       out[17] = kNo;
+
+                       do {
+                               rdata.uartlgw_state = HMUARTLGW_STATE_WAIT_APP;
+                               hmuartlgw_send(dev.hmuartlgw, out, 18, HMUARTLGW_APP);
+                               do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+                       } while (rdata.status == 0x08);
+
+                       memset(out, 0, sizeof(out));
+                       out[0] = HMUARTLGW_APP_SET_OLD_KEY;
+                       memcpy(&(out[1]), key, 16);
+                       out[17] = kNo;
+
+                       do {
+                               rdata.uartlgw_state = HMUARTLGW_STATE_WAIT_APP;
+                               hmuartlgw_send(dev.hmuartlgw, out, 18, HMUARTLGW_APP);
+                               do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+                       } while (rdata.status == 0x08);
+               }
        } else {
                uint32_t new_hmid = my_hmid;
 
        } else {
                uint32_t new_hmid = my_hmid;
 
@@ -680,6 +883,38 @@ int main(int argc, char **argv)
        }
 
        if (hmid && my_hmid) {
        }
 
        if (hmid && my_hmid) {
+               switch (dev.type) {
+                       case DEVICE_TYPE_HMCFGUSB:
+                               printf("Adding HMID\n");
+
+                               memset(out, 0, sizeof(out));
+                               out[0] = '+';
+                               out[1] = (hmid >> 16) & 0xff;
+                               out[2] = (hmid >> 8) & 0xff;
+                               out[3] = hmid & 0xff;
+
+                               hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
+                               break;
+                       case DEVICE_TYPE_HMUARTLGW:
+                               printf("Adding HMID\n");
+
+                               memset(out, 0, sizeof(out));
+                               out[0] = HMUARTLGW_APP_ADD_PEER;
+                               out[1] = (hmid >> 16) & 0xff;
+                               out[2] = (hmid >> 8) & 0xff;
+                               out[3] = hmid & 0xff;
+                               out[4] = (kNo > 0) ? kNo : 0x00; /* KeyIndex */
+                               out[5] = 0x00; /* WakeUp? */
+                               out[6] = 0x00; /* WakeUp? */
+
+                               do {
+                                       rdata.uartlgw_state = HMUARTLGW_STATE_WAIT_APP;
+                                       hmuartlgw_send(dev.hmuartlgw, out, 7, HMUARTLGW_APP);
+                                       do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+                               } while (rdata.status == 0x08);
+
+                               break;
+               }
                printf("Sending device with hmid %06x to bootloader\n", hmid);
                out[CTL] = 0x30;
                out[TYPE] = 0x11;
                printf("Sending device with hmid %06x to bootloader\n", hmid);
                out[CTL] = 0x30;
                out[TYPE] = 0x11;
@@ -713,9 +948,14 @@ int main(int argc, char **argv)
                                pfd = culfw_poll(dev.culfw, 1000);
                                break;
                        case DEVICE_TYPE_HMCFGUSB:
                                pfd = culfw_poll(dev.culfw, 1000);
                                break;
                        case DEVICE_TYPE_HMCFGUSB:
-                       default:
                                pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
                                break;
                                pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
                                break;
+                       case DEVICE_TYPE_HMUARTLGW:
+                               pfd = hmuartlgw_poll(dev.hmuartlgw, 1000);
+                               break;
+                       default:
+                               pfd = -1;
+                               break;
                }
 
                if ((pfd < 0) && errno) {
                }
 
                if ((pfd < 0) && errno) {
@@ -743,16 +983,37 @@ int main(int argc, char **argv)
 
        printf("Device with serial %s (HMID: %06x) entered firmware-update-mode\n", serial, hmid);
 
 
        printf("Device with serial %s (HMID: %06x) entered firmware-update-mode\n", serial, hmid);
 
-       if (dev.type == DEVICE_TYPE_HMCFGUSB) {
-               printf("Adding HMID\n");
+       switch (dev.type) {
+               case DEVICE_TYPE_HMCFGUSB:
+                       printf("Adding HMID\n");
 
 
-               memset(out, 0, sizeof(out));
-               out[0] = '+';
-               out[1] = (hmid >> 16) & 0xff;
-               out[2] = (hmid >> 8) & 0xff;
-               out[3] = hmid & 0xff;
+                       memset(out, 0, sizeof(out));
+                       out[0] = '+';
+                       out[1] = (hmid >> 16) & 0xff;
+                       out[2] = (hmid >> 8) & 0xff;
+                       out[3] = hmid & 0xff;
 
 
-               hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
+                       hmcfgusb_send(dev.hmcfgusb, out, sizeof(out), 1);
+                       break;
+               case DEVICE_TYPE_HMUARTLGW:
+                       printf("Adding HMID\n");
+
+                       memset(out, 0, sizeof(out));
+                       out[0] = HMUARTLGW_APP_ADD_PEER;
+                       out[1] = (hmid >> 16) & 0xff;
+                       out[2] = (hmid >> 8) & 0xff;
+                       out[3] = hmid & 0xff;
+                       out[4] = 0x00; /* KeyIndex */
+                       out[5] = 0x00; /* WakeUp? */
+                       out[6] = 0x00; /* WakeUp? */
+
+                       do {
+                               rdata.uartlgw_state = HMUARTLGW_STATE_WAIT_APP;
+                               hmuartlgw_send(dev.hmuartlgw, out, 7, HMUARTLGW_APP);
+                               do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (rdata.uartlgw_state != HMUARTLGW_STATE_ACK_APP);
+                       } while (rdata.status == 0x08);
+
+                       break;
        }
 
        switchcnt = 3;
        }
 
        switchcnt = 3;
@@ -904,8 +1165,11 @@ int main(int argc, char **argv)
        }
 
        printf("Waiting for device to reboot\n");
        }
 
        printf("Waiting for device to reboot\n");
+       rdata.message_type = MESSAGE_TYPE_R;
 
        cnt = 10;
 
        cnt = 10;
+       if (dev.type == DEVICE_TYPE_HMUARTLGW)
+               cnt = 200; /* FIXME */
        do {
                errno = 0;
                switch(dev.type) {
        do {
                errno = 0;
                switch(dev.type) {
@@ -913,9 +1177,14 @@ int main(int argc, char **argv)
                                pfd = culfw_poll(dev.culfw, 1000);
                                break;
                        case DEVICE_TYPE_HMCFGUSB:
                                pfd = culfw_poll(dev.culfw, 1000);
                                break;
                        case DEVICE_TYPE_HMCFGUSB:
-                       default:
                                pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
                                break;
                                pfd = hmcfgusb_poll(dev.hmcfgusb, 1000);
                                break;
+                       case DEVICE_TYPE_HMUARTLGW:
+                               pfd = hmuartlgw_poll(dev.hmuartlgw, 1000);
+                               break;
+                       default:
+                               pfd = -1;
+                               break;
                }
                if ((pfd < 0) && errno) {
                        if (errno != ETIMEDOUT) {
                }
                if ((pfd < 0) && errno) {
                        if (errno != ETIMEDOUT) {
diff --git a/hm.h b/hm.h
index 8126cec65ea36486b66f1e95f17eb275918265ad..f80c58e6771fcd8d1b519cb2ddef8f261d70ea19 100644 (file)
--- a/hm.h
+++ b/hm.h
 #define SET_LEN_FROM_PAYLOADLEN(buf, payloadlen)       do { buf[0x00] = payloadlen + 0x09; } while(0)
 #define PAYLOADLEN(buf)                                        (buf[0x00] - 0x09)
 
 #define SET_LEN_FROM_PAYLOADLEN(buf, payloadlen)       do { buf[0x00] = payloadlen + 0x09; } while(0)
 #define PAYLOADLEN(buf)                                        (buf[0x00] - 0x09)
 
+enum device_type {
+       DEVICE_TYPE_HMCFGUSB,
+       DEVICE_TYPE_CULFW,
+       DEVICE_TYPE_HMUARTLGW,
+};
+
+struct hm_dev {
+       int type;
+       struct hmcfgusb_dev *hmcfgusb;
+       struct culfw_dev *culfw;
+       struct hmuartlgw_dev *hmuartlgw;
+};
+
 uint8_t* hm_sign(uint8_t *key, uint8_t *challenge, uint8_t *m_frame, uint8_t *exp_auth, uint8_t *resp);
 uint8_t* hm_sign(uint8_t *key, uint8_t *challenge, uint8_t *m_frame, uint8_t *exp_auth, uint8_t *resp);
index 82907f78b8f9029e3232b495af28839717eb8f87..638ae1d4e96847e7c7ac178a5a95496abd3be78f 100644 (file)
--- a/hmsniff.c
+++ b/hmsniff.c
@@ -36,6 +36,8 @@
 #include "version.h"
 #include "hexdump.h"
 #include "hmcfgusb.h"
 #include "version.h"
 #include "hexdump.h"
 #include "hmcfgusb.h"
+#include "hmuartlgw.h"
+#include "hm.h"
 
 static int verbose = 0;
 
 
 static int verbose = 0;
 
@@ -213,12 +215,39 @@ static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data)
        return 1;
 }
 
        return 1;
 }
 
+static int parse_hmuartlgw(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data)
+{
+       if (dst == HMUARTLGW_OS) {
+               if ((buf[0] != HMUARTLGW_OS_ACK) ||
+                   (buf[1] != 0x01)) {
+                       hexdump(buf, buf_len, "OS> ");
+               }
+               return 0;
+       }
+
+       if (dst != HMUARTLGW_APP) {
+               return 0;
+       }
+
+       switch(buf[0]) {
+               case HMUARTLGW_APP_RECV:
+                       dissect_hm(buf + 3, buf_len - 3);
+               case HMUARTLGW_APP_ACK:
+                       break;
+               default:
+                       hexdump(buf, buf_len, "Unknown> ");
+       }
+
+       return 1;
+}
+
 void hmsniff_syntax(char *prog)
 {
        fprintf(stderr, "Syntax: %s options\n\n", prog);
        fprintf(stderr, "Possible options:\n");
        fprintf(stderr, "\t-f\t\tfast (100k/firmware update) mode\n");
        fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n");
 void hmsniff_syntax(char *prog)
 {
        fprintf(stderr, "Syntax: %s options\n\n", prog);
        fprintf(stderr, "Possible options:\n");
        fprintf(stderr, "\t-f\t\tfast (100k/firmware update) mode\n");
        fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n");
+       fprintf(stderr, "\t-U device\tuse HM-MOD-UART on given device\n");
        fprintf(stderr, "\t-v\t\tverbose mode\n");
        fprintf(stderr, "\t-V\t\tshow version (" VERSION ")\n");
 
        fprintf(stderr, "\t-v\t\tverbose mode\n");
        fprintf(stderr, "\t-V\t\tshow version (" VERSION ")\n");
 
@@ -226,15 +255,18 @@ void hmsniff_syntax(char *prog)
 
 int main(int argc, char **argv)
 {
 
 int main(int argc, char **argv)
 {
-       struct hmcfgusb_dev *dev;
+       struct hm_dev dev = { 0 };
        struct recv_data rdata;
        char *serial = NULL;
        struct recv_data rdata;
        char *serial = NULL;
+       char *uart = NULL;
        int quit = 0;
        int speed = 10;
        int quit = 0;
        int speed = 10;
-       uint8_t speed_buf[2];
+       uint8_t buf[32];
        int opt;
 
        int opt;
 
-       while((opt = getopt(argc, argv, "fS:vV")) != -1) {
+       dev.type = DEVICE_TYPE_HMCFGUSB;
+
+       while((opt = getopt(argc, argv, "fS:U:vV")) != -1) {
                switch (opt) {
                        case 'f':
                                speed = 100;
                switch (opt) {
                        case 'f':
                                speed = 100;
@@ -242,6 +274,10 @@ int main(int argc, char **argv)
                        case 'S':
                                serial = optarg;
                                break;
                        case 'S':
                                serial = optarg;
                                break;
+                       case 'U':
+                               uart = optarg;
+                               dev.type = DEVICE_TYPE_HMUARTLGW;
+                               break;
                        case 'v':
                                verbose = 1;
                                break;
                        case 'v':
                                verbose = 1;
                                break;
@@ -259,58 +295,109 @@ int main(int argc, char **argv)
                }
        }
 
                }
        }
 
-       hmcfgusb_set_debug(0);
+       if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+               hmcfgusb_set_debug(0);
+       } else {
+               hmuartlgw_set_debug(0);
+       }
 
        do {
                memset(&rdata, 0, sizeof(rdata));
                rdata.wrong_hmid = 0;
 
 
        do {
                memset(&rdata, 0, sizeof(rdata));
                rdata.wrong_hmid = 0;
 
-               dev = hmcfgusb_init(parse_hmcfgusb, &rdata, serial);
-               if (!dev) {
-                       fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n");
-                       sleep(1);
-                       continue;
-               }
-               printf("HM-CFG-USB opened!\n");
+               if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+                       dev.hmcfgusb = hmcfgusb_init(parse_hmcfgusb, &rdata, serial);
+                       if (!dev.hmcfgusb) {
+                               fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n");
+                               sleep(1);
+                               continue;
+                       }
+                       printf("HM-CFG-USB opened!\n");
 
 
-               hmcfgusb_send_null_frame(dev, 1);
-               hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
+                       hmcfgusb_send_null_frame(dev.hmcfgusb, 1);
+                       hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"K", 1, 1);
 
 
-               hmcfgusb_send_null_frame(dev, 1);
-               speed_buf[0] = 'G';
-               speed_buf[1] = speed;
-               hmcfgusb_send(dev, speed_buf, 2, 1);
+                       hmcfgusb_send_null_frame(dev.hmcfgusb, 1);
+                       buf[0] = 'G';
+                       buf[1] = speed;
+                       hmcfgusb_send(dev.hmcfgusb, buf, 2, 1);
+               } else {
+                       dev.hmuartlgw = hmuart_init(uart, parse_hmuartlgw, &rdata);
+                       if (!dev.hmuartlgw) {
+                               fprintf(stderr, "Can't initialize HM-MOD-UART!\n");
+                               exit(1);
+                       }
+                       printf("HM-MOD-UART opened!\n");
+
+                       buf[0] = HMUARTLGW_APP_SET_HMID;
+                       buf[1] = 0x00;
+                       buf[2] = 0x00;
+                       buf[3] = 0x00;
+                       hmuartlgw_send(dev.hmuartlgw, buf, 4, HMUARTLGW_APP);
+                       do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (errno != ETIMEDOUT);
+                       if (speed == 100) {
+                               buf[0] = HMUARTLGW_OS_UPDATE_MODE;
+                               buf[1] = 0xe9;
+                               buf[2] = 0xca;
+                               hmuartlgw_send(dev.hmuartlgw, buf, 3, HMUARTLGW_OS);
+                       } else {
+                               buf[0] = HMUARTLGW_OS_NORMAL_MODE;
+                               hmuartlgw_send(dev.hmuartlgw, buf, 1, HMUARTLGW_OS);
+                       }
+               }
 
                while(!quit) {
                        int fd;
 
                        if (rdata.wrong_hmid) {
                                printf("changing hmId to 000000, this might reboot the device!\n");
 
                while(!quit) {
                        int fd;
 
                        if (rdata.wrong_hmid) {
                                printf("changing hmId to 000000, this might reboot the device!\n");
-                               hmcfgusb_send(dev, (unsigned char*)"A\00\00\00", 4, 1);
-                               rdata.wrong_hmid = 0;
-                               hmcfgusb_send(dev, (unsigned char*)"K", 1, 1);
+                               if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+                                       hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"A\00\00\00", 4, 1);
+                                       rdata.wrong_hmid = 0;
+                                       hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"K", 1, 1);
+                               } else {
+                                       buf[0] = HMUARTLGW_APP_SET_HMID;
+                                       buf[1] = 0x00;
+                                       buf[2] = 0x00;
+                                       buf[3] = 0x00;
+                                       hmuartlgw_send(dev.hmuartlgw, buf, 4, HMUARTLGW_APP);
+                               }
+                       }
+                       if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+                               fd = hmcfgusb_poll(dev.hmcfgusb, 1000);
+                       } else {
+                               fd = hmuartlgw_poll(dev.hmuartlgw, 60000);
                        }
                        }
-                       fd = hmcfgusb_poll(dev, 1000);
                        if (fd >= 0) {
                                fprintf(stderr, "activity on unknown fd %d!\n", fd);
                                continue;
                        } else if (fd == -1) {
                                if (errno) {
                                        if (errno != ETIMEDOUT) {
                        if (fd >= 0) {
                                fprintf(stderr, "activity on unknown fd %d!\n", fd);
                                continue;
                        } else if (fd == -1) {
                                if (errno) {
                                        if (errno != ETIMEDOUT) {
-                                               perror("hmcfgusb_poll");
+                                               perror("hmsniff_poll");
                                                break;
                                        } else {
                                                /* periodically wakeup the device */
                                                break;
                                        } else {
                                                /* periodically wakeup the device */
-                                               hmcfgusb_send_null_frame(dev, 1);
+                                               if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+                                                       hmcfgusb_send_null_frame(dev.hmcfgusb, 1);
+                                               }
                                        }
                                }
                        }
                }
 
                                        }
                                }
                        }
                }
 
-               hmcfgusb_close(dev);
+               if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+                       if (dev.hmcfgusb)
+                               hmcfgusb_close(dev.hmcfgusb);
+               } else {
+                       if (dev.hmuartlgw)
+                               hmuartlgw_close(dev.hmuartlgw);
+               }
        } while (!quit);
 
        } while (!quit);
 
-       hmcfgusb_exit();
+       if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+               hmcfgusb_exit();
+       }
 
        return EXIT_SUCCESS;
 }
 
        return EXIT_SUCCESS;
 }
diff --git a/hmuartlgw.c b/hmuartlgw.c
new file mode 100644 (file)
index 0000000..ccb5dbc
--- /dev/null
@@ -0,0 +1,481 @@
+/* HM-MOD-UART/HM-LGW-O-TW-W-EU driver
+ *
+ * Copyright (c) 2016 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
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "hexdump.h"
+#include "hmuartlgw.h"
+
+#define HMUARTLGW_INIT_TIMEOUT 10000
+
+#define HMUARTLGW_SETTLE_TIME  2
+
+static int debug = 0;
+
+enum hmuartlgw_state {
+       HMUARTLGW_QUERY_APPSTATE,
+       HMUARTLGW_ENTER_BOOTLOADER,
+       HMUARTLGW_ENTER_BOOTLOADER_ACK,
+       HMUARTLGW_BOOTLOADER,
+       HMUARTLGW_ENTER_APPLICATION,
+       HMUARTLGW_ENTER_APPLICATION_ACK,
+       HMUARTLGW_APPLICATION,
+};
+
+struct recv_data {
+       enum hmuartlgw_state state;
+};
+
+
+#define CRC16_POLY     0x8005
+
+static uint16_t crc16(uint8_t* buf, int length)
+{
+       uint16_t crc = 0xd77f;
+       int i;
+
+       while (length--) {
+               crc ^= *buf++ << 8;
+               for (i = 0; i < 8; i++) {
+                       if (crc & 0x8000) {
+                               crc <<= 1;
+                               crc ^= CRC16_POLY;
+                       } else {
+                               crc <<= 1;
+                       }
+               }
+       }
+
+       return crc;
+}
+
+static int hmuartlgw_init_parse(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data)
+{
+       struct recv_data *rdata = data;
+
+#if 0
+       if (debug) {
+               printf("Length: %d\n", buf_len);
+               hexdump(buf, buf_len, "INIT > ");
+       }
+#endif
+
+       if (dst != HMUARTLGW_OS)
+               return 0;
+
+       if ((buf_len == 10) && (buf[0] == 0x00) && !strncmp(((char*)buf)+1, "Co_CPU_BL", 9)) {
+               rdata->state = HMUARTLGW_BOOTLOADER;
+               return 1;
+       }
+
+       if ((buf_len == 11) && (buf[0] == 0x00) && !strncmp(((char*)buf)+1, "Co_CPU_App", 10)) {
+               rdata->state = HMUARTLGW_APPLICATION;
+               return 1;
+       }
+
+       switch(rdata->state) {
+               case HMUARTLGW_QUERY_APPSTATE:
+                       if ((buf[0] == 0x04) && (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)) {
+                                       rdata->state = HMUARTLGW_APPLICATION;
+                               }
+                       }
+                       break;
+               case HMUARTLGW_ENTER_BOOTLOADER:
+                       if ((buf_len == 2) &&
+                           (buf[0] == 0x04) &&
+                           (buf[1] == 0x01)) {
+                               rdata->state = HMUARTLGW_ENTER_BOOTLOADER_ACK;
+                       }
+                       break;
+               case HMUARTLGW_ENTER_BOOTLOADER_ACK:
+                       rdata->state = HMUARTLGW_ENTER_BOOTLOADER;
+                       break;
+               case HMUARTLGW_ENTER_APPLICATION:
+                       if ((buf_len == 2) &&
+                           (buf[0] == 0x04) &&
+                           (buf[1] == 0x01)) {
+                               rdata->state = HMUARTLGW_ENTER_APPLICATION_ACK;
+                       }
+                       break;
+               case HMUARTLGW_ENTER_APPLICATION_ACK:
+                       rdata->state = HMUARTLGW_ENTER_APPLICATION;
+                       break;
+               default:
+                       return 0;
+                       break;
+       }
+
+        return 1;
+}
+
+struct hmuartlgw_dev *hmuart_init(char *device, hmuartlgw_cb_fn cb, void *data)
+{
+       struct hmuartlgw_dev *dev = NULL;
+       struct termios oldtio, tio;
+
+       dev = malloc(sizeof(struct hmuartlgw_dev));
+       if (dev == NULL) {
+               perror("malloc(struct hmuartlgw_dev)");
+               return NULL;
+       }
+
+       memset(dev, 0, sizeof(struct hmuartlgw_dev));
+
+       dev->fd = open(device, O_RDWR | O_NOCTTY);
+       if (dev->fd < 0) {
+               perror("open(hmuartlgw)");
+               goto out;
+       }
+
+       if (debug) {
+               fprintf(stderr, "%s opened\n", device);
+       }
+
+       if (tcgetattr(dev->fd, &oldtio) == -1) {
+               perror("tcgetattr");
+               goto out2;
+       }
+
+       memset(&tio, 0, sizeof(tio));
+
+       tio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
+       tio.c_iflag = IGNPAR;
+       tio.c_oflag = 0;
+       tio.c_lflag = 0;
+       tio.c_cc[VTIME] = 0;
+       tio.c_cc[VMIN] = 1;
+
+       tcflush(dev->fd, TCIFLUSH);
+       if (tcsetattr(dev->fd, TCSANOW, &tio) == -1) {
+               perror("tcsetattr");
+               goto out2;
+       }
+
+       if (debug) {
+               fprintf(stderr, "serial parameters set\n");
+       }
+
+       hmuartlgw_flush(dev);
+
+       hmuartlgw_enter_app(dev);
+
+       dev->cb = cb;
+       dev->cb_data = data;
+
+       return dev;
+
+out2:
+       close(dev->fd);
+out:
+       free(dev);
+       return NULL;
+}
+
+struct hmuartlgw_dev *hmlgw_init(char *device, hmuartlgw_cb_fn cb, void *data)
+{
+       struct hmuartlgw_dev *dev = NULL;
+
+       return dev;
+}
+
+void hmuartlgw_enter_bootloader(struct hmuartlgw_dev *dev)
+{
+       hmuartlgw_cb_fn cb_old = dev->cb;
+       void *cb_data_old = dev->cb_data;
+       struct recv_data rdata = { 0 };
+       uint8_t buf[128] = { 0 };
+
+       if (debug) {
+               fprintf(stderr, "Entering bootloader\n");
+       }
+
+       buf[0] = HMUARTLGW_OS_CHANGE_APP;
+
+       dev->cb = hmuartlgw_init_parse;
+       dev->cb_data = &rdata;
+
+       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);
+       } while (rdata.state == HMUARTLGW_QUERY_APPSTATE);
+
+       if (rdata.state != HMUARTLGW_BOOTLOADER) {
+               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);
+
+               printf("Waiting for bootloader to settle...\n");
+               sleep(HMUARTLGW_SETTLE_TIME);
+       }
+
+       dev->cb = cb_old;
+       dev->cb_data = cb_data_old;
+}
+
+void hmuartlgw_enter_app(struct hmuartlgw_dev *dev)
+{
+       hmuartlgw_cb_fn cb_old = dev->cb;
+       void *cb_data_old = dev->cb_data;
+       struct recv_data rdata = { 0 };
+       uint8_t buf[128] = { 0 };
+
+       if (debug) {
+               fprintf(stderr, "Entering application\n");
+       }
+
+       dev->cb = hmuartlgw_init_parse;
+       dev->cb_data = &rdata;
+
+       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);
+       } while (rdata.state == HMUARTLGW_QUERY_APPSTATE);
+
+       if (rdata.state != HMUARTLGW_APPLICATION) {
+               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);
+
+               printf("Waiting for application to settle...\n");
+               sleep(HMUARTLGW_SETTLE_TIME);
+       }
+
+       dev->cb = cb_old;
+       dev->cb_data = cb_data_old;
+}
+
+static int hmuartlgw_escape(uint8_t *frame, int framelen)
+{
+       int i;
+
+       for (i = 1; i < framelen; i++) {
+               if (frame[i] == 0xfc || frame[i] == 0xfd) {
+                       memmove(frame + i + 1, frame + i, framelen - i);
+                       frame[i++] = 0xfc;
+                       frame[i] &= 0x7f;
+                       framelen++;
+               }
+       }
+       return framelen;
+}
+
+int hmuartlgw_send_raw(struct hmuartlgw_dev *dev, uint8_t *frame, int framelen)
+{
+       int w = 0;
+       int ret;
+
+       if (debug) {
+               hexdump(frame, framelen, "UARTLGW < ");
+       }
+
+       framelen = hmuartlgw_escape(frame, framelen);
+
+       do {
+               ret = write(dev->fd, frame + w, framelen - w);
+               if (ret < 0) {
+                       perror("write");
+                       return 0;
+               }
+               w += ret;
+       } while (w < framelen);
+
+       return 1;
+}
+
+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 };
+       uint16_t crc;
+
+       frame[0] = 0xfd;
+       frame[1] = ((cmdlen + 2) >> 8) & 0xff;
+       frame[2] = (cmdlen + 2) & 0xff;
+       frame[3] = dst;
+       dev->last_send_cnt = cnt;
+       frame[4] = cnt++;
+       memcpy(&(frame[5]), cmd, cmdlen);
+       crc = crc16(frame, cmdlen + 5);
+       frame[cmdlen + 5] = (crc >> 8) & 0xff;
+       frame[cmdlen + 6] = crc & 0xff;
+
+       return hmuartlgw_send_raw(dev, frame, cmdlen + 7);
+}
+
+int hmuartlgw_poll(struct hmuartlgw_dev *dev, int timeout)
+{
+       struct pollfd pfds[1];
+       int ret;
+       int r = 0;
+       uint16_t crc;
+
+       errno = 0;
+
+       memset(pfds, 0, sizeof(struct pollfd) * 1);
+
+       pfds[0].fd = dev->fd;
+       pfds[0].events = POLLIN;
+
+       ret = poll(pfds, 1, timeout);
+       if (ret == -1)
+               return -1;
+
+       errno = 0;
+       if (ret == 0) {
+               errno = ETIMEDOUT;
+               return -1;
+       }
+
+       if (!(pfds[0].revents & POLLIN)) {
+               errno = EIO;
+               return -1;
+       }
+
+       r = read(dev->fd, dev->buf+dev->pos, 1);
+       if (r < 0)
+               return -1;
+
+       if (r == 0) {
+               errno = EOF;
+               return -1;
+       }
+
+       dev->pos += r;
+
+       if (dev->buf[0] != 0xfd) {
+               memset(dev->buf, 0, sizeof(dev->buf));
+               dev->pos = 0;
+               dev->unescape_next = 0;
+               return -1;
+       }
+
+       if (dev->unescape_next) {
+               dev->buf[dev->pos-1] |= 0x80;
+               dev->unescape_next = 0;
+       } else if (dev->buf[dev->pos-1] == 0xfc) {
+               dev->unescape_next = 1;
+               dev->pos--;
+               return -1;
+       }
+
+       if (dev->pos >= 3) {
+               uint16_t len;
+
+               len = ((dev->buf[1] << 8) & 0xff00) | (dev->buf[2] & 0xff);
+
+               if (dev->pos < len + 5)
+                       return -1;
+       } else {
+               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])) {
+
+               if (debug)
+                       hexdump(dev->buf, dev->pos, "UARTLGW > ");
+
+               dev->cb(dev->buf[3], dev->buf + 5 , dev->pos - 7, dev->cb_data);
+
+               memset(dev->buf, 0, sizeof(dev->buf));
+               dev->pos = 0;
+               dev->unescape_next = 0;
+       } else {
+               fprintf(stderr, "Invalid checksum received!\n");
+               hexdump(dev->buf, dev->pos, "ERR> ");
+               printf("calculated: %04x\n", crc);
+
+               memset(dev->buf, 0, sizeof(dev->buf));
+               dev->pos = 0;
+               dev->unescape_next = 0;
+       }
+
+       errno = 0;
+       return -1;
+}
+
+void hmuartlgw_close(struct hmuartlgw_dev *dev)
+{
+       close(dev->fd);
+}
+
+void hmuartlgw_flush(struct hmuartlgw_dev *dev)
+{
+       struct pollfd pfds[1];
+       int ret;
+       int r = 0;
+       uint8_t buf[1024];
+
+       tcflush(dev->fd, TCIOFLUSH);
+
+       while(1) {
+               memset(pfds, 0, sizeof(struct pollfd) * 1);
+
+               pfds[0].fd = dev->fd;
+               pfds[0].events = POLLIN;
+
+               ret = poll(pfds, 1, 100);
+               if (ret <= 0)
+                       break;
+
+               if (!(pfds[0].revents & POLLIN))
+                       break;
+
+               memset(buf, 0, sizeof(buf));
+               r = read(dev->fd, buf, sizeof(buf));
+               if (r <= 0)
+                       break;
+       }
+
+       return;
+}
+
+void hmuartlgw_set_debug(int d)
+{
+       debug = d;
+}
diff --git a/hmuartlgw.h b/hmuartlgw.h
new file mode 100644 (file)
index 0000000..8281bef
--- /dev/null
@@ -0,0 +1,74 @@
+/* HM-MOD-UART/HM-LGW-O-TW-W-EU driver
+ *
+ * Copyright (c) 2016 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
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define HMUARTLGW_OS_GET_APP           0x00
+#define HMUARTLGW_OS_GET_FIRMWARE      0x02
+#define HMUARTLGW_OS_CHANGE_APP                0x03
+#define HMUARTLGW_OS_ACK               0x04
+#define HMUARTLGW_OS_UNSOL_CREDITS     0x05
+#define HMUARTLGW_OS_NORMAL_MODE       0x06
+#define HMUARTLGW_OS_UPDATE_MODE       0x07
+#define HMUARTLGW_OS_GET_CREDITS       0x08
+#define HMUARTLGW_OS_GET_SERIAL                0x0B
+#define HMUARTLGW_OS_SET_TIME          0x0E
+
+#define HMUARTLGW_APP_SET_HMID         0x00
+#define HMUARTLGW_APP_GET_HMID         0x01
+#define HMUARTLGW_APP_SEND             0x02
+#define HMUARTLGW_APP_SET_CURRENT_KEY  0x03    /* key index */
+#define HMUARTLGW_APP_ACK              0x04
+#define HMUARTLGW_APP_RECV             0x05
+#define HMUARTLGW_APP_ADD_PEER         0x06
+#define HMUARTLGW_APP_REMOVE_PEER      0x07
+#define HMUARTLGW_APP_PEER_ADD_AES     0x09
+#define HMUARTLGW_APP_PEER_REMOVE_AES  0x0A
+#define HMUARTLGW_APP_SET_OLD_KEY      0x0F    /* key index */
+#define HMUARTLGW_APP_DEFAULT_HMID     0x10
+
+enum hmuartlgw_dst {
+       HMUARTLGW_OS = 0,
+       HMUARTLGW_APP = 1,
+};
+
+typedef int (*hmuartlgw_cb_fn)(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data);
+
+struct hmuartlgw_dev {
+       int fd;
+       hmuartlgw_cb_fn cb;
+       void *cb_data;
+       uint8_t last_send_cnt;
+       uint8_t buf[1024];
+       int pos;
+       int unescape_next;
+};
+
+struct hmuartlgw_dev *hmuart_init(char *device, hmuartlgw_cb_fn cb, void *data);
+struct hmuartlgw_dev *hmlgw_init(char *device, hmuartlgw_cb_fn cb, void *data);
+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);
+int hmuartlgw_poll(struct hmuartlgw_dev *dev, int timeout);
+void hmuartlgw_close(struct hmuartlgw_dev *dev);
+void hmuartlgw_flush(struct hmuartlgw_dev *dev);
+void hmuartlgw_enter_bootloader(struct hmuartlgw_dev *dev);
+void hmuartlgw_enter_app(struct hmuartlgw_dev *dev);
+void hmuartlgw_set_debug(int d);
diff --git a/reset-hmmoduart.sh b/reset-hmmoduart.sh
new file mode 100755 (executable)
index 0000000..d49ec6d
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+if [ "`id -u`" != "0" ]; then
+       exec sudo "${0}"
+fi
+
+if [ ! -d "/sys/class/gpio/gpio18" ]; then
+       echo 18 >/sys/class/gpio/export
+fi
+
+echo out >/sys/class/gpio/gpio18/direction
+echo 0 >/sys/class/gpio/gpio18/value
+sleep 0.2
+echo 1 >/sys/class/gpio/gpio18/value
+sleep 2
Impressum, Datenschutz