Files
ESPC3-wireless/app/drivers/data_port/usb-host/msc/msc_host.c
LokLiang 176b2c49f6 20250529 同步自原始工程:
优化 CMakeLists.txt,增加 lib-out 目录的包含;修改 app_config.c 中的 LED 灯带开关变量名;更新 app_config.h,增加新的灯效模式和方向控制;更新 SBDEMO.h 中的默认设备名称;在 msc_host.c 中添加 USB 设备连接类型的处理;在 usbport.c 中增加 USB 连接类型的状态管理;更新 Kconfig,增加 LED 灯带的最大图层数和竞速模式选项;新增 spbelib_interface.h 文件,定义无线调参功能接口;删除不再使用的 components/CMakeLists.txt 文件;更新 misc.h,添加读取 MCU 身份信息的 MD5 值的函数声明;修改 tim.h 中的 drv_pwm_init 函数参数;更新 kk.h,增加默认工作队列的创建宏;优化 sh.c 中的命令行插入字符串逻辑;更新 sdkconfig 默认配置文件,升级 ESP-IDF 版本和调整蓝牙默认发射功率。
2025-05-29 18:05:20 +08:00

2704 lines
108 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/param.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "freertos/event_groups.h"
#include "usb/usb_host.h"
#include "private_include/diskio_usb.h"
#include "private_include/msc_common.h"
#include "include/msc_host.h"
#include "private_include/msc_scsi_bot.h"
#include "usb/usb_types_ch9.h"
#include "usb/usb_helpers.h"
#include "cdc/cdc_acm_host/include/usb/usb_types_cdc.h"
#include "config/hardware_define.h"
#include "os/os.h"
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
#define SYS_LOG_DOMAIN "USBH"
#include "sys_log.h"
static portMUX_TYPE msc_lock = portMUX_INITIALIZER_UNLOCKED;
#define MSC_ENTER_CRITICAL() portENTER_CRITICAL(&msc_lock)
#define MSC_EXIT_CRITICAL() portEXIT_CRITICAL(&msc_lock)
#define MSC_GOTO_ON_FALSE_CRITICAL(exp, err) \
do { \
if (!(exp)) { \
MSC_EXIT_CRITICAL(); \
ret = err; \
goto fail; \
} \
} while (0)
#define MSC_RETURN_ON_FALSE_CRITICAL(exp, err) \
do { \
if (!(exp)) { \
MSC_EXIT_CRITICAL(); \
return err; \
} \
} while (0)
#define WAIT_FOR_READY_TIMEOUT_MS 3000
#define TAG "USB_MSC"
#define SCSI_COMMAND_SET 0x06
#define BULK_ONLY_TRANSFER 0x50
#define MSC_NO_SENSE 0x00
#define MSC_NOT_READY 0x02
#define MSC_UNIT_ATTENTION 0x06
typedef struct {
usb_host_client_handle_t client_handle;
msc_host_event_cb_t user_cb;
void *user_arg;
SemaphoreHandle_t all_events_handled;
volatile bool end_client_event_handling;
} msc_driver_t;
static msc_driver_t *s_msc_driver;
STAILQ_HEAD(devices, msc_host_device)
devices_tailq;
typedef struct {
uint8_t type; // usbport_status_e
uint32_t vendor_id;
uint32_t product_id;
} usb_device_id_t;
typedef enum {
USB_DEVICE_TYPE_NONE = 0, // 没有外设
USB_DEVICE_TYPE_CDC = 1, // 外设处于cdc状态
USB_DEVICE_TYPE_DFU = 2, // 外设处于dfu状态
USB_DEVICE_TYPE_MSC = 3, // 外设处于dfu状态
} usb_device_type_e;
/////// cdc
#define CDC_CHECK(a, str, ret) \
if (!(a)) { \
SYS_LOG_ERR("%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret); \
}
#define CDC_CHECK_GOTO(a, str, lable) \
if (!(a)) { \
SYS_LOG_ERR("%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
goto lable; \
}
#define CDC_DATA_TASK_NAME "cdc-data"
#define CDC_DATA_TASK_PRIORITY (5)
#define CDC_DATA_TASK_STACK_SIZE 3072
#define CDC_DATA_TASK_CORE 0
// CDC devices often implement Interface Association Descriptor (IAD). Parse IAD only when
// bDeviceClass = 0xEF (Miscellaneous Device Class), bDeviceSubClass = 0x02 (Common Class), bDeviceProtocol = 0x01 (Interface Association Descriptor)
// @see USB Interface Association Descriptor: Device Class Code and Use Model rev 1.0, Table 1-1
#define USB_SUBCLASS_COMMON 0x02
#define USB_DEVICE_PROTOCOL_IAD 0x01
// CDC-ACM spinlock
static portMUX_TYPE cdc_acm_lock = portMUX_INITIALIZER_UNLOCKED;
#define CDC_ACM_ENTER_CRITICAL() portENTER_CRITICAL(&cdc_acm_lock)
#define CDC_ACM_EXIT_CRITICAL() portEXIT_CRITICAL(&cdc_acm_lock)
// CDC-ACM events
#define CDC_ACM_TEARDOWN BIT0
#define CDC_ACM_TEARDOWN_COMPLETE BIT1
// CDC-ACM check macros
#define CDC_ACM_CHECK(cond, ret_val) ({ \
if (!(cond)) { \
return (ret_val); \
} \
})
#define CDC_ACM_CHECK_FROM_CRIT(cond, ret_val) ({ \
if (!(cond)) { \
CDC_ACM_EXIT_CRITICAL(); \
return ret_val; \
} \
})
// CDC-ACM driver object
typedef struct {
usb_host_client_handle_t cdc_acm_client_hdl; /*!< USB Host handle reused for all CDC-ACM devices in the system */
SemaphoreHandle_t open_close_mutex;
EventGroupHandle_t event_group;
SLIST_HEAD(list_dev, cdc_dev_s)
cdc_devices_list; /*!< List of open pseudo devices */
} cdc_acm_obj_t;
// static cdc_acm_obj_t *p_cdc_acm_obj = NULL;
/**
* @brief USB CDC PSTN Call Descriptor
*
* @see Table 3, USB CDC-PSTN specification rev. 1.2
*/
typedef struct {
uint8_t bFunctionLength;
const uint8_t bDescriptorType;
const cdc_desc_subtype_t bDescriptorSubtype;
union {
struct {
uint8_t call_management : 1; // Device handles call management itself
uint8_t call_over_data_if : 1; // Device sends/receives call management information over Data Class interface
uint8_t reserved : 6;
};
uint8_t val;
} bmCapabilities;
uint8_t bDataInterface; // Interface number of Data Class interface optionally used for call management
} __attribute__((packed)) cdc_acm_call_desc_t;
/**
* @brief USB CDC PSTN Abstract Control Model Descriptor
*
* @see Table 4, USB CDC-PSTN specification rev. 1.2
*/
typedef struct {
uint8_t bFunctionLength;
const uint8_t bDescriptorType;
const cdc_desc_subtype_t bDescriptorSubtype;
union {
struct {
uint8_t feature : 1; // Device supports Set/Clear/Get_Comm_Feature requests
uint8_t serial : 1; // Device supports Set/Get_Line_Coding, Set_Control_Line_State and Serial_State request and notifications
uint8_t send_break : 1; // Device supports Send_Break request
uint8_t network : 1; // Device supports Network_Connection notification
uint8_t reserved : 4;
};
uint8_t val;
} bmCapabilities;
} __attribute__((packed)) cdc_acm_acm_desc_t;
typedef struct cdc_dev_s cdc_dev_t;
struct cdc_dev_s {
usb_device_handle_t dev_hdl; // USB device handle
void *cb_arg; // Common argument for user's callbacks (data IN and Notification)
struct {
usb_transfer_t *out_xfer; // OUT data transfer
usb_transfer_t *in_xfer; // IN data transfer
cdc_acm_data_callback_t in_cb; // User's callback for async (non-blocking) data IN
const usb_intf_desc_t *intf_desc; // Pointer to data interface descriptor
SemaphoreHandle_t out_mux; // OUT mutex
} data;
struct {
usb_transfer_t *xfer; // IN notification transfer
const usb_intf_desc_t *intf_desc; // Pointer to notification interface descriptor, can be NULL if there is no notification channel in the device
cdc_acm_host_dev_callback_t cb; // User's callback for device events
} notif; // Structure with Notif pipe data
usb_transfer_t *ctrl_transfer; // CTRL (endpoint 0) transfer
SemaphoreHandle_t ctrl_mux; // CTRL mutex
cdc_acm_uart_state_t serial_state; // Serial State
cdc_comm_protocol_t comm_protocol;
cdc_data_protocol_t data_protocol;
int num_cdc_intf_desc; // Number of CDC Interface descriptors in following array
const usb_standard_desc_t **cdc_intf_desc; // CDC Interface descriptors
SLIST_ENTRY(cdc_dev_s)
list_entry;
};
cdc_dev_t *g_cdc_dev = NULL;
/**
* @brief Notification received callback
*
* Notification (interrupt) IN transfer is submitted at the end of this function to ensure periodic poll of IN endpoint.
*
* @param[in] transfer Transfer that triggered the callback
*/
static void notif_xfer_cb(usb_transfer_t *transfer);
/**
* @brief Data received callback
*
* Data (bulk) IN transfer is submitted at the end of this function to ensure continuous poll of IN endpoint.
*
* @param[in] transfer Transfer that triggered the callback
*/
static void in_xfer_cb(usb_transfer_t *transfer);
/**
* @brief Data send callback
*
* Reused for bulk OUT and CTRL transfers
*
* @param[in] transfer Transfer that triggered the callback
*/
static void out_xfer_cb(usb_transfer_t *transfer);
/**
* @brief USB Host Client event callback
*
* Handling of USB device connection/disconnection to/from root HUB.
*
* @param[in] event_msg Event message type
* @param[in] arg Caller's argument (not used in this driver)
*/
// static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg);
static EventGroupHandle_t s_usb_event_group = NULL;
static RingbufHandle_t s_in_ringbuf_handle = NULL;
static RingbufHandle_t s_out_ringbuf_handle = NULL;
static SemaphoreHandle_t s_usb_read_mux = NULL;
static SemaphoreHandle_t s_usb_write_mux = NULL;
// static TaskHandle_t s_usb_processing_task_hdl = NULL;
// static portMUX_TYPE s_in_ringbuf_mux = portMUX_INITIALIZER_UNLOCKED;
static portMUX_TYPE s_out_ringbuf_mux = portMUX_INITIALIZER_UNLOCKED;
volatile static int s_in_buffered_data_len = 0;
volatile static int s_out_buffered_data_len = 0;
#define USB_TASK_KILL_BIT BIT1
#define CDC_DATA_TASK_KILL_BIT BIT4
#define CDC_DEVICE_READY_BIT BIT19
#define TIMEOUT_USB_RINGBUF_MS 200 // Timeout for Ring Buffer push
/////// end cdc
///// stm32 dfu update
/**
* @brief Initializer for a request to get a device's device descriptor
*/
#define USB_SETUP_PACKET_INIT_GET_FUNCTION_DESC(setup_pkt_ptr) ({ \
(setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_STANDARD | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
(setup_pkt_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \
(setup_pkt_ptr)->wValue = 0x2100; \
(setup_pkt_ptr)->wIndex = 0; \
(setup_pkt_ptr)->wLength = 255; \
})
#ifndef USB_SETUP_PACKET_INIT_GET_STATUS
#define USB_SETUP_PACKET_INIT_GET_STATUS(setup_pkt_ptr) ({ \
(setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
(setup_pkt_ptr)->bRequest = STM32_DFU_REQUEST_GETSTATUS; \
(setup_pkt_ptr)->wValue = 0; \
(setup_pkt_ptr)->wIndex = 0; \
(setup_pkt_ptr)->wLength = 6; \
})
#endif
#define USB_SETUP_PACKET_INIT_CLEAR_STATUS(setup_pkt_ptr) ({ \
(setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
(setup_pkt_ptr)->bRequest = STM32_DFU_REQUEST_CLRSTATUS; \
(setup_pkt_ptr)->wValue = 0; \
(setup_pkt_ptr)->wIndex = 0; \
(setup_pkt_ptr)->wLength = 0; \
})
#define USB_SETUP_PACKET_INIT_LOAD_ADDRESS(setup_pkt_ptr, pkt_data) ({ \
(setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \
(setup_pkt_ptr)->bRequest = STM32_DFU_REQUEST_DNLOAD; \
(setup_pkt_ptr)->wValue = 0; \
(setup_pkt_ptr)->wIndex = 0; \
(setup_pkt_ptr)->wLength = 5; \
memcpy(((uint8_t *)(setup_pkt_ptr)) + sizeof(usb_setup_packet_t), pkt_data, 5); \
})
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bmAttributes;
uint16_t wDetachTimeOut;
uint16_t wTransferSize;
uint8_t bcdDFUVersion;
} __attribute__((packed));
uint8_t val[USB_SETUP_PACKET_SIZE];
} usb_function_desc_packet_t;
#define ENUM_CTRL_TRANSFER_MAX_LEN 256
#define STM32_DFU_REQUEST_DETACH 0x00
#define STM32_DFU_REQUEST_DNLOAD 0x01
#define STM32_DFU_REQUEST_UPLOAD 0x02
#define STM32_DFU_REQUEST_GETSTATUS 0x03
#define STM32_DFU_REQUEST_CLRSTATUS 0x04
#define STM32_DFU_REQUEST_GETSTATE 0x05
#define STM32_DFU_REQUEST_ABORT 0x06
#define STM32_DFU_STATE_APP_IDLE 0
#define STM32_DFU_STATE_APP_DETACH 1
#define STM32_DFU_STATE_DFU_IDLE 2
#define STM32_DFU_STATE_DNLOAD_SYNC 3
#define STM32_DFU_STATE_DNBUSY 4
#define STM32_DFU_STATE_DNLOAD_IDLE 5
#define STM32_DFU_STATE_MAINFES_SYNC 6
#define STM32_DFU_STATE_MAINFEST 7
#define STM32_DFU_STATE_MAINFEST_WAIT_RESET 8
#define STM32_DFU_STATE_UPLOAD_IDLE 9
#define STM32_DFU_STATE_ERROR 10
///// end stm32 dfu update
// 兼容USB设备
static const usb_device_id_t g_compatiable_usb_device_list[] = {
{.type = USB_DEVICE_TYPE_CDC, .vendor_id = 0x1209, .product_id = 0x5741},
{.type = USB_DEVICE_TYPE_CDC, .vendor_id = 0x483, .product_id = 0x5740},
{.type = USB_DEVICE_TYPE_DFU, .vendor_id = 0x483, .product_id = 0xDF11}};
static uint8_t g_current_device_type = USB_DEVICE_TYPE_NONE;
static const usb_standard_desc_t *next_interface_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset)
{
return usb_parse_next_descriptor_of_type(desc, len, USB_W_VALUE_DT_INTERFACE, (int *)offset);
}
static const usb_standard_desc_t *next_endpoint_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset)
{
return usb_parse_next_descriptor_of_type(desc, len, USB_B_DESCRIPTOR_TYPE_ENDPOINT, (int *)offset);
}
static const usb_intf_desc_t *find_msc_interface(const usb_config_desc_t *config_desc, size_t *offset)
{
size_t total_length = config_desc->wTotalLength;
const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)config_desc;
next_desc = next_interface_desc(next_desc, total_length, offset);
while (next_desc) {
const usb_intf_desc_t *ifc_desc = (const usb_intf_desc_t *)next_desc;
if (ifc_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE && ifc_desc->bInterfaceSubClass == SCSI_COMMAND_SET && ifc_desc->bInterfaceProtocol == BULK_ONLY_TRANSFER) {
return ifc_desc;
}
next_desc = next_interface_desc(next_desc, total_length, offset);
};
return NULL;
}
/**
* @brief Extracts configuration from configuration descriptor.
*
* @note Passes interface and endpoint descriptors to obtain:
* - interface number, IN endpoint, OUT endpoint, max. packet size
*
* @param[in] cfg_desc Configuration descriptor
* @param[out] cfg Obtained configuration
* @return esp_err_t
*/
static esp_err_t extract_config_from_descriptor(const usb_config_desc_t *cfg_desc, msc_config_t *cfg)
{
size_t offset = 0;
size_t total_len = cfg_desc->wTotalLength;
const usb_intf_desc_t *ifc_desc = find_msc_interface(cfg_desc, &offset);
assert(ifc_desc);
const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)ifc_desc;
const usb_ep_desc_t *ep_desc = NULL;
cfg->iface_num = ifc_desc->bInterfaceNumber;
next_desc = next_endpoint_desc(next_desc, total_len, &offset);
MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED);
ep_desc = (const usb_ep_desc_t *)next_desc;
if (ep_desc->bEndpointAddress & 0x80) {
cfg->bulk_in_ep = ep_desc->bEndpointAddress;
cfg->bulk_in_mps = ep_desc->wMaxPacketSize;
} else {
cfg->bulk_out_ep = ep_desc->bEndpointAddress;
}
next_desc = next_endpoint_desc(next_desc, total_len, &offset);
MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED);
ep_desc = (const usb_ep_desc_t *)next_desc;
if (ep_desc->bEndpointAddress & 0x80) {
cfg->bulk_in_ep = ep_desc->bEndpointAddress;
cfg->bulk_in_mps = ep_desc->wMaxPacketSize;
} else {
cfg->bulk_out_ep = ep_desc->bEndpointAddress;
}
return ESP_OK;
}
static esp_err_t msc_deinit_device(msc_device_t *dev, bool install_failed)
{
MSC_ENTER_CRITICAL();
MSC_RETURN_ON_FALSE_CRITICAL(dev, ESP_ERR_INVALID_STATE);
STAILQ_REMOVE(&devices_tailq, dev, msc_host_device, tailq_entry);
MSC_EXIT_CRITICAL();
if (dev->transfer_done) {
vSemaphoreDelete(dev->transfer_done);
}
if (install_failed) {
// Error code is unchecked, as it's unknown at what point installation failed.
usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num);
usb_host_device_close(s_msc_driver->client_handle, dev->handle);
usb_host_transfer_free(dev->xfer);
} else {
MSC_RETURN_ON_ERROR(usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num));
MSC_RETURN_ON_ERROR(usb_host_device_close(s_msc_driver->client_handle, dev->handle));
MSC_RETURN_ON_ERROR(usb_host_transfer_free(dev->xfer));
}
free(dev);
return ESP_OK;
}
// Some MSC devices requires to change its internal state from non-ready to ready
static esp_err_t msc_wait_for_ready_state(msc_device_t *dev, size_t timeout_ms)
{
esp_err_t err;
scsi_sense_data_t sense;
uint32_t trials = MAX(1, timeout_ms / 100);
do {
err = scsi_cmd_unit_ready(dev);
if (err != ESP_OK) {
MSC_RETURN_ON_ERROR(scsi_cmd_sense(dev, &sense));
if (sense.key != MSC_NOT_READY && sense.key != MSC_UNIT_ATTENTION && sense.key != MSC_NO_SENSE) {
return ESP_ERR_MSC_INTERNAL;
}
}
vTaskDelay(pdMS_TO_TICKS(100));
} while (trials-- && err);
return err;
}
static bool is_mass_storage_device(uint8_t dev_addr)
{
size_t dummy = 0;
bool is_msc_device = false;
usb_device_handle_t device;
const usb_config_desc_t *config_desc;
if (usb_host_device_open(s_msc_driver->client_handle, dev_addr, &device) == ESP_OK) {
if (usb_host_get_active_config_descriptor(device, &config_desc) == ESP_OK) {
if (find_msc_interface(config_desc, &dummy)) {
is_msc_device = true;
} else {
SYS_LOG_DBG("Connected USB device is not MSC");
}
}
usb_host_device_close(s_msc_driver->client_handle, device);
}
return is_msc_device;
}
static void event_handler_task(void *arg)
{
while (1) {
usb_host_client_handle_events(s_msc_driver->client_handle, pdMS_TO_TICKS(50));
if (s_msc_driver->end_client_event_handling) {
break;
}
}
usb_host_client_unblock(s_msc_driver->client_handle);
ESP_ERROR_CHECK(usb_host_client_deregister(s_msc_driver->client_handle));
xSemaphoreGive(s_msc_driver->all_events_handled);
vTaskDelete(NULL);
}
static msc_device_t *find_msc_device(usb_device_handle_t device_handle)
{
msc_host_device_handle_t device;
STAILQ_FOREACH(device, &devices_tailq, tailq_entry)
{
if (device_handle == device->handle) {
return device;
}
}
return NULL;
}
static void client_event_cb(const usb_host_client_event_msg_t *event, void *arg)
{
SYS_LOG_INF("CLIENT EVENT DID RECEIVED");
if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV) {
if (is_mass_storage_device(event->new_dev.address)) {
const msc_host_event_t msc_event = {
.event = MSC_DEVICE_CONNECTED,
.device.address = event->new_dev.address,
};
g_current_device_type = USB_DEVICE_TYPE_MSC;
s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg);
} else {
// 检查vendor id和product id判断是cdc还是dfu设备
usb_device_handle_t device;
const usb_device_desc_t *device_desc;
uint8_t event_type = 0;
uint16_t vendor_id = 0;
uint16_t product_id = 0;
if (usb_host_device_open(s_msc_driver->client_handle, event->new_dev.address, &device) == ESP_OK) {
if (usb_host_get_device_descriptor(device, &device_desc) == ESP_OK) {
const int compatiable_dev_count =
sizeof(g_compatiable_usb_device_list) / sizeof(usb_device_id_t);
for (int j = 0; j < compatiable_dev_count; j++) {
const usb_device_id_t *comp_dev_info =
&(g_compatiable_usb_device_list[j]);
SYS_LOG_INF("loop comp dev: 0x%08x, 0x%08x, %d", comp_dev_info->vendor_id, comp_dev_info->product_id, comp_dev_info->type);
if (device_desc->idVendor == comp_dev_info->vendor_id && device_desc->idProduct == comp_dev_info->product_id) {
if (comp_dev_info->type == USB_DEVICE_TYPE_CDC) {
event_type = CDC_DEVICE_CONNECTED;
g_current_device_type = USB_DEVICE_TYPE_CDC;
} else if (comp_dev_info->type == USB_DEVICE_TYPE_DFU) {
event_type = DFU_DEVICE_CONNECTED;
g_current_device_type = USB_DEVICE_TYPE_DFU;
}
vendor_id = device_desc->idVendor;
product_id = device_desc->idProduct;
SYS_LOG_INF("get device event:%d", event_type);
break;
}
}
}
usb_host_device_close(s_msc_driver->client_handle, device);
}
if (event_type != 0) {
const msc_host_event_t msc_event = {
.event = event_type,
.device.address = event->new_dev.address,
.vendor_id = vendor_id,
.product_id = product_id,
};
s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg);
}
}
} else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE) {
msc_device_t *usb_device = find_msc_device(event->dev_gone.dev_hdl);
int event = 0;
SYS_LOG_INF("DEV GONE:%d", g_current_device_type);
switch (g_current_device_type) {
case USB_DEVICE_TYPE_CDC:
event = CDC_DEVICE_DISCONNECTED;
// 退出任务
xEventGroupSetBits(s_usb_event_group, CDC_DATA_TASK_KILL_BIT);
SYS_LOG_WRN("Waitting for CDC task delete");
while (xEventGroupGetBits(s_usb_event_group) & CDC_DATA_TASK_KILL_BIT) {
vTaskDelay(10 / portTICK_PERIOD_MS);
}
break;
case USB_DEVICE_TYPE_DFU:
event = DFU_DEVICE_DISCONNECTED;
break;
case USB_DEVICE_TYPE_MSC:
event = MSC_DEVICE_DISCONNECTED;
break;
}
if (event != 0) {
const msc_host_event_t msc_event = {
.event = event,
.device.handle = usb_device,
};
s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg);
}
}
}
esp_err_t msc_host_install(const msc_host_driver_config_t *config)
{
esp_err_t ret;
MSC_RETURN_ON_INVALID_ARG(config);
MSC_RETURN_ON_INVALID_ARG(config->callback);
if (config->create_backround_task) {
MSC_RETURN_ON_FALSE(config->stack_size != 0, ESP_ERR_INVALID_ARG);
MSC_RETURN_ON_FALSE(config->task_priority != 0, ESP_ERR_INVALID_ARG);
}
MSC_RETURN_ON_FALSE(!s_msc_driver, ESP_ERR_INVALID_STATE);
msc_driver_t *driver = calloc(1, sizeof(msc_driver_t));
MSC_RETURN_ON_FALSE(driver, ESP_ERR_NO_MEM);
driver->user_cb = config->callback;
driver->user_arg = config->callback_arg;
usb_host_client_config_t client_config = {
.async.client_event_callback = client_event_cb,
.async.callback_arg = NULL,
.max_num_event_msg = 10,
};
driver->end_client_event_handling = false;
driver->all_events_handled = xSemaphoreCreateBinary();
MSC_GOTO_ON_FALSE(driver->all_events_handled, ESP_ERR_NO_MEM);
MSC_GOTO_ON_ERROR(usb_host_client_register(&client_config, &driver->client_handle));
MSC_ENTER_CRITICAL();
MSC_GOTO_ON_FALSE_CRITICAL(!s_msc_driver, ESP_ERR_INVALID_STATE);
s_msc_driver = driver;
STAILQ_INIT(&devices_tailq);
MSC_EXIT_CRITICAL();
if (config->create_backround_task) {
BaseType_t task_created = xTaskCreatePinnedToCore(
event_handler_task, "USB MSC", config->stack_size, NULL, SBTASK_PRIORITY_USB_MSC, NULL, SBTASK_CORE_INDEX_USB_MSC);
MSC_GOTO_ON_FALSE(task_created, ESP_ERR_NO_MEM);
}
return ESP_OK;
fail:
s_msc_driver = NULL;
usb_host_client_deregister(driver->client_handle);
if (driver->all_events_handled) {
vSemaphoreDelete(driver->all_events_handled);
}
free(driver);
return ret;
}
esp_err_t msc_host_uninstall(void)
{
// Make sure msc driver is installed,
// not being uninstalled from other task
// and no msc device is registered
MSC_ENTER_CRITICAL();
MSC_RETURN_ON_FALSE_CRITICAL(s_msc_driver != NULL, ESP_ERR_INVALID_STATE);
MSC_RETURN_ON_FALSE_CRITICAL(!s_msc_driver->end_client_event_handling, ESP_ERR_INVALID_STATE);
MSC_RETURN_ON_FALSE_CRITICAL(STAILQ_EMPTY(&devices_tailq), ESP_ERR_INVALID_STATE);
s_msc_driver->end_client_event_handling = true;
MSC_EXIT_CRITICAL();
xSemaphoreTake(s_msc_driver->all_events_handled, portMAX_DELAY);
vSemaphoreDelete(s_msc_driver->all_events_handled);
free(s_msc_driver);
s_msc_driver = NULL;
return ESP_OK;
}
esp_err_t msc_host_install_device(uint8_t device_address, msc_host_device_handle_t *msc_device_handle)
{
esp_err_t ret;
uint32_t block_size, block_count;
const usb_config_desc_t *config_desc;
msc_device_t *msc_device;
// uint8_t lun;
size_t transfer_size = 512; // Normally the smallest block size
MSC_GOTO_ON_FALSE(msc_device = calloc(1, sizeof(msc_device_t)), ESP_ERR_NO_MEM);
MSC_ENTER_CRITICAL();
MSC_GOTO_ON_FALSE_CRITICAL(s_msc_driver, ESP_ERR_INVALID_STATE);
MSC_GOTO_ON_FALSE_CRITICAL(s_msc_driver->client_handle, ESP_ERR_INVALID_STATE);
STAILQ_INSERT_TAIL(&devices_tailq, msc_device, tailq_entry);
MSC_EXIT_CRITICAL();
MSC_GOTO_ON_FALSE(msc_device->transfer_done = xSemaphoreCreateBinary(), ESP_ERR_NO_MEM);
MSC_GOTO_ON_ERROR(usb_host_device_open(s_msc_driver->client_handle, device_address, &msc_device->handle));
MSC_GOTO_ON_ERROR(usb_host_get_active_config_descriptor(msc_device->handle, &config_desc));
MSC_GOTO_ON_ERROR(extract_config_from_descriptor(config_desc, &msc_device->config));
MSC_GOTO_ON_ERROR(usb_host_transfer_alloc(transfer_size, 0, &msc_device->xfer));
MSC_GOTO_ON_ERROR(usb_host_interface_claim(s_msc_driver->client_handle,
msc_device->handle,
msc_device->config.iface_num,
0));
MSC_GOTO_ON_ERROR(msc_mass_reset(msc_device));
MSC_GOTO_ON_ERROR(scsi_cmd_inquiry(msc_device));
MSC_GOTO_ON_ERROR(msc_wait_for_ready_state(msc_device, WAIT_FOR_READY_TIMEOUT_MS));
MSC_GOTO_ON_ERROR(scsi_cmd_read_capacity(msc_device, &block_size, &block_count));
// Configuration descriptor size of simple MSC device is 32 bytes.
if (config_desc->wTotalLength != 32) {
SYS_LOG_ERR("COMPOSITE DEVICES UNSUPPORTED");
}
msc_device->disk.block_size = block_size;
msc_device->disk.block_count = block_count;
if (block_size > transfer_size) {
usb_transfer_t *larger_xfer;
MSC_GOTO_ON_ERROR(usb_host_transfer_alloc(block_size, 0, &larger_xfer));
usb_host_transfer_free(msc_device->xfer);
msc_device->xfer = larger_xfer;
}
*msc_device_handle = msc_device;
return ESP_OK;
fail:
msc_deinit_device(msc_device, true);
return ret;
}
esp_err_t msc_host_uninstall_device(msc_host_device_handle_t device)
{
MSC_RETURN_ON_INVALID_ARG(device);
return msc_deinit_device((msc_device_t *)device, false);
}
esp_err_t msc_host_read_sector(msc_host_device_handle_t device, size_t sector, void *data, size_t size)
{
MSC_RETURN_ON_INVALID_ARG(device);
msc_device_t *dev = (msc_device_t *)device;
return scsi_cmd_read10(dev, data, sector, 1, dev->disk.block_size);
}
esp_err_t msc_host_write_sector(msc_host_device_handle_t device, size_t sector, const void *data, size_t size)
{
MSC_RETURN_ON_INVALID_ARG(device);
msc_device_t *dev = (msc_device_t *)device;
return scsi_cmd_write10(dev, data, sector, 1, dev->disk.block_size);
}
esp_err_t msc_host_handle_events(uint32_t timeout_ms)
{
MSC_RETURN_ON_FALSE(s_msc_driver != NULL, ESP_ERR_INVALID_STATE);
return usb_host_client_handle_events(s_msc_driver->client_handle, timeout_ms);
}
static esp_err_t msc_read_string_desc(msc_device_t *dev, uint8_t index, wchar_t *str)
{
if (index == 0) {
// String descriptor not available
str[0] = 0;
return ESP_OK;
}
usb_transfer_t *xfer = dev->xfer;
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)xfer->data_buffer, index, 0x409, 64);
MSC_RETURN_ON_ERROR(msc_control_transfer(dev, xfer, USB_SETUP_PACKET_SIZE + 64));
usb_standard_desc_t *desc = (usb_standard_desc_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE);
wchar_t *data = (wchar_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE + 2);
size_t len = MIN((desc->bLength - USB_STANDARD_DESC_SIZE) / 2, MSC_STR_DESC_SIZE - 1);
wcsncpy(str, data, len);
str[len] = 0;
return ESP_OK;
}
esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_device_info_t *info)
{
MSC_RETURN_ON_INVALID_ARG(device);
MSC_RETURN_ON_INVALID_ARG(info);
msc_device_t *dev = (msc_device_t *)device;
const usb_device_desc_t *desc;
MSC_RETURN_ON_ERROR(usb_host_get_device_descriptor(dev->handle, &desc));
info->idProduct = desc->idProduct;
info->idVendor = desc->idVendor;
info->sector_size = dev->disk.block_size;
info->sector_count = dev->disk.block_count;
MSC_RETURN_ON_ERROR(msc_read_string_desc(dev, desc->iManufacturer, info->iManufacturer));
MSC_RETURN_ON_ERROR(msc_read_string_desc(dev, desc->iProduct, info->iProduct));
MSC_RETURN_ON_ERROR(msc_read_string_desc(dev, desc->iSerialNumber, info->iSerialNumber));
return ESP_OK;
}
esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device)
{
msc_device_t *dev = (msc_device_t *)device;
const usb_device_desc_t *device_desc;
const usb_config_desc_t *config_desc;
MSC_RETURN_ON_ERROR(usb_host_get_device_descriptor(dev->handle, &device_desc));
MSC_RETURN_ON_ERROR(usb_host_get_active_config_descriptor(dev->handle, &config_desc));
if (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_INF)
{
usb_print_device_descriptor(device_desc);
usb_print_config_descriptor(config_desc, NULL);
}
return ESP_OK;
}
static void transfer_callback(usb_transfer_t *transfer)
{
msc_device_t *device = (msc_device_t *)transfer->context;
if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
ESP_LOGE("Transfer failed", "Status %d", transfer->status);
}
device->transfer_status = transfer->status;
xSemaphoreGive(device->transfer_done);
}
static esp_err_t wait_for_transfer_done(usb_transfer_t *xfer)
{
msc_device_t *device = (msc_device_t *)xfer->context;
BaseType_t received = xSemaphoreTake(device->transfer_done, pdMS_TO_TICKS(xfer->timeout_ms));
if (received != pdTRUE) {
usb_host_endpoint_halt(xfer->device_handle, xfer->bEndpointAddress);
usb_host_endpoint_flush(xfer->device_handle, xfer->bEndpointAddress);
xSemaphoreTake(device->transfer_done, portMAX_DELAY);
return ESP_ERR_TIMEOUT;
}
return (device->transfer_status == USB_TRANSFER_STATUS_COMPLETED) ? ESP_OK : ESP_FAIL;
}
static inline bool is_in_endpoint(uint8_t endpoint)
{
return endpoint & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK ? true : false;
}
esp_err_t msc_bulk_transfer(msc_device_t *device, uint8_t *data, size_t size, msc_endpoint_t ep)
{
usb_transfer_t *xfer = device->xfer;
MSC_RETURN_ON_FALSE(size <= xfer->data_buffer_size, ESP_ERR_INVALID_SIZE);
uint8_t endpoint = (ep == MSC_EP_IN) ? device->config.bulk_in_ep : device->config.bulk_out_ep;
if (is_in_endpoint(endpoint)) {
xfer->num_bytes = usb_round_up_to_mps(size, device->config.bulk_in_mps);
} else {
memcpy(xfer->data_buffer, data, size);
xfer->num_bytes = size;
}
xfer->device_handle = device->handle;
xfer->bEndpointAddress = endpoint;
xfer->callback = transfer_callback;
xfer->timeout_ms = 1000;
xfer->context = device;
MSC_RETURN_ON_ERROR(usb_host_transfer_submit(xfer));
MSC_RETURN_ON_ERROR(wait_for_transfer_done(xfer));
if (is_in_endpoint(endpoint)) {
memcpy(data, xfer->data_buffer, size);
}
return ESP_OK;
}
esp_err_t msc_control_transfer(msc_device_t *device, usb_transfer_t *xfer, size_t len)
{
xfer->device_handle = device->handle;
xfer->bEndpointAddress = 0;
xfer->callback = transfer_callback;
xfer->timeout_ms = 1000;
xfer->num_bytes = len;
xfer->context = device;
MSC_RETURN_ON_ERROR(usb_host_transfer_submit_control(s_msc_driver->client_handle, xfer));
return wait_for_transfer_done(xfer);
}
////// CDC接口实现
static esp_err_t usb_out_ringbuf_push(const uint8_t *buf, size_t write_bytes, TickType_t xTicksToWait)
{
int res =
xRingbufferSend(s_out_ringbuf_handle, buf, write_bytes, xTicksToWait);
if (res != pdTRUE) {
SYS_LOG_WRN("The out buffer is too small, the data has been lost %u", write_bytes);
return ESP_FAIL;
}
portENTER_CRITICAL(&s_out_ringbuf_mux);
s_out_buffered_data_len += write_bytes;
#ifdef CONFIG_CDC_USE_TRACE_FACILITY
s_ringbuf_out_max = s_out_buffered_data_len > s_ringbuf_out_max ? s_out_buffered_data_len : s_ringbuf_out_max;
#endif
portEXIT_CRITICAL(&s_out_ringbuf_mux);
return ESP_OK;
}
static esp_err_t usb_out_ringbuf_pop(uint8_t *buf, size_t req_bytes, size_t *read_bytes, TickType_t ticks_to_wait)
{
uint8_t *buf_rcv = xRingbufferReceiveUpTo(s_out_ringbuf_handle, read_bytes, ticks_to_wait, req_bytes);
if (buf_rcv) {
memcpy(buf, buf_rcv, *read_bytes);
vRingbufferReturnItem(s_out_ringbuf_handle, (void *)(buf_rcv));
portENTER_CRITICAL(&s_out_ringbuf_mux);
s_out_buffered_data_len -= *read_bytes;
portEXIT_CRITICAL(&s_out_ringbuf_mux);
return ESP_OK;
} else {
return ESP_ERR_NO_MEM;
}
}
static bool _cdc_driver_is_init(void)
{
if (s_usb_event_group == NULL) {
return false;
}
return true;
}
static bool _if_device_ready()
{
if (!s_usb_event_group)
return false;
return xEventGroupGetBits(s_usb_event_group) & CDC_DEVICE_READY_BIT;
}
void cdc_submit_transfer_in(cdc_acm_dev_hdl_t cdc_hdl)
{
assert(cdc_hdl);
cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
ESP_LOGD("CDC_ACM", "Submitting poll for BULK IN transfer");
usb_host_transfer_submit(cdc_dev->data.in_xfer);
}
int cdc_write_bytes(const uint8_t *buf, size_t length)
{
// SYS_LOG_INF("write data to cdc devi11111");
CDC_CHECK(buf != NULL, "invalid args", -1);
int tx_data_size = 0;
if (_cdc_driver_is_init() == false) {
SYS_LOG_INF("CDC Driver not installed");
return -1;
}
if (_if_device_ready() == false) {
SYS_LOG_INF("Device not connected or not ready");
return -1;
}
// SYS_LOG_INF("write data to cdc devi12222");
xSemaphoreTake(s_usb_write_mux, portMAX_DELAY);
// SYS_LOG_INF("write data to cdc devi3333");
esp_err_t ret = usb_out_ringbuf_push(buf, length, pdMS_TO_TICKS(TIMEOUT_USB_RINGBUF_MS));
if (ret != ESP_OK) {
xSemaphoreGive(s_usb_write_mux);
SYS_LOG_DBG("Write ringbuffer failed");
return -1;
}
tx_data_size = length;
xSemaphoreGive(s_usb_write_mux);
return tx_data_size;
}
static esp_err_t cdc_reset_transfer_endpoint(usb_device_handle_t dev_hdl, usb_transfer_t *transfer);
static void _cdc_data_task(void *arg)
{
cdc_dev_t *cdc_dev = (cdc_dev_t *)arg;
const uint32_t timeout_ms = 100;
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
xEventGroupSetBits(s_usb_event_group, CDC_DEVICE_READY_BIT);
SYS_LOG_INF("CDC TASK RUNNING");
while (!(xEventGroupGetBits(s_usb_event_group) & CDC_DATA_TASK_KILL_BIT)) {
size_t num_bytes_to_send = 0;
// SYS_LOG_INF("buffer addr:%08x, buffer size:%d", (uint32_t)cdc_dev->data.out_xfer->data_buffer, cdc_dev->data.out_xfer->data_buffer_size);
esp_err_t ret = usb_out_ringbuf_pop(cdc_dev->data.out_xfer->data_buffer,
cdc_dev->data.out_xfer->data_buffer_size,
&num_bytes_to_send,
0);
if (ret != ESP_OK || num_bytes_to_send == 0) {
vTaskDelay(pdMS_TO_TICKS(20));
continue;
}
// Take OUT mutex and fill the OUT transfer
BaseType_t taken = xSemaphoreTake(cdc_dev->data.out_mux, pdMS_TO_TICKS(timeout_ms));
if (taken != pdTRUE) {
vTaskDelay(pdMS_TO_TICKS(20));
continue;
}
ESP_LOGD("CDC_ACM", "Submitting BULK OUT transfer");
// memcpy(cdc_dev->data.out_xfer->data_buffer, data, data_len);
cdc_dev->data.out_xfer->num_bytes = num_bytes_to_send;
cdc_dev->data.out_xfer->timeout_ms = 100;
ESP_GOTO_ON_ERROR(usb_host_transfer_submit(cdc_dev->data.out_xfer), unblock, TAG, );
// Wait for OUT transfer completion
taken = xSemaphoreTake((SemaphoreHandle_t)cdc_dev->data.out_xfer->context, pdMS_TO_TICKS(timeout_ms));
if (!taken) {
// Reset the endpoint
cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->data.out_xfer);
ret = ESP_ERR_TIMEOUT;
goto unblock;
}
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Bulk OUT transfer error");
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->actual_num_bytes == num_bytes_to_send, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
ret = ESP_OK;
unblock:
xSemaphoreGive(cdc_dev->data.out_mux);
}
xEventGroupClearBits(s_usb_event_group, CDC_DATA_TASK_KILL_BIT);
SYS_LOG_INF("CDC task deleted");
vTaskDelete(NULL);
// esp_err_t ret;
// CDC_ACM_CHECK(cdc_hdl, ESP_ERR_INVALID_ARG);
// cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
// CDC_ACM_CHECK(data && (data_len > 0), ESP_ERR_INVALID_ARG);
// CDC_ACM_CHECK(cdc_dev->data.out_xfer, ESP_ERR_NOT_SUPPORTED); // Device was opened as read-only.
// CDC_ACM_CHECK(data_len <= cdc_dev->data.out_xfer->data_buffer_size, ESP_ERR_INVALID_SIZE);
// return ret;
}
/**
* @brief Free USB transfers used by this device
*
* @note There can be no transfers in flight, at the moment of calling this function.
* @param[in] cdc_dev Pointer to CDC device
*/
static void cdc_transfers_free(cdc_dev_t *cdc_dev)
{
assert(cdc_dev);
usb_host_transfer_free(cdc_dev->notif.xfer);
usb_host_transfer_free(cdc_dev->data.in_xfer);
if (cdc_dev->data.out_xfer != NULL) {
if (cdc_dev->data.out_xfer->context != NULL) {
vSemaphoreDelete((SemaphoreHandle_t)cdc_dev->data.out_xfer->context);
}
if (cdc_dev->data.out_mux != NULL) {
vSemaphoreDelete(cdc_dev->data.out_mux);
}
usb_host_transfer_free(cdc_dev->data.out_xfer);
}
if (cdc_dev->ctrl_transfer != NULL) {
if (cdc_dev->ctrl_transfer->context != NULL) {
vSemaphoreDelete((SemaphoreHandle_t)cdc_dev->ctrl_transfer->context);
}
if (cdc_dev->ctrl_mux != NULL) {
vSemaphoreDelete(cdc_dev->ctrl_mux);
}
usb_host_transfer_free(cdc_dev->ctrl_transfer);
}
}
/**
* @brief Allocate CDC transfers
*
* @param[in] cdc_dev Pointer to CDC device
* @param[in] notif_ep_desc Pointer to notification EP descriptor
* @param[in] in_ep_desc- Pointer to data IN EP descriptor
* @param[in] out_ep_desc Pointer to data OUT EP descriptor
* @param[in] out_buf_len Length of data OUT buffer
* @return esp_err_t
*/
static esp_err_t cdc_transfers_allocate(cdc_dev_t *cdc_dev, const usb_ep_desc_t *notif_ep_desc, const usb_ep_desc_t *in_ep_desc, const usb_ep_desc_t *out_ep_desc, size_t out_buf_len)
{
esp_err_t ret;
// 1. Setup notification and control transfers if they are supported
if (notif_ep_desc) {
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(USB_EP_DESC_GET_MPS(notif_ep_desc), 0, &cdc_dev->notif.xfer),
err,
TAG, );
cdc_dev->notif.xfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->notif.xfer->bEndpointAddress = notif_ep_desc->bEndpointAddress;
cdc_dev->notif.xfer->callback = notif_xfer_cb;
cdc_dev->notif.xfer->context = cdc_dev;
cdc_dev->notif.xfer->num_bytes = USB_EP_DESC_GET_MPS(notif_ep_desc);
usb_device_info_t dev_info;
ESP_ERROR_CHECK(usb_host_device_info(cdc_dev->dev_hdl, &dev_info));
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(dev_info.bMaxPacketSize0, 0, &cdc_dev->ctrl_transfer),
err,
TAG, );
cdc_dev->ctrl_transfer->timeout_ms = 1000;
cdc_dev->ctrl_transfer->bEndpointAddress = 0;
cdc_dev->ctrl_transfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->ctrl_transfer->context = cdc_dev;
cdc_dev->ctrl_transfer->callback = out_xfer_cb;
cdc_dev->ctrl_transfer->context = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->context, ESP_ERR_NO_MEM, err, TAG, );
cdc_dev->ctrl_mux = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_mux, ESP_ERR_NO_MEM, err, TAG, );
}
// 2. Setup IN data transfer
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(1024 * 20, 0, &cdc_dev->data.in_xfer),
err,
TAG, );
assert(cdc_dev->data.in_xfer);
cdc_dev->data.in_xfer->callback = in_xfer_cb;
cdc_dev->data.in_xfer->num_bytes = 1024 * 20;
cdc_dev->data.in_xfer->bEndpointAddress = in_ep_desc->bEndpointAddress;
cdc_dev->data.in_xfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->data.in_xfer->context = cdc_dev;
// 3. Setup OUT bulk transfer (if it is required (out_buf_len > 0))
if (out_buf_len != 0) {
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(out_buf_len, 0, &cdc_dev->data.out_xfer),
err,
TAG, );
assert(cdc_dev->data.out_xfer);
cdc_dev->data.out_xfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->data.out_xfer->context = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->context, ESP_ERR_NO_MEM, err, TAG, );
cdc_dev->data.out_mux = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(cdc_dev->data.out_mux, ESP_ERR_NO_MEM, err, TAG, );
cdc_dev->data.out_xfer->bEndpointAddress = out_ep_desc->bEndpointAddress;
cdc_dev->data.out_xfer->callback = out_xfer_cb;
}
return ESP_OK;
err:
cdc_transfers_free(cdc_dev);
return ret;
}
/**
* @brief Find CDC interface descriptor and its endpoint descriptors
*
* @note This function is called in open procedure of CDC compliant devices only.
* @param[in] cdc_dev Pointer to CDC device
* @param[in] intf_idx Index of CDC interface that should be used for this device
* @param[out] notif_ep Pointer to notification EP descriptor
* @param[out] in_ep Pointer to data IN EP descriptor
* @param[out] out_ep Pointer to data OUT EP descriptor
* @return esp_err_t
*/
static esp_err_t cdc_find_intf_and_ep_desc(cdc_dev_t *cdc_dev, uint8_t intf_idx, const usb_ep_desc_t **notif_ep, const usb_ep_desc_t **in_ep, const usb_ep_desc_t **out_ep)
{
bool interface_found = false;
const usb_config_desc_t *config_desc;
const usb_device_desc_t *device_desc;
int data_intf_idx, notif_intf_idx;
int desc_offset = 0;
// Get required descriptors
ESP_ERROR_CHECK(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc));
ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc));
if ((device_desc->bDeviceClass == USB_CLASS_MISC) && (device_desc->bDeviceSubClass == USB_SUBCLASS_COMMON) && (device_desc->bDeviceProtocol == USB_DEVICE_PROTOCOL_IAD)) {
// This is a composite device, that uses Interface Association Descriptor
SYS_LOG_INF("found 111");
const usb_standard_desc_t *this_desc = (const usb_standard_desc_t *)config_desc;
do {
this_desc = usb_parse_next_descriptor_of_type(
this_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, &desc_offset);
SYS_LOG_INF("BBBBBFFFF 111");
if (this_desc == NULL)
break; // Reached end of configuration descriptor
const usb_iad_desc_t *iad_desc = (const usb_iad_desc_t *)this_desc;
SYS_LOG_INF("iad_desc->bFirstInterface:%d", iad_desc->bFirstInterface);
if (iad_desc->bFirstInterface == intf_idx) {
// IAD with correct interface number was found: Check Class/Subclass codes, save Interface indexes
assert(iad_desc->bInterfaceCount == 2);
assert(iad_desc->bFunctionClass == USB_CLASS_COMM);
assert(iad_desc->bFunctionSubClass == CDC_SUBCLASS_ACM);
notif_intf_idx = iad_desc->bFirstInterface;
data_intf_idx = iad_desc->bFirstInterface + 1;
interface_found = true;
}
} while (!interface_found);
} else if ((device_desc->bDeviceClass == USB_CLASS_COMM) && (intf_idx == 0)) {
SYS_LOG_INF("device_desc->bDeviceClass:%d, device_desc->bDeviceSubClass:%d, device_desc->bDeviceProtocol:%d", device_desc->bDeviceClass, device_desc->bDeviceSubClass, device_desc->bDeviceProtocol);
// This is a Communication Device Class
notif_intf_idx = 0;
data_intf_idx = 1;
interface_found = true;
SYS_LOG_INF("found 222");
}
// Save found interfaces descriptors:
if (interface_found) {
// Notification IF and EP
cdc_dev->notif.intf_desc = usb_parse_interface_descriptor(config_desc, notif_intf_idx, 0, &desc_offset);
assert(cdc_dev->notif.intf_desc);
// CDC specific descriptors should be right after CDC-Communication interface descriptor
// Note: That's why we use usb_parse_next_descriptor instead of usb_parse_next_descriptor_of_type.
// The latter could return CDC specific descriptors that don't belong to this interface
const usb_standard_desc_t *cdc_desc = (usb_standard_desc_t *)cdc_dev->notif.intf_desc;
do {
cdc_desc = usb_parse_next_descriptor(cdc_desc, config_desc->wTotalLength, &desc_offset);
if ((cdc_desc == NULL) || (cdc_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_W_VALUE_DT_INTERFACE)))
break; // We found all CDC specific descriptors
cdc_dev->num_cdc_intf_desc++;
cdc_dev->cdc_intf_desc =
realloc(cdc_dev->cdc_intf_desc, cdc_dev->num_cdc_intf_desc * (sizeof(usb_standard_desc_t *)));
assert(cdc_dev->cdc_intf_desc);
cdc_dev->cdc_intf_desc[cdc_dev->num_cdc_intf_desc - 1] = cdc_desc;
} while (1);
*notif_ep = usb_parse_endpoint_descriptor_by_index(cdc_dev->notif.intf_desc, 0, config_desc->wTotalLength, &desc_offset);
assert(notif_ep);
// Data IF and EP
cdc_dev->data.intf_desc = usb_parse_interface_descriptor(config_desc, data_intf_idx, 0, &desc_offset);
assert(cdc_dev->data.intf_desc);
int temp_offset = desc_offset;
for (int i = 0; i < 2; i++) {
const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(cdc_dev->data.intf_desc, i, config_desc->wTotalLength, &desc_offset);
assert(this_ep);
if (USB_EP_DESC_GET_EP_DIR(this_ep)) {
*in_ep = this_ep;
} else {
*out_ep = this_ep;
}
desc_offset = temp_offset;
}
return ESP_OK;
}
return ESP_ERR_NOT_FOUND;
}
/**
* @brief Start CDC device
*
* After this call, USB host peripheral will continuously poll IN endpoints.
*
* @param cdc_dev
* @param[in] event_cb Device event callback
* @param[in] in_cb Data received callback
* @param[in] user_arg Optional user's argument, that will be passed to the callbacks
* @return esp_err_t
*/
static esp_err_t cdc_start(cdc_dev_t *cdc_dev, cdc_acm_host_dev_callback_t event_cb, cdc_acm_data_callback_t in_cb, void *user_arg)
{
esp_err_t ret = ESP_OK;
assert(cdc_dev);
CDC_ACM_ENTER_CRITICAL();
cdc_dev->notif.cb = event_cb;
cdc_dev->data.in_cb = in_cb;
cdc_dev->cb_arg = user_arg;
CDC_ACM_EXIT_CRITICAL();
// Claim data interface and start polling its IN endpoint
SYS_LOG_INF("interface claim for cdc bulk in");
ESP_GOTO_ON_ERROR(usb_host_interface_claim(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->data.intf_desc->bInterfaceNumber, 0), err, TAG, );
ESP_LOGD("CDC_ACM", "Submitting poll for BULK IN transfer");
ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->data.in_xfer));
// If notification are supported, claim its interface and start polling its IN endpoint
// if (cdc_dev->notif.intf_desc != NULL) {
// if (cdc_dev->notif.intf_desc != cdc_dev->data.intf_desc) {
// esp_err_t result = usb_host_interface_claim(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->notif.intf_desc->bInterfaceNumber, 0);
// SYS_LOG_INF("CLAIM INTERFACE RESULT:%d", result);
// ESP_GOTO_ON_ERROR(result, err, TAG, );
// }
// ESP_LOGD("CDC_ACM", "Submitting poll for INTR IN transfer");
// ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->notif.xfer));
// }
// Everything OK, add the device into list and return
// CDC_ACM_ENTER_CRITICAL();
// SLIST_INSERT_HEAD(&p_cdc_acm_obj->cdc_devices_list, cdc_dev, list_entry);
// CDC_ACM_EXIT_CRITICAL();
return ret;
err:
usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->data.intf_desc->bInterfaceNumber);
if (cdc_dev->notif.intf_desc != NULL) {
usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->notif.intf_desc->bInterfaceNumber);
}
return ret;
}
/**
* @brief Open USB device with requested VID/PID
*
* This function has two regular return paths:
* 1. USB device with matching VID/PID is already opened by this driver: allocate new CDC device on top of the already opened USB device.
* 2. USB device with matching VID/PID is NOT opened by this driver yet: poll USB connected devices until it is found.
*
* @note This function will block for timeout_ms, if the device is not enumerated at the moment of calling this function.
* @param[in] vid Vendor ID
* @param[in] pid Product ID
* @param[in] timeout_ms Connection timeout [ms]
* @param[out] dev CDC-ACM device
* @return esp_err_t
*/
static esp_err_t cdc_find_and_open_usb_device(uint16_t vid, uint16_t pid, int timeout_ms, cdc_dev_t **dev)
{
// assert(p_cdc_acm_obj);
assert(dev);
*dev = calloc(1, sizeof(cdc_dev_t));
if (*dev == NULL) {
return ESP_ERR_NO_MEM;
}
// // First, check list of already opened CDC devices
// SYS_LOG_DBG("Checking list of opened USB devices");
// cdc_dev_t *cdc_dev;
// SLIST_FOREACH(cdc_dev, &p_cdc_acm_obj->cdc_devices_list, list_entry)
// {
// const usb_device_desc_t *device_desc;
// ESP_ERROR_CHECK(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc));
// if (device_desc->idVendor == vid && device_desc->idProduct == pid) {
// // Return path 1:
// (*dev)->dev_hdl = cdc_dev->dev_hdl;
// return ESP_OK;
// }
// }
// Second, poll connected devices until new device is connected or timeout
TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
TimeOut_t connection_timeout;
vTaskSetTimeOutState(&connection_timeout);
while (true) {
SYS_LOG_DBG("Checking list of connected USB devices");
uint8_t dev_addr_list[10];
int num_of_devices;
ESP_ERROR_CHECK(usb_host_device_addr_list_fill(sizeof(dev_addr_list), dev_addr_list, &num_of_devices));
// Go through device address list and find the one we are looking for
for (int i = 0; i < num_of_devices; i++) {
usb_device_handle_t current_device;
// Open USB device
if (usb_host_device_open(s_msc_driver->client_handle, dev_addr_list[i], &current_device) != ESP_OK) {
continue; // In case we failed to open this device, continue with next one in the list
}
assert(current_device);
const usb_device_desc_t *device_desc;
ESP_ERROR_CHECK(usb_host_get_device_descriptor(current_device, &device_desc));
if (device_desc->idVendor == vid && device_desc->idProduct == pid) {
// Return path 2:
(*dev)->dev_hdl = current_device;
return ESP_OK;
}
usb_host_device_close(s_msc_driver->client_handle, current_device);
}
if (xTaskCheckForTimeOut(&connection_timeout, &timeout_ticks) != pdFALSE) {
break; // Timeout elapsed and the device is not connected
}
vTaskDelay(pdMS_TO_TICKS(50));
}
// Timeout was reached, clean-up
free(*dev);
*dev = NULL;
return ESP_ERR_NOT_FOUND;
}
/**
* @brief Helper function that releases resources claimed by CDC device
*
* Close underlying USB device, free device driver memory
*
* @note All interfaces claimed by this device must be release before calling this function
* @param cdc_dev CDC device handle to be removed
*/
static void cdc_device_remove(cdc_dev_t *cdc_dev)
{
assert(cdc_dev);
cdc_transfers_free(cdc_dev);
free(cdc_dev->cdc_intf_desc);
// We don't check the error code of usb_host_device_close, as the close might fail, if someone else is still using the device (not all interfaces are released)
usb_host_device_close(s_msc_driver->client_handle, cdc_dev->dev_hdl); // Gracefully continue on error
free(cdc_dev);
}
esp_err_t cdc_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret)
{
esp_err_t ret = ESP_FAIL;
// CDC_ACM_CHECK(p_cdc_acm_obj, ESP_ERR_INVALID_STATE);
CDC_ACM_CHECK(dev_config, ESP_ERR_INVALID_ARG);
CDC_ACM_CHECK(cdc_hdl_ret, ESP_ERR_INVALID_ARG);
// xSemaphoreTake(p_cdc_acm_obj->open_close_mutex, portMAX_DELAY);
// Find underlying USB device
cdc_dev_t *cdc_dev;
ESP_GOTO_ON_ERROR(
cdc_find_and_open_usb_device(vid, pid, dev_config->connection_timeout_ms, &cdc_dev),
exit,
TAG,
"USB device with VID: 0x%04X, PID: 0x%04X not found",
vid,
pid);
// Find and save relevant interface and endpoint descriptors
const usb_ep_desc_t *notif_ep = NULL;
const usb_ep_desc_t *in_ep = NULL;
const usb_ep_desc_t *out_ep = NULL;
ESP_GOTO_ON_ERROR(
cdc_find_intf_and_ep_desc(cdc_dev, interface_idx, &notif_ep, &in_ep, &out_ep),
err,
TAG,
"Could not find required interface");
// Check whether found Interfaces are really CDC-ACM
assert(cdc_dev->notif.intf_desc->bInterfaceClass == USB_CLASS_COMM);
assert(cdc_dev->notif.intf_desc->bInterfaceSubClass == CDC_SUBCLASS_ACM);
assert(cdc_dev->notif.intf_desc->bNumEndpoints == 1);
assert(cdc_dev->data.intf_desc->bInterfaceClass == USB_CLASS_CDC_DATA);
assert(cdc_dev->data.intf_desc->bNumEndpoints == 2);
// Save Communication and Data protocols
cdc_dev->comm_protocol = (cdc_comm_protocol_t)cdc_dev->notif.intf_desc->bInterfaceProtocol;
cdc_dev->data_protocol = (cdc_data_protocol_t)cdc_dev->data.intf_desc->bInterfaceProtocol;
// Allocate USB transfers, claim CDC interfaces and return CDC-ACM handle
ESP_GOTO_ON_ERROR(cdc_transfers_allocate(cdc_dev, notif_ep, in_ep, out_ep, dev_config->out_buffer_size), err, TAG, );
ESP_GOTO_ON_ERROR(cdc_start(cdc_dev, dev_config->event_cb, dev_config->data_cb, dev_config->user_arg), err, TAG, );
*cdc_hdl_ret = (cdc_acm_dev_hdl_t)cdc_dev;
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
// cdc_task_args.bulk_in_ep_desc = in_ep;
// cdc_task_args.bulk_out_ep_desc = out_ep;
SYS_LOG_INF("s_usb_event_group created");
s_usb_event_group = xEventGroupCreate();
CDC_CHECK(s_usb_event_group != NULL, "Create event group failed", ESP_FAIL);
if (s_out_ringbuf_handle == NULL) {
// s_in_ringbuf_handle =
// xRingbufferCreate(4096, RINGBUF_TYPE_BYTEBUF);
// CDC_CHECK_GOTO(s_in_ringbuf_handle != NULL, "Create in ringbuffer failed", delete_resource_);
s_out_ringbuf_handle =
xRingbufferCreate(1024, RINGBUF_TYPE_BYTEBUF);
CDC_CHECK_GOTO(s_out_ringbuf_handle != NULL, "Create out ringbuffer failed", delete_resource_);
s_usb_read_mux = xSemaphoreCreateMutex();
CDC_CHECK_GOTO(s_usb_read_mux != NULL, "Create read mutex failed", delete_resource_);
s_usb_write_mux = xSemaphoreCreateMutex();
CDC_CHECK_GOTO(s_usb_write_mux != NULL, "Create write mutex failed", delete_resource_);
}
TaskHandle_t cdc_data_task_hdl = NULL;
// _cdc_data_task_args_t cdc_task_args = {
// .dev_addr = 0,
// // .bulk_in_ep_desc = *(cdc_config->bulk_in_ep),
// // .bulk_out_ep_desc = *(cdc_config->bulk_out_ep),
// .event_group_hdl = s_usb_event_group,
// .rx_callback = NULL,
// .rx_callback_arg = NULL,
// };
xTaskCreatePinnedToCore(
_cdc_data_task,
CDC_DATA_TASK_NAME,
CDC_DATA_TASK_STACK_SIZE,
(void *)(cdc_dev),
SBTASK_PRIORITY_USB_CDC,
&cdc_data_task_hdl,
CDC_DATA_TASK_CORE);
vTaskDelay(50 / portTICK_PERIOD_MS);
xTaskNotifyGive(cdc_data_task_hdl);
g_cdc_dev = cdc_dev;
SYS_LOG_INF("g_cdc_dev:%08x", (uint32_t)g_cdc_dev);
return ESP_OK;
err:
cdc_device_remove(cdc_dev);
exit:
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
*cdc_hdl_ret = NULL;
return ret;
delete_resource_:
if (s_usb_write_mux)
vSemaphoreDelete(s_usb_write_mux);
if (s_usb_read_mux)
vSemaphoreDelete(s_usb_read_mux);
if (s_out_ringbuf_handle)
vRingbufferDelete(s_out_ringbuf_handle);
if (s_in_ringbuf_handle)
vRingbufferDelete(s_in_ringbuf_handle);
if (s_usb_event_group)
vEventGroupDelete(s_usb_event_group);
s_usb_event_group = NULL;
s_in_ringbuf_handle = NULL;
s_out_ringbuf_handle = NULL;
s_usb_read_mux = NULL;
s_usb_write_mux = NULL;
*cdc_hdl_ret = NULL;
return ret;
}
/**
* @brief Check finished transfer status
*
* Return to on transfer completed OK.
* Cancel the transfer and issue user's callback in case of an error.
*
* @param[in] transfer Transfer to be checked
* @return true Transfer completed
* @return false Transfer NOT completed
*/
static bool cdc_is_transfer_completed(usb_transfer_t *transfer)
{
cdc_dev_t *cdc_dev = (cdc_dev_t *)transfer->context;
bool completed = false;
switch (transfer->status) {
case USB_TRANSFER_STATUS_COMPLETED:
completed = true;
break;
case USB_TRANSFER_STATUS_NO_DEVICE: // User is notified about device disconnection from usb_event_cb
case USB_TRANSFER_STATUS_CANCELED:
break;
case USB_TRANSFER_STATUS_ERROR:
case USB_TRANSFER_STATUS_TIMED_OUT:
case USB_TRANSFER_STATUS_STALL:
case USB_TRANSFER_STATUS_OVERFLOW:
case USB_TRANSFER_STATUS_SKIPPED:
default:
// Transfer was not completed or cancelled by user. Inform user about this
if (cdc_dev->notif.cb) {
const cdc_acm_host_dev_event_data_t error_event = {
.type = CDC_ACM_HOST_ERROR,
.data.error = (int)transfer->status};
cdc_dev->notif.cb((cdc_acm_dev_hdl_t)cdc_dev, &error_event, cdc_dev->cb_arg);
}
}
return completed;
}
static void in_xfer_cb(usb_transfer_t *transfer)
{
ESP_LOGD("CDC_ACM", "in xfer cb");
cdc_dev_t *cdc_dev = (cdc_dev_t *)transfer->context;
if (cdc_is_transfer_completed(transfer)) {
if (cdc_dev->data.in_cb) {
cdc_dev->data.in_cb(transfer->data_buffer, transfer->actual_num_bytes, cdc_dev->cb_arg);
}
/* 通过 cdc_submit_transfer_in() 使能传输 */
// ESP_LOGD("CDC_ACM", "Submitting poll for BULK IN transfer");
// usb_host_transfer_submit(cdc_dev->data.in_xfer);
} else {
SYS_LOG_INF("IN COMPLETE");
}
}
static void notif_xfer_cb(usb_transfer_t *transfer)
{
ESP_LOGD("CDC_ACM", "notif xfer cb");
cdc_dev_t *cdc_dev = (cdc_dev_t *)transfer->context;
if (cdc_is_transfer_completed(transfer)) {
cdc_notification_t *notif = (cdc_notification_t *)transfer->data_buffer;
switch (notif->bNotificationCode) {
case CDC_NOTIF_NETWORK_CONNECTION: {
if (cdc_dev->notif.cb) {
const cdc_acm_host_dev_event_data_t net_conn_event = {
.type = CDC_ACM_HOST_NETWORK_CONNECTION,
.data.network_connected = (bool)notif->wValue};
cdc_dev->notif.cb((cdc_acm_dev_hdl_t)cdc_dev, &net_conn_event, cdc_dev->cb_arg);
}
break;
}
case CDC_NOTIF_SERIAL_STATE: {
cdc_dev->serial_state.val = *((uint16_t *)notif->Data);
if (cdc_dev->notif.cb) {
const cdc_acm_host_dev_event_data_t serial_state_event = {
.type = CDC_ACM_HOST_SERIAL_STATE,
.data.serial_state = cdc_dev->serial_state};
cdc_dev->notif.cb((cdc_acm_dev_hdl_t)cdc_dev, &serial_state_event, cdc_dev->cb_arg);
}
break;
}
case CDC_NOTIF_RESPONSE_AVAILABLE: // Encapsulated commands not implemented - fallthrough
default:
ESP_LOGW("CDC_ACM", "Unsupported notification type 0x%02X", notif->bNotificationCode);
ESP_LOG_BUFFER_HEX("CDC_ACM", transfer->data_buffer, transfer->actual_num_bytes);
break;
}
// Start polling for new data again
ESP_LOGD("CDC_ACM", "Submitting poll for INTR IN transfer");
usb_host_transfer_submit(cdc_dev->notif.xfer);
}
}
static void out_xfer_cb(usb_transfer_t *transfer)
{
ESP_LOGD("CDC_ACM", "out/ctrl xfer cb");
assert(transfer->context);
xSemaphoreGive((SemaphoreHandle_t)transfer->context);
}
void cdc_host_desc_print(cdc_acm_dev_hdl_t cdc_hdl)
{
assert(cdc_hdl);
cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
ESP_RETURN_ON_FALSE(cdc_dev->num_cdc_intf_desc > 0, , TAG, "No CDC-ACM specific descriptors found");
for (int i = 0; i < cdc_dev->num_cdc_intf_desc; i++) {
switch (((cdc_header_desc_t *)cdc_dev->cdc_intf_desc[i])->bDescriptorSubtype) {
case CDC_DESC_SUBTYPE_HEADER: {
cdc_header_desc_t *desc = (cdc_header_desc_t *)cdc_dev->cdc_intf_desc[i];
SYS_PRINT("CDC Header Descriptor:\n");
SYS_PRINT("\tbcdCDC: %d.%d0\n", ((desc->bcdCDC >> 8) & 0xF), ((desc->bcdCDC >> 4) & 0xF));
break;
}
case CDC_DESC_SUBTYPE_CALL: {
cdc_acm_call_desc_t *desc = (cdc_acm_call_desc_t *)cdc_dev->cdc_intf_desc[i];
SYS_PRINT("CDC Call Descriptor:\n");
SYS_PRINT("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val);
SYS_PRINT("\tbDataInterface: %d\n", desc->bDataInterface);
break;
}
case CDC_DESC_SUBTYPE_ACM: {
cdc_acm_acm_desc_t *desc = (cdc_acm_acm_desc_t *)cdc_dev->cdc_intf_desc[i];
SYS_PRINT("CDC ACM Descriptor:\n");
SYS_PRINT("\tbmCapabilities: 0x%02X\n", desc->bmCapabilities.val);
break;
}
case CDC_DESC_SUBTYPE_UNION: {
cdc_union_desc_t *desc = (cdc_union_desc_t *)cdc_dev->cdc_intf_desc[i];
SYS_PRINT("CDC Union Descriptor:\n");
SYS_PRINT("\tbControlInterface: %d\n", desc->bControlInterface);
SYS_PRINT("\tbSubordinateInterface[0]: %d\n", desc->bSubordinateInterface[0]);
break;
}
default:
SYS_LOG_WRN("Unsupported CDC specific descriptor");
break;
}
}
}
/**
* @brief Cancel transfer and reset endpoint
*
* This function will cancel ongoing transfer a reset its endpoint to ready state.
*
* @param[in] dev_hdl USB device handle
* @param[in] transfer Transfer to be cancelled
* @return esp_err_t
*/
static esp_err_t cdc_reset_transfer_endpoint(usb_device_handle_t dev_hdl, usb_transfer_t *transfer)
{
assert(dev_hdl);
assert(transfer);
ESP_RETURN_ON_ERROR(usb_host_endpoint_halt(dev_hdl, transfer->bEndpointAddress), TAG, );
ESP_RETURN_ON_ERROR(usb_host_endpoint_flush(dev_hdl, transfer->bEndpointAddress), TAG, );
usb_host_endpoint_clear(dev_hdl, transfer->bEndpointAddress);
return ESP_OK;
}
esp_err_t cdc_host_close(cdc_acm_dev_hdl_t cdc_hdl)
{
// CDC_ACM_CHECK(p_cdc_acm_obj, ESP_ERR_INVALID_STATE);
CDC_ACM_CHECK(cdc_hdl, ESP_ERR_INVALID_ARG);
// xSemaphoreTake(p_cdc_acm_obj->open_close_mutex, portMAX_DELAY);
cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
// Cancel polling of BULK IN and INTERRUPT IN endpoints
cdc_dev->notif.cb = NULL;
cdc_dev->data.in_cb = NULL;
ESP_ERROR_CHECK(cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->data.in_xfer));
if (cdc_dev->notif.intf_desc != NULL) {
// ESP_ERROR_CHECK(cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->notif.xfer));
}
// Release all interfaces
ESP_ERROR_CHECK(usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->data.intf_desc->bInterfaceNumber));
if ((cdc_dev->notif.intf_desc != NULL) && (cdc_dev->notif.intf_desc != cdc_dev->data.intf_desc)) {
// ESP_ERROR_CHECK(usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->notif.intf_desc->bInterfaceNumber));
}
// CDC_ACM_ENTER_CRITICAL();
// SLIST_REMOVE(&p_cdc_acm_obj->cdc_devices_list, cdc_dev, cdc_dev_s, list_entry);
// CDC_ACM_EXIT_CRITICAL();
cdc_device_remove(cdc_dev);
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
return ESP_OK;
}
///////// dfu 设备处理
/**
* @brief Allocate CDC transfers
*
* @param[in] cdc_dev Pointer to CDC device
* @param[in] notif_ep_desc Pointer to notification EP descriptor
* @param[in] in_ep_desc- Pointer to data IN EP descriptor
* @param[in] out_ep_desc Pointer to data OUT EP descriptor
* @param[in] out_buf_len Length of data OUT buffer
* @return esp_err_t
*/
static esp_err_t dfu_transfers_allocate(cdc_dev_t *cdc_dev)
{
esp_err_t ret;
// 1. Setup notification and control transfers if they are supported
SYS_LOG_INF("PRE DFU dfu_transfers_allocate");
// if (notif_ep_desc) {
SYS_LOG_INF("IN DFU dfu_transfers_allocate");
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(512, 0, &cdc_dev->notif.xfer),
err,
TAG, );
cdc_dev->notif.xfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->notif.xfer->bEndpointAddress = 0;
cdc_dev->notif.xfer->callback = notif_xfer_cb;
cdc_dev->notif.xfer->context = cdc_dev;
cdc_dev->notif.xfer->num_bytes = 512;
usb_device_info_t dev_info;
ESP_ERROR_CHECK(usb_host_device_info(cdc_dev->dev_hdl, &dev_info));
ESP_GOTO_ON_ERROR(
usb_host_transfer_alloc(4096, 0, &cdc_dev->ctrl_transfer),
err,
TAG, );
cdc_dev->ctrl_transfer->timeout_ms = 1000;
cdc_dev->ctrl_transfer->bEndpointAddress = 0;
cdc_dev->ctrl_transfer->device_handle = cdc_dev->dev_hdl;
cdc_dev->ctrl_transfer->context = cdc_dev;
cdc_dev->ctrl_transfer->callback = out_xfer_cb;
cdc_dev->ctrl_transfer->context = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->context, ESP_ERR_NO_MEM, err, TAG, );
cdc_dev->ctrl_mux = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_mux, ESP_ERR_NO_MEM, err, TAG, );
// }
// // 2. Setup IN data transfer
// ESP_GOTO_ON_ERROR(
// usb_host_transfer_alloc(512, 0, &cdc_dev->data.in_xfer),
// err,
// TAG, );
// assert(cdc_dev->data.in_xfer);
// cdc_dev->data.in_xfer->callback = in_xfer_cb;
// cdc_dev->data.in_xfer->num_bytes = 512;
// cdc_dev->data.in_xfer->bEndpointAddress = in_ep_desc->bEndpointAddress;
// cdc_dev->data.in_xfer->device_handle = cdc_dev->dev_hdl;
// cdc_dev->data.in_xfer->context = cdc_dev;
// // 3. Setup OUT bulk transfer (if it is required (out_buf_len > 0))
// if (out_buf_len != 0) {
// ESP_GOTO_ON_ERROR(
// usb_host_transfer_alloc(out_buf_len, 0, &cdc_dev->data.out_xfer),
// err,
// TAG, );
// assert(cdc_dev->data.out_xfer);
// cdc_dev->data.out_xfer->device_handle = cdc_dev->dev_hdl;
// cdc_dev->data.out_xfer->context = xSemaphoreCreateBinary();
// ESP_GOTO_ON_FALSE(cdc_dev->data.out_xfer->context, ESP_ERR_NO_MEM, err, TAG, );
// cdc_dev->data.out_mux = xSemaphoreCreateMutex();
// ESP_GOTO_ON_FALSE(cdc_dev->data.out_mux, ESP_ERR_NO_MEM, err, TAG, );
// cdc_dev->data.out_xfer->bEndpointAddress = out_ep_desc->bEndpointAddress;
// cdc_dev->data.out_xfer->callback = out_xfer_cb;
// }
return ESP_OK;
err:
cdc_transfers_free(cdc_dev);
return ret;
}
/**
* @brief Find CDC interface descriptor and its endpoint descriptors
*
* @note This function is called in open procedure of CDC compliant devices only.
* @param[in] cdc_dev Pointer to CDC device
* @param[in] intf_idx Index of CDC interface that should be used for this device
* @param[out] notif_ep Pointer to notification EP descriptor
* @param[out] in_ep Pointer to data IN EP descriptor
* @param[out] out_ep Pointer to data OUT EP descriptor
* @return esp_err_t
*/
// static esp_err_t dfu_find_intf_and_ep_desc(cdc_dev_t *cdc_dev, uint8_t intf_idx, const usb_ep_desc_t **notif_ep)
// {
// bool interface_found = false;
// const usb_config_desc_t *config_desc;
// const usb_device_desc_t *device_desc;
// int data_intf_idx, notif_intf_idx;
// int desc_offset = 0;
// // Get required descriptors
// ESP_ERROR_CHECK(usb_host_get_device_descriptor(cdc_dev->dev_hdl, &device_desc));
// ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc));
// SYS_LOG_INF("get inpoint step0, device_desc->bDeviceClass:%d, device_desc->bDeviceSubClass:%d, device_desc->bDeviceProtocol:%d", device_desc->bDeviceClass, device_desc->bDeviceSubClass, device_desc->bDeviceProtocol);
// // if ((device_desc->bDeviceClass == USB_CLASS_MISC) && (device_desc->bDeviceSubClass == USB_SUBCLASS_COMMON) && (device_desc->bDeviceProtocol == USB_DEVICE_PROTOCOL_IAD)) {
// // This is a composite device, that uses Interface Association Descriptor
// SYS_LOG_INF("found 111");
// // const usb_standard_desc_t *this_desc = (const usb_standard_desc_t *)config_desc;
// // do {
// // SYS_LOG_INF("config_desc:%08x", (uint32_t)config_desc);
// // this_desc = usb_parse_next_descriptor_of_type(
// // this_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &desc_offset);
// // SYS_LOG_INF("fjdlkfladjfkldasjkfl:%d, this_desc:%08x", config_desc->wTotalLength, (uint32_t)this_desc);
// // if (this_desc == NULL)
// // break; // Reached end of configuration descriptor
// // const usb_iad_desc_t *iad_desc = (const usb_iad_desc_t *)this_desc;
// // SYS_LOG_INF("iad_desc->bFirstInterfa:%d", iad_desc->bFirstInterface);
// // if (iad_desc->bFirstInterface == intf_idx) {
// // // IAD with correct interface number was found: Check Class/Subclass codes, save Interface indexes
// // SYS_LOG_INF()
// // assert(iad_desc->bInterfaceCount == 2);
// // assert(iad_desc->bFunctionClass == USB_CLASS_COMM);
// // assert(iad_desc->bFunctionSubClass == CDC_SUBCLASS_ACM);
// // notif_intf_idx = iad_desc->bFirstInterface;
// // data_intf_idx = iad_desc->bFirstInterface + 1;
// // interface_found = true;
// // }
// // } while (!interface_found);
// // // } else if ((device_desc->bDeviceClass == USB_CLASS_COMM) && (intf_idx == 0)) {
// // // // This is a Communication Device Class
// // // notif_intf_idx = 0;
// // // data_intf_idx = 1;
// // // interface_found = true;
// // // SYS_LOG_INF("found 222");
// // // }
// // Save found interfaces descriptors:
// interface_found = true;
// if (interface_found) {
// // Notification IF and EP
// cdc_dev->notif.intf_desc = usb_parse_interface_descriptor(config_desc, 0, 0, &desc_offset);
// assert(cdc_dev->notif.intf_desc);
// // CDC specific descriptors should be right after CDC-Communication interface descriptor
// // Note: That's why we use usb_parse_next_descriptor instead of usb_parse_next_descriptor_of_type.
// // The latter could return CDC specific descriptors that don't belong to this interface
// const usb_standard_desc_t *cdc_desc = (usb_standard_desc_t *)cdc_dev->notif.intf_desc;
// do {
// cdc_desc = usb_parse_next_descriptor(cdc_desc, config_desc->wTotalLength, &desc_offset);
// if ((cdc_desc == NULL) || (cdc_desc->bDescriptorType != ((USB_CLASS_COMM << 4) | USB_W_VALUE_DT_INTERFACE)))
// break; // We found all CDC specific descriptors
// cdc_dev->num_cdc_intf_desc++;
// cdc_dev->cdc_intf_desc =
// realloc(cdc_dev->cdc_intf_desc, cdc_dev->num_cdc_intf_desc * (sizeof(usb_standard_desc_t *)));
// assert(cdc_dev->cdc_intf_desc);
// cdc_dev->cdc_intf_desc[cdc_dev->num_cdc_intf_desc - 1] = cdc_desc;
// } while (1);
// SYS_LOG_INF("BEFORE NOTIFY EP SETUP DONE");
// *notif_ep = usb_parse_endpoint_descriptor_by_index(cdc_dev->notif.intf_desc, 0, config_desc->wTotalLength, &desc_offset);
// assert(notif_ep);
// // // Data IF and EP
// // cdc_dev->data.intf_desc = usb_parse_interface_descriptor(config_desc, data_intf_idx, 0, &desc_offset);
// // assert(cdc_dev->data.intf_desc);
// // int temp_offset = desc_offset;
// // for (int i = 0; i < 2; i++) {
// // const usb_ep_desc_t *this_ep = usb_parse_endpoint_descriptor_by_index(cdc_dev->data.intf_desc, i, config_desc->wTotalLength, &desc_offset);
// // assert(this_ep);
// // if (USB_EP_DESC_GET_EP_DIR(this_ep)) {
// // *in_ep = this_ep;
// // } else {
// // *out_ep = this_ep;
// // }
// // desc_offset = temp_offset;
// // }
// return ESP_OK;
// }
// return ESP_ERR_NOT_FOUND;
// }
esp_err_t dfu_host_open(uint16_t vid, uint16_t pid, uint8_t interface_idx, const cdc_acm_host_device_config_t *dev_config, cdc_acm_dev_hdl_t *cdc_hdl_ret)
{
esp_err_t ret;
// CDC_ACM_CHECK(p_cdc_acm_obj, ESP_ERR_INVALID_STATE);
CDC_ACM_CHECK(dev_config, ESP_ERR_INVALID_ARG);
CDC_ACM_CHECK(cdc_hdl_ret, ESP_ERR_INVALID_ARG);
// xSemaphoreTake(p_cdc_acm_obj->open_close_mutex, portMAX_DELAY);
// Find underlying USB device
cdc_dev_t *cdc_dev;
ESP_GOTO_ON_ERROR(
cdc_find_and_open_usb_device(vid, pid, dev_config->connection_timeout_ms, &cdc_dev),
exit,
TAG,
"USB device with VID: 0x%04X, PID: 0x%04X not found",
vid,
pid);
// Find and save relevant interface and endpoint descriptors
// const usb_ep_desc_t *notif_ep = NULL;
// const usb_ep_desc_t *in_ep = NULL;
// const usb_ep_desc_t *out_ep = NULL;
// ESP_GOTO_ON_ERROR(
// dfu_find_intf_and_ep_desc(cdc_dev, interface_idx, &notif_ep),
// err,
// TAG,
// "Could not find required interface");
// // Check whether found Interfaces are really CDC-ACM
// assert(cdc_dev->notif.intf_desc->bInterfaceClass == USB_CLASS_COMM);
// assert(cdc_dev->notif.intf_desc->bInterfaceSubClass == CDC_SUBCLASS_ACM);
// assert(cdc_dev->notif.intf_desc->bNumEndpoints == 1);
// assert(cdc_dev->data.intf_desc->bInterfaceClass == USB_CLASS_CDC_DATA);
// assert(cdc_dev->data.intf_desc->bNumEndpoints == 2);
// // Save Communication and Data protocols
// cdc_dev->comm_protocol = (cdc_comm_protocol_t)cdc_dev->notif.intf_desc->bInterfaceProtocol;
// cdc_dev->data_protocol = (cdc_data_protocol_t)cdc_dev->data.intf_desc->bInterfaceProtocol;
// // Allocate USB transfers, claim CDC interfaces and return CDC-ACM handle
ESP_GOTO_ON_ERROR(dfu_transfers_allocate(cdc_dev), err, TAG, );
// ESP_GOTO_ON_ERROR(cdc_start(cdc_dev, dev_config->event_cb, dev_config->data_cb, dev_config->user_arg), err, TAG, );
*cdc_hdl_ret = (cdc_acm_dev_hdl_t)cdc_dev;
g_cdc_dev = cdc_dev;
SYS_LOG_INF("g_cdc_dev:%08x", (uint32_t)g_cdc_dev);
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
return ESP_OK;
err:
cdc_device_remove(cdc_dev);
exit:
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
*cdc_hdl_ret = NULL;
return ret;
}
esp_err_t dfu_host_close(cdc_acm_dev_hdl_t cdc_hdl)
{
// CDC_ACM_CHECK(p_cdc_acm_obj, ESP_ERR_INVALID_STATE);
CDC_ACM_CHECK(cdc_hdl, ESP_ERR_INVALID_ARG);
// xSemaphoreTake(p_cdc_acm_obj->open_close_mutex, portMAX_DELAY);
cdc_dev_t *cdc_dev = (cdc_dev_t *)cdc_hdl;
// // Cancel polling of BULK IN and INTERRUPT IN endpoints
// cdc_dev->notif.cb = NULL;
// cdc_dev->data.in_cb = NULL;
// ESP_ERROR_CHECK(cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->data.in_xfer));
// if (cdc_dev->notif.intf_desc != NULL) {
// ESP_ERROR_CHECK(cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->notif.xfer));
// }
// // Release all interfaces
// ESP_ERROR_CHECK(usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->data.intf_desc->bInterfaceNumber));
// if ((cdc_dev->notif.intf_desc != NULL) && (cdc_dev->notif.intf_desc != cdc_dev->data.intf_desc)) {
// ESP_ERROR_CHECK(usb_host_interface_release(s_msc_driver->client_handle, cdc_dev->dev_hdl, cdc_dev->notif.intf_desc->bInterfaceNumber));
// }
// // CDC_ACM_ENTER_CRITICAL();
// // SLIST_REMOVE(&p_cdc_acm_obj->cdc_devices_list, cdc_dev, cdc_dev_s, list_entry);
// // CDC_ACM_EXIT_CRITICAL();
cdc_device_remove(cdc_dev);
// xSemaphoreGive(p_cdc_acm_obj->open_close_mutex);
return ESP_OK;
}
///// stm32固件升级
static esp_err_t _usb_control_transfer_ex(cdc_dev_t *cdc_dev,
uint8_t direction,
uint8_t request,
uint16_t value,
uint16_t interface,
uint16_t length,
uint8_t *packet_data,
uint8_t *out_buffer,
uint16_t out_buffer_size,
uint16_t *actual_result_size,
uint16_t timeout)
{
esp_err_t ret = ESP_FAIL;
CDC_ACM_CHECK(cdc_dev->ctrl_transfer, ESP_ERR_NOT_SUPPORTED);
CDC_ACM_CHECK(cdc_dev->ctrl_transfer->data_buffer_size >= length, ESP_ERR_INVALID_SIZE);
// Take Mutex and fill the CTRL request
BaseType_t taken = xSemaphoreTake(cdc_dev->ctrl_mux, pdMS_TO_TICKS(1000));
if (!taken) {
return ESP_ERR_TIMEOUT;
}
usb_setup_packet_t *req = (usb_setup_packet_t *)(cdc_dev->ctrl_transfer->data_buffer);
uint8_t *start_of_data = (uint8_t *)req + sizeof(usb_setup_packet_t);
req->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
req->bRequest = request;
req->wValue = value;
req->wIndex = interface;
req->wLength = length;
if (direction == USB_BM_REQUEST_TYPE_DIR_IN) {
req->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
} else {
memcpy(start_of_data, packet_data, length);
}
cdc_dev->ctrl_transfer->num_bytes = length + sizeof(usb_setup_packet_t);
ESP_GOTO_ON_ERROR(
usb_host_transfer_submit_control(s_msc_driver->client_handle, cdc_dev->ctrl_transfer),
unblock,
TAG,
"CTRL transfer failed");
taken = xSemaphoreTake((SemaphoreHandle_t)cdc_dev->ctrl_transfer->context, pdMS_TO_TICKS(timeout)); // This is a fixed timeout. Every CDC device should be able to respond to CTRL transfer in 1 second
if (!taken) {
// Transfer was not finished, error in USB LIB. Reset the endpoint
cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->ctrl_transfer);
ret = ESP_ERR_TIMEOUT;
goto unblock;
}
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Control transfer error");
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->actual_num_bytes == cdc_dev->ctrl_transfer->num_bytes, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
if (direction == USB_BM_REQUEST_TYPE_DIR_IN) {
uint16_t result_data_length = cdc_dev->ctrl_transfer->actual_num_bytes - sizeof(usb_setup_packet_t);
if (result_data_length > out_buffer_size) {
result_data_length = out_buffer_size;
}
memcpy(out_buffer, start_of_data, result_data_length);
if (actual_result_size) {
*actual_result_size = result_data_length;
}
}
ret = ESP_OK;
unblock:
xSemaphoreGive(cdc_dev->ctrl_mux);
return ret;
}
static esp_err_t _usb_control_transfer(cdc_dev_t *cdc_dev,
uint8_t direction,
uint8_t request,
uint16_t value,
uint16_t interface,
uint16_t length,
uint8_t *packet_data,
uint8_t *out_buffer,
uint16_t out_buffer_size,
uint16_t *actual_result_size)
{
esp_err_t ret = _usb_control_transfer_ex(cdc_dev,
direction,
request,
value,
interface,
length,
packet_data,
out_buffer,
out_buffer_size,
actual_result_size,
5000);
return ret;
}
static esp_err_t _usb_get_status_ex(cdc_dev_t *cdc_dev, uint8_t *out_result_data /*[6]*/, uint16_t timeout)
{
return _usb_control_transfer_ex(cdc_dev,
USB_BM_REQUEST_TYPE_DIR_IN,
STM32_DFU_REQUEST_GETSTATUS,
0,
0,
6,
0,
out_result_data,
6,
NULL,
timeout);
}
esp_err_t usbh_stm32_get_status_ex(uint8_t *out_result_data /*[6]*/, uint16_t timeout)
{
if (g_cdc_dev != NULL) {
return _usb_get_status_ex(g_cdc_dev, out_result_data, timeout);
}
return ESP_FAIL;
}
esp_err_t usbh_stm32_get_status(uint8_t *out_result_data /*[6]*/)
{
// return _usbh_
return usbh_stm32_get_status_ex(out_result_data, 500);
}
static esp_err_t _usb_get_string(cdc_dev_t *cdc_dev,
uint8_t index,
char *out_string,
uint16_t max_length,
uint16_t *actual_length)
{
esp_err_t ret;
SYS_LOG_INF("GET STRING 00000");
CDC_ACM_CHECK(cdc_dev->ctrl_transfer, ESP_ERR_NOT_SUPPORTED);
// CDC_ACM_CHECK(cdc_dev->ctrl_transfer->data_buffer_size >= data_len, ESP_ERR_INVALID_SIZE);
// Take Mutex and fill the CTRL request
SYS_LOG_INF("GET STRING 1111");
BaseType_t taken = xSemaphoreTake(cdc_dev->ctrl_mux, pdMS_TO_TICKS(1000));
if (!taken) {
return ESP_ERR_TIMEOUT;
}
SYS_LOG_INF("GET STRING 2222");
// usb_setup_packet_t *req = (usb_setup_packet_t *)(cdc_dev->ctrl_transfer->data_buffer);
// uint8_t *start_of_data = (uint8_t *)cdc_dev->ctrl_transfer->data_buffer;
USB_SETUP_PACKET_INIT_GET_STR_DESC(
(usb_setup_packet_t *)cdc_dev->ctrl_transfer->data_buffer, index, 0x409, ENUM_CTRL_TRANSFER_MAX_LEN);
cdc_dev->ctrl_transfer->num_bytes = sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_LEN;
// req->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
// req->bRequest = request;
// req->wValue = value;
// req->wIndex = cdc_dev->notif.intf_desc->bInterfaceNumber;
// req->wLength = data_len;
cdc_dev->ctrl_transfer->num_bytes = ENUM_CTRL_TRANSFER_MAX_LEN + sizeof(usb_setup_packet_t);
SYS_LOG_INF("cdc_dev->ctrl_transfer->num_bytes:%d, cdc_dev->ctrl_transfer->data_buffer_size:%d", cdc_dev->ctrl_transfer->num_bytes, cdc_dev->ctrl_transfer->data_buffer_size);
ESP_GOTO_ON_ERROR(
usb_host_transfer_submit_control(s_msc_driver->client_handle, cdc_dev->ctrl_transfer),
unblock,
TAG,
"CTRL transfer failed");
SYS_LOG_INF("GET STRING 33333");
taken = xSemaphoreTake((SemaphoreHandle_t)cdc_dev->ctrl_transfer->context, pdMS_TO_TICKS(1000)); // This is a fixed timeout. Every CDC device should be able to respond to CTRL transfer in 1 second
if (!taken) {
// Transfer was not finished, error in USB LIB. Reset the endpoint
cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->ctrl_transfer);
ret = ESP_ERR_TIMEOUT;
SYS_LOG_INF("GET STRING 5555");
goto unblock;
}
SYS_LOG_INF("GET STRING 6666");
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Control transfer error");
SYS_LOG_INF("GET STRING 7777");
// ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->actual_num_bytes == cdc_dev->ctrl_transfer->num_bytes, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
SYS_LOG_INF("GET STRING 88888:%d", cdc_dev->ctrl_transfer->actual_num_bytes);
uint16_t actual_string_length = 0;
for (int i = 10; i < cdc_dev->ctrl_transfer->actual_num_bytes; i += 2) {
if (actual_string_length > max_length) {
break;
}
out_string[actual_string_length] = cdc_dev->ctrl_transfer->data_buffer[i];
actual_string_length += 1;
}
SYS_LOG_INF("GET STRING 9999:%s", out_string);
ret = ESP_OK;
unblock:
xSemaphoreGive(cdc_dev->ctrl_mux);
return ret;
}
static void _usb_get_interface_descriptors(cdc_dev_t *cdc_dev,
int interface_num,
char *descriptors,
uint8_t max_descriptors_count,
uint8_t *actual_descriptors_count)
{
const usb_config_desc_t *config_desc;
int i = 0;
const usb_standard_desc_t *this_desc = NULL;
SYS_LOG_INF("pre get active config desc done:%d", (uint32_t)cdc_dev->dev_hdl);
ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(cdc_dev->dev_hdl, &config_desc));
this_desc = (const usb_standard_desc_t *)config_desc;
int desc_offset = 0;
SYS_LOG_INF("get active config desc done");
do {
this_desc = usb_parse_next_descriptor_of_type(
this_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &desc_offset);
if (this_desc == NULL) {
break; // Reached end of configuration descriptor
}
const usb_intf_desc_t *intf_desc = (const usb_intf_desc_t *)this_desc;
char *result_string = descriptors + i * 255;
memset(result_string, 0, 255);
_usb_get_string(cdc_dev, intf_desc->iInterface, result_string, 255, NULL);
i += 1;
if (i >= max_descriptors_count) {
break;
}
} while (true);
for (int k = 0; k < i; k++) {
SYS_LOG_INF("index:%d, descriptor:%s", k, descriptors + k * 255);
}
if (actual_descriptors_count) {
*actual_descriptors_count = i;
}
}
void usbh_stm32_get_chipinfo(char *descriptors, uint8_t count, uint8_t *actual_desc_count)
{
SYS_LOG_INF("before usbh_stm32_get_chipinfo:%d", (uint32_t)g_cdc_dev);
if (g_cdc_dev != NULL) {
_usb_get_interface_descriptors(g_cdc_dev, 0, (char *)descriptors, count, actual_desc_count);
}
}
static esp_err_t _usb_get_function_descriptors(cdc_dev_t *cdc_dev, int interface_num, usb_function_desc_packet_t *out_function_desc)
{
esp_err_t ret;
SYS_LOG_INF("GET function 00000");
CDC_ACM_CHECK(cdc_dev->ctrl_transfer, ESP_ERR_NOT_SUPPORTED);
// CDC_ACM_CHECK(cdc_dev->ctrl_transfer->data_buffer_size >= data_len, ESP_ERR_INVALID_SIZE);
// Take Mutex and fill the CTRL request
SYS_LOG_INF("GET function 1111");
BaseType_t taken = xSemaphoreTake(cdc_dev->ctrl_mux, pdMS_TO_TICKS(1000));
if (!taken) {
return ESP_ERR_TIMEOUT;
}
SYS_LOG_INF("GET function 2222");
// usb_setup_packet_t *req = (usb_setup_packet_t *)(cdc_dev->ctrl_transfer->data_buffer);
// uint8_t *start_of_data = (uint8_t *)cdc_dev->ctrl_transfer->data_buffer;
USB_SETUP_PACKET_INIT_GET_FUNCTION_DESC((usb_setup_packet_t *)cdc_dev->ctrl_transfer->data_buffer);
// cdc_dev->ctrl_transfer->num_bytes = 4096; // sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_LEN;
// req->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
// req->bRequest = request;
// req->wValue = value;
// req->wIndex = cdc_dev->notif.intf_desc->bInterfaceNumber;
// req->wLength = data_len;
cdc_dev->ctrl_transfer->num_bytes = 255 + sizeof(usb_setup_packet_t);
SYS_LOG_INF("cdc_dev->ctrl_transfer->num_bytes:%d, cdc_dev->ctrl_transfer->data_buffer_size:%d", cdc_dev->ctrl_transfer->num_bytes, cdc_dev->ctrl_transfer->data_buffer_size);
ESP_GOTO_ON_ERROR(
usb_host_transfer_submit_control(s_msc_driver->client_handle, cdc_dev->ctrl_transfer),
unblock,
TAG,
"get function transfer failed");
SYS_LOG_INF("GET function 33333");
taken = xSemaphoreTake((SemaphoreHandle_t)cdc_dev->ctrl_transfer->context, pdMS_TO_TICKS(1000)); // This is a fixed timeout. Every CDC device should be able to respond to CTRL transfer in 1 second
if (!taken) {
// Transfer was not finished, error in USB LIB. Reset the endpoint
cdc_reset_transfer_endpoint(cdc_dev->dev_hdl, cdc_dev->ctrl_transfer);
ret = ESP_ERR_TIMEOUT;
SYS_LOG_INF("GET function 5555");
goto unblock;
}
SYS_LOG_INF("GET function 6666");
ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->status == USB_TRANSFER_STATUS_COMPLETED, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Control transfer error");
SYS_LOG_INF("GET function 7777");
// ESP_GOTO_ON_FALSE(cdc_dev->ctrl_transfer->actual_num_bytes == cdc_dev->ctrl_transfer->num_bytes, ESP_ERR_INVALID_RESPONSE, unblock, TAG, "Incorrect number of bytes transferred");
SYS_LOG_INF("GET function 88888:%d", cdc_dev->ctrl_transfer->actual_num_bytes);
const usb_function_desc_packet_t *function_desc =
(const usb_function_desc_packet_t *)(cdc_dev->ctrl_transfer->data_buffer + sizeof(usb_setup_packet_t));
memcpy(out_function_desc, function_desc, sizeof(usb_function_desc_packet_t));
SYS_LOG_INF("GET function 9999");
ret = ESP_OK;
unblock:
xSemaphoreGive(cdc_dev->ctrl_mux);
return ret;
}
uint16_t usbh_stm32_get_transfer_block_size()
{
if (g_cdc_dev != NULL) {
usb_function_desc_packet_t function_desc_packet;
esp_err_t ret = _usb_get_function_descriptors(g_cdc_dev, 0, &function_desc_packet);
if (ret != ESP_OK) {
return 2048;
} else {
return function_desc_packet.wTransferSize;
}
}
return 0;
}
esp_err_t _usbh_stm32_control_transfer(uint8_t direction,
uint8_t request,
uint16_t value,
uint16_t interface,
uint16_t length,
uint8_t *packet_data,
uint8_t *out_buffer,
uint16_t out_buffer_size,
uint16_t *actual_result_size)
{
if (g_cdc_dev != NULL) {
esp_err_t ret = _usb_control_transfer(g_cdc_dev, direction, request, value, interface, length, packet_data, out_buffer, out_buffer_size, actual_result_size);
return ret;
}
return ESP_FAIL;
}
esp_err_t _usbh_stm32_control_transfer_ex(uint8_t direction,
uint8_t request,
uint16_t value,
uint16_t interface,
uint16_t length,
uint8_t *packet_data,
uint8_t *out_buffer,
uint16_t out_buffer_size,
uint16_t *actual_result_size,
uint16_t timeout)
{
if (g_cdc_dev != NULL) {
return _usb_control_transfer_ex(g_cdc_dev,
direction,
request,
value,
interface,
length,
packet_data,
out_buffer,
out_buffer_size,
actual_result_size,
timeout);
}
return ESP_FAIL;
}
static esp_err_t _usb_get_status(cdc_dev_t *cdc_dev, uint8_t *out_result_data /*[6]*/)
{
return _usb_get_status_ex(cdc_dev, out_result_data, 500);
;
}
static int _get_tick_by_append_ms(unsigned int ms)
{
return os_get_sys_ticks() + os_calc_msec_to_ticks(ms);
}
static esp_err_t _usb_clear_status(cdc_dev_t *cdc_dev)
{
_usb_control_transfer(cdc_dev, USB_BM_REQUEST_TYPE_DIR_OUT, STM32_DFU_REQUEST_CLRSTATUS, 0, 0, 0, 0, NULL, 0, NULL);
uint8_t status[6];
memset(status, 0, 6);
esp_err_t ret = _usb_get_status(cdc_dev, status);
if (ESP_OK != ret) {
SYS_LOG_ERR("failed to get status");
return ret;
}
if (status[4] != STM32_DFU_STATE_DFU_IDLE) {
uint32_t delay_ms = status[1] | (status[2] << 8) | (status[3] << 16);
uint32_t wait_timeout_ticks =
_get_tick_by_append_ms(delay_ms);
while (os_get_sys_ticks() < wait_timeout_ticks) {
os_thread_sleep(50);
}
ret = _usb_clear_status(cdc_dev);
}
return ret;
}
static esp_err_t _usb_try_read_ob(cdc_dev_t *cdc_dev, uint16_t ob_data_size)
{
// uint16_t ob_data_size = g_option_bytes.total_size;
uint8_t *ob_data = malloc(ob_data_size);
memset(ob_data, 0, ob_data_size);
uint16_t actual_ob_data_length = 0;
esp_err_t ret = _usb_control_transfer(cdc_dev, USB_BM_REQUEST_TYPE_DIR_IN, STM32_DFU_REQUEST_UPLOAD, 2, 0, ob_data_size, NULL, ob_data, ob_data_size, &actual_ob_data_length);
if (ret != ESP_OK) {
return ret;
}
SYS_LOG_INF("ob data(%d,%d):", ob_data_size, actual_ob_data_length);
ESP_LOG_BUFFER_HEX(TAG, ob_data, ob_data_size);
uint8_t status[6];
memset(status, 0, 6);
ret = _usb_get_status_ex(cdc_dev, status, 2000);
CDC_CHECK(ESP_OK == ret, "get status failed on load address", ret);
ESP_LOG_BUFFER_HEX(TAG, status, 6);
if (status[4] == STM32_DFU_STATE_UPLOAD_IDLE && actual_ob_data_length == ob_data_size) {
ret = _usb_clear_status(cdc_dev);
} else {
SYS_LOG_ERR("failed to get status on read ob");
ret = ESP_FAIL;
}
free(ob_data);
return ret;
}
esp_err_t _usbh_stm32_try_read_ob(uint16_t ob_data_size)
{
if (g_cdc_dev != NULL) {
return _usb_try_read_ob(g_cdc_dev, ob_data_size);
}
return ESP_FAIL;
}
static esp_err_t _usb_unprotect(cdc_dev_t *cdc_dev)
{
SYS_LOG_INF("unprotect");
uint8_t unprotect_command = 0x92;
esp_err_t ret = _usb_control_transfer(cdc_dev, USB_BM_REQUEST_TYPE_DIR_OUT, STM32_DFU_REQUEST_DNLOAD, 0, 0, 1, &unprotect_command, NULL, 0, NULL);
if (ret != ESP_OK) {
SYS_LOG_ERR("failed to send unprotect command");
return ret;
}
uint8_t status[6];
memset(status, 0, 6);
ret = _usb_get_status(cdc_dev, status);
if (ret != ESP_OK) {
SYS_LOG_ERR("failed to get status");
return ret;
}
if (status[4] == STM32_DFU_STATE_DNBUSY) {
uint32_t delay_ms = 20000 + (status[1] | (status[2] << 8) | (status[3] << 16)); // 等待STM32解除读保护时间为20秒+delay
SYS_LOG_INF("flash erase is running, wait the flash:%d ms", delay_ms);
uint32_t wait_timeout_ticks =
_get_tick_by_append_ms(delay_ms);
while (os_get_sys_ticks() < wait_timeout_ticks) {
SYS_LOG_INF("waiting flash erase");
os_thread_sleep(1000);
}
SYS_LOG_INF("reget status");
ret = _usb_get_status(cdc_dev, status);
if (ret != ESP_OK) {
SYS_LOG_INF("unprotect mcu done");
return ESP_OK; // unprotect done(flash was erased), tell the user replug the FC with DFU mode
} else {
SYS_LOG_ERR("failed to unprotect");
return ESP_FAIL;
}
}
return ret;
}
esp_err_t _usbh_stm32_unprotect()
{
if (g_cdc_dev != NULL) {
return _usb_unprotect(g_cdc_dev);
}
return ESP_FAIL;
}
esp_err_t _usbh_stm32_leave_dfu()
{
if (g_cdc_dev == NULL) {
return ESP_FAIL;
}
esp_err_t ret;
SYS_LOG_INF("leave dfu 00000");
CDC_ACM_CHECK(g_cdc_dev->ctrl_transfer, ESP_ERR_NOT_SUPPORTED);
// CDC_ACM_CHECK(cdc_dev->ctrl_transfer->data_buffer_size >= data_len, ESP_ERR_INVALID_SIZE);
// Take Mutex and fill the CTRL request
SYS_LOG_INF("leave dfu 1111");
BaseType_t taken = xSemaphoreTake(g_cdc_dev->ctrl_mux, pdMS_TO_TICKS(1000));
if (!taken) {
return ESP_ERR_TIMEOUT;
}
SYS_LOG_INF("leave dfu 2222");
usb_setup_packet_t *setup_packet = (usb_setup_packet_t *)(g_cdc_dev->ctrl_transfer->data_buffer);
// uint8_t *start_of_data = (uint8_t *)g_cdc_dev->ctrl_transfer->data_buffer;
setup_packet->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
setup_packet->bRequest = STM32_DFU_REQUEST_GETSTATUS;
setup_packet->wValue = 0;
setup_packet->wIndex = 0;
setup_packet->wLength = 6;
g_cdc_dev->ctrl_transfer->num_bytes = sizeof(usb_setup_packet_t) + 6;
// req->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
// req->bRequest = request;
// req->wValue = value;
// req->wIndex = cdc_dev->notif.intf_desc->bInterfaceNumber;
// req->wLength = data_len;
// g_cdc_dev->ctrl_transfer->num_bytes = ENUM_CTRL_TRANSFER_MAX_LEN + sizeof(usb_setup_packet_t);
SYS_LOG_INF("g_cdc_dev->ctrl_transfer->num_bytes:%d, g_cdc_dev->ctrl_transfer->data_buffer_size:%d", g_cdc_dev->ctrl_transfer->num_bytes, g_cdc_dev->ctrl_transfer->data_buffer_size);
ESP_GOTO_ON_ERROR(
usb_host_transfer_submit_control(s_msc_driver->client_handle, g_cdc_dev->ctrl_transfer),
unblock,
TAG,
"leave dfu failed");
SYS_LOG_INF("leave dfu 33333");
taken = xSemaphoreTake((SemaphoreHandle_t)g_cdc_dev->ctrl_transfer->context, pdMS_TO_TICKS(10000)); // This is a fixed timeout. Every CDC device should be able to respond to CTRL transfer in 1 second
if (!taken) {
// Transfer was not finished, error in USB LIB. Reset the endpoint
cdc_reset_transfer_endpoint(g_cdc_dev->dev_hdl, g_cdc_dev->ctrl_transfer);
ret = ESP_ERR_TIMEOUT;
SYS_LOG_INF("leave dfu 5555");
goto unblock;
}
SYS_LOG_INF("leave dfu 6666");
if (g_cdc_dev->ctrl_transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
SYS_LOG_WRN("FAILED TO GET STATUS FOR LEAVE DFU");
} else {
SYS_LOG_INF("leave dfu 88888:%d", g_cdc_dev->ctrl_transfer->actual_num_bytes);
}
SYS_LOG_INF("leave dfu 9999");
ret = ESP_OK;
unblock:
xSemaphoreGive(g_cdc_dev->ctrl_mux);
return ret;
// // _usb_control_transfer_ex(pipe_handle,
// // USB_BM_REQUEST_TYPE_DIR_IN,
// // STM32_DFU_REQUEST_GETSTATUS,
// // 0,
// // 0,
// // 6,
// // 0,
// // out_result_data,
// // 6,
// // NULL,
// // timeout);
// uint8_t direction = USB_BM_REQUEST_TYPE_DIR_IN;
// uint8_t request = STM32_DFU_REQUEST_GETSTATUS;
// uint16_t value = 0;
// uint16_t interface = 0;
// uint16_t length = 6;
// uint8_t *packet_data = NULL;
// uint8_t *out_buffer = NULL;
// uint16_t out_buffer_size = 0;
// uint16_t *actual_result_size = NULL;
// uint16_t timeout = 500;
// CDC_CHECK(g_cdc_dev != NULL, "g_cdc_dev can't be NULL", ESP_ERR_INVALID_ARG);
// // malloc URB for default control
// uint16_t packet_data_size = ENUM_CTRL_TRANSFER_MAX_LEN;
// if (length > packet_data_size) {
// packet_data_size = length;
// }
// urb_t *urb_ctrl = _usb_urb_alloc(0, sizeof(usb_setup_packet_t) + packet_data_size, NULL);
// CDC_CHECK(urb_ctrl != NULL, "alloc urb failed", ESP_ERR_NO_MEM);
// usb_setup_packet_t *setup_packet = (usb_setup_packet_t *)urb_ctrl->transfer.data_buffer;
// setup_packet->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
// setup_packet->bRequest = request;
// setup_packet->wValue = value;
// setup_packet->wIndex = interface;
// setup_packet->wLength = length;
// urb_ctrl->transfer.num_bytes = sizeof(usb_setup_packet_t) + length;
// // Enqueue it
// esp_err_t ret = hcd_urb_enqueue(g_cdc_dev, urb_ctrl);
// CDC_CHECK_GOTO(ESP_OK == ret, "urb enqueue failed", free_urb_);
// SYS_LOG_INF("urb request timeout:%d ms, and becuase it used for leave dfu, so dont wait response", timeout);
// goto free_urb_;
// free_urb_:
// _usb_pipe_flush(g_cdc_dev, 1);
// _usb_urb_free(urb_ctrl);
// return ret;
}
esp_err_t usbh_stm32_clear_status()
{
// return _usbh_
if (g_cdc_dev != NULL) {
return _usb_clear_status(g_cdc_dev);
}
return ESP_FAIL;
}
static esp_err_t _usb_load_address(cdc_dev_t *cdc_dev, uint32_t address)
{
// CDC_CHECK(pipe_handle != NULL, "pipe_handle can't be NULL", ESP_ERR_INVALID_ARG);
// // malloc URB for default control
// urb_t *urb_ctrl = _usb_urb_alloc(0, sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_LEN, NULL);
// CDC_CHECK(urb_ctrl != NULL, "alloc urb failed", ESP_ERR_NO_MEM);
uint8_t packet_data[5];
packet_data[0] = 0x21;
packet_data[1] = address & 0xff;
packet_data[2] = (address >> 8) & 0xff;
packet_data[3] = (address >> 16) & 0xff;
packet_data[4] = (address >> 24) & 0xff;
// USB_SETUP_PACKET_INIT_LOAD_ADDRESS((usb_setup_packet_t *)urb_ctrl->transfer.data_buffer, packet_data);
// urb_ctrl->transfer.num_bytes = sizeof(usb_setup_packet_t) + 5;
// SYS_LOG_INF("load address urb data, original address:%d", address);
// ESP_LOG_BUFFER_HEX(TAG, urb_ctrl->transfer.data_buffer, sizeof(usb_setup_packet_t) + 5);
// // Enqueue it
// esp_err_t ret = hcd_urb_enqueue(pipe_handle, urb_ctrl);
// CDC_CHECK_GOTO(ESP_OK == ret, "urb enqueue failed", free_urb_);
// ret = _default_pipe_event_wait_until(pipe_handle, HCD_PIPE_EVENT_URB_DONE, pdMS_TO_TICKS(500));
// CDC_CHECK_GOTO(ESP_OK == ret, "urb event error", flush_urb_);
// urb_t *urb_done = hcd_urb_dequeue(pipe_handle);
// CDC_CHECK_GOTO(urb_done == urb_ctrl, "urb status: not same", free_urb_);
// CDC_CHECK_GOTO(USB_TRANSFER_STATUS_COMPLETED == urb_done->transfer.status,
// "urb status: not complete",
// free_urb_);
// CDC_CHECK_GOTO(urb_ctrl->transfer.actual_num_bytes >= sizeof(usb_setup_packet_t),
// "clear status descriptor too short",
// free_urb_);
esp_err_t ret = _usbh_stm32_control_transfer(USB_BM_REQUEST_TYPE_DIR_OUT, STM32_DFU_REQUEST_DNLOAD, 0, 0, 5, packet_data, NULL, 0, NULL);
CDC_CHECK(ESP_OK == ret, "failed to load address", ret);
uint8_t status[6];
memset(status, 0, 6);
ret = _usb_get_status(cdc_dev, status);
CDC_CHECK(ESP_OK == ret, "get status failed on load address", ret);
if (status[4] == STM32_DFU_STATE_DNBUSY) {
uint32_t delay_ms = status[1] | (status[2] << 8) | (status[3] << 16);
uint32_t wait_timeout_ticks =
_get_tick_by_append_ms(delay_ms);
while (os_get_sys_ticks() < wait_timeout_ticks) {
os_thread_sleep(20);
}
ret = _usb_get_status(cdc_dev, status);
CDC_CHECK(ESP_OK == ret, "get status failed on load address", ret);
if (status[4] != STM32_DFU_STATE_DNLOAD_IDLE) {
SYS_LOG_ERR("unexpeceted dfu status:%d", status[4]);
return ESP_FAIL;
}
} else {
SYS_LOG_INF("result of get status");
return ESP_FAIL;
}
return ret;
}
esp_err_t _usbh_stm32_load_address(uint32_t address)
{
if (g_cdc_dev != NULL) {
return _usb_load_address(g_cdc_dev, address);
}
return ESP_FAIL;
}