00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #include <sys/time.h>
00045 #include <libusb.h>
00046
00047 #include "ftdi.h"
00048
00049 typedef struct
00050 {
00051 FTDIStreamCallback *callback;
00052 void *userdata;
00053 int packetsize;
00054 int activity;
00055 int result;
00056 FTDIProgressInfo progress;
00057 } FTDIStreamState;
00058
00059
00060
00061
00062
00063
00064
00065 static void LIBUSB_CALL
00066 ftdi_readstream_cb(struct libusb_transfer *transfer)
00067 {
00068 FTDIStreamState *state = transfer->user_data;
00069 int packet_size = state->packetsize;
00070
00071 state->activity++;
00072 if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
00073 {
00074 int i;
00075 uint8_t *ptr = transfer->buffer;
00076 int length = transfer->actual_length;
00077 int numPackets = (length + packet_size - 1) / packet_size;
00078 int res = 0;
00079
00080 for (i = 0; i < numPackets; i++)
00081 {
00082 int payloadLen;
00083 int packetLen = length;
00084
00085 if (packetLen > packet_size)
00086 packetLen = packet_size;
00087
00088 payloadLen = packetLen - 2;
00089 state->progress.current.totalBytes += payloadLen;
00090
00091 res = state->callback(ptr + 2, payloadLen,
00092 NULL, state->userdata);
00093
00094 ptr += packetLen;
00095 length -= packetLen;
00096 }
00097 if (res)
00098 {
00099 free(transfer->buffer);
00100 libusb_free_transfer(transfer);
00101 }
00102 else
00103 {
00104 transfer->status = -1;
00105 state->result = libusb_submit_transfer(transfer);
00106 }
00107 }
00108 else
00109 {
00110 fprintf(stderr, "unknown status %d\n",transfer->status);
00111 state->result = LIBUSB_ERROR_IO;
00112 }
00113 }
00114
00121 static double
00122 TimevalDiff(const struct timeval *a, const struct timeval *b)
00123 {
00124 return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
00125 }
00126
00147 int
00148 ftdi_readstream(struct ftdi_context *ftdi,
00149 FTDIStreamCallback *callback, void *userdata,
00150 int packetsPerTransfer, int numTransfers)
00151 {
00152 struct libusb_transfer **transfers;
00153 FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 };
00154 int bufferSize = packetsPerTransfer * ftdi->max_packet_size;
00155 int xferIndex;
00156 int err = 0;
00157
00158
00159 if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H))
00160 {
00161 fprintf(stderr,"Device doesn't support synchronous FIFO mode\n");
00162 return 1;
00163 }
00164
00165
00166 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
00167 {
00168 fprintf(stderr,"Can't reset mode\n");
00169 return 1;
00170 }
00171
00172
00173 if (ftdi_usb_purge_buffers(ftdi) < 0)
00174 {
00175 fprintf(stderr,"Can't Purge\n");
00176 return 1;
00177 }
00178
00179
00180
00181
00182
00183 transfers = calloc(numTransfers, sizeof *transfers);
00184 if (!transfers)
00185 {
00186 err = LIBUSB_ERROR_NO_MEM;
00187 goto cleanup;
00188 }
00189
00190 for (xferIndex = 0; xferIndex < numTransfers; xferIndex++)
00191 {
00192 struct libusb_transfer *transfer;
00193
00194 transfer = libusb_alloc_transfer(0);
00195 transfers[xferIndex] = transfer;
00196 if (!transfer)
00197 {
00198 err = LIBUSB_ERROR_NO_MEM;
00199 goto cleanup;
00200 }
00201
00202 libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
00203 malloc(bufferSize), bufferSize,
00204 ftdi_readstream_cb,
00205 &state, 0);
00206
00207 if (!transfer->buffer)
00208 {
00209 err = LIBUSB_ERROR_NO_MEM;
00210 goto cleanup;
00211 }
00212
00213 transfer->status = -1;
00214 err = libusb_submit_transfer(transfer);
00215 if (err)
00216 goto cleanup;
00217 }
00218
00219
00220
00221
00222
00223
00224 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
00225 {
00226 fprintf(stderr,"Can't set synchronous fifo mode: %s\n",
00227 ftdi_get_error_string(ftdi));
00228 goto cleanup;
00229 }
00230
00231
00232
00233
00234
00235 gettimeofday(&state.progress.first.time, NULL);
00236
00237 do
00238 {
00239 FTDIProgressInfo *progress = &state.progress;
00240 const double progressInterval = 1.0;
00241 struct timeval timeout = { 0, ftdi->usb_read_timeout * 1000};
00242 struct timeval now;
00243
00244 int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
00245 if (err == LIBUSB_ERROR_INTERRUPTED)
00246
00247 err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
00248 if (!state.result)
00249 {
00250 state.result = err;
00251 }
00252 if (state.activity == 0)
00253 state.result = 1;
00254 else
00255 state.activity = 0;
00256
00257
00258 gettimeofday(&now, NULL);
00259 if (TimevalDiff(&now, &progress->current.time) >= progressInterval)
00260 {
00261 progress->current.time = now;
00262 progress->totalTime = TimevalDiff(&progress->current.time,
00263 &progress->first.time);
00264
00265 if (progress->prev.totalBytes)
00266 {
00267
00268
00269 double currentTime;
00270
00271 currentTime = TimevalDiff(&progress->current.time,
00272 &progress->prev.time);
00273
00274 progress->totalRate =
00275 progress->current.totalBytes /progress->totalTime;
00276 progress->currentRate =
00277 (progress->current.totalBytes -
00278 progress->prev.totalBytes) / currentTime;
00279 }
00280
00281 state.callback(NULL, 0, progress, state.userdata);
00282 progress->prev = progress->current;
00283
00284 }
00285 } while (!state.result);
00286
00287
00288
00289
00290
00291 cleanup:
00292 fprintf(stderr, "cleanup\n");
00293 if (transfers)
00294 free(transfers);
00295 if (err)
00296 return err;
00297 else
00298 return state.result;
00299 }
00300