目录

一般来说HID设备的报表在端点数量资源充裕的情况下都走中断端点上传,不会走控制端点即端点0上传,如果资源不足,可以利用端点0上传报表,USB协议中也是支持在端点0上传报表的。

以CH582为例,EVT中的键鼠复合例程中,键盘走端点1而鼠标走端点2上传报表,互不耽误。如果端点资源比较紧张,多个设备的报表比如键鼠的报表,可以走同一个端点上传,这时就要在同一个端点上传的数据中区分报表。区分方法也很简单,在报表开头再添加一个字节作为Report ID,比如说键盘和鼠标的Report ID分别设置为0x01和0x02,上传8字节键盘报表前再加个0x01即可。如果端点资源真的很紧张,其他端点都被占用了,又要跑CDC又要跑MIDI等等,那还有端点0可以使用。当然当端点资源很紧张时需要首先评估一下在端点0上报数据能不能满足稳定性要求,如果非要实现严格的1ms上传一个HID报表,还是建议留足资源。

默认例程代码中没有处理端点0上传的HID类请求,可以按参考下方代码。下方代码中新增了一个结构体记录各标志(ram紧张的话可以压缩压缩,按位标志),在主函数中处理报表的上传。PS:下列代码上传超过64字节的报表时有BUG,待修复。

改动之处见有//XXX注释的代码行,复制到编译器中,在右侧一栏有蓝色标记帮助寻找位置。

#include "CH58x_common.h"

#define DEF_USB_GET_REPORT           0x01      //XXX 主机可以使用端点0来获取报表描述符

struct USB_ep0_st                    //XXX
{
uint8_t ep0_in; //置1时表示收到端点0收到in令牌包
uint8_t ep0_1st_data; //第1个数据包同步切换为data1
uint8_t ep0_getting_report; //置1时表示正在获取报表,报表全部传输完后手动置0
uint8_t ep0_report_choosing; //置1时表示收到了GET_REPORT请求,正在进行报表选择
uint8_t ep0_report_ID; //HID类请求中的report ID
uint16_t ep0_Req_Len; //HID类请求中的report长度
uint16_t ep0_Send_Len; //实际上传发送的长度
}; struct USB_ep0_st ep0_st = {0}; //XXX 帮助进行HID类请求的回复 const uint8_t HID_Descr_Ep0_1[] = { //XXX 先行定义待上传数据
0x03, 0x04
}; const uint8_t HID_Descr_Ep0_2[] = { //XXX 先行定义待上传数据
0x0a, 0x0b, 0x0c, 0x0d, 0x0f
}; #define DevEP0SIZE 0x40
// 设备描述符
const uint8_t MyDevDescr[] = {0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, DevEP0SIZE, 0x3d, 0x41, 0x07, 0x21, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01};
// 配置描述符
const uint8_t MyCfgDescr[] = {
0x09, 0x02, 0x3b, 0x00, 0x02, 0x01, 0x00, 0xA0, 0x32, //配置描述符
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x00, //接口描述符,键盘
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3e, 0x00, //HID类描述符
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x0a, //端点描述符
0x09, 0x04, 0x01, 0x00, 0x01, 0x03, 0x01, 0x02, 0x00, //接口描述符,鼠标
0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, 0x34, 0x00, //HID类描述符
0x07, 0x05, 0x82, 0x03, 0x04, 0x00, 0x0a //端点描述符 };
/* USB速度匹配描述符 */
const uint8_t My_QueDescr[] = {0x0A, 0x06, 0x00, 0x02, 0xFF, 0x00, 0xFF, 0x40, 0x01, 0x00}; /* USB全速模式,其他速度配置描述符 */
uint8_t USB_FS_OSC_DESC[sizeof(MyCfgDescr)] = {
0x09, 0x07, /* 其他部分通过程序复制 */
}; // 语言描述符
const uint8_t MyLangDescr[] = {0x04, 0x03, 0x09, 0x04};
// 厂家信息
const uint8_t MyManuInfo[] = {0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0};
// 产品信息
const uint8_t MyProdInfo[] = {0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '7', 0, 'x', 0};
/*HID类报表描述符*/
const uint8_t KeyRepDesc[] = {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, 0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x29, 0x91, 0x81,
0x00, 0xC0};
const uint8_t MouseRepDesc[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29,
0x03, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x03, 0x81, 0x02, 0x75, 0x05, 0x95, 0x01,
0x81, 0x01, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75,
0x08, 0x95, 0x03, 0x81, 0x06, 0xC0, 0xC0}; /**********************************************************/
uint8_t DevConfig, Ready;
uint8_t SetupReqCode;
uint16_t SetupReqLen;
const uint8_t *pDescr;
uint8_t Report_Value = 0x00;
uint8_t Idle_Value = 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;
}
ep0_st.ep0_in = 0; //XXX 清标志表示已上传完成
}
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 */
Idle_Value = EP0_Databuf[3];
break; //这个一定要有 case DEF_USB_SET_REPORT: /* 0x09: SET_REPORT */
break; case DEF_USB_SET_PROTOCOL: /* 0x0B: SET_PROTOCOL */
Report_Value = EP0_Databuf[2];
break; case DEF_USB_GET_IDLE: /* 0x02: GET_IDLE */
EP0_Databuf[0] = Idle_Value;
len = 1;
break; case DEF_USB_GET_PROTOCOL: /* 0x03: GET_PROTOCOL */
EP0_Databuf[0] = Report_Value;
len = 1;
break; case DEF_USB_GET_REPORT: //XXX
ep0_st.ep0_report_ID = (uint8_t)pSetupReqPak->wValue; //保存report ID
ep0_st.ep0_Req_Len = SetupReqLen; //保存请求中索取的长度
ep0_st.ep0_report_choosing = 1; //置标志表示待选择report ID
PRINT("GET_REPORT_ID\n");
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(!ep0_st.ep0_report_choosing) //XXX 如果有待选择的报表,放到主函数里处理
{
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)
{
if(ep0_st.ep0_report_choosing)
{
switch(ep0_st.ep0_report_ID) //XXX 根据USB传输中断中的赋值选择
{
case 0x03:
ep0_st.ep0_1st_data = 1;
ep0_st.ep0_getting_report = 1; //选好报表后将要上传
PRINT("select id %d\n", ep0_st.ep0_report_ID);
pDescr = HID_Descr_Ep0_1; //选择预设的待上传数据,可改动
ep0_st.ep0_Send_Len = sizeof(HID_Descr_Ep0_1); //实际发送长度预设为实际长度 if (ep0_st.ep0_Send_Len > ep0_st.ep0_Req_Len) //ep0_Req_Len中存放的是HID请求中的长度,ep0_Send_Len存放应该上传的长度
{ //如果实际长度不足,按实际长度发送
ep0_st.ep0_Send_Len = ep0_st.ep0_Req_Len; //如果实际长度太长,按HID请求中的长度发送
PRINT("select IN_if\n");
}
PRINT("select len %d\n", ep0_st.ep0_Send_Len);
break; case 0x0A:
ep0_st.ep0_1st_data = 1;
ep0_st.ep0_getting_report = 1; //选好报表后将要上传
PRINT("select id %d\n", ep0_st.ep0_report_ID);
pDescr = HID_Descr_Ep0_2; //选择预设的待上传数据,可改动
ep0_st.ep0_Send_Len = sizeof(HID_Descr_Ep0_2); //实际发送长度预设为实际长度 if (ep0_st.ep0_Send_Len > ep0_st.ep0_Req_Len) //ep0_Req_Len中存放的是HID请求中的长度,ep0_Send_Len存放应该上传的长度
{ //如果实际长度不足,按实际长度发送
ep0_st.ep0_Send_Len = ep0_st.ep0_Req_Len; //如果实际长度太长,按HID请求中的长度发送
PRINT("select IN_if\n");
}
PRINT("select len %d\n", ep0_st.ep0_Send_Len);
break; default: //无法识别,应该发stall,参考上面的处理,这里没有添加
break;
}
ep0_st.ep0_report_choosing = 0; //清标志,报表数组选择完了
} if((ep0_st.ep0_in == 0) && (ep0_st.ep0_getting_report == 1)) //XXX 上一包IN令牌包完成且正在上传报表
{
PRINT("S_IN\n");
uint16_t len = 0; //存放待发送的长度 if(ep0_st.ep0_Send_Len <= DevEP0SIZE) //检查一包能否传完
{
len = ep0_st.ep0_Send_Len;
}
else
{
len = DevEP0SIZE;
} memcpy(pEP0_DataBuf, pDescr, len);
ep0_st.ep0_in = 1; //置位表示当前IN事务正在上传
ep0_st.ep0_Send_Len -= len; //记录剩下的需要发送的数据长度
pDescr += len; //更新接下来需要发送的数据的起始地址,拷贝函数用
if(!ep0_st.ep0_Send_Len)
{
ep0_st.ep0_getting_report = 0; //报表上传完毕,清标志
}
R8_UEP0_T_LEN = len; if(ep0_st.ep0_1st_data) //控制传输中第一个数据包同步切换为data1
{
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
ep0_st.ep0_1st_data = 0; //清标志
}
else //第一个包之后同步切换
{
R8_UEP0_CTRL ^= RB_UEP_T_TOG; // 同步切换。IN方向(对于单片机就是T方向)的PID中的DATA0和DATA1切换
R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
} PRINT("S_%d\n", ep0_st.ep0_Send_Len);
}
}
} /*********************************************************************
* @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();
}

最新文章

  1. Asp.net Core准备工作
  2. HTML5本地存储——IndexedDB(一:基本使用)
  3. iOS Bundle display name国际化
  4. Scalaz(53)- scalaz-stream: 程序运算器-application scenario
  5. CSS3硬件加速需要注意的事项
  6. jeecms子栏目或者文章页导航父栏目选中解决方法
  7. hdu 3778
  8. [Tommas] 测试场景 VS 测试用例 哪个更好?(转)
  9. flashback database操作步骤
  10. 【BZOJ2208】【JSOI2010】连通数 传递闭包
  11. 模块---hashlib、configparse、logging
  12. 配置sudo日志审计
  13. 基于LNMP(fastcgi协议)环境部署、原理介绍以及fastcgi_cache配置以及upstream模块负载均衡讲解
  14. Jenkins-Multijob plugin多任务串并行
  15. PHP 错误 系列:编码格式错误解决
  16. Xcode工程编译错误:“Cannot assign to &#39;self&#39; outside of a method in the init family”
  17. leetcode 29-&gt; Divide Two Integers without using multiplication, division and mod operator
  18. TweenMax 参考
  19. tar 使用总结
  20. Google File System 学习

热门文章

  1. VUEX state 的使用学习二
  2. vue element admin 关闭eslint校验
  3. 一键部署nfs、rsync、sersync
  4. 花1分钟配置远程DEBUG,开发效率翻倍,妹子直呼绝绝子
  5. Pycharm中图标的含义
  6. FAQ selenium无法click的一个案例分享(2)
  7. 【一句话】CAP原则
  8. Idea未识别maven项目
  9. mysql17-sql优化-慢查询日志
  10. 2.1.新建项目及项目目录和预览uni项目