Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* ----------------------------------------------------------------
- * ftdi_loopback.c
- *
- * 1/7/2013 D. W. Hawkins ([email protected])
- *
- * FTDI loopback test application.
- *
- * This application transmits data to an FTDI device, receives
- * the response data, and checks the data matches.
- *
- * The application uses two threads; a writer thread and a
- * reader thread. This allows data transmission and reception
- * to occur in parallel.
- *
- * The application was written to test FTDI UM245R and UM232H
- * modules connected to BeMicro and BeMicro-SDK FPGA kits,
- * with the FTDI FIFO interface looped back internal to the
- * FPGA. The FPGA design also included a logic analyzer
- * (SignalTap II), allowing the capture of FIFO interface
- * waveform timing.
- *
- * ----------------------------------------------------------------
- * Examples
- * --------
- *
- * 1. BeMicro-SDK + UM245R module
- *
- * ./ftdi_loopback -i -l 0x100000 1MB
- * ./ftdi_loopback -i -l 0x1000000 16MB
- * ./ftdi_loopback -i -l 0x10000000 256MB
- *
- * All passed.
- *
- * 2. BeMicro-SDK + UM232H module
- *
- * The same set of tests passed fine.
- *
- * The results of (1) and (2) indicate that the wiring
- * between the BeMicro-SDK and the FTDI modules is fine
- * (no issues with transmission line reflections).
- *
- * ----------------------------------------------------------------
- * Notes
- * -----
- *
- * 1. The FTDI code was derived from max2pci_loopback.c. The MAX II
- * PCI kit has an FT245B device on the board.
- *
- * See max2pci_loopback.c for the modifications required to run
- * this application under Linux (it was developed under WinXP).
- *
- * 2. The serial loopback threading code was derived from the
- * COBRA driver program serial_loopback_test.c
- *
- * The main application thread creates a buffer of data to send,
- * and passes a buffer pointer off to the write thread. The
- * writer thread transmits the buffer. The reader thread reads
- * the response bytes, checks them, waits for the writer thread,
- * and then exits the application.
- *
- * ----------------------------------------------------------------
- */
- /* ----------------------------------------------------------------
- * Includes
- * ----------------------------------------------------------------
- */
- /* Standard C includes */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- /* Threading */
- #include <pthread.h>
- /* Windows types used by the FTDI D2XX direct access API */
- #ifdef __linux__
- #include "WinTypes.h"
- #else
- #include <windows.h>
- #endif
- /* FTDI D2XX direct access API */
- #include "ftd2xx.h"
- /* ----------------------------------------------------------------
- * Local data types
- * ----------------------------------------------------------------
- */
- /* Parameters passed from the main thread to the writer thread */
- typedef struct writer_arg {
- FT_HANDLE handle;
- BYTE *buffer;
- int length;
- } writer_arg_t;
- /* ----------------------------------------------------------------
- * Local function declarations
- * ----------------------------------------------------------------
- */
- static void show_usage(void);
- static void *writer_thread(void *arg);
- /* ----------------------------------------------------------------
- * Main application
- * ----------------------------------------------------------------
- */
- int
- main(
- int argc,
- char **argv)
- {
- int opt;
- int option_index = 0;
- static struct option long_options[] = {
- /* Long options */
- /* Long and short options */
- /* (name, has_arg, flag, val) */
- {"desc", 1, 0, 'd'},
- {"help", 0, 0, 'h'},
- {"invert", 0, 0, 'i'},
- {"length", 1, 0, 'l'},
- {"sync", 0, 0, 's'},
- {0, 0, 0, 0}
- };
- FT_STATUS ftStatus;
- FT_HANDLE ftHandle;
- DWORD i;
- DWORD nDevices;
- DWORD bytesToRead, bytesRead, totalBytesRead;
- BYTE *readBuffer;
- BYTE *writeBuffer;
- DWORD Flags;
- DWORD ID;
- DWORD Type;
- DWORD LocId;
- char SerialNumber[16];
- char Description[64];
- int device_detected = 0;
- int device_index = 0;
- int status;
- int length = -1;
- int invert = 0;
- char *desc = NULL;
- char descDefault[] = "UM245R";
- int sync_mode = 0;
- pthread_t writer_id;
- writer_arg_t arg;
- while ((opt = getopt_long(
- argc, argv, "d:hil:s", long_options, &option_index)) != -1) {
- switch (opt) {
- /* Long options */
- case 'd':
- desc = optarg;
- break;
- case 'h':
- show_usage();
- return 0;
- case 'i':
- invert = 1;
- break;
- case 'l':
- /* Extract the buffer size */
- if ( (optarg[0] == '0') &&
- ((optarg[1] == 'x') || (optarg[1] = 'X')) ) {
- /* scan hex */
- status = sscanf(optarg, "%x", &length);
- } else {
- /* scan decimal */
- status = sscanf(optarg, "%d", &length);
- }
- if (status < 0) {
- printf("Error: invalid length argument\n");
- return -1;
- }
- break;
- case 's':
- sync_mode = 1;
- break;
- default:
- show_usage();
- return 0;
- }
- }
- printf("\n");
- printf("FTDI device loopback test\n");
- printf("-------------------------\n");
- if (length < 0) {
- printf("\nPlease provide a length argument.\n");
- return 0;
- }
- if (desc == NULL) {
- desc = descDefault;
- }
- /* ------------------------------------------------------------
- * Buffers
- * ------------------------------------------------------------
- */
- readBuffer = (BYTE *)malloc(length);
- if (readBuffer == NULL) {
- printf("Error: read buffer allocation failed!\n");
- return -1;
- }
- memset(readBuffer,0, length);
- writeBuffer = (BYTE *)malloc(length);
- if (writeBuffer == NULL) {
- printf("Error: write buffer allocation failed!\n");
- return -1;
- }
- memset(writeBuffer,0, length);
- /* ------------------------------------------------------------
- * Find the device
- * ------------------------------------------------------------
- *
- * Device details (determined using FT_PROG v2.4.2):
- * Chip Type: 'FT245R'
- * Vendor ID: 0x0403
- * Product ID: 0x6001
- * Manufacturer: FTDI
- * Description: 'UM245R'
- * Serial Number: 'FTG6LJTG'
- *
- * Detect the device based on the description string.
- */
- /* Get the number of devices */
- nDevices = 0;
- ftStatus = FT_CreateDeviceInfoList(&nDevices);
- if (ftStatus != FT_OK) {
- printf("Error: FT_CreateDeviceInfoList returned %d\n",
- (int)ftStatus);
- return 1;
- }
- if (nDevices == 0) {
- printf("Error: the %s device was not detected\n", desc);
- return -1;
- }
- /* Match the description string */
- device_detected = 0;
- for (i = 0; i < nDevices; i++) {
- ftStatus = FT_GetDeviceInfoDetail(
- i, &Flags, &Type, &ID, &LocId,
- SerialNumber, Description,
- &ftHandle);
- if (ftStatus != FT_OK) {
- printf("Error: FT_GetDeviceInfoDetail returned %d\n",
- (int)ftStatus);
- return 1;
- }
- if (strncmp(Description, desc, strlen(desc)) == 0) {
- device_detected = 1;
- device_index = i;
- }
- }
- if (device_detected == 0) {
- printf("Error: the %s device was not detected\n", desc);
- return 1;
- } else {
- printf(" * %s device detected at device index %d\n", desc, device_index);
- }
- /* ------------------------------------------------------------
- * Open the device
- * ------------------------------------------------------------
- */
- ftStatus = FT_Open(
- device_index,
- &ftHandle);
- if (ftStatus != FT_OK) {
- printf("Error: FT_Open returned %d\n", (int)ftStatus);
- return 1;
- }
- /* ------------------------------------------------------------
- * Configure the device
- * ------------------------------------------------------------
- *
- * PROBLEM:
- * --------
- *
- * If the device is configured in SYNC mode, then it appears
- * to stay in SYNC mode. If sync_mode is not set, then I want
- * to put the device in ASYNC mode ... but there is no
- * BITMODE setting for asynchronous FIFO mode!
- *
- * Read the FTDI App notes and see what they do.
- */
- /* This does not seem to do anything */
- /*
- printf(" * Reset the device\n");
- ftStatus = FT_ResetDevice(ftHandle);
- if (ftStatus != FT_OK) {
- printf("Error: FT_ResetDevice returned %d\n", (int)ftStatus);
- return 1;
- }
- usleep(10000);
- */
- /* This seems to reset the device properly on a sync->async change
- * But it does hang sometimes - even with a delay
- */
- /*
- printf(" * Reset the port\n");
- ftStatus = FT_ResetPort(ftHandle);
- if (ftStatus != FT_OK) {
- printf("Error: FT_ResetPort returned %d\n", (int)ftStatus);
- return 1;
- }
- usleep(10000);
- */
- /* Use synchronous mode */
- if (sync_mode == 1) {
- /* Per AN130 sequence
- * Mask = 0xFF = outputs -> 0 = inputs should be ok.
- * Mode = 0x00 = reset mode
- * = 0x40 = synchronous mode
- */
- ftStatus = FT_SetBitMode(ftHandle, 0, FT_BITMODE_RESET);
- if (ftStatus != FT_OK) {
- printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus);
- return 1;
- }
- /* 10ms sleep */
- usleep(10000);
- ftStatus = FT_SetBitMode(ftHandle, 0, FT_BITMODE_SYNC_FIFO);
- if (ftStatus != FT_OK) {
- printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus);
- return 1;
- }
- }
- /* Set flow control per AN130 - apparantly this stops the
- * driver from dropping data.
- */
- ftStatus = FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0, 0);
- if (ftStatus != FT_OK) {
- printf("Error: FT_SetFlowControl returned %d\n", (int)ftStatus);
- return 1;
- }
- /* ------------------------------------------------------------
- * Fill the write buffer
- * ------------------------------------------------------------
- */
- for (i = 0; i < length; i++) {
- writeBuffer[i] = i;
- }
- /* ------------------------------------------------------------
- * Create the writer thread
- * ------------------------------------------------------------
- */
- arg.handle = ftHandle;
- arg.buffer = writeBuffer;
- arg.length = length;
- status = pthread_create(
- &writer_id, NULL, writer_thread, &arg);
- if (status != 0) {
- printf("Error: Thread creation failed\n");
- return 1;
- }
- /* ------------------------------------------------------------
- * Read the bytes and check them
- * ------------------------------------------------------------
- */
- printf("READER_THREAD: poll for the response bytes\n");
- totalBytesRead = 0;
- status = 0;
- while ((totalBytesRead != length) & (status < 100)) {
- /* Number of bytes ready */
- ftStatus = FT_GetQueueStatus(
- ftHandle,
- &bytesToRead);
- if (ftStatus != FT_OK) {
- printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus);
- return 1;
- }
- printf("READER_THREAD: bytesToRead = %d\n", (int)bytesToRead);
- if (bytesToRead > 0) {
- status = 0;
- ftStatus = FT_Read(
- ftHandle,
- &readBuffer[totalBytesRead],
- (int)bytesToRead,
- &bytesRead);
- if (ftStatus != FT_OK) {
- printf("Error: FT_Read returned %d\n", (int)ftStatus);
- return 1;
- }
- totalBytesRead += bytesRead;
- printf("READER_THREAD: %d-bytes received (%.2f-percent)\n", (int)bytesRead,
- (double)totalBytesRead/(double)length*100.0);
- } else {
- /* Give up after 100 tries */
- status++;
- /* 10ms delay when bytesToRead = 0 */
- usleep(10000);
- }
- }
- if (status != 0) {
- printf("Error: bytesToRead was zero for too many iterations!\n");
- exit(1);
- }
- printf("READER_THREAD: check the response bytes\n");
- status = 0;
- for (i = 0; i < length; i++) {
- if (invert == 0) {
- if (readBuffer[i] != writeBuffer[i]) {
- printf(" - Error: data error at index %d (read %X, expected %X)\n",
- (int)i, (int)readBuffer[i], writeBuffer[i]);
- status = -1;
- }
- } else {
- /* Check for inverted data
- *
- * The loopback test can invert the bits in hardware so that
- * the SignalTap II traces show when the FPGA drives the
- * external data bus.
- */
- if (readBuffer[i] != (~writeBuffer[i] & 0xFF)) {
- printf(" - Error: data error at index %d (read %X, expected %X)\n",
- (int)i, (int)readBuffer[i], (int)(~writeBuffer[i] & 0xFF));
- status = -1;
- }
- }
- }
- if (status == 0) {
- printf("READER_THREAD: The bytes received match the expected values.\n\n");
- }
- printf("READER_THREAD: %d-bytes (%.2fMB) transferred.\n\n", length, (double)length/(1024.0*1024.0));
- /* ------------------------------------------------------------
- * Wait for the writer thread
- * ------------------------------------------------------------
- */
- printf("READER_THREAD: Wait for the writer thread\n");
- status = pthread_join(writer_id, NULL);
- if (status != 0) {
- printf("join failed - %s\n", strerror(status));
- return -1;
- }
- /* Resource cleanup */
- FT_Close(ftHandle);
- free(readBuffer);
- free(writeBuffer);
- return 0;
- }
- /* ================================================================
- * Local function definitions
- * ================================================================
- */
- /* ----------------------------------------------------------------
- * Usage
- * ----------------------------------------------------------------
- */
- static void show_usage(void)
- {
- printf(
- "\n"\
- "FTDI device loopback test\n"\
- "-------------------------\n\n"\
- "Usage: ftdi_loopback [options]\n\n"\
- "Options:\n"\
- " -l | --length Length (number of bytes to transfer)\n"\
- " -h | --help Help (this message)\n"\
- "\n"
- );
- }
- /* ----------------------------------------------------------------
- * Writer thread
- * ----------------------------------------------------------------
- */
- static void *writer_thread(void *arg)
- {
- writer_arg_t *args = (writer_arg_t *)arg;
- FT_HANDLE ftHandle = args->handle;
- BYTE *writeBuffer = args->buffer;
- int length = args->length;
- FT_STATUS ftStatus;
- DWORD bytesWritten, totalBytesWritten, bytesRemaining, bytesToWrite;
- /* ------------------------------------------------------------
- * Write a sequence of bytes and read it back
- * ------------------------------------------------------------
- */
- totalBytesWritten = 0;
- bytesRemaining = length;
- while (bytesRemaining > 0) {
- /* Send the buffer in 64kB blocks */
- if (bytesRemaining > 64*1024) {
- bytesToWrite = 64*1024;
- } else {
- bytesToWrite = bytesRemaining;
- }
- printf("WRITER_THREAD: write %d-bytes\n", (int)bytesToWrite);
- ftStatus = FT_Write(
- ftHandle,
- &writeBuffer[totalBytesWritten],
- bytesToWrite,
- &bytesWritten);
- if (ftStatus != FT_OK) {
- printf("Error: FT_Write returned %d\n", (int)ftStatus);
- return NULL;
- }
- printf("WRITER_THREAD: %d-bytes written\n", (int)bytesWritten);
- totalBytesWritten += bytesWritten;
- bytesRemaining -= bytesWritten;
- /* A delay was necessary to give the reader thread a chance to run */
- usleep(1000);
- }
- return NULL;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement