在端点0由GET_REPORT类请求上传报表
一般来说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紧张的话可以压缩压缩,按位标志),在主函数中处理报表的上传。
改动之处见有//XXX注释的代码行,复制到编译器中,在右侧一栏有蓝色标记帮助寻找位置。
#include "CH58x_common.h" //XXX "CH59x_common.h" 改个头文件就可以适配CH592 #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时表示第1个数据包,同步切换为data1 uint8_t ep0_present_tog; //当前使用的同步切换标志 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 先行定义待上传数据。拷贝了微软触摸板的默认blob进行测试。 0xfc,0x28,0xfe,0x84,0x40,0xcb,0x9a,0x87,0x0d,0xbe,0x57,0x3c,0xb6,0x70,0x09,0x88, 0x07,0x97,0x2d,0x2b,0xe3,0x38,0x34,0xb6,0x6c,0xed,0xb0,0xf7,0xe5,0x9c,0xf6,0xc2, 0x2e,0x84,0x1b,0xe8,0xb4,0x51,0x78,0x43,0x1f,0x28,0x4b,0x7c,0x2d,0x53,0xaf,0xfc, 0x47,0x70,0x1b,0x59,0x6f,0x74,0x43,0xc4,0xf3,0x47,0x18,0x53,0x1a,0xa2,0xa1,0x71, 0xc7,0x95,0x0e,0x31,0x55,0x21,0xd3,0xb5,0x1e,0xe9,0x0c,0xba,0xec,0xb8,0x89,0x19, 0x3e,0xb3,0xaf,0x75,0x81,0x9d,0x53,0xb9,0x41,0x57,0xf4,0x6d,0x39,0x25,0x29,0x7c, 0x87,0xd9,0xb4,0x98,0x45,0x7d,0xa7,0x26,0x9c,0x65,0x3b,0x85,0x68,0x89,0xd7,0x3b, 0xbd,0xff,0x14,0x67,0xf2,0x2b,0xf0,0x2a,0x41,0x54,0xf0,0xfd,0x2c,0x66,0x7c,0xf8, 0xc0,0x8f,0x33,0x13,0x03,0xf1,0xd3,0xc1,0x0b,0x89,0xd9,0x1b,0x62,0xcd,0x51,0xb7, 0x80,0xb8,0xaf,0x3a,0x10,0xc1,0x8a,0x5b,0xe8,0x8a,0x56,0xf0,0x8c,0xaa,0xfa,0x35, 0xe9,0x42,0xc4,0xd8,0x55,0xc3,0x38,0xcc,0x2b,0x53,0x5c,0x69,0x52,0xd5,0xc8,0x73, 0x02,0x38,0x7c,0x73,0xb6,0x41,0xe7,0xff,0x05,0xd8,0x2b,0x79,0x9a,0xe2,0x34,0x60, 0x8f,0xa3,0x32,0x1f,0x09,0x78,0x62,0xbc,0x80,0xe3,0x0f,0xbd,0x65,0x20,0x08,0x13, 0xc1,0xe2,0xee,0x53,0x2d,0x86,0x7e,0xa7,0x5a,0xc5,0xd3,0x7d,0x98,0xbe,0x31,0x48, 0x1f,0xfb,0xda,0xaf,0xa2,0xa8,0x6a,0x89,0xd6,0xbf,0xf2,0xd3,0x32,0x2a,0x9a,0xe4, 0xcf,0x17,0xb7,0xb8,0xf4,0xe1,0x33,0x08,0x24,0x8b,0xc4,0x43,0xa5,0xe5,0x24,0xc2 }; #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(); UART1_BaudRateCfg(1500000); 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) { ep0_st.ep0_present_tog = 1; //控制传输中第一个数据包同步切换为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 //第一个包之后同步切换 { if(ep0_st.ep0_present_tog) //上一包是data1 { R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; R8_UEP0_CTRL &= ~(RB_UEP_T_TOG); ep0_st.ep0_present_tog = 0; } else //上一包是data0 { R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; R8_UEP0_CTRL |= RB_UEP_T_TOG; ep0_st.ep0_present_tog = 1; } } 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(); }
用BUS HOUND测试可以获取到测试使用的256个字节的信息。