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); | |||||
} | } | ||||
} | } | ||||
} | } |