开始打算做一个关于USB设备共享的机器,多台电脑共享一个鼠标键盘;
模拟鼠标或者键盘,必须使用外部固件模式,内置固件只负责信息数据的传输,所以不得不选择并口控制或者SPI的方式,接下来就是了解基本的USB协议的尝试,懂得USB设备与PC机进行信息握手的过程,懂得什么是SETUP,什么是设备描述符,什么是配置描述符,
以下是部分关于CH372模拟HID鼠标的程序:使用STM32
static void CH376_DATA_DIR_IN( );
BOOLEAN CH375ACT;
BOOLEAN CH375FLAGERR; //错误清0
BOOLEAN CH375CONFLAG;
BOOLEAN IsBusying;
unsigned char buf[64];
typedef union _REQUEST_PACK{
unsigned char buffer[8];
struct{
unsigned char bmReuestType; //标准请求字
unsigned char bRequest; //请求代码
unsigned int wValue; //特性选择高
unsigned int wIndx; //索引
unsigned int wLength; //数据长度
}r;
} mREQUEST_PACKET, *mpREQUEST_PACKET;
//设备的描述符包含设备描述符、配置描述符、字符描述符;识别描述符的类型就是根据它的第二个字节值来识别;
//一般情况下设备描述符不需要用户去配置,因为可以直接用软件从现有的设备中读取;同种设备的描述符都相同;如优盘描述符都一样
/*以下是设备描述符,(为什么是这些数值,可查阅USB协议书籍)*/
unsigned char DevDes[]={
0x12, //描述符长度,长度1个字节,值18
0x01, //描述符类型,长度1个字节,值:1-设备描述符,2-配置描述符,3-字符串描述符,4-接口描述符,5-端点描述符
0x10, //USB规范版本信息,长度2个字节,BCD码:USB1.1-0110、USB2.0-0200
0x01,
0x00, //类别码,长度1个字节,数值0X01~0XFE为USB定义的类,如打印机等;00-USB设备的各个接口属于不同的类,由接口描述符提供类的值;02-通信类;03-HID类;09-集线器类;
//DC-用于诊断用途的设备类;e0-无线通信设备类;XFF是由厂商定义的设备的类别;
0x00, //子类别码,长度1个字节,类别码为0,则也必须为0;USB协会指定;0xff-厂商自定义
0x00, //协议代码,长度1个字节,USB协会指定;0-不使用任何设备类协议,类别码为0时,必须为0;0xff-厂商自定义
0x08, //端点0的最大信息包大小,长度1字节,低速设备-8,全速设备-8/16/32/64,高速设备-64
0x87, //厂商ID,VID长度2字节,USB协会分配给不同的厂商,操作系统会根据VID和PID加载驱动
0x88,
0x11, //产品ID,PID长度2字节,厂商定义,操作系统加载设备驱动与其有关
0x00,
0x00, //设备版本信息,长度2字节,厂商定义,操作系统加载驱动与其有关
0x01,
0x01, //描述厂商的字符串描述符的索引值,长度1字节,0-没有厂商字符串;主机获取设备描述符时将其放入WVALUE中,以选择不同的字符串;具体字符串内容在字符串描述符中定义
0x02, //描述产品的字符串描述符的索引值,长度1字节,0-没有产品字符串;第一次插入USB设备时,在系统桌面右下角弹出的提示信息就是产品字符串
0x03, //描述设备的序列号的字符串描述符的索引值,长度1字节,0-没有序列号描述符
0x01, //设备支持的配置的数目,长度1字节,一个设备可能有多种配置,每种配置有一个配置描述符,主机通过发送设备配置来选择某一配置
};
//配置描述符;包括配置描述符、接口描述符、端点描述符,HID设备还包括HID描述符;
unsigned char ConDes[]={
//配置描述符
0x09, //描述符大小
0x02, //描述符类型02-配置描述符
0x22, //此配置传回所有数据大小,包括配置描述符、接口描述符、类描述符、端点描述符
0x00, //
0x01, //接口数
0x01, //配置值
0x00, //描述改配置的字符串的索引,0-没有配置描述字符串
0x80, //设备属性D7保留位 1,D6:0-总线供电 D5:1-支持远程唤醒 D4-D0:保留位 0000
0x40, //设备需要的电流,单位为2ma
//接口描述符
0x09, //描述符大小
0x04, //描述符类型04-接口描述符
0x00, //接口编号
0x00, //接口备用编号
0x01, //支持的端点数 0-没有非零端点 使用默认控制端点
0x03, //类别码
0x01, //子类别码 0-无引导的HID设备 1-有引导的HID设备
0x02, //协议码子类别码为0时必须也为0 子类别吗为1时 1-键盘 2-鼠标
0x00, //描述该接口的字符串的索引,0-没有
//HID描述符
0x09, //描述符长度
0x21, //描述符类型 0x21-HID
0x10, //HID协议版本
0x01,
0x21, //国家码,美式键盘33
0x01, //下级描述符数量,至少为1,下级描述符即报告描述符或物理描述符
0x22, //下级描述符类型,0x22-报告描述符 0x23-物理描述符
0x34, //下级描述符长度,2字节,
0x00,
//端点描述符
0x07, //描述符长度
0x05, //描述符类型 5-端点描述符
0x81, //端点地址,D7-传输方向 1-IN 0-OUT,D3-D0:端点号,D6-D4:保留值
0x03, //端点类型;D1-D0:0-控制传输 1-等时传输 2-批量传输 3-中断传输;非等时传输D7-D2保留值 0,等时传输D7-D6保留,D5-D4用途 0-数据端点 1反馈端点 2-暗含反馈的数据端点 D3-D2同步类型0 无同步1-异步 2适配 3 同步
0x10, //最大数据包长度
0x00, //
0x0a, //查询间隔
};
//字符串描述符,报表描述符;
//作键盘设备时,报表描述符描述了数据格式;如键盘,则必须发送8个字节的数据;其中第3个字节是要在
//各种文本里显示的数据(如WORD文挡);其余字节全为0;
unsigned char Hid_des[]={
0x05, 0x01, //全局项目,表示用途页为桌面设备
0x09, 0x02, //局部项目,表示用途为鼠标
0xa1, 0x01, //开集合,主项目,应用集合
0x09, 0x01, //局部项目,指针设备
0xa1, 0x00, //开集合,主项目,物理集合
0x05, 0x09, //全局项目,用途为按键
0x19, 0x01, //局部项目,用途最小值为1,鼠标左键
0x29, 0x03, //局部项目,用途最大值为3,鼠标中键
0x15, 0x00, //全局项目,返回数据的逻辑值的最小值为0
0x25, 0x01, //全局项目,返回数据的逻辑值的最大值为1
0x95, 0x03, //全局项目,返回值的数据域数量有3个
0x75, 0x01, //全局项目,返回值每个数据域长度1位
0x81, 0x02, //主项目,说明有3个长度为1的数据域做输入,属性为DATA VAR ABS,ADAT表示数据可变动,VAR表示这些数据域是独立的变量,即每个数据域表示一个意思,ABS表示他们是绝对值。长度由前述的两个全局项目定义,
0x95, 0x01, //全局项目,数据域数量有1个
0x75, 0x05, //全局项目,数据域长度为5位
0x81, 0x03, //主项目,说明有一个长度为5位的数据域做输入,属性为CNST VAR ABS,CNST表示常量,目的是补齐8位,因为前面只有3位
0x05, 0x01, //全局项目,用途是通用桌面
0x09, 0x30, //局部项目,用途X轴
0x09, 0x31, //局部项目,用途Y轴
0x09, 0x38, //局部项目,用途为滚轮,即中键
0x15, 0x81, //全局项目,返回值的逻辑值的最大和最小值分别为-127和127;
0x25, 0x7f,
0x75, 0x08, //全局项目,每个数据域的长度为8位
0x95, 0x03, //全局项目,数据域的个数为3个
0x81, 0x06, //全局项目,说明前述的3个数据域为输入,属性为DATA VAR REL,DATA、VAR前面已经讲过,REL表示这些值是相对值,即鼠标移动时,发送的只是变化量
0xc0, //关闭集合
0xc0 //关闭集合
};
unsigned char LangDes[]={0x04,0x03,0x09,0x04}; //语言描述符
unsigned char SerDes[] ={0x16,0x03,0xDD,0x84,0xD7,0x65,0x4C,0x5D,0x65,0x51,0x0F,0x5F,0x48,0x00,0x49,0x00,
0x44,0x00,0x20,0x9F,0x07,0x68};
unsigned char Chan[]={0x16,0x03,0x32,0x00,0x30,0x00,0x30,0x00,0x31,0x00,0x2d,0x00,0x30,0x00,0x37,0x00,0x2d,0x00,0x30,0x00,0x31,0x00};
unsigned char Chang[] ={0x14,0x03,'L',0,'E',0,'N',0,'C',0,'H',0,'I',0,'M',0,'C',0,'U',0};
unsigned char mVarSetupRequest; // ;USB请求码
unsigned char mVarSetupLength; // ;后续数据长度
unsigned char * VarSetupDescr;// ;描述符偏移地址
unsigned char buf1[8];
unsigned char VarUsbAddress ; //
unsigned char Report_ID=0X01;
unsigned char UPDATA_FLAG;
mREQUEST_PACKET request;
void sys_DATA_IoInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = WR_PIN ;
GPIO_Init(WR_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = A0_PIN ;
GPIO_Init(A0_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RD_PIN ;
GPIO_Init(RD_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CS_PIN ;
GPIO_Init(CS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CH376_INT1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(CH376_INT1_PORT , &GPIO_InitStructure);
GPIO_SetBits(CS_PORT,CS_PIN); // CH376_CS = 1;
GPIO_SetBits(WR_PORT,WR_PIN); // CH376_WR = 1;
GPIO_SetBits(RD_PORT,RD_PIN); // CH376_RD = 1;
GPIO_ResetBits(A0_PORT,A0_PIN); // CH376_A0 = 0;
CH376_DATA_DIR_IN();
}
/***********************************************************************************
****函数名称:不准确的延时20US的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay20us(void)
{
// unsigned char i;
// for(i=0;i<20;i++);
}
/***********************************************************************************
****函数名称:不准确的延时1mS的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay1ms(void)
{
// unsigned char m,n;
// for(m=0;m<200;m++)
// for(n=0;n<50;n++);
}
/***********************************************************************************
****函数名称:不准确的延时50mS的函数
****函数作用:
****函数描述:
************************************************************************************/
static void delay50ms(void)
{
// unsigned char m,n;
// for(m=0;m<200;m++)
// for(n=0;n<250;n++);
}
static void CH376_DATA_DIR_IN( )
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = D0_PIN|D1_PIN|D2_PIN|D3_PIN|D4_PIN|D5_PIN|D6_PIN|D7_PIN; //OE0:PA7 OE1:PA15 OE2:PA8
GPIO_Init(D0_PORT, &GPIO_InitStructure);
}
static void CH376_DATA_DIR_OUT( )
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = D0_PIN| D1_PIN|D2_PIN|D3_PIN|D4_PIN|D5_PIN|D6_PIN|D7_PIN; //OE0:PA7 OE1:PA15 OE2:PA8
GPIO_Init(D0_PORT, &GPIO_InitStructure);
}
static uint8_t CH376_DATA_DAT_IN(void)
{
u16 cmd1; uint8_t cmd;
cmd1=GPIO_ReadInputData(D0_PORT);
cmd=(GPIO_ReadInputData(D0_PORT)&0xff00)>>8;
delay50ms();
return(cmd);
}
static void CH376_DATA_DAT_OUT(u16 cmd)
{
u16 Temp;
Temp=GPIO_ReadOutputData(D0_PORT);
delay50ms();
GPIO_Write(D0_PORT,(Temp&0x00ff)|(((u16)cmd)<<8));
}
/*******************************************************************************
* Function Name : CH376_WR_CMD_PORT 串口发送命令前需要发送57 ab同步码
* Description : 写CH376命令子函数
* Input : - cmd: 8位命令码
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void CH376_WR_CMD_PORT( u16 cmd )
{
delay20us();
CH376_DATA_DIR_OUT( );
CH376_DATA_DAT_OUT(cmd);
GPIO_SetBits(A0_PORT,A0_PIN); // CH376_A0 = 1;
GPIO_SetBits(RD_PORT,RD_PIN); // CH376_RD =1;
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
GPIO_ResetBits(WR_PORT,WR_PIN); // CH376_WR = 0;
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
delay50ms();
GPIO_SetBits(WR_PORT,WR_PIN); // CH376_WR =1;
GPIO_SetBits(CS_PORT,CS_PIN); // CH376_CS = 1;
GPIO_ResetBits(A0_PORT,A0_PIN); // CH376_A0 = 0;
CH376_DATA_DAT_OUT(0xffff);
}
/*******************************************************************************
* Function Name : CH376_WR_DAT_PORT
* Description : 写CH376数据子函数
* Input : - dat: 8位数据
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void CH376_WR_DAT_PORT( u16 dat )
{
CH376_DATA_DIR_OUT( ); /* 设置并口方向为输出 */
delay20us();
CH376_DATA_DAT_OUT( dat ); /* 向CH376的并口输出数据 */
GPIO_ResetBits(A0_PORT,A0_PIN); // CH376_A0 = 0;
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
GPIO_ResetBits(WR_PORT,WR_PIN); // CH376_WR = 0;
delay20us();
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
delay20us();
GPIO_SetBits(WR_PORT,WR_PIN); // CH376_WR =1;
GPIO_SetBits(CS_PORT,CS_PIN); // CH376_CS = 1;
CH376_DATA_DAT_OUT(0xffff); /* 禁止数据输出 */
}
/*******************************************************************************
* Function Name : CH376_RD_DAT_PORT
* Description : 读CH376数据子函数
* Input : None
* Output : None
* Return : 8位数据
* Attention : 等待读到数据
*******************************************************************************/
uint8_t CH376_RD_DAT_PORT( void )
{
uint8_t mData;
// mDelay0_5uS( ); /* 确保读写周期大于0.6uS */
CH376_DATA_DIR_OUT( ); /* 设置并口方向为输出 */
CH376_DATA_DAT_OUT(0xffff); /* 禁止数据输出 */
GPIO_ResetBits(A0_PORT,A0_PIN); // CH376_A0 = 0;
CH376_DATA_DIR_IN( ); /* 设置并口方向为输入 */
CH376_DATA_DAT_OUT(0x0000); /* 禁止数据输出 */
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
GPIO_ResetBits(RD_PORT,RD_PIN); // CH376_WR = 0;
GPIO_ResetBits(CS_PORT,CS_PIN); // CH376_CS = 0;
delay50ms();
delay20us();
mData = CH376_DATA_DAT_IN( ); /* 从CH376的并口输入数据 */
GPIO_SetBits(RD_PORT,RD_PIN); // CH376_RD =1;
delay50ms();
GPIO_SetBits(CS_PORT,CS_PIN); // CH376_CS = 1;
CH376_DATA_DIR_OUT( ); /* 设置并口方向为输出 */
CH376_DATA_DAT_OUT(0xffff); /* 禁止数据输出 */
return( mData );
}
void device_376(void)
{
sys_DATA_IoInit();
sysReset();
CH376_WR_CMD_PORT( CMD_SET_USB_MODE );
CH376_WR_DAT_PORT( 0);
delay50ms();
CH376_WR_CMD_PORT( CMD_SET_USB_MODE );
CH376_WR_DAT_PORT( 1); /* 设置为使用内置固件的USB设备方式 */
for ( ;; ) { /* 等待操作成功,通常需要等待10uS-20uS */
if ( CH376_RD_DAT_PORT( )==CMD_RET_SUCCESS ) break;
}
}
void IO_cfg() //GPIO初始化
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //选择引脚2 3 5 作为中断信号输入端
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
GPIO_Init(GPIOA,&GPIO_InitStructure); //设置PA.2 /PA.3 /PA.5
}
void EXTIX_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //选择中断分组2,3个中断源,需2bit进行优先级设置
//高两位用于设置抢占式 优先级;
//低两位用于设置响应式 优先级
NVIC_InitStructure.NVIC_IRQChannel = EXTI_Line0; //选择中断通道2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
void EXTI_cfg() //将相应的IO口与中断线路进行连接
{
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量
EXTI_ClearITPendingBit(EXTI_Line0); //清空中断标志 PA.2 中断口
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择中断管脚PA.2 PA.3 PA.5
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //选择中断线路2 3 5
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断请求,非事件请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //设置中断触发方式为上下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //外部中断使能
EXTI_Init(&EXTI_InitStructure);
}
void ioInterruptSet(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_ClearITPendingBit(EXTI_Line0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //选择中断线路0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断请求,非事件请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //外部中断使能
EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择中断分组2
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //选择中断通道2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
///***********************************************************************************
//****函数名称:端点1数据上传函数
//****函数作用:
//****函数描述:
//************************************************************************************/
//void ch372ep1up()
//{
// unsigned char i;
// CH375_WRCMD(CMD_WR_USB_DATA5);
// CH375_WRDAT(0x04);
// for(i=0;i<4;i++)
// CH375_WRDAT(MouseData[i]);
// IsBusying=1;
//
//}
/***********************************************************************************
****函数名称:端点0数据上传函数
****函数作用:
****函数描述:
************************************************************************************/
void mCh375Ep0Up()
{
unsigned char i,len;
if(mVarSetupLength)
{ //长度不为0传输具体长度的数据
if(mVarSetupLength<=8)
{
len=mVarSetupLength;
mVarSetupLength=0;
} //长度小于8则长输要求的长度
else
{
len=8;
mVarSetupLength-=8;
} //长度大于8则传输8个,切总长度减8
CH376_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令
CH376_WR_DAT_PORT(len); //写入长度
for(i=0;i!=len;i++)
{
CH376_WR_DAT_PORT(request.buffer[i]); //循环写入数据
}
}
else
{
CH376_WR_CMD_PORT(CMD_WR_USB_DATA3); //发出写端点0的命令
CH376_WR_DAT_PORT(0); //上传0长度数据,这是一个状态阶段
}
}
/***********************************************************************************
****函数名称:描述符复制函数
****函数作用:
****函数描述:
************************************************************************************/
void mCh375DesUp()
{
unsigned char k;
for (k=0; k!=8; k++ )
{
request.buffer[k]=*VarSetupDescr; //依次复制8个描述符,
VarSetupDescr++;
}
}
/***********************************************************************************
****函数名称:外部中断0的响应函数
****函数作用:通过判断375的终端类型值进行相应的处理
****函数描述:
************************************************************************************/
void EXTI0_IRQHandler(void)
{
unsigned char i,temp,length,len;
unsigned char c1;
// ;//SendStr("......进入中断......\r\n");
//unsigned char *pBuf;
//unsigned char mBuf[64];
EXTI_ClearITPendingBit(EXTI_Line0); //清空中断标志位,防止持续进入中断
CH376_WR_CMD_PORT(CMD_GET_STATUS); /* 向CH375芯片发送获取中断状态的命令;CMD_GET_STATUS为命令码,数值大小在CH375INC.H 头文件中*/
temp =CH376_RD_DAT_PORT(); /* 读取中断状态 */
switch(temp) //判断中断类型(状态),具体区分请见375头文件中的定义
{
case USB_INT_EP0_SETUP:
;//SendStr("......接收到SETUP......\r\n");
CH376_WR_CMD_PORT(CMD_RD_USB_DATA);
length=CH376_RD_DAT_PORT();
for(i=0;i
request.buffer[i]=CH376_RD_DAT_PORT();
//SendHex(request.buffer[i]);
;//SendStr("\r\n");
}
if(length==8)//如果长度是8
{
mVarSetupLength=request.buffer[6]&0x7f;//控制传输的数据长度最长是128字节
if(request.r.bmReuestType&0x40)//6-5=10厂商请求
;//SendStr("......厂商请求......\r\n");
if(request.r.bmReuestType&0x20)//6-5=01类请求
;//SendStr("......类请求......\r\n");
if(!(request.r.bmReuestType&0x60))//6-5=00标准请求,一共11中标准请求
{
mVarSetupRequest=request.r.bRequest;//将标准请求保存
switch(request.r.bRequest)//判断标准请求
{
case DEF_USB_GET_CONFIG://获取配置
;//SendStr("......获取配置......\r\n");
break;
case DEF_USB_GET_DESCR://获取描述符
;//SendStr("......获取描述符......\r\n");
switch(request.buffer[3])//判断描述符的类型
{
case 1://设备描述符
;//SendStr("......请求设备描述符......\r\n");
VarSetupDescr=DevDes;
break;
case 2://配置描述符
;//SendStr("......请求配置描述符......\r\n");
VarSetupDescr=ConDes;
break;
case 3://字数串描述符
;//SendStr("......请求字符串描述符......\r\n");
//VarSetupDescr=
if(request.buffer[4]==0)
{
;//SendStr("......请求语言描述符......\r\n");
VarSetupDescr=LangDes;
mVarSetupLength=4;
}
if(request.buffer[2]==1)
{
;//SendStr("......请求厂商字符串......\r\n");
VarSetupDescr=Chang;
mVarSetupLength=0x14;
}
if (request.buffer[2]==2)
{
;//SendStr("......请求产品字符串......\r\n");
VarSetupDescr=SerDes;
mVarSetupLength=0x16;
}
if(request.buffer[2]==3)
{
;//SendStr("......请求产品序列号......\r\n");
VarSetupDescr=Chan;
mVarSetupLength=0x16;
}
break;
case 4://接口描述符
;//SendStr("......请求接口描述符......\r\n");
break;
case 5://端点描述符
;//SendStr("......请求端点描述符......\r\n");
break;
case 0x22://获取HID报告描述符
;//SendStr("......请求HID......\r\n");
VarSetupDescr=Hid_des;
mVarSetupLength=0x34;
break;
default://没有定义
;//SendStr("......不支持的描述符请求......\r\n");
break;
}
mCh375DesUp();
break;
case DEF_USB_GET_INTERF://获取接口
;//SendStr("......获取接口......\r\n");
break;
case DEF_USB_GET_STATUS://获取状态
;//SendStr("......获取状态......\r\n");
break;
case DEF_USB_SYNC_FRAME://同步帧
;//SendStr("......同步帧......\r\n");
break;
case DEF_USB_CLR_FEATURE://清除特性
;//SendStr("......清除特性......\r\n");
break;
case DEF_USB_SET_ADDRESS://设置地址
;//SendStr("......设置地址......\r\n");
VarUsbAddress=request.buffer[2];
break;
case DEF_USB_SET_CONFIG://设置配置
;//SendStr("......设置配置......\r\n");
break;
case DEF_USB_SET_DESCR://设置描述
;//SendStr("......设置描述......\r\n");
CH375CONFLAG=0;
if(request.buffer[2]!=0)
{
CH375CONFLAG=1;
}
break;
case DEF_USB_SET_FEATURE://设置特性
;//SendStr("......设置特性......\r\n");
break;
case DEF_USB_SET_INTERF://设置接口
;//SendStr("......设置接口......\r\n");
break;
default :
;//SendStr("......不支持的标准请求......\r\n");
CH376_WR_CMD_PORT (CMD_UNLOCK_USB); //释放缓冲区
break;
}
}
}
mCh375Ep0Up();
break;
case USB_INT_EP0_OUT:
CH376_WR_CMD_PORT(CMD_RD_USB_DATA); //发出读数据命令
if(length=CH376_RD_DAT_PORT())
{ //长度为0跳出
for(len=0;len!=length;len++)
c1=CH376_RD_DAT_PORT(); //取出下传数据
}
break;
case USB_INT_EP0_IN:
;//SendStr("......端点0IN......\r\n");
if(mVarSetupRequest==DEF_USB_GET_DESCR)
{
mCh375DesUp();
mCh375Ep0Up();
;//SendStr("......描述符上传成功......\r\n");
}
else
if(mVarSetupRequest==DEF_USB_SET_ADDRESS)
{ //设置地址
CH376_WR_CMD_PORT(CMD_SET_USB_ADDR);
CH376_WR_DAT_PORT(VarUsbAddress); //设置USB地址,设置下次事务的USB地址
}
CH376_WR_CMD_PORT(CMD_UNLOCK_USB); //释放缓冲区
break;
case USB_INT_EP1_OUT:
;//SendStr("......端点1OUT......\r\n");
break;
case USB_INT_EP1_IN:
;//SendStr("......端点1IN......\r\n");
CH376_WR_CMD_PORT(CMD_UNLOCK_USB);
IsBusying=0;
break;
case USB_INT_EP2_OUT:
;//SendStr("......端点2OUT......\r\n");
break;
case USB_INT_EP2_IN:
;//SendStr("......端点2IN......\r\n");
break;
case USB_INT_USB_SUSPEND:
;//SendStr("......USB挂起......\r\n");
break;
default:
;//SendStr("......总线复位......\r\n");
if((temp&0x03)==0x03)
{ //总线复位
CH375FLAGERR=0; //错误清0
CH375CONFLAG=0; //配置清0
mVarSetupLength=0;
}
CH376_WR_CMD_PORT (CMD_UNLOCK_USB); //释放缓冲区
break;
break;
}
}