BOT是Bulk Only Transport的缩写。数据、命令、状态都通过Bulk端点传输(没有使用到中断、控制端点),这里用到的是EP1和EP2,2个端点都是Bulk的模式,这就是所谓的Bulk Only,即在EP1和EP2上传输的数据再包一层协议。
命令/数据/状态的协议如下图所示:
【CBW】
CBW是Command Block Wrapper的缩写。USB主机通过OUT端点发送CBW包,这样设备才知道接下来需要接收什么样数据还是发送对应的数据。一个CBW包结构如下图所示:
dCBWSignature: 固定为43425355h(小端),表示这段数据是CBW。
dCBWTag: HOST发送的命令标记。设备在CSW.dCSWTag返回这个值,表示当前CSW是响应对应的CBW。
dCBWDataTransferLength: 主机期望的数据长度(Data-Out或Data-In过程中的数据长度)。如果为0,则没有Data过程。
bmCBWFlags:
Bit 7:数据方向,0表示Data Out,HOST到设备;1表示Data In,设备到HOST。
Bit6: 不再使用(Obsolete). HOST设置为0.
Bit5-0: 预留位,HOST设置为0
bCBWLUN: HOST告知设备该CBW是给哪个LUN的。如果设备不支持LUN,这个值为0.
bCBWCBLength: CBWCB的有效长度。有效值1到16,其他值无效。
CBWCB: 设备执行的命令块。设备应该可以解释这个数据区域的第bCBWCBLength个字节,这个字节由bInterfaceSubClass指定的类决定它的含义。如果设备支持的命令集使用长度小于16(10h)字节的命令块,则应首先传输有效字节,从偏移量15(Fh)处的字节开始。设备应该忽略CBWCB中偏移地址(15 + bCBWCBLength - 1)的内容。
typedef struct _Bulk_Only_CBW
{
uint32_t dSignature;
uint32_t dTag;
uint32_t dDataLength;
uint8_t bmFlags;
uint8_t bLUN;
uint8_t bCBLength;
uint8_t CB[16];
}stBulkOnlyCBW;
【CSW】
CSW是Command Status Wrapper的缩写。一个CSW包结构如下图所示:
dCSWSignature: 固定为53425355h(小端),表示这段数据是CSW。
dCSWTag: 与dCBWTag相等,用于关联CSW到对应的CBW。
dCSWDataResidue: 对于DATA OUT,设备告知HOST处理的实际数据量;对于DATA IN,设备告知HOST实际发送的数据。DCSWDataRemain不得超过dCBWDataTransferLength中发送的值。
bCSWStatus: bCSWStatus表示命令是否成功。
值 | 描述 |
00h | 命令成功 |
01h | 命令失败 |
02h | 相位错误 |
03h和04h | 不再使用 |
05h到FFh | 预留 |
1. 端点函数
void EP1_IN_Callback(void)
{
mscBotIn();
}
void EP2_OUT_Callback(void)
{
mscBotOut();
}
2. mscBotOut
首先从OUT端点的Buffer中读入HOST发送过来的数据。
gMscBotData.len = USB_SIL_Read(USB_MSC_EP_OUT, gMscBotData.dat);
EP OUT数据主要分2种情况:
switch(gMscBotState)
{
case MSC_BOT_IDLE:
break;
case MSC_BOT_DATA_OUT:
break;
default:
break;
}
如果当前状态是IDLE,则读入的数据是CBW,CBW解析依据SCSI的命令。
如果状态是DATA OUT,则表明是数据。
3. mscBotIn
IN数据的含义分3种情况:MSC_BOT_CSW_Send是指已经发送完CSW,MSC_BOT_ERROR是指BOT传输出错了,这2个状态都是将状态设置为IDLE,并且OUT端点设置为可接收;MSC_BOT_DATA_IN是HOST读入数据,只需要支持SCI命令SCSI_READ10;BOT_DATA_IN_LAST表示数据已经完全读入。
void mscBotIn(void)
{
switch(gMscBotState)
{
case MSC_BOT_CSW_Send:
case MSC_BOT_ERROR:
break;
case MSC_BOT_DATA_IN:
break;
case MSC_BOT_DATA_IN_LAST:
break;
default:
break;
}
}
4. HOST开始是发送CBW到设备,此时gMscBotState的状态应该是MSC_BOT_IDLE,
void mscBotOut(void)
{
gMscBotData.len = USB_SIL_Read(USB_MSC_EP_OUT, gMscBotData.dat);
switch(gMscBotState)
{
case MSC_BOT_IDLE:
mscBotCBWDecode();
break;
case MSC_BOT_DATA_OUT:
break;
default:
break;
}
}