diff --git a/examples/peripherals/usb/host/hid/components/hid/CMakeLists.txt b/examples/peripherals/usb/host/hid/components/hid/CMakeLists.txt deleted file mode 100644 index 1819d1439f..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "hid_host.c" - PRIV_REQUIRES usb - INCLUDE_DIRS "include") diff --git a/examples/peripherals/usb/host/hid/components/hid/hid_host.c b/examples/peripherals/usb/host/hid/components/hid/hid_host.c deleted file mode 100644 index 5d3dbb8db1..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/hid_host.c +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include "esp_log.h" -#include "esp_check.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "usb/usb_host.h" - -#include "hid_host.h" - -// HID spinlock -static portMUX_TYPE hid_lock = portMUX_INITIALIZER_UNLOCKED; -#define HID_ENTER_CRITICAL() portENTER_CRITICAL(&hid_lock) -#define HID_EXIT_CRITICAL() portEXIT_CRITICAL(&hid_lock) - -// HID verification macroses -#define HID_GOTO_ON_FALSE_CRITICAL(exp, err) \ - do { \ - if(!(exp)) { \ - HID_EXIT_CRITICAL(); \ - ret = err; \ - goto fail; \ - } \ - } while(0) - -#define HID_RETURN_ON_FALSE_CRITICAL(exp, err) \ - do { \ - if(!(exp)) { \ - HID_EXIT_CRITICAL(); \ - return err; \ - } \ - } while(0) - -#define HID_GOTO_ON_ERROR(exp) ESP_GOTO_ON_ERROR(exp, fail, TAG, "") - -#define HID_GOTO_ON_FALSE(exp, err) ESP_GOTO_ON_FALSE( (exp), err, fail, TAG, "" ) - -#define HID_RETURN_ON_ERROR(exp) ESP_RETURN_ON_ERROR((exp), TAG, "") - -#define HID_RETURN_ON_FALSE(exp, err) ESP_RETURN_ON_FALSE( (exp), (err), TAG, "") - -#define HID_RETURN_ON_INVALID_ARG(exp) ESP_RETURN_ON_FALSE((exp) != NULL, ESP_ERR_INVALID_ARG, TAG, "") - -static const char *TAG = "hid-host"; - -/** - * @brief HID Interface structure in device to interact with. After HID device opening keeps the interface configuration - * - */ -typedef struct hid_interface { - STAILQ_ENTRY(hid_interface) tailq_entry; - uint8_t dev_addr; /**< USB device address */ - hid_protocol_t proto; /**< HID Interface protocol */ - hid_host_device_handle_t dev; /**< Parent USB HID device */ - uint8_t num; /**< Interface number */ - uint8_t ep; /**< Interrupt IN EP number */ - uint16_t ep_mps; /**< Interrupt IN max size */ - uint8_t country_code; /**< Country code */ - uint16_t report_size; /**< Size of Report */ - uint8_t *report; /**< Pointer to HID Report */ - usb_transfer_t *in_xfer; /**< Pointer to IN transfer buffer */ - hid_input_report_cb_t report_cb; /**< Input report callback */ - hid_host_interface_event_cb_t user_cb; /**< Interface application callback */ - void *user_cb_arg; /**< Interface application callback arg */ - bool ready; /**< Interface ready for claiming */ -} hid_iface_t; - -/** - * @brief HID Device structure. - * - */ -typedef struct hid_host_device { - STAILQ_ENTRY(hid_host_device) tailq_entry; /**< HID device queue */ - SemaphoreHandle_t device_busy; /**< HID device main mutex */ - SemaphoreHandle_t ctrl_xfer_done; /**< Control transfer semaphore */ - usb_transfer_t *ctrl_xfer; /**< Pointer to control transfer buffer */ - usb_device_handle_t dev_hdl; /**< USB device handle */ -} hid_device_t; - -/** - * @brief HID driver default context - * - * This context is created during HID Host install. - */ -typedef struct { - usb_host_client_handle_t client_handle; /**< Client task handle */ - hid_host_event_cb_t user_cb; /**< User application callback */ - void *user_arg; /**< User application callback args */ - SemaphoreHandle_t all_events_handled; /**< Events handler semaphore */ - volatile bool end_client_event_handling; /**< Client event handling flag */ -} hid_driver_t; - -static hid_driver_t *s_hid_driver; /**< Internal pointer to HID driver */ - -STAILQ_HEAD(devices, hid_host_device) devices_tailq; -STAILQ_HEAD(interfaces, hid_interface) ifaces_tailq; - -// ----------------------- Private ------------------------- - -/** - * @brief Get Next Interface descriptor - * - * @param[in] desc Pointer to Descriptor buffer (usually starts from Configuration descriptor) - * @param[in] len Total length - * @param[in] offset Pointer to offset descriptor buffer - * @return const usb_standard_desc_t* Pointer to Interface descriptor - */ -static inline const usb_standard_desc_t *next_interface_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset) -{ - return usb_parse_next_descriptor_of_type(desc, len, USB_W_VALUE_DT_INTERFACE, (int *)offset); -} - -/** - * @brief Get Next HID descriptor - * - * @param[in] desc Pointer to the Descriptor buffer - * @param[in] len Total length - * @param[in] offset Pointer to offset in descriptor buffer - * @return const usb_standard_desc_t* Pointer to HID descriptor - */ -static inline const usb_standard_desc_t *next_hid_descriptor(const usb_standard_desc_t *desc, size_t len, size_t *offset) -{ - return usb_parse_next_descriptor_of_type(desc, len, HID_CLASS_DESCRIPTOR_TYPE_HID, (int *)offset); -} - -/** - * @brief Get Next Endpoint descriptor - * - * @param[in] desc Pointer to Descriptor buffer - * @param[in] len Total length - * @param[in] offset Pointer to offset in descriptor buffer - * @return const usb_standard_desc_t* Pointer to Endpoint descriptor - */ -static inline const usb_standard_desc_t *next_endpoint_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset) -{ - return usb_parse_next_descriptor_of_type(desc, len, USB_B_DESCRIPTOR_TYPE_ENDPOINT, (int *)offset); -} - -/** - * @brief USB Event handler - * - * Handle all USB related events such as USB host (usbh) events or hub events from USB hardware - * - * @param[in] arg Argument, does not used - */ -static void event_handler_task(void *arg) -{ - while (1) { - /* Here wee need a timeout 50 ms to handle end_client_event_handling flag - * during situation when all devices were removed and it is time to remove - * and destroy everything. - */ - usb_host_client_handle_events(s_hid_driver->client_handle, pdMS_TO_TICKS(50)); - - if (s_hid_driver->end_client_event_handling) { - break; - } - } - usb_host_client_unblock(s_hid_driver->client_handle); - ESP_ERROR_CHECK( usb_host_client_deregister(s_hid_driver->client_handle) ); - xSemaphoreGive(s_hid_driver->all_events_handled); - vTaskDelete(NULL); -} - -/** - * @brief Return HID device in devices list by USB device handle - * - * @param[in] usb_device_handle_t USB device handle - * @return hid_device_t Pointer to device, NULL if device not present - */ -static hid_device_t *get_hid_device_by_handle(usb_device_handle_t usb_handle) -{ - hid_host_device_handle_t device = NULL; - - HID_ENTER_CRITICAL(); - STAILQ_FOREACH(device, &devices_tailq, tailq_entry) { - if (usb_handle == device->dev_hdl) { - HID_EXIT_CRITICAL(); - return device; - } - } - HID_EXIT_CRITICAL(); - return NULL; -} - -/** - * @brief Get HID Interface pointer by Endpoint address - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] ep_addr Endpoint address - * @return hid_iface_t Pointer to HID Interface configuration structure - */ -static hid_iface_t *get_interface_by_ep(hid_device_t *hid_device, uint8_t ep_addr) -{ - hid_iface_t *interface = NULL; - - HID_ENTER_CRITICAL(); - STAILQ_FOREACH(interface, &ifaces_tailq, tailq_entry) { - if (ep_addr == interface->ep) { - HID_EXIT_CRITICAL(); - return interface; - } - } - - HID_EXIT_CRITICAL(); - return NULL; -} - -/** - * @brief Get Interface structure from the RAM list - * - * @param[in] proto HID Protocol - * @return hid_iface_t Pointer to an interface structure - */ -static hid_iface_t *get_interface_by_proto(hid_protocol_t proto) -{ - hid_iface_t *interface = NULL; - - HID_ENTER_CRITICAL(); - STAILQ_FOREACH(interface, &ifaces_tailq, tailq_entry) { - if (proto == interface->proto) { - HID_EXIT_CRITICAL(); - return interface; - } - } - - HID_EXIT_CRITICAL(); - return NULL; -} - -/** - * @brief Verify claim/release status of the particular interface - * - * @param[in] proto HID Interface protocol - * @return true Interface is claimed by application logic - * @return false Interface is released - */ -static bool is_interface_claimed(hid_protocol_t proto) -{ - hid_iface_t *interface = get_interface_by_proto(proto); - - if (interface) { - return (interface->report_cb != NULL); - } - - return false; -} - -/** - * @brief Get Interface Descriptor - * - * @param[in] config_desc Pointer to Configuration Descriptor - * @param[in] offset Offset - * @param[in] proto Interface Protocol field to search, or set to `HID_PROTOCOL_NONE` to ignore - * @return esp_err_t - */ -static const usb_intf_desc_t *get_interface_desc_by_proto(const usb_config_desc_t *config_desc, - size_t *offset, - hid_protocol_t proto) -{ - size_t total_length = config_desc->wTotalLength; - const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)config_desc; - - next_desc = next_interface_desc(next_desc, total_length, offset); - - while ( next_desc ) { - - const usb_intf_desc_t *ifc_desc = (const usb_intf_desc_t *)next_desc; - - if ( ifc_desc->bInterfaceClass == USB_CLASS_HID && - ifc_desc->bInterfaceSubClass == HID_SUBCLASS_BOOT_INTERFACE) { - - if (proto != HID_PROTOCOL_NONE) { - if (ifc_desc->bInterfaceProtocol == proto) { - return ifc_desc; - } - } else { - return ifc_desc; - } - - } - - next_desc = next_interface_desc(next_desc, total_length, offset); - }; - return NULL; -} - -/** - * @brief Interface user callback function. - * - * @param[in] iface Pointer to Interface structure - * @param[in] event HID Interface event - */ -static void interface_user_callback(hid_iface_t *iface, hid_interface_event_t event) -{ - if (!iface->user_cb) { - return; - } - - const hid_host_interface_event_t iface_event = { - .event = event, - .interface.dev_addr = iface->dev_addr, - .interface.num = iface->num, - .interface.proto = iface->proto - }; - - iface->user_cb(&iface_event, iface->user_cb_arg); -} - -/** - * @brief Add interface in a list - * - * @param[in] dev_config Pointer to device config structure - * @param[in] hid_device Pointer to HID device structure - * @param[in] iface_desc Pointer to an Interface descriptor - * @param[in] hid_desc Pointer to an HID device descriptor - * @param[in] ep_desc Pointer to an EP descriptor - * @return esp_err_t - */ -static esp_err_t add_interface_to_list(const hid_host_device_config_t *dev_config, - hid_device_t *hid_device, - const usb_intf_desc_t *iface_desc, - const hid_descriptor_t *hid_desc, - const usb_ep_desc_t *ep_desc) -{ - hid_iface_t *iface = calloc(1, sizeof(hid_iface_t)); - - HID_RETURN_ON_FALSE(iface, ESP_ERR_NO_MEM); - - iface->dev_addr = dev_config->dev_addr; - - if (iface_desc) { - iface->proto = iface_desc->bInterfaceProtocol; - iface->num = iface_desc->bInterfaceNumber; - } - - if (hid_desc) { - iface->country_code = hid_desc->bCountryCode; - iface->report_size = hid_desc->wReportDescriptorLength; - } - - // EP IN && INT Type - if (ep_desc) { - if ( (ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) && - (ep_desc->bmAttributes & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) ) { - iface->ep = ep_desc->bEndpointAddress; - iface->ep_mps = USB_EP_DESC_GET_MPS(ep_desc); - } else { - ESP_LOGE(TAG, "HID device does not have INT EP"); - } - } - - if (iface_desc && hid_desc && ep_desc) { - iface->dev = hid_device; - iface->ready = true; - } - - iface->user_cb = dev_config->iface_event_cb; - iface->user_cb_arg = dev_config->iface_event_arg; - - HID_ENTER_CRITICAL(); - STAILQ_INSERT_TAIL(&ifaces_tailq, iface, tailq_entry); - HID_EXIT_CRITICAL(); - - interface_user_callback(iface, HID_DEVICE_INTERFACE_INIT); - - return ESP_OK; -} - -/** - * @brief Search HID class descriptor in USB device - * - * @param[in] dev_addr USB device physical address - * @return true USB device contain HID Interface - * @return false USB does not contain HID Interface - */ -static bool is_hid_device(uint8_t dev_addr) -{ - bool is_hid_device = false; - usb_device_handle_t device; - const usb_config_desc_t *config_desc; - size_t offset = 0; - - if ( usb_host_device_open(s_hid_driver->client_handle, dev_addr, &device) == ESP_OK) { - if ( usb_host_get_active_config_descriptor(device, &config_desc) == ESP_OK ) { - if (get_interface_desc_by_proto(config_desc, &offset, HID_PROTOCOL_NONE)) { - is_hid_device = true; - } - } - usb_host_device_close(s_hid_driver->client_handle, device); - } - - if (is_hid_device) { - ESP_LOGD(TAG, "Found HID Interface, USB addr %d", dev_addr); - } else { - ESP_LOGW(TAG, "Device at addr %d has no HID Interface", dev_addr); - } - - return is_hid_device; -} - -/** - * @brief Create a list of available interfaces in RAM - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] dev_addr USB device physical address - * @param[in] sub_class USB HID SubClass value - * @return esp_err_t - */ -static esp_err_t create_interface_list(hid_device_t *hid_device, - const hid_host_device_config_t *dev_config, - uint8_t sub_class) -{ - const usb_config_desc_t *config_desc = NULL; - const usb_intf_desc_t *iface_desc = NULL; - const hid_descriptor_t *hid_desc = NULL; - const usb_ep_desc_t *ep_desc = NULL; - size_t offset = 0; - - HID_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(hid_device->dev_hdl, &config_desc)); - - const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)config_desc; - size_t total_length = config_desc->wTotalLength; - - next_desc = next_interface_desc(next_desc, total_length, &offset); - - while ( next_desc ) { - iface_desc = (const usb_intf_desc_t *)next_desc; - hid_desc = NULL; - ep_desc = NULL; - - if ( iface_desc->bInterfaceClass == USB_CLASS_HID && - iface_desc->bInterfaceSubClass == sub_class) { - // HID descriptor (extract Report size) - next_desc = next_hid_descriptor(next_desc, total_length, &offset); - if (next_desc) { - hid_desc = (const hid_descriptor_t *)next_desc; - } - // HID mouse and keyboard contain one INT descriptor - next_desc = next_endpoint_desc(next_desc, total_length, &offset); - if (next_desc) { - ep_desc = (const usb_ep_desc_t *)next_desc; - } - - HID_RETURN_ON_ERROR( add_interface_to_list(dev_config, - hid_device, - iface_desc, - hid_desc, - ep_desc) ); - } - next_desc = next_interface_desc(next_desc, total_length, &offset); - }; - - return ESP_OK; -} - -/** - * @brief Destroy a list of available interfaces in RAM - * - * @return esp_err_t - */ -static esp_err_t destroy_interface_list(void) -{ - hid_iface_t *interface = NULL; - - for (int proto = HID_PROTOCOL_KEYBOARD; proto < HID_PROTOCOL_MAX; proto++) { - - interface = get_interface_by_proto(proto); - - if (interface) { - HID_ENTER_CRITICAL(); - interface->ready = false; - STAILQ_REMOVE(&ifaces_tailq, interface, hid_interface, tailq_entry); - HID_EXIT_CRITICAL(); - free(interface); - } - } - - return ESP_OK; -} - -/** - * @brief USB Host Client's event callback - * - * @param[in] event Client event message - * @param[in] arg Argument, does not used - */ -static void client_event_cb(const usb_host_client_event_msg_t *event, void *arg) -{ - if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV) { - if (is_hid_device(event->new_dev.address)) { - const hid_host_event_t hid_event = { - .event = HID_DEVICE_CONNECTED, - .device.address = event->new_dev.address, - }; - s_hid_driver->user_cb(&hid_event, s_hid_driver->user_arg); - } - } else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE) { - hid_device_t *hid_device = get_hid_device_by_handle(event->dev_gone.dev_hdl); - if (hid_device) { - const hid_host_event_t hid_event = { - .event = HID_DEVICE_DISCONNECTED, - .device.handle = hid_device, - }; - s_hid_driver->user_cb(&hid_event, s_hid_driver->user_arg); - } - } -} - -/** - * @brief HID Host prepare interface transfer - * - * @param[in] iface Pointer to Interface structure, - * @param[in] callback Input report data callback - * @return esp_err_t - */ -static esp_err_t hid_host_interface_prepare_transfer(hid_iface_t *iface) -{ - HID_RETURN_ON_ERROR( usb_host_interface_claim( s_hid_driver->client_handle, - iface->dev->dev_hdl, - iface->num, 0) ); - - HID_RETURN_ON_ERROR( usb_host_transfer_alloc(iface->ep_mps, 0, &iface->in_xfer) ); - - return ESP_OK; -} - -/** - * @brief Disable active interface - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] iface Pointer to Interface structure - * @return esp_err_t - */ -static esp_err_t hid_host_disable_interface(hid_device_t *hid_device, hid_iface_t *iface) -{ - HID_RETURN_ON_INVALID_ARG(hid_device); - HID_RETURN_ON_INVALID_ARG(iface); - - if (!iface->ready) { - return ESP_ERR_INVALID_STATE; - } - - HID_RETURN_ON_ERROR( usb_host_endpoint_halt(hid_device->dev_hdl, iface->ep) ); - HID_RETURN_ON_ERROR( usb_host_endpoint_flush(hid_device->dev_hdl, iface->ep) ); - usb_host_endpoint_clear(hid_device->dev_hdl, iface->ep); - - return ESP_OK; -} - -/** - * @brief HID transfer complete status verification - * - * @param[in] transfer Pointer to USB transfer struct - * @return true Transfer completed successfully - * @return false Transfer completed with error - */ -static bool transfer_complete_status_verify(usb_transfer_t *transfer) -{ - bool completed = false; - - assert(transfer); - - switch (transfer->status) { - case USB_TRANSFER_STATUS_COMPLETED: - completed = true; - break; - case USB_TRANSFER_STATUS_NO_DEVICE: // User is notified about device disconnection from usb_event_cb - case USB_TRANSFER_STATUS_CANCELED: - break; - case USB_TRANSFER_STATUS_ERROR: - case USB_TRANSFER_STATUS_TIMED_OUT: - case USB_TRANSFER_STATUS_STALL: - case USB_TRANSFER_STATUS_OVERFLOW: - case USB_TRANSFER_STATUS_SKIPPED: - default: - // Transfer was not completed or canceled by user. - ESP_LOGE(TAG, "Transfer failed, status %d", transfer->status); - } - return completed; -} - -/** - * @brief HID IN Transfer complete callback - * - * @param[in] transfer Pointer to transfer data structure - */ -static void in_xfer_done(usb_transfer_t *in_xfer) -{ - assert(in_xfer); - - hid_device_t *hid_device = (hid_device_t *)in_xfer->context; - hid_iface_t *iface = get_interface_by_ep(hid_device, in_xfer->bEndpointAddress); - - assert(iface); - - if (!transfer_complete_status_verify(in_xfer)) { - interface_user_callback(iface, HID_DEVICE_INTERFACE_TRANSFER_ERROR); - return; - } - - if (iface->report_cb) { - iface->report_cb(in_xfer->data_buffer, in_xfer->actual_num_bytes); - } - - usb_host_transfer_submit(in_xfer); -} - -static void hid_device_release(hid_device_t *hid_device) -{ - xSemaphoreGive(hid_device->device_busy); -} - -static esp_err_t hid_device_claim(hid_device_t *hid_device, uint32_t timeout_ms) -{ - return ( xSemaphoreTake(hid_device->device_busy, pdMS_TO_TICKS(timeout_ms)) - ? ESP_OK - : ESP_ERR_TIMEOUT ); -} - -static esp_err_t hid_device_wait_ready(hid_device_t *hid_device, uint32_t timeout_ms) -{ - HID_RETURN_ON_ERROR( hid_device_claim(hid_device, timeout_ms) ); - hid_device_release(hid_device); - return ESP_OK; -} - -/** - * @brief HID Control transfer complete callback - * - * @param[in] ctrl_xfer Pointer to transfer data structure - */ -static void ctrl_xfer_done(usb_transfer_t *ctrl_xfer) -{ - assert(ctrl_xfer); - hid_device_t *hid_device = (hid_device_t *)ctrl_xfer->context; - xSemaphoreGive(hid_device->ctrl_xfer_done); -} - -/** - * @brief HID control transfer synchronous. - * - * @note Passes interface and endpoint descriptors to obtain: - - * - interface number, IN endpoint, OUT endpoint, max. packet size - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] ctrl_xfer Pointer to the Transfer structure - * @param[in] len Number of bytes to transfer - * @param[in] timeout_ms Timeout in ms - * @return esp_err_t - */ -esp_err_t hid_control_transfer(hid_device_t *hid_device, - usb_transfer_t *ctrl_xfer, - size_t len, - uint32_t timeout_ms) -{ - ctrl_xfer->device_handle = hid_device->dev_hdl; - ctrl_xfer->callback = ctrl_xfer_done; - ctrl_xfer->context = hid_device; - ctrl_xfer->bEndpointAddress = 0; - ctrl_xfer->timeout_ms = timeout_ms; - ctrl_xfer->num_bytes = len; - - HID_RETURN_ON_ERROR( usb_host_transfer_submit_control(s_hid_driver->client_handle, ctrl_xfer)); - - BaseType_t received = xSemaphoreTake(hid_device->ctrl_xfer_done, pdMS_TO_TICKS(ctrl_xfer->timeout_ms)); - - if (received != pdTRUE) { - // Transfer was not finished, error in USB LIB. Reset the endpoint - ESP_LOGE(TAG, "Control Transfer Timeout"); - - HID_RETURN_ON_ERROR( usb_host_endpoint_halt(hid_device->dev_hdl, ctrl_xfer->bEndpointAddress) ); - HID_RETURN_ON_ERROR( usb_host_endpoint_flush(hid_device->dev_hdl, ctrl_xfer->bEndpointAddress) ); - usb_host_endpoint_clear(hid_device->dev_hdl, ctrl_xfer->bEndpointAddress); - return ESP_ERR_TIMEOUT; - } - - ESP_LOG_BUFFER_HEXDUMP(TAG, ctrl_xfer->data_buffer, ctrl_xfer->actual_num_bytes, ESP_LOG_DEBUG); - - return ESP_OK; -} - -/** - * @brief HID class specific request Set - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] bRequest Value to fill bRequest filed in request - * @param[in] wValue Value to fill wValue filed in request - * @param[in] wIndex Value to fill wIndex filed in request - * @param[in] wLength Value to fill wLength filed in request - * @return esp_err_t - */ -static esp_err_t hid_class_request_set(hid_device_t *hid_device, - uint8_t bRequest, - uint16_t wValue, - uint16_t wIndex, - uint16_t wLength) -{ - esp_err_t ret; - usb_transfer_t *ctrl_xfer = hid_device->ctrl_xfer; - HID_RETURN_ON_INVALID_ARG(hid_device); - HID_RETURN_ON_INVALID_ARG(hid_device->ctrl_xfer); - - HID_RETURN_ON_ERROR( hid_device_wait_ready(hid_device, 5000 /* timeout */) ); - HID_RETURN_ON_ERROR( hid_device_claim(hid_device, 5000 /* timeout */) ); - - usb_setup_packet_t *setup = (usb_setup_packet_t *)ctrl_xfer->data_buffer; - setup->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | - USB_BM_REQUEST_TYPE_TYPE_CLASS | - USB_BM_REQUEST_TYPE_RECIP_INTERFACE; - setup->bRequest = bRequest; - setup->wValue = wValue; - setup->wIndex = wIndex; - setup->wLength = wLength; - - ret = hid_control_transfer(hid_device, ctrl_xfer, USB_SETUP_PACKET_SIZE, 5000 /* timeout */); - - hid_device_release(hid_device); - - return ret; -} - -/** - * @brief HID class specific request Get - * - * @param[in] hid_device Pointer to HID device structure - * @param[in] bRequest Value to fill bRequest filed in request - * @param[in] wValue Value to fill wValue filed in request - * @param[in] wIndex Value to fill wIndex filed in request - * @param[in] data Pointer to date buffer to put received data, should be not less than length - * @param[in] length Length of data to receive - * @return esp_err_t - */ -static esp_err_t hid_class_request_get(hid_device_t *hid_device, - uint8_t bRequest, - uint16_t wValue, - uint16_t wIndex, - uint8_t *data, - uint32_t length) -{ - esp_err_t ret; - HID_RETURN_ON_INVALID_ARG(hid_device); - HID_RETURN_ON_INVALID_ARG(hid_device->ctrl_xfer); - HID_RETURN_ON_INVALID_ARG(data); - - usb_transfer_t *ctrl_xfer = hid_device->ctrl_xfer; - - HID_RETURN_ON_ERROR( hid_device_wait_ready(hid_device, 5000 /* timeout */) ); - HID_RETURN_ON_ERROR( hid_device_claim(hid_device, 5000 /* timeout */) ); - - usb_setup_packet_t *setup = (usb_setup_packet_t *)ctrl_xfer->data_buffer; - - setup->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | - USB_BM_REQUEST_TYPE_TYPE_CLASS | - USB_BM_REQUEST_TYPE_RECIP_INTERFACE; - setup->bRequest = bRequest; - setup->wValue = wValue; - setup->wIndex = wIndex; - setup->wLength = length; - - ret = hid_control_transfer(hid_device, ctrl_xfer, USB_SETUP_PACKET_SIZE + length, 5000 /* timeout */); - - if (ESP_OK == ret) { - ctrl_xfer->actual_num_bytes -= USB_SETUP_PACKET_SIZE; - - if (ctrl_xfer->actual_num_bytes <= length) { - memcpy(data, ctrl_xfer->data_buffer + USB_SETUP_PACKET_SIZE, ctrl_xfer->actual_num_bytes); - } - } - - hid_device_release(hid_device); - - return ret; -} - -/** - * @brief HID class specific request SET IDLE - * - * @param[in] iface Pointer to HID Interface configuration structure - * @param[in] duration 0 (zero) for the indefinite duration, non-zero, then a fixed duration used. - * @param[in] report_id If 0 (zero) the idle rate applies to all input reports generated by the device, otherwise ReportID - * @return esp_err_t - */ -static esp_err_t hid_class_request_set_idle(hid_iface_t *iface, - uint8_t duration, - uint8_t report_id) -{ - HID_RETURN_ON_INVALID_ARG(iface); - - return hid_class_request_set(iface->dev, - HID_CLASS_SPECIFIC_REQ_SET_IDLE, - (duration << 8) | report_id, - iface->num, 0); -} - -/** - * @brief HID class specific request SET PROTOCOL - * - * @param[in] iface Pointer to HID Interface configuration structure - * @param[in] protocol HID report protocol (boot or report) - * @return esp_err_t - */ -static esp_err_t hid_class_request_set_protocol(hid_iface_t *iface, - hid_report_protocol_t protocol) -{ - HID_RETURN_ON_INVALID_ARG(iface); - - return hid_class_request_set(iface->dev, - HID_CLASS_SPECIFIC_REQ_SET_PROTOCOL, - protocol, - iface->num, 0); -} - -/** - * @brief HID class specific request GET PROTOCOL - * - * @param[in] iface Pointer to HID Interface configuration structure - * @param[in] protocol Pointer to HID report protocol (boot or report) of device - * @return esp_err_t - */ -static esp_err_t hid_class_request_get_protocol(hid_iface_t *iface, - hid_report_protocol_t *protocol) -{ - uint8_t tmp[1] = { 0xff }; - - HID_RETURN_ON_INVALID_ARG(iface); - HID_RETURN_ON_INVALID_ARG(protocol); - - hid_class_request_get(iface->dev, HID_CLASS_SPECIFIC_REQ_GET_PROTOCOL, 0, iface->num, tmp, 1); - *protocol = (hid_report_protocol_t) tmp[0]; - return ESP_OK; -} - -/** - * @brief HID Host Interface start transfer - * - * @param[in] iface Pointer to HID Interface configuration structure - * @param[in] timeout Timeout in ms - * @return esp_err_t - */ -static esp_err_t hid_host_iface_start_transfer(hid_iface_t *iface, - const uint32_t timeout) -{ - HID_RETURN_ON_INVALID_ARG(iface); - HID_RETURN_ON_INVALID_ARG(iface->in_xfer); - HID_RETURN_ON_INVALID_ARG(iface->dev); - - // prepare transfer - iface->in_xfer->device_handle = iface->dev->dev_hdl; - iface->in_xfer->callback = in_xfer_done; - iface->in_xfer->context = iface->dev; - iface->in_xfer->timeout_ms = timeout; - iface->in_xfer->bEndpointAddress = iface->ep; - iface->in_xfer->num_bytes = iface->ep_mps; - - // start data transfer - return usb_host_transfer_submit(iface->in_xfer); -} - -// ----------------------- Public -------------------------- - -esp_err_t hid_host_install(const hid_host_driver_config_t *config) -{ - esp_err_t ret; - HID_RETURN_ON_INVALID_ARG(config); - HID_RETURN_ON_INVALID_ARG(config->callback); - if ( config->create_background_task ) { - HID_RETURN_ON_FALSE(config->stack_size != 0, ESP_ERR_INVALID_ARG); - HID_RETURN_ON_FALSE(config->task_priority != 0, ESP_ERR_INVALID_ARG); - } - HID_RETURN_ON_FALSE(!s_hid_driver, ESP_ERR_INVALID_STATE); - - hid_driver_t *driver = calloc(1, sizeof(hid_driver_t)); - HID_RETURN_ON_FALSE(driver, ESP_ERR_NO_MEM); - driver->user_cb = config->callback; - driver->user_arg = config->callback_arg; - - usb_host_client_config_t client_config = { - .async.client_event_callback = client_event_cb, - .async.callback_arg = NULL, - .max_num_event_msg = 10, - }; - - driver->end_client_event_handling = false; - driver->all_events_handled = xSemaphoreCreateBinary(); - HID_GOTO_ON_FALSE(driver->all_events_handled, ESP_ERR_NO_MEM); - - HID_GOTO_ON_ERROR( usb_host_client_register(&client_config, &driver->client_handle) ); - - HID_ENTER_CRITICAL(); - HID_GOTO_ON_FALSE_CRITICAL(!s_hid_driver, ESP_ERR_INVALID_STATE); - s_hid_driver = driver; - STAILQ_INIT(&devices_tailq); - STAILQ_INIT(&ifaces_tailq); - HID_EXIT_CRITICAL(); - - if (config->create_background_task) { - BaseType_t task_created = xTaskCreatePinnedToCore( - event_handler_task, - "USB HID HOST", - config->stack_size, - NULL, - config->task_priority, - NULL, - config->core_id); - HID_GOTO_ON_FALSE(task_created, ESP_ERR_NO_MEM); - } - - return ESP_OK; - -fail: - s_hid_driver = NULL; - if (driver->client_handle) { - usb_host_client_deregister(driver->client_handle); - } - if (driver->all_events_handled) { - vSemaphoreDelete(driver->all_events_handled); - } - free(driver); - return ret; -} - -esp_err_t hid_host_uninstall(void) -{ - // Make sure hid driver is installed, - // not being uninstalled from other task - // and no hid device is registered - HID_ENTER_CRITICAL(); - HID_RETURN_ON_FALSE_CRITICAL( s_hid_driver != NULL, ESP_ERR_INVALID_STATE ); - HID_RETURN_ON_FALSE_CRITICAL( !s_hid_driver->end_client_event_handling, ESP_ERR_INVALID_STATE ); - HID_RETURN_ON_FALSE_CRITICAL( STAILQ_EMPTY(&devices_tailq), ESP_ERR_INVALID_STATE ); - HID_RETURN_ON_FALSE_CRITICAL( STAILQ_EMPTY(&ifaces_tailq), ESP_ERR_INVALID_STATE ); - s_hid_driver->end_client_event_handling = true; - HID_EXIT_CRITICAL(); - - xSemaphoreTake(s_hid_driver->all_events_handled, portMAX_DELAY); - vSemaphoreDelete(s_hid_driver->all_events_handled); - free(s_hid_driver); - s_hid_driver = NULL; - return ESP_OK; -} - -void hid_host_event_handler_task(void *arg) -{ - event_handler_task(arg); -} - -esp_err_t hid_host_claim_interface(const hid_host_interface_config_t *iface_config, - hid_host_interface_handle_t *iface_handle) -{ - hid_iface_t *iface = NULL; - hid_report_protocol_t report_protocol; - - HID_RETURN_ON_FALSE((iface_config->proto > HID_PROTOCOL_NONE) - && (iface_config->proto < HID_PROTOCOL_MAX), - ESP_ERR_INVALID_ARG); - - // Search Interface in list - iface = get_interface_by_proto(iface_config->proto); - - // Interface not found in list - if (iface == NULL) { - return ESP_ERR_NOT_FOUND; - } - - // Interface already claimed - if (iface->report_cb != NULL) { - return ESP_ERR_INVALID_STATE; - } - - HID_RETURN_ON_ERROR( hid_host_interface_prepare_transfer(iface) ); - - /* Set infinity duration for output report = 0. Only reporting when a - * change is detected in the report data. - */ - HID_RETURN_ON_ERROR( hid_class_request_set_idle(iface, 0, 0) ); - - // Set BOOT protocol for interface - HID_RETURN_ON_ERROR (hid_class_request_get_protocol(iface, &report_protocol) ); - - if (report_protocol != HID_REPORT_PROTOCOL_BOOT) { - HID_RETURN_ON_ERROR( hid_class_request_set_protocol(iface, HID_REPORT_PROTOCOL_BOOT) ); - // verify that protocol has been successfully changed - report_protocol = HID_REPORT_PROTOCOL_MAX; - HID_RETURN_ON_ERROR (hid_class_request_get_protocol(iface, &report_protocol) ); - - if (report_protocol != HID_REPORT_PROTOCOL_BOOT) { - ESP_LOGE(TAG, "Interface %d Set BOOT Protocol Failure, protocol=%d", - iface->num, - report_protocol); - } - } - - // Claim interface and save report callback - iface->report_cb = iface_config->callback; - - HID_RETURN_ON_ERROR( hid_host_iface_start_transfer(iface, 5000 /* timeout */) ); - - interface_user_callback(iface, HID_DEVICE_INTERFACE_CLAIM); - - *iface_handle = iface; - - return ESP_OK; -} - -esp_err_t hid_host_release_interface(hid_host_interface_handle_t iface_handle) -{ - hid_iface_t *iface = (hid_iface_t *)iface_handle; - - HID_RETURN_ON_FALSE(iface, ESP_ERR_NOT_FOUND); - - if (!is_interface_claimed(iface->proto)) { - return ESP_ERR_INVALID_STATE; - } - - if (iface->ready) { - HID_RETURN_ON_ERROR( hid_host_disable_interface(iface->dev, iface)); - HID_RETURN_ON_ERROR( usb_host_interface_release(s_hid_driver->client_handle, iface->dev->dev_hdl, iface->num) ); - } else { - usb_host_interface_release(s_hid_driver->client_handle, iface->dev->dev_hdl, iface->num); - } - - ESP_ERROR_CHECK( usb_host_transfer_free(iface->in_xfer) ); - - iface->report_cb = NULL; - - interface_user_callback(iface, HID_DEVICE_INTERFACE_RELEASE); - - return ESP_OK; -} - -esp_err_t hid_host_install_device(const hid_host_device_config_t *hid_host_dev_config, - hid_host_device_handle_t *hid_device_handle) -{ - esp_err_t ret; - hid_device_t *hid_device; - - HID_GOTO_ON_FALSE( hid_device = calloc(1, sizeof(hid_device_t)), ESP_ERR_NO_MEM ); - - HID_GOTO_ON_FALSE( hid_device->ctrl_xfer_done = xSemaphoreCreateBinary(), ESP_ERR_NO_MEM ); - HID_GOTO_ON_FALSE( hid_device->device_busy = xSemaphoreCreateMutex(), ESP_ERR_NO_MEM ); - - HID_GOTO_ON_ERROR( usb_host_device_open(s_hid_driver->client_handle, - hid_host_dev_config->dev_addr, - &hid_device->dev_hdl) ); - - - // dev_info.bMaxPacketSize0 + 1 because of the GET PROTOCOL specific class request - usb_device_info_t dev_info; - ESP_ERROR_CHECK(usb_host_device_info(hid_device->dev_hdl, &dev_info)); - HID_GOTO_ON_ERROR(usb_host_transfer_alloc(dev_info.bMaxPacketSize0 + 1, 0, &hid_device->ctrl_xfer)); - - HID_GOTO_ON_ERROR( create_interface_list(hid_device, - hid_host_dev_config, - HID_SUBCLASS_BOOT_INTERFACE) ); - - HID_ENTER_CRITICAL(); - HID_GOTO_ON_FALSE_CRITICAL( s_hid_driver, ESP_ERR_INVALID_STATE ); - HID_GOTO_ON_FALSE_CRITICAL( s_hid_driver->client_handle, ESP_ERR_INVALID_STATE ); - STAILQ_INSERT_TAIL(&devices_tailq, hid_device, tailq_entry); - HID_EXIT_CRITICAL(); - - *hid_device_handle = hid_device; - - return ESP_OK; - -fail: - hid_host_uninstall_device(hid_device); - return ret; -} - -esp_err_t hid_host_uninstall_device(hid_host_device_handle_t hid_device_handle) -{ - hid_device_t *hid_device = (hid_device_t *)hid_device_handle; - - HID_RETURN_ON_INVALID_ARG(hid_device); - - for (int proto = HID_PROTOCOL_KEYBOARD; proto < HID_PROTOCOL_MAX; proto++) { - if (is_interface_claimed(proto)) { - return ESP_ERR_INVALID_STATE; - }; - } - - HID_RETURN_ON_ERROR( destroy_interface_list() ); - - HID_RETURN_ON_ERROR( usb_host_transfer_free(hid_device->ctrl_xfer) ); - HID_RETURN_ON_ERROR( usb_host_device_close(s_hid_driver->client_handle, hid_device->dev_hdl) ); - - if (hid_device->ctrl_xfer_done) { - vSemaphoreDelete(hid_device->ctrl_xfer_done); - } - - if (hid_device->device_busy) { - vSemaphoreDelete(hid_device->device_busy); - } - - HID_ENTER_CRITICAL(); - STAILQ_REMOVE(&devices_tailq, hid_device, hid_host_device, tailq_entry); - HID_EXIT_CRITICAL(); - - free(hid_device); - return ESP_OK; - -} - -esp_err_t hid_host_print_descriptors(hid_host_device_handle_t hid_device_handle) -{ - hid_device_t *hid_devive = (hid_device_t *)hid_device_handle; - const usb_device_desc_t *device_desc; - const usb_config_desc_t *config_desc; - HID_RETURN_ON_ERROR( usb_host_get_device_descriptor(hid_devive->dev_hdl, &device_desc) ); - HID_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(hid_devive->dev_hdl, &config_desc) ); - usb_print_device_descriptor(device_desc); - usb_print_config_descriptor(config_desc, NULL); - return ESP_OK; -} diff --git a/examples/peripherals/usb/host/hid/components/hid/include/hid.h b/examples/peripherals/usb/host/hid/components/hid/include/hid.h deleted file mode 100644 index 13ef007495..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/include/hid.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief HID Subclass - * - * @see 4.2 Subclass, p.8 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_SUBCLASS_NO_SUBCLASS = 0x00, - HID_SUBCLASS_BOOT_INTERFACE = 0x01 -} __attribute__((packed)) hid_subclass_t; - -/** - * @brief HID Protocols - * - * @see 4.3 Protocols, p.9 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_PROTOCOL_NONE = 0x00, - HID_PROTOCOL_KEYBOARD = 0x01, - HID_PROTOCOL_MOUSE = 0x02, - HID_PROTOCOL_MAX -} __attribute__((packed)) hid_protocol_t; - -/** - * @brief HID Descriptor - * - * @see 6.2.1 HID Descriptor, p.22 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef struct { - uint8_t bLength; // Numeric expression that is the total size of the HID descriptor - uint8_t bDescriptorType; // Constant name specifying type of HID descriptor - uint16_t bcdHID; // Numeric expression identifying the HIDClass Specification release - int8_t bCountryCode; // Numeric expression identifying country code of the localized hardware - uint8_t bNumDescriptors; // Numeric expression specifying the number of class descriptors (always at least one i.e. Report descriptor.) - uint8_t bReportDescriptorType; // Constant name identifying type of class descriptor. See Section 7.1.2: Set_Descriptor Request for a table of class descriptor constants - uint16_t wReportDescriptorLength; // Numeric expression that is the total size of the Report descriptor - // Optional descriptors may follow further -} __attribute__((packed)) hid_descriptor_t; - -/** - * @brief HID Country Codes - * - * @see 6.2.1 HID Descriptor, p.23 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ - -typedef enum { - HID_COUNTRY_CODE_NOT_SUPPORTED = 0x00, - HID_COUNTRY_CODE_ARABIC = 0x01, - HID_COUNTRY_CODE_BELGIAN = 0x02, - HID_COUNTRY_CODE_CANADIAN_BILINGUAL = 0x03, - HID_COUNTRY_CODE_CANADIAN_FRENCH = 0x04, - HID_COUNTRY_CODE_CZECH = 0x05, - HID_COUNTRY_CODE_DANISH = 0x06, - HID_COUNTRY_CODE_FINNISH = 0x07, - HID_COUNTRY_CODE_FRENCH = 0x08, - HID_COUNTRY_CODE_GERMAN = 0x09, - HID_COUNTRY_CODE_GREEK = 0x0A, - HID_COUNTRY_CODE_HEBREW = 0x0B, - HID_COUNTRY_CODE_HUNGARY = 0x0C, - HID_COUNTRY_CODE_ISO = 0x0D, - HID_COUNTRY_CODE_ITALIAN = 0x0E, - HID_COUNTRY_CODE_JAPAN = 0x0F, - HID_COUNTRY_CODE_KOREAN = 0x10, - HID_COUNTRY_CODE_LATIN_AMERICAN = 0x11, - HID_COUNTRY_CODE_NETHERLANDS = 0x12, - HID_COUNTRY_CODE_NORWEGIAN = 0x13, - HID_COUNTRY_CODE_PERSIAN = 0x14, - HID_COUNTRY_CODE_POLAND = 0x15, - HID_COUNTRY_CODE_PORTUGUESE = 0x16, - HID_COUNTRY_CODE_RUSSIA = 0x17, - HID_COUNTRY_CODE_SLOVAKIA = 0x18, - HID_COUNTRY_CODE_SPANISH = 0x19, - HID_COUNTRY_CODE_SWEDISH = 0x1A, - HID_COUNTRY_CODE_SWISS_F = 0x1B, - HID_COUNTRY_CODE_SWISS_G = 0x1C, - HID_COUNTRY_CODE_SWITZERLAND = 0x1D, - HID_COUNTRY_CODE_TAIWAN = 0x1E, - HID_COUNTRY_CODE_TURKISH_Q = 0x1F, - HID_COUNTRY_CODE_UK = 0x20, - HID_COUNTRY_CODE_US = 0x21, - HID_COUNTRY_CODE_YUGOSLAVIA = 0x22, - HID_COUNTRY_CODE_TURKISH_F = 0x23 -} __attribute__((packed)) hid_country_code_t; - -/** - * @brief HID Class Descriptor Types - * - * @see 7.1, p.49 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_CLASS_DESCRIPTOR_TYPE_HID = 0x21, - HID_CLASS_DESCRIPTOR_TYPE_REPORT = 0x22, - HID_CLASS_DESCRIPTOR_TYPE_PHYSICAL = 0x23 -} __attribute__((packed)) hid_class_descritpor_type_t; - -/** - * @brief HID Class-Specific Requests - * - * @see 7.2, p.50 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_CLASS_SPECIFIC_REQ_GET_REPORT = 0x01, - HID_CLASS_SPECIFIC_REQ_GET_IDLE = 0x02, - HID_CLASS_SPECIFIC_REQ_GET_PROTOCOL = 0x03, - HID_CLASS_SPECIFIC_REQ_SET_REPORT = 0x09, - HID_CLASS_SPECIFIC_REQ_SET_IDLE = 0x0A, - HID_CLASS_SPECIFIC_REQ_SET_PROTOCOL = 0x0B -} __attribute__((packed)) hid_class_specific_req_t; - -/** - * @brief HID Report Types - * - * @see 7.2.1, p.51 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_REPORT_TYPE_INPUT = 0x01, - HID_REPORT_TYPE_OUTPUT = 0x02, - HID_REPORT_TYPE_FEATURE = 0x03, -} __attribute__((packed)) hid_report_type_t; - -/** - * @brief HID Report protocol - * - * @see 7.2.5/7.2.6, p.54 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_REPORT_PROTOCOL_BOOT = 0x00, - HID_REPORT_PROTOCOL_REPORT = 0x01, - HID_REPORT_PROTOCOL_MAX -} __attribute__((packed)) hid_report_protocol_t; - -#ifdef __cplusplus -} -#endif //__cplusplus diff --git a/examples/peripherals/usb/host/hid/components/hid/include/hid_host.h b/examples/peripherals/usb/host/hid/components/hid/include/hid_host.h deleted file mode 100644 index 2352666bcf..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/include/hid_host.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#include -#include "esp_err.h" -#include - -#include "hid.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct hid_host_device *hid_host_device_handle_t; /**< Handle to a HID */ -typedef struct hid_interface *hid_host_interface_handle_t; /**< Handle to a particular HID interface */ - -/** - * @brief HID Interface input report callback - * - * @param[in] data Pointer to buffer containing input report data - * @param[in] length Data length - */ -typedef void (*hid_input_report_cb_t)(const uint8_t *const data, const int length); - -/** - * @brief USB HID event containing event type and associated device handle -*/ -typedef struct { - enum { - HID_DEVICE_CONNECTED, /**< HID device has been connected to the system.*/ - HID_DEVICE_DISCONNECTED, /**< HID device has been disconnected from the system.*/ - } event; - union { - uint8_t address; /**< Address of connected HID device.*/ - hid_host_device_handle_t handle; /**< HID device handle to disconnected device.*/ - } device; -} hid_host_event_t; - -/** - * @brief USB HID interface event for application logic -*/ -typedef enum { - HID_DEVICE_INTERFACE_INIT = 0x00, /**< Interface available for application logic */ - HID_DEVICE_INTERFACE_CLAIM, /**< Interface was claimed */ - HID_DEVICE_INTERFACE_RELEASE, /**< Interface was released */ - HID_DEVICE_INTERFACE_TRANSFER_ERROR /**< Interface transfer error occurred */ -} hid_interface_event_t; - -/** - * @brief USB HID Host interface event containing event type and associated parameters -*/ -typedef struct { - hid_interface_event_t event; /**< USB HID Interface event */ - struct interface_event_param { - uint8_t dev_addr; /**< USB Device address */ - uint8_t num; /**< USB Interface number */ - hid_protocol_t proto; /**< USB HID Interface protocol */ - } interface; -} hid_host_interface_event_t; - - -/** - * @brief USB HID host event callback. - * - * @param[in] event mass storage event -*/ -typedef void (*hid_host_event_cb_t)(const hid_host_event_t *event, void *arg); - -typedef void (*hid_host_interface_event_cb_t)(const hid_host_interface_event_t *event, void *arg); - -/** - * @brief HID configuration structure. -*/ -typedef struct { - bool create_background_task; /**< When set to true, background task handling USB events is created. - Otherwise user has to periodically call hid_host_handle_events function */ - size_t task_priority; /**< Task priority of created background task */ - size_t stack_size; /**< Stack size of created background task */ - BaseType_t core_id; /**< Select core on which background task will run or tskNO_AFFINITY */ - hid_host_event_cb_t callback; /**< Callback invoked when HID event occurs. Must not be NULL. */ - void *callback_arg; /**< User provided argument passed to callback */ -} hid_host_driver_config_t; - -typedef struct { - uint8_t dev_addr; - hid_host_interface_event_cb_t iface_event_cb; /**< Callback invoked when HID event occurs. Must not be NULL. */ - void *iface_event_arg; /**< User provided argument passed to callback */ -} hid_host_device_config_t; - -typedef struct { - hid_protocol_t proto; - hid_input_report_cb_t callback; -} hid_host_interface_config_t; - -/** - * @brief Install USB Host HID Class driver - * - * @param[in] config configuration structure HID to create - * @return esp_err_r - */ -esp_err_t hid_host_install(const hid_host_driver_config_t *config); - -/** - * @brief Uninstall HID Class driver - * @return esp_err_t - */ -esp_err_t hid_host_uninstall(void); - -/** - * @brief HID Host USB event handler - * - * If HID Host install was made with create_background_task=false configuration, - * application needs to handle USB Host events itself. - * Do not used id HID host install was made with create_background_task=true configuration - * - * @param[in] arg Pointer to handler argument - * @return none - */ -void hid_host_event_handler_task(void *arg); - -/** - * @brief Initialization of HID device. - * - * @param[in] hid_host_dev_config Pointer to HID Host device configuration structure - * @param[out] hid_device_handle Pointer to HID device handle - * @return esp_err_t - */ -esp_err_t hid_host_install_device(const hid_host_device_config_t *hid_host_dev_config, - hid_host_device_handle_t *hid_device_handle); - -/** - * @brief Deinitialization of HID device. - * - * @param[in] hid_device_handle Device handle obtained from hid_host_install_device function - * @return esp_err_t - */ -esp_err_t hid_host_uninstall_device(hid_host_device_handle_t hid_device_handle); - -/** - * @brief Print configuration descriptor. - * - * @param[in] hid_device_handle Device handle obtained from hid_host_install_device function - * @return esp_err_t - */ -esp_err_t hid_host_print_descriptors(hid_host_device_handle_t hid_device_handle); - -/** - * @brief USB HID Interface claim - * - * @param[in] iface_config Pointer to Interface configuration structure - * @param[out] iface_handle Pointer to Interface handle - * @param[in] esp_err_t - */ -esp_err_t hid_host_claim_interface(const hid_host_interface_config_t *iface_config, - hid_host_interface_handle_t *iface_handle); - -/** - * @brief USB HID Interface release - * - * @param[in] iface_handle Interface handle obtained from hid_host_claim_interface function - * @param[in] esp_err_t - */ -esp_err_t hid_host_release_interface(hid_host_interface_handle_t iface_handle); - - -#ifdef __cplusplus -} -#endif //__cplusplus diff --git a/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_keyboard.h b/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_keyboard.h deleted file mode 100644 index a740b90a07..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_keyboard.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------ HID usage keys --------------------------------------------------------------- -/** - * @brief HID Keys - * - */ -typedef enum { - HID_KEY_NO_PRESS = 0x00, - HID_KEY_ROLLOVER = 0x01, - HID_KEY_POST_FAIL = 0x02, - HID_KEY_ERROR_UNDEFINED = 0x03, - HID_KEY_A = 0x04, - HID_KEY_B = 0x05, - HID_KEY_C = 0x06, - HID_KEY_D = 0x07, - HID_KEY_E = 0x08, - HID_KEY_F = 0x09, - HID_KEY_G = 0x0A, - HID_KEY_H = 0x0B, - HID_KEY_I = 0x0C, - HID_KEY_J = 0x0D, - HID_KEY_K = 0x0E, - HID_KEY_L = 0x0F, - HID_KEY_M = 0x10, - HID_KEY_N = 0x11, - HID_KEY_O = 0x12, - HID_KEY_P = 0x13, - HID_KEY_Q = 0x14, - HID_KEY_R = 0x15, - HID_KEY_S = 0x16, - HID_KEY_T = 0x17, - HID_KEY_U = 0x18, - HID_KEY_V = 0x19, - HID_KEY_W = 0x1A, - HID_KEY_X = 0x1B, - HID_KEY_Y = 0x1C, - HID_KEY_Z = 0x1D, - HID_KEY_1 = 0x1E, - HID_KEY_2 = 0x1F, - HID_KEY_3 = 0x20, - HID_KEY_4 = 0x21, - HID_KEY_5 = 0x22, - HID_KEY_6 = 0x23, - HID_KEY_7 = 0x24, - HID_KEY_8 = 0x25, - HID_KEY_9 = 0x26, - HID_KEY_0 = 0x27, - HID_KEY_ENTER = 0x28, - HID_KEY_ESC = 0x29, - HID_KEY_DEL = 0x2A, - HID_KEY_TAB = 0x2B, - HID_KEY_SPACE = 0x2C, - HID_KEY_MINUS = 0x2D, - HID_KEY_EQUAL = 0x2E, - HID_KEY_OPEN_BRACKET = 0x2F, - HID_KEY_CLOSE_BRACKET = 0x30, - HID_KEY_BACK_SLASH = 0x31, - HID_KEY_SHARP = 0x32, - HID_KEY_COLON = 0x33, - HID_KEY_QUOTE = 0x34, - HID_KEY_TILDE = 0x35, - HID_KEY_LESS = 0x36, - HID_KEY_GREATER = 0x37, - HID_KEY_SLASH = 0x38, - HID_KEY_CAPS_LOCK = 0x39, - HID_KEY_F1 = 0x3A, - HID_KEY_F2 = 0x3B, - HID_KEY_F3 = 0x3C, - HID_KEY_F4 = 0x3D, - HID_KEY_F5 = 0x3E, - HID_KEY_F6 = 0x3F, - HID_KEY_F7 = 0x40, - HID_KEY_F8 = 0x41, - HID_KEY_F9 = 0x42, - HID_KEY_F10 = 0x43, - HID_KEY_F11 = 0x44, - HID_KEY_F12 = 0x45, - HID_KEY_PRINT_SCREEN = 0x46, - HID_KEY_SCROLL_LOCK = 0x47, - HID_KEY_PAUSE = 0x48, - HID_KEY_INSERT = 0x49, - HID_KEY_HOME = 0x4A, - HID_KEY_PAGEUP = 0x4B, - HID_KEY_DELETE = 0x4C, - HID_KEY_END = 0x4D, - HID_KEY_PAGEDOWN = 0x4E, - HID_KEY_RIGHT = 0x4F, - HID_KEY_LEFT = 0x50, - HID_KEY_DOWN = 0x51, - HID_KEY_UP = 0x52, - HID_KEY_NUM_LOCK = 0x53, - HID_KEY_KEYPAD_DIV = 0x54, - HID_KEY_KEYPAD_MUL = 0x55, - HID_KEY_KEYPAD_SUB = 0x56, - HID_KEY_KEYPAD_ADD = 0x57, - HID_KEY_KEYPAD_ENTER = 0x58, - HID_KEY_KEYPAD_1 = 0x59, - HID_KEY_KEYPAD_2 = 0x5A, - HID_KEY_KEYPAD_3 = 0x5B, - HID_KEY_KEYPAD_4 = 0x5C, - HID_KEY_KEYPAD_5 = 0x5D, - HID_KEY_KEYPAD_6 = 0x5E, - HID_KEY_KEYPAD_7 = 0x5F, - HID_KEY_KEYPAD_8 = 0x60, - HID_KEY_KEYPAD_9 = 0x61, - HID_KEY_KEYPAD_0 = 0x62, - HID_KEY_KEYPAD_DELETE = 0x63, - HID_KEY_KEYPAD_SLASH = 0x64, - HID_KEY_APPLICATION = 0x65, - HID_KEY_POWER = 0x66, - HID_KEY_KEYPAD_EQUAL = 0x67, - HID_KEY_F13 = 0x68, - HID_KEY_F14 = 0x69, - HID_KEY_F15 = 0x6A, - HID_KEY_F16 = 0x6B, - HID_KEY_F17 = 0x6C, - HID_KEY_F18 = 0x6D, - HID_KEY_F19 = 0x6E, - HID_KEY_F20 = 0x6F, - HID_KEY_F21 = 0x70, - HID_KEY_F22 = 0x71, - HID_KEY_F23 = 0x72, - HID_KEY_F24 = 0x73, - HID_KEY_EXECUTE = 0x74, - HID_KEY_HELP = 0x75, - HID_KEY_MENU = 0x76, - HID_KEY_SELECT = 0x77, - HID_KEY_STOP = 0x78, - HID_KEY_AGAIN = 0x79, - HID_KEY_UNDO = 0x7A, - HID_KEY_CUT = 0x7B, - HID_KEY_COPY = 0x7C, - HID_KEY_PASTE = 0x7D, - HID_KEY_FIND = 0x7E, - HID_KEY_MUTE = 0x7F, - HID_KEY_VOLUME_UP = 0x80, - HID_KEY_VOLUME_DOWN = 0x81, - HID_KEY_LOCKING_CAPS_LOCK = 0x82, - HID_KEY_LOCKING_NUM_LOCK = 0x83, - HID_KEY_LOCKING_SCROLL_LOCK = 0x84, - HID_KEY_KEYPAD_COMMA = 0x85, - HID_KEY_KEYPAD_EQUAL_SIGN = 0x86, - HID_KEY_INTERNATIONAL_1 = 0x87, - HID_KEY_INTERNATIONAL_2 = 0x88, - HID_KEY_INTERNATIONAL_3 = 0x89, - HID_KEY_INTERNATIONAL_4 = 0x8A, - HID_KEY_INTERNATIONAL_5 = 0x8B, - HID_KEY_INTERNATIONAL_6 = 0x8C, - HID_KEY_INTERNATIONAL_7 = 0x8D, - HID_KEY_INTERNATIONAL_8 = 0x8E, - HID_KEY_INTERNATIONAL_9 = 0x8F, - HID_KEY_LANG_1 = 0x90, - HID_KEY_LANG_2 = 0x91, - HID_KEY_LANG_3 = 0x92, - HID_KEY_LANG_4 = 0x93, - HID_KEY_LANG_5 = 0x94, - HID_KEY_LANG_6 = 0x95, - HID_KEY_LANG_7 = 0x96, - HID_KEY_LANG_8 = 0x97, - HID_KEY_LANG_9 = 0x98, - HID_KEY_ALTERNATE_ERASE = 0x99, - HID_KEY_SYSREQ = 0x9A, - HID_KEY_CANCEL = 0x9B, - HID_KEY_CLEAR = 0x9C, - HID_KEY_PRIOR = 0x9D, - HID_KEY_RETURN = 0x9E, - HID_KEY_SEPARATOR = 0x9F, - HID_KEY_OUT = 0xA0, - HID_KEY_OPER = 0xA1, - HID_KEY_CLEAR_AGAIN = 0xA2, - HID_KEY_CRSEL = 0xA3, - HID_KEY_EXSEL = 0xA4, - HID_KEY_KEYPAD_00 = 0xB0, - HID_KEY_KEYPAD_000 = 0xB1, - HID_KEY_THOUSANDS_SEPARATOR = 0xB2, - HID_KEY_DECIMAL_SEPARATOR = 0xB3, - HID_KEY_CURRENCY_UNIT = 0xB4, - HID_KEY_CURRENCY_SUB_UNIT = 0xB5, - HID_KEY_KEYPAD_OPEN_PARENTHESIS = 0xB6, - HID_KEY_KEYPAD_CLOSE_PARENTHESIS = 0xB7, - HID_KEY_KEYPAD_OPEN_BRACE = 0xB8, - HID_KEY_KEYPAD_CLOSE_BRACE = 0xB9, - HID_KEY_KEYPAD_TAB = 0xBA, - HID_KEY_KEYPAD_BACKSPACE = 0xBB, - HID_KEY_KEYPAD_A = 0xBC, - HID_KEY_KEYPAD_B = 0xBD, - HID_KEY_KEYPAD_C = 0xBE, - HID_KEY_KEYPAD_D = 0xBF, - HID_KEY_KEYPAD_E = 0xC0, - HID_KEY_KEYPAD_F = 0xC1, - HID_KEY_KEYPAD_XOR = 0xC2, - HID_KEY_KEYPAD_CARET = 0xC3, - HID_KEY_KEYPAD_PERCENT = 0xC4, - HID_KEY_KEYPAD_LESSER = 0xC5, - HID_KEY_KEYPAD_GREATER = 0xC6, - HID_KEY_KEYPAD_AND = 0xC7, - HID_KEY_KEYPAD_LOGICAL_AND = 0xC8, - HID_KEY_KEYPAD_OR = 0xC9, - HID_KEY_KEYPAD_LOGICAL_OR = 0xCA, - HID_KEY_KEYPAD_COLON = 0xCB, - HID_KEY_KEYPAD_SHARP = 0xCC, - HID_KEY_KEYPAD_SPACE = 0xCD, - HID_KEY_KEYPAD_AT = 0xCE, - HID_KEY_KEYPAD_BANG = 0xCF, - HID_KEY_KEYPAD_MEMORY_STORE = 0xD0, - HID_KEY_KEYPAD_MEMORY_RECALL = 0xD1, - HID_KEY_KEYPAD_MEMORY_CLEAD = 0xD2, - HID_KEY_KEYPAD_MEMORY_ADD = 0xD3, - HID_KEY_KEYPAD_MEMORY_SUBSTRACT = 0xD4, - HID_KEY_KEYPAD_MEMORY_MULTIPLY = 0xD5, - HID_KEY_KEYPAD_MEMORY_DIVIDE = 0xD6, - HID_KEY_KEYPAD_SIGN = 0xD7, - HID_KEY_KEYPAD_CLEAR = 0xD8, - HID_KEY_KEYPAD_CLEAR_ENTRY = 0xD9, - HID_KEY_KEYPAD_BINARY = 0xDA, - HID_KEY_KEYPAD_OCTAL = 0xDB, - HID_KEY_KEYPAD_DECIMAL = 0xDC, - HID_KEY_KEYPAD_HEXADECIMAL = 0xDD, - HID_KEY_LEFT_CONTROL = 0xE0, - HID_KEY_LEFT_SHIFT = 0xE1, - HID_KEY_LEFT_ALT = 0xE2, - HID_KEY_LEFT_GUI = 0xE3, - HID_KEY_RIGHT_CONTROL = 0xE0, - HID_KEY_RIGHT_SHIFT = 0xE1, - HID_KEY_RIGHT_ALT = 0xE2, - HID_KEY_RIGHT_GUI = 0xE3 -} __attribute__((packed)) hid_key_t; - -// Modifier bit mask -#define HID_LEFT_CONTROL (1 << 0) -#define HID_LEFT_SHIFT (1 << 1) -#define HID_LEFT_ALT (1 << 2) -#define HID_LEFT_GUI (1 << 3) -#define HID_RIGHT_CONTROL (1 << 4) -#define HID_RIGHT_SHIFT (1 << 5) -#define HID_RIGHT_ALT (1 << 6) -#define HID_RIGHT_GUI (1 << 7) - -/** - * @brief HID Keyboard Key number for Boot Interface - * - * @see B.1, p.60 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef enum { - HID_KEYBOARD_KEY_NUMBER0 = 0, - HID_KEYBOARD_KEY_NUMBER1, - HID_KEYBOARD_KEY_NUMBER2, - HID_KEYBOARD_KEY_NUMBER3, - HID_KEYBOARD_KEY_NUMBER4, - HID_KEYBOARD_KEY_NUMBER5, - HID_KEYBOARD_KEY_MAX, -} hid_keyboard_key_number_t; - -/** - * @brief HID Keyboard Input Report for Boot Interfaces - * - * @see B.1, p.60 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef struct { - union { - struct { - uint8_t left_ctr: 1; - uint8_t left_shift: 1; - uint8_t left_alt: 1; - uint8_t left_gui: 1; - uint8_t rigth_ctr: 1; - uint8_t right_shift: 1; - uint8_t right_alt: 1; - uint8_t right_gui: 1; - }; - uint8_t val; - } modifier; - uint8_t reserved; - uint8_t key[HID_KEYBOARD_KEY_MAX]; -} __attribute__((packed)) hid_keyboard_input_report_boot_t; - -#ifdef __cplusplus -} -#endif //__cplusplus diff --git a/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_mouse.h b/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_mouse.h deleted file mode 100644 index 5ef01836ff..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/include/hid_usage_mouse.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief HID Mouse Input Report for Boot Interfaces - * - * @see B.1, p.60 of Device Class Definition for Human Interface Devices (HID) Version 1.11 - */ -typedef struct { - union { - struct { - uint8_t button1: 1; - uint8_t button2: 1; - uint8_t button3: 1; - uint8_t reserved: 5; - }; - uint8_t val; - } buttons; - int8_t x_displacement; - int8_t y_displacement; -} __attribute__((packed)) hid_mouse_input_report_boot_t; - -#ifdef __cplusplus -} -#endif //__cplusplus diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/CMakeLists.txt b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/CMakeLists.txt deleted file mode 100644 index 9e5560df03..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -#This is the project CMakeLists.txt file for the test subproject -cmake_minimum_required(VERSION 3.16) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(test_app_hid_basic) diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/README.md b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/README.md deleted file mode 100644 index cfd217d911..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/README.md +++ /dev/null @@ -1,3 +0,0 @@ -| Supported Targets | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | - diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/CMakeLists.txt b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/CMakeLists.txt deleted file mode 100644 index ab2a053136..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# In order for the cases defined by `TEST_CASE` to be linked into the final elf, -# the component can be registered as WHOLE_ARCHIVE -idf_component_register(SRC_DIRS "." "../../../" - INCLUDE_DIRS "." "../../../include" ${CMAKE_CURRENT_BINARY_DIR} - REQUIRES usb unity esp_common - WHOLE_ARCHIVE) diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_app_main.c b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_app_main.c deleted file mode 100644 index eff7b877c4..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_app_main.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "esp_heap_caps.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "unity.h" -#include "unity_test_utils.h" -#include "esp_err.h" - -#include "hid_host.h" -#include "test_hid_basic.h" - -void setUp(void) -{ - unity_utils_record_free_mem(); -} - -void tearDown(void) -{ - unity_utils_evaluate_leaks(); -} - -void app_main(void) -{ - // ____ ___ ___________________ __ __ - // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ - // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. - // | | / / \ | | \ | | \ ___/ \___ \ | | - // |______/ /_______ / |______ / |__| \___ >____ > |__| - // \/ \/ \/ \/ - printf(" ____ ___ ___________________ __ __ \r\n"); - printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); - printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); - printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); - printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); - printf(" \\/ \\/ \\/ \\/ \r\n"); - - unity_utils_setup_heap_record(80); - unity_utils_set_leak_level(20); - unity_run_menu(); -} diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.c b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.c deleted file mode 100644 index 3f972ffa62..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "unity.h" -#include "unity_test_utils.h" -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "freertos/semphr.h" -#include "usb/usb_host.h" - -#include "hid_host.h" -#include "hid_usage_keyboard.h" -#include "hid_usage_mouse.h" - -#include "test_hid_basic.h" - -typedef enum { - HOST_NO_CLIENT = 0x1, - HOST_ALL_FREE = 0x2, - DEVICE_CONNECTED = 0x4, - DEVICE_DISCONNECTED = 0x8, - DEVICE_ADDRESS_MASK = 0xFF0, -} test_app_event_t; - -static EventGroupHandle_t test_usb_flags; -hid_host_device_handle_t test_hid_device = NULL; -TaskHandle_t test_usb_event_task_handle; -SemaphoreHandle_t test_semaphore; - -// ----------------------- Private ------------------------- -/** - * @brief USB HID Host event callback. Handle such event as device connection and removing - * - * @param[in] event HID Host device event - * @param[in] arg Pointer to arguments, does not used - * - */ -static void test_hid_host_event_callback(const hid_host_event_t *event, void *arg) -{ - if (event->event == HID_DEVICE_CONNECTED) { - // Obtained USB device address is placed after application events - xEventGroupSetBits(test_usb_flags, DEVICE_CONNECTED | (event->device.address << 4)); - } else if (event->event == HID_DEVICE_DISCONNECTED) { - xEventGroupSetBits(test_usb_flags, DEVICE_DISCONNECTED); - } -} - -/** - * @brief USB HID Host interface callback - * - * @param[in] event HID Host interface event - * @param[in] arg Pointer to arguments, does not used - */ -static void test_hid_host_interface_event_callback(const hid_host_interface_event_t *event, void *arg) -{ - switch (event->event) { - case HID_DEVICE_INTERFACE_INIT: - printf("Found Interface number %d, protocol %s\n", - event->interface.num, - (event->interface.proto == HID_PROTOCOL_KEYBOARD) - ? "Keyboard" - : "Mouse"); - break; - case HID_DEVICE_INTERFACE_TRANSFER_ERROR: - case HID_DEVICE_INTERFACE_CLAIM: - case HID_DEVICE_INTERFACE_RELEASE: - default: - // ... do nothing here for now - break; - } -} - -/** - * @brief Handle common USB host library events - * - * @param[in] args Pointer to arguments, does not used - */ -static void test_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(test_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) { - xEventGroupSetBits(test_usb_flags, HOST_ALL_FREE); - } - } - - vTaskDelete(NULL); -} - -/** - * @brief Create global semaphore - */ -static void test_create_semaphore(void) -{ - test_semaphore = xSemaphoreCreateBinary(); -} - -/** - * @brief Deletes global semaphore - */ -static void test_delete_semaphore(void) -{ - vSemaphoreDelete(test_semaphore); -} - -/** - * @brief HID Keyboard report callback - * - * Keyboard report length == size of keyboard boot report - * - */ -static void test_hid_host_keyboard_report_callback(const uint8_t *const data, const int length) -{ - printf("Keyboard report length %d\n", length); - TEST_ASSERT_EQUAL(sizeof(hid_keyboard_input_report_boot_t), length); - xSemaphoreGive(test_semaphore); -} - -/** - * @brief HID Mouse report callback - * - * Mouse report length >= size of mouse boot report - * - */ -static void test_hid_host_mouse_report_callback(const uint8_t *const data, const int length) -{ - printf("Mouse report length %d\n", length); - TEST_ASSERT_GREATER_OR_EQUAL(sizeof(hid_mouse_input_report_boot_t), length); - xSemaphoreGive(test_semaphore); -} - -/** - * @brief Waits global semaphore for timeout - */ -static bool test_wait_semaphore_timeout(unsigned int ms) -{ - return ( xSemaphoreTake(test_semaphore, pdMS_TO_TICKS(ms)) ) - ? true - : false; -} - -/** - * @brief HID Keyboard report length test - * - * - Claim Keyboard interface - * - Wait Keyboard interface report callback for 5 sec - * - Release Keyboard interface - */ -static void test_hid_keyboard_report_length(void) -{ - hid_host_interface_handle_t keyboard_handle; - hid_host_interface_config_t keyboard_iface_config = { - .proto = HID_PROTOCOL_KEYBOARD, - .callback = test_hid_host_keyboard_report_callback, - }; - - // claim keyboard interface - TEST_ASSERT_EQUAL(ESP_OK, hid_host_claim_interface(&keyboard_iface_config, &keyboard_handle) ); - // wait report - printf("Please, press any keyboard key ...\n"); - fflush(stdout); - test_wait_semaphore_timeout(5000); - // release keyboard interface - TEST_ASSERT_EQUAL(ESP_OK, hid_host_release_interface(keyboard_handle) ); -} - -/** - * @brief HID Mouse report length test - * - * - Claim Mouse interface - * - Wait Mouse interface report callback for 5 sec - * - Release Mouse interface - */ -static void test_hid_mouse_report_length(void) -{ - hid_host_interface_handle_t mouse_handle; - hid_host_interface_config_t mouse_iface_config = { - .proto = HID_PROTOCOL_MOUSE, - .callback = test_hid_host_mouse_report_callback, - }; - // claim mouse interface - TEST_ASSERT_EQUAL(ESP_OK, hid_host_claim_interface(&mouse_iface_config, &mouse_handle) ); - // wait report - printf("Please, move mouse or press any button ...\n"); - fflush(stdout); - test_wait_semaphore_timeout(5000); - // release mouse interface - TEST_ASSERT_EQUAL(ESP_OK, hid_host_release_interface(mouse_handle) ); -} - -// ----------------------- Public ------------------------- - -/** - * @brief Setups HID - * - * - Create events handle - * - Create usb_events task - * - Install USB Host driver - * - Install HID Host driver - */ -void test_hid_setup(void) -{ - test_usb_flags = xEventGroupCreate(); - const usb_host_config_t host_config = { .intr_flags = ESP_INTR_FLAG_LEVEL1 }; - TEST_ASSERT_EQUAL(ESP_OK, usb_host_install(&host_config) ); - - xTaskCreate(test_handle_usb_events, "usb_events", 4096, NULL, 2, &test_usb_event_task_handle); - - // hid host driver config - const hid_host_driver_config_t hid_host_config = { - .create_background_task = true, - .task_priority = 5, - .stack_size = 4096, - .callback = test_hid_host_event_callback, - }; - - TEST_ASSERT_EQUAL(ESP_OK, hid_host_install(&hid_host_config) ); -} - -/** - * @brief Waits HID connection and install - * - * - Wait events: DEVICE_CONNECTED, DEVICE_ADDRESS_MASK - * - On DEVICE_ADDRESS_MASK install HID Host device driver and return handle - * - * @return hid_host_device_handle_t HID Device handle - */ -hid_host_device_handle_t test_hid_wait_connection_and_install(void) -{ - TEST_ASSERT_NULL(test_hid_device); - - printf("Please, insert HID device ...\n"); - fflush(stdout); - - EventBits_t event = xEventGroupWaitBits(test_usb_flags, - DEVICE_CONNECTED | DEVICE_ADDRESS_MASK, - pdTRUE, - pdFALSE, - portMAX_DELAY); - - if (event & DEVICE_CONNECTED) { - xEventGroupClearBits(test_usb_flags, DEVICE_CONNECTED); - } - - if (event & DEVICE_ADDRESS_MASK) { - xEventGroupClearBits(test_usb_flags, DEVICE_ADDRESS_MASK); - - const hid_host_device_config_t hid_host_device_config = { - .dev_addr = (event & DEVICE_ADDRESS_MASK) >> 4, - .iface_event_cb = test_hid_host_interface_event_callback, - .iface_event_arg = NULL, - }; - - TEST_ASSERT_EQUAL(ESP_OK, hid_host_install_device(&hid_host_device_config, &test_hid_device) ); - } - - return test_hid_device; -} - -/** - * @brief Test HID Wait device removal - * - * - Wait events: DEVICE_DISCONNECTED - * - On DEVICE_DISCONNECTED proceed - */ -void test_hid_wait_for_removal(void) -{ - printf("Please, remove HID device ...\n"); - fflush(stdout); - - EventBits_t event = xEventGroupWaitBits(test_usb_flags, - DEVICE_DISCONNECTED, - pdTRUE, - pdFALSE, - portMAX_DELAY); - - if (event & DEVICE_DISCONNECTED) { - xEventGroupClearBits(test_usb_flags, DEVICE_DISCONNECTED); - } -} - -/** - * @brief Uninstalls HID device by handle obtained from test_hid_wait_connection_and_install() - * - * - Wait events: DEVICE_DISCONNECTED - * - On DEVICE_DISCONNECTED proceed - */ -void test_hid_uninstall_hid_device(hid_host_device_handle_t hid_device_handle) -{ - TEST_ASSERT_EQUAL(ESP_OK, hid_host_uninstall_device(test_hid_device) ); -} - -/** - * @brief Teardowns HID - * - * - Uninstall HID Host driver - * - Uninstall USB Host driver - * - Delete usb_events task - * - Delete events handle - */ -void test_hid_teardown(void) -{ - TEST_ASSERT_EQUAL(ESP_OK, hid_host_uninstall() ); - TEST_ASSERT_EQUAL(ESP_OK, usb_host_uninstall() ); - - vTaskDelete(test_usb_event_task_handle); - vEventGroupDelete(test_usb_flags); -} - -// ------------------------- HID Test ------------------------------------------ - -static void test_setup_hid_basic(void) -{ - test_hid_setup(); - test_create_semaphore(); -} - -static void test_teardown_hid_basic(void) -{ - test_delete_semaphore(); - test_hid_teardown(); - //Short delay to allow task to be cleaned up - vTaskDelay(pdMS_TO_TICKS(10)); - test_hid_device = NULL; -} - -TEST_CASE("(HID Host) Memory leakage basic", "[auto][hid_host]") -{ - test_setup_hid_basic(); - test_teardown_hid_basic(); - vTaskDelay(20); -} - -TEST_CASE("(HID Host) Memory leakage with HID device", "[hid_host]") -{ - test_setup_hid_basic(); - test_hid_device = test_hid_wait_connection_and_install(); - test_hid_wait_for_removal(); - test_hid_uninstall_hid_device(test_hid_device); - test_teardown_hid_basic(); - vTaskDelay(20); -} - -TEST_CASE("(HID Host) HID Keyboard report length", "[hid_host]") -{ - test_setup_hid_basic(); - test_hid_device = test_hid_wait_connection_and_install(); - test_hid_keyboard_report_length(); - test_hid_wait_for_removal(); - test_hid_uninstall_hid_device(test_hid_device); - test_teardown_hid_basic(); - vTaskDelay(20); -} - -TEST_CASE("(HID Host) HID Mouse report length", "[hid_host]") -{ - test_setup_hid_basic(); - test_hid_device = test_hid_wait_connection_and_install(); - test_hid_mouse_report_length(); - test_hid_wait_for_removal(); - test_hid_uninstall_hid_device(test_hid_device); - test_teardown_hid_basic(); - vTaskDelay(20); -} diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.h b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.h deleted file mode 100644 index 9e6c8082df..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_basic.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "hid_host.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern hid_host_device_handle_t test_hid_device; - -// ------------------------ HID Test ------------------------------------------- - -void test_hid_setup(void); - -hid_host_device_handle_t test_hid_wait_connection_and_install(void); - -void test_hid_wait_for_removal(void); - -void test_hid_uninstall_hid_device(hid_host_device_handle_t hid_device_handle); - -void test_hid_teardown(void); - -#ifdef __cplusplus -} -#endif //__cplusplus diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_err_handling.c b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_err_handling.c deleted file mode 100644 index 84ac4688dd..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_err_handling.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "unity.h" -#include "unity_test_utils.h" - -#include "hid_host.h" - -#define TEST_HID_ERR_HANDLING_CASES (3) - -static void test_install_hid_driver_without_config(void); -static void test_install_hid_driver_with_wrong_config(void); -static void test_claim_interface_without_driver(void); - -void (*test_hid_err_handling_case[TEST_HID_ERR_HANDLING_CASES])(void) = { - test_install_hid_driver_without_config, - test_install_hid_driver_with_wrong_config, - test_claim_interface_without_driver -}; -// ----------------------- Private ------------------------- -/** - * @brief USB HID Host event callback. Handle such event as device connection and removing - * - * @param[in] event HID Host device event - * @param[in] arg Pointer to arguments, does not used - * - */ -static void test_hid_host_event_callback_stub(const hid_host_event_t *event, void *arg) -{ - if (event->event == HID_DEVICE_CONNECTED) { - // Device connected - } else if (event->event == HID_DEVICE_DISCONNECTED) { - // Device disconnected - } -} - -// Install HID driver without USB Host and without configuration -static void test_install_hid_driver_without_config(void) -{ - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, hid_host_install(NULL)); -} - -// Install HID driver without USB Host and with configuration -static void test_install_hid_driver_with_wrong_config(void) -{ - const hid_host_driver_config_t hid_host_config_callback_null = { - .create_background_task = true, - .task_priority = 5, - .stack_size = 4096, - .core_id = 0, - .callback = NULL, /* error expected */ - .callback_arg = NULL - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, hid_host_install(&hid_host_config_callback_null)); - - const hid_host_driver_config_t hid_host_config_stack_size_null = { - .create_background_task = true, - .task_priority = 5, - .stack_size = 0, /* error expected */ - .core_id = 0, - .callback = NULL, - .callback_arg = NULL - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, hid_host_install(&hid_host_config_stack_size_null)); - - const hid_host_driver_config_t hid_host_config_task_priority_null = { - .create_background_task = true, - .task_priority = 0,/* error expected */ - .stack_size = 4096, - .core_id = 0, - .callback = NULL, - .callback_arg = NULL - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, hid_host_install(&hid_host_config_task_priority_null)); - - const hid_host_driver_config_t hid_host_config_correct = { - .create_background_task = true, - .task_priority = 5, - .stack_size = 4096, - .core_id = 0, - .callback = test_hid_host_event_callback_stub, - .callback_arg = NULL - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, hid_host_install(&hid_host_config_correct)); -} - -// Open device without installed driver -static void test_claim_interface_without_driver(void) -{ - hid_host_interface_handle_t keyboard_handle; - - - hid_host_interface_config_t keyboard_iface_config_wrong_proto1 = { - .proto = HID_PROTOCOL_NONE, - .callback = NULL, - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, - hid_host_claim_interface(&keyboard_iface_config_wrong_proto1, &keyboard_handle)); - - hid_host_interface_config_t keyboard_iface_config_wrong_proto2 = { - .proto = HID_PROTOCOL_MAX, - .callback = NULL, - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, - hid_host_claim_interface(&keyboard_iface_config_wrong_proto2, &keyboard_handle)); - - /* - hid_host_interface_config_t keyboard_iface_config = { - .proto = HID_PROTOCOL_KEYBOARD, - .callback = NULL, - }; - - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, - hid_host_claim_interface(&keyboard_iface_config, &keyboard_handle)); - */ -} - -// ----------------------- Public -------------------------- - -/** - * @brief HID - * - * There are multiple erroneous scenarios checked in this test: - * - * -# Install HID driver without USB Host - * -# Open device without installed driver - * -# Uninstall driver before installing it - * -# Open non-existent device - * -# Open the same device twice - * -# Uninstall driver with open devices - */ -TEST_CASE("(HID Host) Error handling", "[auto][hid_host]") -{ - for (int i = 0; i < TEST_HID_ERR_HANDLING_CASES; i++) { - (*test_hid_err_handling_case[i])(); - } -} diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_usb_driver.c b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_usb_driver.c deleted file mode 100644 index d4a7f980b8..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/main/test_hid_usb_driver.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "unity.h" -#include "unity_test_utils.h" - -#include "hid_host.h" -#include "test_hid_basic.h" - -// ----------------------- Private ------------------------- -/** - * @brief Test HID Uninstall USB driver with device inserted - * - * - Wait events: DEVICE_DISCONNECTED - * - On DEVICE_DISCONNECTED proceed - */ -void test_hid_usb_uninstall(void) -{ - printf("HID device remain inserted, uninstall device ... "); - test_hid_uninstall_hid_device(test_hid_device); -} - -// ----------------------- Public -------------------------- - - -// ------------------------- USB Test ------------------------------------------ -static void test_setup_hid_usb_driver(void) -{ - test_hid_setup(); -} - -static void test_teardown_hid_usb_driver(void) -{ - test_hid_teardown(); - //Short delay to allow task to be cleaned up - vTaskDelay(pdMS_TO_TICKS(10)); - test_hid_device = NULL; -} - -TEST_CASE("(HID Host) USB uninstall (dev present)", "[hid_host]") -{ - test_setup_hid_usb_driver(); - - test_hid_device = test_hid_wait_connection_and_install(); - test_hid_usb_uninstall(); - test_teardown_hid_usb_driver(); - vTaskDelay(20); -} diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/pytest_hid_basic.py b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/pytest_hid_basic.py deleted file mode 100644 index 8d9c58c9d6..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/pytest_hid_basic.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: Unlicense OR CC0-1.0 - -import pytest -from pytest_embedded_idf.dut import IdfDut - - -@pytest.mark.esp32s2 -@pytest.mark.esp32s3 -def test_hid_basic(dut: IdfDut) -> None: - dut.expect_exact('Press ENTER to see the list of tests') - dut.write('[auto]') - dut.expect_unity_test_output() diff --git a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/sdkconfig.ci.defaults b/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/sdkconfig.ci.defaults deleted file mode 100644 index e0406a0174..0000000000 --- a/examples/peripherals/usb/host/hid/components/hid/test_apps/hid_basic/sdkconfig.ci.defaults +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_ESP_TASK_WDT=n -CONFIG_HEAP_POISONING_COMPREHENSIVE=y -CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y diff --git a/examples/peripherals/usb/host/hid/main/hid_host_example.c b/examples/peripherals/usb/host/hid/main/hid_host_example.c index 1d7639501d..7a37d95e90 100644 --- a/examples/peripherals/usb/host/hid/main/hid_host_example.c +++ b/examples/peripherals/usb/host/hid/main/hid_host_example.c @@ -11,41 +11,46 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" +#include "freertos/queue.h" #include "esp_err.h" #include "esp_log.h" #include "usb/usb_host.h" #include "errno.h" #include "driver/gpio.h" -#include "hid_host.h" -#include "hid_usage_keyboard.h" -#include "hid_usage_mouse.h" +#include "usb/hid_host.h" +#include "usb/hid_usage_keyboard.h" +#include "usb/hid_usage_mouse.h" +/* GPIO Pin number for quit from example logic */ #define APP_QUIT_PIN GPIO_NUM_0 -#define APP_QUIT_PIN_POLL_MS 500 -#define READY_TO_UNINSTALL (HOST_NO_CLIENT | HOST_ALL_FREE) - -/* Main char symbol for ENTER key */ -#define KEYBOARD_ENTER_MAIN_CHAR '\r' -/* When set to 1 pressing ENTER will be extending with LineFeed during serial debug output */ -#define KEYBOARD_ENTER_LF_EXTEND 1 +static const char *TAG = "example"; +QueueHandle_t hid_host_event_queue; +bool user_shutdown = false; /** - * @brief Application Event from USB Host driver + * @brief HID Host event * + * This event is used for delivering the HID Host event from callback to a task. */ -typedef enum { - HOST_NO_CLIENT = 0x1, - HOST_ALL_FREE = 0x2, - DEVICE_CONNECTED = 0x4, - DEVICE_DISCONNECTED = 0x8, - DEVICE_ADDRESS_MASK = 0xFF0, -} app_event_t; +typedef struct { + hid_host_device_handle_t hid_device_handle; + hid_host_driver_event_t event; + void *arg; +} hid_host_event_queue_t; + +/** + * @brief HID Protocol string names + */ +static const char *hid_proto_name_str[] = { + "NONE", + "KEYBOARD", + "MOUSE" +}; /** * @brief Key event - * */ typedef struct { enum key_state { @@ -56,14 +61,10 @@ typedef struct { uint8_t key_code; } key_event_t; -#define USB_EVENTS_TO_WAIT (DEVICE_CONNECTED | DEVICE_ADDRESS_MASK | DEVICE_DISCONNECTED) - -static const char *TAG = "example"; -static EventGroupHandle_t usb_flags; -static bool hid_device_connected = false; - -hid_host_interface_handle_t keyboard_handle = NULL; -hid_host_interface_handle_t mouse_handle = NULL; +/* Main char symbol for ENTER key */ +#define KEYBOARD_ENTER_MAIN_CHAR '\r' +/* When set to 1 pressing ENTER will be extending with LineFeed during serial debug output */ +#define KEYBOARD_ENTER_LF_EXTEND 1 /** * @brief Scancode to ascii table @@ -135,16 +136,17 @@ const uint8_t keycode2ascii [57][2] = { */ static void hid_print_new_device_report_header(hid_protocol_t proto) { - static hid_protocol_t prev_proto_output = HID_PROTOCOL_NONE; + static hid_protocol_t prev_proto_output = -1; if (prev_proto_output != proto) { prev_proto_output = proto; printf("\r\n"); if (proto == HID_PROTOCOL_MOUSE) { printf("Mouse\r\n"); - } - if (proto == HID_PROTOCOL_KEYBOARD) { + } else if (proto == HID_PROTOCOL_KEYBOARD) { printf("Keyboard\r\n"); + } else { + printf("Generic\r\n"); } fflush(stdout); } @@ -160,8 +162,8 @@ static void hid_print_new_device_report_header(hid_protocol_t proto) */ static inline bool hid_keyboard_is_modifier_shift(uint8_t modifier) { - if ((modifier && HID_LEFT_SHIFT) || - (modifier && HID_RIGHT_SHIFT)) { + if (((modifier & HID_LEFT_SHIFT) == HID_LEFT_SHIFT) || + ((modifier & HID_RIGHT_SHIFT) == HID_RIGHT_SHIFT)) { return true; } return false; @@ -324,113 +326,118 @@ static void hid_host_mouse_report_callback(const uint8_t *const data, const int } /** - * @brief USB HID Host event callback. Handle such event as device connection and removing + * @brief USB HID Host Generic Interface report callback handler * - * @param[in] event HID device event - * @param[in] arg Pointer to arguments, does not used + * 'generic' means anything else than mouse or keyboard + * + * @param[in] data Pointer to input report data buffer + * @param[in] length Length of input report data buffer */ -static void hid_host_event_callback(const hid_host_event_t *event, void *arg) +static void hid_host_generic_report_callback(const uint8_t *const data, const int length) { - if (event->event == HID_DEVICE_CONNECTED) { - // Obtained USB device address is placed after application events - xEventGroupSetBits(usb_flags, DEVICE_CONNECTED | (event->device.address << 4)); - } else if (event->event == HID_DEVICE_DISCONNECTED) { - xEventGroupSetBits(usb_flags, DEVICE_DISCONNECTED); + hid_print_new_device_report_header(HID_PROTOCOL_NONE); + for (int i = 0; i < length; i++) { + printf("%02X", data[i]); } + putchar('\r'); } + /** * @brief USB HID Host interface callback * - * @param[in] event HID interface event - * @param[in] arg Pointer to arguments, does not used + * @param[in] hid_device_handle HID Device handle + * @param[in] event HID Host interface event + * @param[in] arg Pointer to arguments, does not used */ -static void hid_host_interface_event_callback(const hid_host_interface_event_t *event, void *arg) +void hid_host_interface_callback(hid_host_device_handle_t hid_device_handle, + const hid_host_interface_event_t event, + void *arg) { - switch (event->event) { - case HID_DEVICE_INTERFACE_INIT: - ESP_LOGI(TAG, "Interface number %d, protocol %s", - event->interface.num, - (event->interface.proto == HID_PROTOCOL_KEYBOARD) - ? "Keyboard" - : "Mouse"); + uint8_t data[64] = { 0 }; + size_t data_length = 0; + hid_host_dev_params_t dev_params; + ESP_ERROR_CHECK( hid_host_device_get_params(hid_device_handle, &dev_params)); - if (event->interface.proto == HID_PROTOCOL_KEYBOARD) { - const hid_host_interface_config_t hid_keyboard_config = { - .proto = HID_PROTOCOL_KEYBOARD, - .callback = hid_host_keyboard_report_callback, - }; + switch (event) { + case HID_HOST_INTERFACE_EVENT_INPUT_REPORT: + ESP_ERROR_CHECK( hid_host_device_get_raw_input_report_data(hid_device_handle, + data, + 64, + &data_length)); - hid_host_claim_interface(&hid_keyboard_config, &keyboard_handle); - } - - if (event->interface.proto == HID_PROTOCOL_MOUSE) { - const hid_host_interface_config_t hid_mouse_config = { - .proto = HID_PROTOCOL_MOUSE, - .callback = hid_host_mouse_report_callback, - }; - - hid_host_claim_interface(&hid_mouse_config, &mouse_handle); + if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) { + if (HID_PROTOCOL_KEYBOARD == dev_params.proto) { + hid_host_keyboard_report_callback(data, data_length); + } else if (HID_PROTOCOL_MOUSE == dev_params.proto) { + hid_host_mouse_report_callback(data, data_length); + } + } else { + hid_host_generic_report_callback(data, data_length); } break; - case HID_DEVICE_INTERFACE_TRANSFER_ERROR: - ESP_LOGD(TAG, "Interface number %d, transfer error", - event->interface.num); + case HID_HOST_INTERFACE_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "HID Device, protocol '%s' DISCONNECTED", + hid_proto_name_str[dev_params.proto]); + ESP_ERROR_CHECK( hid_host_device_close(hid_device_handle) ); break; - - case HID_DEVICE_INTERFACE_CLAIM: - case HID_DEVICE_INTERFACE_RELEASE: - // ... do nothing here for now + case HID_HOST_INTERFACE_EVENT_TRANSFER_ERROR: + ESP_LOGI(TAG, "HID Device, protocol '%s' TRANSFER_ERROR", + hid_proto_name_str[dev_params.proto]); break; - default: - ESP_LOGI(TAG, "%s Unhandled event %X, Interface number %d", - __FUNCTION__, - event->event, - event->interface.num); + ESP_LOGE(TAG, "HID Device, protocol '%s' Unhandled event", + hid_proto_name_str[dev_params.proto]); break; } } /** - * @brief Handle common USB host library events + * @brief USB HID Host Device event * - * @param[in] args Pointer to arguments, does not used + * @param[in] hid_device_handle HID Device handle + * @param[in] event HID Host Device event + * @param[in] arg Pointer to arguments, does not used */ -static void handle_usb_events(void *args) +void hid_host_device_event(hid_host_device_handle_t hid_device_handle, + const hid_host_driver_event_t event, + void *arg) { - while (1) { - uint32_t event_flags; - usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + hid_host_dev_params_t dev_params; + ESP_ERROR_CHECK( hid_host_device_get_params(hid_device_handle, &dev_params)); - // 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) { - xEventGroupSetBits(usb_flags, HOST_ALL_FREE); + switch (event) { + case HID_HOST_DRIVER_EVENT_CONNECTED: + ESP_LOGI(TAG, "HID Device, protocol '%s' CONNECTED", + hid_proto_name_str[dev_params.proto]); + + const hid_host_device_config_t dev_config = { + .callback = hid_host_interface_callback, + .callback_arg = NULL + }; + + ESP_ERROR_CHECK( hid_host_device_open(hid_device_handle, &dev_config) ); + if (HID_SUBCLASS_BOOT_INTERFACE == dev_params.sub_class) { + ESP_ERROR_CHECK( hid_class_request_set_protocol(hid_device_handle, HID_REPORT_PROTOCOL_BOOT)); + if (HID_PROTOCOL_KEYBOARD == dev_params.proto) { + ESP_ERROR_CHECK( hid_class_request_set_idle(hid_device_handle, 0, 0)); + } } + ESP_ERROR_CHECK( hid_host_device_start(hid_device_handle) ); + break; + default: + break; } - - vTaskDelete(NULL); } -static bool wait_for_event(EventBits_t event, TickType_t timeout) +/** + * @brief Start USB Host install and handle common USB host library events while app pin not low + * + * @param[in] arg Not used + */ +static void usb_lib_task(void *arg) { - return xEventGroupWaitBits(usb_flags, event, pdTRUE, pdTRUE, timeout) & event; -} - -void app_main(void) -{ - TaskHandle_t usb_events_task_handle; - hid_host_device_handle_t hid_device; - - BaseType_t task_created; - const gpio_config_t input_pin = { .pin_bit_mask = BIT64(APP_QUIT_PIN), .mode = GPIO_MODE_INPUT, @@ -438,78 +445,129 @@ void app_main(void) }; ESP_ERROR_CHECK( gpio_config(&input_pin) ); - ESP_LOGI(TAG, "HID HOST example"); - - usb_flags = xEventGroupCreate(); - assert(usb_flags); - const usb_host_config_t host_config = { .skip_phy_setup = false, - .intr_flags = ESP_INTR_FLAG_LEVEL1 + .intr_flags = ESP_INTR_FLAG_LEVEL1, }; ESP_ERROR_CHECK( usb_host_install(&host_config) ); - task_created = xTaskCreate(handle_usb_events, "usb_events", 4096, NULL, 2, &usb_events_task_handle); - assert(task_created); + xTaskNotifyGive(arg); - // hid host driver config - const hid_host_driver_config_t hid_host_config = { + while (gpio_get_level(APP_QUIT_PIN) != 0) { + 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(); + 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"); + } + } + // 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 + ESP_ERROR_CHECK( usb_host_uninstall()); + vTaskDelete(NULL); +} + +/** + * @brief HID Host main task + * + * Creates queue and get new event from the queue + * + * @param[in] pvParameters Not used + */ +void hid_host_task(void *pvParameters) +{ + 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); + } + } + + xQueueReset(hid_host_event_queue); + vQueueDelete(hid_host_event_queue); + vTaskDelete(NULL); +} + +/** + * @brief HID Host Device callback + * + * Puts new HID Device event to the queue + * + * @param[in] hid_device_handle HID Device handle + * @param[in] event HID Device event + * @param[in] arg Not used + */ +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 + }; + xQueueSend(hid_host_event_queue, &evt_queue, 0); +} + +void app_main(void) +{ + BaseType_t task_created; + ESP_LOGI(TAG, "HID Host example"); + + /* + * Create usb_lib_task to: + * - initialize USB Host library + * - Handle USB Host events while APP pin in in HIGH state + */ + task_created = xTaskCreatePinnedToCore(usb_lib_task, + "usb_events", + 4096, + xTaskGetCurrentTaskHandle(), + 2, NULL, 0); + assert(task_created == pdTRUE); + + // Wait for notification from usb_lib_task to proceed + ulTaskNotifyTake(false, 1000); + + /* + * HID host driver configuration + * - create background task for handling low level event inside the HID driver + * - provide the device callback to get new HID Device connection event + */ + const hid_host_driver_config_t hid_host_driver_config = { .create_background_task = true, .task_priority = 5, .stack_size = 4096, .core_id = 0, - .callback = hid_host_event_callback, + .callback = hid_host_device_callback, .callback_arg = NULL }; - ESP_ERROR_CHECK( hid_host_install(&hid_host_config) ); + ESP_ERROR_CHECK( hid_host_install(&hid_host_driver_config) ); - do { - EventBits_t event = xEventGroupWaitBits(usb_flags, USB_EVENTS_TO_WAIT, pdTRUE, pdFALSE, pdMS_TO_TICKS(APP_QUIT_PIN_POLL_MS)); + // Task is working until the devices are gone (while 'user_shutdown' if false) + user_shutdown = false; - if (event & DEVICE_CONNECTED) { - xEventGroupClearBits(usb_flags, DEVICE_CONNECTED); - hid_device_connected = true; - } - - if (event & DEVICE_ADDRESS_MASK) { - xEventGroupClearBits(usb_flags, DEVICE_ADDRESS_MASK); - - const hid_host_device_config_t hid_host_device_config = { - .dev_addr = (event & DEVICE_ADDRESS_MASK) >> 4, - .iface_event_cb = hid_host_interface_event_callback, - .iface_event_arg = NULL, - }; - - ESP_ERROR_CHECK( hid_host_install_device(&hid_host_device_config, &hid_device) ); - } - - if (event & DEVICE_DISCONNECTED) { - xEventGroupClearBits(usb_flags, DEVICE_DISCONNECTED); - - hid_host_release_interface(keyboard_handle); - hid_host_release_interface(mouse_handle); - - ESP_ERROR_CHECK( hid_host_uninstall_device(hid_device) ); - - hid_device_connected = false; - } - - } while (gpio_get_level(APP_QUIT_PIN) != 0); - - if (hid_device_connected) { - ESP_LOGI(TAG, "Uninitializing HID Device"); - hid_host_release_interface(keyboard_handle); - hid_host_release_interface(mouse_handle); - ESP_ERROR_CHECK( hid_host_uninstall_device(hid_device) ); - hid_device_connected = false; - } - - ESP_LOGI(TAG, "Uninitializing USB"); - ESP_ERROR_CHECK( hid_host_uninstall() ); - wait_for_event(READY_TO_UNINSTALL, portMAX_DELAY); - ESP_ERROR_CHECK( usb_host_uninstall() ); - vTaskDelete(usb_events_task_handle); - vEventGroupDelete(usb_flags); - ESP_LOGI(TAG, "Done"); + /* + * 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); } diff --git a/examples/peripherals/usb/host/hid/main/idf_component.yml b/examples/peripherals/usb/host/hid/main/idf_component.yml new file mode 100644 index 0000000000..46a1c21a43 --- /dev/null +++ b/examples/peripherals/usb/host/hid/main/idf_component.yml @@ -0,0 +1,4 @@ +## IDF Component Manager Manifest File +dependencies: + idf: ">=4.4" + usb_host_hid: "1.0.0"