From 7a2d9ddd539a4d578f0da6c3428456946e4011b7 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Tue, 29 May 2018 08:31:26 +0100 Subject: [PATCH] Use serial number as base address + report in USB descriptor Rather than hard coding the base Energenie address use the serial number to encode it. Also report it as part of the USB descriptor making it easier to match against for udev etc. --- main.c | 110 +++++++++++++++++++++++++++++++++++----------------- usbconfig.h | 2 +- 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/main.c b/main.c index d5bf590..5805cee 100644 --- a/main.c +++ b/main.c @@ -34,11 +34,11 @@ #define CMD_OFF 0xfd #define CMD_SET_SERIAL 0xfa -/* Energenie 24 bit address , last 4 all 0 for code */ -#define ENER_ADDR 0x123450 - -uchar serno_read = 0; -uchar serno[6]; +int serno_str[] = { + USB_STRING_DESCRIPTOR_HEADER(5), + '1', '2', '3', '4', '5', +}; +uint32_t serno; unsigned long cmd = 0; int repeat = 0, wait = 0; @@ -55,20 +55,41 @@ PROGMEM const char usbHidReportDescriptor[22] = { 0xc0 /* END_COLLECTION */ }; +inline char hexdigit(int i) +{ + return (i < 10) ? ('0' + i) : ('A' - 10 + i); +} + +inline int digithex(char i) +{ + if (i >= '0' && i <= '9') + return i - '0'; + + if (i >= 'A' && i <= 'F') + return i - 'A' + 10; + + if (i >= 'a' && i <= 'f') + return i - 'a' + 10; + + return 0; +} + void fetch_serno(void) { - if (!serno_read) { - eeprom_read_block(serno, 0, 6); - if (serno[0] == 0xff) { - /* If the EEPROM is blank, return a default serial # */ - serno[0] = 'U'; - serno[1] = 'N'; - serno[2] = 'S'; - serno[3] = 'E'; - serno[4] = 'T'; - serno[5] = 0; - } - serno_read = 1; + eeprom_read_block(&serno, 0, 4); + if (serno == 0xffffffff) { + /* If the EEPROM is blank, return a default serial # */ + serno_str[1] = '1'; + serno_str[2] = '2'; + serno_str[3] = '3'; + serno_str[4] = '4'; + serno_str[5] = '5'; + } else { + serno_str[1] = hexdigit((serno >> 20) & 0xF); + serno_str[2] = hexdigit((serno >> 16) & 0xF); + serno_str[3] = hexdigit((serno >> 12) & 0xF); + serno_str[4] = hexdigit((serno >> 8) & 0xF); + serno_str[5] = hexdigit((serno >> 4) & 0xF); } } @@ -76,16 +97,22 @@ void update_serno(uchar *buf, uchar len) { uchar i; + serno = 0; + for (i = 0; i < 5; i++) { + serno |= digithex(buf[i]); + serno <<= 4; + } + /* * I have no idea why this gets stored 3 times, but the original * firmware does it. */ - eeprom_write_block(buf, (void *) 0x00, len); - eeprom_write_block(buf, (void *) 0x40, len); - eeprom_write_block(buf, (void *) 0x80, len); + eeprom_write_block(&serno, (void *) 0x00, 4); + eeprom_write_block(&serno, (void *) 0x40, 4); + eeprom_write_block(&serno, (void *) 0x80, 4); - for (i = 0; i < 6; i++) { - serno[i] = buf[i]; + for (i = 0; i < 5; i++) { + serno_str[i + 1] = buf[i]; } } @@ -103,16 +130,25 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) return 0; } +usbMsgLen_t usbFunctionDescriptor(usbRequest_t *rq) +{ + if (rq->wValue.bytes[1] == USBDESCR_STRING && + rq->wValue.bytes[0] == 3) { + usbMsgPtr = (usbMsgPtr_t) serno_str; + return sizeof(serno_str); + } + return 0; +} + uchar usbFunctionRead(uchar *data, uchar len) { uchar i; if (len != 0) { - fetch_serno(); - for (i = 0; i < 6; i++) { - data[i] = serno[i]; + for (i = 0; i < 5; i++) { + data[i] = serno_str[i + 1]; } - data[6] = data[7] = 0; + data[5] = data[6] = data[7] = 0; if (PORTB & (1 << PB0)) { data[7] = 1; } @@ -125,30 +161,30 @@ uchar usbFunctionRead(uchar *data, uchar len) uchar usbFunctionWrite(uchar *data, uchar len) { if (data[0] == CMD_ALL_ON) { - cmd = ENER_ADDR | 0xd; + cmd = serno | 0xd; wait = 200; repeat = 5; } else if (data[0] == CMD_ALL_OFF) { - cmd = ENER_ADDR | 0xc; + cmd = serno | 0xc; wait = 10; repeat = 5; } else if (data[0] == CMD_ON) { wait = 200; switch (data[1]) { case 1: - cmd = ENER_ADDR | 0xf; + cmd = serno | 0xf; repeat = 5; break; case 2: - cmd = ENER_ADDR | 0x7; + cmd = serno | 0x7; repeat = 5; break; case 3: - cmd = ENER_ADDR | 0xb; + cmd = serno | 0xb; repeat = 5; break; case 4: - cmd = ENER_ADDR | 0x3; + cmd = serno | 0x3; repeat = 5; break; default: @@ -158,19 +194,19 @@ uchar usbFunctionWrite(uchar *data, uchar len) wait = 200; switch (data[1]) { case 1: - cmd = ENER_ADDR | 0xe; + cmd = serno | 0xe; repeat = 5; break; case 2: - cmd = ENER_ADDR | 0x6; + cmd = serno | 0x6; repeat = 5; break; case 3: - cmd = ENER_ADDR | 0xa; + cmd = serno | 0xa; repeat = 5; break; case 4: - cmd = ENER_ADDR | 0x2; + cmd = serno | 0x2; repeat = 5; break; default: @@ -224,6 +260,8 @@ int __attribute__((noreturn)) main(void) wdt_enable(WDTO_1S); + fetch_serno(); + usbInit(); usbDeviceDisconnect(); diff --git a/usbconfig.h b/usbconfig.h index 656ddb8..5337edb 100644 --- a/usbconfig.h +++ b/usbconfig.h @@ -352,7 +352,7 @@ section at the end of this file). #define USB_CFG_DESCR_PROPS_STRING_0 0 #define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 #define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 -#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER (USB_PROP_IS_DYNAMIC | USB_PROP_IS_RAM) #define USB_CFG_DESCR_PROPS_HID 0 #define USB_CFG_DESCR_PROPS_HID_REPORT 0 #define USB_CFG_DESCR_PROPS_UNKNOWN 0 -- 2.39.5