Skip to content

Commit 89ffd9d

Browse files
authored
Merge pull request #353 from adafruit/suport-pico-host-native
support rp2040 native usb host configuration
2 parents 58698b0 + b276e9e commit 89ffd9d

File tree

7 files changed

+314
-27
lines changed

7 files changed

+314
-27
lines changed

.github/workflows/githubci.yml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ jobs:
1616
python-version: '3.x'
1717

1818
- name: Checkout code
19-
uses: actions/checkout@v3
19+
uses: actions/checkout@v4
2020

2121
- name: Run pre-commit
2222
uses: pre-commit/[email protected]
2323

2424
- name: Checkout adafruit/ci-arduino
25-
uses: actions/checkout@v3
25+
uses: actions/checkout@v4
2626
with:
2727
repository: adafruit/ci-arduino
2828
path: ci
@@ -46,17 +46,15 @@ jobs:
4646
fail-fast: false
4747
matrix:
4848
arduino-platform:
49-
# ESP32S3
50-
- 'feather_esp32s3'
51-
# ESP32S2
49+
# ESP32
5250
- 'feather_esp32s2'
51+
- 'feather_esp32s3'
5352
# nRF52
5453
- 'cpb'
5554
- 'nrf52840'
5655
# RP2040
5756
- 'feather_rp2040_tinyusb'
5857
# SAMD
59-
- 'feather_m4_can_tinyusb'
6058
- 'metro_m0_tinyusb'
6159
- 'metro_m4_tinyusb'
6260

@@ -67,10 +65,10 @@ jobs:
6765
python-version: '3.x'
6866

6967
- name: Checkout code
70-
uses: actions/checkout@v3
68+
uses: actions/checkout@v4
7169

7270
- name: Checkout adafruit/ci-arduino
73-
uses: actions/checkout@v3
71+
uses: actions/checkout@v4
7472
with:
7573
repository: adafruit/ci-arduino
7674
path: ci

examples/Host/Simple/host_device_info/.none.test.only

Whitespace-only changes.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
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+
/* This example demonstrates use of native controller as host (TinyUSB Host)
13+
* Note:
14+
* - For most mcu with only 1 native usb, Serial is not available. We will use Serial1 instead
15+
*
16+
* Host example will get device descriptors of attached devices and print it out as follows:
17+
Device 1: ID 046d:c52f
18+
Device Descriptor:
19+
bLength 18
20+
bDescriptorType 1
21+
bcdUSB 0200
22+
bDeviceClass 0
23+
bDeviceSubClass 0
24+
bDeviceProtocol 0
25+
bMaxPacketSize0 8
26+
idVendor 0x046d
27+
idProduct 0xc52f
28+
bcdDevice 2200
29+
iManufacturer 1 Logitech
30+
iProduct 2 USB Receiver
31+
iSerialNumber 0
32+
bNumConfigurations 1
33+
*
34+
*/
35+
36+
#include "Adafruit_TinyUSB.h"
37+
38+
#ifndef USE_TINYUSB_HOST
39+
#error This example requires usb stack configured as host in "Tools -> USB Stack -> Adafruit TinyUSB Host"
40+
#endif
41+
42+
// Language ID: English
43+
#define LANGUAGE_ID 0x0409
44+
45+
typedef struct {
46+
tusb_desc_device_t desc_device;
47+
uint16_t manufacturer[32];
48+
uint16_t product[48];
49+
uint16_t serial[16];
50+
bool mounted;
51+
} dev_info_t;
52+
53+
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
54+
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
55+
56+
Adafruit_USBH_Host USBHost;
57+
58+
void setup() {
59+
Serial1.begin(115200);
60+
Serial1.println("TinyUSB Host: Device Info Example");
61+
62+
// Init USB Host on native controller roothub port0
63+
USBHost.begin(0);
64+
}
65+
66+
//------------- Core0 -------------//
67+
void loop() {
68+
USBHost.task();
69+
Serial1.flush();
70+
}
71+
72+
//--------------------------------------------------------------------+
73+
// TinyUSB Host callbacks
74+
//--------------------------------------------------------------------+
75+
void print_device_descriptor(tuh_xfer_t *xfer);
76+
77+
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
78+
79+
void print_lsusb(void) {
80+
bool no_device = true;
81+
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
82+
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
83+
// use local connected flag instead
84+
dev_info_t *dev = &dev_info[daddr - 1];
85+
if (dev->mounted) {
86+
Serial1.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
87+
dev->desc_device.idVendor, dev->desc_device.idProduct,
88+
(char *) dev->manufacturer, (char *) dev->product);
89+
90+
no_device = false;
91+
}
92+
}
93+
94+
if (no_device) {
95+
Serial1.println("No device connected (except hub)");
96+
}
97+
}
98+
99+
// Invoked when device is mounted (configured)
100+
void tuh_mount_cb(uint8_t daddr) {
101+
Serial1.printf("Device attached, address = %d\r\n", daddr);
102+
103+
dev_info_t *dev = &dev_info[daddr - 1];
104+
dev->mounted = true;
105+
106+
// Get Device Descriptor
107+
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
108+
}
109+
110+
/// Invoked when device is unmounted (bus reset/unplugged)
111+
void tuh_umount_cb(uint8_t daddr) {
112+
Serial1.printf("Device removed, address = %d\r\n", daddr);
113+
dev_info_t *dev = &dev_info[daddr - 1];
114+
dev->mounted = false;
115+
116+
// print device summary
117+
print_lsusb();
118+
}
119+
120+
void print_device_descriptor(tuh_xfer_t *xfer) {
121+
if (XFER_RESULT_SUCCESS != xfer->result) {
122+
Serial1.printf("Failed to get device descriptor\r\n");
123+
return;
124+
}
125+
126+
uint8_t const daddr = xfer->daddr;
127+
dev_info_t *dev = &dev_info[daddr - 1];
128+
tusb_desc_device_t *desc = &dev->desc_device;
129+
130+
Serial1.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
131+
Serial1.printf("Device Descriptor:\r\n");
132+
Serial1.printf(" bLength %u\r\n" , desc->bLength);
133+
Serial1.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
134+
Serial1.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
135+
Serial1.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
136+
Serial1.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
137+
Serial1.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
138+
Serial1.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
139+
Serial1.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
140+
Serial1.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
141+
Serial1.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
142+
143+
// Get String descriptor using Sync API
144+
Serial1.printf(" iManufacturer %u ", desc->iManufacturer);
145+
if (XFER_RESULT_SUCCESS ==
146+
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
147+
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
148+
Serial1.printf((char *) dev->manufacturer);
149+
}
150+
Serial1.printf("\r\n");
151+
152+
Serial1.printf(" iProduct %u ", desc->iProduct);
153+
if (XFER_RESULT_SUCCESS ==
154+
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
155+
utf16_to_utf8(dev->product, sizeof(dev->product));
156+
Serial1.printf((char *) dev->product);
157+
}
158+
Serial1.printf("\r\n");
159+
160+
Serial1.printf(" iSerialNumber %u ", desc->iSerialNumber);
161+
if (XFER_RESULT_SUCCESS ==
162+
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
163+
utf16_to_utf8(dev->serial, sizeof(dev->serial));
164+
Serial1.printf((char *) dev->serial);
165+
}
166+
Serial1.printf("\r\n");
167+
168+
Serial1.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
169+
170+
// print device summary
171+
print_lsusb();
172+
}
173+
174+
//--------------------------------------------------------------------+
175+
// String Descriptor Helper
176+
//--------------------------------------------------------------------+
177+
178+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
179+
// TODO: Check for runover.
180+
(void) utf8_len;
181+
// Get the UTF-16 length out of the data itself.
182+
183+
for (size_t i = 0; i < utf16_len; i++) {
184+
uint16_t chr = utf16[i];
185+
if (chr < 0x80) {
186+
*utf8++ = chr & 0xff;
187+
} else if (chr < 0x800) {
188+
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
189+
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
190+
} else {
191+
// TODO: Verify surrogate.
192+
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
193+
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
194+
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
195+
}
196+
// TODO: Handle UTF-16 code points that take two entries.
197+
}
198+
}
199+
200+
// Count how many bytes a utf-16-le encoded string will take in utf-8.
201+
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
202+
size_t total_bytes = 0;
203+
for (size_t i = 0; i < len; i++) {
204+
uint16_t chr = buf[i];
205+
if (chr < 0x80) {
206+
total_bytes += 1;
207+
} else if (chr < 0x800) {
208+
total_bytes += 2;
209+
} else {
210+
total_bytes += 3;
211+
}
212+
// TODO: Handle UTF-16 code points that take two entries.
213+
}
214+
return total_bytes;
215+
}
216+
217+
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
218+
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
219+
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
220+
221+
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
222+
((uint8_t *) temp_buf)[utf8_len] = '\0';
223+
}

src/arduino/Adafruit_USBD_CDC.cpp

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424

2525
#include "tusb_option.h"
2626

27-
#if CFG_TUD_ENABLED && CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32)
27+
// esp32 use built-in core cdc
28+
#if CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32)
2829

2930
#include "Arduino.h"
3031

@@ -37,19 +38,16 @@
3738
#define TINYUSB_API_VERSION 0
3839
#endif
3940

40-
// Starting endpoints; adjusted elsewhere as needed
41-
#define EPOUT 0x00
42-
#define EPIN 0x80
43-
4441
// SerialTinyUSB can be macro expanding to "Serial" on supported cores
4542
Adafruit_USBD_CDC SerialTinyUSB;
4643

47-
//------------- Static member -------------//
4844
uint8_t Adafruit_USBD_CDC::_instance_count = 0;
45+
Adafruit_USBD_CDC::Adafruit_USBD_CDC(void) { _instance = INVALID_INSTANCE; }
4946

50-
uint8_t Adafruit_USBD_CDC::getInstanceCount(void) { return _instance_count; }
47+
#if CFG_TUD_ENABLED
5148

52-
Adafruit_USBD_CDC::Adafruit_USBD_CDC(void) { _instance = INVALID_INSTANCE; }
49+
#define EPOUT 0x00
50+
#define EPIN 0x80
5351

5452
uint16_t Adafruit_USBD_CDC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
5553
uint16_t bufsize) {
@@ -265,4 +263,60 @@ void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
265263
}
266264
}
267265

266+
#else
267+
268+
// Device stack is not enabled (probably in host mode)
269+
#warning "NO_USB selected. No output to Serial will occur!"
270+
271+
uint16_t Adafruit_USBD_CDC::getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
272+
uint16_t bufsize) {
273+
(void)itfnum;
274+
(void)buf;
275+
(void)bufsize;
276+
277+
return 0;
278+
}
279+
280+
// Baud and config is ignore in CDC
281+
void Adafruit_USBD_CDC::begin(uint32_t baud) { (void)baud; }
282+
283+
void Adafruit_USBD_CDC::begin(uint32_t baud, uint8_t config) { (void)config; }
284+
285+
void Adafruit_USBD_CDC::end(void) {}
286+
287+
uint32_t Adafruit_USBD_CDC::baud(void) { return 0; }
288+
289+
uint8_t Adafruit_USBD_CDC::stopbits(void) { return 0; }
290+
291+
uint8_t Adafruit_USBD_CDC::paritytype(void) { return 0; }
292+
293+
uint8_t Adafruit_USBD_CDC::numbits(void) { return 0; }
294+
295+
int Adafruit_USBD_CDC::dtr(void) { return 0; }
296+
297+
Adafruit_USBD_CDC::operator bool() { return false; }
298+
299+
int Adafruit_USBD_CDC::available(void) { return 0; }
300+
301+
int Adafruit_USBD_CDC::peek(void) { return -1; }
302+
303+
int Adafruit_USBD_CDC::read(void) { return -1; }
304+
305+
size_t Adafruit_USBD_CDC::read(uint8_t *buffer, size_t size) {
306+
(void)buffer;
307+
(void)size;
308+
return 0;
309+
}
310+
311+
void Adafruit_USBD_CDC::flush(void) {}
312+
313+
size_t Adafruit_USBD_CDC::write(uint8_t ch) { return -1; }
314+
315+
size_t Adafruit_USBD_CDC::write(const uint8_t *buffer, size_t size) {
316+
return 0;
317+
}
318+
319+
int Adafruit_USBD_CDC::availableForWrite(void) { return 0; }
320+
268321
#endif // CFG_TUD_ENABLED
322+
#endif // CDC + ESP32

src/arduino/Adafruit_USBD_CDC.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface {
4343
public:
4444
Adafruit_USBD_CDC(void);
4545

46-
static uint8_t getInstanceCount(void);
46+
static uint8_t getInstanceCount(void) { return _instance_count; }
4747

4848
// from Adafruit_USBD_Interface
4949
virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,

0 commit comments

Comments
 (0)