Эх сурвалжийг харах

usb_host: Propagate new device connection to user

Closes https://github.com/espressif/esp-idf/issues/8762
Tomas Rezucha 3 жил өмнө
parent
commit
0428efa4ad

+ 14 - 1
examples/peripherals/usb/host/cdc/common/cdc_acm_host/cdc_acm_host.c

@@ -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 */
     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;
     SemaphoreHandle_t open_close_mutex;
     EventGroupHandle_t event_group;
     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 */
     SLIST_HEAD(list_dev, cdc_dev_s) cdc_devices_list;   /*!< List of open pseudo devices */
 } cdc_acm_obj_t;
 } 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 = {
 static const cdc_acm_host_driver_config_t cdc_acm_driver_config_default = {
     .driver_task_stack_size = 4096,
     .driver_task_stack_size = 4096,
     .driver_task_priority = 10,
     .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->event_group = event_group;
     cdc_acm_obj->open_close_mutex = mutex;
     cdc_acm_obj->open_close_mutex = mutex;
     cdc_acm_obj->cdc_acm_client_hdl = usb_client;
     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:
     // 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
     // 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) {
     switch (event_msg->event) {
     case USB_HOST_CLIENT_EVENT_NEW_DEV:
     case USB_HOST_CLIENT_EVENT_NEW_DEV:
         ESP_LOGD(TAG, "New device connected");
         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;
         break;
     case USB_HOST_CLIENT_EVENT_DEV_GONE: {
     case USB_HOST_CLIENT_EVENT_DEV_GONE: {
         ESP_LOGD(TAG, "Device suddenly disconnected");
         ESP_LOGD(TAG, "Device suddenly disconnected");

+ 12 - 0
examples/peripherals/usb/host/cdc/common/cdc_acm_host/include/usb/cdc_acm_host.h

@@ -7,6 +7,7 @@
 #pragma once
 #pragma once
 
 
 #include <stdbool.h>
 #include <stdbool.h>
+#include "usb/usb_host.h"
 #include "usb_types_cdc.h"
 #include "usb_types_cdc.h"
 #include "esp_err.h"
 #include "esp_err.h"
 
 
@@ -69,6 +70,16 @@ typedef struct {
     } data;
     } data;
 } cdc_acm_host_dev_event_data_t;
 } 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
  * @brief Data receive callback type
  */
  */
@@ -88,6 +99,7 @@ typedef struct {
     size_t driver_task_stack_size;         /**< Stack size of the driver's task */
     size_t driver_task_stack_size;         /**< Stack size of the driver's task */
     unsigned driver_task_priority;         /**< Priority of the driver's task */
     unsigned driver_task_priority;         /**< Priority of the driver's task */
     int  xCoreID;                          /**< Core affinity 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;
 } cdc_acm_host_driver_config_t;
 
 
 /**
 /**

+ 36 - 0
examples/peripherals/usb/host/cdc/common/cdc_acm_host/test/test_cdc_acm_host.c

@@ -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:
 /* Basic test to check CDC communication:
  * open/read/write/close device
  * open/read/write/close device
  * CDC-ACM specific commands: set/get_line_coding, set_control_line_state */
  * CDC-ACM specific commands: set/get_line_coding, set_control_line_state */
@@ -398,6 +411,29 @@ TEST_CASE("custom_command", "[cdc_acm]")
     vTaskDelay(20);
     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 */
 /* 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);
 void run_usb_dual_cdc_device(void);
 TEST_CASE("mock_device_app", "[cdc_acm_device][ignore]")
 TEST_CASE("mock_device_app", "[cdc_acm_device][ignore]")