CH552/examples/USB/Device/CompatibilityHID.C
2018-10-17 16:44:45 +08:00

451 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************** (C) COPYRIGHT *******************************
* File Name :CompatibilityHID.C
* Author : WCH
* Version : V1.0
* Date : 2017/01/20
* Description : CH554模拟HID兼容设备支持中断上下传支持设置全速低速
*******************************************************************************/
#include "./Public/CH554.H"
#include "./Public/Debug.H"
#include <stdio.h>
#include <string.h>
#define Fullspeed 1
#ifdef Fullspeed
#define THIS_ENDP0_SIZE 64
#else
#define THIS_ENDP0_SIZE DEFAULT_ENDP0_SIZE
#endif
UINT8X Ep0Buffer[8<(THIS_ENDP0_SIZE+2)?8:(THIS_ENDP0_SIZE+2)] _at_ 0x0000; //端点0 OUT&IN缓冲区必须是偶地址
UINT8X Ep2Buffer[128<(2*MAX_PACKET_SIZE+4)?128:(2*MAX_PACKET_SIZE+4)] _at_ 0x0044;//端点2 IN&OUT缓冲区,必须是偶地址
UINT8 SetupReq,SetupLen,Ready,Count,FLAG,UsbConfig;
PUINT8 pDescr; //USB配置标志
USB_SETUP_REQ SetupReqBuf; //暂存Setup包
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
sbit Ep2InKey = P1^5; //K1按键
#pragma NOAREGS
/*设备描述符*/
UINT8C DevDesc[18] = {0x12,0x01,0x10,0x01,0x00,0x00,0x00,THIS_ENDP0_SIZE,
0x31,0x51,0x07,0x20,0x00,0x00,0x00,0x00,
0x00,0x01
};
UINT8C CfgDesc[41] =
{
0x09,0x02,0x29,0x00,0x01,0x01,0x04,0xA0,0x23, //配置描述符
0x09,0x04,0x00,0x00,0x02,0x03,0x00,0x00,0x05, //接口描述符
0x09,0x21,0x00,0x01,0x00,0x01,0x22,0x22,0x00, //HID类描述符
0x07,0x05,0x82,0x03,THIS_ENDP0_SIZE,0x00,0x18, //端点描述符
0x07,0x05,0x02,0x03,THIS_ENDP0_SIZE,0x00,0x18, //端点描述符
};
/*字符串描述符 略*/
/*HID类报表描述符*/
UINT8C HIDRepDesc[ ] =
{
0x06, 0x00,0xff,
0x09, 0x01,
0xa1, 0x01, //集合开始
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, THIS_ENDP0_SIZE, //Report Counet
0x81, 0x06, //Input
0x09, 0x02, //Usage Page 用法
0x15, 0x00, //Logical Minimun
0x26, 0x00,0xff, //Logical Maximun
0x75, 0x08, //Report Size
0x95, THIS_ENDP0_SIZE, //Report Counet
0x91, 0x06, //Output
0xC0
};
// unsigned char code LangDes[]={0x04,0x03,0x09,0x04}; //语言描述符
// unsigned char code SerDes[]={
// 0x28,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x49,0x00,0x43,0x00,0x42,
// 0x00,0x43,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00
// }; //字符串描述符
UINT8X UserEp2Buf[64]; //用户数据定义
/*******************************************************************************
* Function Name : USBDeviceInit()
* Description : USB设备模式配置,设备模式启动,收发端点配置,中断开启
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USBDeviceInit()
{
IE_USB = 0;
USB_CTRL = 0x00; // 先设定USB设备模式
#ifndef Fullspeed
UDEV_CTRL |= bUD_LOW_SPEED; //选择低速1.5M模式
#else
UDEV_CTRL &= ~bUD_LOW_SPEED; //选择全速12M模式默认方式
#endif
UEP2_DMA = Ep2Buffer; //端点2数据传输地址
UEP2_3_MOD |= bUEP2_TX_EN; //端点2发送使能
UEP2_3_MOD |= bUEP2_RX_EN; //端点2接收使能
UEP2_3_MOD &= ~bUEP2_BUF_MOD; //端点2收发各64字节缓冲区
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; //端点2自动翻转同步标志位IN事务返回NAKOUT返回ACK
UEP0_DMA = Ep0Buffer; //端点0数据传输地址
UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN); //端点0单64字节收发缓冲区
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //OUT事务返回ACKIN事务返回NAK
USB_DEV_AD = 0x00;
UDEV_CTRL = bUD_PD_DIS; // 禁止DP/DM下拉电阻
USB_CTRL = bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;
}
/*******************************************************************************
* Function Name : Enp2BlukIn()
* Description : USB设备模式端点2的批量上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Enp2BlukIn( )
{
memcpy( Ep2Buffer+MAX_PACKET_SIZE, UserEp2Buf, sizeof(UserEp2Buf)); //加载上传数据
UEP2_T_LEN = THIS_ENDP0_SIZE; //上传最大包长度
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; //有数据时上传数据并应答ACK
while(UEP2_CTRL&UEP_T_RES_ACK); //等待传输完成
}
/*******************************************************************************
* Function Name : DeviceInterrupt()
* Description : CH559USB中断处理函数
*******************************************************************************/
void DeviceInterrupt( void ) interrupt INT_NO_USB using 1 //USB中断服务程序,使用寄存器组1
{
UINT8 len,i;
if(UIF_TRANSFER) //USB传输完成标志
{
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
{
case UIS_TOKEN_IN | 2: //endpoint 2# 端点批量上传
UEP2_T_LEN = 0; //预使用发送长度一定要清空
// UEP1_CTRL ^= bUEP_T_TOG; //如果不设置自动翻转则需要手动翻转
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK; //默认应答NAK
break;
case UIS_TOKEN_OUT | 2: //endpoint 2# 端点批量下传
if ( U_TOG_OK ) // 不同步的数据包将丢弃
{
len = USB_RX_LEN; //接收数据长度数据从Ep2Buffer首地址开始存放
for ( i = 0; i < len; i ++ )
{
Ep2Buffer[MAX_PACKET_SIZE+i] = Ep2Buffer[i] ^ 0xFF; // OUT数据取反到IN由计算机验证
}
UEP2_T_LEN = len;
UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK; // 允许上传
}
break;
case UIS_TOKEN_SETUP | 0: //SETUP事务
len = USB_RX_LEN;
if(len == (sizeof(USB_SETUP_REQ)))
{
SetupLen = UsbSetupBuf->wLengthL;
if(UsbSetupBuf->wLengthH || SetupLen > 0x7F )
{
SetupLen = 0x7F; // 限制总长度
}
len = 0; // 默认为成功并且上传0长度
SetupReq = UsbSetupBuf->bRequest;
if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/*HID类命令*/
{
switch( SetupReq )
{
case 0x01: //GetReport
break;
case 0x02: //GetIdle
break;
case 0x03: //GetProtocol
break;
case 0x09: //SetReport
break;
case 0x0A: //SetIdle
break;
case 0x0B: //SetProtocol
break;
default:
len = 0xFF; /*命令不支持*/
break;
}
}
else //标准请求
{
switch(SetupReq) //请求码
{
case USB_GET_DESCRIPTOR:
switch(UsbSetupBuf->wValueH)
{
case 1: //设备描述符
pDescr = DevDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(DevDesc);
break;
case 2: //配置描述符
pDescr = CfgDesc; //把设备描述符送到要发送的缓冲区
len = sizeof(CfgDesc);
break;
case 0x22: //报表描述符
pDescr = HIDRepDesc; //数据准备上传
len = sizeof(HIDRepDesc);
Ready = 1; //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
break;
default:
len = 0xff; //不支持的命令或者出错
break;
}
if ( SetupLen > len )
{
SetupLen = len; //限制总长度
}
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;//本次传输长度
memcpy(Ep0Buffer,pDescr,len); //加载上传数据
SetupLen -= len;
pDescr += len;
break;
case USB_SET_ADDRESS:
SetupLen = UsbSetupBuf->wValueL; //暂存USB设备地址
break;
case USB_GET_CONFIGURATION:
Ep0Buffer[0] = UsbConfig;
if ( SetupLen >= 1 )
{
len = 1;
}
break;
case USB_SET_CONFIGURATION:
UsbConfig = UsbSetupBuf->wValueL;
break;
case 0x0A:
break;
case USB_CLEAR_FEATURE: //Clear Feature
if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
{
switch( UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
break;
default:
len = 0xFF; // 不支持的端点
break;
}
}
else
{
len = 0xFF; // 不是端点不支持
}
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 ) /* 设置设备 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
{
if( CfgDesc[ 7 ] & 0x20 )
{
/* 设置唤醒使能标志 */
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 ) /* 设置端点 */
{
if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
{
switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
{
case 0x82:
UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
break;
case 0x02:
UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
break;
case 0x81:
UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
break;
default:
len = 0xFF; /* 操作失败 */
break;
}
}
else
{
len = 0xFF; /* 操作失败 */
}
}
else
{
len = 0xFF; /* 操作失败 */
}
break;
case USB_GET_STATUS:
Ep0Buffer[0] = 0x00;
Ep0Buffer[1] = 0x00;
if ( SetupLen >= 2 )
{
len = 2;
}
else
{
len = SetupLen;
}
break;
default:
len = 0xff; //操作失败
break;
}
}
}
else
{
len = 0xff; //包长度错误
}
if(len == 0xff)
{
SetupReq = 0xFF;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
}
else if(len <= THIS_ENDP0_SIZE) //上传数据或者状态阶段返回0长度包
{
UEP0_T_LEN = len;
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1返回应答ACK
}
else
{
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
}
break;
case UIS_TOKEN_IN | 0: //endpoint0 IN
switch(SetupReq)
{
case USB_GET_DESCRIPTOR:
len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
memcpy( Ep0Buffer, pDescr, len ); //加载上传数据
SetupLen -= len;
pDescr += len;
UEP0_T_LEN = len;
UEP0_CTRL ^= bUEP_T_TOG; //同步标志位翻转
break;
case USB_SET_ADDRESS:
USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
UEP0_T_LEN = 0; //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT | 0: // endpoint0 OUT
len = USB_RX_LEN;
if(SetupReq == 0x09)
{
if(Ep0Buffer[0])
{
printf("Light on Num Lock LED!\n");
}
else if(Ep0Buffer[0] == 0)
{
printf("Light off Num Lock LED!\n");
}
}
UEP0_T_LEN = 0; //虽然尚未到状态阶段但是提前预置上传0长度数据包以防主机提前进入状态阶段
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA0,返回应答ACK
break;
default:
break;
}
UIF_TRANSFER = 0; //写0清空中断
}
if(UIF_BUS_RST) //设备模式USB总线复位中断
{
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
UEP1_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP2_CTRL = bUEP_AUTO_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
USB_DEV_AD = 0x00;
UIF_SUSPEND = 0;
UIF_TRANSFER = 0;
UIF_BUS_RST = 0; //清中断标志
}
if (UIF_SUSPEND) //USB总线挂起/唤醒完成
{
UIF_SUSPEND = 0;
if ( USB_MIS_ST & bUMS_SUSPEND ) //挂起
{
#ifdef DE_PRINTF
printf( "zz" ); //睡眠状态
#endif
while ( XBUS_AUX & bUART0_TX )
{
; //等待发送完成
}
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; //USB或者RXD0有信号时可被唤醒
PCON |= PD; //睡眠
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
WAKE_CTRL = 0x00;
}
}
else { //意外的中断,不可能发生的情况
USB_INT_FG = 0xFF; //清中断标志
// printf("UnknownInt N");
}
}
main()
{
UINT8 i;
CfgFsys( ); //CH559时钟选择配置
mDelaymS(5); //修改主频等待内部晶振稳定,必加
mInitSTDIO( ); //串口0初始化
#ifdef DE_PRINTF
printf("start ...\n");
#endif
for(i=0; i<64; i++) //准备演示数据
{
UserEp2Buf[i] = i;
}
USBDeviceInit(); //USB设备模式初始化
EA = 1; //允许单片机中断
UEP1_T_LEN = 0; //预使用发送长度一定要清空
UEP2_T_LEN = 0; //预使用发送长度一定要清空
FLAG = 0;
Ready = 0;
while(1)
{
if(Ready&& (Ep2InKey==0))
{
Enp2BlukIn( );
mDelaymS( 100 );
}
mDelaymS( 100 ); //模拟单片机做其它事
}
}