|
|
@@ -0,0 +1,188 @@
|
|
|
+/*
|
|
|
+ * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
|
|
+ *
|
|
|
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdlib.h>
|
|
|
+#include "freertos/FreeRTOS.h"
|
|
|
+#include "freertos/semphr.h"
|
|
|
+#include "esp_log.h"
|
|
|
+#include "usb/usb_host.h"
|
|
|
+
|
|
|
+#define CLIENT_NUM_EVENT_MSG 5
|
|
|
+
|
|
|
+#define ACTION_OPEN_DEV 0x01
|
|
|
+#define ACTION_GET_DEV_INFO 0x02
|
|
|
+#define ACTION_GET_DEV_DESC 0x04
|
|
|
+#define ACTION_GET_CONFIG_DESC 0x08
|
|
|
+#define ACTION_GET_STR_DESC 0x10
|
|
|
+#define ACTION_CLOSE_DEV 0x20
|
|
|
+#define ACTION_EXIT 0x40
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ usb_host_client_handle_t client_hdl;
|
|
|
+ uint8_t dev_addr;
|
|
|
+ usb_device_handle_t dev_hdl;
|
|
|
+ uint32_t actions;
|
|
|
+} class_driver_t;
|
|
|
+
|
|
|
+static const char *TAG = "CLASS";
|
|
|
+
|
|
|
+static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
|
|
|
+{
|
|
|
+ class_driver_t *driver_obj = (class_driver_t *)arg;
|
|
|
+ switch (event_msg->event) {
|
|
|
+ case USB_HOST_CLIENT_EVENT_NEW_DEV:
|
|
|
+ if (driver_obj->dev_addr == 0) {
|
|
|
+ driver_obj->dev_addr = event_msg->new_dev.address;
|
|
|
+ //Open the device next
|
|
|
+ driver_obj->actions |= ACTION_OPEN_DEV;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case USB_HOST_CLIENT_EVENT_DEV_GONE:
|
|
|
+ if (driver_obj->dev_hdl != NULL) {
|
|
|
+ //Cancel any other actions and close the device next
|
|
|
+ driver_obj->actions = ACTION_CLOSE_DEV;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ //Should never occur
|
|
|
+ abort();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void action_open_dev(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ assert(driver_obj->dev_addr != 0);
|
|
|
+ ESP_LOGI(TAG, "Opening device at address %d", driver_obj->dev_addr);
|
|
|
+ ESP_ERROR_CHECK(usb_host_device_open(driver_obj->client_hdl, driver_obj->dev_addr, &driver_obj->dev_hdl));
|
|
|
+ //Get the device's information next
|
|
|
+ driver_obj->actions &= ~ACTION_OPEN_DEV;
|
|
|
+ driver_obj->actions |= ACTION_GET_DEV_INFO;
|
|
|
+}
|
|
|
+
|
|
|
+static void action_get_info(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ assert(driver_obj->dev_hdl != NULL);
|
|
|
+ ESP_LOGI(TAG, "Getting device information");
|
|
|
+ usb_device_info_t dev_info;
|
|
|
+ ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
|
|
|
+ ESP_LOGI(TAG, "\t%s speed", (dev_info.speed == USB_SPEED_LOW) ? "Low" : "Full");
|
|
|
+ ESP_LOGI(TAG, "\tbConfigurationValue %d", dev_info.bConfigurationValue);
|
|
|
+ //Todo: Print string descriptors
|
|
|
+
|
|
|
+ //Get the device descriptor next
|
|
|
+ driver_obj->actions &= ~ACTION_GET_DEV_INFO;
|
|
|
+ driver_obj->actions |= ACTION_GET_DEV_DESC;
|
|
|
+}
|
|
|
+
|
|
|
+static void action_get_dev_desc(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ assert(driver_obj->dev_hdl != NULL);
|
|
|
+ ESP_LOGI(TAG, "Getting device descriptor");
|
|
|
+ const usb_device_desc_t *dev_desc;
|
|
|
+ ESP_ERROR_CHECK(usb_host_get_device_descriptor(driver_obj->dev_hdl, &dev_desc));
|
|
|
+ usb_print_device_descriptor(dev_desc);
|
|
|
+ //Get the device's config descriptor next
|
|
|
+ driver_obj->actions &= ~ACTION_GET_DEV_DESC;
|
|
|
+ driver_obj->actions |= ACTION_GET_CONFIG_DESC;
|
|
|
+}
|
|
|
+
|
|
|
+static void action_get_config_desc(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ assert(driver_obj->dev_hdl != NULL);
|
|
|
+ ESP_LOGI(TAG, "Getting config descriptor");
|
|
|
+ const usb_config_desc_t *config_desc;
|
|
|
+ ESP_ERROR_CHECK(usb_host_get_active_config_descriptor(driver_obj->dev_hdl, &config_desc));
|
|
|
+ usb_print_config_descriptor(config_desc, NULL);
|
|
|
+ //Get the device's string descriptors next
|
|
|
+ driver_obj->actions &= ~ACTION_GET_CONFIG_DESC;
|
|
|
+ driver_obj->actions |= ACTION_GET_STR_DESC;
|
|
|
+}
|
|
|
+
|
|
|
+static void action_get_str_desc(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ assert(driver_obj->dev_hdl != NULL);
|
|
|
+ usb_device_info_t dev_info;
|
|
|
+ ESP_ERROR_CHECK(usb_host_device_info(driver_obj->dev_hdl, &dev_info));
|
|
|
+ if (dev_info.str_desc_manufacturer) {
|
|
|
+ ESP_LOGI(TAG, "Getting Manufacturer string descriptor");
|
|
|
+ usb_print_string_descriptor(dev_info.str_desc_manufacturer);
|
|
|
+ }
|
|
|
+ if (dev_info.str_desc_product) {
|
|
|
+ ESP_LOGI(TAG, "Getting Product string descriptor");
|
|
|
+ usb_print_string_descriptor(dev_info.str_desc_product);
|
|
|
+ }
|
|
|
+ if (dev_info.str_desc_serial_num) {
|
|
|
+ ESP_LOGI(TAG, "Getting Serial Number string descriptor");
|
|
|
+ usb_print_string_descriptor(dev_info.str_desc_serial_num);
|
|
|
+ }
|
|
|
+ //Nothing to do until the device disconnects
|
|
|
+ driver_obj->actions &= ~ACTION_GET_STR_DESC;
|
|
|
+}
|
|
|
+
|
|
|
+static void aciton_close_dev(class_driver_t *driver_obj)
|
|
|
+{
|
|
|
+ ESP_ERROR_CHECK(usb_host_device_close(driver_obj->client_hdl, driver_obj->dev_hdl));
|
|
|
+ driver_obj->dev_hdl = NULL;
|
|
|
+ driver_obj->dev_addr = 0;
|
|
|
+ //We need to exit the event handler loop
|
|
|
+ driver_obj->actions &= ~ACTION_CLOSE_DEV;
|
|
|
+ driver_obj->actions |= ACTION_EXIT;
|
|
|
+}
|
|
|
+
|
|
|
+void class_driver_task(void *arg)
|
|
|
+{
|
|
|
+ SemaphoreHandle_t signaling_sem = (SemaphoreHandle_t)arg;
|
|
|
+ class_driver_t driver_obj = {0};
|
|
|
+
|
|
|
+ //Wait until daemon task has installed USB Host Library
|
|
|
+ xSemaphoreTake(signaling_sem, portMAX_DELAY);
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Registering Client");
|
|
|
+ usb_host_client_config_t client_config = {
|
|
|
+ .is_synchronous = false, //Synchronous clients currently not supported. Set this to false
|
|
|
+ .max_num_event_msg = CLIENT_NUM_EVENT_MSG,
|
|
|
+ .async = {
|
|
|
+ .client_event_callback = client_event_cb,
|
|
|
+ .callback_arg = (void *)&driver_obj,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ ESP_ERROR_CHECK(usb_host_client_register(&client_config, &driver_obj.client_hdl));
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ if (driver_obj.actions == 0) {
|
|
|
+ usb_host_client_handle_events(driver_obj.client_hdl, portMAX_DELAY);
|
|
|
+ } else {
|
|
|
+ if (driver_obj.actions & ACTION_OPEN_DEV) {
|
|
|
+ action_open_dev(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_GET_DEV_INFO) {
|
|
|
+ action_get_info(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_GET_DEV_DESC) {
|
|
|
+ action_get_dev_desc(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_GET_CONFIG_DESC) {
|
|
|
+ action_get_config_desc(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_GET_STR_DESC) {
|
|
|
+ action_get_str_desc(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_CLOSE_DEV) {
|
|
|
+ aciton_close_dev(&driver_obj);
|
|
|
+ }
|
|
|
+ if (driver_obj.actions & ACTION_EXIT) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Deregistering Client");
|
|
|
+ ESP_ERROR_CHECK(usb_host_client_deregister(driver_obj.client_hdl));
|
|
|
+
|
|
|
+ //Wait to be deleted
|
|
|
+ xSemaphoreGive(signaling_sem);
|
|
|
+ vTaskSuspend(NULL);
|
|
|
+}
|