Skip to content

Commit 31f1edc

Browse files
committed
add specific example for max3421e: device_info_max3421e
1 parent 6905192 commit 31f1edc

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
13+
/* This example demonstrates use of both device and host, where
14+
* - Device run on native usb controller (roothub port0)
15+
* - Host run on MAX3421E controller (roothub port1) tested with:
16+
* - SAMD21, SAMD51, nRF52840, ESP32S2, ESP32S3, ESP32
17+
* - RP2040: "pio_usb.h" must not be included, otherwise pio-usb will be used as host controller
18+
*
19+
* Requirements:
20+
* - SPI instance, CS pin, INT pin are correctly configured
21+
*/
22+
23+
/* Host example will get device descriptors of attached devices and print it out via
24+
* device cdc (Serial) as follows:
25+
* Device 1: ID 046d:c52f
26+
Device Descriptor:
27+
bLength 18
28+
bDescriptorType 1
29+
bcdUSB 0200
30+
bDeviceClass 0
31+
bDeviceSubClass 0
32+
bDeviceProtocol 0
33+
bMaxPacketSize0 8
34+
idVendor 0x046d
35+
idProduct 0xc52f
36+
bcdDevice 2200
37+
iManufacturer 1 Logitech
38+
iProduct 2 USB Receiver
39+
iSerialNumber 0
40+
bNumConfigurations 1
41+
*
42+
*/
43+
#include "Adafruit_TinyUSB.h"
44+
45+
// USBHost is defined in usbh_helper.h
46+
// USB Host using MAX3421E: SPI, CS, INT
47+
#include "SPI.h"
48+
49+
#if defined(ARDUINO_METRO_ESP32S2)
50+
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
51+
52+
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
53+
Adafruit_USBH_Host USBHost(&SPI, 27, 33);
54+
55+
#else
56+
57+
// Default CS and INT are pin 10, 9
58+
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
59+
#endif
60+
61+
// Language ID: English
62+
#define LANGUAGE_ID 0x0409
63+
64+
typedef struct {
65+
tusb_desc_device_t desc_device;
66+
uint16_t manufacturer[32];
67+
uint16_t product[48];
68+
uint16_t serial[16];
69+
bool mounted;
70+
} dev_info_t;
71+
72+
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
73+
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
74+
75+
void setup() {
76+
Serial.begin(115200);
77+
78+
// init host stack on controller (rhport) 1
79+
// For rp2040: this is called in core1's setup1()
80+
USBHost.begin(1);
81+
82+
// while ( !Serial ) delay(10); // wait for native usb
83+
Serial.println("TinyUSB Dual: Device Info Example with MAX3421E");
84+
}
85+
86+
void loop() {
87+
USBHost.task();
88+
Serial.flush();
89+
}
90+
91+
//--------------------------------------------------------------------+
92+
// TinyUSB Host callbacks
93+
//--------------------------------------------------------------------+
94+
void print_device_descriptor(tuh_xfer_t *xfer);
95+
96+
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
97+
98+
void print_lsusb(void) {
99+
bool no_device = true;
100+
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
101+
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
102+
// use local connected flag instead
103+
dev_info_t *dev = &dev_info[daddr - 1];
104+
if (dev->mounted) {
105+
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
106+
dev->desc_device.idVendor, dev->desc_device.idProduct,
107+
(char *) dev->manufacturer, (char *) dev->product);
108+
109+
no_device = false;
110+
}
111+
}
112+
113+
if (no_device) {
114+
Serial.println("No device connected (except hub)");
115+
}
116+
}
117+
118+
// Invoked when device is mounted (configured)
119+
void tuh_mount_cb(uint8_t daddr) {
120+
Serial.printf("Device attached, address = %d\r\n", daddr);
121+
122+
dev_info_t *dev = &dev_info[daddr - 1];
123+
dev->mounted = true;
124+
125+
// Get Device Descriptor
126+
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
127+
}
128+
129+
/// Invoked when device is unmounted (bus reset/unplugged)
130+
void tuh_umount_cb(uint8_t daddr) {
131+
Serial.printf("Device removed, address = %d\r\n", daddr);
132+
dev_info_t *dev = &dev_info[daddr - 1];
133+
dev->mounted = false;
134+
135+
// print device summary
136+
print_lsusb();
137+
}
138+
139+
void print_device_descriptor(tuh_xfer_t *xfer) {
140+
if (XFER_RESULT_SUCCESS != xfer->result) {
141+
Serial.printf("Failed to get device descriptor\r\n");
142+
return;
143+
}
144+
145+
uint8_t const daddr = xfer->daddr;
146+
dev_info_t *dev = &dev_info[daddr - 1];
147+
tusb_desc_device_t *desc = &dev->desc_device;
148+
149+
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
150+
Serial.printf("Device Descriptor:\r\n");
151+
Serial.printf(" bLength %u\r\n" , desc->bLength);
152+
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
153+
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
154+
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
155+
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
156+
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
157+
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
158+
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
159+
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
160+
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
161+
162+
// Get String descriptor using Sync API
163+
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
164+
if (XFER_RESULT_SUCCESS ==
165+
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
166+
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
167+
Serial.printf((char *) dev->manufacturer);
168+
}
169+
Serial.printf("\r\n");
170+
171+
Serial.printf(" iProduct %u ", desc->iProduct);
172+
if (XFER_RESULT_SUCCESS ==
173+
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
174+
utf16_to_utf8(dev->product, sizeof(dev->product));
175+
Serial.printf((char *) dev->product);
176+
}
177+
Serial.printf("\r\n");
178+
179+
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
180+
if (XFER_RESULT_SUCCESS ==
181+
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
182+
utf16_to_utf8(dev->serial, sizeof(dev->serial));
183+
Serial.printf((char *) dev->serial);
184+
}
185+
Serial.printf("\r\n");
186+
187+
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
188+
189+
// print device summary
190+
print_lsusb();
191+
}
192+
193+
//--------------------------------------------------------------------+
194+
// String Descriptor Helper
195+
//--------------------------------------------------------------------+
196+
197+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
198+
// TODO: Check for runover.
199+
(void) utf8_len;
200+
// Get the UTF-16 length out of the data itself.
201+
202+
for (size_t i = 0; i < utf16_len; i++) {
203+
uint16_t chr = utf16[i];
204+
if (chr < 0x80) {
205+
*utf8++ = chr & 0xff;
206+
} else if (chr < 0x800) {
207+
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
208+
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
209+
} else {
210+
// TODO: Verify surrogate.
211+
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
212+
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
213+
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
214+
}
215+
// TODO: Handle UTF-16 code points that take two entries.
216+
}
217+
}
218+
219+
// Count how many bytes a utf-16-le encoded string will take in utf-8.
220+
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
221+
size_t total_bytes = 0;
222+
for (size_t i = 0; i < len; i++) {
223+
uint16_t chr = buf[i];
224+
if (chr < 0x80) {
225+
total_bytes += 1;
226+
} else if (chr < 0x800) {
227+
total_bytes += 2;
228+
} else {
229+
total_bytes += 3;
230+
}
231+
// TODO: Handle UTF-16 code points that take two entries.
232+
}
233+
return total_bytes;
234+
}
235+
236+
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
237+
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
238+
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
239+
240+
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
241+
((uint8_t *) temp_buf)[utf8_len] = '\0';
242+
}

0 commit comments

Comments
 (0)