From 0d062a6c216fd25a6b887161bed52621bb2e8596 Mon Sep 17 00:00:00 2001 From: Ezra Maccabee Date: Fri, 3 Apr 2026 15:22:41 +0300 Subject: [PATCH] # USB CDC - 1st stage --- bsp/CMakeLists.txt | 1 + bsp/common/include/bsp/status.h | 3 + bsp/usb_cdc/CMakeLists.txt | 18 + bsp/usb_cdc/include/bsp/usb_cdc.h | 100 ++ bsp/usb_cdc/src/fsl_os_abstraction_config.h | 21 + bsp/usb_cdc/src/usb_cdc.c | 664 ++++++++++++ bsp/usb_cdc/src/usb_cdc_descriptors.c | 428 ++++++++ bsp/usb_cdc/src/usb_cdc_hw.c | 97 ++ bsp/usb_cdc/src/usb_device_cdc_acm.h | 86 ++ bsp/usb_cdc/src/usb_device_ch9.c | 1014 +++++++++++++++++++ bsp/usb_cdc/src/usb_device_ch9.h | 86 ++ bsp/usb_cdc/src/usb_device_config.h | 52 + bsp/usb_cdc/src/usb_device_descriptor.h | 116 +++ firmware/test/CMakeLists.txt | 4 +- firmware/test/main.c | 73 +- project_tree.txt | 317 ------ sdk/CMakeLists.txt | 44 + 17 files changed, 2742 insertions(+), 382 deletions(-) create mode 100644 bsp/usb_cdc/include/bsp/usb_cdc.h create mode 100644 bsp/usb_cdc/src/fsl_os_abstraction_config.h create mode 100644 bsp/usb_cdc/src/usb_cdc.c create mode 100644 bsp/usb_cdc/src/usb_cdc_descriptors.c create mode 100644 bsp/usb_cdc/src/usb_cdc_hw.c create mode 100644 bsp/usb_cdc/src/usb_device_cdc_acm.h create mode 100644 bsp/usb_cdc/src/usb_device_ch9.c create mode 100644 bsp/usb_cdc/src/usb_device_ch9.h create mode 100644 bsp/usb_cdc/src/usb_device_config.h create mode 100644 bsp/usb_cdc/src/usb_device_descriptor.h delete mode 100644 project_tree.txt diff --git a/bsp/CMakeLists.txt b/bsp/CMakeLists.txt index ea7ddf8..9de92ce 100644 --- a/bsp/CMakeLists.txt +++ b/bsp/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(uart_host) add_subdirectory(opto) add_subdirectory(can) add_subdirectory(button) +add_subdirectory(usb_cdc) # Подавляем предупреждения при компиляции собственных .c файлов библиотеки target_compile_options(bsp_board PRIVATE -w) diff --git a/bsp/common/include/bsp/status.h b/bsp/common/include/bsp/status.h index acefb42..8a4514d 100644 --- a/bsp/common/include/bsp/status.h +++ b/bsp/common/include/bsp/status.h @@ -39,6 +39,9 @@ typedef enum bsp_status_e BSP_ERR_PARAM = 4, /**< Невалидный аргумент */ BSP_ERR_OVERFLOW = 5, /**< Переполнение буфера, данные потеряны. */ BSP_ERR_NOT_SUPPORTED = 6, /**< Функция не поддерживается */ + BSP_ERR_INVALID = 7, /**< Невалидная операция. */ + BSP_ERR_HW = 8, /**< Ошибки аппаратного стека. */ + BSP_ERR_NOT_READY = 9, /**< Модуль не готов. */ } bsp_status_t; #endif /* BSP_STATUS_H */ \ No newline at end of file diff --git a/bsp/usb_cdc/CMakeLists.txt b/bsp/usb_cdc/CMakeLists.txt index e69de29..fcfe0fd 100644 --- a/bsp/usb_cdc/CMakeLists.txt +++ b/bsp/usb_cdc/CMakeLists.txt @@ -0,0 +1,18 @@ +if(BUILD_TESTS_HOST) + return() +endif() + +add_library(bsp_usb_cdc STATIC src/usb_cdc.c src/usb_cdc_descriptors.c + src/usb_cdc_hw.c src/usb_device_ch9.c) + +target_include_directories( + bsp_usb_cdc + PUBLIC include/ + PRIVATE src/) + +target_link_libraries( + bsp_usb_cdc + PUBLIC bsp_status + PRIVATE bsp_board bsp_tick sdk_usb_device_ehci sdk_usb_phy sdk_osa_bm) + +target_compile_options(bsp_usb_cdc PRIVATE -w) diff --git a/bsp/usb_cdc/include/bsp/usb_cdc.h b/bsp/usb_cdc/include/bsp/usb_cdc.h new file mode 100644 index 0000000..e7c0d11 --- /dev/null +++ b/bsp/usb_cdc/include/bsp/usb_cdc.h @@ -0,0 +1,100 @@ +/* + * Copyright 2025 MU LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_cdc.h + * @brief BSP: USB CDC ACM (Virtual COM Port) на USB1 / EHCI0. + * + * Публичный API без зависимостей от NXP SDK. + * Все USB-специфичные типы и хедеры скрыты в реализации. + */ + +#ifndef BSP_USB_CDC_H_ +#define BSP_USB_CDC_H_ + +#include "bsp/status.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Максимальный размер одной передачи (HS bulk packet). */ +#define BSP_USB_CDC_MAX_PACKET_SIZE (512U) + + /** + * @brief Инициализация USB CDC ACM (USB1 / EHCI0). + * + * Включает тактирование USB PHY 480 MHz, инициализирует EHCI контроллер, + * регистрирует CDC ACM дескрипторы и запускает USB device stack. + * + * @pre board_hw_init() вызван (MPU настроен, NonCacheable регион активен). + * + * @return BSP_OK при успехе, BSP_ERR_HW при ошибке инициализациистека. + */ + bsp_status_t bsp_usb_cdc_init(void); + + /** + * @brief Проверить готовность канала (хост открыл COM-порт). + * + * Возвращает true когда USB enumeration завершён и хост установил + * DTR (Data Terminal Ready) через SET_CONTROL_LINE_STATE. + * + * @return true — можно передавать данные, false — хост не подключён. + */ + bool bsp_usb_cdc_is_ready(void); + + /** + * @brief Отправить данные хосту (неблокирующая). + * + * Копирует данные во внутренний TX буфер (NonCacheable OCRAM) + * и ставит в очередь USB IN transfer. + * + * @param data Указатель на данные. + * @param len Количество байт, 0 < len <= BSP_USB_CDC_MAX_PACKET_SIZE. + * + * @return BSP_OK — transfer поставлен в очередь. + * @return BSP_ERR_BUSY — предыдущий transfer не завершён. + * @return BSP_ERR_NOT_READY — хост не подключён или USB не инициализирован. + * @return BSP_ERR_INVALID — data == NULL или len == 0 или len слишком велик. + */ + bsp_status_t bsp_usb_cdc_write(const uint8_t *p_data, size_t len); + + /** + * @brief Готов ли TX канал к следующей отправке. + * + * @return true — можно вызывать bsp_usb_cdc_write(). + */ + bool bsp_usb_cdc_write_ready(void); + + /** + * @brief Прочитать данные от хоста (неблокирующая). + * + * Забирает данные из внутреннего RX буфера, заполненного USB OUT + * callback. Автоматически перепланирует следующий OUT transfer. + * + * @param buf Буфер для приёма. + * @param max_len Размер буфера. + * + * @return Количество прочитанных байт (0 если данных нет). + */ + size_t bsp_usb_cdc_read(uint8_t *p_buf, size_t max_len); + + /** + * @brief Поллинг USB стека — вызывать из main loop (bare-metal). + * + * Для FreeRTOS не нужен если USB_DEVICE_CONFIG_USE_TASK = 1. + */ + void bsp_usb_cdc_poll(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BSP_USB_CDC_H_ */ \ No newline at end of file diff --git a/bsp/usb_cdc/src/fsl_os_abstraction_config.h b/bsp/usb_cdc/src/fsl_os_abstraction_config.h new file mode 100644 index 0000000..9c7d0de --- /dev/null +++ b/bsp/usb_cdc/src/fsl_os_abstraction_config.h @@ -0,0 +1,21 @@ +/* + * Copyright 2025 TFT Project + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file fsl_os_abstraction_config.h + * @brief Конфигурация OSA bare-metal для bsp_usb_cdc. + * + * NXP OSA подключает этот файл через include path. + * Настройки под bare-metal (без FreeRTOS). + */ +#ifndef FSL_OS_ABSTRACTION_CONFIG_H_ +#define FSL_OS_ABSTRACTION_CONFIG_H_ + +#define gMainThreadStackSize_c (1024U) +#define gMainThreadPriority_c (7U) +#define gTaskMultipleInstancesManagement_c (0U) +#define FSL_OSA_ALLOCATED_HEAP (1U) + +#endif /* FSL_OS_ABSTRACTION_CONFIG_H_ */ \ No newline at end of file diff --git a/bsp/usb_cdc/src/usb_cdc.c b/bsp/usb_cdc/src/usb_cdc.c new file mode 100644 index 0000000..e634677 --- /dev/null +++ b/bsp/usb_cdc/src/usb_cdc.c @@ -0,0 +1,664 @@ +/* + * Copyright 2025 MU LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_cdc.c + * @brief BSP USB CDC ACM — реализация публичного API и NXP callbacks. + * + * Архитектура: + * - Публичные функции bsp_usb_cdc_*() — вызываются приложением. + * - USB_Device*() callbacks — вызываются NXP USB стеком из ISR контекста. + * - Данные между ISR и main loop синхронизируются через volatile флаги + * и DisableGlobalIRQ/EnableGlobalIRQ (bare-metal critical section). + * + * Все DMA-буферы размещены в NonCacheable OCRAM через USB_DMA_*_ALIGN макросы. + */ + +#include "bsp/usb_cdc.h" + +#include "bsp/tick.h" +#include "fsl_common.h" +#include "usb.h" +#include "usb_device.h" +#include "usb_device_cdc_acm.h" +#include "usb_device_ch9.h" +#include "usb_device_config.h" +#include "usb_device_descriptor.h" + +#include + +/* ======================================================================== + * Внутренние определения + * ======================================================================== */ + +#define CONTROLLER_ID kUSB_ControllerEhci0 + +/** Размер bulk-буферов. При HS = 512, при FS = 64. Аллоцируем под HS. */ +#define DATA_BUFF_SIZE HS_CDC_VCOM_BULK_OUT_PACKET_SIZE + +/** Line coding defaults (115200 8N1). */ +#define LINE_CODING_DTERATE (115200U) +#define LINE_CODING_CHARFORMAT (0x00U) +#define LINE_CODING_PARITYTYPE (0x00U) +#define LINE_CODING_DATABITS (0x08U) +#define LINE_CODING_SIZE (7U) + +#define COMM_FEATURE_DATA_SIZE (2U) +#define STATUS_ABSTRACT_STATE (0x0000U) +#define COUNTRY_SETTING (0x0000U) + +#define NOTIF_PACKET_SIZE (8U) +#define UART_BITMAP_SIZE (2U) +#define NOTIF_REQUEST_TYPE (0xA1U) + +/** Задержка после USB_DeviceRun для стабилизации DP pull-down (мкс). */ +#define USB_ATTACH_DELAY_US (5000U) +#define USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF (0x20U) +/* ======================================================================== + * Состояние устройства + * ======================================================================== */ + +/** Глобальный handle — используется IRQ handler в usb_cdc_hw.c. */ +usb_device_handle g_usbDeviceHandle = NULL; + +/** Информация о состоянии ACM (serial state notification). */ +typedef struct +{ + uint8_t serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE]; + bool dtePresent; + uint16_t breakDuration; + uint8_t dteStatus; + uint8_t currentInterface; + uint16_t uartState; +} usb_cdc_acm_info_t; + +/** Внутреннее состояние CDC. */ +static struct +{ + volatile uint8_t attach; /**< 1 = USB enumeration done. */ + volatile uint8_t startTransactions; /**< 1 = DTE present, can TX/RX. */ + uint8_t speed; /**< USB_SPEED_HIGH / _FULL. */ + uint8_t currentConfiguration; + uint8_t currentInterfaceAlt[USB_CDC_VCOM_INTERFACE_COUNT]; + uint8_t hasSentState; /**< Serial state notification sent. */ +} s_cdcState; + +/* ======================================================================== + * DMA-aligned буферы (NonCacheable OCRAM) + * ======================================================================== */ + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_lineCoding[LINE_CODING_SIZE] = { + (LINE_CODING_DTERATE >> 0U) & 0xFFU, + (LINE_CODING_DTERATE >> 8U) & 0xFFU, + (LINE_CODING_DTERATE >> 16U) & 0xFFU, + (LINE_CODING_DTERATE >> 24U) & 0xFFU, + LINE_CODING_CHARFORMAT, + LINE_CODING_PARITYTYPE, + LINE_CODING_DATABITS, +}; + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_abstractState[COMM_FEATURE_DATA_SIZE] = { + (STATUS_ABSTRACT_STATE >> 0U) & 0xFFU, + (STATUS_ABSTRACT_STATE >> 8U) & 0xFFU, +}; + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_countryCode[COMM_FEATURE_DATA_SIZE] = { + (COUNTRY_SETTING >> 0U) & 0xFFU, + (COUNTRY_SETTING >> 8U) & 0xFFU, +}; + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static usb_cdc_acm_info_t s_usbCdcAcmInfo; + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_recvBuf[DATA_BUFF_SIZE]; + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_sendBuf[DATA_BUFF_SIZE]; + +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +static uint8_t s_setupOutBuffer[8]; + +/** Количество полученных байт (0 = нет данных, заполняется в ISR). */ +static volatile uint32_t s_recvSize = 0U; + +/** Количество байт для отправки (0 = idle). */ +static volatile uint32_t s_sendSize = 0U; + +/** Текущий max packet size (обновляется при смене скорости). */ +static uint32_t s_bulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + +/** TX transfer завершён (1 = можно отправлять следующий). */ +static volatile uint8_t s_txIdle = 1U; + +/* ======================================================================== + * Прототипы внешних функций (usb_cdc_hw.c) + * ======================================================================== */ + +extern void USB_DeviceClockInit(void); +extern void USB_DeviceIsrEnable(void); + +/* ======================================================================== + * USB Endpoint Callbacks (вызываются из ISR контекста) + * ======================================================================== */ + +static usb_status_t +USB_DeviceCdcAcmInterruptIn(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + (void) handle; + (void) message; + (void) callbackParam; + s_cdcState.hasSentState = 0U; + return kStatus_USB_Error; +} + +static usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + (void) callbackParam; + usb_status_t error = kStatus_USB_Error; + + if ((message->length != 0U) && (0U == (message->length % s_bulkMaxPacketSize))) + { + /* Отправить ZLP чтобы хост понял что передача завершена. */ + error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_BULK_IN_ENDPOINT, NULL, 0U); + } + else if ((1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions)) + { + if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0U))) + { + s_txIdle = 1U; + /* TX завершён — готовы к следующей отправке. */ + error = kStatus_USB_Success; + } + } + else + { + /* no action */ + } + + return error; +} + +static usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + (void) handle; + (void) callbackParam; + + if ((1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions)) + { + s_recvSize = message->length; + + if (0U == s_recvSize) + { + /* Хост послал ZLP — сразу планируем следующий приём. */ + USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf, + s_bulkMaxPacketSize); + } + + return kStatus_USB_Success; + } + + return kStatus_USB_Error; +} + +/* ======================================================================== + * USB Device Callbacks (вызываются стеком) + * ======================================================================== */ + +usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer) +{ + (void) handle; + static uint32_t s_setupBuf[2]; + + if (setupBuffer == NULL) + { + return kStatus_USB_InvalidParameter; + } + *setupBuffer = (usb_setup_struct_t *) &s_setupBuf; + return kStatus_USB_Success; +} + +usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle, usb_setup_struct_t *setup, + uint32_t *length, uint8_t **buffer) +{ + (void) handle; + (void) setup; + + if ((buffer == NULL) || ((*length) > sizeof(s_setupOutBuffer))) + { + return kStatus_USB_InvalidRequest; + } + *buffer = s_setupOutBuffer; + return kStatus_USB_Success; +} + +usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable) +{ + (void) handle; + (void) enable; + return kStatus_USB_InvalidRequest; +} + +usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status) +{ + if (status != 0U) + { + return USB_DeviceStallEndpoint(handle, ep); + } + return USB_DeviceUnstallEndpoint(handle, ep); +} + +/* ---- CDC Class-Specific Request Handler ---- */ + +usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, usb_setup_struct_t *setup, + uint32_t *length, uint8_t **buffer) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + usb_cdc_acm_info_t *acmInfo = &s_usbCdcAcmInfo; + uint32_t len; + uint8_t *uartBitmap; + + if (setup->wIndex != USB_CDC_VCOM_COMM_INTERFACE_INDEX) + { + return error; + } + + switch (setup->bRequest) + { + case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND: + case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE: + case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE: + case USB_DEVICE_CDC_REQUEST_SEND_BREAK: + break; + + case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE: + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) && + (setup->wLength != 0U)) + { + if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) + { + (void) memcpy(s_abstractState, *buffer, COMM_FEATURE_DATA_SIZE); + error = kStatus_USB_Success; + } + else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) + { + (void) memcpy(s_countryCode, *buffer, COMM_FEATURE_DATA_SIZE); + error = kStatus_USB_Success; + } + else + { + /* no action */ + } + } + break; + + case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE: + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) && + (setup->wLength != 0U)) + { + if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) + { + *buffer = s_abstractState; + *length = COMM_FEATURE_DATA_SIZE; + error = kStatus_USB_Success; + } + else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) + { + *buffer = s_countryCode; + *length = COMM_FEATURE_DATA_SIZE; + error = kStatus_USB_Success; + } + else + { + /* no action */ + } + } + break; + + case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING: + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN) && + (setup->wLength != 0U)) + { + *buffer = s_lineCoding; + *length = LINE_CODING_SIZE; + error = kStatus_USB_Success; + } + break; + + case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING: + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) && + (setup->wLength != 0U)) + { + (void) memcpy(s_lineCoding, *buffer, LINE_CODING_SIZE); + error = kStatus_USB_Success; + } + break; + + case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE: + { + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) && + (setup->wLength == 0U)) + { + error = kStatus_USB_Success; + acmInfo->dteStatus = setup->wValue; + + /* TX carrier */ + if ((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) != 0U) + { + acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER; + } + else + { + acmInfo->uartState &= (uint16_t) ~USB_DEVICE_CDC_UART_STATE_TX_CARRIER; + } + + /* RX carrier (DTE presence) */ + if ((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) != 0U) + { + acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER; + } + else + { + acmInfo->uartState &= (uint16_t) ~USB_DEVICE_CDC_UART_STATE_RX_CARRIER; + } + + acmInfo->dtePresent = + ((acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) != 0U); + + /* Формируем serial state notification */ + acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE; + acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF; + acmInfo->serialStateBuf[2] = 0x00U; + acmInfo->serialStateBuf[3] = 0x00U; + acmInfo->serialStateBuf[4] = (uint8_t) setup->wIndex; + acmInfo->serialStateBuf[5] = 0x00U; + acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; + acmInfo->serialStateBuf[7] = 0x00U; + + uartBitmap = &acmInfo->serialStateBuf[NOTIF_PACKET_SIZE]; + uartBitmap[0] = (uint8_t) (acmInfo->uartState & 0xFFU); + uartBitmap[1] = (uint8_t) ((acmInfo->uartState >> 8U) & 0xFFU); + + len = (uint32_t) (NOTIF_PACKET_SIZE + UART_BITMAP_SIZE); + if (0U == s_cdcState.hasSentState) + { + error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT, + acmInfo->serialStateBuf, len); + if (kStatus_USB_Success == error) + { + s_cdcState.hasSentState = 1U; + } + } + + if (1U == s_cdcState.attach) + { + s_cdcState.startTransactions = 1U; + } + } + break; + } + + default: + break; + } + + return error; +} + +/* ---- USB_DeviceCallback (bus reset, set configuration) ---- */ + +usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t *temp8 = (uint8_t *) param; + + switch (event) + { + case kUSB_DeviceEventBusReset: + { + USB_DeviceControlPipeInit(handle); + s_cdcState.attach = 0U; + s_cdcState.currentConfiguration = 0U; + s_txIdle = 1U; + s_recvSize = 0U; + s_sendSize = 0U; + error = kStatus_USB_Success; + + if (kStatus_USB_Success == + USB_DeviceGetStatus(handle, kUSB_DeviceStatusSpeed, &s_cdcState.speed)) + { + USB_DeviceSetSpeed(handle, s_cdcState.speed); + } + break; + } + + case kUSB_DeviceEventSetConfiguration: + { + if (0U == (*temp8)) + { + s_cdcState.attach = 0U; + s_cdcState.currentConfiguration = 0U; + s_cdcState.startTransactions = 0U; + error = kStatus_USB_Success; + } + else if (USB_CDC_VCOM_CONFIGURE_INDEX == (*temp8)) + { + usb_device_endpoint_init_struct_t epInit; + usb_device_endpoint_callback_struct_t epCb; + + s_cdcState.attach = 1U; + s_cdcState.currentConfiguration = *temp8; + + /* Interrupt IN endpoint */ + epCb.callbackFn = USB_DeviceCdcAcmInterruptIn; + epCb.callbackParam = handle; + epInit.zlt = 0U; + epInit.transferType = USB_ENDPOINT_INTERRUPT; + epInit.endpointAddress = USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + + if (USB_SPEED_HIGH == s_cdcState.speed) + { + epInit.maxPacketSize = HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE; + epInit.interval = HS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + } + else + { + epInit.maxPacketSize = FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE; + epInit.interval = FS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + } + USB_DeviceInitEndpoint(handle, &epInit, &epCb); + + /* Bulk IN endpoint */ + epCb.callbackFn = USB_DeviceCdcAcmBulkIn; + epCb.callbackParam = handle; + epInit.zlt = 0U; + epInit.interval = 0U; + epInit.transferType = USB_ENDPOINT_BULK; + epInit.endpointAddress = USB_CDC_VCOM_BULK_IN_ENDPOINT | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + + if (USB_SPEED_HIGH == s_cdcState.speed) + { + epInit.maxPacketSize = HS_CDC_VCOM_BULK_IN_PACKET_SIZE; + } + else + { + epInit.maxPacketSize = FS_CDC_VCOM_BULK_IN_PACKET_SIZE; + } + USB_DeviceInitEndpoint(handle, &epInit, &epCb); + + /* Bulk OUT endpoint */ + epCb.callbackFn = USB_DeviceCdcAcmBulkOut; + epCb.callbackParam = handle; + epInit.zlt = 0U; + epInit.interval = 0U; + epInit.transferType = USB_ENDPOINT_BULK; + epInit.endpointAddress = USB_CDC_VCOM_BULK_OUT_ENDPOINT | + (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + + if (USB_SPEED_HIGH == s_cdcState.speed) + { + epInit.maxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + s_bulkMaxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + else + { + epInit.maxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + s_bulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + USB_DeviceInitEndpoint(handle, &epInit, &epCb); + + /* Планируем первый OUT transfer */ + error = USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf, + s_bulkMaxPacketSize); + } + else + { + /* unknown configuration */ + } + break; + } + + case kUSB_DeviceEventSetInterface: + error = kStatus_USB_Success; + break; + + default: + break; + } + + return error; +} + +/* ======================================================================== + * Публичный API (BSP) + * ======================================================================== */ + +bsp_status_t bsp_usb_cdc_init(void) +{ + s_cdcState.speed = USB_SPEED_FULL; + s_cdcState.attach = 0U; + s_cdcState.startTransactions = 0U; + s_cdcState.hasSentState = 0U; + s_cdcState.currentConfiguration = 0U; + s_txIdle = 1U; + g_usbDeviceHandle = NULL; + + USB_DeviceClockInit(); + + if (kStatus_USB_Success != + USB_DeviceInit(CONTROLLER_ID, USB_DeviceCallback, &g_usbDeviceHandle)) + { + return BSP_ERR_HW; + } + + USB_DeviceIsrEnable(); + + /* FIXME:Задержка для стабилизации DP pull-down. */ + //SDK_DelayAtLeastUs(USB_ATTACH_DELAY_US, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); + bsp_delay(USB_ATTACH_DELAY_US / 1000); + USB_DeviceRun(g_usbDeviceHandle); + + return BSP_OK; +} + +bool bsp_usb_cdc_is_ready(void) +{ + return (1U == s_cdcState.attach) && (1U == s_cdcState.startTransactions); +} + +bool bsp_usb_cdc_write_ready(void) +{ + return bsp_usb_cdc_is_ready() && (1U == s_txIdle); +} + +bsp_status_t bsp_usb_cdc_write(const uint8_t *data, size_t len) +{ + if ((data == NULL) || (len == 0U) || (len > DATA_BUFF_SIZE)) + { + return BSP_ERR_INVALID; + } + + if (!bsp_usb_cdc_is_ready()) + { + return BSP_ERR_NOT_READY; + } + + if (0U == s_txIdle) + { + return BSP_ERR_BUSY; + } + + /* Копируем в NonCacheable TX буфер и запускаем transfer. */ + (void) memcpy(s_sendBuf, data, len); + + s_txIdle = 0U; + + usb_status_t status = USB_DeviceSendRequest(g_usbDeviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, + s_sendBuf, (uint32_t) len); + + if (kStatus_USB_Success != status) + { + s_txIdle = 1U; + return BSP_ERR_HW; + } + + return BSP_OK; +} + +size_t bsp_usb_cdc_read(uint8_t *buf, size_t max_len) +{ + if ((buf == NULL) || (max_len == 0U)) + { + return 0U; + } + + if (!bsp_usb_cdc_is_ready()) + { + return 0U; + } + + uint32_t sr; + uint32_t available = 0U; + + sr = DisableGlobalIRQ(); + if ((s_recvSize != 0U) && (s_recvSize != USB_CANCELLED_TRANSFER_LENGTH)) + { + available = s_recvSize; + s_recvSize = 0U; + } + EnableGlobalIRQ(sr); + + if (available == 0U) + { + return 0U; + } + + size_t to_copy = (available > (uint32_t) max_len) ? max_len : (size_t) available; + (void) memcpy(buf, s_recvBuf, to_copy); + + /* Перепланируем приём следующего пакета. */ + USB_DeviceRecvRequest(g_usbDeviceHandle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_recvBuf, + s_bulkMaxPacketSize); + + return to_copy; +} + +void bsp_usb_cdc_poll(void) +{ + /* Bare-metal: NXP USB стек на EHCI обрабатывает всё в ISR. + * Эта функция зарезервирована для будущего использования + * (USB_DEVICE_CONFIG_USE_TASK или software event processing). */ +} \ No newline at end of file diff --git a/bsp/usb_cdc/src/usb_cdc_descriptors.c b/bsp/usb_cdc/src/usb_cdc_descriptors.c new file mode 100644 index 0000000..d4864bd --- /dev/null +++ b/bsp/usb_cdc/src/usb_cdc_descriptors.c @@ -0,0 +1,428 @@ +/* + * Copyright 2025 MU LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_cdc_descriptors.c + * @brief USB CDC ACM дескрипторы и descriptor callbacks. + * + * Содержит device/configuration/string дескрипторы и функции + * которые NXP USB стек вызывает для получения дескрипторов при + * enumeration. Также USB_DeviceSetSpeed() для обновления + * дескрипторов при переключении HS/FS. + */ + +#include "usb.h" +#include "usb_device.h" +#include "usb_device_config.h" +#include "usb_device_descriptor.h" + +#include + +/* ======================================================================== + * Глобальное состояние (используется ch9 callbacks) + * ======================================================================== */ + +uint8_t g_currentConfigure = 0U; +uint8_t g_interface[USB_CDC_VCOM_INTERFACE_COUNT]; + +/* ======================================================================== + * Device Descriptor + * ======================================================================== */ + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +uint8_t g_UsbDeviceDescriptor[] = { + USB_DESCRIPTOR_LENGTH_DEVICE, + USB_DESCRIPTOR_TYPE_DEVICE, + USB_SHORT_GET_LOW(USB_DEVICE_SPECIFIC_BCD_VERSION), + USB_SHORT_GET_HIGH(USB_DEVICE_SPECIFIC_BCD_VERSION), + USB_DEVICE_CLASS, + USB_DEVICE_SUBCLASS, + USB_DEVICE_PROTOCOL, + USB_CONTROL_MAX_PACKET_SIZE, + USB_SHORT_GET_LOW(USB_DEVICE_VID), + USB_SHORT_GET_HIGH(USB_DEVICE_VID), + USB_SHORT_GET_LOW(USB_DEVICE_PID), + USB_SHORT_GET_HIGH(USB_DEVICE_PID), + USB_SHORT_GET_LOW(USB_DEVICE_DEMO_BCD_VERSION), + USB_SHORT_GET_HIGH(USB_DEVICE_DEMO_BCD_VERSION), + 0x01U, /* iManufacturer */ + 0x02U, /* iProduct */ + 0x00U, /* iSerialNumber */ + USB_DEVICE_CONFIGURATION_COUNT, +}; + +/* ======================================================================== + * Configuration Descriptor (CIC + DIC) + * ======================================================================== */ + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +uint8_t g_UsbDeviceConfigurationDescriptor[] = { + /* --- Configuration --- */ + USB_DESCRIPTOR_LENGTH_CONFIGURE, + USB_DESCRIPTOR_TYPE_CONFIGURE, + USB_SHORT_GET_LOW(USB_DESCRIPTOR_LENGTH_CONFIGURE + USB_DESCRIPTOR_LENGTH_INTERFACE + + USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC + USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG + + USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT + USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC + + USB_DESCRIPTOR_LENGTH_ENDPOINT + USB_DESCRIPTOR_LENGTH_INTERFACE + + USB_DESCRIPTOR_LENGTH_ENDPOINT + USB_DESCRIPTOR_LENGTH_ENDPOINT), + USB_SHORT_GET_HIGH(USB_DESCRIPTOR_LENGTH_CONFIGURE + USB_DESCRIPTOR_LENGTH_INTERFACE + + USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC + + USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG + USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT + + USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC + USB_DESCRIPTOR_LENGTH_ENDPOINT + + USB_DESCRIPTOR_LENGTH_INTERFACE + USB_DESCRIPTOR_LENGTH_ENDPOINT + + USB_DESCRIPTOR_LENGTH_ENDPOINT), + USB_CDC_VCOM_INTERFACE_COUNT, + USB_CDC_VCOM_CONFIGURE_INDEX, + 0x00U, /* iConfiguration */ + (USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK) | + (1U << USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT), + USB_DEVICE_MAX_POWER, + + /* --- CIC: Communication Interface --- */ + USB_DESCRIPTOR_LENGTH_INTERFACE, + USB_DESCRIPTOR_TYPE_INTERFACE, + USB_CDC_VCOM_COMM_INTERFACE_INDEX, + USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_0, + USB_CDC_VCOM_ENDPOINT_CIC_COUNT, + USB_CDC_VCOM_CIC_CLASS, + USB_CDC_VCOM_CIC_SUBCLASS, + USB_CDC_VCOM_CIC_PROTOCOL, + 0x00U, + + /* --- CDC Header Functional Descriptor --- */ + USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC, + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, + USB_CDC_HEADER_FUNC_DESC, + 0x10U, + 0x01U, + + /* --- CDC Call Management Functional Descriptor --- */ + USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG, + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, + USB_CDC_CALL_MANAGEMENT_FUNC_DESC, + 0x01U, + 0x01U, + + /* --- CDC ACM Functional Descriptor --- */ + USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT, + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, + USB_CDC_ABSTRACT_CONTROL_FUNC_DESC, + 0x06U, + + /* --- CDC Union Functional Descriptor --- */ + USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC, + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, + USB_CDC_UNION_FUNC_DESC, + USB_CDC_VCOM_COMM_INTERFACE_INDEX, + USB_CDC_VCOM_DATA_INTERFACE_INDEX, + + /* --- Notification Endpoint (Interrupt IN) --- */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, + USB_DESCRIPTOR_TYPE_ENDPOINT, + USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT | (USB_IN << 7U), + USB_ENDPOINT_INTERRUPT, + USB_SHORT_GET_LOW(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE), + FS_CDC_VCOM_INTERRUPT_IN_INTERVAL, + + /* --- DIC: Data Interface --- */ + USB_DESCRIPTOR_LENGTH_INTERFACE, + USB_DESCRIPTOR_TYPE_INTERFACE, + USB_CDC_VCOM_DATA_INTERFACE_INDEX, + USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_0, + USB_CDC_VCOM_ENDPOINT_DIC_COUNT, + USB_CDC_VCOM_DIC_CLASS, + USB_CDC_VCOM_DIC_SUBCLASS, + USB_CDC_VCOM_DIC_PROTOCOL, + 0x00U, + + /* --- Bulk IN Endpoint --- */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, + USB_DESCRIPTOR_TYPE_ENDPOINT, + USB_CDC_VCOM_BULK_IN_ENDPOINT | (USB_IN << 7U), + USB_ENDPOINT_BULK, + USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_IN_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_IN_PACKET_SIZE), + 0x00U, + + /* --- Bulk OUT Endpoint --- */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, + USB_DESCRIPTOR_TYPE_ENDPOINT, + USB_CDC_VCOM_BULK_OUT_ENDPOINT | (USB_OUT << 7U), + USB_ENDPOINT_BULK, + USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE), + 0x00U, +}; + +/* ======================================================================== + * String Descriptors + * ======================================================================== */ + +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +uint8_t g_UsbDeviceString0[] = { + 2U + 2U, USB_DESCRIPTOR_TYPE_STRING, 0x09U, 0x04U, /* English (US) */ +}; + +/* Manufacturer: "MU LLC" */ +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +uint8_t g_UsbDeviceString1[] = { + 2U + 2U * 6U, USB_DESCRIPTOR_TYPE_STRING, + 'M', 0x00U, + 'U', 0x00U, + ' ', 0x00U, + 'L', 0x00U, + 'L', 0x00U, + 'C', 0x00U, +}; + +/* Product: "TFT Indicator Board" */ +USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) +uint8_t g_UsbDeviceString2[] = { + 2U + 2U * 19U, USB_DESCRIPTOR_TYPE_STRING, + 'T', 0x00U, + 'F', 0x00U, + 'T', 0x00U, + ' ', 0x00U, + 'I', 0x00U, + 'n', 0x00U, + 'd', 0x00U, + 'i', 0x00U, + 'c', 0x00U, + 'a', 0x00U, + 't', 0x00U, + 'o', 0x00U, + 'r', 0x00U, + ' ', 0x00U, + 'B', 0x00U, + 'o', 0x00U, + 'a', 0x00U, + 'r', 0x00U, + 'd', 0x00U, +}; + +/* ======================================================================== + * Language / String List (используется USB_DeviceGetDescriptor) + * ======================================================================== */ +/* Массивы строк и длин — индексируются по (stringIndex - 1) */ +static uint8_t *g_UsbDeviceStringDescriptorArray[USB_DEVICE_STRING_COUNT] = { + g_UsbDeviceString0, + g_UsbDeviceString1, + g_UsbDeviceString2, +}; + +static uint32_t g_UsbDeviceStringDescriptorLength[USB_DEVICE_STRING_COUNT] = { + sizeof(g_UsbDeviceString0), + sizeof(g_UsbDeviceString1), + sizeof(g_UsbDeviceString2), +}; + +usb_language_t g_UsbDeviceLanguage[USB_DEVICE_LANGUAGE_COUNT] = { { + g_UsbDeviceStringDescriptorArray, + g_UsbDeviceStringDescriptorLength, + (uint16_t) 0x0409U, +} }; + +usb_language_list_t g_UsbDeviceLanguageList = { + g_UsbDeviceString0, + sizeof(g_UsbDeviceString0), + g_UsbDeviceLanguage, + USB_DEVICE_LANGUAGE_COUNT, +}; + +/* ======================================================================== + * Descriptor Callbacks — вызываются NXP USB стеком + * ======================================================================== */ + +usb_status_t USB_DeviceGetDescriptor(usb_device_handle handle, usb_setup_struct_t *setup, + uint32_t *length, uint8_t **buffer) +{ + uint8_t descriptorType = (uint8_t) ((setup->wValue & 0xFF00U) >> 8U); + uint8_t descriptorIndex = (uint8_t) ((setup->wValue & 0x00FFU)); + usb_status_t ret = kStatus_USB_Success; + + if (USB_REQUEST_STANDARD_GET_DESCRIPTOR != setup->bRequest) + { + return kStatus_USB_InvalidRequest; + } + + switch (descriptorType) + { + case USB_DESCRIPTOR_TYPE_STRING: + { + if (descriptorIndex == 0U) + { + *buffer = (uint8_t *) g_UsbDeviceLanguageList.languageString; + *length = g_UsbDeviceLanguageList.stringLength; + } + else + { + uint8_t langId = USB_DEVICE_LANGUAGE_COUNT; + + for (uint8_t i = 0U; i < USB_DEVICE_LANGUAGE_COUNT; i++) + { + if (setup->wIndex == g_UsbDeviceLanguageList.languageList[i].languageId) + { + langId = i; + break; + } + } + + if (USB_DEVICE_LANGUAGE_COUNT == langId) + { + ret = kStatus_USB_InvalidRequest; + break; + } + + uint8_t strIdx = descriptorIndex - 1U; + if (strIdx < USB_DEVICE_STRING_COUNT) + { + *buffer = (uint8_t *) g_UsbDeviceLanguageList.languageList[langId].string[strIdx]; + *length = g_UsbDeviceLanguageList.languageList[langId].length[strIdx]; + } + else + { + ret = kStatus_USB_InvalidRequest; + } + } + break; + } + case USB_DESCRIPTOR_TYPE_DEVICE: + { + *buffer = g_UsbDeviceDescriptor; + *length = USB_DESCRIPTOR_LENGTH_DEVICE; + break; + } + case USB_DESCRIPTOR_TYPE_CONFIGURE: + { + *buffer = g_UsbDeviceConfigurationDescriptor; + *length = USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL; + break; + } + default: + ret = kStatus_USB_InvalidRequest; + break; + } + + return ret; +} + +/* ---- Chapter 9: Set/Get Configure/Interface ---- */ + +usb_status_t USB_DeviceSetConfigure(usb_device_handle handle, uint8_t cfg) +{ + if (cfg == 0U) + { + return kStatus_USB_Error; + } + g_currentConfigure = cfg; + return USB_DeviceCallback(handle, kUSB_DeviceEventSetConfiguration, &cfg); +} + +usb_status_t USB_DeviceGetConfigure(usb_device_handle handle, uint8_t *cfg) +{ + *cfg = g_currentConfigure; + return kStatus_USB_Success; +} + +usb_status_t USB_DeviceSetInterface(usb_device_handle handle, uint8_t iface, uint8_t alt) +{ + if (iface < USB_CDC_VCOM_INTERFACE_COUNT) + { + g_interface[iface] = alt; + return USB_DeviceCallback(handle, kUSB_DeviceEventSetInterface, &iface); + } + return kStatus_USB_InvalidRequest; +} + +usb_status_t USB_DeviceGetInterface(usb_device_handle handle, uint8_t iface, uint8_t *alt) +{ + if (iface < USB_CDC_VCOM_INTERFACE_COUNT) + { + *alt = g_interface[iface]; + return kStatus_USB_Success; + } + return kStatus_USB_InvalidRequest; +} + +/* ---- USB_DeviceSetSpeed ---- */ + +usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed) +{ + usb_descriptor_union_t *ptr1; + usb_descriptor_union_t *ptr2; + + ptr1 = (usb_descriptor_union_t *) (&g_UsbDeviceConfigurationDescriptor[0]); + ptr2 = + (usb_descriptor_union_t + *) (&g_UsbDeviceConfigurationDescriptor[USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL - 1U]); + + while (ptr1 < ptr2) + { + if (ptr1->common.bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT) + { + /* Interrupt IN */ + if (((ptr1->endpoint.bEndpointAddress & + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT)) + { + if (USB_SPEED_HIGH == speed) + { + ptr1->endpoint.bInterval = HS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + else + { + ptr1->endpoint.bInterval = FS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + } + /* Bulk IN */ + else if (((ptr1->endpoint.bEndpointAddress & + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_BULK_IN_ENDPOINT)) + { + if (USB_SPEED_HIGH == speed) + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + else + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + } + /* Bulk OUT */ + else if (((ptr1->endpoint.bEndpointAddress & + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((ptr1->endpoint.bEndpointAddress & 0x0FU) == USB_CDC_VCOM_BULK_OUT_ENDPOINT)) + { + if (USB_SPEED_HIGH == speed) + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_OUT_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + else + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + } + else + { + /* other endpoints — no action */ + } + } + ptr1 = (usb_descriptor_union_t *) ((uint8_t *) ptr1 + ptr1->common.bLength); + } + + return kStatus_USB_Success; +} \ No newline at end of file diff --git a/bsp/usb_cdc/src/usb_cdc_hw.c b/bsp/usb_cdc/src/usb_cdc_hw.c new file mode 100644 index 0000000..afa9344 --- /dev/null +++ b/bsp/usb_cdc/src/usb_cdc_hw.c @@ -0,0 +1,97 @@ +/* + * Copyright 2025 MU LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_cdc_hw.c + * @brief Аппаратная инициализация USB1 (EHCI0): clock, PHY, IRQ. + * + * Функции вызываются из usb_cdc.c при инициализации. + * IRQ handler делегирует обработку в NXP USB device stack. + */ + +#include "board.h" +#include "clock_config.h" +#include "usb.h" +#include "usb_device.h" +#include "usb_device_config.h" +#include "usb_phy.h" + +/* -------------------------------------------------------------------------- + * Определения платы (из board.h / schematic) + * -------------------------------------------------------------------------- */ + +/** D_CAL, TXCAL45DP, TXCAL45DM — калибровка USB PHY. */ +#define BOARD_USB_PHY_D_CAL (0x0CU) +#define BOARD_USB_PHY_TXCAL45DP (0x06U) +#define BOARD_USB_PHY_TXCAL45DM (0x06U) + +/** Приоритет USB прерывания (ниже числовое значение = выше приоритет). */ +#define USB_DEVICE_INTERRUPT_PRIORITY (3U) + +/** Контроллер: USB1 = kUSB_ControllerEhci0. */ +#define CONTROLLER_ID kUSB_ControllerEhci0 + +/* -------------------------------------------------------------------------- + * Внешний символ — handle USB device, определён в usb_cdc.c + * -------------------------------------------------------------------------- */ +extern usb_device_handle g_usbDeviceHandle; + +/* -------------------------------------------------------------------------- + * IRQ Handler + * -------------------------------------------------------------------------- */ + +/** + * @brief USB OTG1 IRQ — делегирует в NXP EHCI ISR. + * + * Имя совпадает с вектором прерывания в startup_MIMXRT1052.S. + * Внутри — только вызов SDK функции, без блокировки и аллокаций. + */ +void USB_OTG1_IRQHandler(void) +{ + USB_DeviceEhciIsrFunction(g_usbDeviceHandle); +} + +/* -------------------------------------------------------------------------- + * Clock + PHY + * -------------------------------------------------------------------------- */ + +/** + * @brief Включить тактирование USB1 PHY 480 MHz и инициализировать PHY. + * + * Вызывается один раз из bsp_usb_cdc_init() до USB_DeviceInit(). + */ +void USB_DeviceClockInit(void) +{ + usb_phy_config_struct_t phyConfig = { + BOARD_USB_PHY_D_CAL, + BOARD_USB_PHY_TXCAL45DP, + BOARD_USB_PHY_TXCAL45DM, + }; + + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); + + USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &phyConfig); +} + +/* -------------------------------------------------------------------------- + * NVIC + * -------------------------------------------------------------------------- */ + +/** + * @brief Разрешить USB1 прерывание в NVIC. + * + * Вызывается один раз из bsp_usb_cdc_init() после USB_DeviceInit(). + */ +void USB_DeviceIsrEnable(void) +{ + uint8_t irqNumber; + uint8_t usbDeviceEhciIrq[] = USBHS_IRQS; + + irqNumber = usbDeviceEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0]; + + NVIC_SetPriority((IRQn_Type) irqNumber, USB_DEVICE_INTERRUPT_PRIORITY); + EnableIRQ((IRQn_Type) irqNumber); +} \ No newline at end of file diff --git a/bsp/usb_cdc/src/usb_device_cdc_acm.h b/bsp/usb_cdc/src/usb_device_cdc_acm.h new file mode 100644 index 0000000..803a6cc --- /dev/null +++ b/bsp/usb_cdc/src/usb_device_cdc_acm.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_DEVICE_CDC_ACM_H_ +#define _USB_DEVICE_CDC_ACM_H_ 1 +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_DEVICE_CONFIG_CDC_ACM_MAX_INSTANCE (1) + +#define USB_DEVICE_CONFIG_CDC_COMM_CLASS_CODE (0x02) +#define USB_DEVICE_CONFIG_CDC_DATA_CLASS_CODE (0x0A) + +/* Class specific request Codes */ +#define USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND (0x00) +#define USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE (0x01) +#define USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE (0x02) +#define USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE (0x03) +#define USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE (0x04) +#define USB_DEVICE_CDC_REQUEST_SET_AUX_LINE_STATE (0x10) +#define USB_DEVICE_CDC_REQUEST_SET_HOOK_STATE (0x11) +#define USB_DEVICE_CDC_REQUEST_PULSE_SETUP (0x12) +#define USB_DEVICE_CDC_REQUEST_SEND_PULSE (0x13) +#define USB_DEVICE_CDC_REQUEST_SET_PULSE_TIME (0x14) +#define USB_DEVICE_CDC_REQUEST_RING_AUX_JACK (0x15) +#define USB_DEVICE_CDC_REQUEST_SET_LINE_CODING (0x20) +#define USB_DEVICE_CDC_REQUEST_GET_LINE_CODING (0x21) +#define USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) +#define USB_DEVICE_CDC_REQUEST_SEND_BREAK (0x23) +#define USB_DEVICE_CDC_REQUEST_SET_RINGER_PARAMS (0x30) +#define USB_DEVICE_CDC_REQUEST_GET_RINGER_PARAMS (0x31) +#define USB_DEVICE_CDC_REQUEST_SET_OPERATION_PARAM (0x32) +#define USB_DEVICE_CDC_REQUEST_GET_OPERATION_PARAM (0x33) +#define USB_DEVICE_CDC_REQUEST_SET_LINE_PARAMS (0x34) +#define USB_DEVICE_CDC_REQUEST_GET_LINE_PARAMS (0x35) +#define USB_DEVICE_CDC_REQUEST_DIAL_DIGITS (0x36) +#define USB_DEVICE_CDC_REQUEST_SET_UNIT_PARAMETER (0x37) +#define USB_DEVICE_CDC_REQUEST_GET_UNIT_PARAMETER (0x38) +#define USB_DEVICE_CDC_REQUEST_CLEAR_UNIT_PARAMETER (0x39) +#define USB_DEVICE_CDC_REQUEST_GET_PROFILE (0x3A) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS (0x40) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_POW_PATTER_FILTER (0x41) +#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_POW_PATTER_FILTER (0x42) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_PACKET_FILTER (0x43) +#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_STATISTIC (0x44) +#define USB_DEVICE_CDC_REQUEST_SET_ATM_DATA_FORMAT (0x50) +#define USB_DEVICE_CDC_REQUEST_GET_ATM_DEVICE_STATISTICS (0x51) +#define USB_DEVICE_CDC_REQUEST_SET_ATM_DEFAULT_VC (0x52) +#define USB_DEVICE_CDC_REQUEST_GET_ATM_VC_STATISTICS (0x53) +#define USB_DEVICE_CDC_REQUEST_MDLM_SPECIFIC_REQUESTS_MASK (0x7F) + +#define USB_DEVICE_CDC_REQUEST_GET_ABSTRACT_STATE (0x23) +#define USB_DEVICE_CDC_REQUEST_GET_COUNTRY_SETTING (0x24) +#define USB_DEVICE_CDC_REQUEST_SET_ABSTRACT_STATE (0x25) +#define USB_DEVICE_CDC_REQUEST_SET_COUNTRY_SETTING (0x26) +/* Class Specific Notification Codes */ +#define USB_DEVICE_CDC_REQUEST_NETWORK_CONNECTION_NOTIF (0x00) +#define USB_DEVICE_CDC_REQUEST_RESPONSE_AVAIL_NOTIF (0x01) +#define USB_DEVICE_CDC_REQUEST_AUX_JACK_HOOK_STATE_NOTIF (0x08) +#define USB_DEVICE_CDC_REQUEST_RING_DETECT_NOTIF (0x09) +#define USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF (0x20) +#define USB_DEVICE_CDC_REQUEST_CALL_STATE_CHANGE_NOTIF (0x28) +#define USB_DEVICE_CDC_REQUEST_LINE_STATE_CHANGE_NOTIF (0x29) +#define USB_DEVICE_CDC_REQUEST_CONNECTION_SPEED_CHANGE_NOTIF (0x2A) +/* Communications Feature Selector Codes */ +#define USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE (0x01) +#define USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING (0x02) +/* Control Signal Bitmap Values */ +#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION (0x02) +#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE (0x01) +/* UART State Bitmap Values */ +#define USB_DEVICE_CDC_UART_STATE_RX_CARRIER (0x01) +#define USB_DEVICE_CDC_UART_STATE_TX_CARRIER (0x02) +#define USB_DEVICE_CDC_UART_STATE_BREAK (0x04) +#define USB_DEVICE_CDC_UART_STATE_RING_SIGNAL (0x08) +#define USB_DEVICE_CDC_UART_STATE_FRAMING (0x10) +#define USB_DEVICE_CDC_UART_STATE_PARITY (0x20) +#define USB_DEVICE_CDC_UART_STATE_OVERRUN (0x40) + +#endif /* _USB_DEVICE_CDC_ACM_H_ */ diff --git a/bsp/usb_cdc/src/usb_device_ch9.c b/bsp/usb_cdc/src/usb_device_ch9.c new file mode 100644 index 0000000..81be6d1 --- /dev/null +++ b/bsp/usb_cdc/src/usb_device_ch9.c @@ -0,0 +1,1014 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" +#include "usb_device_ch9.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief Standard request callback function typedef. + * + * This function is used to handle the standard request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_standard_request_callback_t)(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get the setup packet buffer. + * + * The function is used to get the setup packet buffer to save the setup packet data. + * + * @param handle The device handle. + * @param setupBuffer It is an OUT parameter, return the setup buffer address to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer); + +/*! + * @brief Handle the class request. + * + * The function is used to handle the class request. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length It is an OUT parameter, return the data length need to be sent to host. + * @param buffer It is an OUT parameter, return the data buffer address. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/*! + * @brief Get the buffer to save the class specific data sent from host. + * + * The function is used to get the buffer to save the class specific data sent from host. + * The function will be called when the device receives a setup packet, and the host needs to send data to the device in + * the data stage. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length Pass the length the host needs to sent. + * @param buffer It is an OUT parameter, return the data buffer address to save the host's data. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/* standard request */ +/*! + * @brief Get the descriptor. + * + * The function is used to get the descriptor, including the device descriptor, configuration descriptor, and string + * descriptor, etc. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length It is an OUT parameter, return the data length need to be sent to host. + * @param buffer It is an OUT parameter, return the data buffer address. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/*! + * @brief Set the device configuration. + * + * The function is used to set the device configuration. + * + * @param handle The device handle. + * @param configure The configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceSetConfigure(usb_device_handle handle, uint8_t configure); + +/*! + * @brief Get the device configuration. + * + * The function is used to get the device configuration. + * + * @param handle The device handle. + * @param configure It is an OUT parameter, save the current configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetConfigure(usb_device_handle handle, uint8_t *configure); + +/*! + * @brief Set an interface alternate setting. + * + * The function is used to set an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting The new alternate setting value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceSetInterface(usb_device_handle handle, uint8_t interface, uint8_t alternateSetting); + +/*! + * @brief Get an interface alternate setting. + * + * The function is used to get an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting It is an OUT parameter, save the new alternate setting value of the interface. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetInterface(usb_device_handle handle, uint8_t interface, uint8_t *alternateSetting); + +/*! + * @brief Configure a specified endpoint status. + * + * The function is used to configure a specified endpoint status, idle or halt. + * + * @param handle The device handle. + * @param endpointAddress The endpoint address, the BIT7 is the direction, 0 - USB_OUT, 1 - USB_IN. + * @param status The new status of the endpoint, 0 - idle, 1 - halt. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t status); + +/*! + * @brief Configure the device remote wakeup feature. + * + * The function is used to configure the device remote wakeup feature, enable or disable the remote wakeup feature. + * + * @param handle The device handle. + * @param enable The new feature value of the device remote wakeup, 0 - disable, 1 - enable. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable); + +static usb_status_t USB_DeviceCh9GetStatus(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetAddress(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SynchFrame(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* The function list to handle the standard request. */ +static const usb_standard_request_callback_t s_UsbDeviceStandardRequest[] = { + USB_DeviceCh9GetStatus, + USB_DeviceCh9SetClearFeature, + (usb_standard_request_callback_t)NULL, + USB_DeviceCh9SetClearFeature, + (usb_standard_request_callback_t)NULL, + USB_DeviceCh9SetAddress, + USB_DeviceCh9GetDescriptor, + (usb_standard_request_callback_t)NULL, /* USB_DeviceCh9SetDescriptor */ + USB_DeviceCh9GetConfiguration, + USB_DeviceCh9SetConfiguration, + USB_DeviceCh9GetInterface, + USB_DeviceCh9SetInterface, + USB_DeviceCh9SynchFrame, +}; + +/* + * The internal global variable. + * This variable is used in: + * get status request + * get configuration request + * get interface request + * set interface request + * get sync frame request + */ +static uint16_t s_UsbDeviceStandardRx; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Handle get status request. + * + * This function is used to handle get status request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetStatus(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_IN) || (setup->wValue != 0U) || + (setup->wLength != 2U)) + { + return error; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return error; + } + + if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) + { + /* Get the device status */ + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusDevice, &s_UsbDeviceStandardRx); + s_UsbDeviceStandardRx = s_UsbDeviceStandardRx & USB_GET_STATUS_DEVICE_MASK; + s_UsbDeviceStandardRx = USB_SHORT_TO_LITTLE_ENDIAN(s_UsbDeviceStandardRx); + /* The device status length must be USB_DEVICE_STATUS_SIZE. */ + *length = USB_DEVICE_STATUS_SIZE; + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_INTERFACE) + { + /* Get the interface status */ + error = kStatus_USB_Success; + s_UsbDeviceStandardRx = 0U; + /* The interface status length must be USB_INTERFACE_STATUS_SIZE. */ + *length = USB_INTERFACE_STATUS_SIZE; + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) + { + /* Get the endpoint status */ + usb_device_endpoint_status_struct_t endpointStatus; + endpointStatus.endpointAddress = (uint8_t)setup->wIndex; + endpointStatus.endpointStatus = kUSB_DeviceEndpointStateIdle; + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusEndpoint, &endpointStatus); + s_UsbDeviceStandardRx = endpointStatus.endpointStatus & USB_GET_STATUS_ENDPOINT_MASK; + s_UsbDeviceStandardRx = USB_SHORT_TO_LITTLE_ENDIAN(s_UsbDeviceStandardRx); + /* The endpoint status length must be USB_INTERFACE_STATUS_SIZE. */ + *length = USB_ENDPOINT_STATUS_SIZE; + } + else + { + } + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + + return error; +} + +/*! + * @brief Handle set or clear device feature request. + * + * This function is used to handle set or clear device feature request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + uint8_t isSet = 0U; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_OUT) || (setup->wLength != 0U)) + { + return error; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return error; + } + + /* Identify the request is set or clear the feature. */ + if (USB_REQUEST_STANDARD_SET_FEATURE == setup->bRequest) + { + isSet = 1U; + } + + if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) + { + /* Set or Clear the device feature. */ + if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP == setup->wValue) + { +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + USB_DeviceSetStatus(handle, kUSB_DeviceStatusRemoteWakeup, &isSet); +#endif + /* Set or Clear the device remote wakeup feature. */ + error = USB_DeviceConfigureRemoteWakeup(handle, isSet); + } +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE == setup->wValue) + { + state = kUSB_DeviceStateTestMode; + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + } +#endif + else + { + } + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) + { + /* Set or Clear the endpoint feature. */ + if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT == setup->wValue) + { + if (USB_CONTROL_ENDPOINT == (setup->wIndex & USB_ENDPOINT_NUMBER_MASK)) + { + /* Set or Clear the control endpoint status(halt or not). */ + if (isSet) + { + USB_DeviceStallEndpoint(handle, (uint8_t)setup->wIndex); + } + else + { + USB_DeviceUnstallEndpoint(handle, (uint8_t)setup->wIndex); + } + } + + /* Set or Clear the endpoint status feature. */ + error = USB_DeviceConfigureEndpointStatus(handle, setup->wIndex, isSet); + } + else + { + } + } + else + { + } + + return error; +} + +/*! + * @brief Handle set address request. + * + * This function is used to handle set address request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state. + */ +static usb_status_t USB_DeviceCh9SetAddress(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_OUT) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_DEVICE) || + (setup->wIndex != 0U) || (setup->wLength != 0U)) + { + return error; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddressing != state) && (kUSB_DeviceStateAddress != state) && + (kUSB_DeviceStateDefault != state)) + { + return error; + } + + if (kUSB_DeviceStateAddressing != state) + { + /* If the device address is not setting, pass the address and the device state will change to + * kUSB_DeviceStateAddressing internally. */ + state = setup->wValue & 0xFFU; + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusAddress, &state); + } + else + { + /* If the device address is setting, set device address and the address will be write into the controller + * internally. */ + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusAddress, NULL); + /* And then change the device state to kUSB_DeviceStateAddress. */ + if (kStatus_USB_Success == error) + { + state = kUSB_DeviceStateAddress; + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + } + } + + return error; +} + +/*! + * @brief Handle get descriptor request. + * + * This function is used to handle get descriptor request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + if ((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_IN) + { + return kStatus_USB_InvalidRequest; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state) && + (kUSB_DeviceStateDefault != state)) + { + return kStatus_USB_InvalidRequest; + } + + return USB_DeviceGetDescriptor(handle, setup, length, buffer); +} + +/*! + * @brief Handle get current configuration request. + * + * This function is used to handle get current configuration request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_IN) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_DEVICE) || + (setup->wValue != 0U) || (setup->wIndex != 0U) || (setup->wLength != 1U)) + { + return kStatus_USB_InvalidRequest; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && ((kUSB_DeviceStateConfigured != state))) + { + return kStatus_USB_InvalidRequest; + } + + *length = USB_CONFIGURE_SIZE; + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + return USB_DeviceGetConfigure(handle, (uint8_t *)&s_UsbDeviceStandardRx); +} + +/*! + * @brief Handle set current configuration request. + * + * This function is used to handle set current configuration request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_OUT) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_DEVICE) || + (setup->wIndex != 0U) || (setup->wLength != 0U)) + { + return kStatus_USB_InvalidRequest; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return kStatus_USB_InvalidRequest; + } + + /* The device state is changed to kUSB_DeviceStateConfigured */ + state = kUSB_DeviceStateConfigured; + USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + if (!setup->wValue) + { + /* If the new configuration is zero, the device state is changed to kUSB_DeviceStateAddress */ + state = kUSB_DeviceStateAddress; + USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + } + + return USB_DeviceSetConfigure(handle, setup->wValue); +} + +/*! + * @brief Handle get the alternate setting of a interface request. + * + * This function is used to handle get the alternate setting of a interface request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_IN) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE) || + (setup->wValue != 0U) || (setup->wLength != 1U)) + { + return error; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + *length = USB_INTERFACE_SIZE; + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + + return USB_DeviceGetInterface(handle, setup->wIndex & 0xFFU, (uint8_t *)&s_UsbDeviceStandardRx); +} + +/*! + * @brief Handle set the alternate setting of a interface request. + * + * This function is used to handle set the alternate setting of a interface request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_OUT) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE) || + (setup->wLength != 0U)) + { + return kStatus_USB_InvalidRequest; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return kStatus_USB_InvalidRequest; + } + + return USB_DeviceSetInterface(handle, (setup->wIndex & 0xFFU), (setup->wValue & 0xFFU)); +} + +/*! + * @brief Handle get sync frame request. + * + * This function is used to handle get sync frame request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The request is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SynchFrame(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if (((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) != USB_REQUEST_TYPE_DIR_IN) || + ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) || + (setup->wValue != 0U) || (setup->wLength != 2U)) + { + return error; + } + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + + s_UsbDeviceStandardRx = setup->wIndex; + /* Get the sync frame value */ + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusSynchFrame, &s_UsbDeviceStandardRx); + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + *length = sizeof(s_UsbDeviceStandardRx); + + return error; +} + +/*! + * @brief Send the response to the host. + * + * This function is used to send the response to the host. + * + * There are two cases this function will be called. + * Case one when a setup packet is received in control endpoint callback function: + * 1. If there is not data phase in the setup transfer, the function will prime an IN transfer with the data + * length is zero for status phase. + * 2. If there is an IN data phase, the function will prime an OUT transfer with the actual length to need to + * send for data phase. And then prime an IN transfer with the data length is zero for status phase. + * 3. If there is an OUT data phase, the function will prime an IN transfer with the actual length to want to + * receive for data phase. + * + * Case two when is not a setup packet received in control endpoint callback function: + * 1. The function will prime an IN transfer with data length is zero for status phase. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param error The error code returned from the standard request function. + * @param stage The stage of the control transfer. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceControlCallbackFeedback(usb_device_handle handle, + usb_setup_struct_t *setup, + usb_status_t error, + usb_device_control_read_write_sequence_t stage, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t errorCode = kStatus_USB_Error; + + if (kStatus_USB_InvalidRequest == error) + { + errorCode = USB_DeviceStallEndpoint(handle, (uint8_t)USB_CONTROL_ENDPOINT); + } + else + { + if (*length > setup->wLength) + { + *length = setup->wLength; + } + + if (kStatus_USB_Success == error) + { + errorCode = USB_DeviceSendRequest(handle, (USB_CONTROL_ENDPOINT), *buffer, *length); + } + else + { + errorCode = USB_DeviceSendRequest(handle, (USB_CONTROL_ENDPOINT), (uint8_t *)NULL, 0U); + } + + if ((kStatus_USB_Success == errorCode) && + (USB_REQUEST_TYPE_DIR_IN == (setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK))) + { + errorCode = USB_DeviceRecvRequest(handle, (USB_CONTROL_ENDPOINT), (uint8_t *)NULL, 0U); + } + } + return errorCode; +} + +/*! + * @brief Control endpoint callback function. + * + * This callback function is used to notify upper layer the transfered result of a transfer. + * This callback pointer is passed when a specified endpoint initialized by calling API USB_DeviceInitEndpoint. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The result of a transfer, includes transfer buffer, transfer length and whether is in setup + * phase for control pipe. + * @param callbackParam The parameter for this callback. It is same with + * usb_device_endpoint_callback_struct_t::callbackParam. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceControlCallback(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_setup_struct_t *deviceSetup; + uint8_t *setupOutBuffer = (uint8_t *)NULL; + uint8_t *buffer = (uint8_t *)NULL; + uint32_t length = 0U; + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */ + if (USB_CANCELLED_TRANSFER_LENGTH == message->length) + { + return error; + } + + USB_DeviceGetSetupBuffer(handle, &deviceSetup); + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (message->isSetup) + { + if ((USB_SETUP_PACKET_SIZE != message->length) || (NULL == message->buffer)) + { + /* If a invalid setup is received, the control pipes should be de-init and init again. + * Due to the IP can not meet this require, it is reserved for feature. + */ + /* + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + USB_DeviceControlPipeInit(handle); + */ + return error; + } + /* Receive a setup request */ + usb_setup_struct_t *setup = (usb_setup_struct_t *)(message->buffer); + + /* Copy the setup packet to the application buffer */ + deviceSetup->wValue = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wValue); + deviceSetup->wIndex = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wIndex); + deviceSetup->wLength = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wLength); + deviceSetup->bRequest = setup->bRequest; + deviceSetup->bmRequestType = setup->bmRequestType; + + /* Check the invalid value */ + if ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) > USB_REQUEST_TYPE_RECIPIENT_OTHER) + { + USB_DeviceControlCallbackFeedback(handle, deviceSetup, kStatus_USB_InvalidRequest, + kUSB_DeviceControlPipeSetupStage, NULL, 0U); + return error; + } + + if ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_STANDARD) + { + /* Handle the standard request */ + /* Handle the standard request, only handle the request in request array. */ + if (deviceSetup->bRequest < (sizeof(s_UsbDeviceStandardRequest) / 4U)) + { + if (s_UsbDeviceStandardRequest[deviceSetup->bRequest] != (usb_standard_request_callback_t)NULL) + { + error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](handle, deviceSetup, &buffer, &length); + } + } + } + else + { + if ((deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) + { + /* Class or vendor request with the OUT data phase. */ + if ((deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Get data buffer to receive the data from the host. */ + length = deviceSetup->wLength; + error = USB_DeviceGetClassReceiveBuffer(handle, deviceSetup, &length, &setupOutBuffer); + } + else + { + } + if (kStatus_USB_Success == error) + { + /* Prime an OUT transfer */ + if (length > deviceSetup->wLength) + { + length = deviceSetup->wLength; + } + error = USB_DeviceRecvRequest(handle, USB_CONTROL_ENDPOINT, setupOutBuffer, length); + return error; + } + else + { + /* Other error codes, will stall control endpoint */ + error = kStatus_USB_InvalidRequest; + } + } + else + { + /* Class or vendor request with the IN data phase. */ + if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Get data buffer to response the host. */ + error = USB_DeviceProcessClassRequest(handle, deviceSetup, &length, &buffer); + } + else + { + } + } + } + /* Buffer that is equal to NULL means the application or classs driver does not prepare a buffer for + sending or receiving the data, so control endpoint will be stalled here. */ + if ((0U != length) && (NULL == buffer)) + { + error = kStatus_USB_InvalidRequest; + } + /* Send the response to the host. */ + error = USB_DeviceControlCallbackFeedback(handle, deviceSetup, error, kUSB_DeviceControlPipeSetupStage, &buffer, + &length); + } + else if (kUSB_DeviceStateAddressing == state) + { + /* Set the device address to controller. */ + if (USB_REQUEST_STANDARD_SET_ADDRESS == deviceSetup->bRequest) + { + error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](handle, deviceSetup, &buffer, &length); + } + } +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + else if (kUSB_DeviceStateTestMode == state) + { + uint8_t portTestControl = (uint8_t)(deviceSetup->wIndex >> 8); + /* Set the controller.into test mode. */ + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusTestMode, &portTestControl); + } +#endif + else if ((message->length) && (deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) + { + if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Data received in OUT phase, and notify the class driver. */ + error = USB_DeviceProcessClassRequest(handle, deviceSetup, &message->length, &message->buffer); + } + else + { + } + /* Send the response to the host. */ + error = USB_DeviceControlCallbackFeedback(handle, deviceSetup, error, kUSB_DeviceControlPipeDataStage, &buffer, + &length); + } + else + { + } + return error; +} + +/*! + * @brief Control endpoint initialization function. + * + * This callback function is used to initialize the control pipes. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param param The up layer handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle) +{ + usb_device_endpoint_init_struct_t epInitStruct; + usb_device_endpoint_callback_struct_t epCallback; + usb_status_t error; + + epCallback.callbackFn = USB_DeviceControlCallback; + epCallback.callbackParam = handle; + + epInitStruct.zlt = 1U; + epInitStruct.interval = 0U; + epInitStruct.transferType = USB_ENDPOINT_CONTROL; + epInitStruct.endpointAddress = USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + epInitStruct.maxPacketSize = USB_CONTROL_MAX_PACKET_SIZE; + /* Initialize the control IN pipe */ + error = USB_DeviceInitEndpoint(handle, &epInitStruct, &epCallback); + + if (kStatus_USB_Success != error) + { + return error; + } + epInitStruct.endpointAddress = USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + /* Initialize the control OUT pipe */ + error = USB_DeviceInitEndpoint(handle, &epInitStruct, &epCallback); + + if (kStatus_USB_Success != error) + { + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + return error; + } + + return kStatus_USB_Success; +} diff --git a/bsp/usb_cdc/src/usb_device_ch9.h b/bsp/usb_cdc/src/usb_device_ch9.h new file mode 100644 index 0000000..5fd2375 --- /dev/null +++ b/bsp/usb_cdc/src/usb_device_ch9.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DEVICE_CH9_H__ +#define __USB_DEVICE_CH9_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! + * @addtogroup usb_device_ch9 + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines USB device status size when the host request to get device status */ +#define USB_DEVICE_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device interface status size when the host request to get interface status */ +#define USB_INTERFACE_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device endpoint status size when the host request to get endpoint status */ +#define USB_ENDPOINT_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device configuration size when the host request to get current configuration */ +#define USB_CONFIGURE_SIZE (0X01U) + +/*! @brief Defines USB device interface alternate setting size when the host request to get interface alternate setting + */ +#define USB_INTERFACE_SIZE (0X01U) + +/*! @brief Defines USB device status mask */ +#define USB_GET_STATUS_DEVICE_MASK (0x03U) + +/*! @brief Defines USB device interface status mask */ +#define USB_GET_STATUS_INTERFACE_MASK (0x03U) + +/*! @brief Defines USB device endpoint status mask */ +#define USB_GET_STATUS_ENDPOINT_MASK (0x03U) + +/*! @brief Control read and write sequence */ +typedef enum _usb_device_control_read_write_sequence +{ + kUSB_DeviceControlPipeSetupStage = 0U, /*!< Setup stage */ + kUSB_DeviceControlPipeDataStage, /*!< Data stage */ + kUSB_DeviceControlPipeStatusStage, /*!< status stage */ +} usb_device_control_read_write_sequence_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initialize the control pipes. + * + * The function is used to initialize the control pipes. This function should be called when event + * kUSB_DeviceEventBusReset is received. + * + * @param handle The device handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle); + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* __USB_DEVICE_CH9_H__ */ diff --git a/bsp/usb_cdc/src/usb_device_config.h b/bsp/usb_cdc/src/usb_device_config.h new file mode 100644 index 0000000..f24f4b2 --- /dev/null +++ b/bsp/usb_cdc/src/usb_device_config.h @@ -0,0 +1,52 @@ +/* + * Copyright 2025 TFT Project + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_device_config.h + * @brief Конфигурация NXP USB Device Stack для bsp_usb_cdc. + * + * Этот файл — application-specific конфиг, который NXP USB middleware + * подключает через include path. Не является частью SDK. + * + * Настройки под bare-metal CDC ACM на USB1 (EHCI0). + */ +#ifndef USB_DEVICE_CONFIG_H_ +#define USB_DEVICE_CONFIG_H_ + +/* ---- Контроллер -------------------------------------------------------- */ +#define USB_DEVICE_CONFIG_EHCI (1U) +#define USB_DEVICE_CONFIG_KHCI (0U) +#define USB_DEVICE_CONFIG_LPCIP3511FS (0U) +#define USB_DEVICE_CONFIG_LPCIP3511HS (0U) + +/** Суммарное количество активных контроллеров. */ +#define USB_DEVICE_CONFIG_NUM \ + (USB_DEVICE_CONFIG_EHCI + USB_DEVICE_CONFIG_KHCI + USB_DEVICE_CONFIG_LPCIP3511FS + \ + USB_DEVICE_CONFIG_LPCIP3511HS) + +/* ---- EHCI-специфичные -------------------------------------------------- */ +#define USB_DEVICE_CONFIG_EHCI_MAX_DTD (16U) + +/* ---- Классы устройства ------------------------------------------------- */ +#define USB_DEVICE_CONFIG_CDC_ACM (1U) +#define USB_DEVICE_CONFIG_HID (0U) +#define USB_DEVICE_CONFIG_MSC (0U) +#define USB_DEVICE_CONFIG_AUDIO (0U) +#define USB_DEVICE_CONFIG_VIDEO (0U) +#define USB_DEVICE_CONFIG_PHDC (0U) +#define USB_DEVICE_CONFIG_DFU (0U) +#define USB_DEVICE_CONFIG_PRINTER (0U) +#define USB_DEVICE_CONFIG_CCID (0U) +#define USB_DEVICE_CONFIG_MTP (0U) +#define USB_DEVICE_CONFIG_CDC_ECM (0U) +#define USB_DEVICE_CONFIG_CDC_RNDIS (0U) + +/* ---- Общие настройки --------------------------------------------------- */ +#define USB_DEVICE_CONFIG_ENDPOINTS (4U) +#define USB_DEVICE_CONFIG_SELF_POWER (1U) +#define USB_DEVICE_CONFIG_MAX_MESSAGES (8U) +#define USB_DEVICE_CONFIG_ROOT2_TEST (0U) + +#endif /* USB_DEVICE_CONFIG_H_ */ \ No newline at end of file diff --git a/bsp/usb_cdc/src/usb_device_descriptor.h b/bsp/usb_cdc/src/usb_device_descriptor.h new file mode 100644 index 0000000..c8a4dc8 --- /dev/null +++ b/bsp/usb_cdc/src/usb_device_descriptor.h @@ -0,0 +1,116 @@ +/* + * Copyright 2025 TFT Project + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file usb_device_descriptor.h + * @brief USB CDC ACM дескрипторы — константы и прототипы. + * + * Определяет VID/PID, номера эндпоинтов, размеры пакетов. + * Используется только внутри bsp_usb_cdc. + */ + +#ifndef USB_DEVICE_DESCRIPTOR_H_ +#define USB_DEVICE_DESCRIPTOR_H_ + +/* ---- Версии USB -------------------------------------------------------- */ +#define USB_DEVICE_SPECIFIC_BCD_VERSION (0x0200U) +#define USB_DEVICE_DEMO_BCD_VERSION (0x0101U) + +/* ---- VID / PID --------------------------------------------------------- */ +#define USB_DEVICE_VID (0x1996U) /* TODO: заменить на свой */ +#define USB_DEVICE_PID (0x00ADU) /* TODO: заменить на свой */ + +/* ---- CDC коды классов -------------------------------------------------- */ +#define CDC_COMM_CLASS (0x02U) +#define CDC_DATA_CLASS (0x0AU) + +/* ---- CDC SubClass / Protocol ------------------------------------------- */ +#define USB_CDC_ABSTRACT_CONTROL_MODEL (0x02U) +#define USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL (0x00U) + +/* ---- Functional Descriptor SubTypes ------------------------------------ */ +#define USB_CDC_HEADER_FUNC_DESC (0x00U) +#define USB_CDC_CALL_MANAGEMENT_FUNC_DESC (0x01U) +#define USB_CDC_ABSTRACT_CONTROL_FUNC_DESC (0x02U) +#define USB_CDC_UNION_FUNC_DESC (0x06U) + +/* ---- Длины функциональных дескрипторов --------------------------------- */ +#define USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC (5U) +#define USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG (5U) +#define USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT (4U) +#define USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC (5U) + +/* ---- CS Descriptor Types ----------------------------------------------- */ +#define USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE (0x24U) +#define USB_DESCRIPTOR_TYPE_CDC_CS_ENDPOINT (0x25U) + +/* ---- Конфигурация, интерфейсы, эндпоинты ------------------------------- */ +#define USB_DEVICE_CONFIGURATION_COUNT (1U) +#define USB_DEVICE_STRING_COUNT (3U) +#define USB_DEVICE_LANGUAGE_COUNT (1U) + +#define USB_CDC_VCOM_CONFIGURE_INDEX (1U) + +#define USB_CDC_VCOM_ENDPOINT_CIC_COUNT (1U) +#define USB_CDC_VCOM_ENDPOINT_DIC_COUNT (2U) + +#define USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT (1U) +#define USB_CDC_VCOM_BULK_IN_ENDPOINT (2U) +#define USB_CDC_VCOM_BULK_OUT_ENDPOINT (3U) + +#define USB_CDC_VCOM_INTERFACE_COUNT (2U) +#define USB_CDC_VCOM_COMM_INTERFACE_INDEX (0U) +#define USB_CDC_VCOM_DATA_INTERFACE_INDEX (1U) + +/* ---- Размеры пакетов --------------------------------------------------- */ +#define HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16U) +#define FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16U) +#define HS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x07U) +#define FS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x08U) + +#define HS_CDC_VCOM_BULK_IN_PACKET_SIZE (512U) +#define FS_CDC_VCOM_BULK_IN_PACKET_SIZE (64U) +#define HS_CDC_VCOM_BULK_OUT_PACKET_SIZE (512U) +#define FS_CDC_VCOM_BULK_OUT_PACKET_SIZE (64U) + +/* ---- Device class codes ------------------------------------------------ */ +#define USB_DEVICE_CLASS (0x02U) +#define USB_DEVICE_SUBCLASS (0x00U) +#define USB_DEVICE_PROTOCOL (0x00U) +#define USB_DEVICE_MAX_POWER (0x32U) + +/* ---- CIC / DIC class codes -------------------------------------------- */ +#define USB_CDC_VCOM_CIC_CLASS (CDC_COMM_CLASS) +#define USB_CDC_VCOM_CIC_SUBCLASS (USB_CDC_ABSTRACT_CONTROL_MODEL) +#define USB_CDC_VCOM_CIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL) +#define USB_CDC_VCOM_DIC_CLASS (CDC_DATA_CLASS) +#define USB_CDC_VCOM_DIC_SUBCLASS (0x00U) +#define USB_CDC_VCOM_DIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL) + +/* ---- Alternate settings ------------------------------------------------ */ +#define USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_COUNT (1U) +#define USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_COUNT (1U) +#define USB_CDC_VCOM_COMM_INTERFACE_ALTERNATE_0 (0U) +#define USB_CDC_VCOM_DATA_INTERFACE_ALTERNATE_0 (0U) + +/* ---- String descriptor lengths (computed from arrays) ------------------ */ +#define USB_DESCRIPTOR_LENGTH_STRING0 (sizeof(g_UsbDeviceString0)) +#define USB_DESCRIPTOR_LENGTH_STRING1 (sizeof(g_UsbDeviceString1)) +#define USB_DESCRIPTOR_LENGTH_STRING2 (sizeof(g_UsbDeviceString2)) +#define USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL (sizeof(g_UsbDeviceConfigurationDescriptor)) + +/* ---- Прототипы (реализация в usb_cdc.c) -------------------------------- */ + +/** + * @brief Обработка USB device событий (bus reset, set config и т.д.). + */ +extern usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param); + +/** + * @brief Обновление дескрипторов при смене скорости HS/FS. + */ +extern usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed); + +#endif /* USB_DEVICE_DESCRIPTOR_H_ */ \ No newline at end of file diff --git a/firmware/test/CMakeLists.txt b/firmware/test/CMakeLists.txt index 517d32c..8c4b399 100644 --- a/firmware/test/CMakeLists.txt +++ b/firmware/test/CMakeLists.txt @@ -18,11 +18,9 @@ target_link_libraries( PRIVATE bsp_board bsp_led bsp_tick - bsp_can - bsp_button bsp_uart_host bsp_boot_xip - bsp_opto + bsp_usb_cdc port_log_uart lib_external # SEGGER RTT если включён через SEGGER_RTT_ENABLED ) diff --git a/firmware/test/main.c b/firmware/test/main.c index e159f28..a46b8a3 100644 --- a/firmware/test/main.c +++ b/firmware/test/main.c @@ -3,65 +3,12 @@ #include "bsp/led.h" #include "bsp/tick.h" #include "bsp/uart_host.h" -#include "fsl_common.h" +#include "bsp/usb_cdc.h" #include "log/log.h" #include "port/log_uart.h" #include #include -#include - -/* -------------------------------------------------------------------------- - * Проверка non-cacheable региона - * -------------------------------------------------------------------------- - * Буфер размещён в секции NonCacheable — OCRAM @ 0x20200000. - * MPU Region 9 настраивает эту область как Normal non-cacheable, - * поэтому записи CPU сразу видны DMA без SCB_CleanDCache(). - * -------------------------------------------------------------------------- */ - -#define NCACHE_TEST_BUF_SIZE 64U -#define NCACHE_REGION_BASE 0x20200000U -#define NCACHE_REGION_END 0x20202000U /* 8 KB — размер из линкер-скрипта */ - -AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t s_ncache_buf[NCACHE_TEST_BUF_SIZE], 4U); - -static bool ncache_test_run(void) -{ - uint32_t buf_addr = (uint32_t) s_ncache_buf; - - /* Проверяем что буфер физически лежит в ожидаемом ncache регионе */ - if (buf_addr < NCACHE_REGION_BASE || buf_addr >= NCACHE_REGION_END) - { - LOG_E("NCACHE", "buf addr 0x%08lx outside ncache region [0x%08x..0x%08x)", - (unsigned long) buf_addr, NCACHE_REGION_BASE, NCACHE_REGION_END); - return false; - } - - /* Записываем паттерн */ - for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++) - { - s_ncache_buf[i] = (uint8_t) (i ^ 0xA5U); - } - - /* Для non-cacheable памяти flush не нужен — данные уже когерентны. - * Вызываем CleanDCache чтобы убедиться что он не ломает данные. */ - SCB_CleanDCache(); - - /* Читаем обратно и сравниваем */ - for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++) - { - uint8_t expected = (uint8_t) (i ^ 0xA5U); - - if (s_ncache_buf[i] != expected) - { - LOG_E("NCACHE", "mismatch at [%lu]: got 0x%02x expected 0x%02x", (unsigned long) i, - s_ncache_buf[i], expected); - return false; - } - } - - return true; -} int main(void) { @@ -76,20 +23,22 @@ int main(void) LOG_I("BOOT", "firmware_test started, tick=%lu", (unsigned long) bsp_tick_get_ms()); - if (ncache_test_run()) + if (bsp_usb_cdc_init() == BSP_OK) { - LOG_I("NCACHE", "OK addr=0x%08lx size=%u", (unsigned long) (uint32_t) s_ncache_buf, - NCACHE_TEST_BUF_SIZE); - } - else - { - LOG_E("NCACHE", "FAIL"); + LOG_I("BOOT", "USB CDC ACM initialized"); } bsp_led_on(LED_APP); - + bool is_connection_established = false; while (1) { + if (bsp_usb_cdc_is_ready() == true && is_connection_established == false) + { + is_connection_established = true; + LOG_I("BOOT", "USB CDC ACM ready"); + } + + bsp_usb_cdc_poll(); bsp_led_toggle(LED_HEARTBEAT); bsp_delay(DELAY_MS); } diff --git a/project_tree.txt b/project_tree.txt deleted file mode 100644 index 0a3797b..0000000 --- a/project_tree.txt +++ /dev/null @@ -1,317 +0,0 @@ -. -├── CMakeLists.txt -├── CMakePresets.json -├── Justfile -├── README.md -├── bootstrap.sh -├── bsp -│   ├── CMakeLists.txt -│   ├── README.md -│   ├── button -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   └── src -│   ├── can -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   ├── mocks -│   │   └── src -│   ├── common -│   │   ├── CMakeLists.txt -│   │   └── include -│   ├── generated -│   │   ├── README.md -│   │   ├── TFT_Board.mex -│   │   ├── board -│   │   ├── board.c -│   │   ├── board.h -│   │   ├── clock_config.c -│   │   ├── clock_config.h -│   │   ├── pin_mux.c -│   │   ├── pin_mux.h -│   │   ├── startup -│   │   └── syscalls.c -│   ├── led -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   └── src -│   ├── opto -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   └── src -│   ├── sdram -│   │   ├── README.md -│   │   ├── include -│   │   └── src -│   ├── tick -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   └── src -│   ├── uart_host -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── include -│   │   ├── mocks -│   │   └── src -│   └── usb_cdc -│   ├── CMakeLists.txt -│   ├── README.md -│   ├── include -│   └── src -├── build -│   ├── Debug -│   │   ├── CMakeCache.txt -│   │   ├── CMakeFiles -│   │   ├── bsp -│   │   ├── build.ninja -│   │   ├── cmake_install.cmake -│   │   ├── compile_commands.json -│   │   ├── firmware -│   │   ├── firmware_test.bin -│   │   ├── firmware_test.elf -│   │   ├── firmware_test.map -│   │   ├── firmware_test_hab.bin -│   │   ├── lib -│   │   ├── port -│   │   ├── sdk -│   │   └── utils -│   ├── host-debug -│   │   ├── CMakeCache.txt -│   │   ├── CMakeFiles -│   │   ├── CTestTestfile.cmake -│   │   ├── Testing -│   │   ├── bsp -│   │   ├── build.ninja -│   │   ├── cmake_install.cmake -│   │   ├── compile_commands.json -│   │   ├── lib -│   │   ├── port -│   │   ├── sdk -│   │   ├── tests -│   │   └── utils -│   └── host-release -│   ├── CMakeCache.txt -│   ├── CMakeFiles -│   ├── CTestTestfile.cmake -│   ├── Testing -│   ├── bsp -│   ├── build.ninja -│   ├── cmake_install.cmake -│   ├── compile_commands.json -│   ├── lib -│   ├── port -│   ├── sdk -│   ├── tests -│   └── utils -├── cmake -│   ├── linker -│   │   ├── MIMXRT1052xxxxx_flexspi_nor.ld -│   │   ├── MIMXRT1052xxxxx_flexspi_nor_sdram.ld -│   │   ├── MIMXRT1052xxxxx_ram.ld -│   │   ├── MIMXRT1052xxxxx_sdram.ld -│   │   └── MIMXRT1052xxxxx_sdram_txt.ld -│   ├── toolchain_arm.cmake -│   └── toolchain_host.cmake -├── docs -│   ├── DEV_ARCH.md -│   ├── HOW_TO_DEBUG.md -│   ├── HOW_TO_FLASH.md -│   ├── hardware -│   │   ├── MCULINKINSERT.pdf -│   │   ├── board -│   │   └── m5stamPLC -│   ├── mimxrt1052 -│   │   ├── BOOT_FLAGS.md -│   │   ├── HAB_GUIDE.md -│   │   ├── manufacturing_user's_guide.pdf -│   │   └── mcu_rm.pdf -│   └── testing -│   ├── hil -│   └── host -├── firmware -│   ├── bootloader -│   ├── test -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── arch.svg -│   │   └── main.c -│   └── tft_app -├── just -│   ├── build.just -│   ├── ci.just -│   └── host.just -├── lib -│   ├── CMakeLists.txt -│   ├── SEGGER -│   │   ├── RTT -│   │   └── wrapper -│   ├── Unity -│   │   ├── CMakeLists.txt -│   │   ├── LICENSE.txt -│   │   ├── README.md -│   │   ├── auto -│   │   ├── docs -│   │   ├── examples -│   │   ├── extras -│   │   ├── library.json -│   │   ├── meson.build -│   │   ├── meson_options.txt -│   │   ├── platformio-build.py -│   │   ├── src -│   │   ├── test -│   │   └── unityConfig.cmake -│   └── fff -│   ├── CMakeLists.txt -│   ├── LICENSE -│   ├── README.md -│   ├── buildandtest -│   ├── examples -│   ├── fakegen.rb -│   ├── fff.h -│   └── test -├── port -│   ├── CMakeLists.txt -│   ├── README.md -│   └── log -│   ├── CMakeLists.txt -│   ├── README.md -│   ├── include -│   └── src -├── project_tree.txt -├── pyocd.yaml -├── pyocd_debug.yaml -├── sdk -│   ├── CMSIS -│   │   ├── Core -│   │   ├── DSP -│   │   ├── Driver -│   │   ├── LICENSE.txt -│   │   ├── NN -│   │   └── RTOS2 -│   ├── CMakeLists.txt -│   ├── COPYING-BSD-3 -│   ├── LA_OPT_NXP_Software_License.txt -│   ├── MIMXRT1052xxxxB_manifest_v3_15.xml -│   ├── README.md -│   ├── SW-Content-Register.txt -│   ├── boards -│   │   └── evkbimxrt1050 -│   ├── components -│   │   ├── audio -│   │   ├── button -│   │   ├── codec -│   │   ├── common_task -│   │   ├── crc -│   │   ├── display -│   │   ├── exception_handling -│   │   ├── flash -│   │   ├── gpio -│   │   ├── i2c -│   │   ├── internal_flash -│   │   ├── led -│   │   ├── lists -│   │   ├── log -│   │   ├── mem_manager -│   │   ├── messaging -│   │   ├── mx25r_flash -│   │   ├── osa -│   │   ├── panic -│   │   ├── phy -│   │   ├── pmic -│   │   ├── reset -│   │   ├── rng -│   │   ├── rtt -│   │   ├── sensor -│   │   ├── serial_manager -│   │   ├── silicon_id -│   │   ├── spi -│   │   ├── timer -│   │   ├── timer_manager -│   │   ├── touch -│   │   ├── uart -│   │   ├── video -│   │   └── wifi_bt_module -│   ├── devices -│   │   └── MIMXRT1052 -│   ├── docs -│   │   └── readme.md -│   ├── middleware -│   │   ├── audio_voice -│   │   ├── cjson -│   │   ├── dhara -│   │   ├── fatfs -│   │   ├── freemaster -│   │   ├── libjpeg -│   │   ├── littlefs -│   │   ├── mcuboot_opensource -│   │   ├── pkcs11 -│   │   ├── pngdec -│   │   ├── sdmmc -│   │   ├── tfm -│   │   ├── tinycbor -│   │   └── usb -│   ├── rtos -│   │   └── freertos -│   └── tools -│   └── cmake_toolchain_files -├── tests -│   ├── CMakeLists.txt -│   ├── host -│   │   ├── CMakeLists.txt -│   │   ├── README.md -│   │   ├── button -│   │   ├── can -│   │   ├── led -│   │   ├── log -│   │   ├── mocks -│   │   ├── opto -│   │   ├── ring_buffer -│   │   ├── timeout -│   │   └── uart_host -│   └── target -│   ├── CMakeLists.txt -│   ├── hil_button -│   ├── hil_can -│   ├── hil_opto -│   └── host_uart -├── tools -│   ├── hil -│   │   ├── 01_test_uart.py -│   │   ├── 02_test_opto.py -│   │   ├── 03_test_can.py -│   │   ├── 04_test_button.py -│   │   ├── README.md -│   │   ├── __pycache__ -│   │   ├── conftest.py -│   │   ├── env_config.py -│   │   ├── load_and_run.py -│   │   ├── m5 -│   │   ├── pyocd_utils.py -│   │   ├── pyproject.toml -│   │   └── uv.lock -│   └── host -│   ├── README.md -│   ├── dcd -│   ├── flash_swd.py -│   ├── flash_usb.py -│   ├── hab -│   ├── pyproject.toml -│   └── uv.lock -└── utils - ├── CMakeLists.txt - ├── README.md - ├── log - │   ├── README.md - │   ├── log.c - │   └── log.h - └── ring_buffer - ├── README.md - ├── ring_buffer.c - └── ring_buffer.h - -185 directories, 130 files diff --git a/sdk/CMakeLists.txt b/sdk/CMakeLists.txt index 53478b5..5a386be 100644 --- a/sdk/CMakeLists.txt +++ b/sdk/CMakeLists.txt @@ -67,3 +67,47 @@ add_sdk_driver(flexspi fsl_flexspi.c) target_link_libraries(sdk_semc PUBLIC sdk_clock) target_link_libraries(sdk_flexspi PUBLIC sdk_clock) + +# ----------------------------------------------------------------------------- +# USB middleware — ручные таргеты (middleware/usb/, не drivers/) +# ----------------------------------------------------------------------------- + +# --- sdk_osa_bm: OS Abstraction Layer (bare-metal) --- +# Объявлен первым — от него зависят USB таргеты через fsl_os_abstraction.h +add_library(sdk_osa_bm STATIC components/osa/fsl_os_abstraction_bm.c + components/lists/fsl_component_generic_list.c) +target_include_directories(sdk_osa_bm PUBLIC components/osa components/lists) +target_link_libraries(sdk_osa_bm PUBLIC sdk_device sdk_common sdk_usb_config) +target_compile_options(sdk_osa_bm PRIVATE -w) + +# --- sdk_usb_common: заголовки USB стека --- +add_library(sdk_usb_common INTERFACE) +target_include_directories(sdk_usb_common SYSTEM + INTERFACE middleware/usb/include) + +# --- sdk_usb_config: application-specific конфиги --- +add_library(sdk_usb_config INTERFACE) +target_include_directories(sdk_usb_config SYSTEM + INTERFACE ${CMAKE_SOURCE_DIR}/bsp/usb_cdc/src) + +# --- sdk_usb_device_ehci: EHCI контроллер + DCI абстракция --- +add_library(sdk_usb_device_ehci STATIC middleware/usb/device/usb_device_dci.c + middleware/usb/device/usb_device_ehci.c) +target_include_directories(sdk_usb_device_ehci PUBLIC middleware/usb/device) +target_link_libraries( + sdk_usb_device_ehci PUBLIC sdk_device sdk_common sdk_usb_common + sdk_usb_config sdk_osa_bm) +target_compile_options(sdk_usb_device_ehci PRIVATE -w) + +# --- sdk_usb_device_ch9: Chapter 9 standard requests --- +# add_library(sdk_usb_device_ch9 STATIC middleware/usb/device/usb_device_ch9.c) +# target_include_directories( sdk_usb_device_ch9 PUBLIC middleware/usb/device +# middleware/usb/device/class) target_link_libraries(sdk_usb_device_ch9 PUBLIC +# sdk_usb_device_ehci) target_compile_options(sdk_usb_device_ch9 PRIVATE -w) + +# --- sdk_usb_phy: USB PHY --- +add_library(sdk_usb_phy STATIC middleware/usb/phy/usb_phy.c) +target_include_directories(sdk_usb_phy PUBLIC middleware/usb/phy) +target_link_libraries(sdk_usb_phy PUBLIC sdk_device sdk_common sdk_usb_common + sdk_usb_config sdk_osa_bm) +target_compile_options(sdk_usb_phy PRIVATE -w)