284 lines
9.4 KiB
C
284 lines
9.4 KiB
C
#include "usbd_custom_hid.h"
|
|
#include <string.h>
|
|
#include "main.h"
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "usbd_core.h"
|
|
#include "usbd_hid.h"
|
|
#include "led_control.h"
|
|
|
|
/* 描述符长度 */
|
|
#define HID_CONFIG_DESC_SIZE 41 //配置描述符长度
|
|
#define HID_CUSTOM_REPORT_DESC_SIZE 36 //HID报告描述符
|
|
|
|
/* 端点缓冲区 */
|
|
static USB_MEM_ALIGNX uint8_t read_buffer[CUSTOM_HID_OUT_EP_SIZE];
|
|
static USB_MEM_ALIGNX uint8_t send_buffer[CUSTOM_HID_IN_EP_SIZE];
|
|
|
|
/* 发送信号量 */
|
|
static TaskHandle_t sender_task_handle = NULL;
|
|
|
|
/* USB描述符 */
|
|
static uint8_t usb_descriptor[] = {
|
|
/* 设备(Device)描述符 所有设备有且只有一个 */
|
|
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, USBD_PVN, 0x01),
|
|
|
|
/* 配置(Configuration)描述符 所有设备至少有一个 */
|
|
USB_CONFIG_DESCRIPTOR_INIT(HID_CONFIG_DESC_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
|
/* 截至此处的配置描述符长度: 9 */
|
|
|
|
/* 接口(Interface)描述符 HID设备 */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
|
0x00, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x02, /* bNumEndpoints */
|
|
0x03, /* bInterfaceClass: HID */
|
|
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
|
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
|
0, /* iInterface: Index of string descriptor */
|
|
/* 截至此处的配置描述符长度: 18 */
|
|
|
|
/* HID描述符 自定义HID设备 */
|
|
0x09, /* bLength: HID Descriptor size */
|
|
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
|
|
0x11, /* bcdHID: HID Class Spec release number */
|
|
0x01,
|
|
0x00, /* bCountryCode: Hardware target country */
|
|
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
|
|
0x22, /* bDescriptorType */
|
|
HID_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
|
|
0x00,
|
|
/* 截至此处的配置描述符长度: 27 */
|
|
|
|
/* 端点(Endpoint)描述符 HID IN */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
|
CUSTOM_HID_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
|
0x03, /* bmAttributes: Interrupt endpoint */
|
|
WBVAL(CUSTOM_HID_IN_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
|
CUSTOM_HID_IN_INTERVAL, /* bInterval: Polling Interval */
|
|
/* 截至此处的配置描述符长度: 34 */
|
|
|
|
/* 端点(Endpoint)描述符 HID OUT */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
|
CUSTOM_HID_OUT_EP, /* bEndpointAddress: Endpoint Address (OUT) */
|
|
0x03, /* bmAttributes: Interrupt endpoint */
|
|
WBVAL(CUSTOM_HID_OUT_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
|
CUSTOM_HID_OUT_EP_INTERVAL, /* bInterval: Polling Interval */
|
|
/* 截至此处的配置描述符长度: 41 配置描述符结束 */
|
|
|
|
/* 字符串(String)描述符 设备支持的语言描述符 */
|
|
USB_LANGID_INIT(USBD_LANGID_STRING),
|
|
|
|
/* 字符串(String)描述符 制造商字符串 */
|
|
0x0C, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'S', 0x00,
|
|
'T', 0x00,
|
|
'M', 0x00,
|
|
'3', 0x00,
|
|
'2', 0x00, /* 5字符 */
|
|
|
|
/* 字符串(String)描述符 产品字符串 */
|
|
0x2C, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'H', 0x00,
|
|
'I', 0x00,
|
|
'D', 0x00,
|
|
' ', 0x00,
|
|
'C', 0x00,
|
|
'o', 0x00,
|
|
'n', 0x00,
|
|
't', 0x00,
|
|
'r', 0x00,
|
|
'o', 0x00,
|
|
'l', 0x00,
|
|
' ', 0x00,
|
|
'I', 0x00,
|
|
'n', 0x00,
|
|
't', 0x00,
|
|
'e', 0x00,
|
|
'r', 0x00,
|
|
'f', 0x00,
|
|
'a', 0x00,
|
|
'c', 0x00,
|
|
'e', 0x00, /* 21字符 */
|
|
|
|
/* 字符串(String)描述符 序列号字符串 */
|
|
0x32, /* bLength */
|
|
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00,
|
|
'0', 0x00, /* 24字符 */
|
|
|
|
#ifdef CONFIG_USB_HS
|
|
/* 设备限定(Device Qualifier)描述符 同时支持全速与高速的设备必须有 */
|
|
0x0A,
|
|
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
|
0x00,
|
|
0x02, 0x00,
|
|
0x00,
|
|
0x00,
|
|
0x40,
|
|
0x01,
|
|
0x00,
|
|
#endif
|
|
|
|
/* 空描述符 */
|
|
0x00
|
|
};
|
|
|
|
/* 自定义HID报告描述符 */
|
|
static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
|
|
0x06, 0x00, 0xFF, /* USAGE_PAGE (Vendor Defined Page 0) */
|
|
0x09, 0x01, /* USAGE (Vendor Usage 1) */
|
|
0xA1, 0x01, /* COLLECTION (Application) */
|
|
0x85, 0x01, /* REPORT ID (0x01) */
|
|
0x09, 0x01, /* USAGE (Vendor Usage 1) */
|
|
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
|
0x25, 0xFF, /* LOGICAL_MAXIMUM (255) */
|
|
0x75, 0x08, /* REPORT_SIZE (8) */
|
|
0x95, CUSTOM_HID_OUT_EP_SIZE-1, /* REPORT_COUNT (63) */
|
|
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
|
|
0x85, 0x02, /* REPORT ID (0x02) */
|
|
0x09, 0x01, /* USAGE (Vendor Usage 1) */
|
|
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
|
0x25, 0xFF, /* LOGICAL_MAXIMUM (255) */
|
|
0x75, 0x08, /* REPORT_SIZE (8) */
|
|
0x95, CUSTOM_HID_IN_EP_SIZE-1, /* REPORT_COUNT (63) */
|
|
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
|
0xC0 /* END_COLLECTION */
|
|
};
|
|
|
|
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
|
{
|
|
switch (event) {
|
|
case USBD_EVENT_RESET:
|
|
break;
|
|
case USBD_EVENT_CONNECTED:
|
|
break;
|
|
case USBD_EVENT_DISCONNECTED:
|
|
break;
|
|
case USBD_EVENT_RESUME:
|
|
break;
|
|
case USBD_EVENT_SUSPEND:
|
|
break;
|
|
case USBD_EVENT_CONFIGURED:
|
|
/* setup first out ep read transfer */
|
|
usbd_ep_start_read(busid, CUSTOM_HID_OUT_EP, read_buffer, CUSTOM_HID_OUT_EP_SIZE);
|
|
break;
|
|
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
|
break;
|
|
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
|
{
|
|
BaseType_t higher_task_woken = pdFALSE;
|
|
|
|
vTaskNotifyGiveFromISR(sender_task_handle, &higher_task_woken);
|
|
|
|
portYIELD_FROM_ISR(higher_task_woken);
|
|
}
|
|
|
|
static void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
|
{
|
|
if (read_buffer[0] == 1) {
|
|
led_control_command_send_from_isr(&read_buffer[1]);
|
|
}
|
|
|
|
usbd_ep_start_read(busid, ep, read_buffer, CUSTOM_HID_IN_EP_SIZE);
|
|
}
|
|
|
|
static void fill_usb_descriptor_serial_number(void)
|
|
{
|
|
char uid_string[25];
|
|
sprintf(uid_string, "%08X%08X%08X", HAL_GetUIDw0(), HAL_GetUIDw1(), HAL_GetUIDw2());
|
|
|
|
uint16_t serial_number_offset = 0;
|
|
|
|
for (uint16_t i = 0; i < sizeof(usb_descriptor) - 3; i ++) { //查找USB描述符中序列号字符描述符的偏移
|
|
if (usb_descriptor[i + 0] == '0' && usb_descriptor[i + 1] == 0x00 &&
|
|
usb_descriptor[i + 2] == '0' && usb_descriptor[i + 3] == 0x00) {
|
|
serial_number_offset = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (serial_number_offset == 0) { //未找到
|
|
return;
|
|
}
|
|
|
|
for (uint8_t i = 0; i < 24; i ++) { //共24位
|
|
usb_descriptor[serial_number_offset + i * 2] = uid_string[i];
|
|
}
|
|
}
|
|
|
|
void usbd_custom_hid_start(uint8_t busid, uintptr_t reg_base)
|
|
{
|
|
static struct usbd_interface intf0;
|
|
static struct usbd_endpoint custom_in_ep = {
|
|
.ep_cb = usbd_hid_custom_in_callback,
|
|
.ep_addr = CUSTOM_HID_IN_EP
|
|
};
|
|
static struct usbd_endpoint custom_out_ep = {
|
|
.ep_cb = usbd_hid_custom_out_callback,
|
|
.ep_addr = CUSTOM_HID_OUT_EP
|
|
};
|
|
|
|
fill_usb_descriptor_serial_number();
|
|
|
|
usbd_desc_register(busid, usb_descriptor);
|
|
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE));
|
|
usbd_add_endpoint(busid, &custom_in_ep);
|
|
usbd_add_endpoint(busid, &custom_out_ep);
|
|
|
|
usbd_initialize(busid, reg_base, usbd_event_handler);
|
|
}
|
|
|
|
uint8_t usbd_custom_hid_send(const uint8_t *data, uint16_t length)
|
|
{
|
|
send_buffer[0] = 0x02; //OUT
|
|
|
|
if (length > CUSTOM_HID_IN_EP_SIZE - 1) {
|
|
length = CUSTOM_HID_IN_EP_SIZE - 1; //限制发送长度
|
|
} else {
|
|
memset(&send_buffer[1 + length], 0x00, CUSTOM_HID_IN_EP_SIZE - 1 - length); //缓冲区后部补0
|
|
}
|
|
|
|
memcpy(&send_buffer[1], data, length);
|
|
usbd_ep_start_write(0, CUSTOM_HID_IN_EP, send_buffer, CUSTOM_HID_IN_EP_SIZE);
|
|
|
|
sender_task_handle = xTaskGetCurrentTaskHandle(); //获取当前任务的句柄
|
|
return xTaskNotifyWait(0, 0x00, NULL, pdMS_TO_TICKS(CUSTOM_HID_IN_INTERVAL)) == pdTRUE ? 0 : 1; //等待发送完成
|
|
}
|