فهرست منبع

Merge branch 'feature/msc_example_hotplug' into 'master'

MSC example made hot plugable

Closes IDFGH-6758

See merge request espressif/esp-idf!17813
Martin Válik 3 سال پیش
والد
کامیت
20fdf3bdf1
2فایلهای تغییر یافته به همراه89 افزوده شده و 49 حذف شده
  1. 4 1
      examples/peripherals/usb/host/msc/README.md
  2. 85 48
      examples/peripherals/usb/host/msc/main/msc_example_main.c

+ 4 - 1
examples/peripherals/usb/host/msc/README.md

@@ -6,7 +6,8 @@
 ## Overview
 
 This example demonstrates usage of Mass Storage Class to get access to storage on USB memory stick.
-Example caries out read and write file operations, as USB storage is mounted to Virtual filesystem.
+Upon connection of USB stick, storage is mounted to Virtual filesystem. Example then creates `ESP` subdirectory(if not present already), as well as `text.txt` file. Its content is then repetitively printed to monitor until USB stick is manually ejected. User can decide whether or not to deinitialize the whole 
+USB stack or not by shorting GPIO10 to ground. When GPIO10 is left unconnected USB stack is not deinitialized, USB stick can be plugged-in again. 
 
 ### Hardware Required
 
@@ -29,6 +30,8 @@ ESP BOARD    USB CONNECTOR (type A)
                    --
 ```
 
+Additionally, GPIO10 can be shorted to ground in order to deinitialize USB stack after ejecting USB stick. 
+
 ### Build and Flash
 
 Build the project and flash it to the board, then run monitor tool to view serial output:

+ 85 - 48
examples/peripherals/usb/host/msc/main/msc_example_main.c

@@ -1,17 +1,15 @@
 /*
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  *
- * SPDX-License-Identifier: Apache-2.0
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
  */
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-#include "freertos/queue.h"
-#include "freertos/semphr.h"
+#include "freertos/event_groups.h"
 #include "esp_err.h"
 #include "esp_log.h"
 #include "usb/usb_host.h"
@@ -22,20 +20,34 @@
 #include "esp_vfs.h"
 #include "errno.h"
 #include "hal/usb_hal.h"
+#include "driver/gpio.h"
+#include <esp_vfs_fat.h>
 
-static const char* TAG = "example";
+#define USB_DISCONNECT_PIN  GPIO_NUM_10
 
-static QueueHandle_t app_queue;
-static SemaphoreHandle_t ready_to_uninstall_usb;
+#define READY_TO_UNINSTALL (HOST_NO_CLIENT | HOST_ALL_FREE)
+
+typedef enum {
+    HOST_NO_CLIENT = 0x1,
+    HOST_ALL_FREE = 0x2,
+    DEVICE_CONNECTED = 0x4,
+    DEVICE_DISCONNECTED = 0x8,
+    DEVICE_ADDRESS_MASK = 0xFF0,
+} app_event_t;
+
+static const char *TAG = "example";
+static EventGroupHandle_t usb_flags;
 
 static void msc_event_cb(const msc_host_event_t *event, void *arg)
 {
     if (event->event == MSC_DEVICE_CONNECTED) {
         ESP_LOGI(TAG, "MSC device connected");
+        // Obtained USB device address is placed after application events
+        xEventGroupSetBits(usb_flags, DEVICE_CONNECTED | (event->device.address << 4));
     } else if (event->event == MSC_DEVICE_DISCONNECTED) {
+        xEventGroupSetBits(usb_flags, DEVICE_DISCONNECTED);
         ESP_LOGI(TAG, "MSC device disconnected");
     }
-    xQueueSend(app_queue, event, 10);
 }
 
 static void print_device_info(msc_host_device_info_t *info)
@@ -54,6 +66,12 @@ static void print_device_info(msc_host_device_info_t *info)
     wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber);
 }
 
+static bool file_exists(const char *file_path)
+{
+    struct stat buffer;
+    return stat(file_path, &buffer) == 0;
+}
+
 static void file_operations(void)
 {
     const char *directory = "/usb/esp";
@@ -67,15 +85,18 @@ static void file_operations(void)
         }
     }
 
-    ESP_LOGI(TAG, "Writing file");
-    FILE *f = fopen(file_path, "w");
-    if (f == NULL) {
-        ESP_LOGE(TAG, "Failed to open file for writing");
-        return;
+    if (!file_exists(file_path)) {
+        ESP_LOGI(TAG, "Creating file");
+        FILE *f = fopen(file_path, "w");
+        if (f == NULL) {
+            ESP_LOGE(TAG, "Failed to open file for writing");
+            return;
+        }
+        fprintf(f, "Hello World!\n");
+        fclose(f);
     }
-    fprintf(f, "Hello World!\n");
-    fclose(f);
 
+    FILE *f;
     ESP_LOGI(TAG, "Reading file");
     f = fopen(file_path, "r");
     if (f == NULL) {
@@ -99,15 +120,16 @@ static void handle_usb_events(void *args)
     while (1) {
         uint32_t 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) {
             usb_host_device_free_all();
+            xEventGroupSetBits(usb_flags, HOST_NO_CLIENT);
         }
         // 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) {
-            xSemaphoreGive(ready_to_uninstall_usb);
-            break;
+            xEventGroupSetBits(usb_flags, HOST_ALL_FREE);
         }
     }
 
@@ -116,29 +138,40 @@ static void handle_usb_events(void *args)
 
 static uint8_t wait_for_msc_device(void)
 {
-    msc_host_event_t app_event;
+    EventBits_t event;
+
     ESP_LOGI(TAG, "Waiting for USB stick to be connected");
-    xQueueReceive(app_queue, &app_event, portMAX_DELAY);
-    assert( app_event.event == MSC_DEVICE_CONNECTED );
-    return app_event.device.address;
+    event = xEventGroupWaitBits(usb_flags, DEVICE_CONNECTED | DEVICE_ADDRESS_MASK,
+                                pdTRUE, pdFALSE, portMAX_DELAY);
+    ESP_LOGI(TAG, "connection...");
+    // Extract USB device address from event group bits
+    return (event & DEVICE_ADDRESS_MASK) >> 4;
+}
+
+static bool wait_for_event(EventBits_t event, TickType_t timeout)
+{
+    return xEventGroupWaitBits(usb_flags, event, pdTRUE, pdTRUE, timeout) & event;
 }
 
 void app_main(void)
 {
     msc_host_device_handle_t msc_device;
+    msc_host_vfs_handle_t vfs_handle;
+    msc_host_device_info_t info;
     BaseType_t task_created;
 
-    ready_to_uninstall_usb = xSemaphoreCreateBinary();
+    const gpio_config_t input_pin = {
+        .pin_bit_mask = (1 << USB_DISCONNECT_PIN),
+        .mode = GPIO_MODE_INPUT,
+        .pull_up_en = GPIO_PULLUP_ENABLE,
+    };
+    ESP_ERROR_CHECK( gpio_config(&input_pin) );
 
-    app_queue = xQueueCreate(3, sizeof(msc_host_event_t));
-    assert(app_queue);
+    usb_flags = xEventGroupCreate();
+    assert(usb_flags);
 
-    const usb_host_config_t host_config = {
-        .skip_phy_setup = false,
-        .intr_flags = ESP_INTR_FLAG_LEVEL1,
-    };
+    const usb_host_config_t host_config = { .intr_flags = ESP_INTR_FLAG_LEVEL1 };
     ESP_ERROR_CHECK( usb_host_install(&host_config) );
-
     task_created = xTaskCreate(handle_usb_events, "usb_events", 2048, NULL, 2, NULL);
     assert(task_created);
 
@@ -150,33 +183,37 @@ void app_main(void)
     };
     ESP_ERROR_CHECK( msc_host_install(&msc_config) );
 
-    uint8_t device_address = wait_for_msc_device();
-
-    ESP_ERROR_CHECK( msc_host_install_device(device_address, &msc_device) );
-
-    msc_host_print_descriptors(msc_device);
-
-    msc_host_device_info_t info;
-    ESP_ERROR_CHECK( msc_host_get_device_info(msc_device, &info) );
-    print_device_info(&info);
-
-    msc_host_vfs_handle_t vfs_handle;
     const esp_vfs_fat_mount_config_t mount_config = {
         .format_if_mount_failed = false,
         .max_files = 3,
         .allocation_unit_size = 1024,
     };
 
-    ESP_ERROR_CHECK( msc_host_vfs_register(msc_device, "/usb", &mount_config, &vfs_handle) );
+    do {
+        uint8_t device_address = wait_for_msc_device();
 
-    file_operations();
+        ESP_ERROR_CHECK( msc_host_install_device(device_address, &msc_device) );
 
-    ESP_ERROR_CHECK( msc_host_vfs_unregister(vfs_handle) );
-    ESP_ERROR_CHECK( msc_host_uninstall_device(msc_device) );
-    ESP_ERROR_CHECK( msc_host_uninstall() );
+        msc_host_print_descriptors(msc_device);
 
-    xSemaphoreTake(ready_to_uninstall_usb, portMAX_DELAY);
-    ESP_ERROR_CHECK( usb_host_uninstall() );
+        ESP_ERROR_CHECK( msc_host_get_device_info(msc_device, &info) );
+        print_device_info(&info);
+
+        ESP_ERROR_CHECK( msc_host_vfs_register(msc_device, "/usb", &mount_config, &vfs_handle) );
+
+        while (!wait_for_event(DEVICE_DISCONNECTED, 200)) {
+            file_operations();
+        }
 
+        xEventGroupClearBits(usb_flags, READY_TO_UNINSTALL);
+        ESP_ERROR_CHECK( msc_host_vfs_unregister(vfs_handle) );
+        ESP_ERROR_CHECK( msc_host_uninstall_device(msc_device) );
+
+    } while (gpio_get_level(USB_DISCONNECT_PIN) != 0);
+
+    ESP_LOGI(TAG, "Uninitializing USB ...");
+    ESP_ERROR_CHECK( msc_host_uninstall() );
+    wait_for_event(READY_TO_UNINSTALL, portMAX_DELAY);
+    ESP_ERROR_CHECK( usb_host_uninstall() );
     ESP_LOGI(TAG, "Done");
 }