msc_example_main.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <assert.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/task.h"
  11. #include "freertos/event_groups.h"
  12. #include "esp_err.h"
  13. #include "esp_log.h"
  14. #include "usb/usb_host.h"
  15. #include "msc_host.h"
  16. #include "msc_host_vfs.h"
  17. #include "ffconf.h"
  18. #include "ff.h"
  19. #include "esp_vfs.h"
  20. #include "errno.h"
  21. #include "hal/usb_hal.h"
  22. #include "driver/gpio.h"
  23. #include <esp_vfs_fat.h>
  24. #define USB_DISCONNECT_PIN GPIO_NUM_10
  25. #define READY_TO_UNINSTALL (HOST_NO_CLIENT | HOST_ALL_FREE)
  26. typedef enum {
  27. HOST_NO_CLIENT = 0x1,
  28. HOST_ALL_FREE = 0x2,
  29. DEVICE_CONNECTED = 0x4,
  30. DEVICE_DISCONNECTED = 0x8,
  31. DEVICE_ADDRESS_MASK = 0xFF0,
  32. } app_event_t;
  33. static const char *TAG = "example";
  34. static EventGroupHandle_t usb_flags;
  35. static void msc_event_cb(const msc_host_event_t *event, void *arg)
  36. {
  37. if (event->event == MSC_DEVICE_CONNECTED) {
  38. ESP_LOGI(TAG, "MSC device connected");
  39. // Obtained USB device address is placed after application events
  40. xEventGroupSetBits(usb_flags, DEVICE_CONNECTED | (event->device.address << 4));
  41. } else if (event->event == MSC_DEVICE_DISCONNECTED) {
  42. xEventGroupSetBits(usb_flags, DEVICE_DISCONNECTED);
  43. ESP_LOGI(TAG, "MSC device disconnected");
  44. }
  45. }
  46. static void print_device_info(msc_host_device_info_t *info)
  47. {
  48. const size_t megabyte = 1024 * 1024;
  49. uint64_t capacity = ((uint64_t)info->sector_size * info->sector_count) / megabyte;
  50. printf("Device info:\n");
  51. printf("\t Capacity: %llu MB\n", capacity);
  52. printf("\t Sector size: %u\n", info->sector_size);
  53. printf("\t Sector count: %u\n", info->sector_count);
  54. printf("\t PID: 0x%4X \n", info->idProduct);
  55. printf("\t VID: 0x%4X \n", info->idVendor);
  56. wprintf(L"\t iProduct: %S \n", info->iProduct);
  57. wprintf(L"\t iManufacturer: %S \n", info->iManufacturer);
  58. wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber);
  59. }
  60. static bool file_exists(const char *file_path)
  61. {
  62. struct stat buffer;
  63. return stat(file_path, &buffer) == 0;
  64. }
  65. static void file_operations(void)
  66. {
  67. const char *directory = "/usb/esp";
  68. const char *file_path = "/usb/esp/test.txt";
  69. struct stat s = {0};
  70. bool directory_exists = stat(directory, &s) == 0;
  71. if (!directory_exists) {
  72. if (mkdir(directory, 0775) != 0) {
  73. ESP_LOGE(TAG, "mkdir failed with errno: %s\n", strerror(errno));
  74. }
  75. }
  76. if (!file_exists(file_path)) {
  77. ESP_LOGI(TAG, "Creating file");
  78. FILE *f = fopen(file_path, "w");
  79. if (f == NULL) {
  80. ESP_LOGE(TAG, "Failed to open file for writing");
  81. return;
  82. }
  83. fprintf(f, "Hello World!\n");
  84. fclose(f);
  85. }
  86. FILE *f;
  87. ESP_LOGI(TAG, "Reading file");
  88. f = fopen(file_path, "r");
  89. if (f == NULL) {
  90. ESP_LOGE(TAG, "Failed to open file for reading");
  91. return;
  92. }
  93. char line[64];
  94. fgets(line, sizeof(line), f);
  95. fclose(f);
  96. // strip newline
  97. char *pos = strchr(line, '\n');
  98. if (pos) {
  99. *pos = '\0';
  100. }
  101. ESP_LOGI(TAG, "Read from file: '%s'", line);
  102. }
  103. // Handles common USB host library events
  104. static void handle_usb_events(void *args)
  105. {
  106. while (1) {
  107. uint32_t event_flags;
  108. usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
  109. // Release devices once all clients has deregistered
  110. if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
  111. usb_host_device_free_all();
  112. xEventGroupSetBits(usb_flags, HOST_NO_CLIENT);
  113. }
  114. // Give ready_to_uninstall_usb semaphore to indicate that USB Host library
  115. // can be deinitialized, and terminate this task.
  116. if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
  117. xEventGroupSetBits(usb_flags, HOST_ALL_FREE);
  118. }
  119. }
  120. vTaskDelete(NULL);
  121. }
  122. static uint8_t wait_for_msc_device(void)
  123. {
  124. EventBits_t event;
  125. ESP_LOGI(TAG, "Waiting for USB stick to be connected");
  126. event = xEventGroupWaitBits(usb_flags, DEVICE_CONNECTED | DEVICE_ADDRESS_MASK,
  127. pdTRUE, pdFALSE, portMAX_DELAY);
  128. ESP_LOGI(TAG, "connection...");
  129. // Extract USB device address from event group bits
  130. return (event & DEVICE_ADDRESS_MASK) >> 4;
  131. }
  132. static bool wait_for_event(EventBits_t event, TickType_t timeout)
  133. {
  134. return xEventGroupWaitBits(usb_flags, event, pdTRUE, pdTRUE, timeout) & event;
  135. }
  136. void app_main(void)
  137. {
  138. msc_host_device_handle_t msc_device;
  139. msc_host_vfs_handle_t vfs_handle;
  140. msc_host_device_info_t info;
  141. BaseType_t task_created;
  142. const gpio_config_t input_pin = {
  143. .pin_bit_mask = (1 << USB_DISCONNECT_PIN),
  144. .mode = GPIO_MODE_INPUT,
  145. .pull_up_en = GPIO_PULLUP_ENABLE,
  146. };
  147. ESP_ERROR_CHECK( gpio_config(&input_pin) );
  148. usb_flags = xEventGroupCreate();
  149. assert(usb_flags);
  150. const usb_host_config_t host_config = { .intr_flags = ESP_INTR_FLAG_LEVEL1 };
  151. ESP_ERROR_CHECK( usb_host_install(&host_config) );
  152. task_created = xTaskCreate(handle_usb_events, "usb_events", 2048, NULL, 2, NULL);
  153. assert(task_created);
  154. const msc_host_driver_config_t msc_config = {
  155. .create_backround_task = true,
  156. .task_priority = 5,
  157. .stack_size = 2048,
  158. .callback = msc_event_cb,
  159. };
  160. ESP_ERROR_CHECK( msc_host_install(&msc_config) );
  161. const esp_vfs_fat_mount_config_t mount_config = {
  162. .format_if_mount_failed = false,
  163. .max_files = 3,
  164. .allocation_unit_size = 1024,
  165. };
  166. do {
  167. uint8_t device_address = wait_for_msc_device();
  168. ESP_ERROR_CHECK( msc_host_install_device(device_address, &msc_device) );
  169. msc_host_print_descriptors(msc_device);
  170. ESP_ERROR_CHECK( msc_host_get_device_info(msc_device, &info) );
  171. print_device_info(&info);
  172. ESP_ERROR_CHECK( msc_host_vfs_register(msc_device, "/usb", &mount_config, &vfs_handle) );
  173. while (!wait_for_event(DEVICE_DISCONNECTED, 200)) {
  174. file_operations();
  175. }
  176. xEventGroupClearBits(usb_flags, READY_TO_UNINSTALL);
  177. ESP_ERROR_CHECK( msc_host_vfs_unregister(vfs_handle) );
  178. ESP_ERROR_CHECK( msc_host_uninstall_device(msc_device) );
  179. } while (gpio_get_level(USB_DISCONNECT_PIN) != 0);
  180. ESP_LOGI(TAG, "Uninitializing USB ...");
  181. ESP_ERROR_CHECK( msc_host_uninstall() );
  182. wait_for_event(READY_TO_UNINSTALL, portMAX_DELAY);
  183. ESP_ERROR_CHECK( usb_host_uninstall() );
  184. ESP_LOGI(TAG, "Done");
  185. }