Skip to content

Commit 5b56404

Browse files
committed
Added TCPRAW serial port get_rx_avail() function
Added TCPRAW serial port drain(), flush() emulated functions Added support for select() on Windows Fixed TCPRAW serial port Glib IO events on Windows sr_serial_dev_inst struct sp_data field now store event handle for Windows due acquisition sr_serial_dev_inst struct now always include sp_data field for Windows compilation Added optional code for enable auto-reconnect TCPRAW
1 parent f06f788 commit 5b56404

File tree

3 files changed

+184
-5
lines changed

3 files changed

+184
-5
lines changed

src/libsigrok-internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,8 +1617,8 @@ struct sr_serial_dev_inst {
16171617
GString *rcv_buffer;
16181618
serial_rx_chunk_callback rx_chunk_cb_func;
16191619
void *rx_chunk_cb_data;
1620-
#ifdef HAVE_LIBSERIALPORT
1621-
/** libserialport port handle */
1620+
#if defined(HAVE_LIBSERIALPORT) || defined(_WIN32)
1621+
/** libserialport port handle / WIN32 TCP IO event handle */
16221622
struct sp_port *sp_data;
16231623
#endif
16241624
#ifdef HAVE_LIBHIDAPI

src/serial_tcpraw.c

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
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

@@ -28,6 +34,15 @@
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

187202
static 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+
200236
static 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

210291
static 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+
315491
static 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,

src/tcp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ SR_PRIV gboolean sr_fd_is_readable(int fd)
9393
return FALSE;
9494

9595
return TRUE;
96-
#elif HAVE_SELECT
96+
#elif defined(HAVE_SELECT) || defined(_WIN32)
9797
fd_set rfds;
9898
struct timeval tv;
9999
int ret;
@@ -106,7 +106,7 @@ SR_PRIV gboolean sr_fd_is_readable(int fd)
106106
return FALSE;
107107
if (!ret)
108108
return FALSE;
109-
if (!FD_ISSET(fd, rfds))
109+
if (!FD_ISSET(fd, &rfds))
110110
return FALSE;
111111
return TRUE;
112112
#else

0 commit comments

Comments
 (0)