CH374成功枚举USB键盘,获取按键值失败

#include "include.h"

#include "bsp_ch374.h"




const u8 SetupGetDevDescr[] = {0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00};/* 获取设备描述符 */

constu8 SetupGetCfgDescr[] = {0x80,0x06,0x00,0x02,0x00,0x00,0x04,0x00};/* 获取配置描述符 */

constu8 SetupSetUsbAddr[] = {0x00,0x05,0x02,0x00,0x00,0x00,0x00,0x00};/* 设置USB地址 */

const u8 SetupSetUsbConfig[] = {0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00};/* 设置USB配置 */

u8 SetupSetidle[]={0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00}; /* SET IDLE */

u8 SetupGetHidDes[]={0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00};/* 获取HID 报告描述符 */

u8 SetupSetReport[]={0x21,0x09,0x00,0x02,0x00,0x00,0x01,0x00};/* SET REPORT */  


u8 endp_out_addr;//输出地址(端口)

u8 endp_in_addr;//输入地址(端口)

u8 endp_in_addr;// in 端点地址 

u8 ReadDataFlag;//读取数据的同步标志

u8 hid_des_leng;// HID类报告描述符的长度

u8 FlagDeviceStatus;// 当前USB设备状态,通常用于中断方式的全局变量,本程序中未使用 

u8 UsbDevEndpSize = DEFAULT_ENDP0_SIZE;

/**

  *@Name:SetHostLeisure

*@Describe:设定USB主机空闲

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

void SetHostLeisure(void)

{

//CH374_WRITE_REGISTER( REG_USB_SETUP, M_SET_USB_BUS_FREE( Read374Byte( REG_USB_SETUP ) ) );    // USB总线空闲

CH374_WRITE_REGISTER( REG_USB_SETUP, BIT_SETP_HOST_MODE| BIT_SETP_AUTO_SOF );                 // USB总线复位

}

/**

  *@Name:SetHostUsbAddr

*@Describe:设置USB主机当前操作的USB设备地址

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

void SetHostUsbAddr( u8 addr )  

{

CH374_WRITE_REGISTER(REG_USB_ADDR,addr);

}


/**

  *@Name:Init374Host

*@Describe:初始化USB主机

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

void Init374Host(void)

{

CH374_WRITE_REGISTER( REG_USB_SETUP,0x00);

SetHostUsbAddr(0x00);

CH374_WRITE_REGISTER( REG_USB_H_CTRL,0x00);

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG );  // 清所有中断标志

//CH374_WRITE_REGISTER( REG_INTER_EN, BIT_IE_TRANSFER );                         // 允许传输完成中断,因为本程序使用查询方式检测USB设备插拔,所以无需USB设备检测中断

CH374_WRITE_REGISTER( REG_INTER_EN, BIT_IE_TRANSFER | BIT_IE_DEV_DETECT );     // 允许传输完成中断和USB设备检测中断

CH374_WRITE_REGISTER( REG_SYS_CTRL, BIT_CTRL_OE_POLAR );                       // 对于CH374T或者UEN引脚悬空的CH374S必须置BIT_CTRL_OE_POLAR为1

SetHostLeisure();                                                     // USB总线空闲

}

/**

  *@Name:HostSetReset

*@Describe:USB总线复位

*@Output:Not

*@Input:Not

*@Date:2017-02-20

**/

void HostSetReset(void)

{

UsbDevEndpSize = DEFAULT_ENDP0_SIZE;                                                // USB设备的端点0的最大包尺寸 

SetHostUsbAddr(0x00);

CH374_WRITE_REGISTER(REG_USB_H_CTRL,0x00);

//Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_RESET( Read374Byte( REG_USB_SETUP ) & ~ BIT_SETP_AUTO_SOF ) );  // USB总线复位

CH374_WRITE_REGISTER( REG_USB_SETUP, M_SET_USB_BUS_RESET( BIT_SETP_HOST_MODE ) );           // USB总线复位

  OSTimeDly(1); //延时1*20ms = 20ms  // USB总线复位期间

//Write374Byte( REG_USB_SETUP, M_SET_USB_BUS_FREE( Read374Byte( REG_USB_SETUP ) ) );  // USB总线空闲

SetHostLeisure();                                                                  // USB总线空闲

delay_us(1000);

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_USB_SUSPEND );  // 清中断标志

}



/**

  *@Name:Query374DevFullSpeed

*@Describe:查询当前的USB设备是全速还是低速, 返回TRUE为全速 

*@Output:返回1则全速,返回0则低速

*@Input:Not

*@Date:2017-02-20

**/

u8 Query374DevFullSpeed(void)

{

if((CH374_READ_REGISTER(REG_SYS_INFO) & BIT_INFO_USB_DP))

return 1;

else

return 0;

}


/**

  *@Name:HostSetFullSpeed

*@Describe:设定全速USB设备运行环境 

*@Output:Not

*@Input:Not

*@Date:2017-02-20

**/

void HostSetFullSpeed( void )  

{

CH374_WRITE_REGISTER(REG_USB_SETUP, (CH374_READ_REGISTER(REG_USB_SETUP) & (~BIT_SETP_USB_SPEED)) | BIT_SETP_AUTO_SOF );// 全速且发SOF

delay_us(1000);

}


/**

  *@Name:HostSetLowSpeed

*@Describe:设定低速USB设备运行环境 

*@Output:Not

*@Input:Not

*@Date:2017-02-20

**/

void HostSetLowSpeed( void )  

{

CH374_WRITE_REGISTER(REG_USB_SETUP, CH374_READ_REGISTER(REG_USB_SETUP) | BIT_SETP_USB_SPEED | BIT_SETP_AUTO_SOF );// 低速且发SOF

delay_us(1000);

}


/**

  *@Name:Query374Interrupt

*@Describe:查询CH374的中断

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

u8 Query374Interrupt(void)

{

#ifdef CH374_INT_WIRE   

 if(CH374_INT_WIRE) return 0;

 else return 1;

    //return( CH374_INT_WIRE ? FALSE : TRUE );  /* 如果连接了CH374的中断引脚则直接查询中断引脚 */   

  #else  

 if(CH374_READ_REGISTER( REG_INTER_FLAG ) & ( BIT_IF_DEV_DETECT | BIT_IF_TRANSFER )) return 1;

 else return 0;

   // return( Read374Byte( REG_INTER_FLAG ) & BIT_IF_INTER_FLAG ? TRUE : FALSE );/* 如果未连接CH374的中断引脚则查询中断标志寄存器 */   

  #endif  

}

/**

  *@Name:Query374DeviceIn

*@Describe:检测是否有USB设备插入

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

u8 Query374DeviceIn(void)

{

if(CH374_READ_REGISTER( REG_INTER_FLAG ) & BIT_IF_DEV_ATTACH )  

return 1;

else 

return 0;

}

/**

  *@Name:HostDetectInterrupt

*@Describe:处理USB设备插拔事件中断

*@Output:Not

*@Input:Not

*@Date:2017-02-19

**/

void HostDetectInterrupt( void )      

{

u8s,u;

   

s = CH374_READ_REGISTER( REG_INTER_FLAG );// 获取中断状态

if( s & BIT_IF_DEV_DETECT )// USB设备插拔事件

  {

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT );// 清中断标志

if ( s & BIT_IF_DEV_ATTACH )           // USB设备连接事件

    {

u = CH374_READ_REGISTER( REG_USB_SETUP );

if ( s & BIT_IF_USB_DX_IN )// 速度匹配,不需要切换速度

      {

if ( u & BIT_SETP_USB_SPEED ) FlagDeviceStatus = USB_INT_CONNECT_LS;// 低速USB设备

else FlagDeviceStatus = USB_INT_CONNECT;// 全速USB设备

}

else// 速度失配,需要切换速度

      {

if ( u & BIT_SETP_USB_SPEED ) FlagDeviceStatus = USB_INT_CONNECT;// 全速USB设备

else FlagDeviceStatus = USB_INT_CONNECT_LS;// 低速USB设备

}

}

else FlagDeviceStatus = USB_INT_DISCONNECT;// USB设备断开事件

}

else // 意外的中断

  { 

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER | BIT_IF_USB_SUSPEND | BIT_IF_WAKE_UP );// 清中断标志

}

}

/**

  *@Name:Wait374Interrupt

*@Describe:等待CH374中断(INT#低电平),超时则返回ERR_USB_UNKNOWN 

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

u8 Wait374Interrupt(void)   

{   

u16 i; 

  

for(i = 0; i < 10000; i++ ) // 计数防止超时 

{    

if(Query374Interrupt()) 

return 0;   

}   

return ERR_USB_UNKNOWN; // 不应该发生的情况   

/**

  *@Name:HostTransact374

*@Describe: CH374传输事务

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

/* CH374传输事务,输入目的端点地址/PID令牌/同步标志,返回同CH375,NAK不重试,超时/出错重试 */

u8HostTransact374(u8 endp_addr,u8 pid,u8 tog )

{  // 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化

u8retry;

u8s,r,u;

for(retry = 0;retry < 3;retry++)

{

CH374_WRITE_REGISTER( REG_USB_H_PID,M_MK_HOST_PID_ENDP(pid,endp_addr) ); // 指定令牌PID和目的端点号

//Write374Byte( REG_USB_H_CTRL, BIT_HOST_START | ( tog ? ( BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : 0x00 ) );  // 设置同步标志并启动传输

CH374_WRITE_REGISTER( REG_USB_H_CTRL, ( tog ? ( BIT_HOST_START | BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) : BIT_HOST_START ) );// 设置同步标志并启动传输

/*

if(tog)

 CH374_WRITE_REGISTER( REG_USB_H_CTRL, ( BIT_HOST_START | BIT_HOST_TRAN_TOG | BIT_HOST_RECV_TOG ) );// 设置同步标志并启动传输

else

 CH374_WRITE_REGISTER( REG_USB_H_CTRL, BIT_HOST_START );  // 设置同步标志并启动传输

*/

s = Wait374Interrupt();

if(s == ERR_USB_UNKNOWN ) return( s ); // 中断超时,可能是硬件异常

s = CH374_READ_REGISTER(REG_INTER_FLAG);// 获取中断状态

if( s & BIT_IF_DEV_DETECT ) // USB设备插拔事件

{                  

//delay_us( 250 ); // 等待传输完成

OSTimeDly(1);//1*20ms

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_DEV_DETECT | BIT_IF_TRANSFER );// 清中断标志

if ( s & BIT_IF_DEV_ATTACH )// USB设备连接事件

{             

//delay_us( 200 );  // 等待传输完成

OSTimeDly(1);//1*20ms

u = CH374_READ_REGISTER( REG_USB_SETUP );

if( s & BIT_IF_USB_DX_IN )// 速度匹配,不需要切换速度

{           

if( u & BIT_SETP_USB_SPEED ) 

return( USB_INT_CONNECT_LS );// 低速USB设备

return( USB_INT_CONNECT );// 全速USB设备

}

else // 速度失配,需要切换速度

{                                  

if( u & BIT_SETP_USB_SPEED ) 

return( USB_INT_CONNECT );// 全速USB设备

return( USB_INT_CONNECT_LS );// 低速USB设备

}

}

else return( USB_INT_DISCONNECT );// USB设备断开事件

}

else if( s & BIT_IF_TRANSFER ) // 传输完成

{              

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_TRANSFER );  // 清中断标志

s = CH374_READ_REGISTER(REG_USB_STATUS);// USB状态

r = s & BIT_STAT_DEV_RESP;// USB设备应答状态

switch( pid ) 

{

case DEF_USB_PID_SETUP:

case DEF_USB_PID_OUT:

if ( r == DEF_USB_PID_ACK )

return( USB_INT_SUCCESS );

else if ((r == DEF_USB_PID_STALL) || (r == DEF_USB_PID_NAK) ) 

return( r | 0x20 );

else if ( ! M_IS_HOST_TIMEOUT( s ) ) 

return( r | 0x20 );  // 不是超时/出错,意外应答

break;

case DEF_USB_PID_IN:

if( M_IS_HOST_IN_DATA( s ) ) // DEF_USB_PID_DATA0 or DEF_USB_PID_DATA1

{  

if( s & BIT_STAT_TOG_MATCH ) 

return( USB_INT_SUCCESS );  // 不同步则需丢弃后重试

}

else if ((r == DEF_USB_PID_STALL) || (r == DEF_USB_PID_NAK) ) 

return( r | 0x20 );

else if ( ! M_IS_HOST_TIMEOUT( s ) ) 

return( r | 0x20 );  // 不是超时/出错,意外应答

break;

default:

return( ERR_USB_UNKNOWN );       // 不可能的情况

}

}

else // 其它中断,不应该发生的情况

{                                       

//delay_us(200);// 等待传输完成

OSTimeDly(1); //延时1*20ms = 20ms    

CH374_WRITE_REGISTER( REG_INTER_FLAG, BIT_IF_USB_PAUSE | BIT_IF_INTER_FLAG ); /* 清中断标志 */

if(retry) return( ERR_USB_UNKNOWN );  // 不是第一次检测到则返回错误  FA

}

}

return( 0x20 );// 应答超时

}

/**

  *@Name:WaitHostTransact374

*@Describe: CH374传输事务

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

/*  CH374传输事务,输入目的端点地址/PID令牌/同步标志/以mS为单位的NAK重试总时间(0xFFFF无限重试),返回同CH375,NAK重试,超时出错重试 */

u8 WaitHostTransact374(u8 endp_addr,u8 pid,u8 tog,u16 timeout )

{

u8 i, s;

while(1) 

{

for(i = 0; i < 1; i++ ) 

{

s = HostTransact374( endp_addr, pid, tog );//01 09 00

/*

if(s == 0x14)

 printf("获取按键成功:%02X\r\n",s);

else

 printf("获取按键失败:%02X\r\n",s);

*/

if( (s != ( DEF_USB_PID_NAK | 0x20 )) || (timeout == 0) ) // 0X0A | 0X20

return( s );//返回 0X2A  和  0X20

delay_us( 20 );

//OSTimeDly(1); //延时14*20ms = 280ms    

}

if(timeout < 0xFFFF) timeout --;

}

}

/**

  *@Name:HostCtrlTransfer374

*@Describe: 执行控制传输

*@Output:Not

*@Input:

*@Date:2017-02-20

**/

/* 执行控制传输,ReqBuf指向8字节请求码,DatBuf为收发缓冲区 */

u8 HostCtrlTransfer374(u8 *ReqBuf,u8 *DatBuf,u8 *RetLen )  

{// 如果需要接收和发送数据,那么DatBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度保存在ReqLen指向的字节变量中

u8 s,len,count,total;

u8 tog;

CH374_WRITE_BLOCK(RAM_HOST_TRAN,8,ReqBuf );

CH374_WRITE_REGISTER( REG_USB_LENGTH, 8 );

delay_us(100);

s = WaitHostTransact374(0,DEF_USB_PID_SETUP,0,200 ); // SETUP阶段,200mS超时

if( s == USB_INT_SUCCESS )// SETUP成功

  {

tog = 1;// 默认DATA1,默认无数据故状态阶段为IN

if((*(ReqBuf+3))==0x22)

    {

total = *( ReqBuf+6) - 0x40;

 }

else 

{

total = *( ReqBuf + 6 );

}

if(total && DatBuf)// 需要收数据

    {

len = total;

if( *ReqBuf & 0x80 )// 收

      {

while(len) 

        {

delay_us(100);

s = WaitHostTransact374( 0, DEF_USB_PID_IN, tog, 200 );  // IN数据

if ( s != USB_INT_SUCCESS ) break;

count = CH374_READ_REGISTER( REG_USB_LENGTH );

CH374_READ_BLOCK( RAM_HOST_RECV, count, DatBuf );

DatBuf += count;

if( count <= len ) 

len -= count;

else 

len = 0;

if( count & (UsbDevEndpSize - 1) ) 

break;  // 短包

if(tog)

tog = 0;

else

tog = 1;

}

tog = 0;// 状态阶段为OUT

}

else 

{// 发

while( len ) 

        {

delay_us(100);

count = len >= UsbDevEndpSize ? UsbDevEndpSize : len;

/*

if(len >= UsbDevEndpSize)

count = UsbDevEndpSize;

else

 count = len;

*/

CH374_WRITE_BLOCK( RAM_HOST_TRAN, count, DatBuf );

CH374_WRITE_REGISTER( REG_USB_LENGTH, count );

s = WaitHostTransact374(0,DEF_USB_PID_OUT,tog,200);  // OUT数据

if ( s != USB_INT_SUCCESS ) break;

DatBuf += count;

len -= count;

if(tog)

tog = 0;

else

tog = 1;

}

tog = 1;                // 状态阶段为IN

}

total -= len;                  // 减去剩余长度得实际传输长度

}

if( s == USB_INT_SUCCESS )        // 数据阶段成功

    {

CH374_WRITE_REGISTER( REG_USB_LENGTH,0);

delay_us( 100 );

if(tog)

 s = WaitHostTransact374(0,DEF_USB_PID_IN,1,200);  // STATUS阶段

else

s = WaitHostTransact374(0,DEF_USB_PID_OUT,1,200);  // STATUS阶段

if ( tog && s == USB_INT_SUCCESS )    // 检查IN状态返回数据长度

      {

if( CH374_READ_REGISTER(REG_USB_LENGTH) ) 

s = USB_INT_BUF_OVER;  // 状态阶段错误

}

}

}

if( RetLen ) 

*RetLen = total;// 实际成功收发的总长度

return s;

}

/**

  *@Name:SetUsbAddress

*@Describe:设置USB设备地址 

*@Output:Not

*@Input:addr 地址

*@Date:2017-02-20

**/

u8 SetUsbAddress(u8 addr )  

{

u8 s;

u8 BufSetAddr[sizeof(SetupSetUsbAddr)] ;

memcpy ( BufSetAddr,SetupSetUsbAddr, sizeof( SetupSetUsbAddr ) );

((PUSB_SETUP_REQ)BufSetAddr) -> wValueL = addr;// USB设备地址

s = HostCtrlTransfer374( BufSetAddr, NULL, NULL );// 执行控制传输

if (s == USB_INT_SUCCESS) 

{

SetHostUsbAddr(addr);// 设置USB主机当前操作的USB设备地址

}

delay_us(3000);// 等待USB设备完成操作

return(s);

}

/**

  *@Name:GetDeviceDescr

*@Describe:设置USB设备配置 

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-20

**/


u8 SetUsbConfig(u8 cfg )  

{

u8 BufSetCfg[ sizeof( SetupSetUsbConfig ) ] ;

memcpy ( BufSetCfg, SetupSetUsbConfig, sizeof( SetupSetUsbConfig ) );

((PUSB_SETUP_REQ)BufSetCfg )-> wValueL = cfg;// USB设备配置

return(HostCtrlTransfer374(BufSetCfg,NULL, NULL ));  // 执行控制传输

}


/**

  *@Name:GetDeviceDescr

*@Describe:获取设备描述符

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-20

**/

u8 GetDeviceDescr(u8 *buf )  

{

u8 s,len;

s = HostCtrlTransfer374((u8 *)SetupGetDevDescr,buf,&len );// 执行控制传输

if ( s == USB_INT_SUCCESS ) 

{

UsbDevEndpSize = ((PUSB_DEV_DESCR)buf) -> bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndpSize再继续

if( len < ((PUSB_SETUP_REQ)SetupGetDevDescr) -> wLengthL ) s = USB_INT_BUF_OVER;  // 描述符长度错误

}

return(s);

}

/**

  *@Name:GetConfigDescr

*@Describe:获取配置描述符 

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-20

**/

u8 GetConfigDescr(u8 *buf)  

{

u8 s,len,i,c,j;

u8 BufLogDescr[sizeof(SetupGetCfgDescr)] ;


s = HostCtrlTransfer374((u8*)SetupGetCfgDescr,buf,&len );    // 执行控制传输

if(s == USB_INT_SUCCESS) 

  {

// for(i=0;i!=len;i++)

//  printf("%02x ",(unsigned short)buf[i]);

// printf("\n");

if( len < ((PUSB_SETUP_REQ)SetupGetCfgDescr) -> wLengthL ) 

{

s = USB_INT_BUF_OVER;  // 返回长度错误

}

else 

    {

memcpy(BufLogDescr,SetupGetCfgDescr,sizeof( SetupGetCfgDescr));

((PUSB_SETUP_REQ)BufLogDescr ) -> wLengthL = ((PUSB_CFG_DESCR)buf) -> wTotalLengthL;  // 完整配置描述符的总长度

s = HostCtrlTransfer374(BufLogDescr,buf,&len);   // 执行控制传输

if(s == USB_INT_SUCCESS ) 

      {

        //简单分析配置描述符,获取端点地址,这里只处理一个端点的情况

printf("获取配置描述符:\r\n");

for ( i = 0; i < ( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL; i ++ ) 

 printf("%02X ", (UINT16)( buf[i] ) );  //配置描述符

printf( "\r\n" );

for(i=0;i<((PUSB_CFG_DESCR)buf) -> wTotalLengthL;i++) 

{

if((buf[i]==0x09) && (buf[i+1]==0x21) && (buf[i+6]==0x22))

{

hid_des_leng=buf[i+7];    //获取报告描述符的长度        

            break;

}

}

printf("hid_des_leng=%02x\r\n",hid_des_leng);

endp_out_addr =0;

endp_in_addr = 0;

c = 0;

for(i=0;i<( (PUSB_CFG_DESCR)buf ) -> wTotalLengthL;i++) 

{

if(((buf[i]==0x09) && (buf[i+1]==0x04)&&(buf[i+5]==0x03) && (buf[i+7]==0x01)) || (buf[i+7]==0x02))  //接口描述符为HID的鼠标、键盘   

for(j=0;j<(((PUSB_CFG_DESCR)buf ) -> wTotalLengthL-i);j++) 

{

 if((buf[i+j]==0x07) && (buf[i+j+1]==0x05) && (buf[i+j+3]==0x03))   

c = buf[i+j+2];//判断是否为中断端点

if(c & 0x80)    

endp_in_addr = (c&0x0f);// IN端点的地址                                

else             

endp_out_addr = (c&0x0f);

if((endp_out_addr!=0)||(endp_in_addr!=0))   

break;                                       

}

}

if((endp_out_addr!=0)||(endp_in_addr!=0))   

break;           

}

printf("endp_in_addr=%02x\r\n",(unsigned short)endp_in_addr);

printf("endp_out_addr=%02x\r\n",(unsigned short)endp_out_addr);

}

}

  }

return s ;

}


/**

  *@Name:SetIdle

*@Describe:设置IDLE

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

u8 SetIdle(void)//设置IDLE

{

u8 s;

s = HostCtrlTransfer374(SetupSetidle,NULL,NULL);

return s;

}



/**

  *@Name:GetHidDes

*@Describe:获取报表描述符

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

u8 GetHidDes(u8 *p)//获取报表描述符

{

u8 s;

u8 buffer[8];

//leng=SetupGetHidDes[0x06]-0x40;//报表描述符的长度在发送数据长度的基础上减去0X40

//0x81,0x06,0x00,0x22,0x00,0x00,0x81,0x00

memcpy(buffer,SetupGetHidDes,8);

buffer[0x06] = hid_des_leng+0x40;

s=HostCtrlTransfer374(buffer,p,&buffer[0x06]);

return s;

}

/**

  *@Name:SetReport

*@Describe:

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

u8 SetReport(u8 *p)

{

u8 s,l=1;

s = HostCtrlTransfer374(SetupSetReport,p,&l);//实际的数据可以写别的数据,这个你可以用计算机抓下数据在发下去

return s;

}

 

/**

  *@Name:SetReport

*@Describe:通过中断端点获取鼠标、键盘上传的数据 

*@Output:Not

*@Input:返回是否获取设备描述符成功

*@Date:2017-02-21

**/

u8 Interrupt_Data_Trans(u8 *p)

{

u8 s,count;

s = WaitHostTransact374(endp_in_addr,DEF_USB_PID_IN,ReadDataFlag,1000 );// IN数据 01 09 00 1000


if(s != USB_INT_SUCCESS )

  {

    //delay_us(5000); 

OSTimeDly(3); //延时14*20ms = 280ms    

    return s;

  }

else

  {

count = CH374_READ_REGISTER(REG_USB_LENGTH);

CH374_READ_BLOCK(RAM_HOST_RECV,count,p);

if(ReadDataFlag)

ReadDataFlag = 0;

else

ReadDataFlag = 1;

}

return s;

}

/**

  *@Name:USB_Equipment

*@Describe:USB设备初始化,枚举

*@Output:Not

*@Input:

*@Date:2017-02-19

**/

int USB_Equipment(void)

{

u8 i=0,s=0;

u8 close_bit_flag=0;

u8 DeviceDescribe_buf[80];//由于报告描述符大小不定,缓冲区的大小最好定义大些

Init374Host();// 初始化USB主机

while(1)

{

SetHostLeisure();//设定USB主机空闲

while(1)

{

if (Query374Interrupt()) HostDetectInterrupt();  // 如果有USB主机中断则处理

if (Query374DeviceIn()) break;                   // 有USB设备

 OSTimeDly(5); //100ms

}

OSTimeDly(14); //延时14*20ms = 280ms      // 由于USB设备刚插入尚未稳定,故等待USB设备数百毫秒,消除插拔抖动

if(Query374Interrupt()) HostDetectInterrupt(); // 如果有USB主机中断则处理

    

HostSetReset();// USB总线复位

for(i=0;i<100;i++ )// 等待USB设备复位后重新连接

    {

if(Query374DeviceIn())  break; // 有USB设备

delay_us(1000);

}

if(Query374Interrupt()) HostDetectInterrupt( ); // 如果有USB主机中断则处理

if(Query374DeviceIn())// 有USB设备

    {  

if(Query374DevFullSpeed())

      {

HostSetFullSpeed();// 检测到全速USB设备

// printf("全速USB设备插入:\r\n");

printf("Full-Speed Device\r\n");

}

else 

      {

HostSetLowSpeed();// 检测到低速USB设备

//printf("低速USB设备插入:\r\n");

printf("Low-Speed Device\r\n");

}

}

else 

    {

continue;// 设备已经断开,继续等待

}

OSTimeDly(3); //延时3*20ms = 60ms 

close_bit_flag=0;//设备是否拔出

//1、获取设备描述符

s = GetDeviceDescr(DeviceDescribe_buf); // 获取设备描述符

if(s != USB_INT_SUCCESS )

    {

printf("获取设备描述符失败\r\n");

goto WaitDeviceOut;// 终止操作,等待USB设备拔出

}

printf("设备描述符:");

for(i=0;i <((PUSB_SETUP_REQ)SetupGetDevDescr ) -> wLengthL;i++ ) 

 printf("%02X ",DeviceDescribe_buf[i]);//输出描述符

printf( "\r\n" );

//2、设置USB设备地址    

s = SetUsbAddress(0x02);// 设置USB设备地址

if(s != USB_INT_SUCCESS )

{

printf("设置USB设备地址错误\r\n");

goto WaitDeviceOut;// 终止操作,等待USB设备拔出

}

printf("设置USB设备地址0X02成功\r\n");


//3、获取配置描述符

s = GetConfigDescr(DeviceDescribe_buf); // 获取配置描述符

//printf("config_status=%02x\r\n",(unsigned short)s);

if ( s != USB_INT_SUCCESS )

{

printf("获取配置描述符错误\r\n");

goto WaitDeviceOut;// 终止操作,等待USB设备拔出

}

//4、设置USB设备配置

// 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等 

s = SetUsbConfig( ( (PUSB_CFG_DESCR)DeviceDescribe_buf ) -> bConfigurationValue ); // 设置USB设备配置

if ( s != USB_INT_SUCCESS ) 

{

printf("获取配置描述符错误\r\n");

    goto WaitDeviceOut;// 终止操作,等待USB设备拔出

}

printf("设置USB设备配置成功\r\n");


//-------------------------以下进行HID类的简单操作-----------------------------------------------------------

//5、设置IDLE

s = SetIdle();//设置IDLE,这个步骤是按照HID类的协议来做的

if(s != USB_INT_SUCCESS)

    {

      if((s&0x0f) == USB_INT_RET_STALL)  goto next_operate1; //返回STALL可能本身不支持

}

printf("设置IDLE成功\r\n");

next_operate1:

//6、获取报表描述符

s=GetHidDes(DeviceDescribe_buf);// 获取报表描述符

if(s==USB_INT_SUCCESS)

    {

printf("HID_Desc: ");

for(i=0;i!=hid_des_leng;i++)  

 printf("%02x ",DeviceDescribe_buf[i]);

printf("\r\n");

}

else

    {

printf("获取报表描述符描述符错误\r\n");

goto WaitDeviceOut;//出错退出

}

DeviceDescribe_buf[0]=0x01;

//设置报表

s = SetReport(DeviceDescribe_buf);//设置报表

if(s==USB_INT_SUCCESS)   

{

printf("Set_Report success\r\n");

}

else //设置报告出错

    { 

     if((s&0x0f) == USB_INT_RET_STALL)  goto next_operate2;      //返回STALL可能本身不支持  

}

next_operate2:

// 下面开始读取数据 ( 实际在读取数据的时候,要先发送中断端点的令牌来读取数据,接着才能获取到数据 )

ReadDataFlag = 0;                                  //开始取DATA0

while(1)

    {

s = Interrupt_Data_Trans(DeviceDescribe_buf);


printf("s = %X\r\n",s);

if(s==USB_INT_SUCCESS)

      {

for(i=0;i!=8;i++)

 printf("%02x ",DeviceDescribe_buf[i]);

printf("\r\n");

}

else if(s == USB_INT_DISCONNECT)//  这个是为了知道设备拔出产生的中断状态

      {

close_bit_flag=1;

break;

}

OSTimeDly(5); //100ms

}

//-------------------------------------------------------------------------------------------------------

WaitDeviceOut: // 等待USB设备拔出

 printf( "Wait Device Out\r\n" );

 if(close_bit_flag==0)//设备拔出

{

while(1)

{

if(Query374Interrupt()) HostDetectInterrupt( );// 如果有USB主机中断则处理

if(Query374DeviceIn() == FALSE ) break;   // 没有USB设备

OSTimeDly(5); //100ms 

}

 }

OSTimeDly(5); //延时5*20ms = 100ms  

}

}

//--------------------------------------------------------------------------------------

串口输出信息:

Low-Speed Device

设备描述符:12 01 10 01 00 00 00 08 D5 05 89 06 03 01 00 01 00 01 

设置USB设备地址0X02成功

获取配置描述符:

09 02 3B 00 02 01 00 A0 32 

09 04 00 00 01 03 01 01 00 

09 21 10 01 00 01 22 41 00 

07 05 81 03 08 00 0A 

09 04 01 00 01 03 00 00 00 

09 21 10 01 00 01 22 32 00 

07 05 82 03 05 00 0A 

hid_des_leng=41

endp_in_addr=01

endp_out_addr=00

设置USB设备配置成功

设置IDLE成功

HID_Desc: 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 95 08 75 01 81 02 95 08 75 01 81 01 05 08 19 01 29 03 95 03 75 01 91 02 95 01 75 05 91 01 05 07 19 00 2a ff 00 15 00 26 ff 00 95 06 75 08 81 00 c0 

Set_Report success

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 2A

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20

s = 20


Wait Device Out


急,在线等。有哪位朋友用CH374枚举过USB键盘的吗。

如果朋友有代码的话可以发一份给我吗。个人信息保护,已隐藏  谢谢


这是双接口HID,setidle必须要分别对两个端点都发一次。


抓的包:

Bus Hound 6.01 capture on Windows Vista Service Pack 1 (x64). Complements of www.perisoft.net


双飞燕数字小键盘


  Device - Device ID (followed by the endpoint for USB devices)

            (15) USB 输入设备

            (17) HID Keyboard Device

  Phase  - Phase Type

            CTL   USB control transfer       

            IN    Data in transfer           

            OUT   Data out transfer          

  Data   - Hex dump of the data transferred

  Descr  - Description of the phase

  Cmd... - Position in the captured data



Device  Phase  Data                                       Description                       Cmd.Phase.Ofs(rep)

------  -----  ------------------------------------------------------------------------------------------------------  --------------------------------  ------------------

  15.0  CTL    80 06 00 01  00 00 12 00            GET DESCRIPTOR                           1.1.0        

  15.0  IN     12 01 10 01  00 00 00 08  d5 05 89 06  03 01 00 01  00 01           ..................               1.2.0        

  15.0  CTL    80 06 00 02  00 00 09 00           GET DESCRIPTOR                           2.1.0        

  15.0  IN     09 02 22 00  01 01 00 a0  32                                                             ..".....2                      2.2.0       

  15.0  CTL    80 06 00 02  00 00 22 00               GET DESCRIPTOR                           3.1.0        

  15.0  IN     09 02 22 00  01 01 00 a0  32 09 04 00  00 01 03 01  01 00 09 21  10 01 00 01  22 41 00 07  05 81 03 08  ..".....2..........!...."A......         3.2.0        

               00 0a                                                                                                   ..                      3.2.32       

  15.0  CTL    00 09 01 00  00 00 00 00                 SET CONFIG                               4.1.0        

  15.0  CTL    21 0a 00 00  00 00 00 00                 SET IDLE                                 5.1.0        

 

  15.0  CTL    81 06 00 22  00 00 81 00                  GET DESCRIPTOR                           6.1.0        

  15.0  IN     05 01 09 06  a1 01 05 07  19 e0 29 e7  15 00 25 01  95 08 75 01  81 02 95 08  75 01 81 01  05 08 19 01  ..........)...%...u.....u.......         6.2.0        

               29 03 95 03  75 01 91 02  95 01 75 05  91 01 05 07  19 00 2a ff  00 15 00 26  ff 00 95 06  75 08 81 00  )...u.....u.......*....&....u...         6.2.32       

               c0                                                                                                      .                                        6.2.64       

  15.0  CTL    21 09 00 02  00 00 01 00              SET REPORT                               7.1.0        

  15.0  OUT    01                                                                 .                                        7.2.0        

 

  15.1  IN     00 00 59 00  00 00 00 00                                                                                ..Y.....                                 8.1.0        

  17    IN     01 00 4f 00  00 00 00 00  00 00 00 00                                                                   ..O.........                             9.1.0        

  15.1  IN     00 00 00 00  00 00 00 00                                                                                ........                                10.1.0        

  17    IN     01 00 4f 00  01 00 00 00  00 00 00 00                                                                   ..O.........                            11.1.0        

  15.1  IN     00 00 00 00  00 00 00 00                                                                                ........                                12.1.0        

  15.1  IN     00 00 5a 00  00 00 00 00                                                                                ..Z.....                                13.1.0        

  17    IN     01 00 50 00  00 00 00 00  00 00 00 00                                                                   ..P.........                            14.1.0        

  15.1  IN     00 00 00 00  00 00 00 00                                                                                ........                                15.1.0        

  17    IN     01 00 50 00  01 00 00 00  00 00 00 00                                                                   ..P.........                            16.1.0        



RTX截图未命名.png

这个数组怎么能定义成常量数组呢?那你岂不是把0配置进去了。


间接性改变,

u8 BufSetCfg[ sizeof( SetupSetUsbConfig ) ] ;

memcpy ( BufSetCfg, SetupSetUsbConfig, sizeof( SetupSetUsbConfig ) );

((PUSB_SETUP_REQ)BufSetCfg )-> wValueL = cfg;

      return(HostCtrlTransfer374(BufSetCfg,NULL, NULL ));



只有登录才能回复,可以选择微信账号登录