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

fix(usb/host): added hid_driver_uninstall call during APP_QUIT for HID Host example

Roman Leonov 2 жил өмнө
parent
commit
375907299e

+ 101 - 57
examples/peripherals/usb/host/hid/main/hid_host_example.c

@@ -26,19 +26,37 @@
 #define APP_QUIT_PIN                GPIO_NUM_0
 
 static const char *TAG = "example";
-QueueHandle_t hid_host_event_queue;
-bool user_shutdown = false;
+
+QueueHandle_t app_event_queue = NULL;
+
+/**
+ * @brief APP event group
+ *
+ * Application logic can be different. There is a one among other ways to distingiush the
+ * event by application event group.
+ * In this example we have two event groups:
+ * APP_EVENT            - General event, which is APP_QUIT_PIN press event (Generally, it is IO0).
+ * APP_EVENT_HID_HOST   - HID Host Driver event, such as device connection/disconnection or input report.
+ */
+typedef enum {
+    APP_EVENT = 0,
+    APP_EVENT_HID_HOST
+} app_event_group_t;
 
 /**
- * @brief HID Host event
+ * @brief APP event queue
  *
  * This event is used for delivering the HID Host event from callback to a task.
  */
 typedef struct {
-    hid_host_device_handle_t hid_device_handle;
-    hid_host_driver_event_t event;
-    void *arg;
-} hid_host_event_queue_t;
+    app_event_group_t event_group;
+    /* HID Host - Device related info */
+    struct {
+        hid_host_device_handle_t handle;
+        hid_host_driver_event_t event;
+        void *arg;
+    } hid_host_device;
+} app_event_queue_t;
 
 /**
  * @brief HID Protocol string names
@@ -437,13 +455,6 @@ void hid_host_device_event(hid_host_device_handle_t hid_device_handle,
  */
 static void usb_lib_task(void *arg)
 {
-    const gpio_config_t input_pin = {
-        .pin_bit_mask = BIT64(APP_QUIT_PIN),
-        .mode = GPIO_MODE_INPUT,
-        .pull_up_en = GPIO_PULLUP_ENABLE,
-    };
-    ESP_ERROR_CHECK(gpio_config(&input_pin));
-
     const usb_host_config_t host_config = {
         .skip_phy_setup = false,
         .intr_flags = ESP_INTR_FLAG_LEVEL1,
@@ -452,22 +463,17 @@ static void usb_lib_task(void *arg)
     ESP_ERROR_CHECK(usb_host_install(&host_config));
     xTaskNotifyGive(arg);
 
-    while (gpio_get_level(APP_QUIT_PIN) != 0) {
+    while (true) {
         uint32_t event_flags;
         usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
-
-        // Release devices once all clients has deregistered
+        // In this example, there is only one client registered
+        // So, once we deregister the client, this call must succeed with ESP_OK
         if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
-            usb_host_device_free_all();
-            ESP_LOGI(TAG, "USB Event flags: NO_CLIENTS");
-        }
-        // All devices were removed
-        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
-            ESP_LOGI(TAG, "USB Event flags: ALL_FREE");
+            ESP_ERROR_CHECK(usb_host_device_free_all());
+            break;
         }
     }
-    // App Button was pressed, trigger the flag
-    user_shutdown = true;
+
     ESP_LOGI(TAG, "USB shutdown");
     // Clean up USB Host
     vTaskDelay(10); // Short delay to allow clients clean-up
@@ -476,30 +482,26 @@ static void usb_lib_task(void *arg)
 }
 
 /**
- * @brief HID Host main task
+ * @brief BOOT button pressed callback
  *
- * Creates queue and get new event from the queue
+ * Signal application to exit the HID Host task
  *
- * @param[in] pvParameters Not used
+ * @param[in] arg Unused
  */
-void hid_host_task(void *pvParameters)
+static void gpio_isr_cb(void *arg)
 {
-    hid_host_event_queue_t evt_queue;
-    // Create queue
-    hid_host_event_queue = xQueueCreate(10, sizeof(hid_host_event_queue_t));
-
-    // Wait queue
-    while (!user_shutdown) {
-        if (xQueueReceive(hid_host_event_queue, &evt_queue, pdMS_TO_TICKS(50))) {
-            hid_host_device_event(evt_queue.hid_device_handle,
-                                  evt_queue.event,
-                                  evt_queue.arg);
-        }
+    BaseType_t xTaskWoken = pdFALSE;
+    const app_event_queue_t evt_queue = {
+        .event_group = APP_EVENT,
+    };
+
+    if (app_event_queue) {
+        xQueueSendFromISR(app_event_queue, &evt_queue, &xTaskWoken);
     }
 
-    xQueueReset(hid_host_event_queue);
-    vQueueDelete(hid_host_event_queue);
-    vTaskDelete(NULL);
+    if (xTaskWoken == pdTRUE) {
+        portYIELD_FROM_ISR();
+    }
 }
 
 /**
@@ -515,19 +517,37 @@ void hid_host_device_callback(hid_host_device_handle_t hid_device_handle,
                               const hid_host_driver_event_t event,
                               void *arg)
 {
-    const hid_host_event_queue_t evt_queue = {
-        .hid_device_handle = hid_device_handle,
-        .event = event,
-        .arg = arg
+    const app_event_queue_t evt_queue = {
+        .event_group = APP_EVENT_HID_HOST,
+        // HID Host Device related info
+        .hid_host_device.handle = hid_device_handle,
+        .hid_host_device.event = event,
+        .hid_host_device.arg = arg
     };
-    xQueueSend(hid_host_event_queue, &evt_queue, 0);
+
+    if (app_event_queue) {
+        xQueueSend(app_event_queue, &evt_queue, 0);
+    }
 }
 
 void app_main(void)
 {
     BaseType_t task_created;
+    app_event_queue_t evt_queue;
     ESP_LOGI(TAG, "HID Host example");
 
+    // Init BOOT button: Pressing the button simulates app request to exit
+    // It will disconnect the USB device and uninstall the HID driver and USB Host Lib
+    const gpio_config_t input_pin = {
+        .pin_bit_mask = BIT64(APP_QUIT_PIN),
+        .mode = GPIO_MODE_INPUT,
+        .pull_up_en = GPIO_PULLUP_ENABLE,
+        .intr_type = GPIO_INTR_NEGEDGE,
+    };
+    ESP_ERROR_CHECK(gpio_config(&input_pin));
+    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1));
+    ESP_ERROR_CHECK(gpio_isr_handler_add(APP_QUIT_PIN, gpio_isr_cb, NULL));
+
     /*
     * Create usb_lib_task to:
     * - initialize USB Host library
@@ -559,14 +579,38 @@ void app_main(void)
 
     ESP_ERROR_CHECK(hid_host_install(&hid_host_driver_config));
 
-    // Task is working until the devices are gone (while 'user_shutdown' if false)
-    user_shutdown = false;
+    // Create queue
+    app_event_queue = xQueueCreate(10, sizeof(app_event_queue_t));
+
+    ESP_LOGI(TAG, "Waiting for HID Device to be connected");
+
+    while (1) {
+        // Wait queue
+        if (xQueueReceive(app_event_queue, &evt_queue, portMAX_DELAY)) {
+            if (APP_EVENT == evt_queue.event_group) {
+                // User pressed button
+                usb_host_lib_info_t lib_info;
+                ESP_ERROR_CHECK(usb_host_lib_info(&lib_info));
+                if (lib_info.num_devices == 0) {
+                    // End while cycle
+                    break;
+                } else {
+                    ESP_LOGW(TAG, "To shutdown example, remove all USB devices and press button again.");
+                    // Keep polling
+                }
+            }
 
-    /*
-    * Create HID Host task process for handle events
-    * IMPORTANT: Task is necessary here while there is no possibility to interact
-    * with USB device from the callback.
-    */
-    task_created = xTaskCreate(&hid_host_task, "hid_task", 4 * 1024, NULL, 2, NULL);
-    assert(task_created == pdTRUE);
+            if (APP_EVENT_HID_HOST ==  evt_queue.event_group) {
+                hid_host_device_event(evt_queue.hid_host_device.handle,
+                                      evt_queue.hid_host_device.event,
+                                      evt_queue.hid_host_device.arg);
+            }
+        }
+    }
+
+    ESP_LOGI(TAG, "HID Driver uninstall");
+    ESP_ERROR_CHECK(hid_host_uninstall());
+    gpio_isr_handler_remove(APP_QUIT_PIN);
+    xQueueReset(app_event_queue);
+    vQueueDelete(app_event_queue);
 }

+ 1 - 1
examples/peripherals/usb/host/hid/main/idf_component.yml

@@ -1,4 +1,4 @@
 ## IDF Component Manager Manifest File
 dependencies:
   idf: ">=4.4"
-  usb_host_hid: "1.0.0"
+  usb_host_hid: "^1.0.1"