Skip to content

Commit

Permalink
device info works with samd21 + max3421e
Browse files Browse the repository at this point in the history
not too reliable probably due to tinyusb stack core issue: USBH Defer
Attach until current enumeration complete
  • Loading branch information
hathach committed Sep 14, 2023
1 parent 70605b7 commit 898c62f
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 45 deletions.
73 changes: 37 additions & 36 deletions examples/DualRole/Simple/device_info/device_info.ino
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
bNumConfigurations 1
*
*/

#ifdef ARDUINO_ARCH_RP2040
// pio-usb is required for rp2040 host
#include "pio_usb.h"
Expand All @@ -63,6 +62,7 @@
#include "Adafruit_TinyUSB.h"

#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421

#include "SPI.h"

// USB Host object using MAX3421E: SPI, CS, INT
Expand All @@ -86,18 +86,20 @@ typedef struct {
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };

#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421

void setup() {
Serial.begin(115200);
//while ( !Serial ) delay(10); // wait for native usb

Serial.println("TinyUSB Dual Device Info Example");

// run host stack on controller (rhport) 1
// init host stack on controller (rhport) 1
USBHost.begin(1);

while ( !Serial ) delay(10); // wait for native usb
Serial.println("TinyUSB Dual Device Info Example");
}

void loop() {
USBHost.task();
Serial.flush();
}

#elif defined(ARDUINO_ARCH_RP2040)
Expand Down Expand Up @@ -171,19 +173,20 @@ void loop1() {
//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
void print_device_descriptor(tuh_xfer_t* xfer);
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++ ) {
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
// use local connected flag instead
dev_info_t* dev = &dev_info[daddr-1];
if ( dev->mounted ) {
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);
(char *) dev->manufacturer, (char *) dev->product);

no_device = false;
}
Expand All @@ -195,39 +198,35 @@ void print_lsusb(void) {
}

// Invoked when device is mounted (configured)
void tuh_mount_cb (uint8_t daddr)
{
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_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)
{
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_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 )
{
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;
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");
Expand All @@ -244,23 +243,26 @@ void print_device_descriptor(tuh_xfer_t* xfer)

// 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)) ) {
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((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))) {
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((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))) {
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((char *) dev->serial);
}
Serial.printf("\r\n");

Expand All @@ -276,21 +278,21 @@ void print_device_descriptor(tuh_xfer_t* xfer)

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;
(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));
*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));
*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.
}
Expand Down Expand Up @@ -318,6 +320,5 @@ void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
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';
((uint8_t *) temp_buf)[utf8_len] = '\0';
}

3 changes: 1 addition & 2 deletions examples/MassStorage/msc_ramdisk/msc_ramdisk.ino
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Adafruit_USBD_MSC usb_msc;


// the setup function runs once when you press reset or power the board
void setup()
{
void setup() {
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
// Manual begin() is required on core without built-in support for TinyUSB such as
// - mbed rp2040
Expand Down
14 changes: 14 additions & 0 deletions src/arduino/Adafruit_TinyUSB_API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,34 @@ void TinyUSB_Device_FlushCDC(void) {

// Debug log with Serial1
#if CFG_TUSB_DEBUG && defined(CFG_TUSB_DEBUG_PRINTF)
// #define USE_SEGGER_RTT

#ifdef USE_SEGGER_RTT
#include "SEGGER_RTT/RTT/SEGGER_RTT.h"
#endif

__attribute__((used)) int CFG_TUSB_DEBUG_PRINTF(const char *__restrict format,
...) {
#ifndef USE_SEGGER_RTT
static bool ser1_inited = false;
if (!ser1_inited) {
ser1_inited = true;
Serial1.begin(115200);
}
#endif

char buf[256];
int len;
va_list ap;
va_start(ap, format);
len = vsnprintf(buf, sizeof(buf), format, ap);

#ifdef USE_SEGGER_RTT
SEGGER_RTT_Write(0, buf, len);
#else
Serial1.write(buf);
#endif

va_end(ap);
return len;
}
Expand Down
28 changes: 28 additions & 0 deletions src/arduino/Adafruit_USBH_Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,34 @@ bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const *tx_buf,
return false;
}

Adafruit_USBH_Host *host = Adafruit_USBH_Host::_instance;

// MAX3421e max clock is 26MHz
// Depending on mcu ports, it may need to be clipped down
// uint32_t max_clock = 26000000ul;
uint32_t max_clock = 4000000ul;

SPISettings config(max_clock, MSBFIRST, SPI_MODE0);
host->_spi->beginTransaction(config);

size_t count = 0;
while (count < tx_len || count < rx_len) {
uint8_t data = 0x00;

if (count < tx_len) {
data = tx_buf[count];
}

data = host->_spi->transfer(data);

if (count < rx_len) {
rx_buf[count] = data;
}

count++;
}

host->_spi->endTransaction();
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/arduino/Adafruit_USBH_Host.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
#define ADAFRUIT_USBH_HOST_H_

#include "Adafruit_USBD_Interface.h"
#include "SPI.h"
#include "tusb.h"
#include <SPI.h>

#ifdef ARDUINO_ARCH_ESP32
#include "esp32-hal-tinyusb.h"
Expand Down
7 changes: 2 additions & 5 deletions src/arduino/ports/samd/Adafruit_TinyUSB_samd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,8 @@ void TinyUSB_Port_InitDevice(uint8_t rhport) {
NVIC_SetPriority((IRQn_Type)USB_IRQn, 0UL);
#endif

#if CFG_TUSB_DEBUG
Serial1.begin(115200);
#endif

tusb_init();
// Init port 0 as device
tud_init(0);
}

void TinyUSB_Port_EnterDFU(void) {
Expand Down
43 changes: 43 additions & 0 deletions src/arduino/ports/samd/tusb_config_samd.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,49 @@ extern "C" {
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
#define CFG_TUD_VENDOR_TX_BUFSIZE 64

//--------------------------------------------------------------------
// Host Configuration
//--------------------------------------------------------------------

// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256

// Number of hub devices
#define CFG_TUH_HUB 1

// max device support (excluding hub device): 1 hub typically has 4 ports
#define CFG_TUH_DEVICE_MAX (3 * CFG_TUH_HUB + 1)

// Enable tuh_edpt_xfer() API
// #define CFG_TUH_API_EDPT_XFER 1

// Number of mass storage
#define CFG_TUH_MSC 1

// Number of HIDs
// typical keyboard + mouse device can have 3,4 HID interfaces
#define CFG_TUH_HID (3 * CFG_TUH_DEVICE_MAX)

// Number of CDC interfaces
// FTDI and CP210x are not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC 1
#define CFG_TUH_CDC_FTDI 1
#define CFG_TUH_CDC_CP210X 1

// RX & TX fifo size
#define CFG_TUH_CDC_RX_BUFSIZE 64
#define CFG_TUH_CDC_TX_BUFSIZE 64

// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03

// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
// This need Pico-PIO-USB at least 0.5.1
#define CFG_TUH_CDC_LINE_CODING_ON_ENUM \
{ 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/portable/analog/max3421/hcd_max3421.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is

max3421_spi_lock(rhport, in_isr);

tuh_max3421_spi_xfer_api(rhport, &reg, 1, &hirq, 0);
tuh_max3421_spi_xfer_api(rhport, &reg, 1, &hirq, 1);
_hcd_data.hirq = hirq;
tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len);

Expand Down

0 comments on commit 898c62f

Please sign in to comment.