stm32-code/stm32f072_usb_custom_hid/User/Src/usbd_custom_hid.c

280 lines
9.3 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)
{
xTaskNotifyGive(sender_task_handle);
}
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; //等待发送完成
}