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 objectsmain
| } setup_t; | } setup_t; | ||||
| // Device_t holds all the information about a USB device | // Device_t holds all the information about a USB device | ||||
| #define DEVICE_STRUCT_STRING_BUF_SIZE 48 | |||||
| struct Device_struct { | struct Device_struct { | ||||
| Pipe_t *control_pipe; | Pipe_t *control_pipe; | ||||
| Pipe_t *data_pipes; | Pipe_t *data_pipes; | ||||
| uint16_t idVendor; | uint16_t idVendor; | ||||
| uint16_t idProduct; | uint16_t idProduct; | ||||
| uint16_t LanguageID; | 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 | // Pipe_t holes all information about each USB endpoint/pipe | ||||
| static volatile bool enumeration_busy; | static volatile bool enumeration_busy; | ||||
| private: | private: | ||||
| static void isr(); | 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 void claim_drivers(Device_t *dev); | ||||
| static uint32_t assign_address(void); | static uint32_t assign_address(void); | ||||
| static bool queue_Transfer(Pipe_t *pipe, Transfer_t *transfer); | static bool queue_Transfer(Pipe_t *pipe, Transfer_t *transfer); | ||||
| operator bool() { return (device != nullptr); } | operator bool() { return (device != nullptr); } | ||||
| uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } | uint16_t idVendor() { return (device != nullptr) ? device->idVendor : 0; } | ||||
| uint16_t idProduct() { return (device != nullptr) ? device->idProduct : 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 | // TODO: user-level functions | ||||
| // check if device is bound/active/online | // check if device is bound/active/online | ||||
| // query vid, pid | // query vid, pid |
| dev->enum_state = 4; | dev->enum_state = 4; | ||||
| return; | return; | ||||
| case 4: // parse Language ID | 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) { | if (enumbuf[4] < 4 || enumbuf[5] != 3) { | ||||
| dev->enum_state = 11; | dev->enum_state = 11; | ||||
| } else { | } else { | ||||
| dev->enum_state = 6; | dev->enum_state = 6; | ||||
| return; | return; | ||||
| case 6: // parse Manufacturer string | case 6: // parse Manufacturer string | ||||
| convertStringDescriptorToASCIIString(0, dev, transfer); | |||||
| // TODO: receive the string... | // TODO: receive the string... | ||||
| if (enumbuf[1]) dev->enum_state = 7; | if (enumbuf[1]) dev->enum_state = 7; | ||||
| else if (enumbuf[2]) dev->enum_state = 9; | else if (enumbuf[2]) dev->enum_state = 9; | ||||
| dev->enum_state = 8; | dev->enum_state = 8; | ||||
| return; | return; | ||||
| case 8: // parse Product string | case 8: // parse Product string | ||||
| // TODO: receive the string... | |||||
| convertStringDescriptorToASCIIString(1, dev, transfer); | |||||
| if (enumbuf[2]) dev->enum_state = 9; | if (enumbuf[2]) dev->enum_state = 9; | ||||
| else dev->enum_state = 11; | else dev->enum_state = 11; | ||||
| break; | break; | ||||
| dev->enum_state = 10; | dev->enum_state = 10; | ||||
| return; | return; | ||||
| case 10: // parse Serial Number string | case 10: // parse Serial Number string | ||||
| // TODO: receive the string... | |||||
| convertStringDescriptorToASCIIString(2, dev, transfer); | |||||
| dev->enum_state = 11; | dev->enum_state = 11; | ||||
| break; | break; | ||||
| case 11: // request first 9 bytes of config desc | case 11: // request first 9 bytes of config desc | ||||
| } | } | ||||
| } | } | ||||
| 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) | void USBHost::claim_drivers(Device_t *dev) | ||||
| { | { | ||||
| USBDriver *driver, *prev=NULL; | USBDriver *driver, *prev=NULL; |
| Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); | Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); | ||||
| driver_active[i] = true; | 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); | |||||
| } | } | ||||
| } | } | ||||
| } | } |