X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi_stream.c;h=2ed39b3f4e6a2c29d1811d2f62f659749bef2c85;hp=3f12ebc5462ca8672a2c01f6f9a20b490a2042d7;hb=5a37dcb718d42bcf51bf87c3f8a257e3480686ec;hpb=40da63b1f8924d2c4d1e34d137dc7d12b5b1c643 diff --git a/src/ftdi_stream.c b/src/ftdi_stream.c index 3f12ebc..2ed39b3 100644 --- a/src/ftdi_stream.c +++ b/src/ftdi_stream.c @@ -4,7 +4,7 @@ copyright : (C) 2009 Micah Dowty 2010 Uwe Bonnes email : opensource@intra2net.com ***************************************************************************/ - + /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -13,7 +13,7 @@ * * ***************************************************************************/ -/* Adapted from +/* Adapted from * fastftdi.c - A minimal FTDI FT232H interface for which supports bit-bang * mode, but focuses on very high-performance support for * synchronous FIFO mode. Requires libusb-1.0 @@ -41,6 +41,8 @@ #include #include +#include +#include #include "ftdi.h" @@ -49,67 +51,65 @@ typedef struct FTDIStreamCallback *callback; void *userdata; int packetsize; + int activity; int result; FTDIProgressInfo progress; } FTDIStreamState; -static void +/* Handle callbacks + * + * With Exit request, free memory and release the transfer + * + * state->result is only set when some error happens + */ +static void LIBUSB_CALL ftdi_readstream_cb(struct libusb_transfer *transfer) { - FTDIStreamState *state = transfer->user_data; - int packet_size = state->packetsize; - - if(transfer->status & LIBUSB_TRANSFER_CANCELLED) - { - free(transfer->buffer); - libusb_free_transfer(transfer); - return; - } - if (state->result == 0) - { - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - { - int i; - uint8_t *ptr = transfer->buffer; - int length = transfer->actual_length; - int numPackets = (length + packet_size - 1) / packet_size; - - for (i = 0; i < numPackets; i++) - { - int payloadLen; - int packetLen = length; - - if (packetLen > packet_size) - packetLen = packet_size; - - payloadLen = packetLen - 2; - state->progress.current.totalBytes += payloadLen; - - state->result = state->callback(ptr + 2, payloadLen, - NULL, state->userdata); - if (state->result) - break; - - ptr += packetLen; - length -= packetLen; - } - - - } - else - { - fprintf(stderr, "unknown status %d\n",transfer->status); - state->result = LIBUSB_ERROR_IO; - } - } - else - fprintf(stderr,"state->result %d\n", state->result); - - if (state->result == 0) - { - transfer->status = -1; - state->result = libusb_submit_transfer(transfer); - } + FTDIStreamState *state = transfer->user_data; + int packet_size = state->packetsize; + + state->activity++; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + int i; + uint8_t *ptr = transfer->buffer; + int length = transfer->actual_length; + int numPackets = (length + packet_size - 1) / packet_size; + int res = 0; + + for (i = 0; i < numPackets; i++) + { + int payloadLen; + int packetLen = length; + + if (packetLen > packet_size) + packetLen = packet_size; + + payloadLen = packetLen - 2; + state->progress.current.totalBytes += payloadLen; + + res = state->callback(ptr + 2, payloadLen, + NULL, state->userdata); + + ptr += packetLen; + length -= packetLen; + } + if (res) + { + free(transfer->buffer); + libusb_free_transfer(transfer); + } + else + { + transfer->status = -1; + state->result = libusb_submit_transfer(transfer); + } + } + else + { + fprintf(stderr, "unknown status %d\n",transfer->status); + state->result = LIBUSB_ERROR_IO; + } } /** @@ -121,7 +121,7 @@ ftdi_readstream_cb(struct libusb_transfer *transfer) static double TimevalDiff(const struct timeval *a, const struct timeval *b) { - return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec); + return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec); } /** @@ -146,22 +146,43 @@ TimevalDiff(const struct timeval *a, const struct timeval *b) int ftdi_readstream(struct ftdi_context *ftdi, - FTDIStreamCallback *callback, void *userdata, - int packetsPerTransfer, int numTransfers) + FTDIStreamCallback *callback, void *userdata, + int packetsPerTransfer, int numTransfers) { struct libusb_transfer **transfers; - FTDIStreamState state = { callback, userdata, ftdi->max_packet_size }; + FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 }; int bufferSize = packetsPerTransfer * ftdi->max_packet_size; int xferIndex; int err = 0; - fprintf(stderr, "ftdi_readstream\n"); + /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/ + if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H)) + { + fprintf(stderr,"Device doesn't support synchronous FIFO mode\n"); + return 1; + } + + /* 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"); + return 1; + } + + /* Purge anything remaining in the buffers*/ + if (ftdi_usb_purge_buffers(ftdi) < 0) + { + fprintf(stderr,"Can't Purge\n"); + return 1; + } + /* * Set up all transfers */ transfers = calloc(numTransfers, sizeof *transfers); - if (!transfers) { + if (!transfers) + { err = LIBUSB_ERROR_NO_MEM; goto cleanup; } @@ -172,17 +193,19 @@ ftdi_readstream(struct ftdi_context *ftdi, transfer = libusb_alloc_transfer(0); transfers[xferIndex] = transfer; - if (!transfer) { + if (!transfer) + { err = LIBUSB_ERROR_NO_MEM; goto cleanup; } libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep, - malloc(bufferSize), bufferSize, - ftdi_readstream_cb, + malloc(bufferSize), bufferSize, + ftdi_readstream_cb, &state, 0); - if (!transfer->buffer) { + if (!transfer->buffer) + { err = LIBUSB_ERROR_NO_MEM; goto cleanup; } @@ -194,13 +217,13 @@ ftdi_readstream(struct ftdi_context *ftdi, } /* 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 + * 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\n", + fprintf(stderr,"Can't set synchronous fifo mode: %s\n", ftdi_get_error_string(ftdi)); goto cleanup; } @@ -215,14 +238,21 @@ ftdi_readstream(struct ftdi_context *ftdi, { FTDIProgressInfo *progress = &state.progress; const double progressInterval = 1.0; - struct timeval timeout = { 0, ftdi->usb_read_timeout }; + struct timeval timeout = { 0, ftdi->usb_read_timeout * 1000}; struct timeval now; - int err = libusb_handle_events_timeout(NULL, &timeout); + int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); + if (err == LIBUSB_ERROR_INTERRUPTED) + /* restart interrupted events */ + err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); if (!state.result) { state.result = err; } + if (state.activity == 0) + state.result = 1; + else + state.activity = 0; // If enough time has elapsed, update the progress gettimeofday(&now, NULL); @@ -241,14 +271,14 @@ ftdi_readstream(struct ftdi_context *ftdi, currentTime = TimevalDiff(&progress->current.time, &progress->prev.time); - progress->totalRate = - progress->current.totalBytes /progress->totalTime; - progress->currentRate = - (progress->current.totalBytes - - progress->prev.totalBytes) / currentTime; + progress->totalRate = + progress->current.totalBytes /progress->totalTime; + progress->currentRate = + (progress->current.totalBytes - + progress->prev.totalBytes) / currentTime; } - state.result = state.callback(NULL, 0, progress, state.userdata); + state.callback(NULL, 0, progress, state.userdata); progress->prev = progress->current; } @@ -258,22 +288,10 @@ ftdi_readstream(struct ftdi_context *ftdi, * Cancel any outstanding transfers, and free memory. */ - cleanup: +cleanup: fprintf(stderr, "cleanup\n"); - if (transfers) { - int i; - for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) - { - struct libusb_transfer *transfer = transfers[xferIndex]; - - if (transfer) { - libusb_cancel_transfer(transfer); - } - } - libusb_handle_events(NULL); + if (transfers) free(transfers); - } - if (err) return err; else