转自网易博客,博主:drifer
提纲:
² 第一步从具体数据的总体变化过程来演示原代码是正确的。
² 第二步解释为什么原代码这么变扭
² 第三步是我觉得怎么改才是最合理的
n 第一步
1. 以USB主端第一次发送Get_Descriptor命令为例,其数据构成是"80 06 00 01 00 00 40 00"
2. 在Setup0_Process()中将收到的数据赋值给DEVICE_INFO的前五个子项,赋值结果如下:
USBbmRequestType = 0x80 //pBuf.b单字节获取,无需解释
USBbRequest = 0x06 //pBuf.b单字节获取,无须解释
USBwValues = 0x0001 //pBuf.w获取2个字节,因为是小端模式,*pBuf.w的值是0x0100,byteswap后是0x0001
USBwIndexs = 0x0000 // 过程和USBwValue一样,只是变来变去都是0x0000
USBwLengths = 0x0040 //pBuf.w获取2个字节,因为是小端模式,*pBuf.w的值是0x0040
3. 后进入Data_Setup0(),这里使用到了USBwValues的值,源码“uint8_t wValue1 = pInformation->USBwValue1;”
这里需要了解USBwValue1的定义,定义为“#define USBwValue1 USBwValues.bw.bb1”,在usb_core.h里面。而USBwValues的声明如下: uint16_t_uint8_t USBwValues; /* wValue */
这时候又牵涉到uint16_t_uint8_t的定义了,该定义如下:
typedef union
{
uint16_tw;
structBW
{
uint8_tbb1;
uint8_tbb0;
}
bw;
} uint16_t_uint8_t;
从上面的定义可以看到USBValue1就是USBwValues的低字节,而USBValue0是USBwValues的高字节(重点,变扭的根源!)。
所以赋值语句“uint8_t wValue1 = pInformation->USBwValue1”执行后wValue1的值是0x01,从“usb complete 4th”这本书的第155页可以了解到
这个取值是正确的,0x01是原书的截图如下:
4.Data_Setup0()中还使用了USBwlengths,使用语句是“__IO uint32_t wLength = pInformation->USBwLength;” wLength被赋值后的值是0x40,也是对的。
n 第二步,为什么代码这么变扭
1.变扭的根源就是下面这个定义:
typedef union
{
uint16_tw;
structBW
{
uint8_t bb1;
uint8_t bb0;
}
bw;
} uint16_t_uint8_t;
在小端模式下,低字节存储的地址小,高字节存储的地址大。而上面这个struct的定义时,将bb1作为低字节,将bb0作为高字节,实在是有违常识。这个定义从而导致USBwValue0是高字节,USBwValue1是低字节。
#define USBwValue0 USBwValues.bw.bb0
#define USBwValue1 USBwValues.bw.bb1
所以wValue需要用byteswap操作一下后,仍旧用USBwValue1来获取高字节。也就是说负负得正。
n 第三步,怎么改不变扭,这个简单,如下:
这个要反一下:
typedef union
{
uint16_tw;
structBW
{
uint8_tbb0;
uint8_tbb1;
}
bw;
} uint16_t_uint8_t;
这个不变:
#define USBwValue0 USBwValues.bw.bb0
#define USBwValue1 USBwValues.bw.bb1
然后那个byteswap就不需要了,如下:
if(pInformation->ControlState != PAUSE)
{
// 获取SETUP包的8个字节数据,该数据构成信息详见<usb complete 4th>的第144page
pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */
pInformation->USBbRequest = *pBuf.b++; /* bRequest */
pBuf.w += offset; /* word not accessed because of 32 bits addressing*/
pInformation->USBwValue = *pBuf.w++; /* wValue*/
pBuf.w += offset; /* word not accessedbecause of 32 bits addressing */
pInformation->USBwIndex = *pBuf.w++; /* wIndex */
pBuf.w += offset; /* word not accessedbecause of 32 bits addressing */
pInformation->USBwLength = *pBuf.w; /* wLength */ // zhoulz,这个为什么不需要byteswap澹?
}
实际调用不变,如下:
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
{
uint8_t wValue1 = pInformation->USBwValue1;
if (wValue1 == DEVICE_DESCRIPTOR)
{
CopyRoutine = pProperty->GetDeviceDescriptor;
}
else if (wValue1 == CONFIG_DESCRIPTOR)
{
CopyRoutine = pProperty->GetConfigDescriptor;
}
else if (wValue1 == STRING_DESCRIPTOR)
{
CopyRoutine = pProperty->GetStringDescriptor;
} /* End of GET_DESCRIPTOR */
}