9191#define DO_NOT_BUILD_FT245R
9292#endif
9393
94- #ifndef HAVE_PTHREAD_H
95-
96- static int ft245r_nopthread_open (struct programmer_t * pgm , char * name ) {
97- avrdude_message (MSG_INFO , "%s: error: no pthread support. Please compile again with pthread installed."
98- #if defined(_WIN32 )
99- " See http://sourceware.org/pthreads-win32/."
100- #endif
101- "\n" ,
102- progname );
103-
104- return -1 ;
105- }
106-
107- void ft245r_initpgm (PROGRAMMER * pgm ) {
108- strcpy (pgm -> type , "ftdi_syncbb" );
109- pgm -> open = ft245r_nopthread_open ;
110- }
111-
112- #elif defined(DO_NOT_BUILD_FT245R )
94+ #if defined(DO_NOT_BUILD_FT245R )
11395
11496static int ft245r_noftdi_open (struct programmer_t * pgm , char * name ) {
11597 avrdude_message (MSG_INFO , "%s: error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.\n" ,
@@ -125,21 +107,6 @@ void ft245r_initpgm(PROGRAMMER * pgm) {
125107
126108#else
127109
128- #include <pthread.h>
129-
130- #ifdef __APPLE__
131- /* Mac OS X defines sem_init but actually does not implement them */
132- #include <dispatch/dispatch.h>
133-
134- typedef dispatch_semaphore_t sem_t ;
135-
136- #define sem_init (psem ,x ,val ) *psem = dispatch_semaphore_create(val)
137- #define sem_post (psem ) dispatch_semaphore_signal(*psem)
138- #define sem_wait (psem ) dispatch_semaphore_wait(*psem, DISPATCH_TIME_FOREVER)
139- #else
140- #include <semaphore.h>
141- #endif
142-
143110#define FT245R_CYCLES 2
144111#define FT245R_FRAGMENT_SIZE 512
145112#define REQ_OUTSTANDINGS 10
@@ -152,92 +119,144 @@ static struct ftdi_context *handle;
152119static unsigned char ft245r_ddr ;
153120static unsigned char ft245r_out ;
154121
155- #define BUFSIZE 0x2000
122+ #define FT245R_BUFSIZE 0x2000 // receive buffer size
123+ #define FT245R_MIN_FIFO_SIZE 128 // min of FTDI RX/TX FIFO size
156124
157- // libftdi / libftd2xx compatibility functions.
125+ static struct {
126+ int len ; // # of bytes in transmit buffer
127+ uint8_t buf [FT245R_MIN_FIFO_SIZE ]; // transmit buffer
128+ } tx ;
158129
159- static pthread_t readerthread ;
160- static sem_t buf_data , buf_space ;
161- static unsigned char buffer [BUFSIZE ];
162- static int head , tail ;
163130static struct {
164131 int discard ; // # of bytes to discard during read
132+ int pending ; // # of bytes that have been written since last read
133+ int wr ; // write pointer
134+ int rd ; // read pointer
135+ uint8_t buf [FT245R_BUFSIZE ]; // receive ring buffer
165136} rx ;
166137
167- static void add_to_buf (unsigned char c ) {
168- int nh ;
138+ // Discard all data from the receive buffer.
139+ static void ft245r_rx_buf_purge (PROGRAMMER * pgm ) {
140+ rx .rd = rx .wr = 0 ;
141+ }
169142
170- sem_wait (& buf_space );
171- if (head == (BUFSIZE - 1 )) nh = 0 ;
172- else nh = head + 1 ;
143+ static void ft245r_rx_buf_put (PROGRAMMER * pgm , uint8_t byte ) {
144+ rx .buf [rx .wr ++ ] = byte ;
145+ if (rx .wr >= sizeof (rx .buf ))
146+ rx .wr = 0 ;
147+ }
173148
174- if (nh == tail ) {
175- avrdude_message (MSG_INFO , "buffer overflow. Cannot happen!\n" );
176- }
177- buffer [head ] = c ;
178- head = nh ;
179- sem_post (& buf_data );
149+ static uint8_t ft245r_rx_buf_get (PROGRAMMER * pgm ) {
150+ uint8_t byte = rx .buf [rx .rd ++ ];
151+ if (rx .rd >= sizeof (rx .buf ))
152+ rx .rd = 0 ;
153+ return byte ;
154+ }
155+
156+ /* Fill receive buffer with data from the FTDI receive FIFO. */
157+ static int ft245r_fill (PROGRAMMER * pgm ) {
158+ uint8_t raw [FT245R_MIN_FIFO_SIZE ];
159+ int i , nread ;
160+
161+ nread = ftdi_read_data (handle , raw , rx .pending );
162+ if (nread < 0 )
163+ return -1 ;
164+ rx .pending -= nread ;
165+ #if FT245R_DEBUG
166+ avrdude_message (MSG_INFO , "%s: read %d bytes (pending=%d)\n" ,
167+ __func__ , nread , rx .pending );
168+ #endif
169+ for (i = 0 ; i < nread ; ++ i )
170+ ft245r_rx_buf_put (pgm , raw [i ]);
171+ return nread ;
180172}
181173
182- static void * reader (void * arg ) {
183- pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED ,NULL );
184- struct ftdi_context * handle = (struct ftdi_context * )(arg );
185- unsigned char buf [0x1000 ];
186- int br , i ;
187-
188- while (1 ) {
189- /* 'old_cancel_state' added for portability reasons,
190- * see pthread_setcancelstate() manual */
191- int old_cancel_state ;
192- pthread_testcancel ();
193- /* isolate libftdi and libusb from cancellation requests to prevent unhandled behavior */
194- pthread_setcancelstate (PTHREAD_CANCEL_DISABLE , & old_cancel_state );
195- br = ftdi_read_data (handle , buf , sizeof (buf ));
196- for (i = 0 ; i < br ; i ++ )
197- add_to_buf (buf [i ]);
198- pthread_setcancelstate (PTHREAD_CANCEL_ENABLE , & old_cancel_state );
174+ /* Flush pending TX data to the FTDI send FIFO. */
175+ static int ft245r_flush (PROGRAMMER * pgm ) {
176+ int rv , len = tx .len , avail ;
177+ uint8_t * src = tx .buf ;
178+
179+ if (!len )
180+ return 0 ;
181+
182+ while (len > 0 ) {
183+ avail = FT245R_MIN_FIFO_SIZE - rx .pending ;
184+ if (avail <= 0 ) {
185+ avail = ft245r_fill (pgm );
186+ if (avail < 0 ) {
187+ avrdude_message (MSG_INFO ,
188+ "%s: fill returned %d: %s\n" ,
189+ __func__ , avail , ftdi_get_error_string (handle ));
190+ return -1 ;
191+ }
192+ }
193+ if (avail > len )
194+ avail = len ;
195+
196+ #if FT245R_DEBUG
197+ avrdude_message (MSG_INFO , "%s: writing %d bytes\n" , __func__ , avail );
198+ #endif
199+ rv = ftdi_write_data (handle , src , avail );
200+ if (rv != avail ) {
201+ avrdude_message (MSG_INFO ,
202+ "%s: write returned %d (expected %d): %s\n" ,
203+ __func__ , rv , avail , ftdi_get_error_string (handle ));
204+ return -1 ;
205+ }
206+ src += avail ;
207+ len -= avail ;
208+ rx .pending += avail ;
199209 }
200- return NULL ;
210+ tx .len = 0 ;
211+ return 0 ;
201212}
202213
203- static int ft245r_send (PROGRAMMER * pgm , unsigned char * buf , size_t len ) {
204- int rv ;
214+ static int ft245r_send2 (PROGRAMMER * pgm , unsigned char * buf , size_t len ,
215+ bool discard_rx_data ) {
216+ int i ;
205217
206- rv = ftdi_write_data (handle , buf , len );
207- if (len != rv ) return -1 ;
218+ for (i = 0 ; i < len ; ++ i ) {
219+ if (discard_rx_data )
220+ ++ rx .discard ;
221+ tx .buf [tx .len ++ ] = buf [i ];
222+ if (tx .len >= FT245R_MIN_FIFO_SIZE )
223+ ft245r_flush (pgm );
224+ }
208225 return 0 ;
209226}
210227
228+ static int ft245r_send (PROGRAMMER * pgm , unsigned char * buf , size_t len ) {
229+ return ft245r_send2 (pgm , buf , len , false);
230+ }
231+
211232static int ft245r_send_and_discard (PROGRAMMER * pgm , unsigned char * buf ,
212233 size_t len ) {
213- rx .discard += len ;
214- return ft245r_send (pgm , buf , len );
234+ return ft245r_send2 (pgm , buf , len , true);
215235}
216236
217237static int ft245r_recv (PROGRAMMER * pgm , unsigned char * buf , size_t len ) {
218- int i = 0 ;
219-
220- // Copy over data from the circular buffer..
221- // XXX This should timeout, and return error if there isn't enough
222- // data.
223- while (i < len ) {
224- sem_wait (& buf_data );
225- if (rx .discard > 0 )
226- -- rx .discard ;
227- else
228- buf [i ++ ] = buffer [tail ];
229- if (tail == (BUFSIZE - 1 )) tail = 0 ;
230- else tail ++ ;
231- sem_post (& buf_space );
238+ int i ;
239+
240+ ft245r_flush (pgm );
241+ ft245r_fill (pgm );
242+
243+ #if FT245R_DEBUG
244+ avrdude_message (MSG_INFO , "%s: discarding %d, consuming %zu bytes\n" ,
245+ __func__ , rx .discard , len );
246+ #endif
247+ while (rx .discard > 0 ) {
248+ ft245r_rx_buf_get (pgm );
249+ -- rx .discard ;
232250 }
233251
252+ for (i = 0 ; i < len ; ++ i )
253+ buf [i ] = ft245r_rx_buf_get (pgm );
234254 return 0 ;
235255}
236256
237257
238258static int ft245r_drain (PROGRAMMER * pgm , int display ) {
239259 int r ;
240- unsigned char t ;
241260
242261 // flush the buffer in the chip by changing the mode.....
243262 r = ftdi_set_bitmode (handle , 0 , BITMODE_RESET ); // reset
@@ -246,13 +265,18 @@ static int ft245r_drain(PROGRAMMER * pgm, int display) {
246265 if (r ) return -1 ;
247266
248267 // drain our buffer.
249- while (head != tail ) {
250- ft245r_recv (pgm , & t , 1 );
251- }
268+ ft245r_rx_buf_purge (pgm );
252269 return 0 ;
253270}
254271
255272
273+ /* Ensure any pending writes are sent to the FTDI chip before sleeping. */
274+ static void ft245r_usleep (PROGRAMMER * pgm , useconds_t usec ) {
275+ ft245r_flush (pgm );
276+ usleep (usec );
277+ }
278+
279+
256280static int ft245r_chip_erase (PROGRAMMER * pgm , AVRPART * p ) {
257281 unsigned char cmd [4 ] = {0 ,0 ,0 ,0 };
258282 unsigned char res [4 ];
@@ -268,7 +292,7 @@ static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p) {
268292
269293 avr_set_bits (p -> op [AVR_OP_CHIP_ERASE ], cmd );
270294 pgm -> cmd (pgm , cmd , res );
271- usleep ( p -> chip_erase_delay );
295+ ft245r_usleep ( pgm , p -> chip_erase_delay );
272296 return pgm -> initialize (pgm , p );
273297}
274298
@@ -302,6 +326,8 @@ static int ft245r_set_bitclock(PROGRAMMER * pgm) {
302326static int get_pin (PROGRAMMER * pgm , int pinname ) {
303327 uint8_t byte ;
304328
329+ ft245r_flush (pgm );
330+
305331 if (ftdi_read_pins (handle , & byte ) != 0 )
306332 return -1 ;
307333 if (FT245R_DEBUG )
@@ -365,7 +391,7 @@ static int set_led_vfy(struct programmer_t * pgm, int value) {
365391static void ft245r_powerup (PROGRAMMER * pgm )
366392{
367393 set_vcc (pgm , ON ); /* power up */
368- usleep ( 100 );
394+ ft245r_usleep ( pgm , 100 );
369395}
370396
371397
@@ -395,7 +421,7 @@ static void ft245r_enable(PROGRAMMER * pgm) {
395421 * and not via the buffer chip.
396422 */
397423 set_reset (pgm , OFF );
398- usleep ( 1 );
424+ ft245r_usleep ( pgm , 1 );
399425 set_buff (pgm , ON );
400426}
401427
@@ -434,12 +460,12 @@ static int ft245r_program_enable(PROGRAMMER * pgm, AVRPART * p) {
434460 fflush (stderr );
435461 }
436462 set_pin (pgm , PIN_AVR_RESET , ON );
437- usleep ( 20 );
463+ ft245r_usleep ( pgm , 20 );
438464 set_pin (pgm , PIN_AVR_RESET , OFF );
439465
440466 if (i == 3 ) {
441467 ft245r_drain (pgm , 0 );
442- tail = head ;
468+ ft245r_rx_buf_purge ( pgm ) ;
443469 }
444470 }
445471
@@ -464,15 +490,15 @@ static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p) {
464490 ft245r_powerup (pgm );
465491
466492 set_reset (pgm , OFF );
467- usleep ( 5000 ); // 5ms
493+ ft245r_usleep ( pgm , 5000 ); // 5ms
468494 set_reset (pgm , ON );
469- usleep ( 5000 ); // 5ms
495+ ft245r_usleep ( pgm , 5000 ); // 5ms
470496 set_reset (pgm , OFF );
471497
472498 /* Wait for at least 20 ms and enable serial programming by sending the Programming
473499 * Enable serial instruction to pin MOSI.
474500 */
475- usleep ( 20000 ); // 20ms
501+ ft245r_usleep ( pgm , 20000 ); // 20ms
476502
477503 if (p -> flags & AVRPART_HAS_TPI ) {
478504 bool io_link_ok = true;
@@ -862,15 +888,6 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
862888 goto cleanup ;
863889 }
864890
865- /* We start a new thread to read the output from the FTDI. This is
866- * necessary because otherwise we'll deadlock. We cannot finish
867- * writing because the ftdi cannot send the results because we
868- * haven't provided a read buffer yet. */
869-
870- sem_init (& buf_data , 0 , 0 );
871- sem_init (& buf_space , 0 , BUFSIZE );
872- pthread_create (& readerthread , NULL , reader , handle );
873-
874891 /*
875892 * drain any extraneous input
876893 */
@@ -892,9 +909,6 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
892909
893910static void ft245r_close (PROGRAMMER * pgm ) {
894911 if (handle ) {
895- /* reader thread must be stopped before libftdi de-initialization */
896- pthread_cancel (readerthread );
897- pthread_join (readerthread , NULL );
898912 // I think the switch to BB mode and back flushes the buffer.
899913 ftdi_set_bitmode (handle , 0 , BITMODE_SYNCBB ); // set Synchronous BitBang, all in puts
900914 ftdi_set_bitmode (handle , 0 , BITMODE_RESET ); // disable Synchronous BitBang
@@ -1071,7 +1085,7 @@ static int ft245r_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
10711085#if defined(USE_INLINE_WRITE_PAGE )
10721086 while (do_request (pgm , m ))
10731087 ;
1074- usleep ( m -> max_write_delay );
1088+ ft245r_usleep ( pgm , m -> max_write_delay );
10751089#else
10761090 int addr_wk = addr_save - (addr_save % m -> page_size );
10771091 int rc ;
0 commit comments