Managing Communications on the Bulk Endpoints

22 Mar

Managing Communications on the Bulk Endpoints
One way to manage communications on the bulk endpoints is to set a variable that specifies whether the device is waiting for a CBW, ready to send data or a CSW to the host, or ready to receive data from the host.

Firmware can call a function repeatedly to check the value of the variable and take any needed action:

#define MSD_WAIT           0 // Waiting for a CBW.
#define MSD_DATA_IN           2 // IN Data State (device to host).
#define MSD_DATA_OUT           3 // OUT Data State (host to device).

byte MSD_State; // Holds the current state of the device.

The msd_buffer array holds a 512-byte block of data:
volatile far char msd_buffer[512];

The mMin macro returns the lower of two values (A or B):
#define mMin(A, B) (A < B) ? A:B

The code that follows uses these macros from Chapter 2: MSD_BD_IN, MSD_BD_OUT, MSD_IN_EP_SIZE, MSD_OUT_EP_SIZE, mUSBBufferReady, and mMSDTxIsBusy. The code also calls the USBDriverService function included in Microchip’s Framework firmware. USBDriverService handles interrupts related to USB communications.

Sending Data
The SendData function accepts a pointer to data to send (dataAddr) and the number of bytes to send (dataSize). The function stores the passed address in the buffer descriptor’s address registers, stores the number of bytes to send in the byte-count register, and gives ownership of the buffer descriptor to the SIE. The device sends the data in the next IN transaction on the endpoint.

void SendData(byte* dataAddr, byte dataSize)
{
// Wait for the SIE to give up ownership of the bulk IN endpoint.
while (mMSDTxIsBusy())
{
// Service USB interrupts. See Microchip Framework firmware for details.
USBDriverService();
}
// Set the address in the buffer descriptor to the passed address.
MSD_BD_IN.ADR = dataAddr;
// Set the buffer descriptor’s count to the passed data size.
MSD_BD_IN.Cnt = dataSize;
// Give ownership of the buffer descriptor to the SIE.
mUSBBufferReady(MSD_BD_IN);
// Service USB interrupts.
USBDriverService();
}

Preparing to Send Data to the USB Host
The MSDDataIn function manages sending data in the data-transport phase of a command. The function sets fields in the CSW to indicate how many bytes in the transfer have been received and how many additional bytes the device expects to receive.

byte *ptrNextData; // must be set to the location of the first byte to send
void MSDDataIn(void)
{
byte i;
dword size;
// Does bCSWStatus = no error AND is the total data to be sent >= the endpoint’s size?
if ((msd_csw.bCSWStatus == 0×00) &&
(msd_csw.dCSWDataResidue >= MSD_IN_EP_SIZE))
{
// Send MSD_IN_EP_SIZE bytes of data on the bulk IN endpoint.
// The data begins at ptrNextData.
SendData (ptrNextData, MSD_IN_EP_SIZE);
// Subtract the sent bytes from dCBWDataTransferLength in the CBW.
gblCBW.dCBWDataTransferLength -= MSD_IN_EP_SIZE;
// Subtract the sent bytes from dCSWDataResidue in the CSW.
msd_csw.dCSWDataResidue -= MSD_IN_EP_SIZE;

// Increment the pointer to the next data to send.
ptrNextData += MSD_IN_EP_SIZE;
} else
{
if (msd_csw.bCSWStatus != 0×0)
{
// bCSWStatus indicates an error.
// Set size to the lower of the endpoint size or dCBWDataTransferLength.
size = mMin (MSD_IN_EP_SIZE, gblCBW.dCBWDataTransferLength);
// Reset msd_buffer’s contents to zeroes to send pad data.
for (i = 0; i < size; i++) msd_buffer[i] = 0;
if (gblCBW.dCBWDataTransferLength > MSD_IN_EP_SIZE)
{
// There was an error (bCSWStatus != 0×0)
// and dCBWDataTransferLength is greater than the endpoint size.
// Send MSD_IN_EP_SIZE bytes from msd_buffer.
SendData((byte*)&msd_buffer[0], MSD_IN_EP_SIZE);
// Subtract the sent bytes from dCBWDataTransferLength in the CBW.
gblCBW.dCBWDataTransferLength -= MSD_IN_EP_SIZE;
// Subtract the sent bytes from dCSWDataResidue in the CSW.
msd_csw.dCSWDataResidue -= MSD_IN_EP_SIZE;

} else
{
// There was an error (bCSWStatus != 0×0)
// and dCBWDataTransferLength is <= the endpoint size.
// Send dCBWDataTransferLength bytes from msd_buffer.
SendData((byte*)&msd_buffer[0], gblCBW.dCBWDataTransferLength);
// Set dCBWDataTransferLength = 0 to cause the CSW to be sent.
gblCBW.dCBWDataTransferLength = 0;
// Decrement dCSWDataResidue by the number of bytes sent.
msd_csw.dCSWDataResidue -= gblCBW.dCBWDataTransferLength;
}
} else
{
// There is no error and the data to be sent is <= the endpoint size.
// Send dCSWDataResidue bytes beginning at ptrNextData.
SendData(ptrNextData, msd_csw.dCSWDataResidue);
// Subtract the sent bytes from dCBWDataTransferLength.
gblCBW.dCBWDataTransferLength -= msd_csw.dCSWDataResidue ;
// Set dCSWDataResidue equal to dCBWDataTransferLength.
msd_csw.dCSWDataResidue = gblCBW.dCBWDataTransferLength;
// If the host expected more bytes than were sent,
// dCBWDataTransferLength is greater than zero.
// Set dCBWDataTransferLength = 0 to cause the CSW to be sent.
gblCBW.dCBWDataTransferLength = 0;
}
}
}
}


Random Posts

No comments yet

Leave a Reply

You must be logged in to post a comment.