Merge pull request #2391 from IngHK/cdc_ch34x_support

initial support of CH34x CDC device
This commit is contained in:
Ha Thach 2024-01-22 23:08:16 +07:00 committed by GitHub
commit 57bbf3ad2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 851 additions and 269 deletions

View File

@ -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<CFG_TUH_CDC; idx++)
{
if ( tuh_cdc_mounted(idx) )
{
for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
if (tuh_cdc_mounted(idx)) {
// console --> 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,35 @@ 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) )
{
// 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);
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
}
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);
}

View File

@ -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

View File

@ -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

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -0,0 +1,84 @@
/*
* The MIT License (MIT)
*
* 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
* 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_
// 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
#define CH34X_REQ_READ_REG 0x95 // dec 149
#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
#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
#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)
#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR)
// modem control bits
#define CH34X_BIT_RTS ( 1 << 6 )
#define CH34X_BIT_DTR ( 1 << 5 )
// line control bits
#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_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_ */

View File

@ -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))

View File

@ -472,6 +472,23 @@
{0x10C4, 0xEA60}, {0x10C4, 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, 0x5523 }, /* ch341 chip */ \
{ 0x1a86, 0x7522 }, /* ch340k chip */ \
{ 0x1a86, 0x7523 }, /* ch340 chip */ \
{ 0x1a86, 0xe523 }, /* ch330 chip */ \
{ 0x4348, 0x5523 }, /* ch340 custom chip */ \
{ 0x2184, 0x0057 }, /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ \
{ 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */
#endif
#ifndef CFG_TUH_HID
#define CFG_TUH_HID 0
#endif