V-USB: Outputting Data with usbFunctionRead()
I promised to commenter Marek to post an example of using usbFunctionRead() to return larger amounts of data. So building upon the ATtiny85 version we made in last part, let’s add one more command to usbtest.exe:
#define USB_DATA_LONGOUT 5
// [...] Change the buffer size in main():
char buffer[2048];
// [...] Add the following in the if-else structure in main():
} else if(strcmp(argv[1], "longout") == 0) {
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_DATA_LONGOUT, 0, 0, (char *)buffer, sizeof(buffer), 5000);
printf("Received %d bytes: %s\n", nBytes, buffer);
}
Now let’s tell V-USB that we’re implementing usbFunctionRead() and doing transfers of more than 254 bytes in usbconfig.h:
#define USB_CFG_IMPLEMENT_FN_READ 1
#define USB_CFG_LONG_TRANSFERS 1
Funny thing is, if you don’t define long transfers, V-USB will use a byte-sized variable for transfer length, and transfers using usbFunctionRead will fail with PC-side buffers longer than 254 bytes. So you have two options:
- Define USB_CFG_LONG_TRANSFERS to 1
- Have the PC-side buffer of 254 bytes or less
For some strange reason, the standard V-USB method of using usbMsgPtr does not fail with the 256-byte buffer I had in the tutorials. Weird. Anyways, after we’ve configured long transfers the return value of usbFunctionSetup needs to be changed. V-USB automatically defines usbMsgLen_t to be the correct data type, so we’ll use that. Here are the changes to main.c:
// [...] Add the define and a data counter for USB_DATA_LONGOUT
#define USB_DATA_LONGOUT 5
static int dataSent;
// [...] Change the return type from uchar to usbMsgLen_t
USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) {
// [...] Add handling of USB_DATA_LONGOUT
case USB_DATA_LONGOUT: // send data to PC
dataSent = 0;
return USB_NO_MSG;
// [...] Add new function usbFunctionRead
USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len) {
uchar i;
for(i = 0; dataSent < 1024 && i < len; i++, dataSent++)
data[i] = '0'+i;
// terminate the string if it's the last byte sent
if(i && dataSent == 1024)
data[i-1] = 0; // NULL
return i; // equals the amount of bytes written
}
We're using the dataSent variable to keep track how many bytes we've returned and quit once 1024 bytes is sent. Once usbFunctionRead returns a value less than "len" parameter, the transfer is automatically terminated.
Voila! Note that using long transfers finally pushes the firmware size over 2048 bytes, so ATtiny2313 cannot be used anymore unless you trim something out or maybe optimize main.c for size. With ATtiny85 I'm using now it's not a problem. You can download the zip if you like. :)