Advertisement
Guest User

Untitled

a guest
Aug 28th, 2014
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.74 KB | None | 0 0
  1. /* ----------------------------------------------------------------
  2.  * ftdi_loopback.c
  3.  *
  4.  * 1/7/2013 D. W. Hawkins ([email protected])
  5.  *
  6.  * FTDI loopback test application.
  7.  *
  8.  * This application transmits data to an FTDI device, receives
  9.  * the response data, and checks the data matches.
  10.  *
  11.  * The application uses two threads; a writer thread and a
  12.  * reader thread. This allows data transmission and reception
  13.  * to occur in parallel.
  14.  *
  15.  * The application was written to test FTDI UM245R and UM232H
  16.  * modules connected to BeMicro and BeMicro-SDK FPGA kits,
  17.  * with the FTDI FIFO interface looped back internal to the
  18.  * FPGA. The FPGA design also included a logic analyzer
  19.  * (SignalTap II), allowing the capture of FIFO interface
  20.  * waveform timing.
  21.  *
  22.  * ----------------------------------------------------------------
  23.  * Examples
  24.  * --------
  25.  *
  26.  * 1. BeMicro-SDK + UM245R module
  27.  *
  28.  *    ./ftdi_loopback -i -l 0x100000        1MB
  29.  *    ./ftdi_loopback -i -l 0x1000000      16MB
  30.  *    ./ftdi_loopback -i -l 0x10000000    256MB
  31.  *
  32.  *    All passed.
  33.  *
  34.  * 2. BeMicro-SDK + UM232H module
  35.  *
  36.  *    The same set of tests passed fine.
  37.  *
  38.  *    The results of (1) and (2) indicate that the wiring
  39.  *    between the BeMicro-SDK and the FTDI modules is fine
  40.  *    (no issues with transmission line reflections).
  41.  *
  42.  * ----------------------------------------------------------------
  43.  * Notes
  44.  * -----
  45.  *
  46.  * 1. The FTDI code was derived from max2pci_loopback.c. The MAX II
  47.  *    PCI kit has an FT245B device on the board.
  48.  *
  49.  *    See max2pci_loopback.c for the modifications required to run
  50.  *    this application under Linux (it was developed under WinXP).
  51.  *
  52.  * 2. The serial loopback threading code was derived from the
  53.  *    COBRA driver program serial_loopback_test.c
  54.  *
  55.  *    The main application thread creates a buffer of data to send,
  56.  *    and passes a buffer pointer off to the write thread. The
  57.  *    writer thread transmits the buffer. The reader thread reads
  58.  *    the response bytes, checks them, waits for the writer thread,
  59.  *    and then exits the application.
  60.  *
  61.  * ----------------------------------------------------------------
  62.  */
  63.  
  64. /* ----------------------------------------------------------------
  65.  * Includes
  66.  * ----------------------------------------------------------------
  67.  */
  68. /* Standard C includes */
  69. #include <sys/types.h>
  70. #include <sys/stat.h>
  71. #include <fcntl.h>
  72. #include <stdio.h>
  73. #include <unistd.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include <getopt.h>
  77.  
  78. /* Threading */
  79. #include <pthread.h>
  80.  
  81. /* Windows types used by the FTDI D2XX direct access API */
  82. #ifdef __linux__
  83. #include "WinTypes.h"
  84. #else
  85. #include <windows.h>
  86. #endif
  87.  
  88. /* FTDI D2XX direct access API */
  89. #include "ftd2xx.h"
  90.  
  91. /* ----------------------------------------------------------------
  92.  * Local data types
  93.  * ----------------------------------------------------------------
  94.  */
  95.  
  96. /* Parameters passed from the main thread to the writer thread */
  97. typedef struct writer_arg {
  98.     FT_HANDLE handle;
  99.     BYTE *buffer;
  100.     int length;
  101. } writer_arg_t;
  102.  
  103. /* ----------------------------------------------------------------
  104.  * Local function declarations
  105.  * ----------------------------------------------------------------
  106.  */
  107. static void show_usage(void);
  108. static void *writer_thread(void *arg);
  109.  
  110. /* ----------------------------------------------------------------
  111.  * Main application
  112.  * ----------------------------------------------------------------
  113.  */
  114. int
  115. main(
  116.     int argc,
  117.     char **argv)
  118. {
  119.     int opt;
  120.     int option_index = 0;
  121.     static struct option long_options[] = {
  122.         /* Long options */
  123.  
  124.         /* Long and short options     */
  125.         /* (name, has_arg, flag, val) */
  126.         {"desc",    1, 0, 'd'},
  127.         {"help",    0, 0, 'h'},
  128.         {"invert",  0, 0, 'i'},
  129.         {"length",  1, 0, 'l'},
  130.         {"sync",    0, 0, 's'},
  131.         {0, 0, 0, 0}
  132.     };
  133.  
  134.     FT_STATUS ftStatus;
  135.     FT_HANDLE ftHandle;
  136.     DWORD i;
  137.     DWORD nDevices;
  138.     DWORD bytesToRead, bytesRead, totalBytesRead;
  139.     BYTE *readBuffer;
  140.     BYTE *writeBuffer;
  141.     DWORD Flags;
  142.     DWORD ID;
  143.     DWORD Type;
  144.     DWORD LocId;
  145.     char SerialNumber[16];
  146.     char Description[64];
  147.     int device_detected = 0;
  148.     int device_index = 0;
  149.     int status;
  150.     int length = -1;
  151.     int invert = 0;
  152.     char *desc = NULL;
  153.     char descDefault[] = "UM245R";
  154.     int sync_mode = 0;
  155.     pthread_t writer_id;
  156.     writer_arg_t arg;
  157.  
  158.     while ((opt = getopt_long(
  159.         argc, argv, "d:hil:s", long_options, &option_index)) != -1) {
  160.         switch (opt) {
  161.             /* Long options */
  162.  
  163.             case 'd':
  164.                 desc = optarg;
  165.                 break;
  166.  
  167.             case 'h':
  168.                 show_usage();
  169.                 return 0;
  170.  
  171.             case 'i':
  172.                 invert = 1;
  173.                 break;
  174.  
  175.             case 'l':
  176.                 /* Extract the buffer size */
  177.                 if ( (optarg[0] == '0') &&
  178.                     ((optarg[1] == 'x') || (optarg[1] = 'X')) ) {
  179.                     /* scan hex */
  180.                     status = sscanf(optarg, "%x", &length);
  181.                 } else {
  182.                     /* scan decimal */
  183.                     status = sscanf(optarg, "%d", &length);
  184.                 }
  185.                 if (status < 0) {
  186.                     printf("Error: invalid length argument\n");
  187.                     return -1;
  188.                 }
  189.                 break;
  190.  
  191.             case 's':
  192.                 sync_mode = 1;
  193.                 break;
  194.  
  195.             default:
  196.                 show_usage();
  197.                 return 0;
  198.         }
  199.     }
  200.  
  201.     printf("\n");
  202.     printf("FTDI device loopback test\n");
  203.     printf("-------------------------\n");
  204.  
  205.     if (length < 0) {
  206.         printf("\nPlease provide a length argument.\n");
  207.         return 0;
  208.     }
  209.  
  210.     if (desc == NULL) {
  211.         desc = descDefault;
  212.     }
  213.  
  214.     /* ------------------------------------------------------------
  215.      * Buffers
  216.      * ------------------------------------------------------------
  217.      */
  218.     readBuffer = (BYTE *)malloc(length);
  219.     if (readBuffer == NULL) {
  220.         printf("Error: read buffer allocation failed!\n");
  221.         return -1;
  222.     }
  223.     memset(readBuffer,0, length);
  224.  
  225.     writeBuffer = (BYTE *)malloc(length);
  226.     if (writeBuffer == NULL) {
  227.         printf("Error: write buffer allocation failed!\n");
  228.         return -1;
  229.     }
  230.     memset(writeBuffer,0, length);
  231.  
  232.     /* ------------------------------------------------------------
  233.      * Find the device
  234.      * ------------------------------------------------------------
  235.      *
  236.      * Device details (determined using FT_PROG v2.4.2):
  237.      *   Chip Type:     'FT245R'
  238.      *   Vendor ID:      0x0403
  239.      *   Product ID:     0x6001
  240.      *   Manufacturer:   FTDI
  241.      *   Description:   'UM245R'
  242.      *   Serial Number: 'FTG6LJTG'
  243.      *
  244.      * Detect the device based on the description string.
  245.      */
  246.  
  247.     /* Get the number of devices */
  248.     nDevices = 0;
  249.     ftStatus = FT_CreateDeviceInfoList(&nDevices);
  250.     if (ftStatus != FT_OK) {
  251.         printf("Error: FT_CreateDeviceInfoList returned %d\n",
  252.             (int)ftStatus);
  253.         return 1;
  254.     }
  255.     if (nDevices == 0) {
  256.         printf("Error: the %s device was not detected\n", desc);
  257.         return -1;
  258.     }
  259.  
  260.     /* Match the description string */
  261.     device_detected = 0;
  262.     for (i = 0; i < nDevices; i++) {
  263.         ftStatus = FT_GetDeviceInfoDetail(
  264.             i, &Flags, &Type, &ID, &LocId,
  265.             SerialNumber, Description,
  266.             &ftHandle);
  267.         if (ftStatus != FT_OK) {
  268.             printf("Error: FT_GetDeviceInfoDetail returned %d\n",
  269.                 (int)ftStatus);
  270.             return 1;
  271.         }
  272.         if (strncmp(Description, desc, strlen(desc)) == 0) {
  273.             device_detected = 1;
  274.             device_index = i;
  275.         }
  276.     }
  277.     if (device_detected == 0) {
  278.         printf("Error: the %s device was not detected\n", desc);
  279.         return 1;
  280.     } else {
  281.         printf(" * %s device detected at device index %d\n", desc, device_index);
  282.     }
  283.  
  284.     /* ------------------------------------------------------------
  285.      * Open the device
  286.      * ------------------------------------------------------------
  287.      */
  288.     ftStatus = FT_Open(
  289.         device_index,
  290.         &ftHandle);
  291.     if (ftStatus != FT_OK) {
  292.         printf("Error: FT_Open returned %d\n", (int)ftStatus);
  293.         return 1;
  294.     }
  295.  
  296.     /* ------------------------------------------------------------
  297.      * Configure the device
  298.      * ------------------------------------------------------------
  299.      *
  300.      * PROBLEM:
  301.      * --------
  302.      *
  303.      * If the device is configured in SYNC mode, then it appears
  304.      * to stay in SYNC mode. If sync_mode is not set, then I want
  305.      * to put the device in ASYNC mode ... but there is no
  306.      * BITMODE setting for asynchronous FIFO mode!
  307.      *
  308.      * Read the FTDI App notes and see what they do.
  309.      */
  310.  
  311.     /* This does not seem to do anything */
  312. /*
  313.     printf(" * Reset the device\n");
  314.     ftStatus = FT_ResetDevice(ftHandle);
  315.     if (ftStatus != FT_OK) {
  316.         printf("Error: FT_ResetDevice returned %d\n", (int)ftStatus);
  317.         return 1;
  318.     }
  319.     usleep(10000);
  320. */
  321.  
  322.     /* This seems to reset the device properly on a sync->async change
  323.      * But it does hang sometimes - even with a delay
  324.      */
  325. /*
  326.     printf(" * Reset the port\n");
  327.     ftStatus = FT_ResetPort(ftHandle);
  328.     if (ftStatus != FT_OK) {
  329.         printf("Error: FT_ResetPort returned %d\n", (int)ftStatus);
  330.         return 1;
  331.     }
  332.     usleep(10000);
  333. */
  334.  
  335.  
  336.     /* Use synchronous mode */
  337.     if (sync_mode == 1) {
  338.  
  339.         /* Per AN130 sequence
  340.          * Mask = 0xFF = outputs -> 0 = inputs should be ok.
  341.          * Mode = 0x00 = reset mode
  342.          *      = 0x40 = synchronous mode
  343.          */
  344.         ftStatus = FT_SetBitMode(ftHandle, 0, FT_BITMODE_RESET);
  345.         if (ftStatus != FT_OK) {
  346.             printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus);
  347.             return 1;
  348.         }
  349.  
  350.         /* 10ms sleep */
  351.         usleep(10000);
  352.  
  353.         ftStatus = FT_SetBitMode(ftHandle, 0, FT_BITMODE_SYNC_FIFO);
  354.         if (ftStatus != FT_OK) {
  355.             printf("Error: FT_SetBitMode returned %d\n", (int)ftStatus);
  356.             return 1;
  357.         }
  358.  
  359.     }
  360.  
  361.     /* Set flow control per AN130 - apparantly this stops the
  362.      * driver from dropping data.
  363.      */
  364.     ftStatus = FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0, 0);
  365.     if (ftStatus != FT_OK) {
  366.         printf("Error: FT_SetFlowControl returned %d\n", (int)ftStatus);
  367.         return 1;
  368.     }
  369.  
  370.     /* ------------------------------------------------------------
  371.      * Fill the write buffer
  372.      * ------------------------------------------------------------
  373.      */
  374.     for (i = 0; i < length; i++) {
  375.         writeBuffer[i] = i;
  376.     }
  377.  
  378.     /* ------------------------------------------------------------
  379.      * Create the writer thread
  380.      * ------------------------------------------------------------
  381.      */
  382.     arg.handle = ftHandle;
  383.     arg.buffer = writeBuffer;
  384.     arg.length = length;
  385.     status = pthread_create(
  386.         &writer_id, NULL, writer_thread, &arg);
  387.     if (status != 0) {
  388.         printf("Error: Thread creation failed\n");
  389.         return 1;
  390.     }
  391.  
  392.     /* ------------------------------------------------------------
  393.      * Read the bytes and check them
  394.      * ------------------------------------------------------------
  395.      */
  396.     printf("READER_THREAD: poll for the response bytes\n");
  397.     totalBytesRead = 0;
  398.     status = 0;
  399.     while ((totalBytesRead != length) & (status < 100)) {
  400.  
  401.         /* Number of bytes ready */
  402.         ftStatus = FT_GetQueueStatus(
  403.             ftHandle,
  404.             &bytesToRead);
  405.         if (ftStatus != FT_OK) {
  406.             printf("Error: FT_GetQueueStatus returned %d\n", (int)ftStatus);
  407.             return 1;
  408.         }
  409.  
  410.         printf("READER_THREAD: bytesToRead = %d\n", (int)bytesToRead);
  411.         if (bytesToRead > 0) {
  412.             status = 0;
  413.             ftStatus = FT_Read(
  414.                 ftHandle,
  415.                 &readBuffer[totalBytesRead],
  416.                 (int)bytesToRead,
  417.                 &bytesRead);
  418.             if (ftStatus != FT_OK) {
  419.                 printf("Error: FT_Read returned %d\n", (int)ftStatus);
  420.                 return 1;
  421.             }
  422.             totalBytesRead += bytesRead;
  423.             printf("READER_THREAD: %d-bytes received (%.2f-percent)\n", (int)bytesRead,
  424.                 (double)totalBytesRead/(double)length*100.0);
  425.         } else {
  426.             /* Give up after 100 tries */
  427.             status++;
  428.  
  429.             /* 10ms delay when bytesToRead = 0 */
  430.             usleep(10000);
  431.         }
  432.     }
  433.     if (status != 0) {
  434.         printf("Error: bytesToRead was zero for too many iterations!\n");
  435.         exit(1);
  436.     }
  437.  
  438.     printf("READER_THREAD: check the response bytes\n");
  439.     status = 0;
  440.     for (i = 0; i < length; i++) {
  441.  
  442.         if (invert == 0) {
  443.             if (readBuffer[i] != writeBuffer[i]) {
  444.                 printf("   - Error: data error at index %d (read %X, expected %X)\n",
  445.                     (int)i, (int)readBuffer[i], writeBuffer[i]);
  446.                 status = -1;
  447.             }
  448.         } else {
  449.             /* Check for inverted data
  450.              *
  451.              * The loopback test can invert the bits in hardware so that
  452.              * the SignalTap II traces show when the FPGA drives the
  453.              * external data bus.
  454.              */
  455.             if (readBuffer[i] != (~writeBuffer[i] & 0xFF)) {
  456.                 printf("   - Error: data error at index %d (read %X, expected %X)\n",
  457.                     (int)i, (int)readBuffer[i], (int)(~writeBuffer[i] & 0xFF));
  458.                 status = -1;
  459.             }
  460.         }
  461.     }
  462.     if (status == 0) {
  463.         printf("READER_THREAD: The bytes received match the expected values.\n\n");
  464.     }
  465.  
  466.     printf("READER_THREAD: %d-bytes (%.2fMB) transferred.\n\n", length, (double)length/(1024.0*1024.0));
  467.  
  468.     /* ------------------------------------------------------------
  469.      * Wait for the writer thread
  470.      * ------------------------------------------------------------
  471.      */
  472.     printf("READER_THREAD: Wait for the writer thread\n");
  473.     status = pthread_join(writer_id, NULL);
  474.     if (status != 0) {
  475.         printf("join failed - %s\n", strerror(status));
  476.         return -1;
  477.     }
  478.  
  479.     /* Resource cleanup */
  480.     FT_Close(ftHandle);
  481.     free(readBuffer);
  482.     free(writeBuffer);
  483.     return 0;
  484. }
  485.  
  486. /* ================================================================
  487.  * Local function definitions
  488.  * ================================================================
  489.  */
  490. /* ----------------------------------------------------------------
  491.  * Usage
  492.  * ----------------------------------------------------------------
  493.  */
  494. static void show_usage(void)
  495. {
  496.     printf(
  497.         "\n"\
  498.         "FTDI device loopback test\n"\
  499.         "-------------------------\n\n"\
  500.         "Usage: ftdi_loopback [options]\n\n"\
  501.         "Options:\n"\
  502.         " -l | --length          Length (number of bytes to transfer)\n"\
  503.         " -h | --help            Help (this message)\n"\
  504.         "\n"
  505.     );
  506. }
  507.  
  508. /* ----------------------------------------------------------------
  509.  * Writer thread
  510.  * ----------------------------------------------------------------
  511.  */
  512. static void *writer_thread(void *arg)
  513. {
  514.     writer_arg_t *args = (writer_arg_t *)arg;
  515.  
  516.     FT_HANDLE ftHandle = args->handle;
  517.     BYTE *writeBuffer  = args->buffer;
  518.     int length         = args->length;
  519.     FT_STATUS ftStatus;
  520.     DWORD bytesWritten, totalBytesWritten, bytesRemaining, bytesToWrite;
  521.  
  522.     /* ------------------------------------------------------------
  523.      * Write a sequence of bytes and read it back
  524.      * ------------------------------------------------------------
  525.      */
  526.     totalBytesWritten = 0;
  527.     bytesRemaining = length;
  528.     while (bytesRemaining > 0) {
  529.  
  530.         /* Send the buffer in 64kB blocks */
  531.         if (bytesRemaining > 64*1024) {
  532.             bytesToWrite = 64*1024;
  533.         } else {
  534.             bytesToWrite = bytesRemaining;
  535.         }
  536.         printf("WRITER_THREAD: write %d-bytes\n", (int)bytesToWrite);
  537.         ftStatus = FT_Write(
  538.             ftHandle,
  539.             &writeBuffer[totalBytesWritten],
  540.             bytesToWrite,
  541.             &bytesWritten);
  542.  
  543.         if (ftStatus != FT_OK) {
  544.             printf("Error: FT_Write returned %d\n", (int)ftStatus);
  545.             return NULL;
  546.         }
  547.  
  548.         printf("WRITER_THREAD: %d-bytes written\n", (int)bytesWritten);
  549.  
  550.         totalBytesWritten += bytesWritten;
  551.         bytesRemaining    -= bytesWritten;
  552.  
  553.         /* A delay was necessary to give the reader thread a chance to run */
  554.         usleep(1000);
  555.     }
  556.     return NULL;
  557. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement