// Read bytes asynchronously from the specified channel (1 <= count <= 0x10000). // DLLEXPORT(FLStatus) flReadChannelAsyncSubmit( struct FLContext *handle, uint8 chan, uint32 count, uint8 *buffer, const char **error) { FLStatus retVal = FL_SUCCESS, fStatus; uint8 command[3]; USBStatus uStatus; size_t queueDepth; const uint16 count16 = (count == 0x10000) ? 0x0000 : (uint16)count; CHECK_STATUS( !handle->isCommCapable, FL_PROTOCOL_ERR, cleanup, "flReadChannelAsyncSubmit(): This device does not support CommFPGA"); CHECK_STATUS( count == 0, FL_PROTOCOL_ERR, cleanup, "flReadChannelAsyncSubmit(): Zero-length reads are illegal!"); CHECK_STATUS( count > 0x10000, FL_PROTOCOL_ERR, cleanup, "flReadChannelAsyncSubmit(): Transfer length exceeds 0x10000"); // Write command command[0] = chan | 0x80; flWriteWord(count16, command+1); fStatus = bufferAppend(handle, command, 3, error); CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannelAsyncSubmit()"); // Flush outstanding async writes fStatus = flFlushAsyncWrites(handle, error); CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannelAsyncSubmit()"); // Maybe do a few awaits, to keep things balanced queueDepth = usbNumOutstandingRequests(handle->device); while ( queueDepth > 2 && !handle->completionReport.flags.isRead ) { uStatus = usbBulkAwaitCompletion( handle->device, &handle->completionReport, error ); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "flReadChannelAsyncSubmit()"); queueDepth--; } // Then request the data uStatus = usbBulkReadAsync( handle->device, handle->commInEP, // endpoint to read buffer, // pointer to buffer, or null count, // number of data bytes 5000, // max timeout: 49 days error ); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "flReadChannelAsyncSubmit()"); cleanup: return retVal; }
// Disconnect and cleanup, if necessary. // DLLEXPORT(void) flClose(struct FLContext *handle) { if ( handle ) { USBStatus uStatus; struct CompletionReport completionReport; FLStatus fStatus = flFlushAsyncWrites(handle, NULL); size_t queueDepth = usbNumOutstandingRequests(handle->device); while ( queueDepth-- ) { uStatus = usbBulkAwaitCompletion(handle->device, &completionReport, NULL); } usbCloseDevice(handle->device, 0); free((void*)handle); (void)fStatus; (void)uStatus; } }
// Await a previously-submitted async read. // DLLEXPORT(FLStatus) flReadChannelAsyncAwait( struct FLContext *handle, const uint8 **data, uint32 *requestLength, uint32 *actualLength, const char **error) { FLStatus retVal = FL_SUCCESS; USBStatus uStatus; while ( !handle->completionReport.flags.isRead ) { uStatus = usbBulkAwaitCompletion( handle->device, &handle->completionReport, error ); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "flReadChannelAsyncAwait()"); } *data = handle->completionReport.buffer; *requestLength = handle->completionReport.requestLength; *actualLength = handle->completionReport.actualLength; memset(&handle->completionReport, 0, sizeof(struct CompletionReport)); cleanup: return retVal; }
DLLEXPORT(FLStatus) flAwaitAsyncWrites(struct FLContext *handle, const char **error) { FLStatus retVal = FL_SUCCESS, fStatus; USBStatus uStatus; size_t queueDepth; fStatus = flFlushAsyncWrites(handle, error); CHECK_STATUS(fStatus, fStatus, cleanup, "flAwaitAsyncWrites()"); queueDepth = usbNumOutstandingRequests(handle->device); while ( queueDepth && !handle->completionReport.flags.isRead ) { uStatus = usbBulkAwaitCompletion( handle->device, &handle->completionReport, error ); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "flAwaitAsyncWrites()"); queueDepth--; } CHECK_STATUS( queueDepth, FL_BAD_STATE, cleanup, "flAwaitAsyncWrites(): An asynchronous read is in flight"); cleanup: return retVal; }
static FLStatus bufferAppend( struct FLContext *handle, const uint8 *data, size_t count, const char **error) { FLStatus retVal = FL_SUCCESS; size_t spaceAvailable; size_t queueDepth = usbNumOutstandingRequests(handle->device); USBStatus uStatus; if ( !handle->writePtr ) { // There is not an active write buffer uStatus = usbBulkWriteAsyncPrepare(handle->device, &handle->writePtr, error); CHECK_STATUS(uStatus, FL_ALLOC_ERR, cleanup, "bufferAppend()"); handle->writeBuf = handle->writePtr; } spaceAvailable = handle->chunkSize - (size_t)(handle->writePtr - handle->writeBuf); while ( count > spaceAvailable ) { // Reduce the depth of the work queue a little while ( queueDepth > 2 && !handle->completionReport.flags.isRead ) { uStatus = usbBulkAwaitCompletion( handle->device, &handle->completionReport, error); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "bufferAppend()"); queueDepth--; } // Fill up this buffer memcpy(handle->writePtr, data, spaceAvailable); data += spaceAvailable; count -= spaceAvailable; // Submit it uStatus = usbBulkWriteAsyncSubmit( handle->device, handle->commOutEP, handle->chunkSize, U32MAX, error); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "bufferAppend()"); queueDepth++; // Get a new buffer uStatus = usbBulkWriteAsyncPrepare(handle->device, &handle->writePtr, error); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "bufferAppend()"); handle->writeBuf = handle->writePtr; spaceAvailable = handle->chunkSize; } if ( count == spaceAvailable ) { // Reduce the depth of the work queue a little while ( queueDepth > 2 && !handle->completionReport.flags.isRead ) { uStatus = usbBulkAwaitCompletion( handle->device, &handle->completionReport, error); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "bufferAppend()"); queueDepth--; } // Fill up this buffer memcpy(handle->writePtr, data, spaceAvailable); data += spaceAvailable; count -= spaceAvailable; // Submit it uStatus = usbBulkWriteAsyncSubmit( handle->device, handle->commOutEP, handle->chunkSize, U32MAX, error); CHECK_STATUS(uStatus, FL_USB_ERR, cleanup, "bufferAppend()"); queueDepth++; // Zero the pointers handle->writeBuf = handle->writePtr = NULL; } else { // Count is less than spaceAvailable memcpy(handle->writePtr, data, count); handle->writePtr += count; } cleanup: return retVal; }
int bufferRead(void) { int retVal = 0; USBStatus uStatus; struct USBDevice *deviceHandle = NULL; const char *error = NULL; uint8 *ptr; const uint8 *buf; struct CompletionReport completionReport; // Init library uStatus = usbInitialise(0, &error); CHECK_STATUS(uStatus, 1, cleanup); // Open device uStatus = usbOpenDevice("1d50:602b", 1, 0, 0, &deviceHandle, &error); CHECK_STATUS(uStatus, 2, cleanup); // Select CommFPGA conduit (FX2 slave FIFOs = 0x0001) uStatus = usbControlWrite(deviceHandle, 0x80, 0x0000, 0x0001, NULL, 0, 1000, &error); CHECK_STATUS(uStatus, 3, cleanup); // Get the next available 64KiB write buffer uStatus = usbBulkWriteAsyncPrepare(deviceHandle, &ptr, &error); // Write request command CHECK_STATUS(uStatus, 4, cleanup); buf = ptr; // Populate the buffer with a couple of FPGA write commands and one FPGA read command *ptr++ = 0x00; // write ch0 *ptr++ = (uint8)(CHUNK_SIZE >> 24); *ptr++ = (uint8)(CHUNK_SIZE >> 16); *ptr++ = (uint8)(CHUNK_SIZE >> 8); *ptr++ = (uint8)(CHUNK_SIZE & 0xFF); memcpy(ptr, randomData, CHUNK_SIZE); ptr += CHUNK_SIZE; *ptr++ = 0x00; // write ch0 *ptr++ = (uint8)(CHUNK_SIZE >> 24); *ptr++ = (uint8)(CHUNK_SIZE >> 16); *ptr++ = (uint8)(CHUNK_SIZE >> 8); *ptr++ = (uint8)(CHUNK_SIZE & 0xFF); memcpy(ptr, randomData+CHUNK_SIZE, CHUNK_SIZE); ptr += CHUNK_SIZE; *ptr++ = 0x80; // read ch0 *ptr++ = (uint8)(CHUNK_SIZE >> 24); *ptr++ = (uint8)(CHUNK_SIZE >> 16); *ptr++ = (uint8)(CHUNK_SIZE >> 8); *ptr++ = (uint8)(CHUNK_SIZE & 0xFF); // Submit the write uStatus = usbBulkWriteAsyncSubmit(deviceHandle, 2, (uint32)(ptr-buf), 1000, &error); CHECK_STATUS(uStatus, 5, cleanup); // Submit the read uStatus = usbBulkReadAsync(deviceHandle, 6, NULL, CHUNK_SIZE, 9000, &error); // Read response data CHECK_STATUS(uStatus, 6, cleanup); // Wait for them to be serviced uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 7, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 8, cleanup); printCompletionReport(&completionReport); cleanup: usbCloseDevice(deviceHandle, 0); if ( error ) { fprintf(stderr, "%s\n", error); usbFreeError(error); } return retVal; }
int multiRead(uint32 reqCount, uint32 reqSize, double *speed) { int retVal = 0; USBStatus uStatus; struct USBDevice *deviceHandle = NULL; const char *error = NULL; uint8 buf[5]; struct CompletionReport completionReport; uint32 numBytes; double totalTime; #ifdef WIN32 LARGE_INTEGER tvStart, tvEnd, freq; DWORD_PTR mask = 1; SetThreadAffinityMask(GetCurrentThread(), mask); QueryPerformanceFrequency(&freq); #else struct timeval tvStart, tvEnd; long long startTime, endTime; #endif // We can make one FPGA request message and re-use it buf[0] = 0x80; // write ch0 buf[1] = (uint8)(reqSize >> 24); buf[2] = (uint8)(reqSize >> 16); buf[3] = (uint8)(reqSize >> 8); buf[4] = (uint8)(reqSize & 0xFF); // Init library uStatus = usbInitialise(0, &error); CHECK_STATUS(uStatus, 1, cleanup); // Open device uStatus = usbOpenDevice("1d50:602b", 1, 0, 0, &deviceHandle, &error); CHECK_STATUS(uStatus, 2, cleanup); // Select CommFPGA conduit (FX2 slave FIFOs = 0x0001) uStatus = usbControlWrite(deviceHandle, 0x80, 0x0000, 0x0001, NULL, 0, 1000, &error); CHECK_STATUS(uStatus, 3, cleanup); // Record start time #ifdef WIN32 QueryPerformanceCounter(&tvStart); #else gettimeofday(&tvStart, NULL); #endif // Send a couple of read commands to the FPGA uStatus = usbBulkWriteAsync(deviceHandle, 2, buf, 5, 9000, &error); // Write request command CHECK_STATUS(uStatus, 4, cleanup); uStatus = usbBulkReadAsync(deviceHandle, 6, NULL, reqSize, 9000, &error); // Read response data CHECK_STATUS(uStatus, 5, cleanup); uStatus = usbBulkWriteAsync(deviceHandle, 2, buf, 5, 9000, &error); // Write request command CHECK_STATUS(uStatus, 6, cleanup); uStatus = usbBulkReadAsync(deviceHandle, 6, NULL, reqSize, 9000, &error); // Read response data CHECK_STATUS(uStatus, 7, cleanup); // On each iteration, await completion and send a new read command numBytes = (reqCount+2)*reqSize; while ( reqCount-- ) { uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 8, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 9, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkWriteAsync(deviceHandle, 2, buf, 5, 9000, &error); // Write request command CHECK_STATUS(uStatus, 10, cleanup); uStatus = usbBulkReadAsync(deviceHandle, 6, NULL, reqSize, 9000, &error); // Read response data CHECK_STATUS(uStatus, 11, cleanup); } // Wait for the stragglers... uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 12, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 13, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 14, cleanup); printCompletionReport(&completionReport); uStatus = usbBulkAwaitCompletion(deviceHandle, &completionReport, &error); CHECK_STATUS(uStatus, 15, cleanup); printCompletionReport(&completionReport); // Record stop time #ifdef WIN32 QueryPerformanceCounter(&tvEnd); totalTime = (double)(tvEnd.QuadPart - tvStart.QuadPart); totalTime /= freq.QuadPart; *speed = (double)numBytes / (1024*1024*totalTime); #else gettimeofday(&tvEnd, NULL); startTime = tvStart.tv_sec; startTime *= 1000000; startTime += tvStart.tv_usec; endTime = tvEnd.tv_sec; endTime *= 1000000; endTime += tvEnd.tv_usec; totalTime = (double)(endTime - startTime); totalTime /= 1000000; // convert from uS to S. *speed = (double)numBytes / (1024*1024*totalTime); #endif cleanup: usbCloseDevice(deviceHandle, 0); if ( error ) { fprintf(stderr, "%s\n", error); usbFreeError(error); } return retVal; }