|
libftdi1
1.0
|
00001 /*************************************************************************** 00002 ftdi_stream.c - description 00003 ------------------- 00004 copyright : (C) 2009 Micah Dowty 2010 Uwe Bonnes 00005 email : opensource@intra2net.com 00006 ***************************************************************************/ 00007 00008 /*************************************************************************** 00009 * * 00010 * This program is free software; you can redistribute it and/or modify * 00011 * it under the terms of the GNU Lesser General Public License * 00012 * version 2.1 as published by the Free Software Foundation; * 00013 * * 00014 ***************************************************************************/ 00015 00016 /* Adapted from 00017 * fastftdi.c - A minimal FTDI FT232H interface for which supports bit-bang 00018 * mode, but focuses on very high-performance support for 00019 * synchronous FIFO mode. Requires libusb-1.0 00020 * 00021 * Copyright (C) 2009 Micah Dowty 00022 * 00023 * Permission is hereby granted, free of charge, to any person obtaining a copy 00024 * of this software and associated documentation files (the "Software"), to deal 00025 * in the Software without restriction, including without limitation the rights 00026 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00027 * copies of the Software, and to permit persons to whom the Software is 00028 * furnished to do so, subject to the following conditions: 00029 * 00030 * The above copyright notice and this permission notice shall be included in 00031 * all copies or substantial portions of the Software. 00032 * 00033 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00034 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00035 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00036 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00037 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00038 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00039 * THE SOFTWARE. 00040 */ 00041 00042 #include <stdlib.h> 00043 #include <stdio.h> 00044 #include <libusb.h> 00045 00046 #include "ftdi.h" 00047 00048 typedef struct 00049 { 00050 FTDIStreamCallback *callback; 00051 void *userdata; 00052 int packetsize; 00053 int activity; 00054 int result; 00055 FTDIProgressInfo progress; 00056 } FTDIStreamState; 00057 00058 /* Handle callbacks 00059 * 00060 * With Exit request, free memory and release the transfer 00061 * 00062 * state->result is only set when some error happens 00063 */ 00064 static void 00065 ftdi_readstream_cb(struct libusb_transfer *transfer) 00066 { 00067 FTDIStreamState *state = transfer->user_data; 00068 int packet_size = state->packetsize; 00069 00070 state->activity++; 00071 if (transfer->status == LIBUSB_TRANSFER_COMPLETED) 00072 { 00073 int i; 00074 uint8_t *ptr = transfer->buffer; 00075 int length = transfer->actual_length; 00076 int numPackets = (length + packet_size - 1) / packet_size; 00077 int res = 0; 00078 00079 for (i = 0; i < numPackets; i++) 00080 { 00081 int payloadLen; 00082 int packetLen = length; 00083 00084 if (packetLen > packet_size) 00085 packetLen = packet_size; 00086 00087 payloadLen = packetLen - 2; 00088 state->progress.current.totalBytes += payloadLen; 00089 00090 res = state->callback(ptr + 2, payloadLen, 00091 NULL, state->userdata); 00092 00093 ptr += packetLen; 00094 length -= packetLen; 00095 } 00096 if (res) 00097 { 00098 free(transfer->buffer); 00099 libusb_free_transfer(transfer); 00100 } 00101 else 00102 { 00103 transfer->status = -1; 00104 state->result = libusb_submit_transfer(transfer); 00105 } 00106 } 00107 else 00108 { 00109 fprintf(stderr, "unknown status %d\n",transfer->status); 00110 state->result = LIBUSB_ERROR_IO; 00111 } 00112 } 00113 00120 static double 00121 TimevalDiff(const struct timeval *a, const struct timeval *b) 00122 { 00123 return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec); 00124 } 00125 00146 int 00147 ftdi_readstream(struct ftdi_context *ftdi, 00148 FTDIStreamCallback *callback, void *userdata, 00149 int packetsPerTransfer, int numTransfers) 00150 { 00151 struct libusb_transfer **transfers; 00152 FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 }; 00153 int bufferSize = packetsPerTransfer * ftdi->max_packet_size; 00154 int xferIndex; 00155 int err = 0; 00156 00157 /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/ 00158 if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H)) 00159 { 00160 fprintf(stderr,"Device doesn't support synchronous FIFO mode\n"); 00161 return 1; 00162 } 00163 00164 /* We don't know in what state we are, switch to reset*/ 00165 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) 00166 { 00167 fprintf(stderr,"Can't reset mode\n"); 00168 return 1; 00169 } 00170 00171 /* Purge anything remaining in the buffers*/ 00172 if (ftdi_usb_purge_buffers(ftdi) < 0) 00173 { 00174 fprintf(stderr,"Can't Purge\n"); 00175 return 1; 00176 } 00177 00178 /* 00179 * Set up all transfers 00180 */ 00181 00182 transfers = calloc(numTransfers, sizeof *transfers); 00183 if (!transfers) { 00184 err = LIBUSB_ERROR_NO_MEM; 00185 goto cleanup; 00186 } 00187 00188 for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) 00189 { 00190 struct libusb_transfer *transfer; 00191 00192 transfer = libusb_alloc_transfer(0); 00193 transfers[xferIndex] = transfer; 00194 if (!transfer) { 00195 err = LIBUSB_ERROR_NO_MEM; 00196 goto cleanup; 00197 } 00198 00199 libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep, 00200 malloc(bufferSize), bufferSize, 00201 ftdi_readstream_cb, 00202 &state, 0); 00203 00204 if (!transfer->buffer) { 00205 err = LIBUSB_ERROR_NO_MEM; 00206 goto cleanup; 00207 } 00208 00209 transfer->status = -1; 00210 err = libusb_submit_transfer(transfer); 00211 if (err) 00212 goto cleanup; 00213 } 00214 00215 /* Start the transfers only when everything has been set up. 00216 * Otherwise the transfers start stuttering and the PC not 00217 * fetching data for several to several ten milliseconds 00218 * and we skip blocks 00219 */ 00220 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0) 00221 { 00222 fprintf(stderr,"Can't set synchronous fifo mode: %s\n", 00223 ftdi_get_error_string(ftdi)); 00224 goto cleanup; 00225 } 00226 00227 /* 00228 * Run the transfers, and periodically assess progress. 00229 */ 00230 00231 gettimeofday(&state.progress.first.time, NULL); 00232 00233 do 00234 { 00235 FTDIProgressInfo *progress = &state.progress; 00236 const double progressInterval = 1.0; 00237 struct timeval timeout = { 0, ftdi->usb_read_timeout }; 00238 struct timeval now; 00239 00240 int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); 00241 if (err == LIBUSB_ERROR_INTERRUPTED) 00242 /* restart interrupted events */ 00243 err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); 00244 if (!state.result) 00245 { 00246 state.result = err; 00247 } 00248 if (state.activity == 0) 00249 state.result = 1; 00250 else 00251 state.activity = 0; 00252 00253 // If enough time has elapsed, update the progress 00254 gettimeofday(&now, NULL); 00255 if (TimevalDiff(&now, &progress->current.time) >= progressInterval) 00256 { 00257 progress->current.time = now; 00258 progress->totalTime = TimevalDiff(&progress->current.time, 00259 &progress->first.time); 00260 00261 if (progress->prev.totalBytes) 00262 { 00263 // We have enough information to calculate rates 00264 00265 double currentTime; 00266 00267 currentTime = TimevalDiff(&progress->current.time, 00268 &progress->prev.time); 00269 00270 progress->totalRate = 00271 progress->current.totalBytes /progress->totalTime; 00272 progress->currentRate = 00273 (progress->current.totalBytes - 00274 progress->prev.totalBytes) / currentTime; 00275 } 00276 00277 state.callback(NULL, 0, progress, state.userdata); 00278 progress->prev = progress->current; 00279 00280 } 00281 } while (!state.result); 00282 00283 /* 00284 * Cancel any outstanding transfers, and free memory. 00285 */ 00286 00287 cleanup: 00288 fprintf(stderr, "cleanup\n"); 00289 if (transfers) 00290 free(transfers); 00291 if (err) 00292 return err; 00293 else 00294 return state.result; 00295 } 00296
1.7.6.1