/********************************************************************
函数功能:端点0输出中断处理函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void UsbEp0Out(void)
{
#ifdef DEBUG0
Prints("USB端点0输出中断。\r\n");
#endif
//读取端点0输出最后传输状态,该操作清除中断标志
//并判断第5位是否为1,如果是,则说明是建立包
if(D12ReadEndpointLastStatus(0)&0x20)
{
D12ReadEndpointBuffer(0,16,Buffer); //读建立过程数据
D12AcknowledgeSetup(); //应答建立包
D12ClearBuffer(); //清缓冲区
//将缓冲数据填到设备请求的各字段中
bmRequestType=Buffer[0];
bRequest=Buffer[1];
wValue=Buffer[2]+(((uint16)Buffer[3])<<8);
wIndex=Buffer[4]+(((uint16)Buffer[5])<<8);
wLength=Buffer[6]+(((uint16)Buffer[7])<<8);
//下面的代码判断具体的请求,并根据不同的请求进行相关操作
//如果D7位为1,则说明是输入请求
if((bmRequestType&0x80)==0x80)
{
//根据bmRequestType的D6~5位散转,D6~5位表示请求的类型
//0为标准请求,1为类请求,2为厂商请求。
switch((bmRequestType>>5)&0x03)
{
case 0: //标准请求
#ifdef DEBUG0
Prints("USB标准输入请求:");
#endif
//USB协议定义了几个标准输入请求,我们实现这些标准请求即可
//请求的代码在bRequest中,对不同的请求代码进行散转
//事实上,我们还需要对接收者进行散转,因为不同的请求接收者
//是不一样的。接收者在bmRequestType的D4~D0位中定义。
//我们这里为了简化操作,有些就省略了对接收者的判断。
//例如获取描述符的请求,只根据描述符的类型来区别。
switch(bRequest)
{
case GET_CONFIGURATION: //获取配置
#ifdef DEBUG0
Prints("获取配置。\r\n");
#endif
break;
case GET_DESCRIPTOR: //获取描述符
#ifdef DEBUG0
Prints("获取描述符——");
#endif
//对描述符类型进行散转,对于全速设备,
//标准请求只支持发送到设备的设备、配置、字符串三种描述符
switch((wValue>>8)&0xFF)
{
case DEVICE_DESCRIPTOR: //设备描述符
#ifdef DEBUG0
Prints("设备描述符。\r\n");
#endif
pSendData=DeviceDescriptor; //需要发送的数据
//判断请求的字节数是否比实际需要发送的字节数多
//这里请求的是设备描述符,因此数据长度就是
//DeviceDescriptor[0]。如果请求的比实际的长,
//那么只返回实际长度的数据
if(wLength>DeviceDescriptor[0])
{
SendLength=DeviceDescriptor[0];
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
case CONFIGURATION_DESCRIPTOR: //配置描述符
#ifdef DEBUG0
Prints("配置描述符。\r\n");
#endif
pSendData=ConfigurationDescriptor; //需要发送的数据为配置描述符
//判断请求的字节数是否比实际需要发送的字节数多
//这里请求的是配置描述符集合,因此数据长度就是
//ConfigurationDescriptor[3]*256+ConfigurationDescriptor[2]。
//如果请求的比实际的长,那么只返回实际长度的数据
SendLength=ConfigurationDescriptor[3];
SendLength=SendLength*256+ConfigurationDescriptor[2];
if(wLength>SendLength)
{
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
case STRING_DESCRIPTOR: //字符串描述符
#ifdef DEBUG0
Prints("字符串描述符");
#endif
switch(wValue&0xFF) //根据wValue的低字节(索引值)散转
{
case 0: //获取语言ID
#ifdef DEBUG0
Prints("(语言ID)。\r\n");
#endif
pSendData=LanguageId;
SendLength=LanguageId[0];
break;
case 1: //厂商字符串的索引值为1,所以这里为厂商字符串
#ifdef DEBUG0
Prints("(厂商描述)。\r\n");
#endif
pSendData=ManufacturerStringDescriptor;
SendLength=ManufacturerStringDescriptor[0];
break;
case 2: //产品字符串的索引值为2,所以这里为产品字符串
#ifdef DEBUG0
Prints("(产品描述)。\r\n");
#endif
pSendData=ProductStringDescriptor;
SendLength=ProductStringDescriptor[0];
break;
case 3: //产品序列号的索引值为3,所以这里为序列号
#ifdef DEBUG0
Prints("(产品序列号)。\r\n");
#endif
pSendData=SerialNumberStringDescriptor;
SendLength=SerialNumberStringDescriptor[0];
break;
default :
#ifdef DEBUG0
Prints("(未知的索引值)。\r\n");
#endif
//对于未知索引值的请求,返回一个0长度的包
SendLength=0;
NeedZeroPacket=1;
break;
}
//判断请求的字节数是否比实际需要发送的字节数多
//如果请求的比实际的长,那么只返回实际长度的数据
if(wLength>SendLength)
{
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
case REPORT_DESCRIPTOR: //报告描述符
#ifdef DEBUG0
Prints("报告描述符。\r\n");
#endif
pSendData=ReportDescriptor; //需要发送的数据为报告描述符
SendLength=sizeof(ReportDescriptor); //需要返回的数据长度
//判断请求的字节数是否比实际需要发送的字节数多
//如果请求的比实际的长,那么只返回实际长度的数据
if(wLength>SendLength)
{
if(SendLength%DeviceDescriptor[7]==0) //并且刚好是整数个数据包时
{
NeedZeroPacket=1; //需要返回0长度的数据包
}
}
else
{
SendLength=wLength;
}
//将数据通过EP0返回
UsbEp0SendData();
break;
default: //其它描述符
#ifdef DEBUG0
Prints("其他描述符,描述符代码:");
PrintHex((wValue>>8)&0xFF);
Prints("\r\n");
#endif
break;
}
break;
case GET_INTERFACE: //获取接口
#ifdef DEBUG0
Prints("获取接口。\r\n");
#endif
break;
case GET_STATUS: //获取状态
#ifdef DEBUG0
Prints("获取状态。\r\n");
#endif
break;
case SYNCH_FRAME: //同步帧
#ifdef DEBUG0
Prints("同步帧。\r\n");
#endif
break;
default: //未定义的标准请求
#ifdef DEBUG0
Prints("错误:未定义的标准输入请求。\r\n");
#endif
break;
}
break;
case 1: //类请求
#ifdef DEBUG0
Prints("USB类输入请求:\r\n");
#endif
break;
case 2: //厂商请求
#ifdef DEBUG0
Prints("USB厂商输入请求:\r\n");
#endif
break;
default: //未定义的请求。这里只显示一个报错信息。
#ifdef DEBUG0
Prints("错误:未定义的输入请求。\r\n");
#endif
break;
}
}
//否则说明是输出请求
else //if(bmRequestType&0x80==0x80)之else
{
//根据bmRequestType的D6~5位散转,D6~5位表示请求的类型
//0为标准请求,1为类请求,2为厂商请求。
switch((bmRequestType>>5)&0x03)
{
case 0: //标准请求
#ifdef DEBUG0
Prints("USB标准输出请求:");
#endif
//USB协议定义了几个标准输出请求,我们实现这些标准请求即可
//请求的代码在bRequest中,对不同的请求代码进行散转
switch(bRequest)
{
case CLEAR_FEATURE: //清除特性
#ifdef DEBUG0
Prints("清除特性。\r\n");
#endif
break;
case SET_ADDRESS: //设置地址
#ifdef DEBUG0
Prints("设置地址。地址为:");
PrintHex(wValue&0xFF); //显示所设置的地址
Prints("\r\n");
#endif
D12SetAddress(wValue&0xFF); //wValue中的低字节是设置的地址值
//设置地址没有数据过程,直接进入到状态过程,返回一个0长度的数据包
SendLength=0;
NeedZeroPacket=1;
//将数据通过EP0返回
UsbEp0SendData();
break;
case SET_CONFIGURATION: //设置配置
#ifdef DEBUG0
Prints("设置配置。\r\n");
#endif
//使能非0端点。非0端点只有在设置为非0的配置后才能使能。
//wValue的低字节为配置的值,如果该值为非0,才能使能非0端点。
//保存当前配置值
ConfigValue=wValue&0xFF;
D12SetEndpointEnable(ConfigValue);
//返回一个0长度的状态数据包
SendLength=0;
NeedZeroPacket=1;
//将数据通过EP0返回
UsbEp0SendData();
break;
case SET_DESCRIPTOR: //设置描述符
#ifdef DEBUG0
Prints("设置描述符。\r\n");
#endif
break;
case SET_FEATURE: //设置特性
#ifdef DEBUG0
Prints("设置特性。\r\n");
#endif
break;
case SET_INTERFACE: //设置接口
#ifdef DEBUG0
Prints("设置接口。\r\n");
#endif
break;
default: //未定义的标准请求
#ifdef DEBUG0
Prints("错误:未定义的标准输出请求。\r\n");
#endif
break;
}
break;
case 1: //类请求
#ifdef DEBUG0
Prints("USB类输出请求:");
#endif
switch(bRequest)
{
case SET_IDLE:
#ifdef DEBUG0
Prints("设置空闲。\r\n");
#endif
//只需要返回一个0长度的数据包即可
SendLength=0;
NeedZeroPacket=1;
//将数据通过EP0返回
UsbEp0SendData();
break;
default:
#ifdef DEBUG0
Prints("未知请求。\r\n");
#endif
break;
}
break;
case 2: //厂商请求
#ifdef DEBUG0
Prints("USB厂商输出请求:\r\n");
#endif
break;
default: //未定义的请求。这里只显示一个报错信息。
#ifdef DEBUG0
Prints("错误:未定义的输出请求。\r\n");
#endif
break;
}
}
}
//普通数据输出
else //if(D12ReadEndpointLastStatus(0)&0x20)之else
{
D12ReadEndpointBuffer(0,16,Buffer);
D12ClearBuffer();
}
}
End of function//
端点0输出中断处理函数
最新推荐文章于 2024-01-11 17:15:09 发布