I am trying to create a simple test program where in a main while loop I initialize and startup a callback, run for a short while, close the device and repeat. Although it looks like everything shuts down cleanly, the second time through the loop the callback
only reads data for a short burst then everything shuts down again. I have been trying to debug the ftdi and libusb libraries but have gotten nowhere.
The interesting thing is that if I use ftdi_read_data instead of the callback the while loop works as expected.
I am using version 1.3 of libftdi.
Thanks in advance.
********************** TEST CODE ***************************
#include <iostream>
#include <csignal>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <libftdi1/ftdi.h>
static int exitRequested = 0;
bool showDebug = false;
int countDown = 2500;
void sighandler(int sig) {
std::cout << "Caught a signal: " << sig << ", exiting." << std::endl;
exitRequested = 1;
}
void usage() {
std::cout << "Usage: test_tx -d device" << std::endl;
}
static int readCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata) {
if (length) {
if (showDebug)
printf("USB Read: %i bytes\n", length);
}
else {
// std::cout << "nope" << std::endl;
}
// std::cout << "in readback: " << countDown << std::endl;
if (countDown-- <= 0) {
exitRequested = 1;
}
if (progress) {
fprintf(stderr, "%10.02fs total time %9.3f MiB captured %7.1f kB/s curr rate - %7.3f Mbps\n",
progress->totalTime,
progress->current.totalBytes / (1024.0 * 1024.0),
progress->currentRate / 1024.0,
progress->currentRate * 8 / 1000000
);
}
return exitRequested ? 1 : 0;
}
int main(int argc, char **argv) {
// struct ftdi_context *ftdi;
// struct ftdi_version_info version;
unsigned int device = 3;
int usbTransferSize = 65536;
unsigned char latency = 2;
int err;
int packetsPerTransfer = 32;
int numTransfers = 32;
unsigned char readBuffer[102400];
int res = -1;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'd':
if (argc >= i + 1) {
device = atoi(argv[i+1]);
++i;
}
break;
default:
usage();
return -1;
break;
}
}
}
signal(SIGINT, sighandler);
signal(SIGQUIT, sighandler);
while (1) {
struct ftdi_context *ftdi;
struct ftdi_version_info version;
if ((ftdi = ftdi_new()) == 0) {
printf("error creating data structures\n");
return EXIT_FAILURE;
}
version = ftdi_get_library_version();
printf("Initialized libftdi %s (major: %d, minor: %d, micro: %d, snapshot ver: %s)\n",
version.version_str, version.major, version.minor, version.micro,
version.snapshot_str);
fflush(stdout);
if (ftdi_set_interface(ftdi, INTERFACE_A) < 0) {
printf("error setting interface\n");
ftdi_free(ftdi);
return EXIT_FAILURE;
}
std::cout << "-------- GOING TO OPEN USB DEVICE: " << device << " --------" << std::endl;
if (ftdi_usb_open_desc_index(ftdi, 0x0403, 0x6014, NULL, NULL, device) < 0) {
// if (ftdi_usb_open_desc_index(ftdi, 0x0403, 0x6001, NULL, NULL, device) < 0) {
printf("error opening usb device %i\n", device);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
/* A timeout value of 1 results in may skipped blocks */
if(ftdi_set_latency_timer(ftdi, latency)) {
fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// set chunk sizes???
if (ftdi_write_data_set_chunksize(ftdi, usbTransferSize)) {
printf("couldn't set write chunksize\n");
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
if (ftdi_read_data_set_chunksize(ftdi, usbTransferSize)) {
printf("couldn't set read chunksize\n");
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
if (ftdi_setflowctrl(ftdi, SIO_RTS_CTS_HS)) {
printf("couldn't set flow control\n");
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
/* We don't know in what state we are, switch to reset*/
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) {
fprintf(stderr,"Can't reset mode\n");
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
/* Purge anything remaining in the buffers*/
if (ftdi_usb_purge_buffers(ftdi) < 0) {
fprintf(stderr,"Can't Purge\n");
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
/* Start the transfers only when everything has been set up.
* Otherwise the transfers start stuttering and the PC not
* fetching data for several to several ten milliseconds
* and we skip blocks
*/
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
{
fprintf(stderr,"Can't set synchronous fifo mode: %s\n", ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// testing callback
err = ftdi_readstream(ftdi, readCallback, NULL, packetsPerTransfer, numTransfers);
printf("done with readstream....\n");
printf("checking ret from readstream: %i\n", err);
// testing regular read...
// for (countDown = 2500; countDown > 0; countDown--) {
// printf("checking countDown: %i\n", countDown);
// res = ftdi_read_data(ftdi, readBuffer, 1024);
// if (res > 0) {
// // printf("just read %i bytes\n", res);
// }
// else {
// printf("uhh what... %i\n", res);
// }
// }
// std::cout << "Done regular read...." << std::endl;
// reset bit mode?
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) {
fprintf(stderr,"Can't set reset bitmode: %s\n", ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
err = ftdi_usb_purge_buffers(ftdi);
printf("checking ret from purge buffers: %i\n", err);
err = ftdi_usb_reset(ftdi);
printf("checking ret from usb reset: %i\n", err);
//
err = ftdi_usb_close(ftdi);
printf("checking ret from usb close: %i\n", err);
ftdi_deinit(ftdi);
ftdi_free(ftdi);
signal(SIGINT, SIG_DFL);
std::cout << "going to try again?" << std::endl;
sleep(5);
ftdi = NULL;
countDown = 2500;
}
return 0;
}