mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
refactor(usb_host/examples): Enabled external Hub support feature
This commit is contained in:
@ -6,3 +6,4 @@ CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
|||||||
# CONFIG_UNITY_ENABLE_FLOAT is not set
|
# CONFIG_UNITY_ENABLE_FLOAT is not set
|
||||||
# CONFIG_UNITY_ENABLE_DOUBLE is not set
|
# CONFIG_UNITY_ENABLE_DOUBLE is not set
|
||||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
||||||
|
@ -6,3 +6,4 @@ CONFIG_HEAP_POISONING_COMPREHENSIVE=y
|
|||||||
# CONFIG_UNITY_ENABLE_FLOAT is not set
|
# CONFIG_UNITY_ENABLE_FLOAT is not set
|
||||||
# CONFIG_UNITY_ENABLE_DOUBLE is not set
|
# CONFIG_UNITY_ENABLE_DOUBLE is not set
|
||||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||||
#
|
#
|
||||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
||||||
|
4
examples/peripherals/usb/host/hid/sdkconfig.defaults
Normal file
4
examples/peripherals/usb/host/hid/sdkconfig.defaults
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||||
|
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||||
|
#
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
@ -29,6 +29,11 @@ static const char *TAG = "example";
|
|||||||
#define APP_QUIT_PIN GPIO_NUM_0 // BOOT button on most boards
|
#define APP_QUIT_PIN GPIO_NUM_0 // BOOT button on most boards
|
||||||
#define BUFFER_SIZE 4096 // The read/write performance can be improved with larger buffer for the cost of RAM, 4kB is enough for most usecases
|
#define BUFFER_SIZE 4096 // The read/write performance can be improved with larger buffer for the cost of RAM, 4kB is enough for most usecases
|
||||||
|
|
||||||
|
// IMPORTANT NOTE
|
||||||
|
// MSC Class Driver is not fully support connecting devices through external Hub.
|
||||||
|
// TODO: Remove this line after MSC Class Driver will support it
|
||||||
|
static bool dev_present = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Application Queue and its messages ID
|
* @brief Application Queue and its messages ID
|
||||||
*/
|
*/
|
||||||
@ -78,7 +83,7 @@ static void gpio_cb(void *arg)
|
|||||||
static void msc_event_cb(const msc_host_event_t *event, void *arg)
|
static void msc_event_cb(const msc_host_event_t *event, void *arg)
|
||||||
{
|
{
|
||||||
if (event->event == MSC_DEVICE_CONNECTED) {
|
if (event->event == MSC_DEVICE_CONNECTED) {
|
||||||
ESP_LOGI(TAG, "MSC device connected");
|
ESP_LOGI(TAG, "MSC device connected (usb_addr=%d)", event->device.address);
|
||||||
app_message_t message = {
|
app_message_t message = {
|
||||||
.id = APP_DEVICE_CONNECTED,
|
.id = APP_DEVICE_CONNECTED,
|
||||||
.data.new_dev_address = event->device.address,
|
.data.new_dev_address = event->device.address,
|
||||||
@ -274,47 +279,56 @@ void app_main(void)
|
|||||||
xQueueReceive(app_queue, &msg, portMAX_DELAY);
|
xQueueReceive(app_queue, &msg, portMAX_DELAY);
|
||||||
|
|
||||||
if (msg.id == APP_DEVICE_CONNECTED) {
|
if (msg.id == APP_DEVICE_CONNECTED) {
|
||||||
// 1. MSC flash drive connected. Open it and map it to Virtual File System
|
if (dev_present) {
|
||||||
ESP_ERROR_CHECK(msc_host_install_device(msg.data.new_dev_address, &msc_device));
|
ESP_LOGW(TAG, "MSC Example handles only one device at a time");
|
||||||
const esp_vfs_fat_mount_config_t mount_config = {
|
} else {
|
||||||
.format_if_mount_failed = false,
|
// 0. Change flag
|
||||||
.max_files = 3,
|
dev_present = true;
|
||||||
.allocation_unit_size = 8192,
|
// 1. MSC flash drive connected. Open it and map it to Virtual File System
|
||||||
};
|
ESP_ERROR_CHECK(msc_host_install_device(msg.data.new_dev_address, &msc_device));
|
||||||
ESP_ERROR_CHECK(msc_host_vfs_register(msc_device, MNT_PATH, &mount_config, &vfs_handle));
|
const esp_vfs_fat_mount_config_t mount_config = {
|
||||||
|
.format_if_mount_failed = false,
|
||||||
|
.max_files = 3,
|
||||||
|
.allocation_unit_size = 8192,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(msc_host_vfs_register(msc_device, MNT_PATH, &mount_config, &vfs_handle));
|
||||||
|
|
||||||
// 2. Print information about the connected disk
|
// 2. Print information about the connected disk
|
||||||
msc_host_device_info_t info;
|
msc_host_device_info_t info;
|
||||||
ESP_ERROR_CHECK(msc_host_get_device_info(msc_device, &info));
|
ESP_ERROR_CHECK(msc_host_get_device_info(msc_device, &info));
|
||||||
msc_host_print_descriptors(msc_device);
|
msc_host_print_descriptors(msc_device);
|
||||||
print_device_info(&info);
|
print_device_info(&info);
|
||||||
|
|
||||||
// 3. List all the files in root directory
|
// 3. List all the files in root directory
|
||||||
ESP_LOGI(TAG, "ls command output:");
|
ESP_LOGI(TAG, "ls command output:");
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
DIR *dh = opendir(MNT_PATH);
|
DIR *dh = opendir(MNT_PATH);
|
||||||
assert(dh);
|
assert(dh);
|
||||||
while ((d = readdir(dh)) != NULL) {
|
while ((d = readdir(dh)) != NULL) {
|
||||||
printf("%s\n", d->d_name);
|
printf("%s\n", d->d_name);
|
||||||
|
}
|
||||||
|
closedir(dh);
|
||||||
|
|
||||||
|
// 4. The disk is mounted to Virtual File System, perform some basic demo file operation
|
||||||
|
file_operations();
|
||||||
|
|
||||||
|
// 5. Perform speed test
|
||||||
|
speed_test();
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Example finished, you can disconnect the USB flash drive");
|
||||||
}
|
}
|
||||||
closedir(dh);
|
|
||||||
|
|
||||||
// 4. The disk is mounted to Virtual File System, perform some basic demo file operation
|
|
||||||
file_operations();
|
|
||||||
|
|
||||||
// 5. Perform speed test
|
|
||||||
speed_test();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Example finished, you can disconnect the USB flash drive");
|
|
||||||
}
|
}
|
||||||
if ((msg.id == APP_DEVICE_DISCONNECTED) || (msg.id == APP_QUIT)) {
|
if ((msg.id == APP_DEVICE_DISCONNECTED) || (msg.id == APP_QUIT)) {
|
||||||
if (vfs_handle) {
|
if (dev_present) {
|
||||||
ESP_ERROR_CHECK(msc_host_vfs_unregister(vfs_handle));
|
dev_present = false;
|
||||||
vfs_handle = NULL;
|
if (vfs_handle) {
|
||||||
}
|
ESP_ERROR_CHECK(msc_host_vfs_unregister(vfs_handle));
|
||||||
if (msc_device) {
|
vfs_handle = NULL;
|
||||||
ESP_ERROR_CHECK(msc_host_uninstall_device(msc_device));
|
}
|
||||||
msc_device = NULL;
|
if (msc_device) {
|
||||||
|
ESP_ERROR_CHECK(msc_host_uninstall_device(msc_device));
|
||||||
|
msc_device = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (msg.id == APP_QUIT) {
|
if (msg.id == APP_QUIT) {
|
||||||
// This will cause the usb_task to exit
|
// This will cause the usb_task to exit
|
||||||
|
4
examples/peripherals/usb/host/msc/sdkconfig.defaults
Normal file
4
examples/peripherals/usb/host/msc/sdkconfig.defaults
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||||
|
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||||
|
#
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
@ -13,21 +13,40 @@
|
|||||||
#define CLIENT_NUM_EVENT_MSG 5
|
#define CLIENT_NUM_EVENT_MSG 5
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ACTION_OPEN_DEV = 0x01,
|
ACTION_OPEN_DEV = (1 << 0),
|
||||||
ACTION_GET_DEV_INFO = 0x02,
|
ACTION_GET_DEV_INFO = (1 << 1),
|
||||||
ACTION_GET_DEV_DESC = 0x04,
|
ACTION_GET_DEV_DESC = (1 << 2),
|
||||||
ACTION_GET_CONFIG_DESC = 0x08,
|
ACTION_GET_CONFIG_DESC = (1 << 3),
|
||||||
ACTION_GET_STR_DESC = 0x10,
|
ACTION_GET_STR_DESC = (1 << 4),
|
||||||
ACTION_CLOSE_DEV = 0x20,
|
ACTION_CLOSE_DEV = (1 << 5),
|
||||||
ACTION_EXIT = 0x40,
|
|
||||||
ACTION_RECONNECT = 0x80,
|
|
||||||
} action_t;
|
} action_t;
|
||||||
|
|
||||||
|
#define DEV_MAX_COUNT 128
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
usb_host_client_handle_t client_hdl;
|
usb_host_client_handle_t client_hdl;
|
||||||
uint8_t dev_addr;
|
uint8_t dev_addr;
|
||||||
usb_device_handle_t dev_hdl;
|
usb_device_handle_t dev_hdl;
|
||||||
uint32_t actions;
|
action_t actions;
|
||||||
|
} usb_device_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t unhandled_devices: 1; /**< Device has unhandled devices */
|
||||||
|
uint8_t shutdown: 1; /**< */
|
||||||
|
uint8_t reserved6: 6; /**< Reserved */
|
||||||
|
};
|
||||||
|
uint8_t val; /**< Class drivers' flags value */
|
||||||
|
} flags; /**< Class drivers' flags */
|
||||||
|
usb_device_t device[DEV_MAX_COUNT]; /**< Class drivers' static array of devices */
|
||||||
|
} mux_protected; /**< Mutex protected members. Must be protected by the Class mux_lock when accessed */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
usb_host_client_handle_t client_hdl;
|
||||||
|
SemaphoreHandle_t mux_lock; /**< Mutex for protected members */
|
||||||
|
} constant; /**< Constant members. Do not change after installation thus do not require a critical section or mutex */
|
||||||
} class_driver_t;
|
} class_driver_t;
|
||||||
|
|
||||||
static const char *TAG = "CLASS";
|
static const char *TAG = "CLASS";
|
||||||
@ -38,79 +57,94 @@ static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *
|
|||||||
class_driver_t *driver_obj = (class_driver_t *)arg;
|
class_driver_t *driver_obj = (class_driver_t *)arg;
|
||||||
switch (event_msg->event) {
|
switch (event_msg->event) {
|
||||||
case USB_HOST_CLIENT_EVENT_NEW_DEV:
|
case USB_HOST_CLIENT_EVENT_NEW_DEV:
|
||||||
if (driver_obj->dev_addr == 0) {
|
// Save the device address
|
||||||
driver_obj->dev_addr = event_msg->new_dev.address;
|
xSemaphoreTake(driver_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
//Open the device next
|
driver_obj->mux_protected.device[event_msg->new_dev.address].dev_addr = event_msg->new_dev.address;
|
||||||
driver_obj->actions |= ACTION_OPEN_DEV;
|
driver_obj->mux_protected.device[event_msg->new_dev.address].dev_hdl = NULL;
|
||||||
}
|
// Open the device next
|
||||||
|
driver_obj->mux_protected.device[event_msg->new_dev.address].actions |= ACTION_OPEN_DEV;
|
||||||
|
// Set flag
|
||||||
|
driver_obj->mux_protected.flags.unhandled_devices = 1;
|
||||||
|
xSemaphoreGive(driver_obj->constant.mux_lock);
|
||||||
break;
|
break;
|
||||||
case USB_HOST_CLIENT_EVENT_DEV_GONE:
|
case USB_HOST_CLIENT_EVENT_DEV_GONE:
|
||||||
if (driver_obj->dev_hdl != NULL) {
|
// Cancel any other actions and close the device next
|
||||||
//Cancel any other actions and close the device next
|
xSemaphoreTake(driver_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
driver_obj->actions = ACTION_CLOSE_DEV;
|
for (uint8_t i = 0; i < DEV_MAX_COUNT; i++) {
|
||||||
|
if (driver_obj->mux_protected.device[i].dev_hdl == event_msg->dev_gone.dev_hdl) {
|
||||||
|
driver_obj->mux_protected.device[i].actions = ACTION_CLOSE_DEV;
|
||||||
|
// Set flag
|
||||||
|
driver_obj->mux_protected.flags.unhandled_devices = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
xSemaphoreGive(driver_obj->constant.mux_lock);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//Should never occur
|
// Should never occur
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_open_dev(class_driver_t *driver_obj)
|
static void action_open_dev(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
assert(driver_obj->dev_addr != 0);
|
assert(device_obj->dev_addr != 0);
|
||||||
ESP_LOGI(TAG, "Opening device at address %d", driver_obj->dev_addr);
|
ESP_LOGI(TAG, "Opening device at address %d", device_obj->dev_addr);
|
||||||
ESP_ERROR_CHECK(usb_host_device_open(driver_obj->client_hdl, driver_obj->dev_addr, &driver_obj->dev_hdl));
|
ESP_ERROR_CHECK(usb_host_device_open(device_obj->client_hdl, device_obj->dev_addr, &device_obj->dev_hdl));
|
||||||
//Get the device's information next
|
// Get the device's information next
|
||||||
driver_obj->actions &= ~ACTION_OPEN_DEV;
|
device_obj->actions |= ACTION_GET_DEV_INFO;
|
||||||
driver_obj->actions |= ACTION_GET_DEV_INFO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_get_info(class_driver_t *driver_obj)
|
static void action_get_info(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
assert(driver_obj->dev_hdl != NULL);
|
assert(device_obj->dev_hdl != NULL);
|
||||||
ESP_LOGI(TAG, "Getting device information");
|
ESP_LOGI(TAG, "Getting device information");
|
||||||
usb_device_info_t dev_info;
|
usb_device_info_t dev_info;
|
||||||
ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
|
ESP_ERROR_CHECK(usb_host_device_info(device_obj->dev_hdl, &dev_info));
|
||||||
ESP_LOGI(TAG, "\t%s speed", (char *[]) {
|
ESP_LOGI(TAG, "\t%s speed", (char *[]) {
|
||||||
"Low", "Full", "High"
|
"Low", "Full", "High"
|
||||||
}[dev_info.speed]);
|
}[dev_info.speed]);
|
||||||
ESP_LOGI(TAG, "\tbConfigurationValue %d", dev_info.bConfigurationValue);
|
ESP_LOGI(TAG, "\tParent info:");
|
||||||
|
if (dev_info.parent.dev_hdl) {
|
||||||
|
usb_device_info_t parent_dev_info;
|
||||||
|
ESP_ERROR_CHECK(usb_host_device_info(dev_info.parent.dev_hdl, &parent_dev_info));
|
||||||
|
ESP_LOGI(TAG, "\t\tBus addr: %d", parent_dev_info.dev_addr);
|
||||||
|
ESP_LOGI(TAG, "\t\tPort: %d", dev_info.parent.port_num);
|
||||||
|
|
||||||
//Get the device descriptor next
|
} else {
|
||||||
driver_obj->actions &= ~ACTION_GET_DEV_INFO;
|
ESP_LOGI(TAG, "\t\tPort: ROOT");
|
||||||
driver_obj->actions |= ACTION_GET_DEV_DESC;
|
}
|
||||||
|
ESP_LOGI(TAG, "\tbConfigurationValue %d", dev_info.bConfigurationValue);
|
||||||
|
// Get the device descriptor next
|
||||||
|
device_obj->actions |= ACTION_GET_DEV_DESC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_get_dev_desc(class_driver_t *driver_obj)
|
static void action_get_dev_desc(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
assert(driver_obj->dev_hdl != NULL);
|
assert(device_obj->dev_hdl != NULL);
|
||||||
ESP_LOGI(TAG, "Getting device descriptor");
|
ESP_LOGI(TAG, "Getting device descriptor");
|
||||||
const usb_device_desc_t *dev_desc;
|
const usb_device_desc_t *dev_desc;
|
||||||
ESP_ERROR_CHECK(usb_host_get_device_descriptor(driver_obj->dev_hdl, &dev_desc));
|
ESP_ERROR_CHECK(usb_host_get_device_descriptor(device_obj->dev_hdl, &dev_desc));
|
||||||
usb_print_device_descriptor(dev_desc);
|
usb_print_device_descriptor(dev_desc);
|
||||||
//Get the device's config descriptor next
|
// Get the device's config descriptor next
|
||||||
driver_obj->actions &= ~ACTION_GET_DEV_DESC;
|
device_obj->actions |= ACTION_GET_CONFIG_DESC;
|
||||||
driver_obj->actions |= ACTION_GET_CONFIG_DESC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_get_config_desc(class_driver_t *driver_obj)
|
static void action_get_config_desc(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
assert(driver_obj->dev_hdl != NULL);
|
assert(device_obj->dev_hdl != NULL);
|
||||||
ESP_LOGI(TAG, "Getting config descriptor");
|
ESP_LOGI(TAG, "Getting config descriptor");
|
||||||
const usb_config_desc_t *config_desc;
|
const usb_config_desc_t *config_desc;
|
||||||
ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(driver_obj->dev_hdl, &config_desc));
|
ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(device_obj->dev_hdl, &config_desc));
|
||||||
usb_print_config_descriptor(config_desc, NULL);
|
usb_print_config_descriptor(config_desc, NULL);
|
||||||
//Get the device's string descriptors next
|
// Get the device's string descriptors next
|
||||||
driver_obj->actions &= ~ACTION_GET_CONFIG_DESC;
|
device_obj->actions |= ACTION_GET_STR_DESC;
|
||||||
driver_obj->actions |= ACTION_GET_STR_DESC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_get_str_desc(class_driver_t *driver_obj)
|
static void action_get_str_desc(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
assert(driver_obj->dev_hdl != NULL);
|
assert(device_obj->dev_hdl != NULL);
|
||||||
usb_device_info_t dev_info;
|
usb_device_info_t dev_info;
|
||||||
ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
|
ESP_ERROR_CHECK(usb_host_device_info(device_obj->dev_hdl, &dev_info));
|
||||||
if (dev_info.str_desc_manufacturer) {
|
if (dev_info.str_desc_manufacturer) {
|
||||||
ESP_LOGI(TAG, "Getting Manufacturer string descriptor");
|
ESP_LOGI(TAG, "Getting Manufacturer string descriptor");
|
||||||
usb_print_string_descriptor(dev_info.str_desc_manufacturer);
|
usb_print_string_descriptor(dev_info.str_desc_manufacturer);
|
||||||
@ -123,25 +157,59 @@ static void action_get_str_desc(class_driver_t *driver_obj)
|
|||||||
ESP_LOGI(TAG, "Getting Serial Number string descriptor");
|
ESP_LOGI(TAG, "Getting Serial Number string descriptor");
|
||||||
usb_print_string_descriptor(dev_info.str_desc_serial_num);
|
usb_print_string_descriptor(dev_info.str_desc_serial_num);
|
||||||
}
|
}
|
||||||
//Nothing to do until the device disconnects
|
|
||||||
driver_obj->actions &= ~ACTION_GET_STR_DESC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void action_close_dev(class_driver_t *driver_obj)
|
static void action_close_dev(usb_device_t *device_obj)
|
||||||
{
|
{
|
||||||
ESP_ERROR_CHECK(usb_host_device_close(driver_obj->client_hdl, driver_obj->dev_hdl));
|
ESP_ERROR_CHECK(usb_host_device_close(device_obj->client_hdl, device_obj->dev_hdl));
|
||||||
driver_obj->dev_hdl = NULL;
|
device_obj->dev_hdl = NULL;
|
||||||
driver_obj->dev_addr = 0;
|
device_obj->dev_addr = 0;
|
||||||
//We need to connect a new device
|
}
|
||||||
driver_obj->actions &= ~ACTION_CLOSE_DEV;
|
|
||||||
driver_obj->actions |= ACTION_RECONNECT;
|
static void class_driver_device_handle(usb_device_t *device_obj)
|
||||||
|
{
|
||||||
|
uint8_t actions = device_obj->actions;
|
||||||
|
device_obj->actions = 0;
|
||||||
|
|
||||||
|
while (actions) {
|
||||||
|
if (actions & ACTION_OPEN_DEV) {
|
||||||
|
action_open_dev(device_obj);
|
||||||
|
}
|
||||||
|
if (actions & ACTION_GET_DEV_INFO) {
|
||||||
|
action_get_info(device_obj);
|
||||||
|
}
|
||||||
|
if (actions & ACTION_GET_DEV_DESC) {
|
||||||
|
action_get_dev_desc(device_obj);
|
||||||
|
}
|
||||||
|
if (actions & ACTION_GET_CONFIG_DESC) {
|
||||||
|
action_get_config_desc(device_obj);
|
||||||
|
}
|
||||||
|
if (actions & ACTION_GET_STR_DESC) {
|
||||||
|
action_get_str_desc(device_obj);
|
||||||
|
}
|
||||||
|
if (actions & ACTION_CLOSE_DEV) {
|
||||||
|
action_close_dev(device_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = device_obj->actions;
|
||||||
|
device_obj->actions = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void class_driver_task(void *arg)
|
void class_driver_task(void *arg)
|
||||||
{
|
{
|
||||||
class_driver_t driver_obj = {0};
|
class_driver_t driver_obj = {0};
|
||||||
|
usb_host_client_handle_t class_driver_client_hdl = NULL;
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Registering Client");
|
ESP_LOGI(TAG, "Registering Client");
|
||||||
|
|
||||||
|
SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex();
|
||||||
|
if (mux_lock == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Unable to create class driver mutex");
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
usb_host_client_config_t client_config = {
|
usb_host_client_config_t client_config = {
|
||||||
.is_synchronous = false, //Synchronous clients currently not supported. Set this to false
|
.is_synchronous = false, //Synchronous clients currently not supported. Set this to false
|
||||||
.max_num_event_msg = CLIENT_NUM_EVENT_MSG,
|
.max_num_event_msg = CLIENT_NUM_EVENT_MSG,
|
||||||
@ -150,52 +218,62 @@ void class_driver_task(void *arg)
|
|||||||
.callback_arg = (void *) &driver_obj,
|
.callback_arg = (void *) &driver_obj,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(usb_host_client_register(&client_config, &driver_obj.client_hdl));
|
ESP_ERROR_CHECK(usb_host_client_register(&client_config, &class_driver_client_hdl));
|
||||||
|
|
||||||
|
driver_obj.constant.mux_lock = mux_lock;
|
||||||
|
driver_obj.constant.client_hdl = class_driver_client_hdl;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DEV_MAX_COUNT; i++) {
|
||||||
|
driver_obj.mux_protected.device[i].client_hdl = class_driver_client_hdl;
|
||||||
|
}
|
||||||
|
|
||||||
s_driver_obj = &driver_obj;
|
s_driver_obj = &driver_obj;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (driver_obj.actions == 0) {
|
// Driver has unhandled devices, handle all devices first
|
||||||
usb_host_client_handle_events(driver_obj.client_hdl, portMAX_DELAY);
|
if (driver_obj.mux_protected.flags.unhandled_devices) {
|
||||||
|
xSemaphoreTake(driver_obj.constant.mux_lock, portMAX_DELAY);
|
||||||
|
for (uint8_t i = 0; i < DEV_MAX_COUNT; i++) {
|
||||||
|
if (driver_obj.mux_protected.device[i].actions) {
|
||||||
|
class_driver_device_handle(&driver_obj.mux_protected.device[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
driver_obj.mux_protected.flags.unhandled_devices = 0;
|
||||||
|
xSemaphoreGive(driver_obj.constant.mux_lock);
|
||||||
} else {
|
} else {
|
||||||
if (driver_obj.actions & ACTION_OPEN_DEV) {
|
// Driver is active, handle client events
|
||||||
action_open_dev(&driver_obj);
|
if (driver_obj.mux_protected.flags.shutdown == 0) {
|
||||||
}
|
usb_host_client_handle_events(class_driver_client_hdl, portMAX_DELAY);
|
||||||
if (driver_obj.actions & ACTION_GET_DEV_INFO) {
|
} else {
|
||||||
action_get_info(&driver_obj);
|
// Shutdown the driver
|
||||||
}
|
|
||||||
if (driver_obj.actions & ACTION_GET_DEV_DESC) {
|
|
||||||
action_get_dev_desc(&driver_obj);
|
|
||||||
}
|
|
||||||
if (driver_obj.actions & ACTION_GET_CONFIG_DESC) {
|
|
||||||
action_get_config_desc(&driver_obj);
|
|
||||||
}
|
|
||||||
if (driver_obj.actions & ACTION_GET_STR_DESC) {
|
|
||||||
action_get_str_desc(&driver_obj);
|
|
||||||
}
|
|
||||||
if (driver_obj.actions & ACTION_CLOSE_DEV) {
|
|
||||||
action_close_dev(&driver_obj);
|
|
||||||
}
|
|
||||||
if (driver_obj.actions & ACTION_EXIT) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (driver_obj.actions & ACTION_RECONNECT) {
|
|
||||||
driver_obj.actions = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Deregistering Client");
|
ESP_LOGI(TAG, "Deregistering Class Client");
|
||||||
ESP_ERROR_CHECK(usb_host_client_deregister(driver_obj.client_hdl));
|
ESP_ERROR_CHECK(usb_host_client_deregister(class_driver_client_hdl));
|
||||||
vTaskSuspend(NULL);
|
if (mux_lock != NULL) {
|
||||||
|
vSemaphoreDelete(mux_lock);
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void class_driver_client_deregister(void)
|
void class_driver_client_deregister(void)
|
||||||
{
|
{
|
||||||
if (s_driver_obj->dev_hdl != NULL) {
|
// Mark all opened devices
|
||||||
s_driver_obj->actions = ACTION_CLOSE_DEV;
|
xSemaphoreTake(s_driver_obj->constant.mux_lock, portMAX_DELAY);
|
||||||
|
for (uint8_t i = 0; i < DEV_MAX_COUNT; i++) {
|
||||||
|
if (s_driver_obj->mux_protected.device[i].dev_hdl != NULL) {
|
||||||
|
// Mark device to close
|
||||||
|
s_driver_obj->mux_protected.device[i].actions |= ACTION_CLOSE_DEV;
|
||||||
|
// Set flag
|
||||||
|
s_driver_obj->mux_protected.flags.unhandled_devices = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s_driver_obj->actions |= ACTION_EXIT;
|
s_driver_obj->mux_protected.flags.shutdown = 1;
|
||||||
|
xSemaphoreGive(s_driver_obj->constant.mux_lock);
|
||||||
|
|
||||||
// Unblock, exit the loop and proceed to deregister client
|
// Unblock, exit the loop and proceed to deregister client
|
||||||
ESP_ERROR_CHECK(usb_host_client_unblock(s_driver_obj->client_hdl));
|
ESP_ERROR_CHECK(usb_host_client_unblock(s_driver_obj->constant.client_hdl));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -120,26 +120,26 @@ static void usb_host_lib_task(void *arg)
|
|||||||
xTaskNotifyGive(arg);
|
xTaskNotifyGive(arg);
|
||||||
|
|
||||||
bool has_clients = true;
|
bool has_clients = true;
|
||||||
bool has_devices = true;
|
bool has_devices = false;
|
||||||
while (has_clients || has_devices) {
|
while (has_clients) {
|
||||||
uint32_t event_flags;
|
uint32_t event_flags;
|
||||||
ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags));
|
ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags));
|
||||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
|
||||||
ESP_LOGI(TAG, "No more clients");
|
ESP_LOGI(TAG, "Get FLAGS_NO_CLIENTS");
|
||||||
has_clients = false;
|
|
||||||
if (ESP_OK == usb_host_device_free_all()) {
|
if (ESP_OK == usb_host_device_free_all()) {
|
||||||
ESP_LOGI(TAG, "All devices marked as free");
|
ESP_LOGI(TAG, "All devices marked as free, no need to wait FLAGS_ALL_FREE event");
|
||||||
|
has_clients = false;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "Wait for the ALL FREE EVENT");
|
ESP_LOGI(TAG, "Wait for the FLAGS_ALL_FREE");
|
||||||
|
has_devices = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
if (has_devices && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
|
||||||
ESP_LOGI(TAG, "No more devices");
|
ESP_LOGI(TAG, "Get FLAGS_ALL_FREE");
|
||||||
has_devices = false;
|
has_clients = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "No more clients and devices");
|
ESP_LOGI(TAG, "No more clients and devices, uninstall USB Host library");
|
||||||
|
|
||||||
//Uninstall the USB Host Library
|
//Uninstall the USB Host Library
|
||||||
ESP_ERROR_CHECK(usb_host_uninstall());
|
ESP_ERROR_CHECK(usb_host_uninstall());
|
||||||
@ -167,7 +167,7 @@ void app_main(void)
|
|||||||
|
|
||||||
TaskHandle_t host_lib_task_hdl, class_driver_task_hdl;
|
TaskHandle_t host_lib_task_hdl, class_driver_task_hdl;
|
||||||
|
|
||||||
//Create usb host lib task
|
// Create usb host lib task
|
||||||
BaseType_t task_created;
|
BaseType_t task_created;
|
||||||
task_created = xTaskCreatePinnedToCore(usb_host_lib_task,
|
task_created = xTaskCreatePinnedToCore(usb_host_lib_task,
|
||||||
"usb_host",
|
"usb_host",
|
||||||
@ -178,19 +178,20 @@ void app_main(void)
|
|||||||
0);
|
0);
|
||||||
assert(task_created == pdTRUE);
|
assert(task_created == pdTRUE);
|
||||||
|
|
||||||
//Wait unit the USB host library is installed
|
// Wait unit the USB host library is installed
|
||||||
ulTaskNotifyTake(false, 1000);
|
ulTaskNotifyTake(false, 1000);
|
||||||
|
|
||||||
//Create class driver task
|
// Create class driver task
|
||||||
task_created = xTaskCreatePinnedToCore(class_driver_task,
|
task_created = xTaskCreatePinnedToCore(class_driver_task,
|
||||||
"class",
|
"class",
|
||||||
4096,
|
5 * 1024,
|
||||||
NULL,
|
NULL,
|
||||||
CLASS_TASK_PRIORITY,
|
CLASS_TASK_PRIORITY,
|
||||||
&class_driver_task_hdl,
|
&class_driver_task_hdl,
|
||||||
0);
|
0);
|
||||||
assert(task_created == pdTRUE);
|
assert(task_created == pdTRUE);
|
||||||
vTaskDelay(10); //Add a short delay to let the tasks run
|
// Add a short delay to let the tasks run
|
||||||
|
vTaskDelay(10);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
|
if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
|
||||||
@ -198,22 +199,20 @@ void app_main(void)
|
|||||||
// User pressed button
|
// User pressed button
|
||||||
usb_host_lib_info_t lib_info;
|
usb_host_lib_info_t lib_info;
|
||||||
ESP_ERROR_CHECK(usb_host_lib_info(&lib_info));
|
ESP_ERROR_CHECK(usb_host_lib_info(&lib_info));
|
||||||
if (lib_info.num_devices == 0) {
|
if (lib_info.num_devices != 0) {
|
||||||
// End while cycle
|
ESP_LOGW(TAG, "Shutdown with attached devices.");
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "To shutdown example, remove all USB devices and press button again.");
|
|
||||||
// Keep polling
|
|
||||||
}
|
}
|
||||||
|
// End while cycle
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Deregister client
|
// Deregister client
|
||||||
class_driver_client_deregister();
|
class_driver_client_deregister();
|
||||||
vTaskDelay(10);
|
vTaskDelay(10);
|
||||||
|
|
||||||
//Delete the tasks
|
// Delete the tasks
|
||||||
vTaskDelete(class_driver_task_hdl);
|
vTaskDelete(class_driver_task_hdl);
|
||||||
vTaskDelete(host_lib_task_hdl);
|
vTaskDelete(host_lib_task_hdl);
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||||
|
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||||
|
#
|
||||||
|
CONFIG_USB_HOST_HUBS_SUPPORTED=y
|
Reference in New Issue
Block a user