1
0
mirror of https://github.com/wfjm/w11.git synced 2026-02-18 13:47:24 +00:00
Files
wfjm.w11/rtl/sys_gen/tst_fx2loop/tst_fx2loop.c
Walter F.J. Mueller cbd8ce3468 - interim release w11a_V0.56 (untagged)
- re-organized handling of board and derived clocks in test benches
- added message filter definitions for some designs (.mfset files)
- added Cypress EZ-USB FX2 controller (USB interface)
- added firmware for EZ-USB FX2 supporting jtag access and data transfer
- FPGA configure over USB now supported directly in make build flow
- added test systems for USB testing and rlink over USB verification
- no functional change of w11a CPU core or any pre-existing test systems
- Note: Carefully read the disclaimer about usage of USB VID/PID numbers
        in the file README_USB-VID-PID.txt. You'll be responsible for any
        misuse of the defaults provided with the project sources !!
2013-01-02 21:06:53 +00:00

1045 lines
28 KiB
C

/* $Id: tst_fx2loop.c 465 2012-12-27 21:29:38Z mueller $ */
/*
* Copyright 2011-2012 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
*
* This program is free software; you may redistribute and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 2, or at your option any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for complete details.
*
*
* Revision History:
* Date Rev Version Comment
* 2012-04-09 461 2.1.1 fix loop back code: fix run-down, add pipe drain
* 2012-03-24 460 2.1 add message loop back code (preliminary)
* 2012-03-10 459 2.0 re-write for asynchronous libusb interface
* 2012-02-12 457 1.1 redo argument handling; add -stat and -rndm
* 2012-01-15 453 1.0.1 add -tx2blast; fix bug in loop read loop
* 2011-12-29 446 1.0 Initial version (only -read/write/loop)
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <signal.h>
#include <poll.h>
#include <errno.h>
#include <sys/timerfd.h>
#include <libusb-1.0/libusb.h>
static int nsigint = 0;
static int endpoll = 0;
static libusb_context* pUsbContext = 0;
static libusb_device** pUsbDevList = 0;
static int UsbDevCount = 0;
static libusb_device_handle* pUsbDevHdl = 0;
static struct pollfd pollfd_fds[16];
static int pollfd_nfds = 0;
struct dsc_queue {
int par_nfrm;
int par_nque;
double stat_nbuf;
double stat_nbyt;
double stat_npt;
uint16_t cval;
};
static struct dsc_queue dsc_rx;
static struct dsc_queue dsc_tx1;
static struct dsc_queue dsc_tx2;
static int par_nwmsg = 0;
static int par_nwrndm = 0;
static int par_stat = 0;
static int par_trace = 0;
static int par_nsec = 0;
static int cur_nwmsg = 0;
static double stat_nmsg = 0.;
static double t_start;
static int nreq = 0;
static char** argv;
static int argc;
static int argi;
void usage(FILE* of);
int get_pint(char* p);
double get_double(char* p);
int get_arg_pint(int min, int max, const char* text);
void do_write(uint16_t* buf, int nw);
void do_read(int ep);
void do_run();
void do_stat();
void usb_claim();
void usb_release();
char* usb_strerror(int rc);
void prt_time(void);
double get_time(void);
void bad_syscall_exit(const char* text, int rc);
void bad_usbcall_exit(const char* text, int rc);
void bad_transfer_exit(struct libusb_transfer *t, const char* text);
void sigint_handler(int signum)
{
printf("\n");
nsigint += 1;
if (nsigint > 3) {
fprintf(stderr, "tst_fx2loop-F: 3rd ^C, aborting\n");
exit(EXIT_FAILURE);
}
return;
}
int main(int main_argc, char *main_argv[])
{
argc = main_argc;
argv = main_argv;
argi = 1;
int i;
/* setup ^C handler */
struct sigaction new_action;
new_action.sa_handler = sigint_handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGINT, &new_action, NULL);
/* capture -help case here */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-help") == 0) {
usage(stdout);
return EXIT_SUCCESS;
}
}
/* determine usb device path (first arg or from RETRO_FX2_VID/PID */
char devbuf[10];
char* path = 0;
if (argc > argi && argv[argi][0] != '-') {
path = argv[argi];
argi += 1;
} else {
char* env_vid = getenv("RETRO_FX2_VID");
char* env_pid = getenv("RETRO_FX2_PID");
if (env_vid && strlen(env_vid) == 4 &&
env_pid && strlen(env_pid) == 4) {
strncpy(devbuf , env_vid,4);
devbuf[4] = ':';
strncpy(devbuf+5, env_pid,4);
devbuf[9] = 0;
path = devbuf;
} else {
fprintf(stderr,
"tst_fx2loop-F: RETRO_FX2_VID/PID not or ill defined\n");
return EXIT_FAILURE;
}
}
/* init libusb, connect to device */
libusb_init(&pUsbContext);
libusb_set_debug(pUsbContext, 3);
UsbDevCount = libusb_get_device_list(pUsbContext, &pUsbDevList);
libusb_device* mydev = 0;
if (strlen(path)==8 && path[0]=='/' && path[4]=='/') {
char busnam[4];
char devnam[4];
strncpy(busnam, path+1, 3);
strncpy(devnam, path+5, 3);
busnam[3] = 0;
devnam[3] = 0;
char* endptr;
uint8_t busnum = strtol(busnam, &endptr, 10);
uint8_t devnum = strtol(devnam, &endptr, 10);
int idev;
for (idev=0; idev<UsbDevCount; idev++) {
libusb_device* udev = pUsbDevList[idev];
if (libusb_get_bus_number(udev) == busnum &&
libusb_get_device_address(udev) == devnum) {
mydev = udev;
}
}
} else if (strlen(path)==9 && path[4]==':') {
char vennam[5];
char pronam[5];
memcpy(vennam, path, 4);
memcpy(pronam, path+5, 4);
vennam[4] = 0;
pronam[4] = 0;
char* endptr;
uint16_t vennum = strtol(vennam, &endptr, 16);
uint16_t pronum = strtol(pronam, &endptr, 16);
int idev;
for (idev=0; idev<UsbDevCount; idev++) {
libusb_device* udev = pUsbDevList[idev];
struct libusb_device_descriptor devdsc;
libusb_get_device_descriptor(udev, &devdsc);
if (devdsc.idVendor==vennum && devdsc.idProduct==pronum) {
mydev = udev;
}
}
} else {
fprintf(stderr, "tst_fx2loop-F: dev not in /bus/dev or vend:prod form\n");
return EXIT_FAILURE;
}
if (mydev == 0) {
fprintf(stderr, "tst_fx2loop-F: no usb device %s found\n", path);
return EXIT_FAILURE;
}
int rc;
rc = libusb_open(mydev, &pUsbDevHdl);
if (rc) {
fprintf(stderr, "tst_fx2loop-F: failed to open %s rc=%d: %s\n",
path, rc, usb_strerror(rc));
return EXIT_FAILURE;
}
/* check for internal timeout handling support */
if (libusb_pollfds_handle_timeouts(pUsbContext) == 0) {
fprintf(stderr, "tst_fx2loop-F: libusb_pollfds_handle_timeouts == 0\n"
" this program will not run on this legacy system\n");
return EXIT_FAILURE;
}
for (; argi < argc; ) {
/* handle setup options ----------------------------------------------- */
if (strcmp(argv[argi],"-nbrx") == 0) {
argi += 1;
dsc_rx.par_nfrm = get_arg_pint(1, 256, "rx buffer size invalid");
} else if (strcmp(argv[argi],"-nqrx") == 0) {
argi += 1;
dsc_rx.par_nque = get_arg_pint(1, 8, "rx buffer count invalid");
} else if (strcmp(argv[argi],"-nbtx") == 0) {
argi += 1;
dsc_tx1.par_nfrm = get_arg_pint(1, 256, "tx1 buffer size invalid");
} else if (strcmp(argv[argi],"-nqtx") == 0) {
argi += 1;
dsc_tx1.par_nque = get_arg_pint(1, 8, "tx1 buffer count invalid");
} else if (strcmp(argv[argi],"-nbtx2") == 0) {
argi += 1;
dsc_tx2.par_nfrm = get_arg_pint(1, 256, "tx2 buffer size invalid");
} else if (strcmp(argv[argi],"-nqtx2") == 0) {
argi += 1;
dsc_tx2.par_nque = get_arg_pint(1, 8, "tx2 buffer count invalid");
} else if (strcmp(argv[argi],"-nwmsg") == 0) {
argi += 1;
par_nwmsg = get_arg_pint(1, 4096, "loopback message size invalid");
} else if (strcmp(argv[argi],"-rndm") == 0) {
argi += 1;
par_nwrndm = 1;
} else if (strcmp(argv[argi],"-stat") == 0) {
argi += 1;
par_stat = 1;
} else if (strcmp(argv[argi],"-trace") == 0) {
argi += 1;
par_trace = 1;
/* handle action options ---------------------------------------------- */
} else if (strcmp(argv[argi],"-write") == 0) {
uint16_t buf[4096];
int nw = 0;
argi += 1;
while(argi < argc && nw < 4096) {
char *argp = argv[argi];
if (argp[0] == '-') break;
char* endptr;
long val = strtol(argp, &endptr, 0);
if ((endptr && endptr[0]) || val < 0 || val > 0xffff) {
nw = 0;
break;
}
argi += 1;
buf[nw++] = (uint16_t)val;
}
if (nw == 0) {
fprintf(stderr, "tst_fx2loop-E: bad word list\n");
break;
}
do_write(buf, nw);
} else if (strcmp(argv[argi],"-read") == 0) {
argi += 1;
int ep = 6;
if (argi < argc) ep = get_pint(argv[argi++]);
if (ep != 6 && ep != 8) {
fprintf(stderr, "tst_fx2loop-F: bad read endpoint (must be 6 or 8)\n");
return EXIT_FAILURE;
}
do_read(ep);
} else if (strcmp(argv[argi],"-run") == 0) {
argi += 1;
if (argi < argc) par_nsec = get_pint(argv[argi++]);
if (par_nsec < 0) {
fprintf(stderr, "tst_fx2loop-E: bad args for -run\n");
break;
}
do_run();
do_stat();
} else {
fprintf(stderr, "tst_fx2loop-F: unknown option %s\n", argv[argi]);
usage(stderr);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
/*--------------------------------------------------------------------------*/
void usage(FILE* of)
{
fprintf(of, "Usage: tst_fx2loop [dev] [setup-opts...] [action-opts...]\n");
fprintf(of, " arguments:\n");
fprintf(of, " dev path usb device, either bus/dev or vend:prod\n");
fprintf(of, " default is $RETRO_FX2_VID:$RETRO_FX2_VID\n");
fprintf(of, " setup options:\n");
fprintf(of, " -nbrx nb buffer size (in 512B) for rxblast\n");
fprintf(of, " -nqrx nb number of buffers for rxblast\n");
fprintf(of, " -nbtx nb buffer size (in 512B) for txblast or loop\n");
fprintf(of, " -nqtx nb number of buffers for txblast or loop\n");
fprintf(of, " -nbtx2 nb buffer size (in 512B) for tx2blast\n");
fprintf(of, " -nqtx2 nb number of buffers for tx2blast\n");
fprintf(of, " -nwmsg nw number words for loop test\n");
fprintf(of, " -rndm use random length for loop test\n");
fprintf(of, " -stat print live stats\n");
fprintf(of, " -trace trace usb calls\n");
fprintf(of, " action options:\n");
fprintf(of, " -write w0 w1 ... write list of words to endpoint 4\n");
fprintf(of, " -read ep read from endpoint ep\n");
fprintf(of, " -run ns run tests for nw seconds\n");
}
/*--------------------------------------------------------------------------*/
int get_pint(char* p)
{
char *endptr;
long num = 0;
num = strtol(p, &endptr, 0);
if ((endptr && *endptr) || num < 0 || num > INT_MAX) {
fprintf(stderr, "tst_fx2loop-E: \"%s\" not a non-negative integer\n", p);
return -1;
}
return num;
}
/*--------------------------------------------------------------------------*/
double get_double(char* p)
{
char *endptr;
double num = 0.;
num = strtod(p, &endptr);
if ((endptr && *endptr) || num < 0.) {
fprintf(stderr, "tst_fx2loop-E: \"%s\" not a valid positive float\n", p);
return -1.;
}
return num;
}
/*--------------------------------------------------------------------------*/
int get_arg_pint(int min, int max, const char* text)
{
int tmp = -1;
if (argi < argc) tmp = get_pint(argv[argi++]);
if (tmp < min || tmp > max) {
fprintf(stderr, "tst_fx2loop-F: %s\n", text);
exit(EXIT_FAILURE);
}
return tmp;
}
/*--------------------------------------------------------------------------*/
void do_write(uint16_t* buf, int nw)
{
int rc;
int i;
int ntrans;
int tout = 1000;
int ep = 4;
usb_claim();
rc = libusb_bulk_transfer(pUsbDevHdl, ep,
(unsigned char *)buf, nw*2, &ntrans, tout);
if (rc!=0 || ntrans != nw*2) {
fprintf(stderr, "tst_fx2loop-E: bulk write failed ntrans=%d rc=%d: %s \n",
ntrans, rc, usb_strerror(rc));
} else {
prt_time();
printf("write %4d word:", nw);
for (i = 0; i < nw; i++) printf(" %4.4x", buf[i]);
printf("\n");
}
usb_release();
return;
}
/*--------------------------------------------------------------------------*/
void do_read(int ep)
{
int rc;
int i;
int ntrans;
uint16_t buf[4096];
int tout = 1000;
int nloop;
usb_claim();
for (nloop=0;;nloop++) {
rc = libusb_bulk_transfer(pUsbDevHdl, ep|0x80,
(unsigned char *)buf, 2*4096, &ntrans, tout);
if (ntrans==0 && rc) {
if (rc==LIBUSB_ERROR_TIMEOUT && ntrans==0 && nloop>0) break;
fprintf(stderr, "tst_fx2loop-E: bulk read failed ntrans=%d rc=%d: %s \n",
ntrans, rc, usb_strerror(rc));
break;
}
prt_time();
printf("read %4d word:", ntrans/2);
int nprt = ntrans/2;
if (nprt > 7) nprt = 7;
for (i = 0; i < nprt; i++) printf(" %4.4x", (uint16_t)buf[i]);
printf("\n");
if (nsigint>0) break;
}
usb_release();
return;
}
/*----------------------------------------------------------*/
void pollfd_add(int fd, short events, void *user_data)
{
if (pollfd_nfds >= 16) {
fprintf(stderr, "tst_fx2loop-F: pollfd list overflow\n");
exit(EXIT_FAILURE);
}
if (par_trace) {
prt_time();
printf("pollfd_add: fd=%3d evt=%4.4x\n", fd, events);
}
pollfd_fds[pollfd_nfds].fd = fd;
pollfd_fds[pollfd_nfds].events = events;
pollfd_fds[pollfd_nfds].revents = 0;
pollfd_nfds += 1;
return;
}
/*----------------------------------------------------------*/
void pollfd_remove(int fd, void *user_data)
{
int iw = 0;
int ir = 0;
if (par_trace) {
prt_time();
printf("pollfd_remove: fd=%3d\n", fd);
}
for (ir = 0; ir < pollfd_nfds; ir++) {
if (pollfd_fds[ir].fd != fd) {
pollfd_fds[iw].fd = pollfd_fds[ir].fd;
pollfd_fds[iw].events = pollfd_fds[ir].events;
pollfd_fds[iw].revents = pollfd_fds[ir].revents;
iw += 1;
}
}
pollfd_nfds = iw;
return;
}
/*----------------------------------------------------------*/
void pollfd_init()
{
const struct libusb_pollfd** plist = libusb_get_pollfds(pUsbContext);
const struct libusb_pollfd** p;
for (p = plist; *p !=0; p++) {
pollfd_add((*p)->fd, (*p)->events, NULL);
}
free(plist);
libusb_set_pollfd_notifiers(pUsbContext, pollfd_add, pollfd_remove,NULL);
return;
}
/*----------------------------------------------------------*/
int keep_running()
{
if (nsigint > 0) return 0;
if (par_nsec > 0 && (get_time()-t_start) > par_nsec) return 0;
return 1;
}
/* forward declaration needed... */
void cb_rxblast(struct libusb_transfer *t);
/*----------------------------------------------------------*/
void que_write()
{
int rc;
int i;
int nw = 512*dsc_rx.par_nfrm/2;
int length = 2*nw;
uint16_t* pdat;
struct libusb_transfer* t = libusb_alloc_transfer(0);
t->dev_handle = pUsbDevHdl;
t->flags = LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER;
t->endpoint = 4;
t->type = LIBUSB_TRANSFER_TYPE_BULK;
t->timeout = 1000;
t->status = 0;
t->buffer = malloc(length);
t->length = length;
t->actual_length = 0;
t->callback = cb_rxblast;
t->user_data = 0;
pdat = (uint16_t*)(t->buffer);
for (i = 0; i < nw; i++) *pdat++ = dsc_rx.cval++;
rc = libusb_submit_transfer(t);
if (rc) bad_usbcall_exit("libusb_submit_transfer()", rc);
nreq += 1;
if (par_trace) {
prt_time();
printf("que_write: ep=%1d l=%5d\n", t->endpoint&(~0x80), t->length);
}
return;
}
/*----------------------------------------------------------*/
void que_read(int ep, int nb, libusb_transfer_cb_fn cb)
{
int rc;
int length = 512*nb;
struct libusb_transfer* t = libusb_alloc_transfer(0);
t->dev_handle = pUsbDevHdl;
t->flags = LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER;
t->endpoint = (unsigned char) (ep|0x80);
t->type = LIBUSB_TRANSFER_TYPE_BULK;
t->timeout = 1000;
t->status = 0;
t->buffer = malloc(length);
t->length = length;
t->actual_length = 0;
t->callback = cb;
t->user_data = 0;
rc = libusb_submit_transfer(t);
if (rc) bad_usbcall_exit("libusb_submit_transfer()", rc);
nreq += 1;
if (par_trace) {
prt_time();
printf("que_read: ep=%1d l=%5d\n", t->endpoint&(~0x80), t->length);
}
return;
}
/*----------------------------------------------------------*/
void send_msg()
{
int rc;
int i;
int nw = par_nwmsg;
int length;
uint16_t* pdat;
if (par_nwrndm) nw = 1 + (random() % par_nwmsg);
length = 2 * nw;
cur_nwmsg = nw;
struct libusb_transfer* t = libusb_alloc_transfer(0);
t->dev_handle = pUsbDevHdl;
t->flags = LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER;
t->endpoint = 4;
t->type = LIBUSB_TRANSFER_TYPE_BULK;
t->timeout = 1000;
t->status = 0;
t->buffer = malloc(length);
t->length = length;
t->actual_length = 0;
t->callback = cb_rxblast;
t->user_data = 0;
pdat = (uint16_t*)(t->buffer);
for (i = 0; i < nw-1; i++) *pdat++ = dsc_rx.cval++;
*pdat++ = 0xdead;
rc = libusb_submit_transfer(t);
if (rc) bad_usbcall_exit("libusb_submit_transfer()", rc);
nreq += 1;
if (par_trace) {
prt_time();
printf("send_msg: ep=%1d l=%5d", t->endpoint&(~0x80), t->length);
printf(" buf=%4.4x,..", ((uint16_t*)(t->buffer))[0]);
for (i = nw-2; i < nw; i++) {
printf(",%4.4x", ((uint16_t*)(t->buffer))[i]);
}
printf("\n");
}
return;
}
/*----------------------------------------------------------*/
void cb_rxblast(struct libusb_transfer *t)
{
nreq -= 1;
if (par_trace) {
prt_time();
printf("cb_rx : ep=%d l=%5d al=%5d\n",
t->endpoint&(~0x80), t->length, t->actual_length);
}
bad_transfer_exit(t, "cb_rxblast");
dsc_rx.stat_nbuf += 1;
dsc_rx.stat_nbyt += t->actual_length;
if (par_nwmsg==0 && keep_running()) que_write();
return;
}
/*----------------------------------------------------------*/
void cb_txblast(struct libusb_transfer *t, int ep, libusb_transfer_cb_fn cb,
struct dsc_queue* pdsc)
{
nreq -= 1;
if (par_trace) {
prt_time();
printf("cb_txx: ep=%d l=%5d al=%5d\n",
t->endpoint&(~0x80), t->length, t->actual_length);
}
bad_transfer_exit(t, "cb_txblast");
if (t->actual_length > 0) {
uint16_t* pdat = (uint16_t*)(t->buffer);
int nw = t->actual_length/2;
int i;
if (pdsc->stat_nbuf == 0) pdsc->cval = pdat[0];
for (i = 0; i < nw; i++) {
uint16_t dat = *pdat++;
if (pdsc->cval != dat) {
prt_time();
printf("FAIL: on ep=%d seen %4.4x expect %4.4x after %10.0f char\n",
ep&(~0x80), dat, pdsc->cval, pdsc->stat_nbyt+2*i);
pdsc->cval = dat;
}
pdsc->cval += 1;
}
}
pdsc->stat_nbuf += 1;
pdsc->stat_nbyt += t->actual_length;
if (t->actual_length < t->length) pdsc->stat_npt += 1;
if (keep_running()) que_read(ep, pdsc->par_nfrm, cb);
}
/*----------------------------------------------------------*/
void cb_tx1blast(struct libusb_transfer *t)
{
cb_txblast(t, 6, cb_tx1blast, &dsc_tx1);
return;
}
/*----------------------------------------------------------*/
void cb_tx2blast(struct libusb_transfer *t)
{
cb_txblast(t, 8, cb_tx2blast, &dsc_tx2);
return;
}
/*----------------------------------------------------------*/
void cb_txloop(struct libusb_transfer *t)
{
nreq -= 1;
if (par_trace) {
prt_time();
printf("cb_txl: ep=%d l=%5d al=%5d\n",
t->endpoint&(~0x80), t->length, t->actual_length);
}
bad_transfer_exit(t, "cb_txloop");
if (t->actual_length > 0) {
uint16_t* pdat = (uint16_t*)(t->buffer);
int nw = t->actual_length/2;
int i;
for (i = 0; i < nw; i++) {
uint16_t dat = *pdat++;
if (cur_nwmsg > 0) {
uint16_t dat_exp = (cur_nwmsg>1) ? dsc_tx1.cval++ : 0xdead;
if (dat_exp != dat) {
prt_time();
printf("FAIL: on ep=6 seen %4.4x expect %4.4x after %10.0f char\n",
dat, dat_exp, dsc_tx1.stat_nbyt+2*i);
if (cur_nwmsg>1) dsc_tx1.cval = dat + 1;
}
cur_nwmsg -= 1;
if (cur_nwmsg==0 && dat==0xdead) stat_nmsg += 1;
} else {
prt_time();
printf("FAIL: on ep=6 seen %4.4x unexpected after %10.0f char\n",
dat, dsc_tx1.stat_nbyt+2*i);
}
}
}
dsc_tx1.stat_nbuf += 1;
dsc_tx1.stat_nbyt += t->actual_length;
if (t->actual_length < t->length) dsc_tx1.stat_npt += 1;
if (cur_nwmsg==0) { /* end of message seen */
if (keep_running()) {
send_msg();
} else {
if (par_trace) { prt_time(); printf("set endpoll = 1\n"); }
endpoll = 1;
}
}
que_read(6, dsc_tx1.par_nfrm, cb_txloop);
return;
}
/*----------------------------------------------------------*/
void tx_pipe_drain(int ep)
{
unsigned char buf[16384];
int ntrans;
int rc = libusb_bulk_transfer(pUsbDevHdl, ep|0x80,
buf, sizeof(buf), &ntrans, 10);
if (rc == LIBUSB_ERROR_TIMEOUT) return;
if (rc) bad_usbcall_exit("pipe drain: libusb_bulk_transfer()", rc);
fprintf(stderr, "tst_fx2loop-I: pipe drain for ep=%d: ntrans=%d\n",
ep&(~0x80), ntrans);
return;
}
/*--------------------------------------------------------------------------*/
void do_run()
{
int rc;
int fd_timer = -1;
int i;
struct itimerspec tspec;
struct dsc_queue dsc_rx_last = dsc_rx;
struct dsc_queue dsc_tx1_last = dsc_tx1;
struct dsc_queue dsc_tx2_last = dsc_tx2;
if (par_trace) {
prt_time();
printf("rx:nf=%d,nq=%d; tx1:nf=%d,nq=%d; tx2:nf=%d,nq=%d\n",
dsc_rx.par_nfrm, dsc_rx.par_nque,
dsc_tx1.par_nfrm, dsc_tx2.par_nque,
dsc_tx2.par_nfrm, dsc_tx2.par_nque);
}
/* setup pollfd list */
fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (fd_timer < 0) bad_syscall_exit("timerfd_create() failed", fd_timer);
tspec.it_interval.tv_sec = 1;
tspec.it_interval.tv_nsec = 0;
tspec.it_value.tv_sec = 1;
tspec.it_value.tv_nsec = 0;
rc = timerfd_settime(fd_timer, 0, &tspec, NULL);
if (rc<0) bad_syscall_exit("timerfd_settime() failed", rc);
pollfd_fds[0].fd = fd_timer;
pollfd_fds[0].events = POLLIN;
pollfd_fds[0].revents = 0;
pollfd_nfds = 1;
pollfd_init();
/* setup loop */
if (par_nwmsg > 0) {
dsc_rx.par_nfrm = 0;
dsc_rx.par_nque = 0;
if (dsc_tx1.par_nfrm == 0) dsc_tx1.par_nfrm = 1;
if (dsc_tx1.par_nque == 0) dsc_tx1.par_nque = 1;
tx_pipe_drain(6); /* drain tx1 */
for (i = 0; i < dsc_tx1.par_nque; i++) /* prime tx1 */
que_read(6, dsc_tx1.par_nfrm, cb_txloop);
send_msg();
}
/* setup rxblast */
if (dsc_rx.par_nfrm > 0) {
int i;
if (dsc_rx.par_nque == 0) dsc_rx.par_nque = 1;
for (i = 0; i < dsc_rx.par_nque; i++) que_write();
}
/* setup txblast */
if (par_nwmsg==0 && dsc_tx1.par_nfrm>0) {
int i;
if (dsc_tx1.par_nque == 0) dsc_tx1.par_nque = 1;
for (i = 0; i < dsc_tx1.par_nque; i++)
que_read(6, dsc_tx1.par_nfrm, cb_tx1blast);
}
/* setup tx2blast */
if (dsc_tx2.par_nfrm > 0) {
int i;
if (dsc_tx2.par_nque == 0) dsc_tx2.par_nque = 1;
for (i = 0; i < dsc_tx2.par_nque; i++)
que_read(8, dsc_tx2.par_nfrm, cb_tx2blast);
}
t_start = get_time();
while(nreq>0 && endpoll==0) {
uint64_t tbuf;
rc = poll(pollfd_fds, pollfd_nfds, 2000);
if (rc==-1 && errno==EINTR) continue;
if (rc < 0) bad_syscall_exit("poll() failed", rc);
if (rc == 0) fprintf(stderr, "tst_fx2loop-I: poll() timeout\n");
if (par_trace) {
int i;
prt_time();
printf("poll: rc=%d:", rc);
for (i = 0; i < pollfd_nfds; i++) {
printf(" %d,%2.2x", pollfd_fds[i].fd, pollfd_fds[i].revents);
}
printf("\n");
}
if (pollfd_fds[0].revents == POLLIN) {
errno = EBADMSG; /* to be reported on short read */
rc = read(fd_timer, &tbuf, sizeof(tbuf));
if (rc != sizeof(tbuf)) bad_syscall_exit("read(fd_timer,...) failed", rc);
if (par_stat) {
prt_time();
if (par_nwmsg>0 || dsc_rx.par_nque>0) {
double nbuf = dsc_rx.stat_nbuf - dsc_rx_last.stat_nbuf;
double nbyt = dsc_rx.stat_nbyt - dsc_rx_last.stat_nbyt;
printf("rx: %5.0f,%7.1f ", nbuf, nbyt/1000.);
}
if (dsc_tx1.par_nque > 0 ) {
double nbuf = dsc_tx1.stat_nbuf - dsc_tx1_last.stat_nbuf;
double nbyt = dsc_tx1.stat_nbyt - dsc_tx1_last.stat_nbyt;
printf("tx1: %5.0f,%7.1f ", nbuf, nbyt/1000.);
}
if (dsc_tx2.par_nque > 0 ) {
double nbuf = dsc_tx2.stat_nbuf - dsc_tx2_last.stat_nbuf;
double nbyt = dsc_tx2.stat_nbyt - dsc_tx2_last.stat_nbyt;
printf("tx2: %5.0f,%7.1f ", nbuf, nbyt/1000.);
}
printf("\n");
dsc_rx_last = dsc_rx;
dsc_tx1_last = dsc_tx1;
dsc_tx2_last = dsc_tx2;
}
} else {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
rc = libusb_handle_events_timeout(pUsbContext, &tv);
//setting the timeval pointer to NULL should work, but doesn't (in 1.0.6)
//rc = libusb_handle_events_timeout(pUsbContext, 0);
if (rc) bad_usbcall_exit("libusb_handle_events_timeout()", rc);
}
}
return;
}
/*--------------------------------------------------------------------------*/
void do_stat()
{
printf("run statistics:\n");
printf("runtime : %13.3f\n", get_time()-t_start);
printf("nbuf_rx : %13.0f\n", dsc_rx.stat_nbuf);
printf("nbyt_rx : %13.0f\n", dsc_rx.stat_nbyt);
printf("nbuf_tx1 : %13.0f\n", dsc_tx1.stat_nbuf);
printf("nbyt_tx1 : %13.0f\n", dsc_tx1.stat_nbyt);
printf("npt_tx1 : %13.0f\n", dsc_tx1.stat_npt);
printf("nbuf_tx2 : %13.0f\n", dsc_tx2.stat_nbuf);
printf("nbyt_tx2 : %13.0f\n", dsc_tx2.stat_nbyt);
printf("npt_tx2 : %13.0f\n", dsc_tx2.stat_npt);
printf("nmsg : %13.0f\n", stat_nmsg);
return;
}
/*--------------------------------------------------------------------------*/
void usb_claim()
{
int rc = libusb_claim_interface(pUsbDevHdl, 0);
if (rc) bad_usbcall_exit("libusb_claim_interface()", rc);
return;
}
/*--------------------------------------------------------------------------*/
void usb_release()
{
int rc = libusb_release_interface(pUsbDevHdl, 0);
if (rc) bad_usbcall_exit("libusb_release_interface()", rc);
return;
}
/*--------------------------------------------------------------------------*/
char* usb_strerror(int rc)
{
switch(rc) {
case LIBUSB_SUCCESS:
return "";
case LIBUSB_ERROR_IO:
return "Input/output error";
case LIBUSB_ERROR_INVALID_PARAM:
return "Invalid parameter";
case LIBUSB_ERROR_ACCESS:
return "Access denied";
case LIBUSB_ERROR_NO_DEVICE:
return "No such device";
case LIBUSB_ERROR_NOT_FOUND:
return "Entity not found";
case LIBUSB_ERROR_BUSY:
return "Resource busy";
case LIBUSB_ERROR_TIMEOUT:
return "Operation timed out";
case LIBUSB_ERROR_OVERFLOW:
return "Overflow";
case LIBUSB_ERROR_PIPE:
return "Pipe error";
case LIBUSB_ERROR_INTERRUPTED:
return "System call interrupted";
case LIBUSB_ERROR_NO_MEM:
return "Insufficient memory";
case LIBUSB_ERROR_NOT_SUPPORTED:
return "Operation not supported";
case LIBUSB_ERROR_OTHER:
return "Other error";
default:
return "Unknown libusb error code";
}
}
/*--------------------------------------------------------------------------*/
void prt_time(void)
{
struct timeval tv;
struct timezone tz;
struct tm tmval;
gettimeofday(&tv, &tz);
localtime_r(&tv.tv_sec, &tmval);
printf("%02d:%02d:%02d.%06d: ", tmval.tm_hour, tmval.tm_min, tmval.tm_sec,
(int) tv.tv_usec);
}
/*--------------------------------------------------------------------------*/
double get_time(void)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return (double)tv.tv_sec + 1.e-6 * (double)tv.tv_usec;
}
/*--------------------------------------------------------------------------*/
void bad_syscall_exit(const char* text, int rc)
{
fprintf(stderr, "tst_fx2loop-F: %s failed with rc=%d errno=%d : %s\n",
text, rc, errno, strerror(errno));
exit(EXIT_FAILURE);
}
/*--------------------------------------------------------------------------*/
void bad_usbcall_exit(const char* text, int rc)
{
fprintf(stderr, "tst_fx2loop-F: %s failed with rc=%d: %s\n",
text, rc, usb_strerror(rc));
exit(EXIT_FAILURE);
}
/*--------------------------------------------------------------------------*/
void bad_transfer_exit(struct libusb_transfer *t, const char* text)
{
const char* etext = 0;
if (t->status == LIBUSB_TRANSFER_ERROR) etext = "ERROR";
if (t->status == LIBUSB_TRANSFER_STALL) etext = "STALL";
if (t->status == LIBUSB_TRANSFER_NO_DEVICE) etext = "NO_DEVICE";
if (t->status == LIBUSB_TRANSFER_OVERFLOW) etext = "OVERFLOW";
if (etext == 0) return;
fprintf(stderr, "tst_fx2loop-F: transfer failure in %s on ep=%d: %s\n",
text, (int)(t->endpoint&(~0x80)), etext);
exit(EXIT_FAILURE);
}