优化 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 版本和调整蓝牙默认发射功率。
909 lines
29 KiB
C
909 lines
29 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
#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;
|
||
}
|