OpenCores
URL https://opencores.org/ocsvn/usb_fpga_2_14/usb_fpga_2_14/trunk

Subversion Repositories usb_fpga_2_14

[/] [usb_fpga_2_14/] [trunk/] [capi/] [c/] [memfifo.c] - Rev 2

Compare with Previous | Blame | View Log

/*%
   ZTEX Core API for C with examples
   Copyright (C) 2009-2017 ZTEX GmbH.
   http://www.ztex.de
 
   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0. If a copy of the MPL was not distributed with this file,
   You can obtain one at http://mozilla.org/MPL/2.0/.
 
   Alternatively, the contents of this file may be used under the terms
   of the GNU General Public License Version 3, as described below:
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3 as
   published by the Free Software Foundation.
 
   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 more details.
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, see http://www.gnu.org/licenses/.
%*/
 
/** @file
memfifo example for C.
This example demonstrates the usage of the C API and the high speed interface of the default firmware.
 
It performs certain tests (device and data integrity, read-write tests, performance) using the memory FIFO as described on
<a href="http://wiki.ztex.de/doku.php?id=en:ztex_boards:ztex_fpga_boards:memfifo:memfifo">memfifo example</a>.
 
The correct bitstream is detected and found automatically if the binary is executed from 
the directory tree of the SDK. Otherwise it can be specified with parameter '-s'.
 
Full list of options can be obtained with '-h'
@include memfifo.c
@cond memfifo
*/
 
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <libusb-1.0/libusb.h>
 
#include "ztex.h"
 
#define BULK_BUF_SIZE 4*1024*1024
#define RW_SIZE 65000			// must be smaller then FIFO size, 64K on USB-FPGA Module 2.01
 
static char* prog_name = NULL;		// name of the program
 
static int paramerr(const char* format,...)
{
    fprintf(stderr, "Usage: %s options\n",prog_name);
    fprintf(stderr, "  -h                           Display this usage information\n"
		    "  -fu <vendor ID>:<product ID> Select device by USB IDs, default: 0x221A:0x100, <0:ignore ID\n"
		    "  -fd <bus>:<device>           Select device by bus number and device address\n"
		    "  -fs <string>                 Select device by serial number string\n"
		    "  -fp <string>                 Select device by product string\n"
		    "  -s <path>                    Additional search path for bitstream, default '.."DIRSEP".."DIRSEP"examples"DIRSEP"memfifo'\n"
		    "  -r                           Reset device (default: reset configuration only)\n"
		    "  -i                           Print device info\n"
		    "  -p                           Print matching USB devices\n"
		    "  -pa                          Print all USB devices\n"
	    );
    if ( format ) {
	va_list args;
	va_start(args,format);
    	vfprintf(stderr, format, args);
    	va_end(args);
	return 1;
    }
    return 0;
}
 
int main(int argc, char **argv)
{
    int id_vendor = 0x221A;  	// ZTEX vendor ID
    int id_product = 0x100; 	// default product ID for ZTEX firmware
    int status = 0;
    libusb_device **devs = NULL;
    int print_all=0, print=0, print_info=0, reset_dev=0;
    int busnum = -1, devnum = -1;
    char *sn_string = NULL, *product_string = NULL;
    libusb_device_handle *handle = NULL;
    ztex_device_info info;
    char *bitstream_fn = NULL, *bitstream_path = NULL;
    char sbuf[8192];
    unsigned char *mbuf = NULL;
    int transferred, size;
    struct timeval tv1,tv2;
 
    // process parameters
    prog_name = argv[0];
    for (int i=1; i<argc; i++) {
	if ( !strcmp(argv[i],"-h") ) return paramerr(NULL);
	else if ( !strcmp(argv[i],"-p") ) print=1;
	else if ( !strcmp(argv[i],"-pa") ) print_all=1;
	else if ( !strcmp(argv[i],"-i") ) print_info=1;
	else if ( !strcmp(argv[i],"-r") ) reset_dev=1;
	else if ( !strcmp(argv[i],"-fu") ) {
	    i++;
	    if (i>=argc || sscanf(argv[i],"%i:%i", &id_vendor, &id_product)!=2 ) return paramerr("Error: <vendor ID>:<product ID> expected after -fu\n");
	}
	else if ( !strcmp(argv[i],"-fd") ) {
	    i++;
	    if (i>=argc || sscanf(argv[i],"%i:%i", &busnum, &devnum)!=2 ) return paramerr("Error: <bus>:<device> expected after -fd\n");
	}
	else if ( !strcmp(argv[i],"-fs") ) {
	    i++;
	    if (i>=argc ) return paramerr("Error: <string> expected after -fs\n");
	    sn_string = argv[i];
	}
	else if ( !strcmp(argv[i],"-fp") ) {
	    i++;
	    if (i>=argc ) return paramerr("Error: <string> expected after -fp\n");
	    product_string = argv[i];
	}
	else if ( !strcmp(argv[i],"-s") ) {
	    i++;
	    if (i>=argc ) return paramerr("Error: <path> expected after -s\n");
	    bitstream_path = argv[i];
	}
	else return paramerr("Error: Invalid parameter %s\n", argv[i]);
    }
 
 
    // INIT libusb
    status = libusb_init(NULL);
    if (status < 0) {
    	fprintf(stderr,"Error: Unable to init libusb: %s\n", libusb_error_name(status));
	return 1;
    }
 
    // find all USB devices
    status = libusb_get_device_list(NULL, &devs);
    if (status < 0) {
	fprintf(stderr,"Error: Unable to get device list: %s\n", libusb_error_name(status));
	goto err;
    }
 
    // print bus info or find device
    int dev_idx = ztex_scan_bus(sbuf, sizeof(sbuf), devs, print_all ? -1 : print ? 1 : 0, id_vendor, id_product, busnum, devnum, sn_string, product_string);
    printf(sbuf);
    fflush(stdout);
    if ( print || print_all ) {
	status = 0;
	goto noerr;
    } else if ( dev_idx<0 ) {
	if (dev_idx==-1) fprintf(stderr,"Error: No device found\n");
	goto err;
    }
 
    // open device
    status = libusb_open(devs[dev_idx], &handle);
    if (status < 0) {
	fprintf(stderr,"Error: Unable to open device: %s\n", libusb_error_name(status));
	goto err;
    }
    libusb_free_device_list(devs, 1);
    devs=NULL;
 
    // reset configuration or device
   if ( ! reset_dev ) {
	status = libusb_set_configuration(handle,-1);
	if (status < 0) {
	    fprintf(stderr,"Warning: Unable to unconfigure device: %s, trying to reset it\n", libusb_error_name(status));
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
	    fprintf(stderr,"Due to limitations of Windows neither this nor device reset works. This may cause further errors ...\n");
#endif    
	    reset_dev = 1;
	}
    }
    if ( reset_dev ) {
	status = libusb_reset_device(handle);
	if (status < 0) {
	    fprintf(stderr,"Error: Unable to reset device: %s\n", libusb_error_name(status));
	    goto err;
	}
    }
    status = libusb_set_configuration(handle,1);
    if (status < 0) fprintf(stderr,"Warning: Unable to set configuration 1: %s\n", libusb_error_name(status));
    fflush(stderr);
 
    // get and print device info
    status = ztex_get_device_info(handle, &info);
    if ( status < 0 ) {
	fprintf(stderr,"Error: Unable to get device info: %s\n", libusb_error_name(status));
	goto err;
    }
    if ( print_info ) {
	ztex_print_device_info( sbuf, sizeof(sbuf), &info );
	printf(sbuf);
	status = ztex_get_fpga_config(handle);
	if ( status < 0 ) {
	    fprintf(stderr,"Error: Unable to get FPGA configuration state: %s\n", libusb_error_name(status));
	    goto err;
	}
	printf("FPGA: %s\n", status==0 ? "unconfigured" : "configured");
	status = 0;
	goto noerr;
    }
 
    // find bitstream
    bitstream_fn = ztex_find_bitstream( &info, bitstream_path ? bitstream_path : ".."DIRSEP".."DIRSEP"examples"DIRSEP"memfifo" , "memfifo");
    if ( bitstream_fn )  {
	printf("Using bitstream '%s'\n", bitstream_fn);
	fflush(stdout);
    }
    else {
        fprintf(stderr,"Warning: Bitstream not found\n");
        goto nobitstream;
    }
 
    // read and upload bitstream
    FILE *fd = fopen(bitstream_fn, "rb");
    if ( fd == NULL ) {
        fprintf(stderr,"Warning: Error opening file '%s'\n", bitstream_fn);
        goto nobitstream;
    }
    status = ztex_upload_bitstream(sbuf,sizeof(sbuf),handle,&info,fd,-1);
    fclose(fd);
    fprintf(stderr,sbuf);
 
nobitstream:
    fflush(stderr);
    // check config
    status = ztex_get_fpga_config(handle);
    if ( status < 0 ) {
        fprintf(stderr,"Error: Unable to get FPGA configuration state: %s\n", libusb_error_name(status));
        goto err;
    } else if ( status == 0 ) {
        fprintf(stderr,"Error: FPGA not configured\n");
        goto err;
    }
 
    // claim interface
    status = libusb_claim_interface(handle, 0); 
    if ( status < 0 ) {
        fprintf(stderr,"Error claiming interface 0: %s\n", libusb_error_name(status));
        goto err;
    }
 
    mbuf = malloc(BULK_BUF_SIZE);
    if ( !mbuf ) {
        fprintf(stderr,"Error allocating %d bytes\n", BULK_BUF_SIZE);
        goto err;
    }
 
// verify mode and prepare device if necessary
    if ( ztex_default_gpio_ctl(handle,0,0) ) {
	fprintf(stderr,"Warning: wrong initial mode, switching to mode 0\n");
	ztex_default_gpio_ctl(handle,7,0);
        ztex_default_reset(handle,0);
        libusb_bulk_transfer(handle, info.default_in_ep, mbuf, BULK_BUF_SIZE, &transferred, 250);
    } else {
	status = libusb_bulk_transfer(handle, info.default_in_ep, mbuf, BULK_BUF_SIZE, &transferred, 250);
	if ( (status>=0) && (transferred>0) ) fprintf(stderr,"Warning: found %d bytes in EZ-USB FIFO\n", transferred);
    }
    fflush(stderr);
 
// test 1: read-write test (mode 0)
    for (int i=0; i<RW_SIZE; i+=2) {
	mbuf[i] = (i>>1) & 127;
	mbuf[i+1] = 128 | ((i >> 8 ) & 127);
    }
    TWO_TRIES(status, libusb_bulk_transfer(handle, info.default_out_ep, mbuf, RW_SIZE, &transferred, 2000));
    if ( status < 0 ) {
        fprintf(stderr,"Bulk write error: %s\n", libusb_error_name(status));
        goto err;
    }
    printf("Read-write test, short packet test: wrote %d Bytes\n", transferred);
    fflush(stdout);
 
    TWO_TRIES(status, libusb_bulk_transfer(handle, info.default_in_ep, mbuf, BULK_BUF_SIZE, &transferred, 4000));
    if ( status < 0 ) {
        fprintf(stderr,"Bulk read error: %s\n", libusb_error_name(status));
        goto err;
    }
    {
	int i=mbuf[0]>>7;
	int j=mbuf[i] | ((mbuf[i+1] & 127)<<7);
	printf("Read-write test: read (%d=%d*512+%d) Bytes.  %d leading Bytes lost", transferred, transferred/512, transferred&511, j*2  );
	if ( j ) printf("(This may be platform specific)" );
	size = 0;
	for (i=i+2; i+1<transferred; i+=2) {
	    int k = mbuf[i] | ((mbuf[i+1] & 127)<<7);
	    if ( k != ((j+1) & 0x3fff) ) size +=1;
	    j=k;
        }
	printf(". %d data errors.  %d Bytes remaining in FIFO due to memory transfer granularity\n", size, RW_SIZE-transferred);
	fflush(stdout);
    }
 
// test 2: read rate test using test data generator (mode 1)
    // reset application and set mode 1
    ztex_default_reset(handle,0);
    status = ztex_default_gpio_ctl(handle,7,1);
    if ( status < 0 ) {
        fprintf(stderr,"Error setting GPIO's: %s\n", libusb_error_name(status));
        goto err;
    }
 
    // read data and measure time, first packets are ignored because EZ-USB buffer may be filled
    printf("Measuring read rate using libusb_bulk_transfer ... \n");
    fflush(stdout);
    size=0;
    for (int i=0; i<55; i++) {
	if ( i==5 ) gettimeofday(&tv1, NULL);
	TWO_TRIES( status, libusb_bulk_transfer(handle, info.default_in_ep, mbuf, BULK_BUF_SIZE, &transferred, 2000));
	if ( status < 0 ) {
    	    fprintf(stderr,"Bulk read error: %s\n", libusb_error_name(status));
    	    goto err;
	}
	if ( (i==0) && ( (mbuf[0]!=0) && (mbuf[1]!=239) ) ) {
	    fprintf(stderr,"Warning: Invalid start of data: %d %d, leading data may went lost\n",mbuf[0], mbuf[1]);
	}
	if ( i>=5 ) size+=transferred;
    }
    gettimeofday(&tv2, NULL);
    printf("Read %.1f MB at %.1f MB/s\n", size/(1024.0*1024.0), size/( (tv2.tv_sec-tv1.tv_sec)*1e6 + (tv2.tv_usec-tv1.tv_usec) )); 
    fflush(stdout);
 
    // release resources
    status = 0;
    goto noerr;
err:
    status = 1;
noerr:
    if ( mbuf ) free(mbuf);
    if ( bitstream_fn ) free(bitstream_fn);
    if ( handle ) {
	libusb_release_interface(handle,0);
	libusb_close(handle);
    }
    if ( devs ) libusb_free_device_list(devs, 1);
    libusb_exit(NULL);
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
    printf("Press <return> to quit\n");
    fflush(NULL);
    fgetc(stdin);
#endif    
    return status;
}
///@endcond
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.