usb_host: Propagate new device connection to user

Closes https://github.com/espressif/esp-idf/issues/8762
This commit is contained in:
Tomas Rezucha 2022-03-28 14:16:56 +02:00
parent 0ab17ec695
commit 0428efa4ad
3 changed files with 62 additions and 1 deletions

View File

@ -53,6 +53,7 @@ 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;
cdc_acm_new_dev_callback_t new_dev_cb;
SLIST_HEAD(list_dev, cdc_dev_s) cdc_devices_list; /*!< List of open pseudo devices */
} cdc_acm_obj_t;
@ -66,7 +67,8 @@ static cdc_acm_obj_t *p_cdc_acm_obj = NULL;
static const cdc_acm_host_driver_config_t cdc_acm_driver_config_default = {
.driver_task_stack_size = 4096,
.driver_task_priority = 10,
.xCoreID = 0
.xCoreID = 0,
.new_dev_cb = NULL,
};
/**
@ -429,6 +431,7 @@ esp_err_t cdc_acm_host_install(const cdc_acm_host_driver_config_t *driver_config
cdc_acm_obj->event_group = event_group;
cdc_acm_obj->open_close_mutex = mutex;
cdc_acm_obj->cdc_acm_client_hdl = usb_client;
cdc_acm_obj->new_dev_cb = driver_config->new_dev_cb;
// Between 1st call of this function and following section, another task might try to install this driver:
// Make sure that there is only one instance of this driver in the system
@ -1018,6 +1021,16 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
switch (event_msg->event) {
case USB_HOST_CLIENT_EVENT_NEW_DEV:
ESP_LOGD(TAG, "New device connected");
if (p_cdc_acm_obj->new_dev_cb) {
usb_device_handle_t new_dev;
if (usb_host_device_open(p_cdc_acm_obj->cdc_acm_client_hdl, event_msg->new_dev.address, &new_dev) != ESP_OK) {
ESP_LOGW(TAG, "Couldn't open the new device");
break;
}
assert(new_dev);
p_cdc_acm_obj->new_dev_cb(new_dev);
usb_host_device_close(p_cdc_acm_obj->cdc_acm_client_hdl, new_dev);
}
break;
case USB_HOST_CLIENT_EVENT_DEV_GONE: {
ESP_LOGD(TAG, "Device suddenly disconnected");

View File

@ -7,6 +7,7 @@
#pragma once
#include <stdbool.h>
#include "usb/usb_host.h"
#include "usb_types_cdc.h"
#include "esp_err.h"
@ -69,6 +70,16 @@ typedef struct {
} data;
} cdc_acm_host_dev_event_data_t;
/**
* @brief New USB device callback
*
* Provides already opened usb_dev, that will be closed after this callback returns.
* This is useful for peeking device's descriptors, e.g. peeking VID/PID and loading proper driver.
*
* @attention This callback is called from USB Host context, so the CDC device can't be opened here.
*/
typedef void (*cdc_acm_new_dev_callback_t)(usb_device_handle_t usb_dev);
/**
* @brief Data receive callback type
*/
@ -88,6 +99,7 @@ typedef struct {
size_t driver_task_stack_size; /**< Stack size of the driver's task */
unsigned driver_task_priority; /**< Priority of the driver's task */
int xCoreID; /**< Core affinity of the driver's task */
cdc_acm_new_dev_callback_t new_dev_cb; /**< New USB device connected callback. Can be NULL. */
} cdc_acm_host_driver_config_t;
/**

View File

@ -130,6 +130,19 @@ static void notif_cb(cdc_acm_dev_hdl_t cdc_hdl, const cdc_acm_host_dev_event_dat
}
}
static bool new_dev_cb_called = false;
static void new_dev_cb(usb_device_handle_t usb_dev) {
new_dev_cb_called = true;
const usb_config_desc_t *config_desc;
const usb_device_desc_t *device_desc;
// Get descriptors
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(usb_dev, &device_desc));
TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(usb_dev, &config_desc));
printf("New device connected. VID = 0x%04X PID = %04X\n", device_desc->idVendor, device_desc->idProduct);
}
/* Basic test to check CDC communication:
* open/read/write/close device
* CDC-ACM specific commands: set/get_line_coding, set_control_line_state */
@ -398,6 +411,29 @@ TEST_CASE("custom_command", "[cdc_acm]")
vTaskDelay(20);
}
TEST_CASE("new_device_connection", "[cdc_acm]")
{
// Create a task that will handle USB library events
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(usb_lib_task, "usb_lib", 4*4096, xTaskGetCurrentTaskHandle(), 10, NULL, 0));
ulTaskNotifyTake(false, 1000);
printf("Installing CDC-ACM driver\n");
const cdc_acm_host_driver_config_t driver_config = {
.driver_task_priority = 11,
.driver_task_stack_size = 2048,
.xCoreID = 0,
.new_dev_cb = new_dev_cb,
};
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_install(&driver_config));
vTaskDelay(80);
TEST_ASSERT_TRUE_MESSAGE(new_dev_cb_called, "New device callback was not called\n");
// Clean-up
TEST_ASSERT_EQUAL(ESP_OK, cdc_acm_host_uninstall());
vTaskDelay(20);
}
/* Following test case implements dual CDC-ACM USB device that can be used as mock device for CDC-ACM Host tests */
void run_usb_dual_cdc_device(void);
TEST_CASE("mock_device_app", "[cdc_acm_device][ignore]")