]> the.earth.li Git - energenie-attiny.git/commitdiff
Use serial number as base address + report in USB descriptor
authorJonathan McDowell <noodles@earth.li>
Tue, 29 May 2018 07:31:26 +0000 (08:31 +0100)
committerJonathan McDowell <noodles@earth.li>
Tue, 29 May 2018 07:31:26 +0000 (08:31 +0100)
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
usbconfig.h

diff --git a/main.c b/main.c
index d5bf590ee49d42f92bc2c35bcfe9b9a0ccfdc5e7..5805cee2720064c13b1c4b1341444b93a7b0f448 100644 (file)
--- a/main.c
+++ b/main.c
 #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();
 
index 656ddb886ece1085b93acdf0a94b8f6f044e7bc6..5337edb0f3ccf0737daff9a651f65d1515087ef5 100644 (file)
@@ -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