From 40cb6322acbb957d8c153baa5c780cb09445dda5 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 14 Oct 2017 14:27:09 -0700 Subject: [PATCH] WIP - Add Strings to device structure Added the ability to query the Manufactur, product name and serial number strings from a device. WIP - Eats up lots of memory, next up experiment move from Device_t object to maybe top level objects. Probably fewer than them as each hub allocates something like 7 Device objects --- USBHost_t36.h | 9 +++++++++ enumeration.cpp | 36 ++++++++++++++++++++++++++++++++++-- examples/Mouse/Mouse.ino | 6 ++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/USBHost_t36.h b/USBHost_t36.h index c3ec10b..d459c00 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -141,6 +141,7 @@ typedef union { } setup_t; // Device_t holds all the information about a USB device +#define DEVICE_STRUCT_STRING_BUF_SIZE 48 struct Device_struct { Pipe_t *control_pipe; Pipe_t *data_pipes; @@ -159,6 +160,8 @@ struct Device_struct { uint16_t idVendor; uint16_t idProduct; uint16_t LanguageID; + uint8_t string_buf[DEVICE_STRUCT_STRING_BUF_SIZE]; // Probably want a place to allocate fewer of these... + uint8_t iStrings[3]; // 3 indexes - vendor string, product string, serial number. }; // Pipe_t holes all information about each USB endpoint/pipe @@ -248,6 +251,7 @@ protected: static volatile bool enumeration_busy; private: static void isr(); + static void convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer); static void claim_drivers(Device_t *dev); static uint32_t assign_address(void); static bool queue_Transfer(Pipe_t *pipe, Transfer_t *transfer); @@ -350,6 +354,11 @@ public: operator bool() { return (device != nullptr); } uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 0; } + + const uint8_t *manufacturer() { return (device != nullptr) ? &(device->string_buf[device->iStrings[0]]) : nullptr; } + const uint8_t *product() { return (device != nullptr) ? &(device->string_buf[device->iStrings[1]]) : nullptr; } + const uint8_t *serialNumber() { return (device != nullptr) ? &(device->string_buf[device->iStrings[2]]) : nullptr; } + // TODO: user-level functions // check if device is bound/active/online // query vid, pid diff --git a/enumeration.cpp b/enumeration.cpp index 268bf39..4c8be2e 100644 --- a/enumeration.cpp +++ b/enumeration.cpp @@ -201,6 +201,10 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 4; return; case 4: // parse Language ID + dev->iStrings[0] = 0; // Set indexes into string buffer to say not there... + dev->iStrings[1] = 0; + dev->iStrings[2] = 0; + dev->string_buf[0] = 0; // have trailing NULL.. if (enumbuf[4] < 4 || enumbuf[5] != 3) { dev->enum_state = 11; } else { @@ -218,6 +222,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 6; return; case 6: // parse Manufacturer string + convertStringDescriptorToASCIIString(0, dev, transfer); // TODO: receive the string... if (enumbuf[1]) dev->enum_state = 7; else if (enumbuf[2]) dev->enum_state = 9; @@ -230,7 +235,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 8; return; case 8: // parse Product string - // TODO: receive the string... + convertStringDescriptorToASCIIString(1, dev, transfer); if (enumbuf[2]) dev->enum_state = 9; else dev->enum_state = 11; break; @@ -241,7 +246,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 10; return; case 10: // parse Serial Number string - // TODO: receive the string... + convertStringDescriptorToASCIIString(2, dev, transfer); dev->enum_state = 11; break; case 11: // request first 9 bytes of config desc @@ -286,6 +291,33 @@ void USBHost::enumeration(const Transfer_t *transfer) } } +void USBHost::convertStringDescriptorToASCIIString(uint8_t string_index, Device_t *dev, const Transfer_t *transfer) { + uint8_t *buffer = (uint8_t*)transfer->buffer; + uint8_t buf_index = string_index? dev->iStrings[string_index]+1 : 0; + + // Try to verify - The first byte should be length and the 2nd byte should be 0x3 + if (!buffer || (buffer[1] != 0x3)) { + return; // No string so can simply return + } + + dev->iStrings[string_index] = buf_index; // remember our starting positio + uint8_t count_bytes_returned = buffer[0]; + if ((buf_index + count_bytes_returned/2) >= DEVICE_STRUCT_STRING_BUF_SIZE) + count_bytes_returned = (DEVICE_STRUCT_STRING_BUF_SIZE - buf_index) * 2; + + // Now copy into our storage buffer. + for (uint8_t i = 2; (i < count_bytes_returned) && (buf_index < (DEVICE_STRUCT_STRING_BUF_SIZE -1)); i += 2) { + dev->string_buf[buf_index++] = buffer[i]; + } + dev->string_buf[buf_index] = 0; // null terminate. + + // Update other indexes to point to null character + while (++string_index < 3) { + dev->iStrings[string_index] = buf_index; // point to trailing NULL character + } +} + + void USBHost::claim_drivers(Device_t *dev) { USBDriver *driver, *prev=NULL; diff --git a/examples/Mouse/Mouse.ino b/examples/Mouse/Mouse.ino index 328bffc..0bbe298 100644 --- a/examples/Mouse/Mouse.ino +++ b/examples/Mouse/Mouse.ino @@ -49,6 +49,12 @@ void loop() Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); driver_active[i] = true; + const uint8_t *psz = drivers[i]->manufacturer(); + if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); + psz = drivers[i]->product(); + if (psz && *psz) Serial.printf(" product: %s\n", psz); + psz = drivers[i]->serialNumber(); + if (psz && *psz) Serial.printf(" Serial: %s\n", psz); } } }