359 lines
10 KiB
C
359 lines
10 KiB
C
/* stream_test.c
|
|
*
|
|
* Test reading from FT2232H in synchronous FIFO mode.
|
|
*
|
|
* The FT2232H must supply data due to an appropriate circuit
|
|
*
|
|
* To check for skipped block with appended code,
|
|
* a structure as follows is assumed
|
|
* 1* uint32_t num (incremented in 0x4000 steps)
|
|
* 3* uint32_t dont_care
|
|
*
|
|
* After start, data will be read in streaming until the program is aborted
|
|
* Progess information wil be printed out
|
|
* If a filename is given on the command line, the data read will be
|
|
* written to that file
|
|
*
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <ftdi.h>
|
|
void check_outfile(char *);
|
|
|
|
static FILE *outputFile;
|
|
|
|
static int check = 1;
|
|
static int exitRequested = 0;
|
|
/*
|
|
* sigintHandler --
|
|
*
|
|
* SIGINT handler, so we can gracefully exit when the user hits ctrl-C.
|
|
*/
|
|
|
|
static void
|
|
sigintHandler(int signum)
|
|
{
|
|
exitRequested = 1;
|
|
}
|
|
|
|
static void
|
|
usage(const char *argv0)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s [options...] \n"
|
|
"Test streaming read from FT2232H\n"
|
|
"[-P string] only look for product with given string\n"
|
|
"[-n] don't check for special block structure\n"
|
|
"\n"
|
|
"If some filename is given, write data read to that file\n"
|
|
"Progess information is printed each second\n"
|
|
"Abort with ^C\n"
|
|
"\n"
|
|
"Options:\n"
|
|
"\n"
|
|
"Copyright (C) 2009 Micah Dowty <micah@navi.cx>\n"
|
|
"Adapted for use with libftdi (C) 2010 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>\n",
|
|
argv0);
|
|
exit(1);
|
|
}
|
|
|
|
static uint32_t start = 0;
|
|
static uint32_t offset = 0;
|
|
static uint64_t blocks = 0;
|
|
static uint32_t skips = 0;
|
|
static uint32_t n_err = 0;
|
|
static int
|
|
readCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
|
|
{
|
|
if (length)
|
|
{
|
|
if (check)
|
|
{
|
|
int i,rem;
|
|
uint32_t num;
|
|
for (i= offset; i<length-16; i+=16)
|
|
{
|
|
num = *(uint32_t*) (buffer+i);
|
|
if (start && (num != start +0x4000))
|
|
{
|
|
uint32_t delta = ((num-start)/0x4000)-1;
|
|
fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu\n",
|
|
delta, start -0x4000, num, (unsigned long long)blocks);
|
|
n_err++;
|
|
skips += delta;
|
|
}
|
|
blocks ++;
|
|
start = num;
|
|
}
|
|
rem = length -i;
|
|
if (rem >3)
|
|
{
|
|
num = *(uint32_t*) (buffer+i);
|
|
if (start && (num != start +0x4000))
|
|
{
|
|
uint32_t delta = ((num-start)/0x4000)-1;
|
|
fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu\n",
|
|
delta, start -0x4000, num, (unsigned long long) blocks);
|
|
n_err++;
|
|
skips += delta;
|
|
}
|
|
start = num;
|
|
}
|
|
else if (rem)
|
|
start += 0x4000;
|
|
if (rem != 0)
|
|
{
|
|
blocks ++;
|
|
offset = 16-rem;
|
|
}
|
|
}
|
|
if (outputFile)
|
|
{
|
|
if (fwrite(buffer, length, 1, outputFile) != 1)
|
|
{
|
|
perror("Write error");
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
if (progress)
|
|
{
|
|
fprintf(stderr, "%10.02fs total time %9.3f MiB captured %7.1f kB/s curr rate %7.1f kB/s totalrate %d dropouts\n",
|
|
progress->totalTime,
|
|
progress->current.totalBytes / (1024.0 * 1024.0),
|
|
progress->currentRate / 1024.0,
|
|
progress->totalRate / 1024.0,
|
|
n_err);
|
|
}
|
|
return exitRequested ? 1 : 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct ftdi_context *ftdi;
|
|
int err, c;
|
|
FILE *of = NULL;
|
|
char const *outfile = 0;
|
|
outputFile =0;
|
|
exitRequested = 0;
|
|
char *descstring = NULL;
|
|
int option_index;
|
|
static struct option long_options[] = {{NULL},};
|
|
|
|
while ((c = getopt_long(argc, argv, "P:n", long_options, &option_index)) !=- 1)
|
|
switch (c)
|
|
{
|
|
case -1:
|
|
break;
|
|
case 'P':
|
|
descstring = optarg;
|
|
break;
|
|
case 'n':
|
|
check = 0;
|
|
break;
|
|
default:
|
|
usage(argv[0]);
|
|
}
|
|
|
|
if (optind == argc - 1)
|
|
{
|
|
// Exactly one extra argument- a dump file
|
|
outfile = argv[optind];
|
|
}
|
|
else if (optind < argc)
|
|
{
|
|
// Too many extra args
|
|
usage(argv[0]);
|
|
}
|
|
|
|
if ((ftdi = ftdi_new()) == 0)
|
|
{
|
|
fprintf(stderr, "ftdi_new failed\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (ftdi_set_interface(ftdi, INTERFACE_A) < 0)
|
|
{
|
|
fprintf(stderr, "ftdi_set_interface failed\n");
|
|
ftdi_free(ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (ftdi_usb_open_desc(ftdi, 0x0403, 0x6010, descstring, NULL) < 0)
|
|
{
|
|
fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(ftdi));
|
|
ftdi_free(ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* A timeout value of 1 results in may skipped blocks */
|
|
if(ftdi_set_latency_timer(ftdi, 2))
|
|
{
|
|
fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(ftdi));
|
|
ftdi_usb_close(ftdi);
|
|
ftdi_free(ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* if(ftdi_usb_purge_rx_buffer(ftdi) < 0)
|
|
{
|
|
fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(ftdi));
|
|
return EXIT_FAILURE;
|
|
}*/
|
|
if (outfile)
|
|
if ((of = fopen(outfile,"w+")) == 0)
|
|
fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno));
|
|
if (of)
|
|
if (setvbuf(of, NULL, _IOFBF , 1<<16) == 0)
|
|
outputFile = of;
|
|
signal(SIGINT, sigintHandler);
|
|
|
|
err = ftdi_readstream(ftdi, readCallback, NULL, 8, 256);
|
|
if (err < 0 && !exitRequested)
|
|
exit(1);
|
|
|
|
if (outputFile) {
|
|
fclose(outputFile);
|
|
outputFile = NULL;
|
|
}
|
|
fprintf(stderr, "Capture ended.\n");
|
|
|
|
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
|
|
{
|
|
fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(ftdi));
|
|
ftdi_usb_close(ftdi);
|
|
ftdi_free(ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
ftdi_usb_close(ftdi);
|
|
ftdi_free(ftdi);
|
|
signal(SIGINT, SIG_DFL);
|
|
if (check && outfile)
|
|
{
|
|
if ((outputFile = fopen(outfile,"r")) == 0)
|
|
{
|
|
fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno));
|
|
ftdi_usb_close(ftdi);
|
|
ftdi_free(ftdi);
|
|
return EXIT_FAILURE;
|
|
}
|
|
check_outfile(descstring);
|
|
fclose(outputFile);
|
|
}
|
|
else if (check)
|
|
fprintf(stderr,"%d errors of %llu blocks (%Le), %d (%Le) blocks skipped\n",
|
|
n_err, (unsigned long long) blocks, (long double)n_err/(long double) blocks,
|
|
skips, (long double)skips/(long double) blocks);
|
|
exit (0);
|
|
}
|
|
|
|
void check_outfile(char *descstring)
|
|
{
|
|
if(strcmp(descstring,"FT2232HTEST") == 0)
|
|
{
|
|
char buf0[1024];
|
|
char buf1[1024];
|
|
char bufr[1024];
|
|
char *pa, *pb, *pc;
|
|
unsigned int num_lines = 0, line_num = 1;
|
|
int err_count = 0;
|
|
unsigned int num_start, num_end;
|
|
|
|
pa = buf0;
|
|
pb = buf1;
|
|
pc = buf0;
|
|
if(fgets(pa, 1023, outputFile) == NULL)
|
|
{
|
|
fprintf(stderr,"Empty output file\n");
|
|
return;
|
|
}
|
|
while(fgets(pb, 1023, outputFile) != NULL)
|
|
{
|
|
num_lines++;
|
|
unsigned int num_save = num_start;
|
|
if( sscanf(pa,"%6u%94s%6u",&num_start, bufr,&num_end) !=3)
|
|
{
|
|
fprintf(stdout,"Format doesn't match at line %8d \"%s",
|
|
num_lines, pa);
|
|
err_count++;
|
|
line_num = num_save +2;
|
|
}
|
|
else
|
|
{
|
|
if ((num_start+1)%100000 != num_end)
|
|
{
|
|
if (err_count < 20)
|
|
fprintf(stdout,"Malformed line %d \"%s\"\n",
|
|
num_lines, pa);
|
|
err_count++;
|
|
}
|
|
else if(num_start != line_num)
|
|
{
|
|
if (err_count < 20)
|
|
fprintf(stdout,"Skipping from %d to %d\n",
|
|
line_num, num_start);
|
|
err_count++;
|
|
|
|
}
|
|
line_num = num_end;
|
|
}
|
|
pa = pb;
|
|
pb = pc;
|
|
pc = pa;
|
|
}
|
|
if(err_count)
|
|
fprintf(stdout,"\n%d errors of %d data sets %f\n", err_count, num_lines, (double) err_count/(double)num_lines);
|
|
else
|
|
fprintf(stdout,"No errors for %d lines\n",num_lines);
|
|
}
|
|
else if(strcmp(descstring,"LLBBC10") == 0)
|
|
{
|
|
uint32_t block0[4];
|
|
uint32_t block1[4];
|
|
uint32_t *pa = block0;
|
|
uint32_t *pb = block1;
|
|
uint32_t *pc = block0;
|
|
uint32_t start= 0;
|
|
uint32_t nread = 0;
|
|
int n_shown = 0;
|
|
int n_errors = 0;
|
|
if (fread(pa, sizeof(uint32_t), 4,outputFile) < 4)
|
|
{
|
|
fprintf(stderr,"Empty result file\n");
|
|
return;
|
|
}
|
|
while(fread(pb, sizeof(uint32_t), 4,outputFile) != 0)
|
|
{
|
|
blocks++;
|
|
nread = pa[0];
|
|
if(start>0 && (nread != start))
|
|
{
|
|
if(n_shown < 30)
|
|
{
|
|
fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu \n",
|
|
(nread-start)/0x4000, start -0x4000, nread, (unsigned long long) blocks);
|
|
n_shown ++;
|
|
}
|
|
n_errors++;
|
|
}
|
|
else if (n_shown >0)
|
|
n_shown--;
|
|
start = nread + 0x4000;
|
|
pa = pb;
|
|
pb = pc;
|
|
pc = pa;
|
|
}
|
|
if(n_errors)
|
|
fprintf(stderr, "%d blocks wrong from %llu blocks read\n",
|
|
n_errors, (unsigned long long) blocks);
|
|
else
|
|
fprintf(stderr, "%llu blocks all fine\n", (unsigned long long) blocks);
|
|
}
|
|
}
|