#include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "freertos/queue.h" #include "freertos/semphr.h" #include "freertos/ringbuf.h" #include "esp_err.h" #include "esp_log.h" #include "usb/usb_host.h" #include "msc/include/msc_host.h" #include "msc/include/msc_host_vfs.h" #include "ffconf.h" #include "ff.h" #include "errno.h" #include "esp_vfs.h" #include "spbelib_interface.h" #include "config/hardware_define.h" // #include "usb/cdc_acm_host.h" #include "usbport.h" #define CONFIG_SYS_LOG_DUMP_ON 0 #define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN #define SYS_LOG_DOMAIN "USB" #include "sys_log.h" #define IN_RINGBUF_SIZE (1024 * 1) #define OUT_RINGBUF_SIZE (1024 * 1) #define CDC_CHECK(a, str, ret) \ do \ { \ if (!(a)) \ { \ SYS_LOG_ERR(str); \ return (ret); \ } \ } while (0) #define CDC_CHECK_GOTO(a, str, lable) \ do \ { \ if (!(a)) \ { \ SYS_LOG_ERR(str); \ goto lable; \ } \ } while (0) typedef struct { os_pipe_t pipe_obj; os_work_t *rx_resume_work; } __usb_data_t; static QueueHandle_t app_queue; // static SemaphoreHandle_t ready_to_uninstall_usb; static msc_host_vfs_handle_t vfs_handle; static usbport_status_e g_usb_status = USBPORT_STATUS_NO_CONNECTION; static __usb_data_t s_usb_data; static sb_data_port_t s_port; static msc_host_device_handle_t g_connected_usb_device = NULL; static cdc_acm_dev_hdl_t g_cdc_dev; //////////// CDC 全局变量 //////////// #define BULK_OUT_URB_NUM 2 #define BULK_IN_URB_NUM 2 #define BUFFER_SIZE_BULK_OUT 512 #define BUFFER_SIZE_BULK_IN 512 #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 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; volatile static usb_connect_type_t s_usb_connect_type = USB_CONNECTED_UNKNOWN; //////////// End CDC 全局变量 //////////// //////////// MSC 全局变量 //////////////// static msc_file_info g_msc_file_lists[MAX_FILE_COUNT]; // static excluding_file_item_t msc_excluding_files[MAX_EXCLUDING_FILE_COUNT]; static uint16_t g_msc_file_count = 0; //////////// End MSC 全局变量 //////////// static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle; static void usb_device_event_cb(const msc_host_event_t *event, void *arg) { switch (event->event) { case MSC_DEVICE_CONNECTED: s_usb_connect_type = USB_CONNECTED_MSC; SYS_LOG_INF("MSC device connected"); sblib_send_event(LIB_EVENT_USBH_MSC, 0, NULL); break; case MSC_DEVICE_DISCONNECTED: s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("MSC device disconnected"); sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; case CDC_DEVICE_CONNECTED: s_usb_connect_type = USB_CONNECTED_CDC; SYS_LOG_INF("CDC device connected"); sblib_send_event(LIB_EVENT_USBH_CDC, 0, NULL); break; case CDC_DEVICE_DISCONNECTED: s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("CDC device disconnected"); sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; case DFU_DEVICE_CONNECTED: s_usb_connect_type = USB_CONNECTED_DFU; SYS_LOG_INF("DFU device connected"); sblib_send_event(LIB_EVENT_USBH_DFU, 0, NULL); break; case DFU_DEVICE_DISCONNECTED: s_usb_connect_type = USB_CONNECTED_UNKNOWN; SYS_LOG_INF("DFU device disconnected"); sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL); break; } xQueueSend(app_queue, event, 10); } // Handles common USB host library events static void handle_usb_events(void *args) { while (1) { uint32_t event_flags; SYS_LOG_INF("usb_host_lib_handle_events(portMAX_DELAY, &event_flags);"); usb_host_lib_handle_events(portMAX_DELAY, &event_flags); // Release devices once all clients has deregistered if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { SYS_LOG_INF("usb_host_device_free_all();"); usb_host_device_free_all(); // SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);"); // xSemaphoreGive(ready_to_uninstall_usb); break; } // Give ready_to_uninstall_usb semaphore to indicate that USB Host library // can be deinitialized, and terminate this task. // if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) // { // SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);"); // xSemaphoreGive(ready_to_uninstall_usb); // } } s_usb_task_handle = NULL; vTaskDelete(NULL); } static void print_device_info(msc_host_device_info_t *info) { const size_t megabyte = 1024 * 1024; uint64_t capacity = ((uint64_t)info->sector_size * info->sector_count) / megabyte; printf("Device info:\n"); printf("\t Capacity: %llu MB\n", capacity); printf("\t Sector size: %u\n", info->sector_size); printf("\t Sector count: %u\n", info->sector_count); printf("\t PID: 0x%4X \n", info->idProduct); printf("\t VID: 0x%4X \n", info->idVendor); wprintf(L"\t iProduct: %S \n", info->iProduct); wprintf(L"\t iManufacturer: %S \n", info->iManufacturer); wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber); } /* ------------------------------- Callbacks -------------------------------- */ static void handle_rx(uint8_t *data, size_t data_len, void *arg) { SYS_LOG_INF("Data received %d bytes", data_len); // ESP_LOG_BUFFER_HEXDUMP(data, data_len, ESP_LOG_INFO); int write_result = os_pipe_fifo_fill(&s_usb_data.pipe_obj, data, data_len); if (write_result != data_len) { SYS_LOG_WRN("[ERROR]write data to pipe_obj failed, remain: %d bytes, data_len:%d!!", write_result, data_len); } if (os_pipe_get_empty_size(&s_usb_data.pipe_obj) >= BUFFER_SIZE_BULK_IN) { cdc_submit_transfer_in(g_cdc_dev); } } static uint8_t check_file_is_in_excluding_list(const char *filename, uint8_t is_dir, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count) { if (excluding_file_count == 0 || excluding_files == NULL) { SYS_LOG_INF("excluding file count is empty, break check"); return 0; } int source_str_len = strlen(filename); int i = 0; for (i = 0; i < excluding_file_count; i++) { const excluding_file_item_t *file_item = &(excluding_files[i]); if (is_dir != file_item->is_dir) { SYS_LOG_INF("src is dir:%d, target is dir:%d", is_dir, file_item->is_dir); continue; } uint8_t is_same = 0; if (file_item->compare_type == EXCLUDING_FILE_COMPARE_ALL) { is_same = strcmp(filename, file_item->filename) == 0; } else if (file_item->compare_type == EXCLUDING_FILE_COMPARE_PREFIX) { int len = strlen(file_item->filename); if (source_str_len < len) { // 如果文件名小于要比较的字符串,则忽略检查 SYS_LOG_INF("SOURCE LEN:%d, target len:%d", source_str_len, len); continue; } SYS_LOG_INF("CHECKING, SRC:%s, target:%s, len:%d", filename, file_item->filename, len); is_same = strncmp(filename, file_item->filename, len) == 0; } if (is_same) { SYS_LOG_INF("FOUND THE EXCLUD FILE:%s", filename); return 1; // 这个文件是要排除的 } } return 0; } static void list_all_files(const char *dirpath, uint16_t *current_file_index, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count) { // 递归枚举所有文件 struct dirent *entry; struct stat entry_stat; char entrypath[MAX_FILE_PATH]; char entrysize[16]; const char *entrytype; size_t dirpath_len = strlen(dirpath); DIR *dir = opendir(dirpath); strlcpy(entrypath, dirpath, sizeof(entrypath)); if (entrypath[dirpath_len - 1] != '/') { entrypath[dirpath_len] = '/'; dirpath_len += 1; } uint16_t *file_index = current_file_index; while ((entry = readdir(dir)) != NULL) { entrytype = (entry->d_type == DT_DIR ? "directory" : "file"); strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len); if (entry->d_type != DT_DIR) { if (check_file_is_in_excluding_list(entry->d_name, 0, excluding_files, excluding_file_count)) { continue; } SYS_LOG_INF("file path:%s", entrypath); if (esp_vfs_stat(__getreent(), entrypath, &entry_stat) == -1) { SYS_LOG_ERR("Failed to stat %s : %s", entrytype, entry->d_name); continue; } sprintf(entrysize, "%ld", entry_stat.st_size); SYS_LOG_INF("Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize); msc_file_info *file_info = &(g_msc_file_lists[*file_index]); strlcpy(file_info->file_path, entrypath, MAX_FILE_PATH); file_info->file_size = entry_stat.st_size; *file_index = *file_index + 1; } else { if (check_file_is_in_excluding_list(entry->d_name, 1, excluding_files, excluding_file_count)) { continue; } // 检查文件名是否以.号开始,是的话则忽略这个文件夹 SYS_LOG_INF("ITEM NAME:%s", entry->d_name); if (strncmp(entry->d_name, "SPOTLI~", 7) == 0) { // 这个文件夹是MAC系统自动生成的,用于spotlight搜索的索引文件夹,忽略它,否则会导致opendir失败 continue; } else { SYS_LOG_INF("ENTER SUB DIR:%s", entrypath); list_all_files(entrypath, file_index, excluding_files, excluding_file_count); } } } closedir(dir); } static void handle_device_events(void *args) { msc_host_event_t app_event; while (1) { SYS_LOG_INF("xQueueReceive(app_queue, &app_event, portMAX_DELAY);"); xQueueReceive(app_queue, &app_event, portMAX_DELAY); switch (app_event.event) { case MSC_DEVICE_CONNECTED: { uint8_t device_address = app_event.device.address; ESP_ERROR_CHECK(msc_host_install_device(device_address, &g_connected_usb_device)); msc_host_print_descriptors(g_connected_usb_device); msc_host_device_info_t info; ESP_ERROR_CHECK(msc_host_get_device_info(g_connected_usb_device, &info)); print_device_info(&info); const esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 1, .allocation_unit_size = 1024, }; ESP_ERROR_CHECK(msc_host_vfs_register(g_connected_usb_device, "/usb", &mount_config, &vfs_handle)); for (int i = 0; i < g_msc_file_count; i++) { msc_file_info *file_info = &g_msc_file_lists[i]; SYS_LOG_INF("file path: %s, file_size:%d", file_info->file_path, file_info->file_size); } g_usb_status = USBPORT_STATUS_MSC; } break; case MSC_DEVICE_DISCONNECTED: ESP_ERROR_CHECK(msc_host_vfs_unregister(vfs_handle)); vfs_handle = NULL; ESP_ERROR_CHECK(msc_host_uninstall_device(g_connected_usb_device)); g_connected_usb_device = NULL; g_usb_status = USBPORT_STATUS_NO_CONNECTION; break; case CDC_DEVICE_CONNECTED: { SYS_LOG_INF("cdc device connected"); // SYS_LOG_INF("Installing CDC-ACM driver"); // ESP_ERROR_CHECK(cdc_acm_host_install(NULL)); // cdc_acm_dev_hdl_t cdc_dev; const cdc_acm_host_device_config_t dev_config = { .connection_timeout_ms = 5000, .out_buffer_size = 64, .user_arg = NULL, .event_cb = NULL, .data_cb = handle_rx}; cdc_host_open(app_event.vendor_id, app_event.product_id, 0, &dev_config, &g_cdc_dev); assert(g_cdc_dev); cdc_host_desc_print(g_cdc_dev); g_usb_status = USBPORT_STATUS_CDC; // g_connected_usb_device = cdc_dev; } break; case CDC_DEVICE_DISCONNECTED: SYS_LOG_INF("cdc device dconnected"); cdc_host_close(g_cdc_dev); g_usb_status = USBPORT_STATUS_NO_CONNECTION; break; case DFU_DEVICE_CONNECTED: SYS_LOG_INF("DFU DEVICE CONNECTED"); const cdc_acm_host_device_config_t dev_config = { .connection_timeout_ms = 5000, .out_buffer_size = 64, .user_arg = NULL, .event_cb = NULL, .data_cb = handle_rx}; dfu_host_open(app_event.vendor_id, app_event.product_id, 0, &dev_config, &g_cdc_dev); g_usb_status = USBPORT_STATUS_DFU; break; case DFU_DEVICE_DISCONNECTED: SYS_LOG_INF("DFU DEVICE DISCONNECTED"); dfu_host_close(g_cdc_dev); g_usb_status = USBPORT_STATUS_NO_CONNECTION; break; default: assert(0); break; } /* code */ } vTaskDelete(NULL); } //////////////////////////////////////////////// //////////// CDC设备透传的相关的函数 ////////////// //////////////////////////////////////////////// static bool _if_device_ready() { if (!s_usb_event_group) return false; return xEventGroupGetBits(s_usb_event_group) & CDC_DEVICE_READY_BIT; } static bool _cdc_driver_is_init(void) { if (s_usb_event_group == NULL) { return false; } return true; } 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; } int usbh_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 devie2222"); xSemaphoreTake(s_usb_write_mux, portMAX_DELAY); 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 pipe_obj failed"); return -1; } tx_data_size = length; xSemaphoreGive(s_usb_write_mux); return tx_data_size; } static int _usbhost_port_write(sb_data_port_t *port, const void *data, uint32_t size) { int result = cdc_write_bytes(data, size); return result; } static int _usbhost_port_read(sb_data_port_t *port, void *buffer, uint32_t length) { if (os_pipe_is_valid(&s_usb_data.pipe_obj)) { int ret = os_pipe_fifo_read(&s_usb_data.pipe_obj, buffer, length); if (ret > 0 && os_pipe_get_empty_size(&s_usb_data.pipe_obj) >= BUFFER_SIZE_BULK_IN) { cdc_submit_transfer_in(g_cdc_dev); } SYS_LOG_INF("Data readed %d bytes", ret); return ret; } else { return -1; } } static bool s_is_started = false; static int _usbhost_start(sb_data_port_t *port) { s_is_started = true; return 0; } static int _usbhost_stop(sb_data_port_t *port) { s_is_started = false; return 0; } static bool _usbhost_is_started(sb_data_port_t *port) { return s_is_started; } static uint32_t _usbhost_get_rx_length(sb_data_port_t *port) { return os_pipe_get_valid_size(&s_usb_data.pipe_obj); } static sb_data_port_vtable_t const usbhost_port_vtable = { .start = _usbhost_start, // 由具体驱动实现的,以达到节省资源为主要目的,启动数据接口 .stop = _usbhost_stop, // 由具体驱动实现的,以达到节省资源为主要目的,关闭数据接口 .write = _usbhost_port_write, // 由具体驱动实现的,写数据到对应的接口。 .read = _usbhost_port_read, // 由具体驱动实现的,从数据接口中读取已缓存的数据。 .is_started = _usbhost_is_started, // 由具体驱动实现的,获取当前数据接口是否可用(是否已启动) .get_rx_length = _usbhost_get_rx_length, // 由具体驱动实现的,获取当前数据接口的本次可读长度 }; //////////// CDC设备透传的相关的函数结束 /////////// //////////////////////////////////////////////// //////////// STM32固件升级相关的函数 ////////////// //////////////////////////////////////////////// // 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_pipe_hdl_dflt != NULL) { // // return _usb_control_transfer(g_pipe_hdl_dflt, direction, request, value, interface, length, packet_data, out_buffer, out_buffer_size, actual_result_size); // // } // 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_pipe_hdl_dflt != NULL) { // // return _usb_control_transfer_ex(g_pipe_hdl_dflt, // // direction, // // request, // // value, // // interface, // // length, // // packet_data, // // out_buffer, // // out_buffer_size, // // actual_result_size, // // timeout); // // } // return ESP_FAIL; // } // esp_err_t _usbh_stm32_try_read_ob(uint16_t ob_data_size) // { // // if (g_pipe_hdl_dflt != NULL) { // // return _usb_try_read_ob(g_pipe_hdl_dflt, ob_data_size); // // } // return ESP_FAIL; // } // esp_err_t _usbh_stm32_unprotect() // { // // if (g_pipe_hdl_dflt != NULL) { // // return _usb_unprotect(g_pipe_hdl_dflt); // // } // return ESP_FAIL; // } // esp_err_t _usbh_stm32_leave_dfu() // { // return ESP_OK; // // if (g_pipe_hdl_dflt == NULL) { // // return ESP_FAIL; // // } // // // _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_pipe_hdl_dflt != NULL, "g_pipe_hdl_dflt 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; // // if (direction == USB_BM_REQUEST_TYPE_DIR_IN) { // // 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; // // } else if (direction == USB_BM_REQUEST_TYPE_DIR_OUT) { // // setup_packet->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | 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; // // memcpy(((uint8_t *)setup_packet) + sizeof(usb_setup_packet_t), packet_data, length); // // urb_ctrl->transfer.num_bytes = sizeof(usb_setup_packet_t) + length; // // } // // // Enqueue it // // esp_err_t ret = hcd_urb_enqueue(g_pipe_hdl_dflt, 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_pipe_hdl_dflt, 1); // // _usb_urb_free(urb_ctrl); // // return ret; // } // uint16_t usbh_stm32_get_transfer_block_size() // { // // if (g_pipe_hdl_dflt != NULL) { // // usb_function_desc_packet_t function_desc_packet; // // esp_err_t ret = _usb_get_function_descriptors(g_pipe_hdl_dflt, 0, &function_desc_packet); // // if (ret != ESP_OK) { // // return 2048; // // } else { // // return function_desc_packet.wTransferSize; // // } // // } // return 0; // } // esp_err_t usbh_stm32_clear_status() // { // // // return _usbh_ // // if (g_pipe_hdl_dflt != NULL) { // // return _usb_clear_status(g_pipe_hdl_dflt); // // } // return ESP_FAIL; // } // esp_err_t _usbh_stm32_load_address(uint32_t address) // { // // if (g_pipe_hdl_dflt != NULL) { // // return _usb_load_address(g_pipe_hdl_dflt, address); // // } // return ESP_FAIL; // } //////////// STM32固件升级相关的函数结束 ////////////// // static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle; int usbport_init(void) { SYS_LOG_INF("usbport_init"); if (s_port.vtable) { SYS_LOG_WRN("repeated initialize"); return -1; } s_port.vtable = &usbhost_port_vtable; s_port.data = &s_usb_data; memset(&s_usb_data, 0, sizeof(__usb_data_t)); os_pipe_create(&s_usb_data.pipe_obj, 1024 * 2); // if (ready_to_uninstall_usb == NULL) // { // ready_to_uninstall_usb = xSemaphoreCreateBinary(); // } app_queue = xQueueCreate(3, sizeof(msc_host_event_t)); assert(app_queue); static usb_host_config_t const host_config = { .skip_phy_setup = false, .intr_flags = ESP_INTR_FLAG_LEVEL1, }; ESP_ERROR_CHECK(usb_host_install(&host_config)); if (s_usb_task_handle == NULL) { xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 4096, NULL, SBTASK_PRIORITY_USB_HOST, &s_usb_task_handle, SBTASK_CORE_INDEX_USB_HOST); assert(s_usb_task_handle); } if (s_device_task_handle == NULL) { xTaskCreatePinnedToCore(handle_device_events, "device_events", 4096, NULL, SBTASK_PRIORITY_USB_DEVICE, &s_device_task_handle, SBTASK_CORE_INDEX_USB_DEVICE); assert(s_device_task_handle); } const msc_host_driver_config_t msc_config = { .create_backround_task = true, .task_priority = SBTASK_PRIORITY_USB_MSC, .stack_size = 2048 * 2, .callback = usb_device_event_cb, .core_id = 0}; ESP_ERROR_CHECK(msc_host_install(&msc_config)); return 0; } void usbport_deinit(void) { SYS_LOG_INF("usbport_deinit"); if (s_port.vtable == NULL) { SYS_LOG_WRN("usb host not initialized"); return; } if (g_connected_usb_device) { if (vfs_handle) { msc_host_vfs_unregister(vfs_handle); vfs_handle = NULL; } msc_host_uninstall_device(g_connected_usb_device); g_connected_usb_device = NULL; } if (g_cdc_dev) { cdc_host_close(g_cdc_dev); g_cdc_dev = NULL; } ESP_ERROR_CHECK(msc_host_uninstall()); vTaskDelay(pdMS_TO_TICKS(100)); // if (s_device_task_handle) // { // vTaskDelete(s_device_task_handle); // s_device_task_handle = NULL; // } // if (s_usb_task_handle) // { // vTaskDelete(s_usb_task_handle); // s_usb_task_handle = NULL; // } ESP_ERROR_CHECK(usb_host_uninstall()); if (app_queue) { vQueueDelete(app_queue); app_queue = NULL; } // if (ready_to_uninstall_usb) // { // vSemaphoreDelete(ready_to_uninstall_usb); // ready_to_uninstall_usb = NULL; // } if (os_pipe_is_valid(&s_usb_data.pipe_obj)) { os_pipe_delete(&s_usb_data.pipe_obj); } s_port.vtable = NULL; } sb_data_port_t *usbport_bind(os_work_t *rx_resume_work) { if (s_port.data == NULL) { SYS_LOG_WRN("usb host not initialized"); return NULL; } __usb_data_t *usb_data = s_port.data; usb_data->rx_resume_work = rx_resume_work; os_pipe_regist(&usb_data->pipe_obj, rx_resume_work, 0); return &s_port; } void usbport_unbind(sb_data_port_t *port) { if (port == NULL) { SYS_LOG_WRN("usb host not initialized"); return; } __usb_data_t *usb_data = port->data; os_pipe_unregist(&usb_data->pipe_obj); usb_data->rx_resume_work = NULL; } usbport_status_e usbport_get_state(void) { return g_usb_status; } msc_file_info *msc_get_file_list(uint16_t *out_file_count, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count) { g_msc_file_count = 0; list_all_files("/usb/", &g_msc_file_count, excluding_files, excluding_file_count); return msc_get_cached_file_list(out_file_count); } msc_file_info *msc_get_cached_file_list(uint16_t *out_file_count) { if (out_file_count) { *out_file_count = g_msc_file_count; } return g_msc_file_lists; } usb_connect_type_t usbport_get_usb_type(void) { return s_usb_connect_type; }