Skip to content

Instantly share code, notes, and snippets.

@nickfox-taterli
Created May 28, 2025 13:33
Show Gist options
  • Save nickfox-taterli/a9c076998a7c2d8fc161c5120e54e6a4 to your computer and use it in GitHub Desktop.
Save nickfox-taterli/a9c076998a7c2d8fc161c5120e54e6a4 to your computer and use it in GitHub Desktop.
CompoundDev CH582 Keyboard + Mouse
/********************************** (C) COPYRIGHT *******************************
* File Name : Main.c
* Author : WCH
* Version : V1.1
* Date : 2022/01/25
* Description : 模拟USB复合设备,键鼠,支持类命令
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
#define DevEP0SIZE 0x40
// 支持的最大接口数量
#define USB_INTERFACE_MAX_NUM 2
// 接口号的最大值
#define USB_INTERFACE_MAX_INDEX 1
// 设备描述符
// 设备描述符 - 18字节
const uint8_t MyDevDescr[] = {
0x12, // bLength: 描述符长度(18字节)
0x01, // bDescriptorType: 设备描述符类型(0x01)
0x10, 0x01, // bcdUSB: USB规范版本号(1.10)
0x00, // bDeviceClass: 设备类(0表示由接口定义)
0x00, // bDeviceSubClass: 设备子类
0x00, // bDeviceProtocol: 设备协议
DevEP0SIZE, // bMaxPacketSize0: 端点0最大包大小(8/16/32/64)
0x3d, 0x41, // idVendor: 厂商ID(0x413d)
0x07, 0x21, // idProduct: 产品ID(0x2107)
0x00, 0x00, // bcdDevice: 设备版本号(0.00)
0x01, // iManufacturer: 厂商字符串索引(1)
0x02, // iProduct: 产品字符串索引(2)
0x00, // iSerialNumber: 序列号字符串索引(0表示无)
0x01 // bNumConfigurations: 配置描述符数量(1)
};
// 配置描述符
// 配置描述符 - 59字节(包含接口和端点描述符)
const uint8_t MyCfgDescr[] = {
// 配置描述符(9字节)
0x09, // bLength: 描述符长度(9字节)
0x02, // bDescriptorType: 配置描述符类型(0x02)
0x3b, 0x00, // wTotalLength: 配置总长度(59字节)
0x02, // bNumInterfaces: 接口数量(2)
0x01, // bConfigurationValue: 配置值(1)
0x00, // iConfiguration: 配置字符串索引(0表示无)
0xA0, // bmAttributes: 属性(总线供电,支持远程唤醒)
0x32, // bMaxPower: 最大功耗(100mA)
// 键盘接口描述符(9字节)
0x09, // bLength: 描述符长度(9字节)
0x04, // bDescriptorType: 接口描述符类型(0x04)
0x00, // bInterfaceNumber: 接口号(0)
0x00, // bAlternateSetting: 备用设置号(0)
0x01, // bNumEndpoints: 端点数量(1)
0x03, // bInterfaceClass: 接口类(HID类,0x03)
0x01, // bInterfaceSubClass: 接口子类(1=Boot Interface)
0x01, // bInterfaceProtocol: 接口协议(1=Keyboard)
0x00, // iInterface: 接口字符串索引(0表示无)
// HID类描述符(9字节)
0x09, // bLength: 描述符长度(9字节)
0x21, // bDescriptorType: HID描述符类型(0x21)
0x11, 0x01, // bcdHID: HID规范版本(1.11)
0x00, // bCountryCode: 国家代码(0表示不支持)
0x01, // bNumDescriptors: 下级描述符数量(1)
0x22, // bDescriptorType: 报表描述符类型(0x22)
0x3e, 0x00, // wDescriptorLength: 报表描述符长度(62字节)
// 键盘端点描述符(7字节)
0x07, // bLength: 描述符长度(7字节)
0x05, // bDescriptorType: 端点描述符类型(0x05)
0x81, // bEndpointAddress: 端点地址(IN端点1)
0x03, // bmAttributes: 传输类型(中断传输)
0x08, 0x00, // wMaxPacketSize: 最大包大小(8字节)
0x0a, // bInterval: 轮询间隔(10ms)
// 鼠标接口描述符(9字节)
0x09, // bLength: 描述符长度(9字节)
0x04, // bDescriptorType: 接口描述符类型(0x04)
0x01, // bInterfaceNumber: 接口号(1)
0x00, // bAlternateSetting: 备用设置号(0)
0x01, // bNumEndpoints: 端点数量(1)
0x03, // bInterfaceClass: 接口类(HID类,0x03)
0x01, // bInterfaceSubClass: 接口子类(1=Boot Interface)
0x02, // bInterfaceProtocol: 接口协议(2=Mouse)
0x00, // iInterface: 接口字符串索引(0表示无)
// HID类描述符(9字节)
0x09, // bLength: 描述符长度(9字节)
0x21, // bDescriptorType: HID描述符类型(0x21)
0x10, 0x01, // bcdHID: HID规范版本(1.10)
0x00, // bCountryCode: 国家代码(0表示不支持)
0x01, // bNumDescriptors: 下级描述符数量(1)
0x22, // bDescriptorType: 报表描述符类型(0x22)
0x34, 0x00, // wDescriptorLength: 报表描述符长度(52字节)
// 鼠标端点描述符(7字节)
0x07, // bLength: 描述符长度(7字节)
0x05, // bDescriptorType: 端点描述符类型(0x05)
0x82, // bEndpointAddress: 端点地址(IN端点2)
0x03, // bmAttributes: 传输类型(中断传输)
0x04, 0x00, // wMaxPacketSize: 最大包大小(4字节)
0x0a // bInterval: 轮询间隔(10ms)
};
/* USB速度匹配描述符 */
/* USB速度匹配描述符 - 10字节 */
const uint8_t My_QueDescr[] = {
0x0A, // bLength: 描述符长度(10字节)
0x06, // bDescriptorType: 设备限定描述符类型(0x06)
0x00, 0x02, // bcdUSB: USB规范版本号(2.00)
0xFF, // bDeviceClass: 设备类(FF表示由接口定义)
0x00, // bDeviceSubClass: 设备子类
0xFF, // bDeviceProtocol: 设备协议
0x40, // bMaxPacketSize0: 端点0最大包大小(64)
0x01, // bNumConfigurations: 配置描述符数量(1)
0x00 // 保留
};
/* USB全速模式,其他速度配置描述符 */
uint8_t USB_FS_OSC_DESC[sizeof(MyCfgDescr)] = {
0x09, // bLength: 描述符长度(9字节)
0x07, // bDescriptorType: 其他速度配置描述符类型(0x07)
/* 其他部分通过程序复制 */
};
// 语言描述符 - 4字节
const uint8_t MyLangDescr[] = {
0x04, // bLength: 描述符长度(4字节)
0x03, // bDescriptorType: 字符串描述符类型(0x03)
0x09, 0x04 // wLANGID: 语言ID(0x0409=英语-美国)
};
// 厂家信息字符串描述符 - 14字节("wch.cn")
const uint8_t MyManuInfo[] = {
0x0E, // bLength: 描述符长度(14字节)
0x03, // bDescriptorType: 字符串描述符类型(0x03)
'w', 0, // Unicode字符'w'
'c', 0, // Unicode字符'c'
'h', 0, // Unicode字符'h'
'.', 0, // Unicode字符'.'
'c', 0, // Unicode字符'c'
'n', 0 // Unicode字符'n'
};
// 产品信息字符串描述符 - 12字节("CH58x")
const uint8_t MyProdInfo[] = {
0x0C, // bLength: 描述符长度(12字节)
0x03, // bDescriptorType: 字符串描述符类型(0x03)
'C', 0, // Unicode字符'C'
'H', 0, // Unicode字符'H'
'5', 0, // Unicode字符'5'
'8', 0, // Unicode字符'8'
'x', 0 // Unicode字符'x'
};
/*HID类报表描述符*/
/* HID类键盘报表描述符 - 62字节 */
const uint8_t KeyRepDesc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
// 修饰键(Control, Shift, Alt等)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (0xE0)
0x29, 0xe7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs)
// 保留字节
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Const)
// LED指示灯(Num Lock, Caps Lock等)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x03, // Usage Maximum (Scroll Lock)
0x91, 0x02, // Output (Data,Var,Abs)
// LED保留位
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x91, 0x01, // Output (Const)
// 按键码
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x91, // Usage Maximum (0x91)
0x81, 0x00, // Input (Data,Ary,Abs)
0xC0 // End Collection
};
/* HID类鼠标报表描述符 - 52字节 */
const uint8_t MouseRepDesc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
// 鼠标按钮
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button 1)
0x29, 0x03, // Usage Maximum (Button 3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x03, // Report Count (3)
0x81, 0x02, // Input (Data,Var,Abs)
// 按钮填充位
0x75, 0x05, // Report Size (5)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const)
// 鼠标移动(X,Y)和滚轮
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7f, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x03, // Report Count (3)
0x81, 0x06, // Input (Data,Var,Rel)
0xC0, // End Collection (Physical)
0xC0 // End Collection (Application)
};
/**********************************************************/
uint8_t DevConfig, Ready;
uint8_t SetupReqCode;
uint16_t SetupReqLen;
const uint8_t *pDescr;
uint8_t Report_Value[USB_INTERFACE_MAX_INDEX+1] = {0x00};
uint8_t Idle_Value[USB_INTERFACE_MAX_INDEX+1] = {0x00};
uint8_t USB_SleepStatus = 0x00; /* USB睡眠状态 */
/*鼠标键盘数据*/
uint8_t HIDMouse[4] = {0x0, 0x0, 0x0, 0x0};
uint8_t HIDKey[8] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
/******** 用户自定义分配端点RAM ****************************************/
__attribute__((aligned(4))) uint8_t EP0_Databuf[64 + 64 + 64]; //ep0(64)+ep4_out(64)+ep4_in(64)
__attribute__((aligned(4))) uint8_t EP1_Databuf[64 + 64]; //ep1_out(64)+ep1_in(64)
__attribute__((aligned(4))) uint8_t EP2_Databuf[64 + 64]; //ep2_out(64)+ep2_in(64)
__attribute__((aligned(4))) uint8_t EP3_Databuf[64 + 64]; //ep3_out(64)+ep3_in(64)
/*********************************************************************
* @fn USB_DevTransProcess
*
* @brief USB 传输处理函数
*
* @return none
*/
void USB_DevTransProcess(void)
{
uint8_t len, chtype;
uint8_t intflag, errflag = 0;
intflag = R8_USB_INT_FG;
if(intflag & RB_UIF_TRANSFER)
{
if((R8_USB_INT_ST & MASK_UIS_TOKEN) != MASK_UIS_TOKEN) // 非空闲
{
switch(R8_USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
// 分析操作令牌和端点号
{
case UIS_TOKEN_IN:
{
switch(SetupReqCode)
{
case USB_GET_DESCRIPTOR:
len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen; // 本次传输长度
memcpy(pEP0_DataBuf, pDescr, len); /* 加载上传数据 */
SetupReqLen -= len;
pDescr += len;
R8_UEP0_T_LEN = len;
R8_UEP0_CTRL ^= RB_UEP_T_TOG; // 翻转
break;
case USB_SET_ADDRESS:
R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | SetupReqLen;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
case USB_SET_FEATURE:
break;
default:
R8_UEP0_T_LEN = 0; // 状态阶段完成中断或者是强制上传0长度数据包结束控制传输
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
}
break;
case UIS_TOKEN_OUT:
{
len = R8_USB_RX_LEN;
if(SetupReqCode == 0x09)
{
PRINT("[%s] Num Lock\t", (pEP0_DataBuf[0] & (1<<0)) ? "*" : " ");
PRINT("[%s] Caps Lock\t", (pEP0_DataBuf[0] & (1<<1)) ? "*" : " ");
PRINT("[%s] Scroll Lock\n", (pEP0_DataBuf[0] & (1<<2)) ? "*" : " ");
}
}
break;
case UIS_TOKEN_OUT | 1:
{
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
{ // 不同步的数据包将丢弃
R8_UEP1_CTRL ^= RB_UEP_R_TOG;
len = R8_USB_RX_LEN;
DevEP1_OUT_Deal(len);
}
}
break;
case UIS_TOKEN_IN | 1:
R8_UEP1_CTRL ^= RB_UEP_T_TOG;
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
case UIS_TOKEN_OUT | 2:
{
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
{ // 不同步的数据包将丢弃
R8_UEP2_CTRL ^= RB_UEP_R_TOG;
len = R8_USB_RX_LEN;
DevEP2_OUT_Deal(len);
}
}
break;
case UIS_TOKEN_IN | 2:
R8_UEP2_CTRL ^= RB_UEP_T_TOG;
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
case UIS_TOKEN_OUT | 3:
{
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
{ // 不同步的数据包将丢弃
R8_UEP3_CTRL ^= RB_UEP_R_TOG;
len = R8_USB_RX_LEN;
DevEP3_OUT_Deal(len);
}
}
break;
case UIS_TOKEN_IN | 3:
R8_UEP3_CTRL ^= RB_UEP_T_TOG;
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
case UIS_TOKEN_OUT | 4:
{
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
{
R8_UEP4_CTRL ^= RB_UEP_R_TOG;
len = R8_USB_RX_LEN;
DevEP4_OUT_Deal(len);
}
}
break;
case UIS_TOKEN_IN | 4:
R8_UEP4_CTRL ^= RB_UEP_T_TOG;
R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
default:
break;
}
R8_USB_INT_FG = RB_UIF_TRANSFER;
}
if(R8_USB_INT_ST & RB_UIS_SETUP_ACT) // Setup包处理
{
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
SetupReqLen = pSetupReqPak->wLength;
SetupReqCode = pSetupReqPak->bRequest;
chtype = pSetupReqPak->bRequestType;
len = 0;
errflag = 0;
if((pSetupReqPak->bRequestType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD)
{
/* 非标准请求 */
/* 其它请求,如类请求,产商请求等 */
if(pSetupReqPak->bRequestType & 0x40)
{
/* 厂商请求 */
}
else if(pSetupReqPak->bRequestType & 0x20)
{
switch(SetupReqCode)
{
case DEF_USB_SET_IDLE: /* 0x0A: SET_IDLE */ //主机想设置HID设备特定输入报表的空闲时间间隔
Idle_Value[pSetupReqPak->wIndex] = (uint8_t)(pSetupReqPak->wValue>>8);
break; //这个一定要有
case DEF_USB_SET_REPORT: /* 0x09: SET_REPORT */ //主机想设置HID设备的报表描述符
break;
case DEF_USB_SET_PROTOCOL: /* 0x0B: SET_PROTOCOL */ //主机想设置HID设备当前所使用的协议
Report_Value[pSetupReqPak->wIndex] = (uint8_t)(pSetupReqPak->wValue);
break;
case DEF_USB_GET_IDLE: /* 0x02: GET_IDLE */ //主机想读取HID设备特定输入报表的当前的空闲比率
EP0_Databuf[0] = Idle_Value[pSetupReqPak->wIndex];
len = 1;
break;
case DEF_USB_GET_PROTOCOL: /* 0x03: GET_PROTOCOL */ //主机想获得HID设备当前所使用的协议
EP0_Databuf[0] = Report_Value[pSetupReqPak->wIndex];
len = 1;
break;
default:
errflag = 0xFF;
}
}
}
else /* 标准请求 */
{
switch(SetupReqCode)
{
case USB_GET_DESCRIPTOR:
{
switch(((pSetupReqPak->wValue) >> 8))
{
case USB_DESCR_TYP_DEVICE:
{
pDescr = MyDevDescr;
len = MyDevDescr[0];
}
break;
case USB_DESCR_TYP_CONFIG:
{
pDescr = MyCfgDescr;
len = MyCfgDescr[2];
}
break;
case USB_DESCR_TYP_HID:
switch((pSetupReqPak->wIndex) & 0xff)
{
/* 选择接口 */
case 0:
pDescr = (uint8_t *)(&MyCfgDescr[18]);
len = 9;
break;
case 1:
pDescr = (uint8_t *)(&MyCfgDescr[43]);
len = 9;
break;
default:
/* 不支持的字符串描述符 */
errflag = 0xff;
break;
}
break;
case USB_DESCR_TYP_REPORT:
{
if(((pSetupReqPak->wIndex) & 0xff) == 0) //接口0报表描述符
{
pDescr = KeyRepDesc; //数据准备上传
len = sizeof(KeyRepDesc);
}
else if(((pSetupReqPak->wIndex) & 0xff) == 1) //接口1报表描述符
{
pDescr = MouseRepDesc; //数据准备上传
len = sizeof(MouseRepDesc);
Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
}
else
len = 0xff; //本程序只有2个接口,这句话正常不可能执行
}
break;
case USB_DESCR_TYP_STRING:
{
switch((pSetupReqPak->wValue) & 0xff)
{
case 1:
pDescr = MyManuInfo;
len = MyManuInfo[0];
break;
case 2:
pDescr = MyProdInfo;
len = MyProdInfo[0];
break;
case 0:
pDescr = MyLangDescr;
len = MyLangDescr[0];
break;
default:
errflag = 0xFF; // 不支持的字符串描述符
break;
}
}
break;
case 0x06:
pDescr = (uint8_t *)(&My_QueDescr[0]);
len = sizeof(My_QueDescr);
break;
case 0x07:
memcpy(&USB_FS_OSC_DESC[2], &MyCfgDescr[2], sizeof(MyCfgDescr) - 2);
pDescr = (uint8_t *)(&USB_FS_OSC_DESC[0]);
len = sizeof(USB_FS_OSC_DESC);
break;
default:
errflag = 0xff;
break;
}
if(SetupReqLen > len)
SetupReqLen = len; //实际需上传总长度
len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
memcpy(pEP0_DataBuf, pDescr, len);
pDescr += len;
}
break;
case USB_SET_ADDRESS:
SetupReqLen = (pSetupReqPak->wValue) & 0xff;
break;
case USB_GET_CONFIGURATION:
pEP0_DataBuf[0] = DevConfig;
if(SetupReqLen > 1)
SetupReqLen = 1;
break;
case USB_SET_CONFIGURATION:
DevConfig = (pSetupReqPak->wValue) & 0xff;
break;
case USB_CLEAR_FEATURE:
{
if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) // 端点
{
switch((pSetupReqPak->wIndex) & 0xff)
{
case 0x83:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK;
break;
case 0x03:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK;
break;
case 0x82:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK;
break;
case 0x02:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK;
break;
case 0x81:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK;
break;
case 0x01:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK;
break;
default:
errflag = 0xFF; // 不支持的端点
break;
}
}
else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE)
{
if(pSetupReqPak->wValue == 1)
{
USB_SleepStatus &= ~0x01;
}
}
else
{
errflag = 0xFF;
}
}
break;
case USB_SET_FEATURE:
if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP)
{
/* 端点 */
switch(pSetupReqPak->wIndex)
{
case 0x83:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL;
break;
case 0x03:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL;
break;
case 0x82:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL;
break;
case 0x02:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL;
break;
case 0x81:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_STALL;
break;
case 0x01:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_STALL;
break;
default:
/* 不支持的端点 */
errflag = 0xFF; // 不支持的端点
break;
}
}
else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE)
{
if(pSetupReqPak->wValue == 1)
{
/* 设置睡眠 */
USB_SleepStatus |= 0x01;
}
}
else
{
errflag = 0xFF;
}
break;
case USB_GET_INTERFACE:
pEP0_DataBuf[0] = 0x00;
if(SetupReqLen > 1)
SetupReqLen = 1;
break;
case USB_SET_INTERFACE:
break;
case USB_GET_STATUS:
if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP)
{
/* 端点 */
pEP0_DataBuf[0] = 0x00;
switch(pSetupReqPak->wIndex)
{
case 0x83:
if((R8_UEP3_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
case 0x03:
if((R8_UEP3_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
case 0x82:
if((R8_UEP2_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
case 0x02:
if((R8_UEP2_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
case 0x81:
if((R8_UEP1_CTRL & (RB_UEP_T_TOG | MASK_UEP_T_RES)) == UEP_T_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
case 0x01:
if((R8_UEP1_CTRL & (RB_UEP_R_TOG | MASK_UEP_R_RES)) == UEP_R_RES_STALL)
{
pEP0_DataBuf[0] = 0x01;
}
break;
}
}
else if((pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE)
{
pEP0_DataBuf[0] = 0x00;
if(USB_SleepStatus)
{
pEP0_DataBuf[0] = 0x02;
}
else
{
pEP0_DataBuf[0] = 0x00;
}
}
pEP0_DataBuf[1] = 0;
if(SetupReqLen >= 2)
{
SetupReqLen = 2;
}
break;
default:
errflag = 0xff;
break;
}
}
if(errflag == 0xff) // 错误或不支持
{
// SetupReqCode = 0xFF;
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL
}
else
{
if(chtype & 0x80) // 上传
{
len = (SetupReqLen > DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
SetupReqLen -= len;
}
else
len = 0; // 下传
R8_UEP0_T_LEN = len;
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1
}
R8_USB_INT_FG = RB_UIF_TRANSFER;
}
}
else if(intflag & RB_UIF_BUS_RST)
{
R8_USB_DEV_AD = 0;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_USB_INT_FG = RB_UIF_BUS_RST;
}
else if(intflag & RB_UIF_SUSPEND)
{
if(R8_USB_MIS_ST & RB_UMS_SUSPEND)
{
;
} // 挂起
else
{
;
} // 唤醒
R8_USB_INT_FG = RB_UIF_SUSPEND;
}
else
{
R8_USB_INT_FG = intflag;
}
}
/*********************************************************************
* @fn DevHIDMouseReport
*
* @brief 上报鼠标数据
*
* @return none
*/
void DevHIDMouseReport(uint8_t mouse)
{
HIDMouse[0] = mouse;
memcpy(pEP2_IN_DataBuf, HIDMouse, sizeof(HIDMouse));
DevEP2_IN_Deal(sizeof(HIDMouse));
}
/*********************************************************************
* @fn DevHIDKeyReport
*
* @brief 上报键盘数据
*
* @return none
*/
void DevHIDKeyReport(uint8_t key)
{
HIDKey[2] = key;
memcpy(pEP1_IN_DataBuf, HIDKey, sizeof(HIDKey));
DevEP1_IN_Deal(sizeof(HIDKey));
}
/*********************************************************************
* @fn DevWakeup
*
* @brief 设备模式唤醒主机
*
* @return none
*/
void DevWakeup(void)
{
R16_PIN_ANALOG_IE &= ~(RB_PIN_USB_DP_PU);
R8_UDEV_CTRL |= RB_UD_LOW_SPEED;
mDelaymS(2);
R8_UDEV_CTRL &= ~RB_UD_LOW_SPEED;
R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU;
}
/*********************************************************************
* @fn DebugInit
*
* @brief 调试初始化
*
* @return none
*/
void DebugInit(void)
{
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
DebugInit();
PRINT("start\n");
pEP0_RAM_Addr = EP0_Databuf;
pEP1_RAM_Addr = EP1_Databuf;
pEP2_RAM_Addr = EP2_Databuf;
pEP3_RAM_Addr = EP3_Databuf;
USB_DeviceInit();
PFIC_EnableIRQ(USB_IRQn);
while(1)
{
mDelaymS(1000);
//鼠标左键
DevHIDMouseReport(0x01);
mDelaymS(100);
DevHIDMouseReport(0x00);
mDelaymS(200);
//键盘按键“wch”
mDelaymS(1000);
DevHIDKeyReport(0x1A);
mDelaymS(100);
DevHIDKeyReport(0x00);
mDelaymS(200);
DevHIDKeyReport(0x06);
mDelaymS(100);
DevHIDKeyReport(0x00);
mDelaymS(200);
DevHIDKeyReport(0x0B);
mDelaymS(100);
DevHIDKeyReport(0x00);
}
}
/*********************************************************************
* @fn DevEP1_OUT_Deal
*
* @brief 端点1数据处理
*
* @return none
*/
void DevEP1_OUT_Deal(uint8_t l)
{ /* 用户可自定义 */
uint8_t i;
for(i = 0; i < l; i++)
{
pEP1_IN_DataBuf[i] = ~pEP1_OUT_DataBuf[i];
}
DevEP1_IN_Deal(l);
}
/*********************************************************************
* @fn DevEP2_OUT_Deal
*
* @brief 端点2数据处理
*
* @return none
*/
void DevEP2_OUT_Deal(uint8_t l)
{ /* 用户可自定义 */
uint8_t i;
for(i = 0; i < l; i++)
{
pEP2_IN_DataBuf[i] = ~pEP2_OUT_DataBuf[i];
}
DevEP2_IN_Deal(l);
}
/*********************************************************************
* @fn DevEP3_OUT_Deal
*
* @brief 端点3数据处理
*
* @return none
*/
void DevEP3_OUT_Deal(uint8_t l)
{ /* 用户可自定义 */
uint8_t i;
for(i = 0; i < l; i++)
{
pEP3_IN_DataBuf[i] = ~pEP3_OUT_DataBuf[i];
}
DevEP3_IN_Deal(l);
}
/*********************************************************************
* @fn DevEP4_OUT_Deal
*
* @brief 端点4数据处理
*
* @return none
*/
void DevEP4_OUT_Deal(uint8_t l)
{ /* 用户可自定义 */
uint8_t i;
for(i = 0; i < l; i++)
{
pEP4_IN_DataBuf[i] = ~pEP4_OUT_DataBuf[i];
}
DevEP4_IN_Deal(l);
}
/*********************************************************************
* @fn USB_IRQHandler
*
* @brief USB中断函数
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
void USB_IRQHandler(void) /* USB中断服务程序,使用寄存器组1 */
{
USB_DevTransProcess();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment