From 966584363546023d85f4d8b748b18ace63ea1c57 Mon Sep 17 00:00:00 2001 From: Alexander Mueller Date: Tue, 29 Aug 2023 18:16:50 +0200 Subject: [PATCH 01/41] Fix the weak dcd_edpt0_status_complete for Keil Compiler The Keil compiler seems to have different semantics and the defined function was never called. The same is probably true for the other weak functions. I can change those too. --- src/device/dcd.h | 2 +- src/device/usbd_control.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/device/dcd.h b/src/device/dcd.h index 18a708347..b1984fda3 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -155,7 +155,7 @@ void dcd_sof_enable(uint8_t rhport, bool en); // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request); // Configure endpoint's registers according to descriptor bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 76d062e40..a6081060e 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -135,6 +135,15 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo // USBD API //--------------------------------------------------------------------+ +TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) +{ + (void)rhport; + (void)request; + + // this is the default implementation that is called when no "real" implementation + // of the function exists +} + void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); @@ -173,7 +182,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result TU_ASSERT(0 == xferred_bytes); // invoke optional dcd hook if available - if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); + dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); if (_ctrl_xfer.complete_cb) { From c2bbcc9f60a2b7293fad4e24468d3f045fde28ee Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 26 Dec 2023 20:14:03 +0100 Subject: [PATCH 02/41] initial support of CH34x CDC device --- examples/host/cdc_msc_hid/src/tusb_config.h | 1 + .../cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 466 +++++++++++++++++- src/class/cdc/serial/ch34x.h | 113 +++++ src/tusb_option.h | 17 + 5 files changed, 595 insertions(+), 3 deletions(-) create mode 100644 src/class/cdc/serial/ch34x.h diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 61abb85eb..76d59c316 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -105,6 +105,7 @@ #define CFG_TUH_CDC 1 // CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index c661f47be..bb7c3388d 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -110,6 +110,7 @@ #define CFG_TUH_CDC 1 // CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a6dfb45ae..9b5186e0c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2023 Heiko Kuester (CH34x support) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -69,7 +70,16 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - + #if CFG_TUH_CDC_CH34X + struct { + uint32_t baud_rate; + uint8_t mcr; + uint8_t msr; + uint8_t lcr; + uint32_t quirks; + uint8_t version; + } ch34x; + #endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -121,6 +131,23 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif +//------------- CH34x prototypes -------------// +#if CFG_TUH_CDC_CH34X +#include "serial/ch34x.h" + +static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; +enum { + CH34X_VID_PID_COUNT = sizeof ( ch34x_vids_pids ) / sizeof ( ch34x_vids_pids[0] ) +}; + +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); +static void ch34x_process_config ( tuh_xfer_t* xfer ); + +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +#endif + + enum { SERIAL_DRIVER_ACM = 0, @@ -131,6 +158,10 @@ enum { #if CFG_TUH_CDC_CP210X SERIAL_DRIVER_CP210X, #endif + +#if CFG_TUH_CDC_CH34X + SERIAL_DRIVER_CH34X, +#endif }; typedef struct { @@ -159,6 +190,13 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_baudrate = cp210x_set_baudrate }, #endif + + #if CFG_TUH_CDC_CH34X + { .process_set_config = ch34x_process_config, + .set_control_line_state = ch34x_set_modem_ctrl, + .set_baudrate = ch34x_set_baudrate + }, +#endif }; enum { @@ -426,6 +464,12 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) break; #endif + #if CFG_TUH_CDC_CH34X + case SERIAL_DRIVER_CH34X: + TU_ASSERT(false, ); // see special ch34x_control_complete function + break; + #endif + default: break; } } @@ -641,7 +685,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d { return acm_open(daddr, itf_desc, max_len); } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X else if ( 0xff == itf_desc->bInterfaceClass ) { uint16_t vid, pid; @@ -666,8 +710,16 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } } #endif + + #if CFG_TUH_CDC_CH34X + for (size_t i = 0; i < CH34X_VID_PID_COUNT; i++) { + if ( ch34x_vids_pids[i][0] == vid && ch34x_vids_pids[i][1] == pid ) { + return ch34x_open(daddr, itf_desc, max_len); + } + } + #endif } - #endif + #endif // CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X return false; } @@ -1176,4 +1228,412 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #endif +//--------------------------------------------------------------------+ +// CH34x +//--------------------------------------------------------------------+ + +#if CFG_TUH_CDC_CH34X + +enum { + CONFIG_CH34X_STEP1 = 0, + CONFIG_CH34X_STEP2, + CONFIG_CH34X_STEP3, + CONFIG_CH34X_STEP4, + CONFIG_CH34X_STEP5, + CONFIG_CH34X_STEP6, + CONFIG_CH34X_STEP7, + CONFIG_CH34X_STEP8, + CONFIG_CH34X_COMPLETE +}; + +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) +{ + // CH34x Interface includes 1 vendor interface + 3 bulk endpoints + TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); + TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); + + cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); + TU_VERIFY ( p_cdc ); + + TU_LOG_DRV ( "CH34x opened\r\n" ); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); + + // data endpoints expected to be in pairs + return open_ep_stream_pair ( p_cdc, desc_ep ); +} + +static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + tusb_control_request_t const request_setup = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_VENDOR, + .direction = direction + }, + .bRequest = request, + .wValue = tu_htole16 ( value ), + .wIndex = tu_htole16 ( index ), + .wLength = tu_htole16 ( length ) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t* enum_buf = NULL; + + if ( buffer && length > 0 ) { + enum_buf = usbh_get_enum_buf(); + tu_memcpy_s ( enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length ); + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request_setup, + .buffer = enum_buf, + .complete_cb = complete_cb, + // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber + .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + }; + + return tuh_control_xfer ( &xfer ); + return false; +} + +static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); +} + +static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); +} + +static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); +} + +static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +} + +/* + * The device line speed is given by the following equation: + * + * baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where + * + * 0 <= ps <= 3, + * 0 <= fact <= 1, + * 2 <= div <= 256 if fact = 0, or + * 9 <= div <= 256 if fact = 1 + */ +// calculate baudrate devisors +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) +{ + uint32_t fact, div, clk_div; + bool force_fact0 = false; + int32_t ps; + static const uint32_t ch341_min_rates[] = { + CH341_MIN_RATE(0), + CH341_MIN_RATE(1), + CH341_MIN_RATE(2), + CH341_MIN_RATE(3), + }; + + /* + * Clamp to supported range, this makes the (ps < 0) and (div < 2) + * sanity checks below redundant. + */ + inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } + inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } + inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } + speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); + + /* + * Start with highest possible base clock (fact = 1) that will give a + * divisor strictly less than 512. + */ + fact = 1; + for (ps = 3; ps >= 0; ps--) { + if (speed > ch341_min_rates[ps]) + break; + } + + if (ps < 0) + return -EINVAL; + + /* Determine corresponding divisor, rounding down. */ + clk_div = CH341_CLK_DIV(ps, fact); + div = CH341_CLKRATE / (clk_div * speed); + + /* Some devices require a lower base clock if ps < 3. */ + if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) + force_fact0 = true; + + /* Halve base clock (fact = 0) if required. */ + if (div < 9 || div > 255 || force_fact0) { + div /= 2; + clk_div *= 2; + fact = 0; + } + + if (div < 2) + return -EINVAL; + + /* + * Pick next divisor if resulting rate is closer to the requested one, + * scale up to avoid rounding errors on low rates. + */ + if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= + 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) + div++; + + /* + * Prefer lower base clock (fact = 0) if even divisor. + * + * Note that this makes the receiver more tolerant to errors. + */ + if (fact == 1 && div % 2 == 0) { + div /= 2; + fact = 0; + } + + return (0x100 - div) << 8 | fact << 2 | ps; +} + +// set baudrate (low level) +// do not confuse with ch34x_set_baudrate +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + int val; + + if (!baud_rate) + return -EINVAL; + + val = ch341_get_divisor(p_cdc, baud_rate); + if (val < 0) + return -EINVAL; + + /* + * CH341A buffers data until a full endpoint-size packet (32 bytes) + * has been received unless bit 7 is set. + * + * At least one device with version 0x27 appears to have this bit + * inverted. + */ + if ( p_cdc->ch34x.version > 0x27 ) + val |= BIT(7); + + return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); +} + +// set lcr register +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * Chip versions before version 0x30 as read using + * CH341_REQ_READ_VERSION used separate registers for line control + * (stop bits, parity and word length). Version 0x30 and above use + * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. + */ + if ( p_cdc->ch34x.version < 0x30 ) + return 0; + + return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); +} + +// set handshake (modem controls) +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); +} + +// detect quirks (special versions of CH34x) +// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c +static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * A subset of CH34x devices does not support all features. The + * prescaler is limited and there is no support for sending a RS232 + * break condition. A read failure when trying to set up the latter is + * used to detect these devices. + */ + switch ( step ) + { + case 1: + p_cdc->ch34x.quirks = 0; + return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); + break; + case 2: + if ( xfer->result != XFER_RESULT_SUCCESS ) + p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; + return true; + break; + default: + TU_ASSERT ( false ); // suspicious step + break; + } +} + +// internal control complete to update state such as line state, encoding +// CH34x needs a special interface recovery due to abnormal wIndex usage +static void ch34x_control_complete(tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + TU_ASSERT ( p_cdc, ); + TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x + + if (xfer->result == XFER_RESULT_SUCCESS) { + switch (xfer->setup->bRequest) { + case CH341_REQ_WRITE_REG: { // register write request + switch ( tu_le16toh ( xfer->setup->wValue ) ) { + case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + break; + } + default: { + TU_ASSERT(false, ); // unexpected register write + break; + } + } + break; + } + default: { + TU_ASSERT(false, ); // unexpected request + break; + } + } + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) + xfer->complete_cb(xfer); + } +} + +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate +{ + TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); + uint32_t baud_le = tu_htole32(baudrate); + p_cdc->ch34x.baud_rate = baudrate; + p_cdc->user_control_cb = complete_cb; + return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); +} + +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); + // todo later + return false; +} + +static void ch34x_process_config ( tuh_xfer_t* xfer ) +{ + uintptr_t const state = xfer->user_data & 0xff; + // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber + uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + uint8_t buffer [ CH34X_BUFFER_SIZE ]; + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT ( p_cdc, ); + + if ( state == 0 ) { + // defaults + p_cdc->ch34x.baud_rate = DEFAULT_BAUD_RATE; + p_cdc->ch34x.mcr = 0; + p_cdc->ch34x.msr = 0; + p_cdc->ch34x.quirks = 0; + p_cdc->ch34x.version = 0; + /* + * Some CH340 devices appear unable to change the initial LCR + * settings, so set a sane 8N1 default. + */ + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; + } + // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c + switch ( state ) { + case CONFIG_CH34X_STEP1: // request version read + TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); + break; + case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x + p_cdc->ch34x.version = xfer->buffer[0]; + TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); + TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); + break; + case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) + TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); + break; + case CONFIG_CH34X_STEP4: // set line controls with default values (see above) + TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); + break; + case CONFIG_CH34X_STEP5: // set handshake RTS/DTR + TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); + break; + case CONFIG_CH34X_STEP6: // detect quirks step 1 + TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); + break; + case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values + TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); +#else + TU_ATTR_FALLTHROUGH; #endif + break; + case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + switch ( line_coding.data_bits ) { + case 5: + p_cdc->ch34x.lcr |= CH341_LCR_CS5; + break; + case 6: + p_cdc->ch34x.lcr |= CH341_LCR_CS6; + break; + case 7: + p_cdc->ch34x.lcr |= CH341_LCR_CS7; + break; + case 8: + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + default: + TU_ASSERT ( false, ); // not supported data_bits + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + } + if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { + p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) + p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) + p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + } + TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits + if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) + p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; + TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); +#else + TU_ATTR_FALLTHROUGH; +#endif + break; + case CONFIG_CH34X_COMPLETE: + set_config_complete ( p_cdc, idx, itf_num ); + break; + default: + TU_ASSERT ( false, ); + break; + } +} + +#endif // CFG_TUH_CDC_CH34X + +#endif // (CFG_TUH_ENABLED && CFG_TUH_CDC) diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h new file mode 100644 index 000000000..94e18b252 --- /dev/null +++ b/src/class/cdc/serial/ch34x.h @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _CH34X_H_ +#define _CH34X_H_ + +#include + +#define BIT(nr) ( (uint32_t)1 << (nr) ) + +#define CH34X_BUFFER_SIZE 2 + +// The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c + +#define DEFAULT_BAUD_RATE 9600 + +/* flags for IO-Bits */ +#define CH341_BIT_RTS (1 << 6) +#define CH341_BIT_DTR (1 << 5) + +/******************************/ +/* interrupt pipe definitions */ +/******************************/ +/* always 4 interrupt bytes */ +/* first irq byte normally 0x08 */ +/* second irq byte base 0x7d + below */ +/* third irq byte base 0x94 + below */ +/* fourth irq byte normally 0xee */ + +/* second interrupt byte */ +#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ + +/* status returned in third interrupt answer byte, inverted in data + from irq */ +#define CH341_BIT_CTS 0x01 +#define CH341_BIT_DSR 0x02 +#define CH341_BIT_RI 0x04 +#define CH341_BIT_DCD 0x08 +#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ + +/* Break support - the information used to implement this was gleaned from + * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. + */ + +// USB requests +#define CH341_REQ_READ_VERSION 0x5F // dec 95 +#define CH341_REQ_WRITE_REG 0x9A +#define CH341_REQ_READ_REG 0x95 +#define CH341_REQ_SERIAL_INIT 0xA1 +#define CH341_REQ_MODEM_CTRL 0xA4 + +// CH34x registers +#define CH341_REG_BREAK 0x05 +#define CH341_REG_PRESCALER 0x12 +#define CH341_REG_DIVISOR 0x13 +#define CH341_REG_LCR 0x18 +#define CH341_REG_LCR2 0x25 + +#define CH341_NBREAK_BITS 0x01 + +// line control bits +#define CH341_LCR_ENABLE_RX 0x80 +#define CH341_LCR_ENABLE_TX 0x40 +#define CH341_LCR_MARK_SPACE 0x20 +#define CH341_LCR_PAR_EVEN 0x10 +#define CH341_LCR_ENABLE_PAR 0x08 +#define CH341_LCR_STOP_BITS_2 0x04 +#define CH341_LCR_CS8 0x03 +#define CH341_LCR_CS7 0x02 +#define CH341_LCR_CS6 0x01 +#define CH341_LCR_CS5 0x00 + +#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) +#define CH341_QUIRK_SIMULATE_BREAK BIT(1) + +#define CH341_CLKRATE 48000000 +#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) +#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) + +/* Supported range is 46 to 3000000 bps. */ +#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) +#define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) + +#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP +#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +// error codes +#define EINVAL 22 /* Invalid argument */ + +#endif /* _CH34X_H_ */ diff --git a/src/tusb_option.h b/src/tusb_option.h index a76281c0c..13151a07b 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -470,6 +470,23 @@ 0xEA60, 0xEA70 #endif +#ifndef CFG_TUH_CDC_CH34X + // CH34X is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_CH34X 0 +#endif + +#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST + // List of product IDs that can use the CH34X CDC driver + #define CFG_TUH_CDC_CH34X_VID_PID_LIST \ + { 0x1a86, 0x7523 }, /* ch340 chip */ \ + { 0x1a86, 0x7522 }, /* ch340k chip */ \ + { 0x1a86, 0x5523 }, /* ch341 chip */ \ + { 0x1a86, 0xe523 }, /* ch330 chip */ \ + { 0x4348, 0x5523 }, /* ch340 custom chip */ \ + { 0x2184, 0x0057 }, /* overtaken from Linux driver /drivers/usb/serial/ch341.c */ \ + { 0x9986, 0x7523 } /* overtaken from Linux driver /drivers/usb/serial/ch341.c */ +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif From a4aa454a7a21c022569eccfea493b8a96d182d9c Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 7 Jan 2024 08:25:31 +1030 Subject: [PATCH 03/41] [HUB] Fix double status xfer --- src/host/hub.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index 32f5e0ac7..3bac18698 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -435,9 +435,12 @@ static void hub_port_get_status_complete (tuh_xfer_t* xfer) // Other changes are: L1 state // TODO clear change - // prepare for next hub status - // TODO continue with status_change, or maybe we can do it again with status - hub_edpt_status_xfer(daddr); + else + { + // prepare for next hub status + // TODO continue with status_change, or maybe we can do it again with status + hub_edpt_status_xfer(daddr); + } } } From d39d06e6d920aadc9e479d4dfb8620dd3871cb98 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 9 Jan 2024 16:22:54 +1030 Subject: [PATCH 04/41] [HUB] Prevent status request to invalid ep_num --- src/host/usbh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 4d30d9f81..53e8a654b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -456,7 +456,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { #if CFG_TUH_HUB // TODO remove - if ( event.connection.hub_addr != 0) { + if ( event.connection.hub_addr != 0 && event.connection.hub_port != 0) { // done with hub, waiting for next data on status pipe (void) hub_edpt_status_xfer( event.connection.hub_addr ); } From 91f65a36bfb1d4516c39306e77fb15d4e1c2fc0b Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 9 Jan 2024 09:53:54 +0100 Subject: [PATCH 05/41] [CDC] host: moved acm_open to other acm prototypes --- src/class/cdc/cdc_host.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a6dfb45ae..b20da3723 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -80,6 +80,7 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; //--------------------------------------------------------------------+ //------------- ACM prototypes -------------// +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -605,8 +606,6 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); - static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) { for(size_t i=0; i<2; i++) From 0d4b24e56cf11e79b46f88f0d8b8656c0444a149 Mon Sep 17 00:00:00 2001 From: Okarss <104319900+Okarss@users.noreply.github.com> Date: Sun, 7 Jan 2024 20:18:33 +0200 Subject: [PATCH 06/41] [STM32 FSDEV] Fix ISR race conditions --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 21cd3da26..5f7944d1f 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -673,13 +673,13 @@ void dcd_int_handler(uint8_t rhport) { /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ if(int_status & USB_ISTR_SOF) { - USB->ISTR &=~USB_ISTR_SOF; + USB->ISTR = ~USB_ISTR_SOF; dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); } if(int_status & USB_ISTR_RESET) { // USBRST is start of reset. - USB->ISTR &=~USB_ISTR_RESET; + USB->ISTR = ~USB_ISTR_RESET; dcd_handle_bus_reset(); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? @@ -697,7 +697,7 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR &= ~USB_CNTR_LPMODE; USB->CNTR &= ~USB_CNTR_FSUSP; - USB->ISTR &=~USB_ISTR_WKUP; + USB->ISTR = ~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -711,7 +711,7 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB->ISTR &=~USB_ISTR_SUSP; + USB->ISTR = ~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } @@ -724,7 +724,7 @@ void dcd_int_handler(uint8_t rhport) { { remoteWakeCountdown--; } - USB->ISTR &=~USB_ISTR_ESOF; + USB->ISTR = ~USB_ISTR_ESOF; } } From e7e19f562765999ed76b25b93649e80d9652b088 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 7 Jan 2024 08:30:33 +1030 Subject: [PATCH 07/41] [OHCI] Allow more than 16 devices --- src/portable/ohci/ohci.c | 16 +++++++++++++--- src/portable/ohci/ohci.h | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index f978b0965..c7f4c04ad 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -157,6 +157,7 @@ static ohci_ed_t * const p_ed_head[] = static void ed_list_insert(ohci_ed_t * p_pre, ohci_ed_t * p_ed); static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr); +static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd); //--------------------------------------------------------------------+ // USBH-HCD API @@ -345,7 +346,7 @@ static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes) tu_memclr(p_td, sizeof(ohci_gtd_t)); p_td->used = 1; - p_td->expected_bytes = total_bytes; + gtd_get_extra_data(p_td)->expected_bytes = total_bytes; p_td->buffer_rounding = 1; // less than queued length is not a error p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO; @@ -610,6 +611,16 @@ static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd) } } +static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd) { + if ( gtd_is_control(gtd) ) + { + return &ohci_data.control[((intptr_t)gtd - (intptr_t)&ohci_data.control->gtd) / sizeof(ohci_data.control[0])].gtd_data; + }else + { + return &ohci_data.gtd_data[gtd - ohci_data.gtd_pool]; + } +} + static inline uint32_t gtd_xfer_byte_left(uint32_t buffer_end, uint32_t current_buffer) { // 5.2.9 OHCI sample code @@ -641,8 +652,7 @@ static void done_queue_isr(uint8_t hostid) if ( (qtd->delay_interrupt == OHCI_INT_ON_COMPLETE_YES) || (event != XFER_RESULT_SUCCESS) ) { ohci_ed_t * const ed = gtd_get_ed(qtd); - - uint32_t const xferred_bytes = qtd->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer); + uint32_t const xferred_bytes = gtd_get_extra_data(qtd)->expected_bytes - gtd_xfer_byte_left((uint32_t) qtd->buffer_end, (uint32_t) qtd->current_buffer_pointer); // NOTE Assuming the current list is BULK and there is no other EDs in the list has queued TDs. // When there is a error resulting this ED is halted, and this EP still has other queued TD diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 2081ffabb..cb23396bc 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -45,6 +45,9 @@ enum { #define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX) #define GTD_MAX ED_MAX +// tinyUSB's OHCI implementation caps number of EDs to 8 bits +TU_VERIFY_STATIC (ED_MAX <= 256, "Reduce CFG_TUH_DEVICE_MAX or CFG_TUH_ENDPOINT_MAX"); + //--------------------------------------------------------------------+ // OHCI Data Structure //--------------------------------------------------------------------+ @@ -70,9 +73,8 @@ typedef struct TU_ATTR_ALIGNED(16) { // Word 0 uint32_t used : 1; - uint32_t index : 4; // endpoint index the td belongs to, or device address in case of control xfer - uint32_t expected_bytes : 13; // TODO available for hcd - + uint32_t index : 8; // endpoint index the gtd belongs to, or device address in case of control xfer + uint32_t : 9; // can be used uint32_t buffer_rounding : 1; uint32_t pid : 2; uint32_t delay_interrupt : 3; @@ -152,6 +154,12 @@ typedef struct TU_ATTR_ALIGNED(32) TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" ); +typedef struct +{ + uint16_t expected_bytes : 13; // can be up to 8192 bytes long so use 13 bits + uint16_t : 3; // can be used +} gtd_extra_data_t; + // structure with member alignment required from large to small typedef struct TU_ATTR_ALIGNED(256) { @@ -164,11 +172,13 @@ typedef struct TU_ATTR_ALIGNED(256) struct { ohci_ed_t ed; ohci_gtd_t gtd; + gtd_extra_data_t gtd_data; }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1]; // ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 ohci_ed_t ed_pool[ED_MAX]; ohci_gtd_t gtd_pool[GTD_MAX]; + gtd_extra_data_t gtd_data[GTD_MAX]; // extra data needed by TDs that can't fit in the TD struct volatile uint16_t frame_number_hi; From 3bf6826451536f1afc6eb4e7f088ac65d9b8c707 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Wed, 10 Jan 2024 10:27:21 +0100 Subject: [PATCH 08/41] Disable ULPI clock during sleep on stm32f7 when using internal phy --- src/portable/synopsys/dwc2/dwc2_stm32.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index dd78ccd06..3237a50f6 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -149,7 +149,7 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { // https://community.st.com/t5/stm32cubemx-mcus/why-stm32h743-usb-fs-doesn-t-work-if-freertos-tickless-idle/m-p/349480#M18867 // H7 running on full-speed phy need to disable ULPI clock in sleep mode. // Otherwise, USB won't work when mcu executing WFI/WFE instruction i.e tick-less RTOS. - // Note: there may be other family that is affected by this, but only H7 is tested so far + // Note: there may be other family that is affected by this, but only H7 and F7 is tested so far #if defined(USB_OTG_FS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB2OTGFSULPILPEN) if ( USB_OTG_FS_PERIPH_BASE == (uint32_t) dwc2 ) { RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB2OTGFSULPILPEN; @@ -161,6 +161,13 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB1OTGHSULPILPEN; } #endif + + #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_OTGHSULPILPEN) + if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) { + RCC->AHB1LPENR &= ~RCC_AHB1LPENR_OTGHSULPILPEN; + } + #endif + } else { #if CFG_TUSB_MCU != OPT_MCU_STM32U5 // Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable' From 545821399b10243f84509a543ae8c6457e9da803 Mon Sep 17 00:00:00 2001 From: Okarss <104319900+Okarss@users.noreply.github.com> Date: Thu, 11 Jan 2024 00:59:39 +0200 Subject: [PATCH 09/41] [STM32 FSDEV] Introduce a typedef for bus access width --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 10 +++++----- src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 5f7944d1f..91f90352e 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -673,13 +673,13 @@ void dcd_int_handler(uint8_t rhport) { /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ if(int_status & USB_ISTR_SOF) { - USB->ISTR = ~USB_ISTR_SOF; + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); } if(int_status & USB_ISTR_RESET) { // USBRST is start of reset. - USB->ISTR = ~USB_ISTR_RESET; + USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; dcd_handle_bus_reset(); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? @@ -697,7 +697,7 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR &= ~USB_CNTR_LPMODE; USB->CNTR &= ~USB_CNTR_FSUSP; - USB->ISTR = ~USB_ISTR_WKUP; + USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -711,7 +711,7 @@ void dcd_int_handler(uint8_t rhport) { USB->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB->ISTR = ~USB_ISTR_SUSP; + USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } @@ -724,7 +724,7 @@ void dcd_int_handler(uint8_t rhport) { { remoteWakeCountdown--; } - USB->ISTR = ~USB_ISTR_ESOF; + USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; } } diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h index b71e4f498..d28eb0d9a 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -173,8 +173,11 @@ // For type-safety create a new macro for the volatile address of PMAADDR // The compiler should warn us if we cast it to a non-volatile type? #ifdef PMA_32BIT_ACCESS +typedef uint32_t fsdev_bus_t; static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR; + #else +typedef uint16_t fsdev_bus_t; // Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; From c619a861414d2edeb34c5f59b74ed0fe28b39172 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 11 Jan 2024 08:53:47 +0100 Subject: [PATCH 10/41] bInterfaceClass number replaced by define --- src/class/cdc/cdc_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b20da3723..79477ef53 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -641,7 +641,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return acm_open(daddr, itf_desc, max_len); } #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X - else if ( 0xff == itf_desc->bInterfaceClass ) + else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); From 3349e402766cc82ce20b8cf3ff170ffc80fcf385 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 11 Jan 2024 16:52:18 +0700 Subject: [PATCH 11/41] add cmake support for lpc17 --- .github/workflows/build_arm.yml | 2 +- .github/workflows/cmake_arm.yml | 2 +- .idea/cmake.xml | 1 + hw/bsp/lpc17/FreeRTOSConfig/FreeRTOSConfig.h | 149 +++++++++++++ .../lpc17/boards/lpcxpresso1769/board.cmake | 11 + hw/bsp/lpc17/boards/lpcxpresso1769/board.h | 78 +++++++ .../boards/lpcxpresso1769/lpcxpresso1769.c | 209 ------------------ hw/bsp/lpc17/boards/mbed1768/board.cmake | 11 + hw/bsp/lpc17/boards/mbed1768/board.h | 71 ++++++ .../{boards/mbed1768/mbed1768.c => family.c} | 134 ++++------- hw/bsp/lpc17/family.cmake | 102 +++++++++ hw/bsp/lpc17/family.mk | 3 +- 12 files changed, 473 insertions(+), 300 deletions(-) create mode 100644 hw/bsp/lpc17/FreeRTOSConfig/FreeRTOSConfig.h create mode 100644 hw/bsp/lpc17/boards/lpcxpresso1769/board.cmake create mode 100644 hw/bsp/lpc17/boards/lpcxpresso1769/board.h delete mode 100644 hw/bsp/lpc17/boards/lpcxpresso1769/lpcxpresso1769.c create mode 100644 hw/bsp/lpc17/boards/mbed1768/board.cmake create mode 100644 hw/bsp/lpc17/boards/mbed1768/board.h rename hw/bsp/lpc17/{boards/mbed1768/mbed1768.c => family.c} (61%) create mode 100644 hw/bsp/lpc17/family.cmake diff --git a/.github/workflows/build_arm.yml b/.github/workflows/build_arm.yml index 47dea1925..4127db5bf 100644 --- a/.github/workflows/build_arm.yml +++ b/.github/workflows/build_arm.yml @@ -37,7 +37,7 @@ jobs: # Alphabetical order - 'broadcom_32bit' - 'kinetis_k32l2' - - 'lpc11 lpc13 lpc15 lpc17' + - 'lpc11 lpc13 lpc15' - 'lpc51' - 'mm32 msp432e4' - 'samd11 same5x saml2x' diff --git a/.github/workflows/cmake_arm.yml b/.github/workflows/cmake_arm.yml index 13120f96f..8b87fef21 100644 --- a/.github/workflows/cmake_arm.yml +++ b/.github/workflows/cmake_arm.yml @@ -37,7 +37,7 @@ jobs: # Alphabetical order - 'imxrt' - 'kinetis_kl' - - 'lpc18 lpc40 lpc43' + - 'lpc17 lpc18 lpc40 lpc43' - 'lpc54 lpc55' - 'mcx' - 'nrf' diff --git a/.idea/cmake.xml b/.idea/cmake.xml index d3917c1f7..432e44172 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -80,6 +80,7 @@ + \ No newline at end of file diff --git a/hw/bsp/lpc17/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/lpc17/FreeRTOSConfig/FreeRTOSConfig.h new file mode 100644 index 000000000..9b66fb110 --- /dev/null +++ b/hw/bsp/lpc17/FreeRTOSConfig/FreeRTOSConfig.h @@ -0,0 +1,149 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "chip.h" +#endif + +/* Cortex M23/M33 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 0 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS 3 + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<OTGClkCtrl = clk_en; - while ( (LPC_USB->OTGClkSt & clk_en) != clk_en ); - -#if CFG_TUH_ENABLED - // set portfunc to host !!! - LPC_USB->StCtrl = 0x3; // should be 1 -#endif -} - -//--------------------------------------------------------------------+ -// Board porting API -//--------------------------------------------------------------------+ - -void board_led_write(bool state) -{ - Chip_GPIO_SetPinState(LPC_GPIO, LED_PORT, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); -} - -uint32_t board_button_read(void) -{ - return BUTTON_STATE_ACTIVE == Chip_GPIO_GetPinState(LPC_GPIO, BUTTON_PORT, BUTTON_PIN); -} - -int board_uart_read(uint8_t* buf, int len) -{ -// return UART_ReceiveByte(BOARD_UART_PORT); - (void) buf; (void) len; - return 0; -} - -int board_uart_write(void const * buf, int len) -{ -// UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); - (void) buf; (void) len; - return 0; -} - -#if CFG_TUSB_OS == OPT_OS_NONE -volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ - system_ticks++; -} - -uint32_t board_millis(void) -{ - return system_ticks; -} -#endif diff --git a/hw/bsp/lpc17/boards/mbed1768/board.cmake b/hw/bsp/lpc17/boards/mbed1768/board.cmake new file mode 100644 index 000000000..688f34292 --- /dev/null +++ b/hw/bsp/lpc17/boards/mbed1768/board.cmake @@ -0,0 +1,11 @@ +set(MCU_VARIANT LPC1768) + +set(JLINK_DEVICE LPC1768) +set(PYOCD_TARGET LPC1768) +set(NXPLINK_DEVICE LPC1768:LPC1768) + +set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/lpc1768.ld) + +function(update_board TARGET) + # nothing to do +endfunction() diff --git a/hw/bsp/lpc17/boards/mbed1768/board.h b/hw/bsp/lpc17/boards/mbed1768/board.h new file mode 100644 index 000000000..2b3ddc905 --- /dev/null +++ b/hw/bsp/lpc17/boards/mbed1768/board.h @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define LED_PORT 1 +#define LED_PIN 18 +#define LED_STATE_ON 1 + +// JOYSTICK_DOWN if using LPCXpresso Base Board +#define BUTTON_PORT 0 +#define BUTTON_PIN 15 +#define BUTTON_STATE_ACTIVE 0 + +#define BOARD_UART_PORT LPC_UART3 + +/* System oscillator rate and RTC oscillator rate */ +const uint32_t OscRateIn = 10000000; +const uint32_t RTCOscRateIn = 32768; + +// Pin muxing configuration +static const PINMUX_GRP_T pinmuxing[] = { + {LED_PORT, LED_PIN, IOCON_MODE_INACT | IOCON_FUNC0}, + {BUTTON_PORT, BUTTON_PIN, IOCON_FUNC0 | IOCON_MODE_PULLUP}, +}; + +static const PINMUX_GRP_T pin_usb_mux[] = { + {0, 29, IOCON_MODE_INACT | IOCON_FUNC1}, // D+ + {0, 30, IOCON_MODE_INACT | IOCON_FUNC1}, // D- + {2, 9, IOCON_MODE_INACT | IOCON_FUNC1}, // Soft Connect + + {1, 19, IOCON_MODE_INACT | IOCON_FUNC2}, // USB_PPWR (Host mode) + {1, 22, IOCON_MODE_INACT | IOCON_FUNC2}, // USB_PWRD + + // VBUS is not connected on this board, so leave the pin at default setting. + // Chip_IOCON_PinMux(LPC_IOCON, 1, 30, IOCON_MODE_INACT, IOCON_FUNC2); // USB VBUS +}; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/hw/bsp/lpc17/boards/mbed1768/mbed1768.c b/hw/bsp/lpc17/family.c similarity index 61% rename from hw/bsp/lpc17/boards/mbed1768/mbed1768.c rename to hw/bsp/lpc17/family.c index 613dcb570..79281ba41 100644 --- a/hw/bsp/lpc17/boards/mbed1768/mbed1768.c +++ b/hw/bsp/lpc17/family.c @@ -26,58 +26,24 @@ #include "chip.h" #include "bsp/board_api.h" - -#define LED_PORT 1 -#define LED_PIN 18 -#define LED_STATE_ON 1 - -// JOYSTICK_DOWN if using LPCXpresso Base Board -#define BUTTON_PORT 0 -#define BUTTON_PIN 15 -#define BUTTON_STATE_ACTIVE 0 - -#define BOARD_UART_PORT LPC_UART3 - -/* System oscillator rate and RTC oscillator rate */ -const uint32_t OscRateIn = 10000000; -const uint32_t RTCOscRateIn = 32768; - -/* Pin muxing configuration */ -static const PINMUX_GRP_T pinmuxing[] = -{ - {LED_PORT, LED_PIN, IOCON_MODE_INACT | IOCON_FUNC0}, - {BUTTON_PORT, BUTTON_PIN, IOCON_FUNC0 | IOCON_MODE_PULLUP}, -}; - -static const PINMUX_GRP_T pin_usb_mux[] = -{ - {0, 29, IOCON_MODE_INACT | IOCON_FUNC1}, // D+ - {0, 30, IOCON_MODE_INACT | IOCON_FUNC1}, // D- - {2, 9, IOCON_MODE_INACT | IOCON_FUNC1}, // Connect - - {1, 19, IOCON_MODE_INACT | IOCON_FUNC2}, // USB_PPWR - {1, 22, IOCON_MODE_INACT | IOCON_FUNC2}, // USB_PWRD - - /* VBUS is not connected on this board, so leave the pin at default setting. */ - /*Chip_IOCON_PinMux(LPC_IOCON, 1, 30, IOCON_MODE_INACT, IOCON_FUNC2);*/ /* USB VBUS */ -}; +#include "board.h" // Invoked by startup code -void SystemInit(void) -{ +void SystemInit(void) { #ifdef __USE_LPCOPEN - extern void (* const g_pfnVectors[])(void); - unsigned int *pSCB_VTOR = (unsigned int *) 0xE000ED08; - *pSCB_VTOR = (unsigned int) g_pfnVectors; + extern void (* const g_pfnVectors[])(void); + unsigned int* pSCB_VTOR = (unsigned int*) 0xE000ED08; + *pSCB_VTOR = (unsigned int) g_pfnVectors; #endif Chip_IOCON_Init(LPC_IOCON); Chip_IOCON_SetPinMuxing(LPC_IOCON, pinmuxing, sizeof(pinmuxing) / sizeof(PINMUX_GRP_T)); Chip_SetupXtalClocking(); + + Chip_SYSCTL_SetFLASHAccess(FLASHTIM_100MHZ_CPU); } -void board_init(void) -{ +void board_init(void) { SystemCoreClockUpdate(); #if CFG_TUSB_OS == OPT_OS_NONE @@ -89,11 +55,7 @@ void board_init(void) #endif Chip_GPIO_Init(LPC_GPIO); - - // LED Chip_GPIO_SetPinDIROutput(LPC_GPIO, LED_PORT, LED_PIN); - - // Button Chip_GPIO_SetPinDIRInput(LPC_GPIO, BUTTON_PORT, BUTTON_PIN); #if 0 @@ -106,34 +68,34 @@ void board_init(void) .OpenDrain = 0, .Pinmode = 0 }; - PINSEL_ConfigPin(&PinCfg); + PINSEL_ConfigPin(&PinCfg); - PinCfg.Portnum = 0; - PinCfg.Pinnum = 1; // RXD is P0.1 - PINSEL_ConfigPin(&PinCfg); + PinCfg.Portnum = 0; + PinCfg.Pinnum = 1; // RXD is P0.1 + PINSEL_ConfigPin(&PinCfg); - UART_CFG_Type UARTConfigStruct; + UART_CFG_Type UARTConfigStruct; UART_ConfigStructInit(&UARTConfigStruct); - UARTConfigStruct.Baud_rate = CFG_BOARD_UART_BAUDRATE; + UARTConfigStruct.Baud_rate = CFG_BOARD_UART_BAUDRATE; - UART_Init(BOARD_UART_PORT, &UARTConfigStruct); - UART_TxCmd(BOARD_UART_PORT, ENABLE); // Enable UART Transmit + UART_Init(BOARD_UART_PORT, &UARTConfigStruct); + UART_TxCmd(BOARD_UART_PORT, ENABLE); // Enable UART Transmit #endif - //------------- USB -------------// + //------------- USB -------------// Chip_IOCON_SetPinMuxing(LPC_IOCON, pin_usb_mux, sizeof(pin_usb_mux) / sizeof(PINMUX_GRP_T)); - Chip_USB_Init(); + Chip_USB_Init(); enum { USBCLK_DEVCIE = 0x12, // AHB + Device - USBCLK_HOST = 0x19, // AHB + Host + OTG + USBCLK_HOST = 0x19, // AHB + Host + OTG // 0x1B // Host + Device + OTG + AHB }; uint32_t const clk_en = CFG_TUD_ENABLED ? USBCLK_DEVCIE : USBCLK_HOST; LPC_USB->OTGClkCtrl = clk_en; - while ( (LPC_USB->OTGClkSt & clk_en) != clk_en ); + while ((LPC_USB->OTGClkSt & clk_en) != clk_en) {} #if CFG_TUH_ENABLED // set portfunc to host !!! @@ -141,57 +103,53 @@ void board_init(void) #endif } -//--------------------------------------------------------------------+ -// USB Interrupt Handler -//--------------------------------------------------------------------+ -void USB_IRQHandler(void) -{ - #if CFG_TUD_ENABLED - tud_int_handler(0); - #endif - - #if CFG_TUH_ENABLED - tuh_int_handler(0, true); - #endif -} - //--------------------------------------------------------------------+ // Board porting API //--------------------------------------------------------------------+ - -void board_led_write(bool state) -{ - Chip_GPIO_SetPinState(LPC_GPIO, LED_PORT, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); +void board_led_write(bool state) { + Chip_GPIO_SetPinState(LPC_GPIO, LED_PORT, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); } -uint32_t board_button_read(void) -{ +uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == Chip_GPIO_GetPinState(LPC_GPIO, BUTTON_PORT, BUTTON_PIN); } -int board_uart_read(uint8_t* buf, int len) -{ +int board_uart_read(uint8_t* buf, int len) { // return UART_ReceiveByte(BOARD_UART_PORT); - (void) buf; (void) len; + (void) buf; + (void) len; return 0; } -int board_uart_write(void const * buf, int len) -{ +int board_uart_write(void const* buf, int len) { // UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); - (void) buf; (void) len; + (void) buf; + (void) len; return 0; } #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -void SysTick_Handler (void) -{ + +void SysTick_Handler(void) { system_ticks++; } -uint32_t board_millis(void) -{ +uint32_t board_millis(void) { return system_ticks; } + +//--------------------------------------------------------------------+ +// USB Interrupt Handler +//--------------------------------------------------------------------+ +void USB_IRQHandler(void) { + #if CFG_TUD_ENABLED + tud_int_handler(0); + #endif + + #if CFG_TUH_ENABLED + tuh_int_handler(0, true); + #endif +} + #endif diff --git a/hw/bsp/lpc17/family.cmake b/hw/bsp/lpc17/family.cmake new file mode 100644 index 000000000..63ac3149c --- /dev/null +++ b/hw/bsp/lpc17/family.cmake @@ -0,0 +1,102 @@ +include_guard() + +if (NOT BOARD) + message(FATAL_ERROR "BOARD not specified") +endif () + +set(SDK_DIR ${TOP}/hw/mcu/nxp/lpcopen/lpc175x_6x/lpc_chip_175x_6x) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR cortex-m3 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS LPC175X_6X CACHE INTERNAL "") + + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (NOT TARGET ${BOARD_TARGET}) + add_library(${BOARD_TARGET} STATIC + ${SDK_DIR}/../gcc/cr_startup_lpc175x_6x.c + ${SDK_DIR}/src/chip_17xx_40xx.c + ${SDK_DIR}/src/clock_17xx_40xx.c + ${SDK_DIR}/src/gpio_17xx_40xx.c + ${SDK_DIR}/src/iocon_17xx_40xx.c + ${SDK_DIR}/src/sysctl_17xx_40xx.c + ${SDK_DIR}/src/sysinit_17xx_40xx.c + ${SDK_DIR}/src/uart_17xx_40xx.c + ) + target_compile_options(${BOARD_TARGET} PUBLIC + -nostdlib + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + __USE_LPCOPEN + CORE_M3 + RTC_EV_SUPPORT=0 + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_DIR}/inc + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + # nanolib + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--config=${LD_FILE_IAR}" + ) + endif () + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_LPC175X_6X ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/nxp/lpc17_40/dcd_lpc17_40.c + ${TOP}/src/portable/nxp/lpc17_40/hcd_lpc17_40.c + ${TOP}/src/portable/ohci/ohci.c + ) + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_flash_jlink(${TARGET}) + #family_flash_nxplink(${TARGET}) +endfunction() diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk index 67d5e14b5..694b6cccf 100644 --- a/hw/bsp/lpc17/family.mk +++ b/hw/bsp/lpc17/family.mk @@ -34,4 +34,5 @@ SRC_C += \ $(MCU_DIR)/src/uart_17xx_40xx.c \ INC += \ - $(TOP)/$(MCU_DIR)/inc + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(MCU_DIR)/inc \ From e68c6658c954d0c5daed2952d500c230b7dfb30d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 11 Jan 2024 17:35:05 +0700 Subject: [PATCH 12/41] move gtd extra out of control struct to save sram also rename gtd_data to gtd_extra --- src/portable/ohci/ohci.c | 13 ++++++------- src/portable/ohci/ohci.h | 18 ++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index c7f4c04ad..c59d4755e 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -612,12 +612,11 @@ static inline ohci_ed_t* gtd_get_ed(ohci_gtd_t const * const p_qtd) } static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd) { - if ( gtd_is_control(gtd) ) - { - return &ohci_data.control[((intptr_t)gtd - (intptr_t)&ohci_data.control->gtd) / sizeof(ohci_data.control[0])].gtd_data; - }else - { - return &ohci_data.gtd_data[gtd - ohci_data.gtd_pool]; + if ( gtd_is_control(gtd) ) { + uint8_t idx = ((uintptr_t)gtd - (uintptr_t)&ohci_data.control->gtd) / sizeof(ohci_data.control[0]); + return &ohci_data.gtd_extra_control[idx]; + }else { + return &ohci_data.gtd_extra[gtd - ohci_data.gtd_pool]; } } @@ -661,7 +660,7 @@ static void done_queue_isr(uint8_t hostid) // --> HC will not process Control list (due to service ratio when Bulk list not empty) // To walk-around this, the halted ED will have TailP = HeadP (empty list condition), when clearing halt // the TailP must be set back to NULL for processing remaining TDs - if ((event != XFER_RESULT_SUCCESS)) + if (event != XFER_RESULT_SUCCESS) { ed->td_tail &= 0x0Ful; ed->td_tail |= tu_align16(ed->td_head.address); // mark halted EP as empty queue diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index cb23396bc..4feefd771 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -154,15 +154,12 @@ typedef struct TU_ATTR_ALIGNED(32) TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" ); -typedef struct -{ - uint16_t expected_bytes : 13; // can be up to 8192 bytes long so use 13 bits - uint16_t : 3; // can be used +typedef struct { + uint16_t expected_bytes; // up to 8192 bytes so max is 13 bits } gtd_extra_data_t; // structure with member alignment required from large to small -typedef struct TU_ATTR_ALIGNED(256) -{ +typedef struct TU_ATTR_ALIGNED(256) { ohci_hcca_t hcca; ohci_ed_t bulk_head_ed; // static bulk head (dummy) @@ -172,16 +169,17 @@ typedef struct TU_ATTR_ALIGNED(256) struct { ohci_ed_t ed; ohci_gtd_t gtd; - gtd_extra_data_t gtd_data; - }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1]; + } control[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB + 1]; // ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 ohci_ed_t ed_pool[ED_MAX]; ohci_gtd_t gtd_pool[GTD_MAX]; - gtd_extra_data_t gtd_data[GTD_MAX]; // extra data needed by TDs that can't fit in the TD struct + + // extra data needed by TDs that can't fit in the TD struct + gtd_extra_data_t gtd_extra_control[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB + 1]; + gtd_extra_data_t gtd_extra[GTD_MAX]; volatile uint16_t frame_number_hi; - } ohci_data_t; //--------------------------------------------------------------------+ From 2d3d14891251baedfc965810c650615bdee128cf Mon Sep 17 00:00:00 2001 From: Okarss <104319900+Okarss@users.noreply.github.com> Date: Thu, 11 Jan 2024 21:02:14 +0200 Subject: [PATCH 13/41] [STM32 FSDEV] Align names for consistency --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 30 ++++----- .../st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h | 65 ++++++++++--------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 91f90352e..9c37f1f98 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -128,8 +128,8 @@ # define DCD_STM32_BTABLE_BASE 0U #endif -#ifndef DCD_STM32_BTABLE_LENGTH -# define DCD_STM32_BTABLE_LENGTH (PMA_LENGTH - DCD_STM32_BTABLE_BASE) +#ifndef DCD_STM32_BTABLE_SIZE +# define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) #endif /*************************************************** @@ -137,7 +137,7 @@ */ TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware"); -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_LENGTH))<=(PMA_LENGTH), "BTABLE does not fit in PMA RAM"); +TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); //--------------------------------------------------------------------+ @@ -559,7 +559,7 @@ static void dcd_ep_ctr_rx_handler(uint32_t wIstr) // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) pcd_set_ep_rx_status(USB,0u,USB_EP_RX_NAK); pcd_set_ep_tx_status(USB,0u,USB_EP_TX_NAK); -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT dcd_event_setup_received(0, (uint8_t*)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true); #else // The setup_received function uses memcpy, so this must first copy the setup data into @@ -786,7 +786,7 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, uint16_t length) } // Ensure allocated buffer is aligned -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT length = (length + 3) & ~0x03; #else length = (length + 1) & ~0x01; @@ -798,7 +798,7 @@ static uint16_t dcd_pma_alloc(uint8_t ep_addr, uint16_t length) ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer // Verify no overflow - TU_ASSERT(ep_buf_ptr <= PMA_LENGTH, 0xFFFF); + TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF); epXferCtl->pma_ptr = addr; epXferCtl->pma_alloc_size = length; @@ -1227,7 +1227,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) } } -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) { const uint8_t* srcVal = src; @@ -1283,7 +1283,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui __IO uint16_t *pdwVal; srcVal = src; - pdwVal = &pma[PMA_STRIDE*(dst>>1)]; + pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)]; while (n--) { @@ -1291,7 +1291,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui srcVal++; temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)) ; *pdwVal = temp2; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; srcVal++; } @@ -1323,7 +1323,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit) -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT if((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part @@ -1386,7 +1386,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN return true; } -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) { uint8_t* dstVal = dst; @@ -1434,13 +1434,13 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t __IO const uint16_t *pdwVal; uint32_t temp; - pdwVal = &pma[PMA_STRIDE*(src>>1)]; + pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)]; uint8_t *dstVal = (uint8_t*)dst; while (n--) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); *dstVal++ = ((temp >> 8) & 0xFF); } @@ -1448,7 +1448,7 @@ static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t if (wNBytes & 0x01) { temp = *pdwVal; - pdwVal += PMA_STRIDE; + pdwVal += FSDEV_PMA_STRIDE; *dstVal++ = ((temp >> 0) & 0xFF); } return true; @@ -1475,7 +1475,7 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, // last lin byte will be combined with wrapped part // To ensure PMA is always access aligned (src aligned to 16 or 32 bit) -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT if((cnt_lin & 0x03) && cnt_wrap) { // Copy first linear part diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h index d28eb0d9a..3f4db985d 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h @@ -28,7 +28,7 @@ // This file contains source copied from ST's HAL, and thus should have their copyright statement. -// PMA_LENGTH is PMA buffer size in bytes. +// FSDEV_PMA_SIZE is PMA buffer size in bytes. // On 512-byte devices, access with a stride of two words (use every other 16-bit address) // On 1024-byte devices, access with a stride of one word (use every 16-bit address) @@ -37,7 +37,7 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // F0x2 models are crystal-less // All have internal D+ pull-up // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support @@ -45,7 +45,7 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1 #include "stm32f1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 2 x 16 bits/word @@ -56,7 +56,7 @@ defined(STM32F303xB) || defined(STM32F303xC) || \ defined(STM32F373xC) #include "stm32f3xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) // NO internal Pull-ups // *B, and *C: 1 x 16 bits/word // PMA dedicated to USB (no sharing with CAN) @@ -65,27 +65,27 @@ defined(STM32F302xD) || defined(STM32F302xE) || \ defined(STM32F303xD) || defined(STM32F303xE) #include "stm32f3xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) // NO internal Pull-ups // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support // When CAN clock is enabled, USB can use first 768 bytes ONLY. #elif CFG_TUSB_MCU == OPT_MCU_STM32L0 #include "stm32l0xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L1 #include "stm32l1xx.h" - #define PMA_LENGTH (512u) + #define FSDEV_PMA_SIZE (512u) #elif CFG_TUSB_MCU == OPT_MCU_STM32G4 #include "stm32g4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32G0 #include "stm32g0xx.h" - #define PMA_32BIT_ACCESS - #define PMA_LENGTH (2048u) + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_SIZE (2048u) #undef USB_PMAADDR #define USB_PMAADDR USB_DRD_PMAADDR #define USB_TypeDef USB_DRD_TypeDef @@ -112,8 +112,8 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32H5 #include "stm32h5xx.h" - #define PMA_32BIT_ACCESS - #define PMA_LENGTH (2048u) + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_SIZE (2048u) #undef USB_PMAADDR #define USB_PMAADDR USB_DRD_PMAADDR #define USB_TypeDef USB_DRD_TypeDef @@ -141,18 +141,18 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32WB #include "stm32wbxx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) /* ST provided header has incorrect value */ #undef USB_PMAADDR #define USB_PMAADDR USB1_PMAADDR #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #elif CFG_TUSB_MCU == OPT_MCU_STM32L5 #include "stm32l5xx.h" - #define PMA_LENGTH (1024u) + #define FSDEV_PMA_SIZE (1024u) #ifndef USB_PMAADDR #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS)) @@ -164,15 +164,16 @@ #endif // For purposes of accessing the packet -#if ((PMA_LENGTH) == 512u) - #define PMA_STRIDE (2u) -#elif ((PMA_LENGTH) == 1024u) - #define PMA_STRIDE (1u) +#if ((FSDEV_PMA_SIZE) == 512u) + #define FSDEV_PMA_STRIDE (2u) +#elif ((FSDEV_PMA_SIZE) == 1024u) + #define FSDEV_PMA_STRIDE (1u) #endif +// The fsdev_bus_t type can be used for both register and PMA access necessities // For type-safety create a new macro for the volatile address of PMAADDR // The compiler should warn us if we cast it to a non-volatile type? -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT typedef uint32_t fsdev_bus_t; static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR; @@ -184,7 +185,7 @@ static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR; TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; - total_word_offset *= PMA_STRIDE; + total_word_offset *= FSDEV_PMA_STRIDE; return &(pma[total_word_offset]); } @@ -215,7 +216,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si /* SetENDPOINT */ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4); *reg = wRegValue; @@ -227,7 +228,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui /* GetENDPOINT */ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4); #else @@ -282,7 +283,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, */ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; #else @@ -293,7 +294,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; #else @@ -320,7 +321,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; return pma32[2*bEpIdx] & 0x0000FFFFu ; #else @@ -330,7 +331,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; return pma32[2*bEpIdx + 1] & 0x0000FFFFu; #else @@ -340,7 +341,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); #else @@ -350,7 +351,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USB TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); #else @@ -360,7 +361,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USB TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); #else @@ -371,7 +372,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); #else @@ -383,7 +384,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t blocksize, uint32_t numblocks) { /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ -#ifdef PMA_32BIT_ACCESS +#ifdef FSDEV_BUS_32BIT (void) USBx; pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); #else From 290f4bea91e739979217eb91d589a75f9ac0f6a7 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 12 Jan 2024 15:47:08 +0700 Subject: [PATCH 14/41] - change tuh_event_hook_cb, tud_event_hook_cb to weak default implementation - change code style --- src/device/usbd.c | 340 +++++++++++++++++++------------------- src/device/usbd.h | 2 +- src/device/usbd_control.c | 33 ++-- src/host/usbh.c | 126 +++++++------- src/host/usbh.h | 2 +- 5 files changed, 244 insertions(+), 259 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 59466b42e..5c94ebcc5 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -38,11 +38,19 @@ //--------------------------------------------------------------------+ // USBD Configuration //--------------------------------------------------------------------+ - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif +//--------------------------------------------------------------------+ +// Callback weak stubs (called if application does not provide) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { + (void)rhport; + (void)eventid; + (void)in_isr; +} + //--------------------------------------------------------------------+ // Device Data //--------------------------------------------------------------------+ @@ -50,10 +58,8 @@ // Invalid driver ID in itf2drv[] ep2drv[][] mapping enum { DRVID_INVALID = 0xFFu }; -typedef struct -{ - struct TU_ATTR_PACKED - { +typedef struct { + struct TU_ATTR_PACKED { volatile uint8_t connected : 1; volatile uint8_t addressed : 1; volatile uint8_t suspended : 1; @@ -85,151 +91,150 @@ tu_static usbd_device_t _usbd_dev; #endif // Built-in class drivers -tu_static usbd_class_driver_t const _usbd_driver[] = -{ - #if CFG_TUD_CDC - { - DRIVER_NAME("CDC") - .init = cdcd_init, - .reset = cdcd_reset, - .open = cdcd_open, - .control_xfer_cb = cdcd_control_xfer_cb, - .xfer_cb = cdcd_xfer_cb, - .sof = NULL - }, - #endif +tu_static usbd_class_driver_t const _usbd_driver[] = { + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_MSC - { - DRIVER_NAME("MSC") - .init = mscd_init, - .reset = mscd_reset, - .open = mscd_open, - .control_xfer_cb = mscd_control_xfer_cb, - .xfer_cb = mscd_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_HID - { - DRIVER_NAME("HID") - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = hidd_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_AUDIO - { - DRIVER_NAME("AUDIO") - .init = audiod_init, - .reset = audiod_reset, - .open = audiod_open, - .control_xfer_cb = audiod_control_xfer_cb, - .xfer_cb = audiod_xfer_cb, - .sof = audiod_sof_isr - }, - #endif + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = audiod_sof_isr + }, + #endif - #if CFG_TUD_VIDEO - { - DRIVER_NAME("VIDEO") - .init = videod_init, - .reset = videod_reset, - .open = videod_open, - .control_xfer_cb = videod_control_xfer_cb, - .xfer_cb = videod_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_VIDEO + { + DRIVER_NAME("VIDEO") + .init = videod_init, + .reset = videod_reset, + .open = videod_open, + .control_xfer_cb = videod_control_xfer_cb, + .xfer_cb = videod_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_MIDI - { - DRIVER_NAME("MIDI") - .init = midid_init, - .open = midid_open, - .reset = midid_reset, - .control_xfer_cb = midid_control_xfer_cb, - .xfer_cb = midid_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_VENDOR - { - DRIVER_NAME("VENDOR") - .init = vendord_init, - .reset = vendord_reset, - .open = vendord_open, - .control_xfer_cb = tud_vendor_control_xfer_cb, - .xfer_cb = vendord_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_USBTMC - { - DRIVER_NAME("TMC") - .init = usbtmcd_init_cb, - .reset = usbtmcd_reset_cb, - .open = usbtmcd_open_cb, - .control_xfer_cb = usbtmcd_control_xfer_cb, - .xfer_cb = usbtmcd_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif - #if CFG_TUD_DFU_RUNTIME - { - DRIVER_NAME("DFU-RUNTIME") - .init = dfu_rtd_init, - .reset = dfu_rtd_reset, - .open = dfu_rtd_open, - .control_xfer_cb = dfu_rtd_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif - #if CFG_TUD_DFU - { - DRIVER_NAME("DFU") - .init = dfu_moded_init, - .reset = dfu_moded_reset, - .open = dfu_moded_open, - .control_xfer_cb = dfu_moded_control_xfer_cb, - .xfer_cb = NULL, - .sof = NULL - }, - #endif + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif - #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM - { - DRIVER_NAME("NET") - .init = netd_init, - .reset = netd_reset, - .open = netd_open, - .control_xfer_cb = netd_control_xfer_cb, - .xfer_cb = netd_xfer_cb, - .sof = NULL, - }, - #endif + #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM + { + DRIVER_NAME("NET") + .init = netd_init, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif - #if CFG_TUD_BTH - { - DRIVER_NAME("BTH") - .init = btd_init, - .reset = btd_reset, - .open = btd_open, - .control_xfer_cb = btd_control_xfer_cb, - .xfer_cb = btd_xfer_cb, - .sof = NULL - }, - #endif + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif }; enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; @@ -275,7 +280,7 @@ tu_static osal_queue_t _usbd_q; TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) { bool ret = osal_queue_send(_usbd_q, event, in_isr); - if (tud_event_hook_cb) tud_event_hook_cb(event->rhport, event->event_id, in_isr); + tud_event_hook_cb(event->rhport, event->event_id, in_isr); return ret; } @@ -297,27 +302,23 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, // Debug //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL -tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = -{ - "Invalid" , - "Bus Reset" , - "Unplugged" , - "SOF" , - "Suspend" , - "Resume" , - "Setup Received" , - "Xfer Complete" , - "Func Call" +tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = { + "Invalid", + "Bus Reset", + "Unplugged", + "SOF", + "Suspend", + "Resume", + "Setup Received", + "Xfer Complete", + "Func Call" }; // for usbd_control to print the name of control complete driver -void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) -{ - for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) - { - usbd_class_driver_t const * driver = get_driver(i); - if ( driver && driver->control_xfer_cb == callback ) - { +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) { + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) { + usbd_class_driver_t const* driver = get_driver(i); + if (driver && driver->control_xfer_cb == callback) { TU_LOG_USBD(" %s control complete\r\n", driver->name); return; } @@ -329,43 +330,36 @@ void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) //--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ -tusb_speed_t tud_speed_get(void) -{ +tusb_speed_t tud_speed_get(void) { return (tusb_speed_t) _usbd_dev.speed; } -bool tud_connected(void) -{ +bool tud_connected(void) { return _usbd_dev.connected; } -bool tud_mounted(void) -{ +bool tud_mounted(void) { return _usbd_dev.cfg_num ? true : false; } -bool tud_suspended(void) -{ +bool tud_suspended(void) { return _usbd_dev.suspended; } -bool tud_remote_wakeup(void) -{ +bool tud_remote_wakeup(void) { // only wake up host if this feature is supported and enabled and we are suspended - TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en); dcd_remote_wakeup(_usbd_rhport); return true; } -bool tud_disconnect(void) -{ +bool tud_disconnect(void) { TU_VERIFY(dcd_disconnect); dcd_disconnect(_usbd_rhport); return true; } -bool tud_connect(void) -{ +bool tud_connect(void) { TU_VERIFY(dcd_connect); dcd_connect(_usbd_rhport); return true; diff --git a/src/device/usbd.h b/src/device/usbd.h index 5456148bf..3ab6c813f 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -147,7 +147,7 @@ TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); TU_ATTR_WEAK void tud_resume_cb(void); // Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext() -TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); +void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); // Invoked when received control request with VENDOR TYPE TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index a6081060e..ea18b28da 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -32,24 +32,32 @@ #include "tusb.h" #include "device/usbd_pvt.h" +//--------------------------------------------------------------------+ +// Callback weak stubs (called if application does not provide) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) { + (void)rhport; + (void)request; +} + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback); #endif -enum -{ +enum { EDPT_CTRL_OUT = 0x00, EDPT_CTRL_IN = 0x80 }; -typedef struct -{ +typedef struct { tusb_control_request_t request; - uint8_t* buffer; uint16_t data_len; uint16_t total_xferred; - usbd_control_xfer_cb_t complete_cb; } usbd_control_xfer_t; @@ -134,23 +142,12 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo //--------------------------------------------------------------------+ // USBD API //--------------------------------------------------------------------+ - -TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) -{ - (void)rhport; - (void)request; - - // this is the default implementation that is called when no "real" implementation - // of the function exists -} - void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); -void usbd_control_reset(void) -{ +void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); } diff --git a/src/host/usbh.c b/src/host/usbh.c index 53e8a654b..dfe6ddb42 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -36,7 +36,6 @@ //--------------------------------------------------------------------+ // USBH Configuration //--------------------------------------------------------------------+ - #ifndef CFG_TUH_TASK_QUEUE_SZ #define CFG_TUH_TASK_QUEUE_SZ 16 #endif @@ -45,12 +44,19 @@ #define CFG_TUH_INTERFACE_MAX 8 #endif +//--------------------------------------------------------------------+ +// Callback weak stubs (called if application does not provide) +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { + (void) rhport; + (void) eventid; + (void) in_isr; +} + //--------------------------------------------------------------------+ // USBH-HCD common data structure //--------------------------------------------------------------------+ - -typedef struct -{ +typedef struct { // port uint8_t rhport; uint8_t hub_addr; @@ -112,60 +118,58 @@ typedef struct { //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - #if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL #define DRIVER_NAME(_name) .name = _name, #else #define DRIVER_NAME(_name) #endif -static usbh_class_driver_t const usbh_class_drivers[] = -{ - #if CFG_TUH_CDC +static usbh_class_driver_t const usbh_class_drivers[] = { + #if CFG_TUH_CDC { - DRIVER_NAME("CDC") - .init = cdch_init, - .open = cdch_open, - .set_config = cdch_set_config, - .xfer_cb = cdch_xfer_cb, - .close = cdch_close + DRIVER_NAME("CDC") + .init = cdch_init, + .open = cdch_open, + .set_config = cdch_set_config, + .xfer_cb = cdch_xfer_cb, + .close = cdch_close }, - #endif + #endif - #if CFG_TUH_MSC + #if CFG_TUH_MSC { - DRIVER_NAME("MSC") - .init = msch_init, - .open = msch_open, - .set_config = msch_set_config, - .xfer_cb = msch_xfer_cb, - .close = msch_close + DRIVER_NAME("MSC") + .init = msch_init, + .open = msch_open, + .set_config = msch_set_config, + .xfer_cb = msch_xfer_cb, + .close = msch_close }, - #endif + #endif - #if CFG_TUH_HID + #if CFG_TUH_HID { - DRIVER_NAME("HID") - .init = hidh_init, - .open = hidh_open, - .set_config = hidh_set_config, - .xfer_cb = hidh_xfer_cb, - .close = hidh_close + DRIVER_NAME("HID") + .init = hidh_init, + .open = hidh_open, + .set_config = hidh_set_config, + .xfer_cb = hidh_xfer_cb, + .close = hidh_close }, - #endif + #endif - #if CFG_TUH_HUB + #if CFG_TUH_HUB { - DRIVER_NAME("HUB") - .init = hub_init, - .open = hub_open, - .set_config = hub_set_config, - .xfer_cb = hub_xfer_cb, - .close = hub_close + DRIVER_NAME("HUB") + .init = hub_init, + .open = hub_open, + .set_config = hub_set_config, + .xfer_cb = hub_xfer_cb, + .close = hub_close }, - #endif + #endif - #if CFG_TUH_VENDOR + #if CFG_TUH_VENDOR { DRIVER_NAME("VENDOR") .init = cush_init, @@ -173,7 +177,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = .xfer_cb = cush_isr, .close = cush_close } - #endif + #endif }; enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; @@ -233,8 +237,7 @@ static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE]; // Control transfers: since most controllers do not support multiple control transfers // on multiple devices concurrently and control transfers are not used much except for // enumeration, we will only execute control transfers one at a time. -CFG_TUH_MEM_SECTION struct -{ +CFG_TUH_MEM_SECTION struct { CFG_TUH_MEM_ALIGN tusb_control_request_t request; uint8_t* buffer; tuh_xfer_cb_t complete_cb; @@ -268,7 +271,7 @@ TU_ATTR_WEAK void osal_task_delay(uint32_t msec) { TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) { bool ret = osal_queue_send(_usbh_q, event, in_isr); - if (tuh_event_hook_cb) tuh_event_hook_cb(event->rhport, event->event_id, in_isr); + tuh_event_hook_cb(event->rhport, event->event_id, in_isr); return ret; } @@ -367,17 +370,14 @@ bool tuh_init(uint8_t controller_id) { tu_memclr(_usbh_devices, sizeof(_usbh_devices)); tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer)); - for(uint8_t i=0; iname); driver->init(); } @@ -545,8 +545,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { // Control transfer //--------------------------------------------------------------------+ -static void _control_blocking_complete_cb(tuh_xfer_t* xfer) -{ +static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { // update result *((xfer_result_t*) xfer->user_data) = xfer->result; } @@ -625,21 +624,18 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { return true; } -TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) -{ +TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) { (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); _ctrl_xfer.stage = stage; (void) osal_mutex_unlock(_usbh_mutex); } -static void _xfer_complete(uint8_t daddr, xfer_result_t result) -{ +static void _xfer_complete(uint8_t daddr, xfer_result_t result) { TU_LOG_USBH("\r\n"); // duplicate xfer since user can execute control transfer within callback tusb_control_request_t const request = _ctrl_xfer.request; - tuh_xfer_t xfer_temp = - { + tuh_xfer_t xfer_temp = { .daddr = daddr, .ep_addr = 0, .result = result, @@ -652,8 +648,7 @@ static void _xfer_complete(uint8_t daddr, xfer_result_t result) _set_control_xfer_stage(CONTROL_STAGE_IDLE); - if (xfer_temp.complete_cb) - { + if (xfer_temp.complete_cb) { xfer_temp.complete_cb(&xfer_temp); } } @@ -710,17 +705,16 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result // //--------------------------------------------------------------------+ -bool tuh_edpt_xfer(tuh_xfer_t* xfer) -{ - uint8_t const daddr = xfer->daddr; +bool tuh_edpt_xfer(tuh_xfer_t* xfer) { + uint8_t const daddr = xfer->daddr; uint8_t const ep_addr = xfer->ep_addr; TU_VERIFY(daddr && ep_addr); TU_VERIFY(usbh_edpt_claim(daddr, ep_addr)); - if ( !usbh_edpt_xfer_with_callback(daddr, ep_addr, xfer->buffer, (uint16_t) xfer->buflen, xfer->complete_cb, xfer->user_data) ) - { + if (!usbh_edpt_xfer_with_callback(daddr, ep_addr, xfer->buffer, (uint16_t) xfer->buflen, + xfer->complete_cb, xfer->user_data)) { usbh_edpt_release(daddr, ep_addr); return false; } diff --git a/src/host/usbh.h b/src/host/usbh.h index 7591c7672..9ff118543 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -94,7 +94,7 @@ TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr); TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr); // Invoked when there is a new usb event, which need to be processed by tuh_task()/tuh_task_ext() -TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); +void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); //--------------------------------------------------------------------+ // APPLICATION API From 8eca596fa649a4e32da53f65ac1a41f963b89eb6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 12 Jan 2024 16:05:35 +0700 Subject: [PATCH 15/41] style changes --- src/device/usbd_control.c | 105 ++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index ea18b28da..35cce1f7e 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -35,9 +35,9 @@ //--------------------------------------------------------------------+ // Callback weak stubs (called if application does not provide) //--------------------------------------------------------------------+ -TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) { - (void)rhport; - (void)request; +TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + (void) rhport; + (void) request; } //--------------------------------------------------------------------+ @@ -50,7 +50,7 @@ extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callb enum { EDPT_CTRL_OUT = 0x00, - EDPT_CTRL_IN = 0x80 + EDPT_CTRL_IN = 0x80 }; typedef struct { @@ -71,20 +71,18 @@ tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE]; //--------------------------------------------------------------------+ // Queue ZLP status transaction -static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request) -{ +static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) { // Opposite to endpoint in Data Phase uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); } // Status phase -bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +bool tud_control_status(uint8_t rhport, tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; return _status_stage_xact(rhport, request); } @@ -92,16 +90,15 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request) // Queue a transaction in Data Stage // Each transaction has up to Endpoint0's max packet size. // This function can also transfer an zero-length packet -static bool _data_stage_xact(uint8_t rhport) -{ - uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE); +static bool _data_stage_xact(uint8_t rhport) { + uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, + CFG_TUD_ENDPOINT0_SIZE); uint8_t ep_addr = EDPT_CTRL_OUT; - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { ep_addr = EDPT_CTRL_IN; - if ( xact_len ) { + if (xact_len) { TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); } } @@ -111,29 +108,24 @@ static bool _data_stage_xact(uint8_t rhport) // Transmit data to/from the control endpoint. // If the request's wLength is zero, a status packet is sent instead. -bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = (uint8_t*) buffer; +bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, void* buffer, uint16_t len) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = (uint8_t*) buffer; _ctrl_xfer.total_xferred = 0U; - _ctrl_xfer.data_len = tu_min16(len, request->wLength); + _ctrl_xfer.data_len = tu_min16(len, request->wLength); - if (request->wLength > 0U) - { - if(_ctrl_xfer.data_len > 0U) - { + if (request->wLength > 0U) { + if (_ctrl_xfer.data_len > 0U) { TU_ASSERT(buffer); } // TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); // Data stage - TU_ASSERT( _data_stage_xact(rhport) ); - } - else - { + TU_ASSERT(_data_stage_xact(rhport)); + } else { // Status stage - TU_ASSERT( _status_stage_xact(rhport, request) ); + TU_ASSERT(_status_stage_xact(rhport, request)); } return true; @@ -143,46 +135,41 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo // USBD API //--------------------------------------------------------------------+ void usbd_control_reset(void); -void usbd_control_set_request(tusb_control_request_t const *request); -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void usbd_control_set_request(tusb_control_request_t const* request); +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); } // Set complete callback -void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ) -{ +void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp) { _ctrl_xfer.complete_cb = fp; } // for dcd_set_address where DCD is responsible for status response -void usbd_control_set_request(tusb_control_request_t const *request) -{ - _ctrl_xfer.request = (*request); - _ctrl_xfer.buffer = NULL; +void usbd_control_set_request(tusb_control_request_t const* request) { + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = NULL; _ctrl_xfer.total_xferred = 0; - _ctrl_xfer.data_len = 0; + _ctrl_xfer.data_len = 0; } // callback when a transaction complete on // - DATA stage of control endpoint or // - Status stage -bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; // Endpoint Address is opposite to direction bit, this is Status Stage complete event - if ( tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction ) - { + if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) { TU_ASSERT(0 == xferred_bytes); // invoke optional dcd hook if available dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request); - if (_ctrl_xfer.complete_cb) - { + if (_ctrl_xfer.complete_cb) { // TODO refactor with usbd_driver_print_control_complete_name _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request); } @@ -190,8 +177,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result return true; } - if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) - { + if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) { TU_VERIFY(_ctrl_xfer.buffer); memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2); @@ -202,15 +188,14 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result // Data Stage is complete when all request's length are transferred or // a short packet is sent including zero-length packet. - if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) ) - { + if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || + (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) { // DATA stage is complete bool is_ok = true; // invoke complete callback if set // callback can still stall control in status phase e.g out data does not make sense - if ( _ctrl_xfer.complete_cb ) - { + if (_ctrl_xfer.complete_cb) { #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb); #endif @@ -218,21 +203,17 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request); } - if ( is_ok ) - { + if (is_ok) { // Send status - TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) ); - }else - { + TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request)); + } else { // Stall both IN and OUT control endpoint dcd_edpt_stall(rhport, EDPT_CTRL_OUT); dcd_edpt_stall(rhport, EDPT_CTRL_IN); } - } - else - { + } else { // More data to transfer - TU_ASSERT( _data_stage_xact(rhport) ); + TU_ASSERT(_data_stage_xact(rhport)); } return true; From d92eb38c211899ed963250272d882fcac8dbaf9c Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 16:56:18 +0700 Subject: [PATCH 16/41] change code style --- src/class/cdc/cdc_host.c | 528 +++++++++++++++++---------------------- 1 file changed, 236 insertions(+), 292 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4f36f7517..05a061487 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -106,7 +106,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST }; enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) + FTDI_PID_COUNT = TU_ARRAY_SIZE(ftdi_pids) }; // Store last request baudrate since divisor to baudrate is not easy @@ -114,7 +114,6 @@ static uint32_t _ftdi_requested_baud; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); - static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -125,12 +124,11 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST }; enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) + CP210X_PID_COUNT = TU_ARRAY_SIZE(cp210x_pids) }; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); - static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -141,16 +139,16 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; enum { - CH34X_VID_PID_COUNT = sizeof ( ch34x_vids_pids ) / sizeof ( ch34x_vids_pids[0] ) + CH34X_VID_PID_COUNT = TU_ARRAY_SIZE(ch34x_vids_pids) }; static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); - static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); #endif +//------------- Common -------------// enum { SERIAL_DRIVER_ACM = 0, @@ -204,29 +202,25 @@ static const cdch_serial_driver_t serial_drivers[] = { }; enum { - SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0]) + SERIAL_DRIVER_COUNT = TU_ARRAY_SIZE(serial_drivers) }; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t* get_itf(uint8_t idx) -{ +static inline cdch_interface_t* get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); cdch_interface_t* p_cdc = &cdch_data[idx]; return (p_cdc->daddr != 0) ? p_cdc : NULL; } -static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) -{ - for(uint8_t i=0; idaddr == daddr) && - (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) - { + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { return i; } } @@ -234,14 +228,10 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) return TUSB_INDEX_INVALID_8; } - -static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) -{ - for(uint8_t i=0; idaddr = daddr; p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; @@ -262,20 +252,16 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer); // APPLICATION API //--------------------------------------------------------------------+ -uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) -{ - for(uint8_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) -{ +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && info); @@ -297,30 +283,26 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) return true; } -bool tuh_cdc_mounted(uint8_t idx) -{ +bool tuh_cdc_mounted(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); return p_cdc != NULL; } -bool tuh_cdc_get_dtr(uint8_t idx) -{ +bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } -bool tuh_cdc_get_rts(uint8_t idx) -{ +bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) -{ +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -333,32 +315,28 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) // Write //--------------------------------------------------------------------+ -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } -uint32_t tuh_cdc_write_flush(uint8_t idx) -{ +uint32_t tuh_cdc_write_flush(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); } -bool tuh_cdc_write_clear(uint8_t idx) -{ +bool tuh_cdc_write_clear(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_clear(&p_cdc->stream.tx); } -uint32_t tuh_cdc_write_available(uint8_t idx) -{ +uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -369,32 +347,28 @@ uint32_t tuh_cdc_write_available(uint8_t idx) // Read //--------------------------------------------------------------------+ -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) -{ +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } -uint32_t tuh_cdc_read_available(uint8_t idx) -{ +uint32_t tuh_cdc_read_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) -{ +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } -bool tuh_cdc_read_clear (uint8_t idx) -{ +bool tuh_cdc_read_clear (uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -408,15 +382,13 @@ bool tuh_cdc_read_clear (uint8_t idx) //--------------------------------------------------------------------+ // internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) -{ +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); - if (xfer->result == XFER_RESULT_SUCCESS) - { + if (xfer->result == XFER_RESULT_SUCCESS) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { @@ -502,7 +474,6 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_state = (uint8_t) line_state; return true; } @@ -526,7 +497,6 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = baudrate; return true; } @@ -552,7 +522,6 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, } TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_coding = *line_coding; return true; } @@ -562,31 +531,26 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // CLASS-USBH API //--------------------------------------------------------------------+ -void cdch_init(void) -{ +void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); - for(size_t i=0; istream.tx, true, true, false, - p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, - p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); } } -void cdch_close(uint8_t daddr) -{ - for(uint8_t idx=0; idxdaddr == daddr) - { + if (p_cdc->daddr == daddr) { TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx); // Invoke application callback @@ -618,16 +582,11 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); } - } - else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { + } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { #if CFG_TUH_CDC_FTDI if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { // FTDI reserve 2 bytes for status - // FTDI status -// uint8_t status[2] = { -// p_cdc->stream.rx.ep_buf[0], -// p_cdc->stream.rx.ep_buf[1] -// }; + // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2); }else #endif @@ -653,20 +612,15 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep) -{ - for(size_t i=0; i<2; i++) - { +static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) { + for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && - TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); - + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); - if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) - { + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); - }else - { + } else { tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); } @@ -676,20 +630,17 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co return true; } -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - // Only support ACM subclass + // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device - if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && - CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) - { + if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); } #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) - { + else if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); @@ -721,7 +672,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } #endif } - #endif // CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + #endif return false; } @@ -767,94 +718,85 @@ enum { CONFIG_ACM_COMPLETE, }; -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ - uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len; - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// - uint8_t const * p_desc = tu_desc_next(itf_desc); + uint8_t const* p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) - { - if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) - { + while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { + if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities; } p_desc = tu_desc_next(p_desc); } // Open notification endpoint of control interface if any - if (itf_desc->bNumEndpoints == 1) - { + if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); p_cdc->ep_notif = desc_ep->bEndpointAddress; p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { + if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { // next to endpoint descriptor p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc)); } return true; } -static void acm_process_config(tuh_xfer_t* xfer) -{ +static void acm_process_config(tuh_xfer_t* xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); - switch(state) - { + switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { - TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, - CONFIG_ACM_SET_LINE_CODING), ); + if (p_cdc->acm_capability.support_line_request) { + TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) - { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + if (p_cdc->acm_capability.support_line_request) { cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), ); + TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),); break; } - #endif + #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, idx, itf_num+1); + set_config_complete(p_cdc, idx, itf_num + 1); break; - default: break; + default: + break; } } @@ -987,13 +929,12 @@ static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint1 return tuh_control_xfer(&xfer); } -static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool +ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, @@ -1001,8 +942,7 @@ static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state return true; } -static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; uint32_t divisor; @@ -1022,13 +962,11 @@ static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) return divisor; } -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); @@ -1055,8 +993,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1172,8 +1109,7 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ complete_cb ? cdch_internal_control_complete : NULL, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, @@ -1213,8 +1149,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT( - cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); break; #else TU_ATTR_FALLTHROUGH; @@ -1248,8 +1183,7 @@ enum { CONFIG_CH34X_COMPLETE }; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) -{ +static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) { // CH34x Interface includes 1 vendor interface + 3 bulk endpoints TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); @@ -1303,23 +1237,19 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint return false; } -static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); } -static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); } -static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); } -static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); } @@ -1335,8 +1265,7 @@ static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, u */ // calculate baudrate devisors // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) -{ +static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { uint32_t fact, div, clk_div; bool force_fact0 = false; int32_t ps; @@ -1362,20 +1291,19 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) */ fact = 1; for (ps = 3; ps >= 0; ps--) { - if (speed > ch341_min_rates[ps]) - break; + if (speed > ch341_min_rates[ps]) break; } - if (ps < 0) - return -EINVAL; + if (ps < 0) return -EINVAL; /* Determine corresponding divisor, rounding down. */ clk_div = CH341_CLK_DIV(ps, fact); div = CH341_CLKRATE / (clk_div * speed); /* Some devices require a lower base clock if ps < 3. */ - if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) + if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) { force_fact0 = true; + } /* Halve base clock (fact = 0) if required. */ if (div < 9 || div > 255 || force_fact0) { @@ -1384,16 +1312,16 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) fact = 0; } - if (div < 2) - return -EINVAL; + if (div < 2) return -EINVAL; /* * Pick next divisor if resulting rate is closer to the requested one, * scale up to avoid rounding errors on low rates. */ if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= - 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) + 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) { div++; + } /* * Prefer lower base clock (fact = 0) if even divisor. @@ -1411,16 +1339,13 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) // set baudrate (low level) // do not confuse with ch34x_set_baudrate // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { int val; - if (!baud_rate) - return -EINVAL; + if (!baud_rate) return -EINVAL; val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) - return -EINVAL; + if (val < 0) return -EINVAL; /* * CH341A buffers data until a full endpoint-size packet (32 bytes) @@ -1429,100 +1354,94 @@ static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, * At least one device with version 0x27 appears to have this bit * inverted. */ - if ( p_cdc->ch34x.version > 0x27 ) + if ( p_cdc->ch34x.version > 0x27 ) { val |= BIT(7); + } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); } // set lcr register // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * Chip versions before version 0x30 as read using * CH341_REQ_READ_VERSION used separate registers for line control * (stop bits, parity and word length). Version 0x30 and above use * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. */ - if ( p_cdc->ch34x.version < 0x30 ) - return 0; + if ( p_cdc->ch34x.version < 0x30 ) return 0; return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); } // set handshake (modem controls) // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); } // detect quirks (special versions of CH34x) // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * A subset of CH34x devices does not support all features. The * prescaler is limited and there is no support for sending a RS232 * break condition. A read failure when trying to set up the latter is * used to detect these devices. */ - switch ( step ) - { - case 1: - p_cdc->ch34x.quirks = 0; - return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); - break; - case 2: - if ( xfer->result != XFER_RESULT_SUCCESS ) - p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; - return true; - break; - default: - TU_ASSERT ( false ); // suspicious step - break; + switch (step) { + case 1: + p_cdc->ch34x.quirks = 0; + return ch341_read_reg_request(p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data); + break; + + case 2: + if (xfer->result != XFER_RESULT_SUCCESS) { + p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; + } + return true; + break; + + default: + TU_ASSERT (false); // suspicious step + break; } } // internal control complete to update state such as line state, encoding // CH34x needs a special interface recovery due to abnormal wIndex usage -static void ch34x_control_complete(tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); - uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); - cdch_interface_t *p_cdc = get_itf ( idx ); - TU_ASSERT ( p_cdc, ); - TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x +static void ch34x_control_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = (uint8_t) ((xfer->user_data & 0xff00) >> 8); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT (p_cdc,); + TU_ASSERT (p_cdc->serial_drid == SERIAL_DRIVER_CH34X,); // ch34x_control_complete is only used for CH34x if (xfer->result == XFER_RESULT_SUCCESS) { switch (xfer->setup->bRequest) { - case CH341_REQ_WRITE_REG: { // register write request - switch ( tu_le16toh ( xfer->setup->wValue ) ) { - case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + case CH341_REQ_WRITE_REG: // register write request + switch (tu_le16toh (xfer->setup->wValue)) { + case (CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER): // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + break; + + default: + TU_ASSERT(false,); // unexpected register write + break; + } break; - } - default: { - TU_ASSERT(false, ); // unexpected register write + + default: + TU_ASSERT(false,); // unexpected request break; - } - } - break; - } - default: { - TU_ASSERT(false, ); // unexpected request - break; - } } xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) - xfer->complete_cb(xfer); + if (xfer->complete_cb) xfer->complete_cb(xfer); } } -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate -{ +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) /* do not confuse with ch341_set_baudrate */ { TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->ch34x.baud_rate = baudrate; @@ -1530,15 +1449,13 @@ static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); } -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); // todo later return false; } -static void ch34x_process_config ( tuh_xfer_t* xfer ) -{ +static void ch34x_process_config ( tuh_xfer_t* xfer ) { uintptr_t const state = xfer->user_data & 0xff; // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); @@ -1561,81 +1478,108 @@ static void ch34x_process_config ( tuh_xfer_t* xfer ) */ p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; } + // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c - switch ( state ) { - case CONFIG_CH34X_STEP1: // request version read - TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); - break; - case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x - p_cdc->ch34x.version = xfer->buffer[0]; - TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); - TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); - break; - case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) - TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); - break; - case CONFIG_CH34X_STEP4: // set line controls with default values (see above) - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); - break; - case CONFIG_CH34X_STEP5: // set handshake RTS/DTR - TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); - break; - case CONFIG_CH34X_STEP6: // detect quirks step 1 - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); - break; - case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); + switch (state) { + case CONFIG_CH34X_STEP1: // request version read + TU_ASSERT (ch341_control_in(p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */0, + buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2),); + break; + + case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x + p_cdc->ch34x.version = xfer->buffer[0]; + TU_LOG_DRV ("Chip version=%02x\r\n", p_cdc->ch34x.version); + TU_ASSERT (ch341_control_out(p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */0, + ch34x_process_config, CONFIG_CH34X_STEP3),); + break; + + case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) + TU_ASSERT (ch341_set_baudrate(p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, + CONFIG_CH34X_STEP4) > 0,); + break; + + case CONFIG_CH34X_STEP4: // set line controls with default values (see above) + TU_ASSERT (ch341_set_lcr(p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5) > 0,); + break; + + case CONFIG_CH34X_STEP5: // set handshake RTS/DTR + TU_ASSERT (ch341_set_handshake(p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6) > 0,); + break; + + case CONFIG_CH34X_STEP6: // detect quirks step 1 + TU_ASSERT (ch341_detect_quirks(xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, + ch34x_process_config, CONFIG_CH34X_STEP7) > 0,); + break; + + case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values + TU_ASSERT (ch341_detect_quirks(xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0) > 0,); #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); + TU_ASSERT (ch34x_set_baudrate(p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8),); #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif - break; - case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity + break; + + case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; - switch ( line_coding.data_bits ) { - case 5: - p_cdc->ch34x.lcr |= CH341_LCR_CS5; - break; - case 6: - p_cdc->ch34x.lcr |= CH341_LCR_CS6; - break; - case 7: - p_cdc->ch34x.lcr |= CH341_LCR_CS7; - break; - case 8: - p_cdc->ch34x.lcr |= CH341_LCR_CS8; - break; - default: - TU_ASSERT ( false, ); // not supported data_bits - p_cdc->ch34x.lcr |= CH341_LCR_CS8; - break; - } - if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { - p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; - if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; - if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; - } - TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits - if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) - p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); + p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + switch (line_coding.data_bits) { + case 5: + p_cdc->ch34x.lcr |= CH341_LCR_CS5; + break; + + case 6: + p_cdc->ch34x.lcr |= CH341_LCR_CS6; + break; + + case 7: + p_cdc->ch34x.lcr |= CH341_LCR_CS7; + break; + + case 8: + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + + default: + TU_ASSERT (false,); // not supported data_bits + p_cdc->ch34x.lcr |= CH341_LCR_CS8; + break; + } + + if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { + p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + + if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { + p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + } + + if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { + p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + } + } + TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == + CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits + if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; + } + TU_ASSERT (ch341_set_lcr(p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE) > 0,); #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif - break; + break; + case CONFIG_CH34X_COMPLETE: - set_config_complete ( p_cdc, idx, itf_num ); + set_config_complete(p_cdc, idx, itf_num); break; + default: - TU_ASSERT ( false, ); + TU_ASSERT (false,); break; } } #endif // CFG_TUH_CDC_CH34X -#endif // (CFG_TUH_ENABLED && CFG_TUH_CDC) +#endif From d192868d62b56ef2eab9300bf0698a77e4e01cd3 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 18:25:15 +0700 Subject: [PATCH 17/41] fix sign-conversion warning --- src/class/cdc/cdc_host.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 05a061487..0cc35da52 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1207,7 +1207,7 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_VENDOR, - .direction = direction + .direction = direction & 0x01u }, .bRequest = request, .wValue = tu_htole16 ( value ), @@ -1265,6 +1265,11 @@ static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, u */ // calculate baudrate devisors // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c + +static inline uint32_t clamp_val(uint32_t val, uint32_t minval, uint32_t maxval) { + return tu_min32(tu_max32(val, minval), maxval); +} + static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { uint32_t fact, div, clk_div; bool force_fact0 = false; @@ -1280,9 +1285,6 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { * Clamp to supported range, this makes the (ps < 0) and (div < 2) * sanity checks below redundant. */ - inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } - inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } - inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); /* @@ -1297,7 +1299,7 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { if (ps < 0) return -EINVAL; /* Determine corresponding divisor, rounding down. */ - clk_div = CH341_CLK_DIV(ps, fact); + clk_div = CH341_CLK_DIV((uint32_t) ps, fact); div = CH341_CLKRATE / (clk_div * speed); /* Some devices require a lower base clock if ps < 3. */ @@ -1333,19 +1335,20 @@ static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) { fact = 0; } - return (0x100 - div) << 8 | fact << 2 | ps; + return (int32_t) ((0x100 - div) << 8 | fact << 2 | (uint32_t) ps); } // set baudrate (low level) // do not confuse with ch34x_set_baudrate // Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - int val; - +static int32_t ch341_set_baudrate (cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { if (!baud_rate) return -EINVAL; - val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) return -EINVAL; + int ret; + ret = ch341_get_divisor(p_cdc, baud_rate); + if (ret < 0) return -EINVAL; + + uint16_t val = (uint16_t) ret; /* * CH341A buffers data until a full endpoint-size packet (32 bytes) @@ -1355,7 +1358,7 @@ static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, * inverted. */ if ( p_cdc->ch34x.version > 0x27 ) { - val |= BIT(7); + val = (val | BIT(7)); } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); @@ -1449,8 +1452,13 @@ static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); } -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); + (void) p_cdc; + (void) line_state; + (void) complete_cb; + (void) user_data; + // todo later return false; } From 1f2901e8b12258c953e3c338897f188c98b5eaed Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Jan 2024 18:42:39 +0700 Subject: [PATCH 18/41] fix conflict of BIT() macro --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/serial/ch34x.h | 11 ++++------- src/common/tusb_common.h | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 0cc35da52..ca5bfff04 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1358,7 +1358,7 @@ static int32_t ch341_set_baudrate (cdch_interface_t* p_cdc, uint32_t baud_rate, * inverted. */ if ( p_cdc->ch34x.version > 0x27 ) { - val = (val | BIT(7)); + val = (val | TU_BIT(7)); } return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 94e18b252..4a5e61bbd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -29,7 +29,7 @@ #include -#define BIT(nr) ( (uint32_t)1 << (nr) ) +//#define BIT(nr) ( (uint32_t)1 << (nr) ) #define CH34X_BUFFER_SIZE 2 @@ -93,20 +93,17 @@ #define CH341_LCR_CS6 0x01 #define CH341_LCR_CS5 0x00 -#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) -#define CH341_QUIRK_SIMULATE_BREAK BIT(1) +#define CH341_QUIRK_LIMITED_PRESCALER TU_BIT(0) +#define CH341_QUIRK_SIMULATE_BREAK TU_BIT(1) #define CH341_CLKRATE 48000000 #define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) #define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) /* Supported range is 46 to 3000000 bps. */ -#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) +#define CH341_MIN_BPS TU_DIV_CEIL(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) #define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP -#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - // error codes #define EINVAL 22 /* Invalid argument */ diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index caeb5f2ef..1f08ce4ed 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -37,6 +37,7 @@ #define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) +#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d)) #define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) #define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) From aa58cdcfa6a35cf5d903eaffd304db4834ce56ec Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 01:28:29 +0700 Subject: [PATCH 19/41] change CFG_TUH_CDC_FTDI/CP210X_PID_LIST to CFG_TUH_CDC_FTDI/CP210X_VID_PID_LIST which contains both vid and pid. --- .idea/cmake.xml | 2 +- src/class/cdc/cdc_host.c | 24 ++++++++++-------------- src/tusb_option.h | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 432e44172..3cb883e62 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -80,7 +80,7 @@ - + \ No newline at end of file diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 79477ef53..2463671c6 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -91,9 +91,9 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_pids[] = { CFG_TUH_CDC_FTDI_PID_LIST }; +static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST }; enum { - FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) + FTDI_PID_COUNT = sizeof(ftdi_vid_pid_list) / sizeof(ftdi_vid_pid_list[0]) }; // Store last request baudrate since divisor to baudrate is not easy @@ -110,9 +110,9 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_pids[] = { CFG_TUH_CDC_CP210X_PID_LIST }; +static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST }; enum { - CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0]) + CP210X_PID_COUNT = sizeof(cp210x_vid_pid_list) / sizeof(cp210x_vid_pid_list[0]) }; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); @@ -647,21 +647,17 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); #if CFG_TUH_CDC_FTDI - if (TU_FTDI_VID == vid) { - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_pids[i] == pid) { - return ftdi_open(daddr, itf_desc, max_len); - } + for (size_t i = 0; i < FTDI_PID_COUNT; i++) { + if (ftdi_vid_pid_list[i][0] == vid && ftdi_vid_pid_list[i][1] == pid) { + return ftdi_open(daddr, itf_desc, max_len); } } #endif #if CFG_TUH_CDC_CP210X - if (TU_CP210X_VID == vid) { - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_pids[i] == pid) { - return cp210x_open(daddr, itf_desc, max_len); - } + for (size_t i = 0; i < CP210X_PID_COUNT; i++) { + if (cp210x_vid_pid_list[i][0] == vid && cp210x_vid_pid_list[i][1] == pid) { + return cp210x_open(daddr, itf_desc, max_len); } } #endif diff --git a/src/tusb_option.h b/src/tusb_option.h index a76281c0c..57f026312 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -453,10 +453,12 @@ #define CFG_TUH_CDC_FTDI 0 #endif -#ifndef CFG_TUH_CDC_FTDI_PID_LIST - // List of product IDs that can use the FTDI CDC driver - #define CFG_TUH_CDC_FTDI_PID_LIST \ - 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, 0xCD18 +#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST + // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID + #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ + {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ + {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ + {0x0403, 0xCD18} #endif #ifndef CFG_TUH_CDC_CP210X @@ -464,10 +466,10 @@ #define CFG_TUH_CDC_CP210X 0 #endif -#ifndef CFG_TUH_CDC_CP210X_PID_LIST - // List of product IDs that can use the CP210X CDC driver - #define CFG_TUH_CDC_CP210X_PID_LIST \ - 0xEA60, 0xEA70 +#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST + // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID + #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ + {0x10C4, 0xEA60}, {0x10C4, 0xEA70} #endif #ifndef CFG_TUH_HID From e2aa671346103d3ed80c2849350488d5ddf2e0dc Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 12:54:39 +0700 Subject: [PATCH 20/41] move open() ad vid_pid_list into serial driver struct --- src/class/cdc/cdc_host.c | 102 ++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index c018cf057..91e35ec8c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -104,10 +104,7 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe #if CFG_TUH_CDC_FTDI #include "serial/ftdi_sio.h" -static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST }; -enum { - FTDI_PID_COUNT = TU_ARRAY_SIZE(ftdi_vid_pid_list) -}; +static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; // Store last request baudrate since divisor to baudrate is not easy static uint32_t _ftdi_requested_baud; @@ -122,10 +119,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu #if CFG_TUH_CDC_CP210X #include "serial/cp210x.h" -static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST }; -enum { - CP210X_PID_COUNT = TU_ARRAY_SIZE(cp210x_vid_pid_list) -}; +static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); @@ -137,10 +131,7 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ #if CFG_TUH_CDC_CH34X #include "serial/ch34x.h" -static uint16_t const ch34x_vids_pids[][2] = { CFG_TUH_CDC_CH34X_VID_PID_LIST }; -enum { - CH34X_VID_PID_COUNT = TU_ARRAY_SIZE(ch34x_vids_pids) -}; +static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); @@ -164,9 +155,14 @@ enum { #if CFG_TUH_CDC_CH34X SERIAL_DRIVER_CH34X, #endif + + SERIAL_DRIVER_COUNT }; typedef struct { + uint16_t const (*vid_pid_list)[2]; + uint16_t const vid_pid_count; + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -174,36 +170,50 @@ typedef struct { // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { - { .process_set_config = acm_process_config, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate + { + .vid_pid_list = NULL, + .vid_pid_count = 0, + .open = acm_open, + .process_set_config = acm_process_config, + .set_control_line_state = acm_set_control_line_state, + .set_baudrate = acm_set_baudrate }, #if CFG_TUH_CDC_FTDI - { .process_set_config = ftdi_process_config, - .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate + { + .vid_pid_list = ftdi_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), + .open = ftdi_open, + .process_set_config = ftdi_process_config, + .set_control_line_state = ftdi_sio_set_modem_ctrl, + .set_baudrate = ftdi_sio_set_baudrate }, #endif #if CFG_TUH_CDC_CP210X - { .process_set_config = cp210x_process_config, - .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate + { + .vid_pid_list = cp210x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), + .open = cp210x_open, + .process_set_config = cp210x_process_config, + .set_control_line_state = cp210x_set_modem_ctrl, + .set_baudrate = cp210x_set_baudrate }, #endif #if CFG_TUH_CDC_CH34X - { .process_set_config = ch34x_process_config, - .set_control_line_state = ch34x_set_modem_ctrl, - .set_baudrate = ch34x_set_baudrate + { + .vid_pid_list = ch34x_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), + .open = ch34x_open, + .process_set_config = ch34x_process_config, + .set_control_line_state = ch34x_set_modem_ctrl, + .set_baudrate = ch34x_set_baudrate }, -#endif + #endif }; -enum { - SERIAL_DRIVER_COUNT = TU_ARRAY_SIZE(serial_drivers) -}; +TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch"); //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -639,36 +649,20 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); } - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if (TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + else if (SERIAL_DRIVER_COUNT > 1 && + TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - #if CFG_TUH_CDC_FTDI - for (size_t i = 0; i < FTDI_PID_COUNT; i++) { - if (ftdi_vid_pid_list[i][0] == vid && ftdi_vid_pid_list[i][1] == pid) { - return ftdi_open(daddr, itf_desc, max_len); + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + cdch_serial_driver_t const* driver = &serial_drivers[dr]; + for (size_t i = 0; i < driver->vid_pid_count; i++) { + if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { + return driver->open(daddr, itf_desc, max_len); + } } } - #endif - - #if CFG_TUH_CDC_CP210X - for (size_t i = 0; i < CP210X_PID_COUNT; i++) { - if (cp210x_vid_pid_list[i][0] == vid && cp210x_vid_pid_list[i][1] == pid) { - return cp210x_open(daddr, itf_desc, max_len); - } - } - #endif - - #if CFG_TUH_CDC_CH34X - for (size_t i = 0; i < CH34X_VID_PID_COUNT; i++) { - if ( ch34x_vids_pids[i][0] == vid && ch34x_vids_pids[i][1] == pid ) { - return ch34x_open(daddr, itf_desc, max_len); - } - } - #endif } - #endif return false; } @@ -683,9 +677,7 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i usbh_driver_set_config_complete(p_cdc->daddr, itf_num); } - -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); From 4e6408ea4940085f66c676772d77e3951e82ea11 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 16 Jan 2024 08:07:22 +0100 Subject: [PATCH 21/41] CDCh host: further work on CH340/CH341 support --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- .../cdc_msc_hid_freertos/src/tusb_config.h | 3 +- src/class/cdc/cdc_debug.h | 65 ++ src/class/cdc/cdc_device.c | 21 +- src/class/cdc/cdc_host.c | 570 ++++++++---------- src/class/cdc/cdc_host.h | 4 +- src/class/cdc/serial/ch34x.h | 103 +--- 7 files changed, 370 insertions(+), 399 deletions(-) create mode 100644 src/class/cdc/cdc_debug.h diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 76d59c316..ac14ef97e 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -120,8 +120,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM ( CDC_CONTROL_LINE_STATE_RTS | CDC_CONTROL_LINE_STATE_DTR ) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index bb7c3388d..1b68dd2d8 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -125,8 +125,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM ( CDC_CONTROL_LINE_STATE_RTS | CDC_CONTROL_LINE_STATE_DTR ) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/src/class/cdc/cdc_debug.h b/src/class/cdc/cdc_debug.h new file mode 100644 index 000000000..879e49a50 --- /dev/null +++ b/src/class/cdc/cdc_debug.h @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * Copyright (c) 2023 IngHK Heiko Kuester + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_CDC_DEBUG_H_ +#define _TUSB_CDC_DEBUG_H_ + +#include "cdc.h" + +#ifdef __cplusplus + extern "C" { +#endif + +// logging of line coding +#define TU_LOG_LINE_CODING(PRE_TEXT,LINE_CODING) \ + TU_LOG_DRV(PRE_TEXT "Line Coding %lu Bd, %u%c%s\r\n", \ + LINE_CODING.bit_rate, \ + LINE_CODING.data_bits, \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_NONE ? 'N' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_ODD ? 'O' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_MARK ? 'M' : \ + LINE_CODING.parity == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?', \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \ + LINE_CODING.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?") + +// logging of baudrate +#define TU_LOG_BAUDRATE(PRE_TEXT,BAUDRATE) \ + TU_LOG_DRV(PRE_TEXT "Baudrate %lu Bd\r\n", BAUDRATE) + + // logging of control line state +#define TU_LOG_CONTROL_LINE_STATE(PRE_TEXT,LINE_STATE) \ + TU_LOG_DRV(PRE_TEXT "Control Line State RTS%c DTR%c\r\n", \ + LINE_STATE & CDC_CONTROL_LINE_STATE_RTS ? '+' : '-', \ + LINE_STATE & CDC_CONTROL_LINE_STATE_DTR ? '+' : '-' ) + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CDC_DEBUG_H_ */ diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c26264e60..b763419e7 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -32,6 +32,9 @@ #include "device/usbd_pvt.h" #include "cdc_device.h" +#if 0 // TODO activate and test +#include "cdc_debug.h" +#endif // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUD_CDC_LOG_LEVEL @@ -360,7 +363,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_SET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG_DRV(" Set Line Coding\r\n"); + #if 0 // TODO activate, test and remove else + TU_LOG_LINE_CODING(" Set ", p_cdc->line_coding); + #else + TU_LOG_DRV(" Set Line Coding\r\n"); + #endif tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } else if ( stage == CONTROL_STAGE_ACK) @@ -372,7 +379,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t case CDC_REQUEST_GET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { - TU_LOG_DRV(" Get Line Coding\r\n"); + #if 0 // TODO activate, test and remove else + TU_LOG_LINE_CODING(" Get ", p_cdc->line_coding); + #else + TU_LOG_DRV(" Get Line Coding\r\n"); + #endif tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } break; @@ -397,7 +408,11 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t // Disable fifo overwriting if DTR bit is set tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); - TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + #if 0 // TODO activate, test and remove else + TU_LOG_CONTROL_LINE_STATE(" Set ", p_cdc->line_state); + #else + TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); + #endif // Invoke callback if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f6a6773e0..d46bfecb4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2,7 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Ha Thach (tinyusb.org) - * Copyright (c) 2023 Heiko Kuester (CH34x support) + * Copyright (c) 2023 IngHK Heiko Kuester * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,7 @@ #include "host/usbh_pvt.h" #include "cdc_host.h" +#include "cdc_debug.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -55,7 +56,7 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - uint8_t line_state; // DTR (bit0), RTS (bit1) + uint8_t line_state; // RTS, DTR (refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width tuh_xfer_cb_t user_control_cb; @@ -70,16 +71,9 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - #if CFG_TUH_CDC_CH34X - struct { - uint32_t baud_rate; - uint8_t mcr; - uint8_t msr; - uint8_t lcr; - uint32_t quirks; - uint8_t version; - } ch34x; - #endif +#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X + uint32_t baudrate_requested; +#endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -106,12 +100,10 @@ enum { FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0]) }; -// Store last request baudrate since divisor to baudrate is not easy -static uint32_t _ftdi_requested_baud; - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -128,6 +120,7 @@ enum { static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -144,6 +137,7 @@ enum { static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); static void ch34x_process_config ( tuh_xfer_t* xfer ); +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); #endif @@ -169,35 +163,40 @@ typedef struct { void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); } cdch_serial_driver_t; // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { { .process_set_config = acm_process_config, .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate + .set_baudrate = acm_set_baudrate, + .set_line_coding = acm_set_line_coding }, #if CFG_TUH_CDC_FTDI { .process_set_config = ftdi_process_config, .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate + .set_baudrate = ftdi_sio_set_baudrate, + .set_line_coding = ftdi_set_line_coding }, #endif #if CFG_TUH_CDC_CP210X { .process_set_config = cp210x_process_config, .set_control_line_state = cp210x_set_modem_ctrl, - .set_baudrate = cp210x_set_baudrate + .set_baudrate = cp210x_set_baudrate, + .set_line_coding = cp210x_set_line_coding }, #endif #if CFG_TUH_CDC_CH34X { .process_set_config = ch34x_process_config, .set_control_line_state = ch34x_set_modem_ctrl, - .set_baudrate = ch34x_set_baudrate + .set_baudrate = ch34x_set_baudrate, + .set_line_coding = ch34x_set_line_coding }, -#endif + #endif }; enum { @@ -304,6 +303,7 @@ bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); + TU_LOG_CONTROL_LINE_STATE("CDCh Local ", p_cdc->line_state); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } @@ -312,6 +312,7 @@ bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); + TU_LOG_CONTROL_LINE_STATE("CDCh Local ", p_cdc->line_state); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } @@ -322,6 +323,7 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) TU_VERIFY(p_cdc); *line_coding = p_cdc->line_coding; + TU_LOG_LINE_CODING("CDCh Get ", p_cdc->line_coding); return true; } @@ -440,7 +442,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) case FTDI_SIO_SET_BAUD_RATE: // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = _ftdi_requested_baud; + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; default: break; @@ -465,12 +467,6 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) break; #endif - #if CFG_TUH_CDC_CH34X - case SERIAL_DRIVER_CH34X: - TU_ASSERT(false, ); // see special ch34x_control_complete function - break; - #endif - default: break; } } @@ -487,7 +483,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + TU_VERIFY(driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data)); }else { // blocking xfer_result_t result = XFER_RESULT_INVALID; @@ -501,8 +497,10 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_state = (uint8_t) line_state; - return true; } + TU_LOG_CONTROL_LINE_STATE("CDCh Set ", p_cdc->line_state); + + return true; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -511,7 +509,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + TU_VERIFY(driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data)); }else { // blocking xfer_result_t result = XFER_RESULT_INVALID; @@ -525,23 +523,24 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding.bit_rate = baudrate; - return true; } + TU_LOG_BAUDRATE("CDCh Set ", p_cdc->line_coding.bit_rate); + + return true; } bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); - // only ACM support this set line coding request - TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); - TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { - return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { + TU_VERIFY(driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data)); + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -551,8 +550,10 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding = *line_coding; - return true; } + TU_LOG_LINE_CODING("CDCh Set ", p_cdc->line_coding); + + return true; } //--------------------------------------------------------------------+ @@ -684,13 +685,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d { return acm_open(daddr, itf_desc, max_len); } -<<<<<<< HEAD #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - else if ( 0xff == itf_desc->bInterfaceClass ) -======= - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X else if ( TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass ) ->>>>>>> remotes/hathach/master { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); @@ -816,6 +812,8 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); } + TU_LOG_DRV("[%u] CDCh ACM opened\r\n", daddr); + return true; } @@ -852,6 +850,12 @@ static void acm_process_config(tuh_xfer_t* xfer) TU_ATTR_FALLTHROUGH; case CONFIG_ACM_COMPLETE: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_LOG_LINE_CODING("CDCh ACM Init ", p_cdc->line_coding); + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh ACM Init", p_cdc->line_state); + #endif // itf_num+1 to account for data interface as well set_config_complete(p_cdc, idx, itf_num+1); break; @@ -893,6 +897,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); + TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -994,6 +999,12 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_ASSERT(false, false); // TODO + return false; +} + static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); @@ -1035,7 +1046,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; - _ftdi_requested_baud = baudrate; + p_cdc->baudrate_requested = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1088,6 +1099,14 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_COMPLETE: set_config_complete(p_cdc, idx, itf_num); + #if 0 // TODO set data format + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_LOG_LINE_CODING("CDCh FTDI Init ", p_cdc->line_coding); + #endif + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh FTDI Init ", p_cdc->line_state); + #endif break; default: @@ -1166,6 +1185,12 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + TU_ASSERT(false, false); // TODO + return false; +} + static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); @@ -1224,6 +1249,12 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_COMPLETE: set_config_complete(p_cdc, idx, itf_num); + #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now + TU_LOG_LINE_CODING("CDCh CP210x Init ", p_cdc->line_coding); + #endif + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_LOG_CONTROL_LINE_STATE("CDCh CP210x Init ", p_cdc->line_state); + #endif break; default: break; @@ -1233,20 +1264,19 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #endif //--------------------------------------------------------------------+ -// CH34x +// CH34x (CH340 & CH341) //--------------------------------------------------------------------+ #if CFG_TUH_CDC_CH34X +#define CH34X_LOGS false + enum { - CONFIG_CH34X_STEP1 = 0, - CONFIG_CH34X_STEP2, - CONFIG_CH34X_STEP3, - CONFIG_CH34X_STEP4, - CONFIG_CH34X_STEP5, - CONFIG_CH34X_STEP6, - CONFIG_CH34X_STEP7, - CONFIG_CH34X_STEP8, + CONFIG_CH34X_READ_VERSION = 0, + CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SPECIAL_REG_WRITE, + CONFIG_CH34X_FLOW_CONTROL, + CONFIG_CH34X_MODEM_CONTROL, CONFIG_CH34X_COMPLETE }; @@ -1259,17 +1289,22 @@ static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, u cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); TU_VERIFY ( p_cdc ); - TU_LOG_DRV ( "CH34x opened\r\n" ); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; // endpoint pair tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); // data endpoints expected to be in pairs - return open_ep_stream_pair ( p_cdc, desc_ep ); + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep), false); + + TU_LOG_DRV("[%u] CDCh CH34x opened\r\n", daddr); + + return true; } -static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, + uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { @@ -1297,212 +1332,66 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .setup = &request_setup, .buffer = enum_buf, .complete_cb = complete_cb, - // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + .user_data = user_data }; return tuh_control_xfer ( &xfer ); - return false; } -static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data ); } -static bool ch341_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_control_in ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { return ch34x_set_request ( p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data ); } -static int32_t ch341_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +static bool ch34x_write_reg ( cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - return ch341_control_out ( p_cdc, CH341_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); + return ch34x_control_out ( p_cdc, CH34X_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data ); } -static int32_t ch341_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, +// uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +//{ +// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +//} + +uint8_t ch34x_xfer_get_itf_num ( tuh_xfer_t* xfer ) +// CH34x needs a special handling to get bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber +// CH340 and CH341 derivates have always only one interface, so it's OK to check only daddr { - return ch341_control_in ( p_cdc, CH341_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); -} - -/* - * The device line speed is given by the following equation: - * - * baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where - * - * 0 <= ps <= 3, - * 0 <= fact <= 1, - * 2 <= div <= 256 if fact = 0, or - * 9 <= div <= 256 if fact = 1 - */ -// calculate baudrate devisors -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_get_divisor ( cdch_interface_t* p_cdc, uint32_t speed ) -{ - uint32_t fact, div, clk_div; - bool force_fact0 = false; - int32_t ps; - static const uint32_t ch341_min_rates[] = { - CH341_MIN_RATE(0), - CH341_MIN_RATE(1), - CH341_MIN_RATE(2), - CH341_MIN_RATE(3), - }; - - /* - * Clamp to supported range, this makes the (ps < 0) and (div < 2) - * sanity checks below redundant. - */ - inline uint32_t max ( uint32_t val, uint32_t maxval ) { return val > maxval ? val : maxval; } - inline uint32_t min ( uint32_t val, uint32_t minval ) { return val < minval ? val : minval; } - inline uint32_t clamp_val ( uint32_t val, uint32_t minval, uint32_t maxval ) { return min ( max ( val, minval ), maxval ); } - speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); - - /* - * Start with highest possible base clock (fact = 1) that will give a - * divisor strictly less than 512. - */ - fact = 1; - for (ps = 3; ps >= 0; ps--) { - if (speed > ch341_min_rates[ps]) - break; - } - - if (ps < 0) - return -EINVAL; - - /* Determine corresponding divisor, rounding down. */ - clk_div = CH341_CLK_DIV(ps, fact); - div = CH341_CLKRATE / (clk_div * speed); - - /* Some devices require a lower base clock if ps < 3. */ - if (ps < 3 && (p_cdc->ch34x.quirks & CH341_QUIRK_LIMITED_PRESCALER)) - force_fact0 = true; - - /* Halve base clock (fact = 0) if required. */ - if (div < 9 || div > 255 || force_fact0) { - div /= 2; - clk_div *= 2; - fact = 0; - } - - if (div < 2) - return -EINVAL; - - /* - * Pick next divisor if resulting rate is closer to the requested one, - * scale up to avoid rounding errors on low rates. - */ - if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= - 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) - div++; - - /* - * Prefer lower base clock (fact = 0) if even divisor. - * - * Note that this makes the receiver more tolerant to errors. - */ - if (fact == 1 && div % 2 == 0) { - div /= 2; - fact = 0; - } - - return (0x100 - div) << 8 | fact << 2 | ps; -} - -// set baudrate (low level) -// do not confuse with ch34x_set_baudrate -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baud_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - int val; - - if (!baud_rate) - return -EINVAL; - - val = ch341_get_divisor(p_cdc, baud_rate); - if (val < 0) - return -EINVAL; - - /* - * CH341A buffers data until a full endpoint-size packet (32 bytes) - * has been received unless bit 7 is set. - * - * At least one device with version 0x27 appears to have this bit - * inverted. - */ - if ( p_cdc->ch34x.version > 0x27 ) - val |= BIT(7); - - return ch341_write_reg ( p_cdc, CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, val, complete_cb, user_data ); -} - -// set lcr register -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_lcr ( cdch_interface_t* p_cdc, uint8_t lcr, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - /* - * Chip versions before version 0x30 as read using - * CH341_REQ_READ_VERSION used separate registers for line control - * (stop bits, parity and word length). Version 0x30 and above use - * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. - */ - if ( p_cdc->ch34x.version < 0x30 ) - return 0; - - return ch341_write_reg ( p_cdc, CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr, complete_cb, user_data ); -} - -// set handshake (modem controls) -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_set_handshake ( cdch_interface_t* p_cdc, uint8_t control, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - return ch341_control_out ( p_cdc, CH341_REQ_MODEM_CTRL, /* value */ ~control, /* index */ 0, complete_cb, user_data ); -} - -// detect quirks (special versions of CH34x) -// Parts of this functions have been taken over from Linux driver /drivers/usb/serial/ch341.c -static int32_t ch341_detect_quirks ( tuh_xfer_t* xfer, cdch_interface_t* p_cdc, uint8_t step, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ - /* - * A subset of CH34x devices does not support all features. The - * prescaler is limited and there is no support for sending a RS232 - * break condition. A read failure when trying to set up the latter is - * used to detect these devices. - */ - switch ( step ) + for ( uint8_t i=0; ich34x.quirks = 0; - return ch341_read_reg_request ( p_cdc, CH341_REG_BREAK, buffer, buffersize, complete_cb, user_data ); - break; - case 2: - if ( xfer->result != XFER_RESULT_SUCCESS ) - p_cdc->ch34x.quirks |= CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; - return true; - break; - default: - TU_ASSERT ( false ); // suspicious step - break; + const cdch_interface_t* p_cdc = &cdch_data[i]; + if ( p_cdc->daddr == xfer->daddr ) return p_cdc->bInterfaceNumber; } + + return INTERFACE_INVALID_NUMBER; } // internal control complete to update state such as line state, encoding -// CH34x needs a special interface recovery due to abnormal wIndex usage -static void ch34x_control_complete(tuh_xfer_t* xfer) +static void ch34x_control_complete ( tuh_xfer_t* xfer ) { - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); + uint8_t const itf_num = ch34x_xfer_get_itf_num ( xfer ); uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); cdch_interface_t *p_cdc = get_itf ( idx ); + uint16_t value = tu_le16toh ( xfer->setup->wValue ); TU_ASSERT ( p_cdc, ); TU_ASSERT ( p_cdc->serial_drid == SERIAL_DRIVER_CH34X, ); // ch34x_control_complete is only used for CH34x - if (xfer->result == XFER_RESULT_SUCCESS) { - switch (xfer->setup->bRequest) { - case CH341_REQ_WRITE_REG: { // register write request - switch ( tu_le16toh ( xfer->setup->wValue ) ) { - case ( CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER ): { // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->ch34x.baud_rate; + if ( xfer->result == XFER_RESULT_SUCCESS ) { + switch ( xfer->setup->bRequest ) { + case CH34X_REQ_WRITE_REG: { // register write request + switch ( value ) { + case ( 0x1312 ): { // baudrate write + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + #if CH34X_LOGS + TU_LOG_BAUDRATE("CDCh CH34x Control Complete ", p_cdc->line_coding.bit_rate); + #endif break; } default: { @@ -1512,6 +1401,20 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) } break; } + case CH34X_REQ_MODEM_CTRL: { // set modem controls RTS/DTR request + if ( ~value & CH34X_BIT_RTS ) + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + else + p_cdc->line_state &= ~CDC_CONTROL_LINE_STATE_RTS; + if ( ~value & CH34X_BIT_DTR ) + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + else + p_cdc->line_state &= ~CDC_CONTROL_LINE_STATE_DTR; + #if CH34X_LOGS + TU_LOG_CONTROL_LINE_STATE("CDCh CH34x Control Complete ", p_cdc->line_state); + #endif + break; + } default: { TU_ASSERT(false, ); // unexpected request break; @@ -1523,118 +1426,161 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) } } -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) // do not confuse with ch341_set_baudrate +static bool ch34x_get_factor_divisor ( uint32_t baval, uint8_t *factor, uint8_t *divisor ) +{ // calc baudrate factor and divisor + uint8_t a; + uint8_t b; + uint32_t c; + + switch (baval) { + case 921600: + a = 0xf3; + b = 7; + break; + case 307200: + a = 0xd9; + b = 7; + break; + default: + if (baval > 6000000 / 255) { + b = 3; + c = 6000000; + } else if (baval > 750000 / 255) { + b = 2; + c = 750000; + } else if (baval > 93750 / 255) { + b = 1; + c = 93750; + } else { + b = 0; + c = 11719; + } + a = (unsigned char)(c / baval); + if (a == 0 || a == 0xFF) + return false; + if ((c / a - baval) > (baval - c / (a + 1))) + a++; + a = 256 - a; + break; + } + *factor = a; + *divisor = b; + + return true; +} + +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CH34x Set BaudRate = %lu\r\n", baudrate); - uint32_t baud_le = tu_htole32(baudrate); - p_cdc->ch34x.baud_rate = baudrate; + TU_ASSERT(false, false); // TODO + return false; +} + +static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + p_cdc->baudrate_requested = baudrate; p_cdc->user_control_cb = complete_cb; - return ch341_set_baudrate ( p_cdc, baud_le, complete_cb ? ch34x_control_complete : NULL, user_data ); + uint8_t factor, divisor; + TU_ASSERT ( ch34x_get_factor_divisor ( baudrate, &factor, &divisor ), false ); + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x1312, /* value */ (uint16_t)factor << 8 | 0x80 | divisor, + complete_cb ? ch34x_control_complete : NULL, user_data ), false ); + + return true; } static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { - TU_LOG_DRV("CDC CH34x Set Control Line State\r\n"); - // todo later - return false; + p_cdc->user_control_cb = complete_cb; + uint16_t control = 0; + if ( line_state & CDC_CONTROL_LINE_STATE_RTS ) + control |= CH34X_BIT_RTS; + if ( line_state & CDC_CONTROL_LINE_STATE_DTR ) + control |= CH34X_BIT_DTR; + TU_ASSERT ( ch34x_control_out ( p_cdc, /* request */ CH34X_REQ_MODEM_CTRL, /* value */ (uint8_t)~control, + /* index */ 0, complete_cb ? ch34x_control_complete : NULL, user_data ), false ); + return true; } static void ch34x_process_config ( tuh_xfer_t* xfer ) { - uintptr_t const state = xfer->user_data & 0xff; - // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - uint8_t const itf_num = (uint8_t)( ( xfer->user_data & 0xff00 ) >> 8 ); - uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); - cdch_interface_t *p_cdc = get_itf ( idx ); - uint8_t buffer [ CH34X_BUFFER_SIZE ]; - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + uint8_t const itf_num = ch34x_xfer_get_itf_num ( xfer ); + uintptr_t const state = xfer->user_data; + uint8_t const idx = tuh_cdc_itf_get_index ( xfer->daddr, itf_num ); + cdch_interface_t *p_cdc = get_itf ( idx ); + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint8_t buffer[2]; TU_ASSERT ( p_cdc, ); - if ( state == 0 ) { - // defaults - p_cdc->ch34x.baud_rate = DEFAULT_BAUD_RATE; - p_cdc->ch34x.mcr = 0; - p_cdc->ch34x.msr = 0; - p_cdc->ch34x.quirks = 0; - p_cdc->ch34x.version = 0; - /* - * Some CH340 devices appear unable to change the initial LCR - * settings, so set a sane 8N1 default. - */ - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; - } - // This process flow has been taken over from Linux driver /drivers/usb/serial/ch341.c switch ( state ) { - case CONFIG_CH34X_STEP1: // request version read - TU_ASSERT ( ch341_control_in ( p_cdc, /* request */ CH341_REQ_READ_VERSION, /* value */ 0, /* index */ 0, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP2 ), ); + case CONFIG_CH34X_READ_VERSION: // request version read + #if CH34X_LOGS + TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); + #endif + TU_ASSERT ( ch34x_control_in ( p_cdc, /* request */ CH34X_REQ_READ_VERSION, /* value */ 0, + /* index */ 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT ), ); break; - case CONFIG_CH34X_STEP2: // handle version read data, request to init CH34x - p_cdc->ch34x.version = xfer->buffer[0]; - TU_LOG_DRV ( "Chip version=%02x\r\n", p_cdc->ch34x.version ); - TU_ASSERT ( ch341_control_out ( p_cdc, /* request */ CH341_REQ_SERIAL_INIT, /* value */ 0, /* index */ 0, ch34x_process_config, CONFIG_CH34X_STEP3 ), ); - break; - case CONFIG_CH34X_STEP3: // set baudrate with default values (see above) - TU_ASSERT ( ch341_set_baudrate ( p_cdc, p_cdc->ch34x.baud_rate, ch34x_process_config, CONFIG_CH34X_STEP4 ) > 0, ); - break; - case CONFIG_CH34X_STEP4: // set line controls with default values (see above) - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_STEP5 ) > 0, ); - break; - case CONFIG_CH34X_STEP5: // set handshake RTS/DTR - TU_ASSERT ( ch341_set_handshake ( p_cdc, p_cdc->ch34x.mcr, ch34x_process_config, CONFIG_CH34X_STEP6 ) > 0, ); - break; - case CONFIG_CH34X_STEP6: // detect quirks step 1 - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 1, buffer, CH34X_BUFFER_SIZE, ch34x_process_config, CONFIG_CH34X_STEP7 ) > 0, ); - break; - case CONFIG_CH34X_STEP7: // detect quirks step 2 and set baudrate with configured values - TU_ASSERT ( ch341_detect_quirks ( xfer, p_cdc, /* step */ 2, NULL, 0, NULL, 0 ) > 0, ); -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT ( ch34x_set_baudrate ( p_cdc, line_coding.bit_rate, ch34x_process_config, CONFIG_CH34X_STEP8 ), ); -#else - TU_ATTR_FALLTHROUGH; -#endif - break; - case CONFIG_CH34X_STEP8: // set data/stop bit quantities, parity -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->ch34x.lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate + uint8_t version = xfer->buffer[0]; + #if CH34X_LOGS + TU_LOG_DRV ( "[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version ); + #endif + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers + TU_ASSERT ( version >= 0x30, ); + uint8_t factor, divisor; + TU_ASSERT ( ch34x_get_factor_divisor ( line_coding.bit_rate, &factor, &divisor ), ); + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; switch ( line_coding.data_bits ) { case 5: - p_cdc->ch34x.lcr |= CH341_LCR_CS5; + lcr |= CH34X_LCR_CS5; break; case 6: - p_cdc->ch34x.lcr |= CH341_LCR_CS6; + lcr |= CH34X_LCR_CS6; break; case 7: - p_cdc->ch34x.lcr |= CH341_LCR_CS7; + lcr |= CH34X_LCR_CS7; break; case 8: - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + lcr |= CH34X_LCR_CS8; break; default: TU_ASSERT ( false, ); // not supported data_bits - p_cdc->ch34x.lcr |= CH341_LCR_CS8; + lcr |= CH34X_LCR_CS8; break; } if ( line_coding.parity != CDC_LINE_CODING_PARITY_NONE ) { - p_cdc->ch34x.lcr |= CH341_LCR_ENABLE_PAR; + lcr |= CH34X_LCR_ENABLE_PAR; if ( line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_PAR_EVEN; + lcr |= CH34X_LCR_PAR_EVEN; if ( line_coding.parity == CDC_LINE_CODING_PARITY_MARK || line_coding.parity == CDC_LINE_CODING_PARITY_SPACE ) - p_cdc->ch34x.lcr |= CH341_LCR_MARK_SPACE; + lcr |= CH34X_LCR_MARK_SPACE; } TU_ASSERT ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2, ); // not supported 1.5 stop bits if ( line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2 ) - p_cdc->ch34x.lcr |= CH341_LCR_STOP_BITS_2; - TU_ASSERT ( ch341_set_lcr ( p_cdc, p_cdc->ch34x.lcr, ch34x_process_config, CONFIG_CH34X_COMPLETE ) > 0, ); -#else - TU_ATTR_FALLTHROUGH; -#endif + lcr |= CH34X_LCR_STOP_BITS_2; + TU_ASSERT ( ch34x_control_out ( p_cdc, /* request */ CH34X_REQ_SERIAL_INIT, /* value */ (uint16_t)lcr << 8 | 0x9c, + /* index */ (uint16_t)factor << 8 | 0x80 | divisor, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE ), ); + break; + } + case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x0f2c, /* value */ 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL ), ); + break; + case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control + TU_ASSERT ( ch34x_write_reg ( p_cdc, /* reg */ 0x2727, /* value */ 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL ), ); + break; + case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT ( ch34x_set_modem_ctrl ( p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE ), ); + break; + case CONFIG_CH34X_COMPLETE: + p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete + #if CH34X_LOGS + TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); + TU_LOG_LINE_CODING(" ", p_cdc->line_coding); + TU_LOG_CONTROL_LINE_STATE(" ", p_cdc->line_state); + #endif + set_config_complete ( p_cdc, idx, itf_num ); + break; + default: + TU_ASSERT ( false, ); break; - case CONFIG_CH34X_COMPLETE: - set_config_complete ( p_cdc, idx, itf_num ); - break; - default: - TU_ASSERT ( false, ); - break; } } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9e5edd94e..8e3a2352a 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,7 +37,7 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +// Set Line Control state on enumeration/mounted, refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR #ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 #endif @@ -142,7 +142,7 @@ bool tuh_cdc_read_clear (uint8_t idx); // - The function will return true if transfer is successful, false otherwise. //--------------------------------------------------------------------+ -// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State, refer enums CDC_CONTROL_LINE_STATE_RTS, CDC_CONTROL_LINE_STATE_DTR bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to set baudrate diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 94e18b252..262e012fd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * Copyright (c) 2023 IngHK Heiko Kuester (tinyusb.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,87 +27,34 @@ #ifndef _CH34X_H_ #define _CH34X_H_ -#include - -#define BIT(nr) ( (uint32_t)1 << (nr) ) - -#define CH34X_BUFFER_SIZE 2 - -// The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c - -#define DEFAULT_BAUD_RATE 9600 - -/* flags for IO-Bits */ -#define CH341_BIT_RTS (1 << 6) -#define CH341_BIT_DTR (1 << 5) - -/******************************/ -/* interrupt pipe definitions */ -/******************************/ -/* always 4 interrupt bytes */ -/* first irq byte normally 0x08 */ -/* second irq byte base 0x7d + below */ -/* third irq byte base 0x94 + below */ -/* fourth irq byte normally 0xee */ - -/* second interrupt byte */ -#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ - -/* status returned in third interrupt answer byte, inverted in data - from irq */ -#define CH341_BIT_CTS 0x01 -#define CH341_BIT_DSR 0x02 -#define CH341_BIT_RI 0x04 -#define CH341_BIT_DCD 0x08 -#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ - -/* Break support - the information used to implement this was gleaned from - * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. - */ +// set line_coding @ enumeration +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM +#else // this default is necessary to work properly +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#endif // USB requests -#define CH341_REQ_READ_VERSION 0x5F // dec 95 -#define CH341_REQ_WRITE_REG 0x9A -#define CH341_REQ_READ_REG 0x95 -#define CH341_REQ_SERIAL_INIT 0xA1 -#define CH341_REQ_MODEM_CTRL 0xA4 +#define CH34X_REQ_READ_VERSION 0x5F // dec 95 +#define CH34X_REQ_WRITE_REG 0x9A // dec 154 +#define CH34X_REQ_READ_REG 0x95 // dec 149 +#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 +#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 -// CH34x registers -#define CH341_REG_BREAK 0x05 -#define CH341_REG_PRESCALER 0x12 -#define CH341_REG_DIVISOR 0x13 -#define CH341_REG_LCR 0x18 -#define CH341_REG_LCR2 0x25 - -#define CH341_NBREAK_BITS 0x01 +// modem control bits +#define CH34X_BIT_RTS ( 1 << 6 ) +#define CH34X_BIT_DTR ( 1 << 5 ) // line control bits -#define CH341_LCR_ENABLE_RX 0x80 -#define CH341_LCR_ENABLE_TX 0x40 -#define CH341_LCR_MARK_SPACE 0x20 -#define CH341_LCR_PAR_EVEN 0x10 -#define CH341_LCR_ENABLE_PAR 0x08 -#define CH341_LCR_STOP_BITS_2 0x04 -#define CH341_LCR_CS8 0x03 -#define CH341_LCR_CS7 0x02 -#define CH341_LCR_CS6 0x01 -#define CH341_LCR_CS5 0x00 - -#define CH341_QUIRK_LIMITED_PRESCALER BIT(0) -#define CH341_QUIRK_SIMULATE_BREAK BIT(1) - -#define CH341_CLKRATE 48000000 -#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) -#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) - -/* Supported range is 46 to 3000000 bps. */ -#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) -#define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) - -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP -#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -// error codes -#define EINVAL 22 /* Invalid argument */ +#define CH34X_LCR_ENABLE_RX 0x80 +#define CH34X_LCR_ENABLE_TX 0x40 +#define CH34X_LCR_MARK_SPACE 0x20 +#define CH34X_LCR_PAR_EVEN 0x10 +#define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_STOP_BITS_2 0x04 +#define CH34X_LCR_CS8 0x03 +#define CH34X_LCR_CS7 0x02 +#define CH34X_LCR_CS6 0x01 +#define CH34X_LCR_CS5 0x00 #endif /* _CH34X_H_ */ From 07e3d5c69192b1c45d52fc9760ab0ee65d8b0f0c Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 13:16:53 +0700 Subject: [PATCH 22/41] fix number of endpoint for ch340x, also open notification even not used for now --- src/class/cdc/cdc_host.c | 67 +++++++++++++++++++----------------- src/class/cdc/serial/ch34x.h | 6 ++-- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 91e35ec8c..f7213d558 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -471,9 +471,9 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); @@ -494,9 +494,9 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - if ( complete_cb ) { + if (complete_cb) { return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); @@ -512,16 +512,15 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); // only ACM support this set line coding request TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM); TU_VERIFY(p_cdc->acm_capability.support_line_request); - if ( complete_cb ) { + if (complete_cb) { return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data); - }else { + } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); @@ -711,7 +710,6 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// @@ -881,7 +879,6 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint TU_VERIFY(p_cdc); TU_LOG_DRV("FTDI opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair @@ -921,8 +918,7 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } -static bool -ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, @@ -1171,26 +1167,34 @@ enum { CONFIG_CH34X_COMPLETE }; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ) { - // CH34x Interface includes 1 vendor interface + 3 bulk endpoints - TU_VERIFY ( itf_desc->bNumEndpoints == 3 ); - TU_VERIFY ( sizeof ( tusb_desc_interface_t ) + 2 * sizeof ( tusb_desc_endpoint_t ) <= max_len ); +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints + TU_VERIFY (itf_desc->bNumEndpoints == 3); + TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t *p_cdc = make_new_itf ( daddr, itf_desc ); - TU_VERIFY ( p_cdc ); + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY (p_cdc); - TU_LOG_DRV ( "CH34x opened\r\n" ); + TU_LOG_DRV ("CH34x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next ( itf_desc ); + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); // data endpoints expected to be in pairs - return open_ep_stream_pair ( p_cdc, desc_ep ); + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + desc_ep += 2; + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + return true; } -static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, + uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1198,17 +1202,17 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .direction = direction & 0x01u }, .bRequest = request, - .wValue = tu_htole16 ( value ), - .wIndex = tu_htole16 ( index ), - .wLength = tu_htole16 ( length ) + .wValue = tu_htole16 (value), + .wIndex = tu_htole16 (index), + .wLength = tu_htole16 (length) }; // use usbh enum buf since application variable does not live long enough uint8_t* enum_buf = NULL; - if ( buffer && length > 0 ) { + if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); - tu_memcpy_s ( enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length ); + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); } tuh_xfer_t xfer = { @@ -1218,11 +1222,10 @@ static bool ch34x_set_request ( cdch_interface_t* p_cdc, uint8_t direction, uint .buffer = enum_buf, .complete_cb = complete_cb, // CH34x needs a special handling of bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber - .user_data = (uintptr_t)( ( p_cdc->bInterfaceNumber & 0xff ) << 8 ) | ( user_data & 0xff ) + .user_data = (uintptr_t) ((p_cdc->bInterfaceNumber & 0xff) << 8) | (user_data & 0xff) }; - return tuh_control_xfer ( &xfer ); - return false; + return tuh_control_xfer(&xfer); } static bool ch341_control_out ( cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 4a5e61bbd..cc3ac99fe 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 Heiko Kuester (tinyusb.org) + * Copyright (c) 2023 Heiko Kuester * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ #define CH34X_BUFFER_SIZE 2 // The following defines have been taken over from Linux driver /drivers/usb/serial/ch341.c +// Note: updated driver can also be found in https://github.com/WCHSoftGroup/ch341ser_linux/tree/main/driver #define DEFAULT_BAUD_RATE 9600 @@ -53,8 +54,7 @@ /* second interrupt byte */ #define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ -/* status returned in third interrupt answer byte, inverted in data - from irq */ +/* status returned in third interrupt answer byte, inverted in data from irq */ #define CH341_BIT_CTS 0x01 #define CH341_BIT_DSR 0x02 #define CH341_BIT_RI 0x04 From 46ac03ba8537a32ae2bf1f7d864879657b696f81 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 16 Jan 2024 17:45:16 +0700 Subject: [PATCH 23/41] change code style --- src/class/cdc/cdc_host.c | 97 +++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8ef26a7d9..5541b5dee 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1291,25 +1291,22 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { if (xfer->result == XFER_RESULT_SUCCESS) { switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: { // register write request + case CH34X_REQ_WRITE_REG: + // register write request switch (value) { - case (0x1312): { // baudrate write + case (0x1312): + // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; - #if CH34X_LOGS - TU_LOG_BAUDRATE("CDCh CH34x Control Complete ", p_cdc->line_coding.bit_rate); - #endif break; - } - default: { + default: TU_ASSERT(false,); // unexpected register write break; - } } break; - } - case CH34X_REQ_MODEM_CTRL: { // set modem controls RTS/DTR request + case CH34X_REQ_MODEM_CTRL: + // set modem controls RTS/DTR request if (~value & CH34X_BIT_RTS) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; } else { @@ -1322,16 +1319,11 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; } - #if CH34X_LOGS - TU_LOG_CONTROL_LINE_STATE("CDCh CH34x Control Complete ", p_cdc->line_state); - #endif break; - } - default: { + default: TU_ASSERT(false,); // unexpected request break; - } } xfer->complete_cb = p_cdc->user_control_cb; @@ -1393,33 +1385,31 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t con return false; } -static bool -ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->baudrate_requested = baudrate; p_cdc->user_control_cb = complete_cb; uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor), false); + TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor)); uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); - TU_ASSERT ( - ch34x_write_reg(p_cdc, /* reg */ 0x1312, /* value */ value, - complete_cb ? ch34x_control_complete : NULL, user_data), false); + TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } -static bool -ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; uint16_t control = 0; - if (line_state & CDC_CONTROL_LINE_STATE_RTS) + if (line_state & CDC_CONTROL_LINE_STATE_RTS) { control |= CH34X_BIT_RTS; - if (line_state & CDC_CONTROL_LINE_STATE_DTR) + } + if (line_state & CDC_CONTROL_LINE_STATE_DTR) { control |= CH34X_BIT_DTR; - TU_ASSERT ( - ch34x_control_out(p_cdc, /* request */ CH34X_REQ_MODEM_CTRL, /* value */ (uint8_t) ~control, - /* index */ 0, complete_cb ? ch34x_control_complete : NULL, user_data), false); + } + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, (uint8_t) ~control, 0, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } @@ -1437,9 +1427,9 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { #if CH34X_LOGS TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); #endif - TU_ASSERT (ch34x_control_in(p_cdc, /* request */ CH34X_REQ_READ_VERSION, /* value */ 0, - /* index */ 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; #if CH34X_LOGS @@ -1468,46 +1458,51 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { lcr |= CH34X_LCR_CS8; break; } + if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { lcr |= CH34X_LCR_ENABLE_PAR; if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { lcr |= CH34X_LCR_PAR_EVEN; + } if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) + line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { lcr |= CH34X_LCR_MARK_SPACE; + } } TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits - if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) + if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; - TU_ASSERT (ch34x_control_out(p_cdc, /* request */ CH34X_REQ_SERIAL_INIT, /* value */ - (uint16_t) (lcr << 8 | 0x9c), - /* index */ (uint16_t) (factor << 8 | 0x80 | divisor), ch34x_process_config, - CONFIG_CH34X_SPECIAL_REG_WRITE),); + } + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } - case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver - TU_ASSERT (ch34x_write_reg(p_cdc, /* reg */ 0x0f2c, /* value */ 0x0007, ch34x_process_config, - CONFIG_CH34X_FLOW_CONTROL),); + + case CONFIG_CH34X_SPECIAL_REG_WRITE: + // do special reg write, purpose unknown, overtaken from WCH driver + TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; - case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, /* reg */ 0x2727, /* value */ 0x0000, ch34x_process_config, - CONFIG_CH34X_MODEM_CONTROL),); + + case CONFIG_CH34X_FLOW_CONTROL: + // no hardware flow control + TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; - case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, - CONFIG_CH34X_COMPLETE),); + + case CONFIG_CH34X_MODEM_CONTROL: + // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; + case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete #if CH34X_LOGS TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); - TU_LOG_LINE_CODING(" ", p_cdc->line_coding); - TU_LOG_CONTROL_LINE_STATE(" ", p_cdc->line_state); #endif set_config_complete(p_cdc, idx, itf_num); break; + default: TU_ASSERT (false,); break; From 482a8068a51025ee8c31ccdb4355801c185172cc Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 16 Jan 2024 14:51:04 +0100 Subject: [PATCH 24/41] change code style and code cleanup --- src/class/cdc/cdc_host.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5541b5dee..4cecc79a1 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1260,13 +1260,13 @@ static bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t } static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, /* value */ reg, /* index */ value, complete_cb, user_data); + return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, value, complete_cb, user_data); } //static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, // uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) //{ -// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, /* index */ 0, buffer, buffersize, complete_cb, user_data ); +// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} uint8_t ch34x_xfer_get_itf_num(tuh_xfer_t* xfer) { @@ -1327,7 +1327,9 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb)xfer->complete_cb(xfer); + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } } } @@ -1363,8 +1365,12 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d c = 11719; } a = (unsigned char) (c / baval); - if (a == 0 || a == 0xFF) return false; - if ((c / a - baval) > (baval - c / (a + 1))) a++; + if (a == 0 || a == 0xFF) { + return false; + } + if ((c / a - baval) > (baval - c / (a + 1))) { + a++; + } a = (uint8_t) (256 - a); break; } @@ -1425,7 +1431,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: // request version read #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); + TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); #endif TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; @@ -1433,7 +1439,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version ); + TU_LOG_DRV("[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version); #endif // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers TU_ASSERT (version >= 0x30,); @@ -1470,8 +1476,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { lcr |= CH34X_LCR_MARK_SPACE; } } - TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || line_coding.stop_bits == - CDC_LINE_CODING_STOP_BITS_2,); // not supported 1.5 stop bits + TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || + line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // 1.5 stop bits not supported if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; } @@ -1498,7 +1504,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete #if CH34X_LOGS - TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); + TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); #endif set_config_complete(p_cdc, idx, itf_num); break; From f221c0fb6683fc552febbb9a52300d66f031d275 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 17 Jan 2024 14:45:09 +0700 Subject: [PATCH 25/41] more clean up --- src/class/cdc/cdc_host.c | 28 ++++++++++------------------ src/class/cdc/serial/ch34x.h | 13 +++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4cecc79a1..faee062cf 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -670,6 +670,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { + TU_LOG_DRV("CDCh Set Configure complete\r\n"); if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data @@ -1176,8 +1177,6 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -#define CH34X_LOGS false - enum { CONFIG_CH34X_READ_VERSION = 0, CONFIG_CH34X_SERIAL_INIT, @@ -1247,14 +1246,13 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -static bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, /* buffer */ NULL, /* length */ 0, complete_cb, user_data); +static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); } -static bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, - uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, - uintptr_t user_data) { +static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data); } @@ -1425,27 +1423,24 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint8_t buffer[2]; + uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); switch (state) { case CONFIG_CH34X_READ_VERSION: // request version read - #if CH34X_LOGS - TU_LOG_DRV ( "[%u] CDCh CH34x Process Config started\r\n", p_cdc->daddr ); - #endif + TU_LOG_DRV("[%u] CDCh CH34x attempt to read version\r\n", p_cdc->daddr); TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate uint8_t version = xfer->buffer[0]; - #if CH34X_LOGS - TU_LOG_DRV("[%u] CDCh CH34x Chip version=%02x\r\n", p_cdc->daddr, version); - #endif + TU_LOG_DRV("[%u] CDCh CH34x Chip version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers TU_ASSERT (version >= 0x30,); uint8_t factor, divisor; TU_ASSERT (ch34x_get_factor_divisor(line_coding.bit_rate, &factor, &divisor),); uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + switch (line_coding.data_bits) { case 5: lcr |= CH34X_LCR_CS5; @@ -1503,9 +1498,6 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_COMPLETE: p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete - #if CH34X_LOGS - TU_LOG_DRV("CDCh CH34x Process Config Complete\r\n"); - #endif set_config_complete(p_cdc, idx, itf_num); break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 557e093a9..54b5b3560 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,6 +27,10 @@ #ifndef _CH34X_H_ #define _CH34X_H_ +// There is no official documentation for the CH34x chips. Reference can be found +// - https://github.com/WCHSoftGroup/ch341ser_linux +// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c + // set line_coding @ enumeration #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM @@ -41,6 +45,15 @@ #define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 #define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 +#define CH34X_REG_BREAK 0x05 +#define CH34X_REG_PRESCALER 0x12 +#define CH34X_REG_DIVISOR 0x13 +#define CH34X_REG_LCR 0x18 +#define CH34X_REG_LCR2 0x25 +#define CH34X_REG_MCR_MSR 0x06 +#define CH34X_REG_MCR_MSR2 0x07 +#define CH34X_NBREAK_BITS 0x01 + // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) #define CH34X_BIT_DTR ( 1 << 5 ) From 3968a0fff87c794266284af7901e334d122e894c Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 17 Jan 2024 16:04:31 +0100 Subject: [PATCH 26/41] implemented ch34x_set_line_coding() and some code cleanup --- src/class/cdc/cdc_host.c | 177 +++++++++++++++++++++-------------- src/class/cdc/serial/ch34x.h | 7 ++ 2 files changed, 116 insertions(+), 68 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index faee062cf..45a03a31d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1179,7 +1179,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { enum { CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SET_LINE_CODING, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, CONFIG_CH34X_MODEM_CONTROL, @@ -1292,11 +1292,10 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { case CH34X_REQ_WRITE_REG: // register write request switch (value) { - case (0x1312): + case 0x1312: // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; - default: TU_ASSERT(false,); // unexpected register write break; @@ -1310,13 +1309,60 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; } - if (~value & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; } + break; + case CH34X_REQ_SERIAL_INIT: + // serial init request (set line coding incl. baudrate) + p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + uint8_t lcr = (uint8_t) (value >> 8); + TU_ASSERT (lcr & CH34X_LCR_ENABLE_RX && lcr & CH34X_LCR_ENABLE_TX,); // both have to be enabled + switch (lcr & CH34X_LCR_CS_MASK) { + case CH34X_LCR_CS5: + p_cdc->line_coding.data_bits = 5; + break; + case CH34X_LCR_CS6: + p_cdc->line_coding.data_bits = 6; + break; + case CH34X_LCR_CS7: + p_cdc->line_coding.data_bits = 7; + break; + case CH34X_LCR_CS8: + p_cdc->line_coding.data_bits = 8; + break; + default: + TU_ASSERT (false,); // unexpected data_bits lcr + break; + } + if (lcr & CH34X_LCR_STOP_BITS_2) { + p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_2; + } else { + p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_1; + } + switch (lcr & CH34X_LCR_PAR_MASK) { + case 0: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_NONE; + break; + case CH34X_LCR_ENABLE_PAR: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_ODD; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_EVEN; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_MARK; + break; + case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN: + p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_SPACE; + break; + default: + TU_ASSERT (false,); // unexpected parity lcr + break; + } break; default: @@ -1378,15 +1424,57 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d return true; } +// calc lcr register value (data bits, parity, stop bits) +static bool ch34x_get_lcr(cdc_line_coding_t const* line_coding, uint8_t *lcr) { + *lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + switch (line_coding->data_bits) { + case 5: + *lcr |= CH34X_LCR_CS5; + break; + case 6: + *lcr |= CH34X_LCR_CS6; + break; + case 7: + *lcr |= CH34X_LCR_CS7; + break; + case 8: + *lcr |= CH34X_LCR_CS8; + break; + default: + TU_ASSERT (false); // data_bits not supported + break; + } + TU_ASSERT (line_coding->parity == CDC_LINE_CODING_PARITY_NONE || // supported parities + line_coding->parity == CDC_LINE_CODING_PARITY_ODD || line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || + line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE); + if (line_coding->parity != CDC_LINE_CODING_PARITY_NONE) { + *lcr |= CH34X_LCR_ENABLE_PAR; + if (line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { + *lcr |= CH34X_LCR_PAR_EVEN; + } + if (line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { + *lcr |= CH34X_LCR_MARK_SPACE; + } + } + TU_ASSERT (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_1 || + line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2); // not supported 1.5 stop bits + if (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + *lcr |= CH34X_LCR_STOP_BITS_2; + } + + return true; +} + static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // TODO implement later - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; - - return false; + p_cdc->baudrate_requested = line_coding->bit_rate; + p_cdc->user_control_cb = complete_cb; + uint8_t factor, divisor, lcr; + TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); + TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; } static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, @@ -1398,7 +1486,6 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, complete_cb ? ch34x_control_complete : NULL, user_data)); - return true; } @@ -1427,82 +1514,36 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_ASSERT (p_cdc,); switch (state) { - case CONFIG_CH34X_READ_VERSION: // request version read - TU_LOG_DRV("[%u] CDCh CH34x attempt to read version\r\n", p_cdc->daddr); - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + case CONFIG_CH34X_READ_VERSION: + // version read request + TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SET_LINE_CODING),); break; - - case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate + case CONFIG_CH34X_SET_LINE_CODING: + // handle version read data, set CH34x line coding (incl. baudrate) uint8_t version = xfer->buffer[0]; - TU_LOG_DRV("[%u] CDCh CH34x Chip version = %02x\r\n", p_cdc->daddr, version); - // only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers + TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(line_coding.bit_rate, &factor, &divisor),); - uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - - switch (line_coding.data_bits) { - case 5: - lcr |= CH34X_LCR_CS5; - break; - case 6: - lcr |= CH34X_LCR_CS6; - break; - case 7: - lcr |= CH34X_LCR_CS7; - break; - case 8: - lcr |= CH34X_LCR_CS8; - break; - default: - TU_ASSERT (false,); // not supported data_bits - lcr |= CH34X_LCR_CS8; - break; - } - - if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) { - lcr |= CH34X_LCR_ENABLE_PAR; - if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { - lcr |= CH34X_LCR_PAR_EVEN; - } - if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK || - line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) { - lcr |= CH34X_LCR_MARK_SPACE; - } - } - TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 || - line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // 1.5 stop bits not supported - if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) { - lcr |= CH34X_LCR_STOP_BITS_2; - } - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + TU_ASSERT (ch34x_set_line_coding(p_cdc, &line_coding, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; - } - case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; - case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; - case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; - case CONFIG_CH34X_COMPLETE: - p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete set_config_complete(p_cdc, idx, itf_num); break; - default: - TU_ASSERT (false,); + TU_ASSERT (false,); // something gone wrong, should never reached break; } } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 54b5b3560..b4ed7420c 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,9 +27,13 @@ #ifndef _CH34X_H_ #define _CH34X_H_ +// For simplicity, only the name CH34X is used here, +// but specifically only CH340 and CH341 are supported. + // There is no official documentation for the CH34x chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c +// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c // set line_coding @ enumeration #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM @@ -45,6 +49,7 @@ #define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 #define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 +// registers #define CH34X_REG_BREAK 0x05 #define CH34X_REG_PRESCALER 0x12 #define CH34X_REG_DIVISOR 0x13 @@ -64,10 +69,12 @@ #define CH34X_LCR_MARK_SPACE 0x20 #define CH34X_LCR_PAR_EVEN 0x10 #define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_PAR_MASK 0x38 // all parity bits #define CH34X_LCR_STOP_BITS_2 0x04 #define CH34X_LCR_CS8 0x03 #define CH34X_LCR_CS7 0x02 #define CH34X_LCR_CS6 0x01 #define CH34X_LCR_CS5 0x00 +#define CH34X_LCR_CS_MASK 0x03 // all CSx bits #endif /* _CH34X_H_ */ From 30eb35f17f1baa4698da0cd45dbc3dff8906d7c0 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 01:06:24 +0700 Subject: [PATCH 27/41] - revert the use of serial init for set line coding - update ch34x_get_lcr and ch34x_get_factor_divisor --- src/class/cdc/cdc_host.c | 152 +++++++++++++++++++---------------- src/class/cdc/serial/ch34x.h | 6 ++ 2 files changed, 90 insertions(+), 68 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 45a03a31d..150ac21f2 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1179,7 +1179,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { enum { CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SET_LINE_CODING, + CONFIG_CH34X_SERIAL_INIT, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, CONFIG_CH34X_MODEM_CONTROL, @@ -1231,7 +1231,9 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); - tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + if (direction == TUSB_DIR_OUT) { + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } } tuh_xfer_t xfer = { @@ -1257,8 +1259,8 @@ static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, ui complete_cb, user_data); } -static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, value, complete_cb, user_data); +static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } //static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, @@ -1292,10 +1294,11 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { case CH34X_REQ_WRITE_REG: // register write request switch (value) { - case 0x1312: + case CH34X_REG16_DIVISOR_PRESCALER: // baudrate write p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; break; + default: TU_ASSERT(false,); // unexpected register write break; @@ -1309,6 +1312,7 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } else { p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; } + if (~value & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { @@ -1377,8 +1381,8 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } } -// calc baudrate factor and divisor -static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* divisor) { +// calculate divisor and prescaler for baudrate, return it as 16-bit combined value +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t a; uint8_t b; uint32_t c; @@ -1410,7 +1414,7 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d } a = (unsigned char) (c / baval); if (a == 0 || a == 0xFF) { - return false; + return 0; } if ((c / a - baval) > (baval - c / (a + 1))) { a++; @@ -1418,74 +1422,75 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d a = (uint8_t) (256 - a); break; } - *factor = a; - *divisor = b; - return true; + // reg divisor = a, reg prescaler = b + // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, + // otherwise the chip will buffer data. + return (uint16_t) (a << 8 | 0x80 | b); } -// calc lcr register value (data bits, parity, stop bits) -static bool ch34x_get_lcr(cdc_line_coding_t const* line_coding, uint8_t *lcr) { - *lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - switch (line_coding->data_bits) { - case 5: - *lcr |= CH34X_LCR_CS5; - break; - case 6: - *lcr |= CH34X_LCR_CS6; - break; - case 7: - *lcr |= CH34X_LCR_CS7; - break; - case 8: - *lcr |= CH34X_LCR_CS8; - break; - default: - TU_ASSERT (false); // data_bits not supported - break; +static inline uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; + TU_VERIFY(data_bits >= 5, 0); + lcr |= (uint8_t) (data_bits - 5); + + if (parity) { + lcr |= CH34X_LCR_ENABLE_PAR; } - TU_ASSERT (line_coding->parity == CDC_LINE_CODING_PARITY_NONE || // supported parities - line_coding->parity == CDC_LINE_CODING_PARITY_ODD || line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || - line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE); - if (line_coding->parity != CDC_LINE_CODING_PARITY_NONE) { - *lcr |= CH34X_LCR_ENABLE_PAR; - if (line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { - *lcr |= CH34X_LCR_PAR_EVEN; - } - if (line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) { - *lcr |= CH34X_LCR_MARK_SPACE; - } + switch(parity) { + case CDC_LINE_CODING_PARITY_EVEN: + lcr |= CH34X_LCR_PAR_EVEN; + break; + + case CDC_LINE_CODING_PARITY_MARK: + lcr |= CH34X_LCR_MARK_SPACE; + break; + + case CDC_LINE_CODING_PARITY_SPACE: + lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; + break; + + default: break; } - TU_ASSERT (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_1 || - line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2); // not supported 1.5 stop bits - if (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2) { - *lcr |= CH34X_LCR_STOP_BITS_2; + + // 1.5 stop bits not supported + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { + lcr |= CH34X_LCR_STOP_BITS_2; } + return lcr; +} + +//static bool ch34x_set_line_data(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, +// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->baudrate_requested = baudrate; + p_cdc->user_control_cb = complete_cb; + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; } static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->baudrate_requested = line_coding->bit_rate; - p_cdc->user_control_cb = complete_cb; - uint8_t factor, divisor, lcr; - TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); - TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), - complete_cb ? ch34x_control_complete : NULL, user_data)); - return true; -} +// p_cdc->baudrate_requested = line_coding->bit_rate; +// p_cdc->user_control_cb = complete_cb; +// uint8_t factor, divisor, lcr; +// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); +// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); +// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), +// complete_cb ? ch34x_control_complete : NULL, user_data)); + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->baudrate_requested = baudrate; - p_cdc->user_control_cb = complete_cb; - uint8_t factor, divisor; - TU_ASSERT (ch34x_get_factor_divisor(baudrate, &factor, &divisor)); - uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor); - TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value, - complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } @@ -1515,35 +1520,46 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: - // version read request TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SET_LINE_CODING),); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; - case CONFIG_CH34X_SET_LINE_CODING: + + case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t version = xfer->buffer[0]; TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - TU_ASSERT (ch34x_set_line_coding(p_cdc, &line_coding, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); + TU_ASSERT(div_ps != 0, ); + + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; + } + case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; + case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; + case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; + case CONFIG_CH34X_COMPLETE: set_config_complete(p_cdc, idx, itf_num); break; + default: - TU_ASSERT (false,); // something gone wrong, should never reached + TU_ASSERT (false,); break; } } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index b4ed7420c..3f78a3007 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -59,6 +59,12 @@ #define CH34X_REG_MCR_MSR2 0x07 #define CH34X_NBREAK_BITS 0x01 +#define CH341_REG_0x0F 0x0F // undocumented register +#define CH341_REG_0x2C 0x2C // undocumented register +#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) + +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) + // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) #define CH34X_BIT_DTR ( 1 << 5 ) From c568a6793e99dde311802d4b4cb0633d2d6f5830 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 12:14:45 +0700 Subject: [PATCH 28/41] - add requested line coding to make update data format easier - change ch34x_xfer_get_itf_num() to simply 0 --- src/class/cdc/cdc_host.c | 321 ++++++++++++++++++--------------------- 1 file changed, 149 insertions(+), 172 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 150ac21f2..3843a8edc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -60,6 +60,11 @@ typedef struct { uint8_t line_state; // DTR (bit0), RTS (bit1) TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + cdc_line_coding_t requested_line_coding; + // 1 byte padding + #endif + tuh_xfer_cb_t user_control_cb; struct { @@ -72,10 +77,6 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; } stream; - -#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X - uint32_t baudrate_requested; -#endif } cdch_interface_t; CFG_TUH_MEM_SECTION @@ -429,7 +430,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case FTDI_SIO_SET_BAUD_RATE: // convert from divisor to baudrate is not supported - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; default: break; @@ -968,7 +969,7 @@ static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tu TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; - p_cdc->baudrate_requested = baudrate; + p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1186,6 +1187,9 @@ enum { CONFIG_CH34X_COMPLETE }; +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); +static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); + static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints TU_VERIFY (itf_desc->bNumEndpoints == 3); @@ -1269,20 +1273,10 @@ static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_ // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -uint8_t ch34x_xfer_get_itf_num(tuh_xfer_t* xfer) { -// CH34x needs a special handling to get bInterfaceNumber, because wIndex is used for other purposes and not for bInterfaceNumber -// CH340 and CH341 derivates have always only one interface, so it's OK to check only daddr - for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t* p_cdc = &cdch_data[i]; - if (p_cdc->daddr == xfer->daddr) return p_cdc->bInterfaceNumber; - } - - return INTERFACE_INVALID_NUMBER; -} - // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = ch34x_xfer_get_itf_num(xfer); + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); uint16_t value = tu_le16toh (xfer->setup->wValue); @@ -1296,7 +1290,14 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { switch (value) { case CH34X_REG16_DIVISOR_PRESCALER: // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format write + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; break; default: @@ -1305,68 +1306,26 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } break; - case CH34X_REQ_MODEM_CTRL: - // set modem controls RTS/DTR request - if (~value & CH34X_BIT_RTS) { + case CH34X_REQ_MODEM_CTRL: { + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~value; + if (modem_signal & CH34X_BIT_RTS) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; } else { - p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS; + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; } - if (~value & CH34X_BIT_DTR) { + if (modem_signal & CH34X_BIT_DTR) { p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; } else { - p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR; + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; } break; + } case CH34X_REQ_SERIAL_INIT: // serial init request (set line coding incl. baudrate) - p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested; - uint8_t lcr = (uint8_t) (value >> 8); - TU_ASSERT (lcr & CH34X_LCR_ENABLE_RX && lcr & CH34X_LCR_ENABLE_TX,); // both have to be enabled - switch (lcr & CH34X_LCR_CS_MASK) { - case CH34X_LCR_CS5: - p_cdc->line_coding.data_bits = 5; - break; - case CH34X_LCR_CS6: - p_cdc->line_coding.data_bits = 6; - break; - case CH34X_LCR_CS7: - p_cdc->line_coding.data_bits = 7; - break; - case CH34X_LCR_CS8: - p_cdc->line_coding.data_bits = 8; - break; - default: - TU_ASSERT (false,); // unexpected data_bits lcr - break; - } - if (lcr & CH34X_LCR_STOP_BITS_2) { - p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_2; - } else { - p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_1; - } - switch (lcr & CH34X_LCR_PAR_MASK) { - case 0: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_NONE; - break; - case CH34X_LCR_ENABLE_PAR: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_ODD; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_EVEN; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_MARK; - break; - case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN: - p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_SPACE; - break; - default: - TU_ASSERT (false,); // unexpected parity lcr - break; - } + p_cdc->line_coding = p_cdc->requested_line_coding; break; default: @@ -1381,6 +1340,124 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { } } +//static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, +// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +// uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); +// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, +// complete_cb ? ch34x_control_complete : NULL, user_data)); +// return false; +//} + +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->user_control_cb = complete_cb; + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb ? ch34x_control_complete : NULL, user_data)); + + return true; +} + +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +// p_cdc->baudrate_requested = line_coding->bit_rate; +// p_cdc->user_control_cb = complete_cb; +// uint8_t factor, divisor, lcr; +// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); +// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); +// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), +// complete_cb ? ch34x_control_complete : NULL, user_data)); + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + + return true; +} + +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = 0; + if (line_state & CDC_CONTROL_LINE_STATE_RTS) { + control |= CH34X_BIT_RTS; + } + if (line_state & CDC_CONTROL_LINE_STATE_DTR) { + control |= CH34X_BIT_DTR; + } + + // CH34x signals are inverted + control = ~control; + + p_cdc->user_control_cb = complete_cb; + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} + +static void ch34x_process_config(tuh_xfer_t* xfer) { + // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + uintptr_t const state = xfer->user_data; + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint8_t buffer[2]; // TODO remove + TU_ASSERT (p_cdc,); + + switch (state) { + case CONFIG_CH34X_READ_VERSION: + TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); + TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + break; + + case CONFIG_CH34X_SERIAL_INIT: { + // handle version read data, set CH34x line coding (incl. baudrate) + uint8_t const version = xfer->buffer[0]; + TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD + TU_ASSERT (version >= 0x30,); + + uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); + TU_ASSERT(div_ps != 0, ); + + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + + // Init CH34x with line coding + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + break; + } + + case CONFIG_CH34X_SPECIAL_REG_WRITE: + // do special reg write, purpose unknown, overtaken from WCH driver + p_cdc->line_coding = line_coding; + TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); + break; + + case CONFIG_CH34X_FLOW_CONTROL: + // no hardware flow control + TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + break; + + case CONFIG_CH34X_MODEM_CONTROL: + // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); + break; + + case CONFIG_CH34X_COMPLETE: + set_config_complete(p_cdc, idx, itf_num); + break; + + default: + TU_ASSERT (false,); + break; + } +} + +//------------- CH34x helper -------------// + // calculate divisor and prescaler for baudrate, return it as 16-bit combined value static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t a; @@ -1429,7 +1506,8 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { return (uint16_t) (a << 8 | 0x80 | b); } -static inline uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { +// calculate lcr value from data coding +static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5, 0); lcr |= (uint8_t) (data_bits - 5); @@ -1462,107 +1540,6 @@ static inline uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t d return lcr; } -//static bool ch34x_set_line_data(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, -// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->baudrate_requested = baudrate; - p_cdc->user_control_cb = complete_cb; - uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); - TU_VERIFY(div_ps != 0); - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb ? ch34x_control_complete : NULL, user_data)); - - return true; -} - -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -// p_cdc->baudrate_requested = line_coding->bit_rate; -// p_cdc->user_control_cb = complete_cb; -// uint8_t factor, divisor, lcr; -// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); -// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); -// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), -// complete_cb ? ch34x_control_complete : NULL, user_data)); - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; - - return true; -} - -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; - uint16_t control = 0; - if (line_state & CDC_CONTROL_LINE_STATE_RTS) { - control |= CH34X_BIT_RTS; - } - if (line_state & CDC_CONTROL_LINE_STATE_DTR) { - control |= CH34X_BIT_DTR; - } - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, (uint8_t) ~control, 0, - complete_cb ? ch34x_control_complete : NULL, user_data)); - return true; -} - -static void ch34x_process_config(tuh_xfer_t* xfer) { - uint8_t const itf_num = ch34x_xfer_get_itf_num(xfer); - uintptr_t const state = xfer->user_data; - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint8_t buffer[2]; // TODO remove - TU_ASSERT (p_cdc,); - - switch (state) { - case CONFIG_CH34X_READ_VERSION: - TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); - break; - - case CONFIG_CH34X_SERIAL_INIT: { - // handle version read data, set CH34x line coding (incl. baudrate) - uint8_t version = xfer->buffer[0]; - TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); - // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD - TU_ASSERT (version >= 0x30,); - uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); - TU_ASSERT(div_ps != 0, ); - - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); - break; - } - - case CONFIG_CH34X_SPECIAL_REG_WRITE: - // do special reg write, purpose unknown, overtaken from WCH driver - TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); - break; - - case CONFIG_CH34X_FLOW_CONTROL: - // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); - break; - - case CONFIG_CH34X_MODEM_CONTROL: - // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); - break; - - case CONFIG_CH34X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); - break; - - default: - TU_ASSERT (false,); - break; - } -} #endif // CFG_TUH_CDC_CH34X From 23c2d929a1bae39578b195c7c7b068fb718212bd Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 12:40:37 +0700 Subject: [PATCH 29/41] refactor process_internal_control_complete() --- src/class/cdc/cdc_host.c | 142 +++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 73 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3843a8edc..bfaa64a77 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -396,26 +396,23 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -// internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); +static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t* xfer) { TU_ASSERT(p_cdc, ); + uint16_t const value = tu_le16toh(xfer->setup->wValue); if (xfer->result == XFER_RESULT_SUCCESS) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = (uint8_t) value; break; case CDC_REQUEST_SET_LINE_CODING: { uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); memcpy(&p_cdc->line_coding, xfer->buffer, len); - } break; + } default: break; } @@ -425,11 +422,10 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case SERIAL_DRIVER_FTDI: switch (xfer->setup->bRequest) { case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case FTDI_SIO_SET_BAUD_RATE: - // convert from divisor to baudrate is not supported p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -442,22 +438,62 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { case SERIAL_DRIVER_CP210X: switch(xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff); + p_cdc->line_state = (uint8_t) value; break; case CP210X_SET_BAUDRATE: { uint32_t baudrate; memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); - } break; + } + + default: break; } break; #endif #if CFG_TUH_CDC_CH34X case SERIAL_DRIVER_CH34X: - TU_ASSERT(false, ); // see special ch34x_control_complete function + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (value) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + + default: break; + } + break; + + case CH34X_REQ_MODEM_CTRL: { + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~value; + if (modem_signal & CH34X_BIT_RTS) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; + } + + if (modem_signal & CH34X_BIT_DTR) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; + } + break; + } + + default: break; + } break; #endif @@ -471,6 +507,15 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { } } +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + + process_internal_control_complete(p_cdc, xfer); +} + bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -1279,70 +1324,16 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); - uint16_t value = tu_le16toh (xfer->setup->wValue); - TU_ASSERT (p_cdc,); - TU_ASSERT (p_cdc->serial_drid == SERIAL_DRIVER_CH34X,); - - if (xfer->result == XFER_RESULT_SUCCESS) { - switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: - // register write request - switch (value) { - case CH34X_REG16_DIVISOR_PRESCALER: - // baudrate write - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - case CH32X_REG16_LCR2_LCR: - // data format write - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; - break; - - default: - TU_ASSERT(false,); // unexpected register write - break; - } - break; - - case CH34X_REQ_MODEM_CTRL: { - // set modem controls RTS/DTR request. Note: signals are inverted - uint16_t const modem_signal = ~value; - if (modem_signal & CH34X_BIT_RTS) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; - } - - if (modem_signal & CH34X_BIT_DTR) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; - } - break; - } - - case CH34X_REQ_SERIAL_INIT: - // serial init request (set line coding incl. baudrate) - p_cdc->line_coding = p_cdc->requested_line_coding; - break; - - default: - TU_ASSERT(false,); // unexpected request - break; - } - - xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } + process_internal_control_complete(p_cdc, xfer); } //static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, // tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); +// p_cdc->requested_line_coding.stop_bits = stop_bits; +// p_cdc->requested_line_coding.parity = parity; +// p_cdc->requested_line_coding.data_bits = data_bits; +// // TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, // complete_cb ? ch34x_control_complete : NULL, user_data)); // return false; @@ -1350,16 +1341,21 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = baudrate; - p_cdc->user_control_cb = complete_cb; uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); TU_VERIFY(div_ps != 0); + + p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } +//static void ch34x_set_line_coding_stage1(tuh_xfer_t* xfer) { +// +//} + static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // p_cdc->baudrate_requested = line_coding->bit_rate; From 98781bb903d94190d57ad4b9436a85a31d67404c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 15:58:05 +0700 Subject: [PATCH 30/41] - add ch34x_set_data_format() - add ch34x_set_line_coding() --- examples/host/cdc_msc_hid/src/cdc_app.c | 68 +++++++-------- src/class/cdc/cdc_host.c | 110 ++++++++++++++++-------- src/class/cdc/serial/ch34x.h | 3 +- 3 files changed, 107 insertions(+), 74 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index a1b26e49c..81052047c 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -27,20 +27,11 @@ #include "tusb.h" #include "bsp/board_api.h" -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - - -//------------- IMPLEMENTATION -------------// - -size_t get_console_inputs(uint8_t* buf, size_t bufsize) -{ +size_t get_console_inputs(uint8_t* buf, size_t bufsize) { size_t count = 0; - while (count < bufsize) - { + while (count < bufsize) { int ch = board_getchar(); - if ( ch <= 0 ) break; + if (ch <= 0) break; buf[count] = (uint8_t) ch; count++; @@ -49,22 +40,18 @@ size_t get_console_inputs(uint8_t* buf, size_t bufsize) return count; } -void cdc_app_task(void) -{ - uint8_t buf[64+1]; // +1 for extra null character - uint32_t const bufsize = sizeof(buf)-1; +void cdc_app_task(void) { + uint8_t buf[64 + 1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf) - 1; uint32_t count = get_console_inputs(buf, bufsize); buf[count] = 0; // loop over all mounted interfaces - for(uint8_t idx=0; idx cdc interfaces - if (count) - { + if (count) { tuh_cdc_write(idx, buf, count); tuh_cdc_write_flush(idx); } @@ -72,11 +59,14 @@ void cdc_app_task(void) } } +//--------------------------------------------------------------------+ +// TinyUSB callbacks +//--------------------------------------------------------------------+ + // Invoked when received new data -void tuh_cdc_rx_cb(uint8_t idx) -{ - uint8_t buf[64+1]; // +1 for extra null character - uint32_t const bufsize = sizeof(buf)-1; +void tuh_cdc_rx_cb(uint8_t idx) { + uint8_t buf[64 + 1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf) - 1; // forward cdc interfaces -> console uint32_t count = tuh_cdc_read(idx, buf, bufsize); @@ -85,29 +75,31 @@ void tuh_cdc_rx_cb(uint8_t idx) printf((char*) buf); } -void tuh_cdc_mount_cb(uint8_t idx) -{ - tuh_itf_info_t itf_info = { 0 }; +// Invoked when a device with CDC interface is mounted +// idx is index of cdc interface in the internal pool. +void tuh_cdc_mount_cb(uint8_t idx) { + tuh_itf_info_t itf_info = {0}; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber); + printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, + itf_info.desc.bInterfaceNumber); #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration // otherwise you need to call tuh_cdc_set_line_coding() first - cdc_line_coding_t line_coding = { 0 }; - if ( tuh_cdc_get_local_line_coding(idx, &line_coding) ) - { + cdc_line_coding_t line_coding = {0}; + if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); - printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity , line_coding.data_bits); + printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } #endif } -void tuh_cdc_umount_cb(uint8_t idx) -{ - tuh_itf_info_t itf_info = { 0 }; +// Invoked when a device with CDC interface is unmounted +void tuh_cdc_umount_cb(uint8_t idx) { + tuh_itf_info_t itf_info = {0}; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber); + printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, + itf_info.desc.bInterfaceNumber); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index bfaa64a77..37fa30982 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1327,48 +1327,88 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) { process_internal_control_complete(p_cdc, xfer); } -//static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, -// tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -// uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); -// p_cdc->requested_line_coding.stop_bits = stop_bits; -// p_cdc->requested_line_coding.parity = parity; -// p_cdc->requested_line_coding.data_bits = data_bits; -// -// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, -// complete_cb ? ch34x_control_complete : NULL, user_data)); -// return false; -//} - -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); - TU_VERIFY(div_ps != 0); - - p_cdc->requested_line_coding.bit_rate = baudrate; - p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb ? ch34x_control_complete : NULL, user_data)); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = stop_bits; + p_cdc->requested_line_coding.parity = parity; + p_cdc->requested_line_coding.data_bits = data_bits; + uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, + complete_cb ? ch34x_control_complete : NULL, user_data)); return true; } -//static void ch34x_set_line_coding_stage1(tuh_xfer_t* xfer) { -// -//} +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb, user_data)); + return true; +} +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, + complete_cb ? ch34x_control_complete : NULL, user_data)); + return true; +} + +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) { + // stage 1 success, continue to stage 2 + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity, + p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), ); + } else { + // stage 1 failed, notify user + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { -// p_cdc->baudrate_requested = line_coding->bit_rate; -// p_cdc->user_control_cb = complete_cb; -// uint8_t factor, divisor, lcr; -// TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor)); -// TU_ASSERT (ch34x_get_lcr(line_coding, &lcr)); -// TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor), -// complete_cb ? ch34x_control_complete : NULL, user_data)); - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; + p_cdc->requested_line_coding = *line_coding; + p_cdc->user_control_cb = complete_cb; + + if (complete_cb) { + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, + ch34x_set_line_coding_stage1_complete, user_data)); + } else { + // sync call + xfer_result_t result; + + // stage 1 set baudrate + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.bit_rate = line_coding->bit_rate; + + // stage 2 set data format + TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits, + NULL, (uintptr_t) &result)); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = line_coding->stop_bits; + p_cdc->line_coding.parity = line_coding->parity; + p_cdc->line_coding.data_bits = line_coding->data_bits; + + // update transfer result, user_data is expected to point to xfer_result_t + if (user_data) { + user_data = result; + } + } return true; } diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 3f78a3007..5def8d212 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -63,7 +63,8 @@ #define CH341_REG_0x2C 0x2C // undocumented register #define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) -#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) // modem control bits #define CH34X_BIT_RTS ( 1 << 6 ) From c196a2ed9cbd27188472d76ec428fdb24931d0b6 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 16:04:30 +0700 Subject: [PATCH 31/41] move code around --- src/class/cdc/cdc_host.c | 94 +++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 37fa30982..8965ee261 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1223,46 +1223,12 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -enum { - CONFIG_CH34X_READ_VERSION = 0, - CONFIG_CH34X_SERIAL_INIT, - CONFIG_CH34X_SPECIAL_REG_WRITE, - CONFIG_CH34X_FLOW_CONTROL, - CONFIG_CH34X_MODEM_CONTROL, - CONFIG_CH34X_COMPLETE -}; - static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); -static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { - // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints - TU_VERIFY (itf_desc->bNumEndpoints == 3); - TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY (p_cdc); - - TU_LOG_DRV ("CH34x opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); - desc_ep += 2; - - // Interrupt endpoint: not used for now - TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && - TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); - TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); - p_cdc->ep_notif = desc_ep->bEndpointAddress; - - return true; -} - +//------------- control requestt -------------// static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, - uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1318,6 +1284,17 @@ static bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_ // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); + TU_VERIFY(div_ps != 0); + TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, + complete_cb, user_data)); + return true; +} + +//------------- Driver API -------------// + // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber @@ -1339,15 +1316,6 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui return true; } -static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); - TU_VERIFY(div_ps != 0); - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb, user_data)); - return true; -} - static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = baudrate; @@ -1432,6 +1400,42 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, return true; } +//------------- Enumeration -------------// +enum { + CONFIG_CH34X_READ_VERSION = 0, + CONFIG_CH34X_SERIAL_INIT, + CONFIG_CH34X_SPECIAL_REG_WRITE, + CONFIG_CH34X_FLOW_CONTROL, + CONFIG_CH34X_MODEM_CONTROL, + CONFIG_CH34X_COMPLETE +}; + +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints + TU_VERIFY (itf_desc->bNumEndpoints == 3); + TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY (p_cdc); + + TU_LOG_DRV ("CH34x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CH34X; + + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + desc_ep += 2; + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + + return true; +} + static void ch34x_process_config(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber uint8_t const itf_num = 0; From 55cb713264a1fe531b548a05290ee8fe1289828f Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jan 2024 16:56:32 +0700 Subject: [PATCH 32/41] - add new API tuh_cdc_set_data_format() - add typedef for cdc enum --- src/class/cdc/cdc.h | 20 ++++----- src/class/cdc/cdc_host.c | 90 +++++++++++++++++++++++++++++++++++----- src/class/cdc/cdc_host.h | 13 +++--- 3 files changed, 95 insertions(+), 28 deletions(-) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index deec32ae4..5cbd658fe 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -136,8 +136,7 @@ typedef enum{ //--------------------------------------------------------------------+ /// Communication Interface Management Element Request Codes -typedef enum -{ +typedef enum { CDC_REQUEST_SEND_ENCAPSULATED_COMMAND = 0x00, ///< is used to issue a command in the format of the supported control protocol of the Communications Class interface CDC_REQUEST_GET_ENCAPSULATED_RESPONSE = 0x01, ///< is used to request a response in the format of the supported control protocol of the Communications Class interface. CDC_REQUEST_SET_COMM_FEATURE = 0x02, @@ -180,39 +179,38 @@ typedef enum CDC_REQUEST_GET_ATM_VC_STATISTICS = 0x53, CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, -}cdc_management_request_t; +} cdc_management_request_t; -enum { +typedef enum { CDC_CONTROL_LINE_STATE_DTR = 0x01, CDC_CONTROL_LINE_STATE_RTS = 0x02, -}; +} cdc_control_line_state_t; -enum { +typedef enum { CDC_LINE_CODING_STOP_BITS_1 = 0, // 1 bit CDC_LINE_CODING_STOP_BITS_1_5 = 1, // 1.5 bits CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits -}; +} cdc_line_coding_stopbits_t; // TODO Backward compatible for typos. Maybe removed in the future release #define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1 #define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5 #define CDC_LINE_CONDING_STOP_BITS_2 CDC_LINE_CODING_STOP_BITS_2 -enum { +typedef enum { CDC_LINE_CODING_PARITY_NONE = 0, CDC_LINE_CODING_PARITY_ODD = 1, CDC_LINE_CODING_PARITY_EVEN = 2, CDC_LINE_CODING_PARITY_MARK = 3, CDC_LINE_CODING_PARITY_SPACE = 4, -}; +} cdc_line_coding_parity_t; //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ /// 6.3 Notification Codes -typedef enum -{ +typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8965ee261..f5182efc2 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -90,9 +90,10 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI @@ -100,15 +101,13 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfe static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; -// Store last request baudrate since divisor to baudrate is not easy -// static uint32_t _ftdi_requested_baud; - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// @@ -120,9 +119,10 @@ static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIS static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// @@ -131,16 +131,16 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; -static bool ch34x_open ( uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len ); -static void ch34x_process_config ( tuh_xfer_t* xfer ); +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); +static void ch34x_process_config(tuh_xfer_t* xfer); +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_modem_ctrl ( cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); -static bool ch34x_set_baudrate ( cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data ); +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- Common -------------// - enum { SERIAL_DRIVER_ACM = 0, @@ -166,6 +166,7 @@ typedef struct { void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); } cdch_serial_driver_t; @@ -178,6 +179,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = acm_process_config, .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, + .set_data_format = acm_set_data_format, .set_line_coding = acm_set_line_coding }, @@ -189,6 +191,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = ftdi_process_config, .set_control_line_state = ftdi_sio_set_modem_ctrl, .set_baudrate = ftdi_sio_set_baudrate, + .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding }, #endif @@ -201,6 +204,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = cp210x_process_config, .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, + .set_data_format = cp210x_set_data_format, .set_line_coding = cp210x_set_line_coding }, #endif @@ -213,6 +217,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = ch34x_process_config, .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, + .set_data_format = ch34x_set_data_format, .set_line_coding = ch34x_set_line_coding }, #endif @@ -562,6 +567,32 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete } } +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + + if (complete_cb) { + return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data); + } else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result); + + if (user_data) { + // user_data is not NULL, return result via user_data + *((xfer_result_t*) user_data) = result; + } + + TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + p_cdc->line_coding.stop_bits = stop_bits; + p_cdc->line_coding.parity = parity; + p_cdc->line_coding.data_bits = data_bits; + return true; + } +} + bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -900,6 +931,19 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const return true; } +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC ACM Set Data Format\r\n"); + + cdc_line_coding_t line_coding; + line_coding.bit_rate = p_cdc->line_coding.bit_rate; + line_coding.stop_bits = stop_bits; + line_coding.parity = parity; + line_coding.data_bits = data_bits; + + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); cdc_line_coding_t line_coding = p_cdc->line_coding; @@ -968,6 +1012,18 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; (void) line_coding; @@ -1161,6 +1217,18 @@ static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_ complete_cb ? cdch_internal_control_complete : NULL, user_data); } +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + (void) p_cdc; + (void) stop_bits; + (void) parity; + (void) data_bits; + (void) complete_cb; + (void) user_data; + // TODO not implemented yet + return false; +} + static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9e5edd94e..d512a23a5 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -148,8 +148,11 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c // Request to set baudrate bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -// Request to Set Line Coding (ACM only) -// Should only use if you don't work with serial devices such as FTDI/CP210x +// Request to set data format +bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +// Request to Set Line Coding = baudrate + data format +// Note: only implemented by ACM and CH34x, not supported by FTDI and CP210x yet bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Get Line Coding (ACM only) @@ -159,15 +162,13 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // Connect by set both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } // Disconnect by clear both DTR, RTS TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } From 87d509d416ea7c250f4256f897f6cc9a7b7d2121 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 20 Jan 2024 01:42:31 +0700 Subject: [PATCH 33/41] make CFG_TUH_CDC_LINE_CODING_ON_ENUM optional for ch34x --- examples/host/cdc_msc_hid/src/cdc_app.c | 8 ++++++-- src/class/cdc/cdc_host.c | 19 ++++++++++++++----- src/class/cdc/serial/ch34x.h | 12 +----------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 81052047c..e275e7943 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -85,13 +85,17 @@ void tuh_cdc_mount_cb(uint8_t idx) { itf_info.desc.bInterfaceNumber); #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration - // otherwise you need to call tuh_cdc_set_line_coding() first + // If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack + // while eneumerating new cdc device cdc_line_coding_t line_coding = {0}; if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } +#else + // Set Line Coding upon mounted + cdc_line_coding_t new_line_coding = { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }; + tuh_cdc_set_line_coding(idx, &new_line_coding, NULL, 0); #endif } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f5182efc2..cd948243d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1510,10 +1510,11 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); uintptr_t const state = xfer->user_data; - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint8_t buffer[2]; // TODO remove TU_ASSERT (p_cdc,); + // TODO check xfer->result + switch (state) { case CONFIG_CH34X_READ_VERSION: TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); @@ -1527,20 +1528,28 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + uint16_t const first_arg = tu_u16(lcr, 0x9c); uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); TU_ASSERT(div_ps != 0, ); - - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + #else + uint16_t const first_arg = 0; + uint16_t const div_ps = 0; + #endif // Init CH34x with line coding - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, first_arg, div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: // do special reg write, purpose unknown, overtaken from WCH driver - p_cdc->line_coding = line_coding; + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM); + #endif TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 5def8d212..b9121afb3 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -27,21 +27,11 @@ #ifndef _CH34X_H_ #define _CH34X_H_ -// For simplicity, only the name CH34X is used here, -// but specifically only CH340 and CH341 are supported. - -// There is no official documentation for the CH34x chips. Reference can be found +// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c -// set line_coding @ enumeration -#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM -#else // this default is necessary to work properly -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } -#endif - // USB requests #define CH34X_REQ_READ_VERSION 0x5F // dec 95 #define CH34X_REQ_WRITE_REG 0x9A // dec 154 From 769a237b19bbe5254e1c83869b463c79afb1af34 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 20 Jan 2024 20:34:50 +0100 Subject: [PATCH 34/41] accumulated review changes --- src/class/cdc/cdc_host.c | 68 ++++++++++++++++-------------------- src/class/cdc/serial/ch34x.h | 7 ++++ 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index cd948243d..7adaa0c8c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -401,7 +401,9 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t* xfer) { +static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) { + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); uint16_t const value = tu_le16toh(xfer->setup->wValue); @@ -515,10 +517,7 @@ static void process_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_ // internal control complete to update state such as line state, encoding static void cdch_internal_control_complete(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - - process_internal_control_complete(p_cdc, xfer); + process_internal_control_complete(xfer, itf_num); } bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1294,7 +1293,8 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); -//------------- control requestt -------------// +//------------- control request -------------// + static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { @@ -1366,10 +1366,7 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, // internal control complete to update state such as line state, encoding static void ch34x_control_complete(tuh_xfer_t* xfer) { // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - process_internal_control_complete(p_cdc, xfer); + process_internal_control_complete(xfer, 0); } static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -1379,6 +1376,7 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui p_cdc->requested_line_coding.data_bits = data_bits; uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); + TU_VERIFY(lcr != 0); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, complete_cb ? ch34x_control_complete : NULL, user_data)); return true; @@ -1527,35 +1525,26 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); - - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); - uint16_t const first_arg = tu_u16(lcr, 0x9c); + // init CH34x with line coding + cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); TU_ASSERT(div_ps != 0, ); - #else - uint16_t const first_arg = 0; - uint16_t const div_ps = 0; - #endif - - // Init CH34x with line coding - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, first_arg, div_ps, + uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + TU_ASSERT(lcr != 0, ); + TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: - // do special reg write, purpose unknown, overtaken from WCH driver - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM); - #endif - TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); + // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver + p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X); + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); break; case CONFIG_CH34X_MODEM_CONTROL: @@ -1581,6 +1570,7 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { uint8_t b; uint32_t c; + TU_VERIFY(baval != 0, 0); switch (baval) { case 921600: a = 0xf3; @@ -1606,7 +1596,7 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { b = 0; c = 11719; } - a = (unsigned char) (c / baval); + a = (uint8_t) (c / baval); if (a == 0 || a == 0xFF) { return 0; } @@ -1620,29 +1610,33 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { // reg divisor = a, reg prescaler = b // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, // otherwise the chip will buffer data. - return (uint16_t) (a << 8 | 0x80 | b); + return (uint16_t) ((uint16_t)a << 8 | 0x80 | b); } // calculate lcr value from data coding static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - TU_VERIFY(data_bits >= 5, 0); + TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); lcr |= (uint8_t) (data_bits - 5); - if (parity) { - lcr |= CH34X_LCR_ENABLE_PAR; - } switch(parity) { + case CDC_LINE_CODING_PARITY_NONE: + break; + + case CDC_LINE_CODING_PARITY_ODD: + lcr |= CH34X_LCR_ENABLE_PAR; + break; + case CDC_LINE_CODING_PARITY_EVEN: - lcr |= CH34X_LCR_PAR_EVEN; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN; break; case CDC_LINE_CODING_PARITY_MARK: - lcr |= CH34X_LCR_MARK_SPACE; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE; break; case CDC_LINE_CODING_PARITY_SPACE: - lcr |= CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; + lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN; break; default: break; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index b9121afb3..c18066f57 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -32,6 +32,13 @@ // - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c +// set line_coding @ enumeration +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM +#else // this default is necessary to work properly +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +#endif + // USB requests #define CH34X_REQ_READ_VERSION 0x5F // dec 95 #define CH34X_REQ_WRITE_REG 0x9A // dec 154 From 1c9a839401cb7323f93202f600c6f3148100e10a Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 23 Jan 2024 13:48:09 +0100 Subject: [PATCH 35/41] audio_device: Fix unused variable warning In some configurations local variable p_desc_parse_for_params is declared and never used resulting in warning that can be escalated to build error (for mynewt) Now variable is surrounded with same preprocessor condition as function that uses it audiod_parse_for_AS_params() --- src/class/audio/audio_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index d438d0715..4adc558a6 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1729,7 +1729,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) { -#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING) uint8_t const * p_desc_parse_for_params = p_desc; #endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary From 82218c8d6875947fee29e9b9a0b48b87bb587281 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 24 Jan 2024 00:43:23 +0700 Subject: [PATCH 36/41] retry flashih a few time due to random failed by s3 --- test/hil/hil_test.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 7c662aeea..544a4eb39 100644 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -364,8 +364,14 @@ def main(config_file, board): print(f' {test} ...', end='') - # flash firmware - ret = globals()[f'flash_{flasher}'](item, fw) + # flash firmware. It may fail randomly, retry a few times + for i in range(3): + ret = globals()[f'flash_{flasher}'](item, fw) + if ret.returncode == 0: + break + else: + time.sleep(1) + assert ret.returncode == 0, 'Flash failed\n' + ret.stdout.decode() # run test From 64f86ef8e744e72e27b529ddb3440420ee4e3cf0 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 24 Jan 2024 11:32:28 +0700 Subject: [PATCH 37/41] build workflow with hil-test when test/hil changes --- .github/workflows/build_esp.yml | 2 ++ .github/workflows/build_iar.yml | 2 ++ .github/workflows/cmake_arm.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/build_esp.yml b/.github/workflows/build_esp.yml index 33caa0edb..65ade7b03 100644 --- a/.github/workflows/build_esp.yml +++ b/.github/workflows/build_esp.yml @@ -8,6 +8,7 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' + - 'test/hil/**' - '.github/workflows/build_esp.yml' pull_request: branches: [ master ] @@ -16,6 +17,7 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' + - 'test/hil/**' - '.github/workflows/build_esp.yml' concurrency: diff --git a/.github/workflows/build_iar.yml b/.github/workflows/build_iar.yml index 9f2cc0351..a0a022ecc 100644 --- a/.github/workflows/build_iar.yml +++ b/.github/workflows/build_iar.yml @@ -9,6 +9,7 @@ on: - 'lib/**' - 'hw/**' - 'tools/get_deps.py' + - 'test/hil/**' - '.github/workflows/build_iar.yml' pull_request: branches: [ master ] @@ -18,6 +19,7 @@ on: - 'lib/**' - 'hw/**' - 'tools/get_deps.py' + - 'test/hil/**' - '.github/workflows/build_iar.yml' concurrency: diff --git a/.github/workflows/cmake_arm.yml b/.github/workflows/cmake_arm.yml index 8b87fef21..4ef2de4a6 100644 --- a/.github/workflows/cmake_arm.yml +++ b/.github/workflows/cmake_arm.yml @@ -8,6 +8,7 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' + - 'test/hil/**' - 'tools/get_deps.py' - '.github/workflows/cmake_arm.yml' pull_request: @@ -17,6 +18,7 @@ on: - 'examples/**' - 'lib/**' - 'hw/**' + - 'test/hil/**' - 'tools/get_deps.py' - '.github/workflows/cmake_arm.yml' From 9d0df8ebc5f643ff0b3dd06da14d11b3c1107a21 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 24 Jan 2024 12:10:17 +0700 Subject: [PATCH 38/41] add message when flashing failed --- test/hil/hil_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 544a4eb39..7f03ce43f 100644 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -370,6 +370,7 @@ def main(config_file, board): if ret.returncode == 0: break else: + print(f'Flashing failed, retry {i+1}') time.sleep(1) assert ret.returncode == 0, 'Flash failed\n' + ret.stdout.decode() From de1266699dc804d1ac35254abd3d0dc54d81ad75 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 13 Jan 2024 00:10:24 +0700 Subject: [PATCH 39/41] clean up video example for readability --- examples/device/video_capture/src/images.h | 3 + examples/device/video_capture/src/main.c | 86 +++++----- .../device/video_capture/src/tusb_config.h | 2 +- .../video_capture/src/usb_descriptors.c | 150 ++++++------------ hw/bsp/family_support.cmake | 1 - 5 files changed, 96 insertions(+), 146 deletions(-) diff --git a/examples/device/video_capture/src/images.h b/examples/device/video_capture/src/images.h index 784e7754c..ac372cb16 100644 --- a/examples/device/video_capture/src/images.h +++ b/examples/device/video_capture/src/images.h @@ -1,4 +1,5 @@ #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) +// uncopmressed frame static const unsigned char frame_buffer[128 * (96 + 1) * 2] = { /* 0 */ 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, @@ -1650,8 +1651,10 @@ static const unsigned char frame_buffer[128 * (96 + 1) * 2] = { 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, }; + #else +// mpeg compressed data (not CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) #define color_bar_0_jpg_len 511 #define color_bar_1_jpg_len 512 #define color_bar_2_jpg_len 511 diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index 711d4710a..7b180dd6b 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -40,7 +40,7 @@ * - 1000 ms : device mounted * - 2500 ms : device is suspended */ -enum { +enum { BLINK_NOT_MOUNTED = 250, BLINK_MOUNTED = 1000, BLINK_SUSPENDED = 2500, @@ -52,8 +52,7 @@ void led_blinking_task(void); void video_task(void); /*------------- MAIN -------------*/ -int main(void) -{ +int main(void) { board_init(); // init device stack on configured roothub port @@ -63,8 +62,7 @@ int main(void) board_init_after_tusb(); } - while (1) - { + while (1) { tud_task(); // tinyusb device task led_blinking_task(); @@ -77,33 +75,28 @@ int main(void) //--------------------------------------------------------------------+ // Invoked when device is mounted -void tud_mount_cb(void) -{ +void tud_mount_cb(void) { blink_interval_ms = BLINK_MOUNTED; } // Invoked when device is unmounted -void tud_umount_cb(void) -{ +void tud_umount_cb(void) { blink_interval_ms = BLINK_NOT_MOUNTED; } // Invoked when usb bus is suspended // remote_wakeup_en : if host allow us to perform remote wakeup // Within 7ms, device must draw an average of current less than 2.5 mA from bus -void tud_suspend_cb(bool remote_wakeup_en) -{ +void tud_suspend_cb(bool remote_wakeup_en) { (void) remote_wakeup_en; blink_interval_ms = BLINK_SUSPENDED; } // Invoked when usb bus is resumed -void tud_resume_cb(void) -{ +void tud_resume_cb(void) { blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } - //--------------------------------------------------------------------+ // USB Video //--------------------------------------------------------------------+ @@ -111,11 +104,12 @@ static unsigned frame_num = 0; static unsigned tx_busy = 0; static unsigned interval_ms = 1000 / FRAME_RATE; -/* YUY2 frame buffer */ #ifdef CFG_EXAMPLE_VIDEO_READONLY +// For mcus that does not have enough SRAM for frame buffer, we use fixed frame data. +// To further reduce the size, we use MJPEG format instead of YUY2. #include "images.h" -# if !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) +#if !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) static struct { uint32_t size; uint8_t const *buffer; @@ -129,29 +123,31 @@ static struct { {color_bar_6_jpg_len, color_bar_6_jpg}, {color_bar_7_jpg_len, color_bar_7_jpg}, }; -# endif +#endif #else + +// YUY2 frame buffer static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8]; -static void fill_color_bar(uint8_t *buffer, unsigned start_position) -{ + +static void fill_color_bar(uint8_t* buffer, unsigned start_position) { /* EBU color bars * See also https://stackoverflow.com/questions/6939422 */ static uint8_t const bar_color[8][4] = { - /* Y, U, Y, V */ - { 235, 128, 235, 128}, /* 100% White */ - { 219, 16, 219, 138}, /* Yellow */ - { 188, 154, 188, 16}, /* Cyan */ - { 173, 42, 173, 26}, /* Green */ - { 78, 214, 78, 230}, /* Magenta */ - { 63, 102, 63, 240}, /* Red */ - { 32, 240, 32, 118}, /* Blue */ - { 16, 128, 16, 128}, /* Black */ + /* Y, U, Y, V */ + { 235, 128, 235, 128}, /* 100% White */ + { 219, 16, 219, 138}, /* Yellow */ + { 188, 154, 188, 16}, /* Cyan */ + { 173, 42, 173, 26}, /* Green */ + { 78, 214, 78, 230}, /* Magenta */ + { 63, 102, 63, 240}, /* Red */ + { 32, 240, 32, 118}, /* Blue */ + { 16, 128, 16, 128}, /* Black */ }; - uint8_t *p; + uint8_t* p; /* Generate the 1st line */ - uint8_t *end = &buffer[FRAME_WIDTH * 2]; + uint8_t* end = &buffer[FRAME_WIDTH * 2]; unsigned idx = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2)); p = &buffer[idx * 4]; for (unsigned i = 0; i < 8; ++i) { @@ -163,6 +159,7 @@ static void fill_color_bar(uint8_t *buffer, unsigned start_position) } } } + /* Duplicate the 1st line to the others */ p = &buffer[FRAME_WIDTH * 2]; for (unsigned i = 1; i < FRAME_HEIGHT; ++i) { @@ -170,16 +167,16 @@ static void fill_color_bar(uint8_t *buffer, unsigned start_position) p += FRAME_WIDTH * 2; } } + #endif -void video_task(void) -{ +void video_task(void) { static unsigned start_ms = 0; static unsigned already_sent = 0; if (!tud_video_n_streaming(0, 0)) { - already_sent = 0; - frame_num = 0; + already_sent = 0; + frame_num = 0; return; } @@ -195,7 +192,7 @@ void video_task(void) # endif #else fill_color_bar(frame_buffer, frame_num); - tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8); + tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); #endif } @@ -213,22 +210,22 @@ void video_task(void) # endif #else fill_color_bar(frame_buffer, frame_num); - tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8); + tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); #endif } -void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) -{ - (void)ctl_idx; (void)stm_idx; +void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) { + (void) ctl_idx; + (void) stm_idx; tx_busy = 0; /* flip buffer */ ++frame_num; } int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, - video_probe_and_commit_control_t const *parameters) -{ - (void)ctl_idx; (void)stm_idx; + video_probe_and_commit_control_t const* parameters) { + (void) ctl_idx; + (void) stm_idx; /* convert unit to ms from 100 ns */ interval_ms = parameters->dwFrameInterval / 10000; return VIDEO_ERROR_NONE; @@ -237,13 +234,12 @@ int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ +void led_blinking_task(void) { static uint32_t start_ms = 0; static bool led_state = false; // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + if (board_millis() - start_ms < blink_interval_ms) return; // not enough time start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index 274bf2b9c..8440b47ef 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -101,7 +101,7 @@ #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256 // use bulk endpoint for streaming interface -#define CFG_TUD_VIDEO_STREAMING_BULK 0 +#define CFG_TUD_VIDEO_STREAMING_BULK 1 #ifdef __cplusplus } diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index 49919fc58..d38f158c8 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -43,8 +43,7 @@ //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = -{ +tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, @@ -70,111 +69,70 @@ tusb_desc_device_t const desc_device = // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ - return (uint8_t const *) &desc_device; +uint8_t const* tud_descriptor_device_cb(void) { + return (uint8_t const*) &desc_device; } //--------------------------------------------------------------------+ // Configuration Descriptor //--------------------------------------------------------------------+ -#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK -# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_MJPEG_BULK_LEN) -# else -# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_MJPEG_LEN) -# endif -#else -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK -# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_UNCOMPR_BULK_LEN) -# else -# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN) -# endif -#endif - +// Select appropriate endpoint number #if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ... -#if 1 == CFG_TUD_VIDEO_STREAMING_BULK - #define EPNUM_VIDEO_IN 0x82 -#else - #define EPNUM_VIDEO_IN 0x83 -#endif - + #define EPNUM_VIDEO_IN (CFG_TUD_VIDEO_STREAMING_BULK ? 0x82 : 0x83) #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // nRF5x ISO can only be endpoint 8 - #define EPNUM_VIDEO_IN 0x88 - + #define EPNUM_VIDEO_IN (CFG_TUD_VIDEO_STREAMING_BULK ? 0x81 : 0x88) #else #define EPNUM_VIDEO_IN 0x81 - #endif -uint8_t const desc_fs_configuration[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500), - - // IAD for Video Control +// For mcus that does not have enough SRAM for frame buffer, we use fixed frame data. +// To further reduce the size, we use MJPEG format instead of YUY2. +// Select interface descriptor and length accordingly. #if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK - TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - 64) -# else - TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) -# endif + #if CFG_TUD_VIDEO_STREAMING_BULK + #define ITF_VIDEO_DESC(epsize) TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(4, EPNUM_VIDEO_IN, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, epsize) + #define ITF_VIDEO_LEN TUD_VIDEO_CAPTURE_DESC_MJPEG_BULK_LEN + #else + #define ITF_VIDEO_DESC(epsize) TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(4, EPNUM_VIDEO_IN, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, epsize) + #define ITF_VIDEO_LEN TUD_VIDEO_CAPTURE_DESC_MJPEG_LEN + #endif #else -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK - TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - 64) -# else - TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) -# endif + #if CFG_TUD_VIDEO_STREAMING_BULK + #define ITF_VIDEO_DESC(epsize) TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, EPNUM_VIDEO_IN, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, epsize) + #define ITF_VIDEO_LEN TUD_VIDEO_CAPTURE_DESC_UNCOMPR_BULK_LEN + #else + #define ITF_VIDEO_DESC(epsize) TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(4, EPNUM_VIDEO_IN, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, epsize) + #define ITF_VIDEO_LEN TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN + #endif #endif + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + ITF_VIDEO_LEN) + +// full speed descriptor +uint8_t const desc_fs_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500), + + // IAD for Video Control + ITF_VIDEO_DESC(CFG_TUD_VIDEO_STREAMING_BULK ? 64 : CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) }; #if TUD_OPT_HIGH_SPEED // Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration - -uint8_t const desc_hs_configuration[] = -{ +uint8_t const desc_hs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500), // IAD for Video Control -#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK - TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - 512) -# else - TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) -# endif -#else -# if 1 == CFG_TUD_VIDEO_STREAMING_BULK - TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - 512) -# else - TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(4, EPNUM_VIDEO_IN, - FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, - CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) -# endif -#endif + ITF_VIDEO_DESC(CFG_TUD_VIDEO_STREAMING_BULK ? 512 : CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE) }; // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed -tusb_desc_device_qualifier_t const desc_device_qualifier = -{ +tusb_desc_device_qualifier_t const desc_device_qualifier = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, @@ -192,29 +150,24 @@ tusb_desc_device_qualifier_t const desc_device_qualifier = // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -uint8_t const* tud_descriptor_device_qualifier_cb(void) -{ +uint8_t const* tud_descriptor_device_qualifier_cb(void) { return (uint8_t const*) &desc_device_qualifier; } // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) -{ +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { (void) index; // for multiple configurations - // if link speed is high return fullspeed config, and vice versa return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; } - #endif // highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ +uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations #if TUD_OPT_HIGH_SPEED @@ -238,24 +191,23 @@ enum { }; // array of pointer to string descriptors -char const *string_desc_arr[] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "TinyUSB UVC", // 4: UVC Interface +char const* string_desc_arr[] = { + (const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + NULL, // 3: Serials will use unique ID if possible + "TinyUSB UVC", // 4: UVC Interface }; static uint16_t _desc_str[32 + 1]; // Invoked when received GET STRING DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { (void) langid; size_t chr_count; - switch ( index ) { + switch (index) { case STRID_LANGID: memcpy(&_desc_str[1], string_desc_arr[0], 2); chr_count = 1; @@ -269,17 +221,17 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + if (index >= sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) return NULL; - const char *str = string_desc_arr[index]; + const char* str = string_desc_arr[index]; // Cap at max char chr_count = strlen(str); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if (chr_count > max_count) chr_count = max_count; // Convert ASCII string into UTF-16 - for ( size_t i = 0; i < chr_count; i++ ) { + for (size_t i = 0; i < chr_count; i++) { _desc_str[1 + i] = str[i]; } break; diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 539a776a6..ff3393cfd 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -211,7 +211,6 @@ function(family_configure_common TARGET RTOS) target_link_options(${TARGET} PUBLIC "LINKER:--map=$.map") endif() - # ETM Trace option if (TRACE_ETM STREQUAL "1") target_compile_definitions(${TARGET} PUBLIC TRACE_ETM) From 0b8b8af83dfac97caa7c41f9d5c8c1a3af1b9ac1 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 25 Jan 2024 17:25:48 +0700 Subject: [PATCH 40/41] minor update to video capture example --- examples/device/video_capture/src/main.c | 15 +- .../device/video_capture/src/tusb_config.h | 2 +- .../video_capture/src/usb_descriptors.h | 69 +++----- src/class/video/video_device.c | 6 +- src/common/tusb_types.h | 154 +++++++----------- 5 files changed, 92 insertions(+), 154 deletions(-) diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index 7b180dd6b..e63335e67 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -131,8 +131,7 @@ static struct { static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8]; static void fill_color_bar(uint8_t* buffer, unsigned start_position) { - /* EBU color bars - * See also https://stackoverflow.com/questions/6939422 */ + /* EBU color bars: https://stackoverflow.com/questions/6939422 */ static uint8_t const bar_color[8][4] = { /* Y, U, Y, V */ { 235, 128, 235, 128}, /* 100% White */ @@ -184,12 +183,12 @@ void video_task(void) { already_sent = 1; start_ms = board_millis(); #ifdef CFG_EXAMPLE_VIDEO_READONLY -# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) + #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], FRAME_WIDTH * FRAME_HEIGHT * 16/8); -# else + #else tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size); -# endif + #endif #else fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); @@ -202,12 +201,12 @@ void video_task(void) { start_ms += interval_ms; #ifdef CFG_EXAMPLE_VIDEO_READONLY -# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) + #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], FRAME_WIDTH * FRAME_HEIGHT * 16/8); -# else + #else tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size); -# endif + #endif #else fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index 8440b47ef..d563c6f5c 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -97,7 +97,7 @@ // The number of video streaming interfaces #define CFG_TUD_VIDEO_STREAMING 1 -// video streaming endpoint size +// video streaming endpoint buffer size #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256 // use bulk endpoint for streaming interface diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h index b924c8dbe..fa3c1fbd2 100644 --- a/examples/device/video_capture/src/usb_descriptors.h +++ b/examples/device/video_capture/src/usb_descriptors.h @@ -126,23 +126,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -163,23 +157,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -202,22 +190,17 @@ enum { TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ @@ -235,23 +218,17 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(_stridx, _epin, _width, _height, _fps, _epsize) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ - TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ - UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ - TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ - /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ - /*wObjectiveFocalLength*/0, /*bmControls*/0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ + /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \ + TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \ + /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \ /* Video stream header for without still image capture */ \ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ - /*wTotalLength - bLength */\ - TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\ - + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ /*bmaControls(1)*/0), \ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 3b29454a3..c16a45fcd 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -434,8 +434,9 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm uint_fast32_t interval_ms = interval / 10000; TU_ASSERT(interval_ms); uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) { payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + } param->dwMaxPayloadTransferSize = payload_size; return true; } @@ -577,8 +578,9 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * } else { payload_size = (frame_size + interval_ms - 1) / interval_ms + 2; } - if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) + if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) { payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE; + } param->dwMaxPayloadTransferSize = payload_size; } return true; diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index fab680989..d4ef1fd09 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -44,43 +44,38 @@ *------------------------------------------------------------------*/ /// defined base on EHCI specs value for Endpoint Speed -typedef enum -{ +typedef enum { TUSB_SPEED_FULL = 0, TUSB_SPEED_LOW = 1, TUSB_SPEED_HIGH = 2, TUSB_SPEED_INVALID = 0xff, -}tusb_speed_t; +} tusb_speed_t; /// defined base on USB Specs Endpoint's bmAttributes -typedef enum -{ +typedef enum { TUSB_XFER_CONTROL = 0 , TUSB_XFER_ISOCHRONOUS , TUSB_XFER_BULK , TUSB_XFER_INTERRUPT -}tusb_xfer_type_t; +} tusb_xfer_type_t; -typedef enum -{ +typedef enum { TUSB_DIR_OUT = 0, TUSB_DIR_IN = 1, TUSB_DIR_IN_MASK = 0x80 -}tusb_dir_t; +} tusb_dir_t; -enum -{ +enum { TUSB_EPSIZE_BULK_FS = 64, - TUSB_EPSIZE_BULK_HS= 512, + TUSB_EPSIZE_BULK_HS = 512, TUSB_EPSIZE_ISO_FS_MAX = 1023, TUSB_EPSIZE_ISO_HS_MAX = 1024, }; -/// Isochronous End Point Attributes -typedef enum -{ +/// Isochronous Endpoint Attributes +typedef enum { TUSB_ISO_EP_ATT_NO_SYNC = 0x00, TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, @@ -88,11 +83,10 @@ typedef enum TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback -}tusb_iso_ep_attribute_t; +} tusb_iso_ep_attribute_t; /// USB Descriptor Types -typedef enum -{ +typedef enum { TUSB_DESC_DEVICE = 0x01, TUSB_DESC_CONFIGURATION = 0x02, TUSB_DESC_STRING = 0x03, @@ -119,10 +113,9 @@ typedef enum TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30, TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31 -}tusb_desc_type_t; +} tusb_desc_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_GET_STATUS = 0 , TUSB_REQ_CLEAR_FEATURE = 1 , TUSB_REQ_RESERVED = 2 , @@ -136,25 +129,22 @@ typedef enum TUSB_REQ_GET_INTERFACE = 10 , TUSB_REQ_SET_INTERFACE = 11 , TUSB_REQ_SYNCH_FRAME = 12 -}tusb_request_code_t; +} tusb_request_code_t; -typedef enum -{ +typedef enum { TUSB_REQ_FEATURE_EDPT_HALT = 0, TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1, TUSB_REQ_FEATURE_TEST_MODE = 2 -}tusb_request_feature_selector_t; +} tusb_request_feature_selector_t; -typedef enum -{ +typedef enum { TUSB_REQ_TYPE_STANDARD = 0, TUSB_REQ_TYPE_CLASS, TUSB_REQ_TYPE_VENDOR, TUSB_REQ_TYPE_INVALID } tusb_request_type_t; -typedef enum -{ +typedef enum { TUSB_REQ_RCPT_DEVICE =0, TUSB_REQ_RCPT_INTERFACE, TUSB_REQ_RCPT_ENDPOINT, @@ -162,8 +152,7 @@ typedef enum } tusb_request_recipient_t; // https://www.usb.org/defined-class-codes -typedef enum -{ +typedef enum { TUSB_CLASS_UNSPECIFIED = 0 , TUSB_CLASS_AUDIO = 1 , TUSB_CLASS_CDC = 2 , @@ -187,26 +176,23 @@ typedef enum TUSB_CLASS_MISC = 0xEF , TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE , TUSB_CLASS_VENDOR_SPECIFIC = 0xFF -}tusb_class_code_t; +} tusb_class_code_t; typedef enum { MISC_SUBCLASS_COMMON = 2 }misc_subclass_type_t; -typedef enum -{ +typedef enum { MISC_PROTOCOL_IAD = 1 -}misc_protocol_type_t; +} misc_protocol_type_t; -typedef enum -{ +typedef enum { APP_SUBCLASS_USBTMC = 0x03, APP_SUBCLASS_DFU_RUNTIME = 0x01 } app_subclass_type_t; -typedef enum -{ +typedef enum { DEVICE_CAPABILITY_WIRELESS_USB = 0x01, DEVICE_CAPABILITY_USB20_EXTENSION = 0x02, DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03, @@ -223,7 +209,7 @@ typedef enum DEVICE_CAPABILITY_AUTHENTICATION = 0x0E, DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F, DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10 -}device_capability_type_t; +} device_capability_type_t; enum { TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5), @@ -235,28 +221,25 @@ enum { //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ -typedef enum -{ +typedef enum { XFER_RESULT_SUCCESS = 0, XFER_RESULT_FAILED, XFER_RESULT_STALLED, XFER_RESULT_TIMEOUT, XFER_RESULT_INVALID -}xfer_result_t; +} xfer_result_t; -enum // TODO remove -{ +// TODO remove +enum { DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 }; -enum -{ +enum { INTERFACE_INVALID_NUMBER = 0xff }; -typedef enum -{ +typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, @@ -268,16 +251,14 @@ typedef enum MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 } microsoft_os_20_type_t; -enum -{ +enum { CONTROL_STAGE_IDLE, CONTROL_STAGE_SETUP, CONTROL_STAGE_DATA, CONTROL_STAGE_ACK }; -enum -{ +enum { TUSB_INDEX_INVALID_8 = 0xFFu }; @@ -290,8 +271,7 @@ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN /// USB Device Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< DEVICE Descriptor Type. uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant. @@ -314,8 +294,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); // USB Binary Device Object Store (BOS) Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this descriptor @@ -325,8 +304,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct"); /// USB Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration. @@ -341,8 +319,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct"); /// USB Interface Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type @@ -358,8 +335,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct"); /// USB Endpoint Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; // Size of this descriptor in bytes uint8_t bDescriptorType ; // ENDPOINT Descriptor Type @@ -379,8 +355,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct"); /// USB Other Speed Configuration Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type uint16_t wTotalLength ; ///< Total length of data returned @@ -393,8 +368,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_other_speed_t; /// USB Device Qualifier Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Device Qualifier Type uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00) @@ -411,8 +385,7 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); /// USB Interface Association Descriptor (IAD ECN) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of descriptor uint8_t bDescriptorType ; ///< Other_speed_Configuration Type @@ -427,16 +400,14 @@ typedef struct TU_ATTR_PACKED } tusb_desc_interface_assoc_t; // USB String Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type uint16_t unicode_string[]; } tusb_desc_string_t; // USB Binary Device Object Store (BOS) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType ; uint8_t bDevCapabilityType; @@ -445,9 +416,8 @@ typedef struct TU_ATTR_PACKED uint8_t CapabilityData[]; } tusb_desc_bos_platform_t; -// USB WebuSB URL Descriptor -typedef struct TU_ATTR_PACKED -{ +// USB WebUSB URL Descriptor +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; uint8_t bScheme; @@ -455,8 +425,7 @@ typedef struct TU_ATTR_PACKED } tusb_desc_webusb_url_t; // DFU Functional Descriptor -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength; uint8_t bDescriptorType; @@ -481,7 +450,7 @@ typedef struct TU_ATTR_PACKED // //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED{ +typedef struct TU_ATTR_PACKED { union { struct TU_ATTR_PACKED { uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. @@ -509,36 +478,30 @@ TU_ATTR_BIT_FIELD_ORDER_END //--------------------------------------------------------------------+ // Get direction from Endpoint address -TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) { return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; } // Get Endpoint number from address -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) { return (uint8_t)(addr & (~TUSB_DIR_IN_MASK)); } -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) { return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0)); } -TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) -{ +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) { return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0); } #if CFG_TUSB_DEBUG -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) { tu_static const char *str[] = {"out", "in"}; return str[dir]; } -TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) -{ +TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) { tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"}; return str[t]; } @@ -549,21 +512,18 @@ TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_ //--------------------------------------------------------------------+ // return next descriptor -TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) { uint8_t const* desc8 = (uint8_t const*) desc; return desc8 + desc8[DESC_OFFSET_LEN]; } // get descriptor type -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; } // get descriptor length -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; } From 14d44171b59fc273adcccc1464da6e6cfb2c1864 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 25 Jan 2024 19:13:11 +0700 Subject: [PATCH 41/41] bump up to actions/setup-python@v5 --- .github/workflows/build_aarch64.yml | 2 +- .github/workflows/build_arm.yml | 2 +- .github/workflows/build_esp.yml | 2 +- .github/workflows/build_msp430.yml | 2 +- .github/workflows/build_renesas.yml | 2 +- .github/workflows/build_riscv.yml | 2 +- .github/workflows/build_win_mac.yml | 2 +- .github/workflows/cmake_arm.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_aarch64.yml b/.github/workflows/build_aarch64.yml index 40fc8d63a..e5dbf9494 100644 --- a/.github/workflows/build_aarch64.yml +++ b/.github/workflows/build_aarch64.yml @@ -36,7 +36,7 @@ jobs: - 'broadcom_64bit' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_arm.yml b/.github/workflows/build_arm.yml index 4127db5bf..9f3270c91 100644 --- a/.github/workflows/build_arm.yml +++ b/.github/workflows/build_arm.yml @@ -46,7 +46,7 @@ jobs: - 'tm4c123 xmc4000' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_esp.yml b/.github/workflows/build_esp.yml index 65ade7b03..315df255e 100644 --- a/.github/workflows/build_esp.yml +++ b/.github/workflows/build_esp.yml @@ -37,7 +37,7 @@ jobs: - 'espressif_s3_devkitc' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_msp430.yml b/.github/workflows/build_msp430.yml index 296dbb766..f913df913 100644 --- a/.github/workflows/build_msp430.yml +++ b/.github/workflows/build_msp430.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_renesas.yml b/.github/workflows/build_renesas.yml index 017a29eee..ec06c9426 100644 --- a/.github/workflows/build_renesas.yml +++ b/.github/workflows/build_renesas.yml @@ -35,7 +35,7 @@ jobs: - 'rx' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_riscv.yml b/.github/workflows/build_riscv.yml index e030bb77f..e891a3a51 100644 --- a/.github/workflows/build_riscv.yml +++ b/.github/workflows/build_riscv.yml @@ -37,7 +37,7 @@ jobs: - 'gd32vf103' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/build_win_mac.yml b/.github/workflows/build_win_mac.yml index 7fa1a6943..b33b5b593 100644 --- a/.github/workflows/build_win_mac.yml +++ b/.github/workflows/build_win_mac.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/cmake_arm.yml b/.github/workflows/cmake_arm.yml index 4ef2de4a6..f97645ad1 100644 --- a/.github/workflows/cmake_arm.yml +++ b/.github/workflows/cmake_arm.yml @@ -59,7 +59,7 @@ jobs: - 'stm32u5' steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 2e9ae9264..e36259daa 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x'