/* ****************************************************************************** * @file usb_hid.c * @author FreqChip Firmware Team * @version V1.0.0 * @date 2021 * @brief This file provides the high layer firmware functions to manage the * USB HID Device.(Human Interface Device) ****************************************************************************** * @attention * * Copyright (c) 2021 FreqChip. * All rights reserved. * ****************************************************************************** * How to use, for example: * * int main(void) * { * NVIC_ClearPendingIRQ(USBMCU_IRQn); * NVIC_SetPriority(USBMCU_IRQn, 0); * NVIC_EnableIRQ(USBMCU_IRQn); * * usb_device_init(); * usb_hid_init(); * * // Wait for other initialization of the MCU * * while(1) * { * usb_hid_send_mouse_report(); * usb_hid_send_keyboard_report(); * } * } ****************************************************************************** */ #include "usb_hid.h" #define REPORT0_LENGTH (4) #define REPORT1_LENGTH (8) uint8_t HID_Mouse_Report[REPORT0_LENGTH]; uint8_t HID_Keyboard_Report[REPORT1_LENGTH]; /* USB Standard Device Descriptor */ const uint8_t USB_HID_DeviceDesc[] = { 0x12, /* bLength */ 0x01, /* bDescriptorType */ 0x00, /* bcdUSB */ 0x02, 0x00, /* bDeviceClass */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ 0x40, /* bMaxPacketSize */ 0xA4, /* idVendor */ 0xA8, /* idVendor */ 0x55, /* idProduct */ 0x22, /* idProduct */ 0x00, /* bcdDevice rel. 2.00 */ 0x20, 0x01, /* Index of manufacturer string */ 0x02, /* Index of product string */ 0x03, /* Index of serial number string */ 0x01, /* bNumConfigurations */ }; /* HID Descriptor */ #define HID_DESCRIPTOR_0 0x09, /* bLength */ \ 0x21, /* bDescriptorType: HID */ \ 0x10, /* bcdHID: 1.10 */ \ 0x01, \ 0x21, /* bCountryCode */ \ 0x01, /* bNumDescriptors */ \ 0x22, /* bDescriptorType: Report */ \ 0x2E, /* wDescriptorLength */ \ 0x00 /* HID Descriptor */ #define HID_DESCRIPTOR_1 0x09, /* bLength */ \ 0x21, /* bDescriptorType: HID */ \ 0x10, /* bcdHID: 1.10 */ \ 0x01, \ 0x21, /* bCountryCode */ \ 0x01, /* bNumDescriptors */ \ 0x22, /* bDescriptorType: Report */ \ 0x41, /* wDescriptorLength */ \ 0x00 const uint8_t USB_HID_Desc_0[] = { HID_DESCRIPTOR_0, }; const uint8_t USB_HID_Desc_1[] = { HID_DESCRIPTOR_1, }; /* USB Standard Configuration Descriptor */ const uint8_t USB_HID_ConfigurationDesc[] = { /* Configuration Descriptor */ 0x09, /* bLength */ 0x02, /* bDescriptorType */ 0x42, /* wTotalLength */ 0x00, 0x02, /* bNumInterfaces */ 0x01, /* bConfigurationValue */ 0x00, /* iConfiguration */ 0xA0, /* bmAttributes */ 0x32, /* bMaxPower */ /* HID Interface_0 Descriptor */ 0x09, /* bLength */ 0x04, /* bDescriptorType */ 0x00, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x01, /* bNumEndpoints */ 0x03, /* bInterfaceClass: HID */ 0x01, /* bInterfaceSubClass: Boot interface */ 0x02, /* bInterfaceProtocol: Mouse */ 0x00, /* iConfiguration */ /* HID Descriptor */ HID_DESCRIPTOR_0, /* Endpoint 1 Descriptor */ 0x07, /* bLength */ 0x05, /* bDescriptorType */ 0x81, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ 0x40, /* wMaxPacketSize: 64byte */ 0x00, 0x08, /* bInterval */ /* HID Interface_1 Descriptor */ 0x09, /* bLength */ 0x04, /* bDescriptorType */ 0x01, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ 0x02, /* bNumEndpoints */ 0x03, /* bInterfaceClass: HID */ 0x01, /* bInterfaceSubClass: Boot interface */ 0x01, /* bInterfaceProtocol: Keyboard */ 0x00, /* iConfiguration */ /* HID Descriptor */ HID_DESCRIPTOR_1, /* Endpoint 2 IN Descriptor */ 0x07, /* bLength */ 0x05, /* bDescriptorType */ 0x82, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ 0x40, /* wMaxPacketSize: 64byte */ 0x00, 0x0A, /* bInterval */ /* Endpoint 2 OUT Descriptor */ 0x07, /* bLength */ 0x05, /* bDescriptorType */ 0x02, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ 0x40, /* wMaxPacketSize: 64byte */ 0x00, 0x0A, /* bInterval */ }; /* USB Standard Manufacture Descriptor */ const uint8_t USB_HID_ManufactureDesc[] = { 0x12, /* bLength */ 0x03, /* bDescriptorType */ 'F', 0x00, /* BString */ 'R', 0x00, 'E', 0x00, 'Q', 0x00, 'C', 0x00, 'H', 0x00, 'I', 0x00, 'P', 0x00, }; /* USB Standard Configuration Descriptor */ const uint8_t USB_HID_ProductDesc[] = { 0x1A, /* bLength */ 0x03, /* bDescriptorType */ 'F', 0x00, /* BString */ 'R', 0x00, 'E', 0x00, 'Q', 0x00, 'C', 0x00, 'H', 0x00, 'I', 0x00, 'P', 0x00, '-', 0x00, 'H', 0x00, 'I', 0x00, 'D', 0x00, }; /* USB Standard Configuration Descriptor */ const uint8_t USB_HID_SerialNumberDesc[] = { 0x1E, /* bLength */ 0x03, /* bDescriptorType */ '2', 0x00, /* BString */ '0', 0x00, '2', 0x00, '1', 0x00, '-', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, '1', 0x00, '-', 0x00, 'B', 0x00, '1', 0x00, '3', 0x00, '5', 0x00, }; /* USB Standard Configuration Descriptor */ const uint8_t USB_HID_LanuageIDDesc[] = { 0x04, /* bLength */ 0x03, /* bDescriptorType */ 0x09, /* BString */ 0x04, }; /* HID device report Descriptor */ uint8_t USB_HID_Mouse_ReportDesc[] = { 0x2E, /* Length */ 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 0x75, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xC0, 0xC0, }; /* HID device report Descriptor */ uint8_t USB_HID_Keyboard_ReportDesc[] = { 0x41, /* Length */ 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2A, 0xFF, 0x00, 0x81, 0x00, 0xC0, 0xC0, }; /********************************************************************* * @fn usb_hid_set_mouse_report * * @brief set report * * @param None. * @return None. */ void usb_hid_set_mouse_report(uint8_t fu8_Index, uint8_t fu8_Value) { HID_Mouse_Report[fu8_Index] = fu8_Value; /* HID_Report[0]: 0000 0001 left button 0000 0010 right button 0000 0100 middle button HID_Report[1]: X (-127 ~ +127) HID_Report[2]: Y (-127 ~ +127) HID_Report[3]: wheel (-127 ~ +127) */ } /********************************************************************* * @fn usb_hid_set_keyboard_report * * @brief set report * * @param None. * @return None. */ void usb_hid_set_keyboard_report(uint16_t fu16_Key) { uint32_t i; switch (fu16_Key) { case KEY_LEFT_CONTROL: HID_Keyboard_Report[0] |= 0x01; break; case KEY_LEFT_SHIFT: HID_Keyboard_Report[0] |= 0x02; break; case KEY_LEFT_ALT: HID_Keyboard_Report[0] |= 0x04; break; case KEY_LEFT_GUI: HID_Keyboard_Report[0] |= 0x08; break; case KEY_RIGHT_CONTROL: HID_Keyboard_Report[0] |= 0x10; break; case KEY_RIGHT_SHIFT: HID_Keyboard_Report[0] |= 0x20; break; case KEY_RIGHT_ALT: HID_Keyboard_Report[0] |= 0x40; break; case KEY_RIGHT_GUI: HID_Keyboard_Report[0] |= 0x80; break; default: { for (i = 2; i < 8; i++) { if (HID_Keyboard_Report[i] == fu16_Key) { break; } if (HID_Keyboard_Report[i] == 0x00) { HID_Keyboard_Report[i] = fu16_Key; break; } } }break; } } /********************************************************************* * @fn usb_hid_clear_keyboard_report * * @brief set report * * @param None. * @return None. */ void usb_hid_clear_keyboard_report(uint16_t fu16_Key) { uint32_t i, k; switch (fu16_Key) { case KEY_LEFT_CONTROL: HID_Keyboard_Report[0] &= ~0x01; break; case KEY_LEFT_SHIFT: HID_Keyboard_Report[0] &= ~0x02; break; case KEY_LEFT_ALT: HID_Keyboard_Report[0] &= ~0x04; break; case KEY_LEFT_GUI: HID_Keyboard_Report[0] &= ~0x08; break; case KEY_RIGHT_CONTROL: HID_Keyboard_Report[0] &= ~0x10; break; case KEY_RIGHT_SHIFT: HID_Keyboard_Report[0] &= ~0x20; break; case KEY_RIGHT_ALT: HID_Keyboard_Report[0] &= ~0x40; break; case KEY_RIGHT_GUI: HID_Keyboard_Report[0] &= ~0x80; break; default: { for (i = 2; i < 8; i++) { if (HID_Keyboard_Report[i] == fu16_Key) { HID_Keyboard_Report[i] = 0x00; for (k = i; k < 7; k++) { if (HID_Keyboard_Report[k + 1] != 0x00) { HID_Keyboard_Report[k] = HID_Keyboard_Report[k + 1]; HID_Keyboard_Report[k + 1] = 0x00; } else { break; } } break; } } }break; } } /********************************************************************* * @fn usb_hid_send_mouse_report * * @brief send report to host * * @param None. * @return None. */ void usb_hid_send_mouse_report(void) { usb_selecet_endpoint(ENDPOINT_1); /* FIFO empty */ if (usb_Endpoints_GET_TxPktRdy() == false) { usb_write_fifo(ENDPOINT_1, HID_Mouse_Report, REPORT0_LENGTH); usb_Endpoints_SET_TxPktRdy(); } } /********************************************************************* * @fn usb_hid_send_keyboard_report * * @brief send report to host * * @param None. * @return None. */ void usb_hid_send_keyboard_report(void) { usb_selecet_endpoint(ENDPOINT_2); /* FIFO empty */ if (usb_Endpoints_GET_TxPktRdy() == false) { usb_write_fifo(ENDPOINT_2, HID_Keyboard_Report, REPORT1_LENGTH); usb_Endpoints_SET_TxPktRdy(); } } /********************************************************************* * @fn usb_hid_ClassRequest_Handler * * @brief HID Class Request Handler * * @param None. * @return None. */ static void usb_hid_ClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) { static uint8_t HID_Protocol = 1; // 0: Boot Protocol // 1: Report Protocol switch (pStandardRequest->bRequest) { case HID_GET_PROTOCOL: { pReturnData->DataBuffer = &HID_Protocol; pReturnData->DataLength = 1; }break; case HID_SET_PROTOCOL: { HID_Protocol = pStandardRequest->wValue[0]; }break; case HID_GET_IDLE: { /* Device does not support Getidle command */ usb_Endpoint0_SendStall(); }break; case HID_SET_IDLE: { /* Device does not support Setidle command */ usb_Endpoint0_SendStall(); }break; default: break; } } /********************************************************************* * @fn usb_hid_StandardClassRequest_Handler * * @brief HID Standard Class Request Handler * * @param None. * @return None. */ static void usb_hid_StandardClassRequest_Handler(usb_StandardRequest_t* pStandardRequest, usb_ReturnData_t* pReturnData) { switch (pStandardRequest->wValue[1]) { case DESCRIPTOR_HID_REPORT: { if (pStandardRequest->wIndex[0] == 0){ pReturnData->DataLength = USB_HID_Mouse_ReportDesc[0]; pReturnData->DataBuffer = &USB_HID_Mouse_ReportDesc[1]; } else if (pStandardRequest->wIndex[0] == 1){ pReturnData->DataLength = USB_HID_Keyboard_ReportDesc[0]; pReturnData->DataBuffer = &USB_HID_Keyboard_ReportDesc[1]; } }break; case DESCRIPTOR_HID: { if (pStandardRequest->wIndex[0] == 0){ pReturnData->DataLength = 9; pReturnData->DataBuffer = (uint8_t *)USB_HID_Desc_0; } else if (pStandardRequest->wIndex[0] == 1){ pReturnData->DataLength = 9; pReturnData->DataBuffer = (uint8_t *)USB_HID_Desc_1; } }break; default: break; } } /********************************************************************* * @fn usb_hid_Endpoints_Handler * * @brief hid Endpoints Handler * * @param None. * @return None. */ void usb_hid_Endpoints_Handler(uint8_t RxStatus, uint8_t TxStatus) { uint8_t lu8_RxCount; uint8_t lu8_Buffer[4] = {0,0,0,0}; if (RxStatus & 1 << ENDPOINT_2) { usb_selecet_endpoint(ENDPOINT_2); lu8_RxCount = usb_Endpoints_get_RxCount(); usb_read_fifo(ENDPOINT_2, lu8_Buffer, lu8_RxCount); usb_Endpoints_FlushRxFIFO(); } } /********************************************************************* * @fn usb_hid_init * * @brief hid device parameter initialization * * @param None. * @return None. */ void usb_hid_init(void) { /* Initialize the relevant pointer */ usbdev_get_dev_desc((uint8_t *)USB_HID_DeviceDesc); usbdev_get_config_desc((uint8_t *)USB_HID_ConfigurationDesc); usbdev_get_string_Manufacture((uint8_t *)USB_HID_ManufactureDesc); usbdev_get_string_Product((uint8_t *)USB_HID_ProductDesc); usbdev_get_string_SerialNumber((uint8_t *)USB_HID_SerialNumberDesc); usbdev_get_string_LanuageID((uint8_t *)USB_HID_LanuageIDDesc); Endpoint_0_StandardClassRequest_Handler = usb_hid_StandardClassRequest_Handler; Endpoint_0_ClassRequest_Handler = usb_hid_ClassRequest_Handler; Endpoints_Handler = usb_hid_Endpoints_Handler; USB_Reset_Handler = usb_hid_init; /* config data endpoint fifo */ usb_selecet_endpoint(ENDPOINT_1); usb_endpoint_Txfifo_config(0x08, 3); usb_TxMaxP_set(8); usb_RxMaxP_set(8); usb_selecet_endpoint(ENDPOINT_2); usb_endpoint_Txfifo_config(0x18, 3); usb_endpoint_Rxfifo_config(0x20, 3); usb_TxMaxP_set(8); usb_RxMaxP_set(8); usb_RxInt_Enable(ENDPOINT_2); usb_SuspendDetectEn(); usb_SingleInt_Enable(USB_INT_STATUS_SUSPEND); usb_SingleInt_Enable(USB_INT_STATUS_RESUME); }