mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 02:18:54 +00:00
428 lines
12 KiB
C
428 lines
12 KiB
C
/*
|
|
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Authors: duanmt@artinchip.com
|
|
*/
|
|
|
|
#include <rtdevice.h>
|
|
#include <drivers/serial.h>
|
|
|
|
#include "usbd_core.h"
|
|
#include "usbd_cdc.h"
|
|
|
|
#define DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#undef USB_LOG_DBG
|
|
#define USB_LOG_DBG USB_LOG_INFO
|
|
#endif
|
|
|
|
/*!< endpoint address */
|
|
#define CDC_INT_EP 0x83
|
|
#define CDC_OUT_EP 0x02
|
|
#define CDC_IN_EP 0x81
|
|
|
|
#define USBD_VID 0x33C3
|
|
#define USBD_PID 0x7788
|
|
#define USBD_MAX_POWER 100
|
|
#define USBD_LANGID_STRING 1033
|
|
|
|
#define AICUPG_UART_DEV_NO 2
|
|
#define DEBUG_ENABLE_LOCAL_UART
|
|
|
|
/*!< config descriptor size */
|
|
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
|
|
|
|
#ifdef CONFIG_USB_HS
|
|
#define CDC_MAX_MPS 512
|
|
#else
|
|
#define CDC_MAX_MPS 64
|
|
#endif
|
|
|
|
/*!< global descriptor */
|
|
static const uint8_t cdc_descriptor[] = {
|
|
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
|
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
|
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
|
///////////////////////////////////////
|
|
/// string0 descriptor
|
|
///////////////////////////////////////
|
|
USB_LANGID_INIT(USBD_LANGID_STRING),
|
|
///////////////////////////////////////
|
|
/// string1 descriptor
|
|
///////////////////////////////////////
|
|
0x14, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'A', 0x00, /* wcChar0 */
|
|
'r', 0x00, /* wcChar1 */
|
|
't', 0x00, /* wcChar2 */
|
|
'I', 0x00, /* wcChar3 */
|
|
'n', 0x00, /* wcChar4 */
|
|
'C', 0x00, /* wcChar5 */
|
|
'h', 0x00, /* wcChar6 */
|
|
'i', 0x00, /* wcChar7 */
|
|
'p', 0x00, /* wcChar8 */
|
|
///////////////////////////////////////
|
|
/// string2 descriptor
|
|
///////////////////////////////////////
|
|
0x2A, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'A', 0x00, /* wcChar0 */
|
|
'r', 0x00, /* wcChar1 */
|
|
't', 0x00, /* wcChar2 */
|
|
'I', 0x00, /* wcChar3 */
|
|
'n', 0x00, /* wcChar4 */
|
|
'C', 0x00, /* wcChar5 */
|
|
'h', 0x00, /* wcChar6 */
|
|
'i', 0x00, /* wcChar7 */
|
|
'p', 0x00, /* wcChar8 */
|
|
' ', 0x00, /* wcChar9 */
|
|
'L', 0x00, /* wcChar10 */
|
|
'i', 0x00, /* wcChar11 */
|
|
'n', 0x00, /* wcChar12 */
|
|
'k', 0x00, /* wcChar13 */
|
|
'e', 0x00, /* wcChar14 */
|
|
'r', 0x00, /* wcChar15 */
|
|
' ', 0x00, /* wcChar16 */
|
|
'2', 0x00, /* wcChar16 */
|
|
'.', 0x00, /* wcChar16 */
|
|
'0', 0x00, /* wcChar17 */
|
|
///////////////////////////////////////
|
|
/// string3 descriptor
|
|
///////////////////////////////////////
|
|
0x12, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'2', 0x00, /* wcChar0 */
|
|
'0', 0x00, /* wcChar1 */
|
|
'2', 0x00, /* wcChar2 */
|
|
'0', 0x00, /* wcChar3 */
|
|
'0', 0x00, /* wcChar4 */
|
|
'5', 0x00, /* wcChar5 */
|
|
'2', 0x00, /* wcChar6 */
|
|
'0', 0x00, /* wcChar7 */
|
|
#ifdef CONFIG_USB_HS
|
|
///////////////////////////////////////
|
|
/// device qualifier descriptor
|
|
///////////////////////////////////////
|
|
0x0a,
|
|
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
|
0x00,
|
|
0x02,
|
|
0x02,
|
|
0x02,
|
|
0x01,
|
|
0x40,
|
|
0x01,
|
|
0x00,
|
|
#endif
|
|
0x00
|
|
};
|
|
|
|
#define AICUPG_BUF_SIZE 2048
|
|
|
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[AICUPG_BUF_SIZE] = "";
|
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[AICUPG_BUF_SIZE] = "";
|
|
|
|
volatile bool ep_tx_busy_flag = false;
|
|
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
#include <rtthread.h>
|
|
|
|
static rt_device_t g_aicupg_uart = NULL;
|
|
static struct cdc_line_coding g_aicupg_line = {115200, 0, 0, 8};
|
|
|
|
static struct rt_semaphore g_uart_sem;
|
|
static struct rt_ringbuffer g_uart_rb = {0};
|
|
static unsigned int g_uart_dat_sz = 0;
|
|
static uint8_t g_uart_buf[AICUPG_BUF_SIZE] = "";
|
|
static uint32_t g_acm_in_is_idle = 1;
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB_HS
|
|
#define CDC_MAX_MPS 512
|
|
#else
|
|
#define CDC_MAX_MPS 64
|
|
#endif
|
|
|
|
void usbd_event_handler(uint8_t event)
|
|
{
|
|
switch (event) {
|
|
case USBD_EVENT_RESET:
|
|
break;
|
|
case USBD_EVENT_CONNECTED:
|
|
break;
|
|
case USBD_EVENT_DISCONNECTED:
|
|
break;
|
|
case USBD_EVENT_RESUME:
|
|
break;
|
|
case USBD_EVENT_SUSPEND:
|
|
break;
|
|
case USBD_EVENT_CONFIGURED:
|
|
/* setup first out ep read transfer */
|
|
usbd_ep_start_read(CDC_OUT_EP, read_buffer, AICUPG_BUF_SIZE);
|
|
break;
|
|
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
|
break;
|
|
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void usbd_cdc_acm_bulk_out(uint8_t ep, uint32_t nbytes)
|
|
{
|
|
// USB_LOG_RAW("Out len: %ld\n", nbytes);
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
if (nbytes > 0) {
|
|
int ret = 0;
|
|
|
|
ret = rt_device_write(g_aicupg_uart, -1, (const void *)read_buffer,
|
|
(rt_size_t)nbytes);
|
|
if (ret != nbytes)
|
|
USB_LOG_INFO("rt_device_write(%d) return %d\n", (u32)nbytes, ret);
|
|
}
|
|
#endif
|
|
|
|
/* setup next out ep read transfer */
|
|
usbd_ep_start_read(CDC_OUT_EP, read_buffer, AICUPG_BUF_SIZE);
|
|
}
|
|
|
|
void usbd_cdc_acm_bulk_in(uint8_t ep, uint32_t nbytes)
|
|
{
|
|
rt_size_t len = nbytes;
|
|
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
len = rt_ringbuffer_data_len(&g_uart_rb);
|
|
// USB_LOG_DBG("In len: %d/%ld\n", len, nbytes);
|
|
rt_ringbuffer_get(&g_uart_rb, write_buffer, len);
|
|
|
|
len = rt_ringbuffer_data_len(&g_uart_rb);
|
|
if (len == 0) {
|
|
g_acm_in_is_idle = 1;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
usbd_ep_start_write(CDC_IN_EP, write_buffer, len);
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
g_acm_in_is_idle = 0;
|
|
#endif
|
|
|
|
if (len && (len % CDC_MAX_MPS) == 0) {
|
|
/* send zlp */
|
|
usbd_ep_start_write(CDC_IN_EP, NULL, 0);
|
|
} else {
|
|
ep_tx_busy_flag = false;
|
|
}
|
|
}
|
|
|
|
/*!< endpoint call back */
|
|
struct usbd_endpoint cdc_out_ep = {
|
|
.ep_addr = CDC_OUT_EP,
|
|
.ep_cb = usbd_cdc_acm_bulk_out
|
|
};
|
|
|
|
struct usbd_endpoint cdc_in_ep = {
|
|
.ep_addr = CDC_IN_EP,
|
|
.ep_cb = usbd_cdc_acm_bulk_in
|
|
};
|
|
|
|
static struct usbd_interface intf0;
|
|
static struct usbd_interface intf1;
|
|
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
|
|
rt_err_t aicupg_uart_recv_cb(rt_device_t dev, rt_size_t size)
|
|
{
|
|
if (size > 0) {
|
|
g_uart_dat_sz = size;
|
|
rt_sem_release(&g_uart_sem);
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
void aicupg_uart_recv_thread(void *argv)
|
|
{
|
|
int ret = 0;
|
|
|
|
aicos_msleep(3000);
|
|
while (1) {
|
|
rt_sem_take(&g_uart_sem, RT_WAITING_FOREVER);
|
|
if (!g_uart_dat_sz)
|
|
continue;
|
|
|
|
if (g_uart_dat_sz > AICUPG_BUF_SIZE / 2) {
|
|
pr_err("The data length %d is too bigger!\n", g_uart_dat_sz);
|
|
g_uart_dat_sz = AICUPG_BUF_SIZE / 2;
|
|
}
|
|
|
|
ret = rt_device_read(g_aicupg_uart, -1, write_buffer, g_uart_dat_sz);
|
|
if (ret > 0) {
|
|
write_buffer[ret] = 0;
|
|
pr_debug("Idle %d, recv %d data: |%s|\n",
|
|
g_acm_in_is_idle, ret, write_buffer);
|
|
rt_ringbuffer_put_force(&g_uart_rb, write_buffer, g_uart_dat_sz);
|
|
if (g_acm_in_is_idle)
|
|
usbd_ep_start_write(CDC_IN_EP, write_buffer, g_uart_dat_sz);
|
|
} else {
|
|
if (ret < 0)
|
|
pr_warn("read() return [%ld] %s\n",
|
|
rt_get_errno(), rt_strerror(rt_get_errno()));
|
|
}
|
|
aicos_msleep(10);
|
|
}
|
|
|
|
rt_sem_detach(&g_uart_sem);
|
|
rt_device_close(g_aicupg_uart);
|
|
}
|
|
|
|
#endif
|
|
|
|
int cdc_acm_init(void)
|
|
{
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
rt_thread_t thid = NULL;
|
|
char name[8] = "";
|
|
int ret = 0;
|
|
|
|
snprintf(name, 8, "uart%d", AICUPG_UART_DEV_NO);
|
|
pr_info("Link %s to ACM ...\n", name);
|
|
g_aicupg_uart = rt_device_find(name);
|
|
if (!g_aicupg_uart) {
|
|
pr_err("Failed to find %s\n", name);
|
|
return -1;
|
|
}
|
|
ret = rt_device_open(g_aicupg_uart,
|
|
RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
|
|
if (ret) {
|
|
pr_err("Failed to open %s\n", name);
|
|
return -1;
|
|
}
|
|
rt_device_set_rx_indicate(g_aicupg_uart, aicupg_uart_recv_cb);
|
|
|
|
rt_ringbuffer_init(&g_uart_rb, g_uart_buf, AICUPG_BUF_SIZE);
|
|
rt_sem_init(&g_uart_sem, name, 0, RT_IPC_FLAG_FIFO);
|
|
|
|
thid = rt_thread_create(name, aicupg_uart_recv_thread,
|
|
RT_NULL, 1024*2, 0, 10);
|
|
if (thid != RT_NULL) {
|
|
rt_thread_startup(thid);
|
|
} else {
|
|
pr_err("Failed to create thread %s\n", name);
|
|
rt_device_close(g_aicupg_uart);
|
|
return -RT_ERROR;
|
|
}
|
|
#endif
|
|
|
|
usbd_desc_register(cdc_descriptor);
|
|
usbd_add_interface(usbd_cdc_acm_init_intf(&intf0));
|
|
usbd_add_interface(usbd_cdc_acm_init_intf(&intf1));
|
|
usbd_add_endpoint(&cdc_out_ep);
|
|
usbd_add_endpoint(&cdc_in_ep);
|
|
usbd_initialize();
|
|
return 0;
|
|
}
|
|
INIT_DEVICE_EXPORT(cdc_acm_init);
|
|
|
|
volatile uint8_t dtr_enable = 0;
|
|
|
|
void usbd_cdc_acm_set_dtr(uint8_t intf, bool dtr)
|
|
{
|
|
if (dtr) {
|
|
USB_LOG_INFO("intf: %d, dtr: %d\n", intf, dtr);
|
|
dtr_enable = 1;
|
|
} else {
|
|
dtr_enable = 0;
|
|
}
|
|
}
|
|
|
|
void cdc_acm_data_send_with_dtr_test(void)
|
|
{
|
|
USB_LOG_INFO("dtr_enable: %d, busy_flag: %d\n", dtr_enable, ep_tx_busy_flag);
|
|
if (dtr_enable) {
|
|
ep_tx_busy_flag = true;
|
|
usbd_ep_start_write(CDC_IN_EP, write_buffer, AICUPG_BUF_SIZE);
|
|
while (ep_tx_busy_flag) {
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_ENABLE_LOCAL_UART
|
|
|
|
#pragma GCC optimize ("O0")
|
|
static int baudrate_is_valid(u32 rate)
|
|
{
|
|
int i;
|
|
u32 rates[] = {BAUD_RATE_115200,
|
|
BAUD_RATE_230400,
|
|
BAUD_RATE_460800,
|
|
BAUD_RATE_921600,
|
|
BAUD_RATE_2000000,
|
|
BAUD_RATE_3000000};
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rates); i++) {
|
|
if (rate == rates[i])
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
rt_err_t aic_uart_configure(u32 index, struct serial_configure *cfg);
|
|
|
|
void usbd_cdc_acm_set_line_coding(uint8_t intf,
|
|
struct cdc_line_coding *line_coding)
|
|
{
|
|
struct serial_configure cfg = {0};
|
|
int ret = 0;
|
|
|
|
if (!g_aicupg_uart)
|
|
return;
|
|
|
|
if (!memcmp(line_coding, &g_aicupg_line, sizeof(struct cdc_line_coding))) {
|
|
USB_LOG_DBG("%s() No change\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (!baudrate_is_valid(line_coding->dwDTERate)) {
|
|
pr_warn("Invalid baudrate %d\n", (u32)line_coding->dwDTERate);
|
|
return;
|
|
}
|
|
cfg.baud_rate = line_coding->dwDTERate;
|
|
|
|
if (line_coding->bDataBits < DATA_BITS_5
|
|
|| line_coding->bDataBits > DATA_BITS_8) {
|
|
pr_warn("Invalid data bits %d\n", line_coding->bDataBits);
|
|
return;
|
|
}
|
|
cfg.data_bits = line_coding->bDataBits;
|
|
cfg.stop_bits = 1;
|
|
|
|
USB_LOG_INFO("Change UART: Baud rate %d, Bits %d, Parity %d\n",
|
|
(u32)line_coding->dwDTERate, line_coding->bDataBits,
|
|
line_coding->bParityType);
|
|
|
|
ret = aic_uart_configure(AICUPG_UART_DEV_NO, &cfg);
|
|
if (ret < 0) {
|
|
pr_err("Failed to config UART. ret = -%d\n", -ret);
|
|
return;
|
|
}
|
|
memcpy(&g_aicupg_line, line_coding, sizeof(struct cdc_line_coding));
|
|
}
|
|
|
|
void usbd_cdc_acm_get_line_coding(uint8_t intf,
|
|
struct cdc_line_coding *line_coding)
|
|
{
|
|
if (!g_aicupg_uart)
|
|
return;
|
|
|
|
memcpy(line_coding, &g_aicupg_line, sizeof(struct cdc_line_coding));
|
|
}
|
|
|
|
#endif
|