Created
June 20, 2024 09:35
-
-
Save morgz/d9057d7bce6f3e00059929f2549d8b38 to your computer and use it in GitHub Desktop.
USB Desccription
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Adafruit_TinyUSB.h" | |
#include <SPI.h> | |
// Define your custom SPI pins | |
// UM Feather WORKING | |
// #define MY_MOSI_PIN 35 | |
// #define MY_MISO_PIN 37 | |
// #define MY_CLK_PIN 36 | |
// #define MY_CS_PIN 38 | |
// #define MY_INT_PIN 33 | |
// //ESP Dev Board WORKING | |
// #define MY_MOSI_PIN 35 | |
// #define MY_MISO_PIN 37 | |
// #define MY_CLK_PIN 36 | |
// #define MY_CS_PIN 38 | |
// #define MY_INT_PIN 39 | |
//ESP Dev Board OUR PINS - WORKING on DEV BOARD. NOT WORKING ON PCB | |
#define MY_MOSI_PIN 7 | |
#define MY_MISO_PIN 15 | |
#define MY_CLK_PIN 6 | |
#define MY_CS_PIN 12 | |
#define MY_INT_PIN 13 | |
// SEED XIAO ESP32S3 | |
// #define MY_MOSI_PIN 9 | |
// #define MY_MISO_PIN 8 | |
// #define MY_CLK_PIN 7 | |
// #define MY_CS_PIN 44 | |
// #define MY_INT_PIN 4 | |
// USB Host using MAX3421E: SPI, CS, INT | |
Adafruit_USBH_Host USBHost(&SPI, MY_CS_PIN, MY_INT_PIN); | |
// Language ID: English | |
#define LANGUAGE_ID 0x0409 | |
typedef struct { | |
tusb_desc_device_t desc_device; | |
uint16_t manufacturer[32]; | |
uint16_t product[48]; | |
uint16_t serial[16]; | |
bool mounted; | |
} dev_info_t; | |
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 }; | |
//--------------------------------------------------------------------+ | |
// setup() & loop() | |
//--------------------------------------------------------------------+ | |
void setup() { | |
Serial.begin(115200); | |
while(!Serial); | |
pinMode(10, OUTPUT); | |
digitalWrite(10, LOW); | |
pinMode(11, OUTPUT); | |
digitalWrite(11, HIGH); | |
pinMode(46, OUTPUT); //RST PIN | |
digitalWrite(46, HIGH); | |
// Initialize SPI | |
SPI.begin(MY_CLK_PIN, MY_MISO_PIN, MY_MOSI_PIN); | |
// Init host stack on controller (rhport) 1 | |
USBHost.begin(1); | |
Serial.println("TinyUSB Dual: Device Info Example with MAX3421E"); | |
} | |
void loop() { | |
USBHost.task(); | |
Serial.flush(); | |
} | |
//--------------------------------------------------------------------+ | |
// TinyUSB Host callbacks | |
//--------------------------------------------------------------------+ | |
void print_device_descriptor(tuh_xfer_t *xfer); | |
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len); | |
void print_lsusb(void) { | |
bool no_device = true; | |
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) { | |
dev_info_t *dev = &dev_info[daddr - 1]; | |
if (dev->mounted) { | |
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr, | |
dev->desc_device.idVendor, dev->desc_device.idProduct, | |
(char *) dev->manufacturer, (char *) dev->product); | |
no_device = false; | |
} | |
} | |
if (no_device) { | |
Serial.println("No device connected (except hub)"); | |
} | |
} | |
// Invoked when device is mounted (configured) | |
void tuh_mount_cb(uint8_t daddr) { | |
Serial.printf("Device attached, address = %d\r\n", daddr); | |
dev_info_t *dev = &dev_info[daddr - 1]; | |
dev->mounted = true; | |
// Get Device Descriptor | |
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0); | |
} | |
/// Invoked when device is unmounted (bus reset/unplugged) | |
void tuh_umount_cb(uint8_t daddr) { | |
Serial.printf("Device removed, address = %d\r\n", daddr); | |
dev_info_t *dev = &dev_info[daddr - 1]; | |
dev->mounted = false; | |
// print device summary | |
print_lsusb(); | |
} | |
void print_device_descriptor(tuh_xfer_t *xfer) { | |
if (XFER_RESULT_SUCCESS != xfer->result) { | |
Serial.printf("Failed to get device descriptor\r\n"); | |
return; | |
} | |
uint8_t const daddr = xfer->daddr; | |
dev_info_t *dev = &dev_info[daddr - 1]; | |
tusb_desc_device_t *desc = &dev->desc_device; | |
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct); | |
Serial.printf("Device Descriptor:\r\n"); | |
Serial.printf(" bLength %u\r\n" , desc->bLength); | |
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType); | |
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB); | |
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass); | |
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass); | |
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol); | |
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0); | |
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor); | |
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct); | |
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice); | |
// Get String descriptor using Sync API | |
Serial.printf(" iManufacturer %u ", desc->iManufacturer); | |
if (XFER_RESULT_SUCCESS == | |
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) { | |
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer)); | |
Serial.printf((char *) dev->manufacturer); | |
} | |
Serial.printf("\r\n"); | |
Serial.printf(" iProduct %u ", desc->iProduct); | |
if (XFER_RESULT_SUCCESS == | |
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) { | |
utf16_to_utf8(dev->product, sizeof(dev->product)); | |
Serial.printf((char *) dev->product); | |
} | |
Serial.printf("\r\n"); | |
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber); | |
if (XFER_RESULT_SUCCESS == | |
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) { | |
utf16_to_utf8(dev->serial, sizeof(dev->serial)); | |
Serial.printf((char *) dev->serial); | |
} | |
Serial.printf("\r\n"); | |
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations); | |
// print device summary | |
print_lsusb(); | |
} | |
//--------------------------------------------------------------------+ | |
// String Descriptor Helper | |
//--------------------------------------------------------------------+ | |
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) { | |
// TODO: Check for runover. | |
(void) utf8_len; | |
// Get the UTF-16 length out of the data itself. | |
for (size_t i = 0; i < utf16_len; i++) { | |
uint16_t chr = utf16[i]; | |
if (chr < 0x80) { | |
*utf8++ = chr & 0xff; | |
} else if (chr < 0x800) { | |
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F)); | |
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F)); | |
} else { | |
// TODO: Verify surrogate. | |
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F)); | |
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F)); | |
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F)); | |
} | |
// TODO: Handle UTF-16 code points that take two entries. | |
} | |
} | |
// Count how many bytes a utf-16-le encoded string will take in utf-8. | |
static int _count_utf8_bytes(const uint16_t *buf, size_t len) { | |
size_t total_bytes = 0; | |
for (size_t i = 0; i < len; i++) { | |
uint16_t chr = buf[i]; | |
if (chr < 0x80) { | |
total_bytes += 1; | |
} else if (chr < 0x800) { | |
total_bytes += 2; | |
} else { | |
total_bytes += 3; | |
} | |
// TODO: Handle UTF-16 code points that take two entries. | |
} | |
return total_bytes; | |
} | |
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) { | |
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t); | |
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len); | |
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len); | |
((uint8_t *) temp_buf)[utf8_len] = '\0'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment