1919
2020#include "config.h"
2121
22+ #if defined _WIN32
23+ #include <winsock2.h>
24+ #else
25+ #include <sys/ioctl.h>
26+ #endif
27+
2228#include <libsigrok/libsigrok.h>
2329#include <string.h>
2430
2834
2935#define SER_TCPRAW_CONN_PREFIX "tcp-raw"
3036
37+ /* 100ms, high value for high latency IP connection (like WIFI). */
38+ /* TODO: VERYLOW - make this connection param. */
39+ static const int DRAIN_TIMEOUT = 100 * 1000 ;
40+
41+ /* 1ms */
42+ /* TODO: VERYLOW - make this connection param. */
43+ static const int FLUSH_TIMEOUT = 1 * 1000 ;
44+
45+
3146/**
3247 * @file
3348 *
@@ -186,7 +201,6 @@ static int ser_tcpraw_open(struct sr_serial_dev_inst *serial, int flags)
186201
187202static int ser_tcpraw_close (struct sr_serial_dev_inst * serial )
188203{
189-
190204 if (!serial )
191205 return SR_ERR_ARG ;
192206
@@ -197,21 +211,100 @@ static int ser_tcpraw_close(struct sr_serial_dev_inst *serial)
197211 return SR_OK ;
198212}
199213
214+ #ifdef SER_TCPRAW_TRY_AUTO_RECONNECT
215+ static gboolean sr_tcpraw_reconnect_internal (int ret ,
216+ struct sr_serial_dev_inst * serial )
217+ {
218+ struct sr_tcp_dev_inst * tcp = serial -> tcp_dev ;
219+
220+ if (ret != SR_ERR_IO || (errno != ENOTCONN && errno != EBADF ))
221+ return FALSE;
222+ if (sr_tcp_disconnect (tcp ) != SR_OK )
223+ return FALSE;
224+
225+ sr_info ("Trying reconnect to %s:%s" , tcp -> host_addr , tcp -> tcp_port );
226+ if (sr_tcp_connect (serial -> tcp_dev ) != SR_OK ) {
227+ sr_err ("Failed reconnected to %s:%s. Error: %d" , tcp -> host_addr ,
228+ tcp -> tcp_port , errno );
229+ return FALSE;
230+ }
231+ sr_info ("Successfully reconnected to %s:%s" , tcp -> host_addr , tcp -> tcp_port );
232+ return TRUE;
233+ }
234+ #endif
235+
200236static int ser_tcpraw_setup_source_add (struct sr_session * session ,
201237 struct sr_serial_dev_inst * serial , int events , int timeout ,
202238 sr_receive_data_callback cb , void * cb_data )
203239{
240+ #ifndef _WIN32
204241 if (!serial || !serial -> tcp_dev )
205242 return SR_ERR_ARG ;
206243 return sr_tcp_source_add (session , serial -> tcp_dev ,
207244 events , timeout , cb , cb_data );
245+ #else
246+ struct sr_tcp_dev_inst * tcp ;
247+ HANDLE wsa_evt ;
248+ int ret ;
249+
250+ if (!serial || !serial -> tcp_dev || serial -> tcp_dev -> sock_fd < 0 )
251+ return SR_ERR_ARG ;
252+
253+ /* Initializing serial->sp_data */
254+ if (serial -> sp_data )
255+ sr_warn ("sp_data not NULL (%p) in tcpraw source add" , serial -> sp_data );
256+ serial -> sp_data = NULL ;
257+
258+ /* Creating WinSock2 event for G_IO_IN & G_IO_OUT events in glib. */
259+ /* TODO: LOW - Move that code to tcp.c (need field for save event handle). */
260+ /*
261+ * TODO: VERYLOW - Implement something like "sr_session_source_add_socket"
262+ * based on g_socket_create_source and can be handled by glib
263+ * transparently (need testing).
264+ */
265+ wsa_evt = WSACreateEvent ();
266+ if (wsa_evt == WSA_INVALID_EVENT )
267+ return SR_ERR_BUG ;
268+ sr_spew ("Created WS2 pollfd event %p" , wsa_evt );
269+
270+ tcp = serial -> tcp_dev ;
271+ if (WSAEventSelect (tcp -> sock_fd , wsa_evt , FD_READ ) != 0 ) {
272+ sr_err ("Cant select WS2 socket %x for poolfd event %p" , tcp -> sock_fd ,
273+ wsa_evt );
274+ WSACloseEvent (wsa_evt );
275+ return SR_ERR_IO ;
276+ }
277+
278+ ret = sr_session_fd_source_add (session , GINT_TO_POINTER (tcp -> sock_fd ),
279+ (gintptr )wsa_evt , events , timeout , cb , cb_data );
280+ if (ret != SR_OK ) {
281+ WSACloseEvent (wsa_evt );
282+ wsa_evt = NULL ;
283+ }
284+
285+ /* Using serial sp_data field for store WS2 event handle. */
286+ serial -> sp_data = (struct sp_port * )wsa_evt ;
287+ return ret ;
288+ #endif
208289}
209290
210291static int ser_tcpraw_setup_source_remove (struct sr_session * session ,
211292 struct sr_serial_dev_inst * serial )
212293{
213294 if (!serial || !serial -> tcp_dev )
214295 return SR_ERR_ARG ;
296+
297+ #ifdef _WIN32
298+ if (serial -> sp_data ) {
299+ /* Closing WS2 event handle stored in serial sp_data field. */
300+ if (WSACloseEvent (serial -> sp_data ))
301+ sr_spew ("Closed WS2 poolfd event %p" , serial -> sp_data );
302+ else
303+ sr_warn ("Cant close WS2 poolfd event %p" , serial -> sp_data );
304+ serial -> sp_data = NULL ;
305+ }
306+ #endif
307+
215308 (void )sr_tcp_source_remove (session , serial -> tcp_dev );
216309 return SR_OK ;
217310}
@@ -233,6 +326,17 @@ static int ser_tcpraw_write(struct sr_serial_dev_inst *serial,
233326 total = 0 ;
234327 while (count ) {
235328 ret = sr_tcp_write_bytes (serial -> tcp_dev , buf , count );
329+
330+ #ifdef SER_TCPRAW_TRY_AUTO_RECONNECT
331+ /*
332+ * All device driver send commands for start acquisition.
333+ * So we can do reconnect there with "free" check,
334+ * and socket fd used for source key still be valid.
335+ */
336+ if (ret < 0 && !total && sr_tcpraw_reconnect_internal (ret , serial ))
337+ ret = sr_tcp_write_bytes (serial -> tcp_dev , buf , count );
338+ #endif
339+
236340 if (ret < 0 && !total ) {
237341 sr_err ("Error sending TCP transmit data." );
238342 return total ;
@@ -312,11 +416,86 @@ static int ser_tcpraw_read(struct sr_serial_dev_inst *serial,
312416 return total ;
313417}
314418
419+ static int tcpraw_drain_internal (struct sr_tcp_dev_inst * tcp ,
420+ int timeout , gboolean clear )
421+ {
422+ unsigned char * buf = g_malloc (1024 );
423+ fd_set rset ;
424+ int ret , len = 0 ;
425+ struct timeval tv ;
426+
427+ FD_ZERO (& rset );
428+ FD_SET (tcp -> sock_fd , & rset );
429+
430+ tv .tv_sec = 0 ;
431+ tv .tv_usec = timeout ;
432+
433+ do {
434+ ret = select (tcp -> sock_fd + 1 , & rset , NULL , NULL , & tv );
435+ if (ret > 0 ) {
436+ if (clear )
437+ len += sr_tcp_read_bytes (tcp , buf , 1024 , TRUE);
438+ else
439+ break ;
440+ }
441+ } while (ret > 0 );
442+
443+ g_free (buf );
444+
445+ if (clear )
446+ sr_spew ("Drained %d bytes of data." , len );
447+
448+ return len ;
449+ }
450+
451+ static int ser_tcpraw_drain (struct sr_serial_dev_inst * serial )
452+ {
453+ if (!serial || !serial -> tcp_dev )
454+ return SR_ERR_ARG ;
455+
456+ tcpraw_drain_internal (serial -> tcp_dev , DRAIN_TIMEOUT , FALSE);
457+ return SR_OK ;
458+ }
459+
460+ static size_t ser_tcpraw_get_rx_avail (struct sr_serial_dev_inst * serial )
461+ {
462+ struct sr_tcp_dev_inst * tcp ;
463+
464+ if (!serial || !serial -> tcp_dev )
465+ return 0 ;
466+ tcp = serial -> tcp_dev ;
467+
468+ #ifdef _WIN32
469+ u_long bytes_available ;
470+ if (ioctlsocket (tcp -> sock_fd , FIONREAD , & bytes_available ) != 0 ) {
471+ #else
472+ int bytes_available ;
473+ if (ioctl (tcp -> sock_fd , FIONREAD , & bytes_available ) < 0 ) {
474+ #endif
475+ sr_err ("FIONREAD failed: %s\n" , g_strerror (errno ));
476+ return 0 ;
477+ }
478+ return bytes_available ;
479+ }
480+
481+ /* Just clean incoming buffers. */
482+ static int ser_tcpraw_flush (struct sr_serial_dev_inst * serial )
483+ {
484+ if (!serial || !serial -> tcp_dev )
485+ return SR_ERR ;
486+ tcpraw_drain_internal (serial -> tcp_dev , FLUSH_TIMEOUT , TRUE);
487+ return SR_OK ;
488+ }
489+
490+
315491static struct ser_lib_functions serlib_tcpraw = {
316492 .open = ser_tcpraw_open ,
317493 .close = ser_tcpraw_close ,
318494 .write = ser_tcpraw_write ,
319495 .read = ser_tcpraw_read ,
496+ .drain = ser_tcpraw_drain ,
497+ .flush = ser_tcpraw_flush ,
498+ .get_rx_avail = ser_tcpraw_get_rx_avail ,
320499 .set_params = std_dummy_set_params ,
321500 .set_handshake = std_dummy_set_handshake ,
322501 .setup_source_add = ser_tcpraw_setup_source_add ,
0 commit comments