/* HM-sniffer for HM-CFG-USB
*
- * Copyright (c) 2013-15 Michael Gernoth <michael@gernoth.net>
+ * Copyright (c) 2013-16 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
#include "version.h"
#include "hexdump.h"
#include "hmcfgusb.h"
+#include "hmuartlgw.h"
+#include "hm.h"
static int verbose = 0;
/* See HMConfig.pm */
-char *hm_message_types(uint8_t type, uint8_t subtype)
+const char *hm_message_types(uint8_t type, uint8_t subtype)
{
switch(type) {
case 0x00:
case 0x53:
return "Water sensor";
break;
+ case 0x54:
+ return "Gas sensor";
+ break;
case 0x58:
return "Climate event";
break;
return "Thermal control";
break;
case 0x5e:
+ case 0x5f:
return "Power event";
break;
case 0x70:
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:
+ buf[3] = buf_len - 4;
+ 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");
+ 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");
int main(int argc, char **argv)
{
- struct hmcfgusb_dev *dev;
+ struct hm_dev dev = { 0 };
struct recv_data rdata;
+ char *serial = NULL;
+ char *uart = NULL;
int quit = 0;
int speed = 10;
- uint8_t speed_buf[2];
+ uint8_t buf[32];
int opt;
- while((opt = getopt(argc, argv, "fvV")) != -1) {
+ dev.type = DEVICE_TYPE_HMCFGUSB;
+
+ while((opt = getopt(argc, argv, "fS:U:vV")) != -1) {
switch (opt) {
case 'f':
speed = 100;
break;
+ case 'S':
+ serial = optarg;
+ break;
+ case 'U':
+ uart = optarg;
+ dev.type = DEVICE_TYPE_HMUARTLGW;
+ break;
case 'v':
verbose = 1;
break;
case 'V':
printf("hmsniff " VERSION "\n");
- printf("Copyright (c) 2013-15 Michael Gernoth\n\n");
+ printf("Copyright (c) 2013-16 Michael Gernoth\n\n");
exit(EXIT_SUCCESS);
case 'h':
case ':':
}
}
- 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;
- dev = hmcfgusb_init(parse_hmcfgusb, &rdata);
- 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, 1);
+ 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");
- 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) {
- perror("hmcfgusb_poll");
+ perror("hmsniff_poll");
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);
- hmcfgusb_exit();
+ if (dev.type == DEVICE_TYPE_HMCFGUSB) {
+ hmcfgusb_exit();
+ }
return EXIT_SUCCESS;
}