diff -r 000000000000 -r a41df078684a kerneltest/e32test/win32/usbrflct/usbrflct.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/win32/usbrflct/usbrflct.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,995 @@ +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\win32\usbrflct\usbrflct.cpp +// Win32 USB test program USBRFLCT: performs I/O with a device running the +// Symbian OS test program T_USB, using the generic USB device driver USBIO. +// === Includes === +// +// + +#include +#include +#include +#include + +#include "usbio.h" // USBIO Dev Kit +#include "usbiopipe.h" // ditto + + +// === Global Defines === + +// The version of this program +#define VERSION_MAJOR 1 +#ifdef VERSION_MINOR +# undef VERSION_MINOR // VERSION_MINOR sometimes yields funny compiler warning (c4005) +#endif +#define VERSION_MINOR 6 +#ifdef VERSION_MICRO +# undef VERSION_MICRO // ditto +#endif +#define VERSION_MICRO 0 + +// The version of the USBIO driver this program is compiled against +#define USBIO_VERSION_MAJOR 2 +#define USBIO_VERSION_MINOR 41 + +#define MAX_DESCRIPTOR_BUFFER_SIZE 2047 + +// === Global Vars === + +// Our own private GUID (also used in the .inf file as 'DriverUserInterfaceGuid') +// {55606403-E62D-4707-9F56-40D48C6736D0} +static const GUID g_UsbioID = + {0x55606403, 0xe62d, 0x4707, {0x9f, 0x56, 0x40, 0xd4, 0x8c, 0x67, 0x36, 0xd0}}; + +// Handle for USB device list +static HDEVINFO g_DevList = NULL; + +// USBIO supported device +static CUsbIo g_UsbDev; +static CUsbIoPipe g_BulkOutPipe; +static CUsbIoPipe g_BulkInPipe; + +// 2 Bulk endpoints +static UCHAR g_ucBulkOutEndpoint = 0; +static UCHAR g_ucBulkInEndpoint = 0; + +// Read/write buffer +static const DWORD KBufferSize = 1024 * 1024; +static const DWORD KPreambleLength = 8; +static BYTE Data[KBufferSize]; // the read/write buffer +static DWORD Length; // Length of a transfer +static time_t T_0; // the starting time + +static CUsbIoBuf g_Buf((VOID*) Data, KBufferSize); // the data buffer +static CUsbIoBuf g_ZlpBuf (NULL, 0); // the data buffer + +static DWORD dwRC = USBIO_ERR_SUCCESS; // global error indicator + +enum + { + ELoop, + ELoopDebug, + EReceiveOnly, + ETransmitOnly + }; + +static int TransferMode = ELoop; +static bool VerboseMode = false; +static bool ZlpMode = false; + +static unsigned int maxOutPacketSize = 0; + +// The version of T_USB we require (at least) +static const DWORD KTusbVersion = 20070524; + +// After how many iterations to update the CRT: +static const int KLoopModeDisplayUpdate = 1024; +// After how many iterations (= MBytes) to update the CRT: +static const int KUniModeDisplayUpdate = 10; + +// Helper #defines + +#define PRINT_IF_VERBOSE(string) \ + do { \ + if (VerboseMode) \ + { \ + printf(string); \ + } \ + } while (0) + +#define PRINT_IF_VERBOSE1(string, a) \ + do { \ + if (VerboseMode) \ + { \ + printf(string, a); \ + } \ + } while (0) + + +// === Functions === + +// +// Process the command line arguments, printing a helpful message +// if none are supplied. +// +static int ProcessCmdLine(int argc, char* argv[]) + { + char help_text[] = + "* Syntax: usbrflct [options]\n" + "* Options:\n" + "* /[r|t] receive|transmit only; default is to loop\n" + "* /z zero length packet at end of a transmission\n" + "* (only if last packet is full length)\n" + "* /l loop mode with stats printed for every iteration\n" + "* /v verbose driver & program output\n" + "* /[h|?] displays this help text\n" + "\n"; + + for (int i = 1; i < argc; i++) + { + strupr(argv[i]); + if ((argv[i][0] == '-') || (argv[i][0] == '/')) + { + switch (argv[i][1]) + { + case 'R': + case 'r': + TransferMode = EReceiveOnly; + break; + case 'T': + case 't': + TransferMode = ETransmitOnly; + break; + case 'L': + case 'l': + TransferMode = ELoopDebug; + break; + case 'V': + case 'v': + VerboseMode = true; + break; + case 'Z': + case 'z': + ZlpMode = true; + break; + case '?': + case 'H': + case 'h': + cout << help_text; + return -1; + default: + cout << "* Invalid argument: " << argv[i] << "\n"; + cout << help_text; + return -1; + } + } + } + return 0; + } + + +static void OpenUsbDevice() + { + CUsbIo::DestroyDeviceList(g_DevList); + + // Enumerate attached USB devices supported by USBIO + g_DevList = CUsbIo::CreateDeviceList(&g_UsbioID); + + // Open first device in list + dwRC = g_UsbDev.Open(0, g_DevList, &g_UsbioID); + + PRINT_IF_VERBOSE1("\nCUsbIo::Open returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_VERSION_MISMATCH) + { + printf("\n* Error: \"The API version reported by the USBRFLCT driver\n" \ + "* does not match the expected version.\"\n"); + printf("* The driver will need to be updated as follows:\n"); + printf("* 1. Connect the device to the PC & start T_USB,\n" \ + "* then find the USB device in the Windows Device Manager\n" \ + "* ('Control Panel'->'System'->'Hardware'->'Device Manager').\n" \ + "* Right click on the device name and choose 'Uninstall...'.\n"); + printf("* 2. In c:\\winnt\\inf\\, find (by searching for \"Symbian\") and\n" \ + "* delete the *.INF file that was used to install the existing\n" \ + "* version of USBRFLCT.SYS. Make sure to also delete the\n" \ + "* precompiled version of that file (.PNF).\n"); + printf("* 3. In c:\\winnt\\system32\\drivers\\, delete the file USBRFLCT.SYS.\n"); + printf("* Then unplug & reconnect the USB device and, when prompted, install\n" \ + "* the new USBRFLCT.SYS driver using the .INF file from this distribution.\n" \ + "* (All files can be found under e32test\\win32\\usbrflct_distribution\\.)\n"); + } + } + + +static void CloseUsbDevice() + { + // Close the device + g_UsbDev.Close(); + PRINT_IF_VERBOSE("CUsbIo::Close called\n"); + } + + +static void GetDeviceDescriptor() + { + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + + memset(&DeviceDescriptor, 0, sizeof(USB_DEVICE_DESCRIPTOR)); + + // Get device descriptor + dwRC = g_UsbDev.GetDeviceDescriptor(&DeviceDescriptor); + PRINT_IF_VERBOSE1("CUsbIo::GetDeviceDescriptor returned <0x%X>\n", dwRC); + + if (VerboseMode && (dwRC == USBIO_ERR_SUCCESS)) + { + printf("\nDEVICE DESCRIPTOR:\n" + "bLength = <%u>\n" + "bDescriptorType = <%u>\n" + "bcdUSB = <%u>\n" + "bDeviceClass = <%u>\n" + "bDeviceSubClass = <%u>\n" + "bDeviceProtocol = <%u>\n" + "bMaxPacketSize0 = <%u>\n" + "idVendor = <%u>\n" + "idProduct = <%u>\n" + "bcdDevice = <%u>\n" + "iManufacturer = <%u>\n" + "iProduct = <%u>\n" + "iSerialNumber = <%u>\n" + "bNumConfigurations = <%u>\n\n", + DeviceDescriptor.bLength, + DeviceDescriptor.bDescriptorType, + DeviceDescriptor.bcdUSB, + DeviceDescriptor.bDeviceClass, + DeviceDescriptor.bDeviceSubClass, + DeviceDescriptor.bDeviceProtocol, + DeviceDescriptor.bMaxPacketSize0, + DeviceDescriptor.idVendor, + DeviceDescriptor.idProduct, + DeviceDescriptor.bcdDevice, + DeviceDescriptor.iManufacturer, + DeviceDescriptor.iProduct, + DeviceDescriptor.iSerialNumber, + DeviceDescriptor.bNumConfigurations); + } + } + + +static void GetConfigurationDescriptor() + { + CHAR szBuffer[MAX_DESCRIPTOR_BUFFER_SIZE] = ""; + USB_CONFIGURATION_DESCRIPTOR* pConfigDescriptor = NULL; + USB_INTERFACE_DESCRIPTOR* pInterfaceDescriptor = NULL; + USB_ENDPOINT_DESCRIPTOR* pEndpointDescriptor = NULL; + + DWORD dwByteCount = MAX_DESCRIPTOR_BUFFER_SIZE; + + memset(szBuffer, 0, sizeof(szBuffer)); + + // Get first configuration descriptor + dwRC = + g_UsbDev.GetConfigurationDescriptor((USB_CONFIGURATION_DESCRIPTOR*) szBuffer, + dwByteCount, 0); + PRINT_IF_VERBOSE1("CUsbIo::GetConfigurationDescriptor returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_SUCCESS) + { + USB_COMMON_DESCRIPTOR* Desc; + ULONG rl = dwByteCount; + ULONG ulDescLength = 0; + CHAR* data = szBuffer; + + while (rl > 0) + { + Desc = (USB_COMMON_DESCRIPTOR*) data; + ulDescLength = Desc->bLength; + if ((ulDescLength > rl) || (ulDescLength == 0)) + { + printf("Length remaining too short!\n"); + rl = 0; + } + else + { + switch (Desc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + pConfigDescriptor = + (USB_CONFIGURATION_DESCRIPTOR*) data; + if (VerboseMode) + { + printf("\nCONFIGURATION DESCRIPTOR:\n" + "bLength = <%u>\n" + "bDescriptorType = <%u>\n" + "wTotalLength = <%u>\n" + "bNumInterfaces = <%u>\n" + "bConfigurationValue = <%u>\n" + "iConfiguration = <%u>\n" + "bmAttributes = <%u>\n" + "MaxPower = <%u>\n", + pConfigDescriptor->bLength, + pConfigDescriptor->bDescriptorType, + pConfigDescriptor->wTotalLength, + pConfigDescriptor->bNumInterfaces, + pConfigDescriptor->bConfigurationValue, + pConfigDescriptor->iConfiguration, + pConfigDescriptor->bmAttributes, + pConfigDescriptor->MaxPower); + } + break; + case USB_INTERFACE_DESCRIPTOR_TYPE: + pInterfaceDescriptor = + (USB_INTERFACE_DESCRIPTOR*) data; + if (VerboseMode) + { + printf("\nINTERFACE DESCRIPTOR: \n" + "bLength = <%u>\n" + "bDescriptorType = <%u>\n" + "bInterfaceNumber = <%u>\n" + "bAlternateSetting = <%u>\n" + "bNumEndpoints = <%u>\n" + "bInterfaceClass = <%u>\n" + "bInterfaceSubClass = <%u>\n" + "bInterfaceProtocol = <%u>\n" + "iInterface = <%u>\n", + pInterfaceDescriptor->bLength, + pInterfaceDescriptor->bDescriptorType, + pInterfaceDescriptor->bInterfaceNumber, + pInterfaceDescriptor->bAlternateSetting, + pInterfaceDescriptor->bNumEndpoints, + pInterfaceDescriptor->bInterfaceClass, + pInterfaceDescriptor->bInterfaceSubClass, + pInterfaceDescriptor->bInterfaceProtocol, + pInterfaceDescriptor->iInterface); + } + break; + case USB_ENDPOINT_DESCRIPTOR_TYPE: + pEndpointDescriptor = + (USB_ENDPOINT_DESCRIPTOR*) data; + if (VerboseMode) + { + printf("\nENDPOINT DESCRIPTOR: \n" + "bLength = <%u>\n" + "bDescriptorType = <%u>\n" + "bEndpointAddress = <%u>\n" + "bmAttributes = <%u>\n" + "wMaxPacketSize = <%u>\n" + "bInterval = <%u>\n", + pEndpointDescriptor->bLength, + pEndpointDescriptor->bDescriptorType, + pEndpointDescriptor->bEndpointAddress, + pEndpointDescriptor->bmAttributes, + pEndpointDescriptor->wMaxPacketSize, + pEndpointDescriptor->bInterval); + } + break; + default: + break; + } + } + data += ulDescLength; + rl -= ulDescLength; + } + } + PRINT_IF_VERBOSE("\n"); + } + + +static void GetStringDescriptor() + { + CHAR szBuffer[MAX_DESCRIPTOR_BUFFER_SIZE] = ""; + USB_STRING_DESCRIPTOR* pStringDescriptor = NULL; + DWORD dwByteCount = MAX_DESCRIPTOR_BUFFER_SIZE; + + memset(szBuffer, 0, sizeof(szBuffer)); + + // Get string descriptor + dwRC = g_UsbDev.GetStringDescriptor((USB_STRING_DESCRIPTOR*) szBuffer, + dwByteCount, 1, 0); + PRINT_IF_VERBOSE1("CUsbIo::GetStringDescriptor returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_SUCCESS) + { + pStringDescriptor = (USB_STRING_DESCRIPTOR*) szBuffer; + if (VerboseMode) + { + printf("\nSTRING DESCRIPTOR:\n" + "bLength = <%u>\n" + "bDescriptorType = <%u>\n" + "bString = <", // output continues below! + pStringDescriptor->bLength, + pStringDescriptor->bDescriptorType); + } + INT i = 0; + CHAR* Ptr = szBuffer; + for (i = 2, Ptr += 2; + i < pStringDescriptor->bLength; + i += 2, Ptr += 2) + { + PRINT_IF_VERBOSE1("%c", *Ptr); + } + PRINT_IF_VERBOSE(">\n\n"); + } + } + + +static void SetConfiguration() + { + USBIO_SET_CONFIGURATION SetConfig; + + memset(&SetConfig, 0, sizeof(USBIO_SET_CONFIGURATION)); + + // Set the first configuration as active + SetConfig.ConfigurationIndex = 0; + SetConfig.NbOfInterfaces = 1; + SetConfig.InterfaceList[0].InterfaceIndex = 0; + SetConfig.InterfaceList[0].AlternateSettingIndex = 0; + SetConfig.InterfaceList[0].MaximumTransferSize = KBufferSize; + dwRC = g_UsbDev.SetConfiguration(&SetConfig); + PRINT_IF_VERBOSE1("CUsbIo::SetConfiguration returned <0x%X>\n", dwRC); + } + + +static void GetConfigurationInfo() + { + USBIO_CONFIGURATION_INFO ConfigInfo; + USHORT i = 0; + + memset(&ConfigInfo, 0, sizeof(USBIO_CONFIGURATION_INFO)); + + dwRC = g_UsbDev.GetConfigurationInfo(&ConfigInfo); + PRINT_IF_VERBOSE1("CUsbIo::GetConfigurationInfo returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_SUCCESS) + { + if (VerboseMode) + { + printf("\nCONFIGURATION INFO:\n" + "NbOfInterfaces = <%lu>\n" + "NbOfPipes = <%lu>\n", + ConfigInfo.NbOfInterfaces, + ConfigInfo.NbOfPipes); + } + for (i = 0; i < ConfigInfo.NbOfInterfaces; i++) + { + if (VerboseMode) + { + printf("\nINTERFACE <%u>:\n", i + 1); + printf("InterfaceNumber = <%u>\n" + "AlternateSetting = <%u>\n" + "Class = <%u>\n" + "SubClass = <%u>\n" + "Protocol = <%u>\n" + "NumberOfPipes = <%u>\n" + "reserved1 = <%u>\n" + "reserved2 = <%u>\n", + ConfigInfo.InterfaceInfo[i].InterfaceNumber, + ConfigInfo.InterfaceInfo[i].AlternateSetting, + ConfigInfo.InterfaceInfo[i].Class, + ConfigInfo.InterfaceInfo[i].SubClass, + ConfigInfo.InterfaceInfo[i].Protocol, + ConfigInfo.InterfaceInfo[i].NumberOfPipes, + ConfigInfo.InterfaceInfo[i].reserved1, + ConfigInfo.InterfaceInfo[i].reserved2); + } + } + for (i = 0; i < ConfigInfo.NbOfPipes; i++) + { + PRINT_IF_VERBOSE("\n"); + if ((ConfigInfo.PipeInfo[i].PipeType == PipeTypeBulk) && + !(ConfigInfo.PipeInfo[i].EndpointAddress & 0x80)) + { + PRINT_IF_VERBOSE("Bulk OUT pipe found:\n"); + g_ucBulkOutEndpoint = ConfigInfo.PipeInfo[i].EndpointAddress; + maxOutPacketSize = ConfigInfo.PipeInfo[i].MaximumPacketSize; + } + else if ((ConfigInfo.PipeInfo[i].PipeType == PipeTypeBulk) && + (ConfigInfo.PipeInfo[i].EndpointAddress & 0x80)) + { + PRINT_IF_VERBOSE("Bulk IN pipe found:\n"); + g_ucBulkInEndpoint = ConfigInfo.PipeInfo[i].EndpointAddress; + } + if (VerboseMode) + { + printf("PIPE <%u>\n", i + 1); + printf("PipeType = <%d>\n" + "MaximumTransferSize = <%lu>\n" + "MaximumPacketSize = <%u>\n" + "EndpointAddress = <%u>\n" + "Interval = <%u>\n" + "InterfaceNumber = <%u>\n" + "reserved1 = <%u>\n" + "reserved2 = <%u>\n" + "reserved3 = <%u>\n", + ConfigInfo.PipeInfo[i].PipeType, + ConfigInfo.PipeInfo[i].MaximumTransferSize, + ConfigInfo.PipeInfo[i].MaximumPacketSize, + ConfigInfo.PipeInfo[i].EndpointAddress, + ConfigInfo.PipeInfo[i].Interval, + ConfigInfo.PipeInfo[i].InterfaceNumber, + ConfigInfo.PipeInfo[i].reserved1, + ConfigInfo.PipeInfo[i].reserved2, + ConfigInfo.PipeInfo[i].reserved3); + } + } + } + PRINT_IF_VERBOSE("\n"); + } + + +static void OpenPipes() + { + CUsbIo::DestroyDeviceList(g_DevList); + + // Enumerate attached USB devices supported by USBIO + g_DevList = CUsbIo::CreateDeviceList(&g_UsbioID); + + // Create the bulk OUT pipe + dwRC = g_BulkOutPipe.Bind(0, g_ucBulkOutEndpoint, g_DevList, &g_UsbioID); + PRINT_IF_VERBOSE1("CUsbIoPipe::Bind (Bulk OUT) returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_SUCCESS) + { + // Create the bulk IN pipe + dwRC = g_BulkInPipe.Bind(0, g_ucBulkInEndpoint, g_DevList, &g_UsbioID); + PRINT_IF_VERBOSE1("CUsbIoPipe::Bind (Bulk IN) returned <0x%X>\n", dwRC); + } + PRINT_IF_VERBOSE("\n"); + } + + +static void ClosePipes() + { + // Close down the bulk OUT pipe + dwRC = g_BulkOutPipe.Unbind(); + PRINT_IF_VERBOSE1("CUsbIoPipe::Unbind (Bulk OUT) returned <0x%X>\n", dwRC); + + if (dwRC == USBIO_ERR_SUCCESS) + { + // Close down the bulk IN pipe + dwRC = g_BulkInPipe.Unbind(); + PRINT_IF_VERBOSE1("CUsbIoPipe::Unbind (Bulk IN) returned <0x%X>\n", dwRC); + } + } + + +static void ReceiveVersion() + { + // Here we (hope to) read an 8 byte packet containing the T_USB version. + printf("* Waiting for T_USB version packet to arrive..."); + + // The first 4 bytes are interpreted as an int32 value. + DWORD bytes_read = 0; + g_Buf.NumberOfBytesToTransfer = KPreambleLength; + g_BulkInPipe.Read(&g_Buf); + dwRC = g_BulkInPipe.WaitForCompletion(&g_Buf, INFINITE); + printf(" done.\n"); + bytes_read = g_Buf.BytesTransferred; + if (dwRC == USBIO_ERR_SUCCESS) + { + if (bytes_read < KPreambleLength) + { + printf("* Read less bytes (%d) than expected (%d).\n", + bytes_read, KPreambleLength); + dwRC = USBIO_ERR_FAILED; + return; + } + } + else + { + printf("\n* Error: CUsbIoPipe::Read (version) returned <0x%X>\n", dwRC); + return; + } + // First make sure it's actually the version packet, and not + // a data preamble packet of an old T_USB. + if (!(Data[4] == 'V' && + Data[5] == 'e' && + Data[6] == 'r' && + Data[7] == 's')) + { + printf("* Inadequate version of T_USB: no version packet was sent (we need at least %d)\n", + KTusbVersion); + dwRC = USBIO_ERR_FAILED; + return; + } + DWORD tusb_version = *((ULONG*) Data); // first 4 bytes + if (tusb_version < KTusbVersion) + { + printf("* Inadequate version of T_USB: %d (we need at least %d)\n", + tusb_version, KTusbVersion); + dwRC = USBIO_ERR_FAILED; + return; + } + printf("* Suitable version of T_USB found: %d.\n", tusb_version); + } + + +static void SendVersion() + { + // Here we send an 8 byte packet containing USBRFLCT's + USBIO's versions. + printf("* Sending our version packet to T_USB..."); + + DWORD bytes_written = 0; + g_Buf.NumberOfBytesToTransfer = KPreambleLength; + Data[0] = VERSION_MAJOR; + Data[1] = VERSION_MINOR; + Data[2] = VERSION_MICRO; + Data[3] = USBIO_VERSION_MAJOR; + Data[4] = USBIO_VERSION_MINOR; + g_BulkOutPipe.Write(&g_Buf); + dwRC = g_BulkOutPipe.WaitForCompletion(&g_Buf, INFINITE); + printf(" done.\n"); + bytes_written = g_Buf.BytesTransferred; + if (dwRC == USBIO_ERR_SUCCESS) + { + if (bytes_written < KPreambleLength) + { + printf("* Wrote less bytes (%d) than requested (%d).\n", + bytes_written, KPreambleLength); + dwRC = USBIO_ERR_FAILED; + } + } + else + { + printf("\n* Error: CUsbIoPipe::Write (version) returned <0x%X>\n", dwRC); + } + } + + +static void ExchangeVersions() + { + SendVersion(); + if (dwRC != USBIO_ERR_SUCCESS) + return; + ReceiveVersion(); + } + + +static void GetLength() + { + // The first two bytes are interpreted as a length value. + DWORD bytes_read = KPreambleLength; + g_Buf.NumberOfBytesToTransfer = KPreambleLength; + + g_BulkInPipe.Read(&g_Buf); + dwRC = g_BulkInPipe.WaitForCompletion(&g_Buf, INFINITE); + bytes_read = g_Buf.BytesTransferred; + + if (dwRC == USBIO_ERR_SUCCESS) + { + if (bytes_read < KPreambleLength) + { + printf("* Read less bytes (%d) than expected (%d).\n", + bytes_read, KPreambleLength); + dwRC = USBIO_ERR_FAILED; + return; + } + } + else + { + printf("\n* Error: CUsbIoPipe::Read (length) returned <0x%X>\n", dwRC); + return; + } + Length = *((ULONG*) Data); // first 4 bytes + if (Length > KBufferSize) + { + printf("* This is too much: %d (our buffer is too small: %d)\n", + Length, KBufferSize); + dwRC = USBIO_ERR_FAILED; + } + if (VerboseMode) + { + printf("* Just read %d bytes, now assuming transfer length is %d bytes.\n", + bytes_read, Length); + } + else if (TransferMode == EReceiveOnly || TransferMode == ETransmitOnly) + { + printf("* Single transfer size: %d bytes.\n", Length); + } + } + + +static void ReadData() + { + // We have to setup a read for at least one byte in order to get + // the host to issue IN tokens for our zero-byte read: + if (Length == 0) + g_Buf.NumberOfBytesToTransfer = 1; + else + g_Buf.NumberOfBytesToTransfer = Length; + + g_BulkInPipe.Read(&g_Buf); + dwRC = g_BulkInPipe.WaitForCompletion(&g_Buf, INFINITE); + DWORD bytes_read = g_Buf.BytesTransferred; + + if (dwRC != USBIO_ERR_SUCCESS) + { + printf("\n* Error: CUsbIoPipe::Read (data) returned <0x%X>\n", dwRC); + } + else + { + if (bytes_read != Length) + { + printf("* Read more/less bytes (%d) than expected (%d).\n", + bytes_read, Length); + dwRC = USBIO_ERR_FAILED; + } + else + { + PRINT_IF_VERBOSE1("* Read %d bytes.\n", Length); + } + } + } + + +static void WriteData() + { + DWORD bytes_written = Length; + + g_Buf.NumberOfBytesToTransfer = bytes_written; + + g_BulkOutPipe.Write(&g_Buf); + dwRC = g_BulkOutPipe.WaitForCompletion(&g_Buf, INFINITE); + if (ZlpMode && (Length >= maxOutPacketSize) && ((Length % maxOutPacketSize) == 0)) + { + // writes a zero length packet + g_BulkOutPipe.Write(&g_ZlpBuf); + dwRC = g_BulkOutPipe.WaitForCompletion(&g_ZlpBuf, INFINITE); + } + + + bytes_written = g_Buf.BytesTransferred; + + if (dwRC == USBIO_ERR_SUCCESS) + { + PRINT_IF_VERBOSE1("* Wrote %d bytes.\n", bytes_written); + } + else + { + printf("\n* Error: CUsbIoPipe::Write returned <0x%X>\n", dwRC); + } + } + + +void PrintStats() + { + static DWORD loop = 0; // the loop counter + static double xfer_size = 0; // the total transfer amount so far + time_t t_1 = time(NULL); // current time + double t_diff = difftime(t_1, T_0); // this yields current seconds since start + xfer_size += (KPreambleLength + (2 * Length)) * KLoopModeDisplayUpdate; // + double xfer_rate = xfer_size / t_diff; // mean transfer rate since start + loop += KLoopModeDisplayUpdate; + printf("* Iter: %d (%d bytes) Total: %.0f bytes Rate: %.0f bytes/s \r", + loop, Length, xfer_size, xfer_rate); + } + + +void PrintStatsEveryLoop() + { + static DWORD loop = 0; // the loop counter + static double xfer_size = 0; // the total transfer amount so far + time_t t_1 = time(NULL); // current time + double t_diff = difftime(t_1, T_0); // this yields current seconds since start + xfer_size += (KPreambleLength + (2 * Length)); // + double xfer_rate = xfer_size / t_diff; // mean transfer rate since start + printf("* Iter: %d (%d bytes) Total: %.0f bytes Rate: %.0f bytes/s \r", + ++loop, Length, xfer_size, xfer_rate); + } + + +void PrintUnidirStats() + { + static DWORD loop = 0; // the loop counter + static double xfer_size = 0; // the total transfer amount so far + time_t t_1 = time(NULL); // current time + double t_diff = difftime(t_1, T_0); // this yields current seconds since start + xfer_size += Length * KUniModeDisplayUpdate; + double xfer_rate = xfer_size / t_diff; // mean transfer rate since start + loop += KUniModeDisplayUpdate; + printf("* Iter: %d (%d bytes) Total: %.0f bytes Rate: %.0f bytes/s \r", + loop, Length, xfer_size, xfer_rate); + } + + +static void LoopTransfer() + { + printf("* Loop Transfers -- reading & writing alternately.\n"); + + T_0 = time(NULL); // starting time + + while (dwRC == USBIO_ERR_SUCCESS) + { + static DWORD n = 0; + + // First we get the length (+ the packet size) + GetLength(); + + if (dwRC == USBIO_ERR_SUCCESS) + { + // Then we read 'Length' bytes + ReadData(); + } + + if (dwRC == USBIO_ERR_SUCCESS) + { + // Now we send the received data back to the client. + WriteData(); + } + + if (dwRC == USBIO_ERR_SUCCESS) + { + // Finally, sometimes we print some statistics + if (TransferMode == ELoopDebug) + PrintStatsEveryLoop(); + else if ((++n % KLoopModeDisplayUpdate) == 0) + PrintStats(); + } + } + } + + +static void ReceiveOnlyTransfer() + { + printf("* Receive-only transfers (IN).\n"); + + // First (and only once) we get the transfer length (+ the packet size) + GetLength(); + + T_0 = time(NULL); // starting time + + while (dwRC == USBIO_ERR_SUCCESS) + { + static DWORD n = -1; + static DWORD pktNum; + + // Then we read 'Length' bytes + ReadData(); + pktNum = *(DWORD *)&Data; + if (pktNum != ++n) + { + printf ("\n* Error: rcv'd wrong pkt number: 0x%x (expected: 0x%x)\n", pktNum, n); + // reset from the received packet number, so that ... + // if a packet is lost or duplicated a single error is reported + n = pktNum; + } + // Finally, sometimes we print some statistics + if ((n % KUniModeDisplayUpdate) == 0) + PrintUnidirStats(); + } + } + + +static void TransmitOnlyTransfer() + { + printf("* Transmit-only transfers (OUT).\n"); + + // First (and only once) we get the transfer length (+ the packet size) + GetLength(); + + T_0 = time(NULL); // starting time + + while (dwRC == USBIO_ERR_SUCCESS) + { + static DWORD n = 0; + // First the packet number is put into the first four bytes + *(DWORD *)&Data = n++; + // Then we write 'Length' bytes + WriteData(); + + // Finally, sometimes we print some statistics + if ((n % KUniModeDisplayUpdate) == 0) + PrintUnidirStats(); + } + } + + +static void DoTransfers() + { + switch (TransferMode) + { + case ELoop: + case ELoopDebug: + LoopTransfer(); + break; + case EReceiveOnly: + ReceiveOnlyTransfer(); + break; + case ETransmitOnly: + TransmitOnlyTransfer(); + break; + default: + dwRC = -1; + break; + } + } + + +static void Delay(int milliseconds) + { + printf("* Short wait... "); + Sleep(milliseconds); + printf("done.\n"); + } + + +static void PrintHello() + { + printf("*--------------------------------------------------\n"); + printf("* USBRFLCT v%d.%d.%d (for use with USBRFLCT.SYS v%d.%d)\n", + VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO, + USBIO_VERSION_MAJOR, USBIO_VERSION_MINOR); + printf("* USB Reflector Test Program / T_USB Host-side Part\n"); + printf("* Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).\n"); + printf("*--------------------------------------------------\n"); + } + + +int main(int argc, char* argv[]) + { + PrintHello(); + + if (ProcessCmdLine(argc, argv) != 0) + return -1; + + OpenUsbDevice(); + + if (dwRC == USBIO_ERR_SUCCESS) + { + GetDeviceDescriptor(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + GetConfigurationDescriptor(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + GetStringDescriptor(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + SetConfiguration(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + // In order to give the USB device-side program (t_usb) + // enough time after getting configured to carry out + // some device tests, we wait here for a short while + // before proceeding: + Delay(2000); + GetConfigurationInfo(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + OpenPipes(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + ExchangeVersions(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + DoTransfers(); + } + if (dwRC == USBIO_ERR_SUCCESS) + { + ClosePipes(); + } + + CloseUsbDevice(); + + return 0; + } + + +// --eof