Created
May 28, 2025 13:33
-
-
Save nickfox-taterli/a9c076998a7c2d8fc161c5120e54e6a4 to your computer and use it in GitHub Desktop.
CompoundDev CH582 Keyboard + Mouse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************** (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