From f8e42f46d063f5002f959e502269b9c6698fd423 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 7 Aug 2020 18:45:28 +0200 Subject: [PATCH] Add support for (socat) pseudo serial ports For example: # create a pseudo serial port pair with socat $ socat pty,link=$HOME/dev/foo pty,link=$HOME/dev/bar & [1] 28005 # open one side with the await_events example $ ./await_events $HOME/dev/foo & [2] 28006 Looking for port $HOME/dev/foo. Opening port. Setting port to 9600 8N1, no flow control. Adding port RX event to event set. Waiting up to 5 seconds for RX on any port... # open the other side with the send_receive example $ ./send_receive $HOME/dev/bar Looking for port $HOME/dev/bar. Opening port. Setting port to 9600 8N1, no flow control. Sending 'Hello!' (6 bytes) on port /dev/pts/2. Sent 6 bytes successfully. Receiving 6 bytes on port /dev/pts/2. Port /dev/pts/1: 6 bytes received. # <== await_events Timed out, 0/6 bytes received. Received ''. [2]+ Done ./await_events $HOME/dev/foo $ kill 28005 # socat --- libserialport.h | 4 +++- linux.c | 28 ++++++++++++++++------------ serialport.c | 37 ++++++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/libserialport.h b/libserialport.h index 7467f74..3bbae37 100644 --- a/libserialport.h +++ b/libserialport.h @@ -450,7 +450,9 @@ enum sp_transport { /** USB serial port adapter. @since 0.1.1 */ SP_TRANSPORT_USB, /** Bluetooth serial port adapter. @since 0.1.1 */ - SP_TRANSPORT_BLUETOOTH + SP_TRANSPORT_BLUETOOTH, + /** Pseudo serial port. @since 0.1.2 */ + SP_TRANSPORT_PSEUDO }; /** diff --git a/linux.c b/linux.c index 8f32085..feee9ec 100644 --- a/linux.c +++ b/linux.c @@ -56,18 +56,22 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port) RETURN_ERROR(SP_ERR_ARG, "Device name not recognized"); snprintf(link_name, sizeof(link_name), "/sys/class/tty/%s", dev); - if (lstat(link_name, &statbuf) == -1) - RETURN_ERROR(SP_ERR_ARG, "Device not found"); - if (!S_ISLNK(statbuf.st_mode)) - snprintf(link_name, sizeof(link_name), "/sys/class/tty/%s/device", dev); - count = readlink(link_name, file_name, sizeof(file_name)); - if (count <= 0 || count >= (int)(sizeof(file_name) - 1)) - RETURN_ERROR(SP_ERR_ARG, "Device not found"); - file_name[count] = 0; - if (strstr(file_name, "bluetooth")) - port->transport = SP_TRANSPORT_BLUETOOTH; - else if (strstr(file_name, "usb")) - port->transport = SP_TRANSPORT_USB; + if (lstat(link_name, &statbuf) == -1) { + if (strncmp(port->name + 5, "pts/", 4)) + RETURN_ERROR(SP_ERR_ARG, "Device not found"); + port->transport = SP_TRANSPORT_PSEUDO; + } else { + if (!S_ISLNK(statbuf.st_mode)) + snprintf(link_name, sizeof(link_name), "/sys/class/tty/%s/device", dev); + count = readlink(link_name, file_name, sizeof(file_name)); + if (count <= 0 || count >= (int)(sizeof(file_name) - 1)) + RETURN_ERROR(SP_ERR_ARG, "Device not found"); + file_name[count] = 0; + if (strstr(file_name, "bluetooth")) + port->transport = SP_TRANSPORT_BLUETOOTH; + else if (strstr(file_name, "usb")) + port->transport = SP_TRANSPORT_USB; + } if (port->transport == SP_TRANSPORT_USB) { for (i = 0; i < 5; i++) { diff --git a/serialport.c b/serialport.c index 1daba1c..7dd6052 100644 --- a/serialport.c +++ b/serialport.c @@ -47,6 +47,8 @@ static const struct std_baudrate std_baudrates[] = { void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; +static void init_config(struct sp_port_config *config); + static enum sp_return get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config); @@ -1652,6 +1654,18 @@ static enum sp_return set_flow(int fd, struct port_data *data) } #endif /* USE_TERMIOX */ +static void init_config(struct sp_port_config *config) +{ + config->baudrate = -1; + config->bits = -1; + config->parity = -1; + config->stopbits = -1; + config->rts = -1; + config->cts = -1; + config->dtr = -1; + config->dsr = -1; +} + static enum sp_return get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config) { @@ -1661,6 +1675,8 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, DEBUG_FMT("Getting configuration for port %s", port->name); + init_config(config); + #ifdef _WIN32 if (!GetCommState(port->hdl, &data->dcb)) RETURN_FAIL("GetCommState() failed"); @@ -1758,7 +1774,8 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, if (tcgetattr(port->fd, &data->term) < 0) RETURN_FAIL("tcgetattr() failed"); - if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0) + if (port->transport != SP_TRANSPORT_PSEUDO && ioctl(port->fd, TIOCMGET, + &data->controlbits) < 0) RETURN_FAIL("TIOCMGET ioctl failed"); #ifdef USE_TERMIOX @@ -1824,7 +1841,7 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, if (data->term.c_cflag & CRTSCTS) { config->rts = SP_RTS_FLOW_CONTROL; config->cts = SP_CTS_FLOW_CONTROL; - } else { + } else if (port->transport != SP_TRANSPORT_PSEUDO) { if (data->termiox_supported && data->rts_flow) config->rts = SP_RTS_FLOW_CONTROL; else @@ -1836,11 +1853,12 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, if (data->termiox_supported && data->dtr_flow) config->dtr = SP_DTR_FLOW_CONTROL; - else + else if (port->transport != SP_TRANSPORT_PSEUDO) config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF; - config->dsr = (data->termiox_supported && data->dsr_flow) ? - SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; + if (port->transport != SP_TRANSPORT_PSEUDO) + config->dsr = (data->termiox_supported && data->dsr_flow) ? + SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; if (data->term.c_iflag & IXOFF) { if (data->term.c_iflag & IXON) @@ -2272,14 +2290,7 @@ SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr) if (!(config = malloc(sizeof(struct sp_port_config)))) RETURN_ERROR(SP_ERR_MEM, "Config malloc failed"); - config->baudrate = -1; - config->bits = -1; - config->parity = -1; - config->stopbits = -1; - config->rts = -1; - config->cts = -1; - config->dtr = -1; - config->dsr = -1; + init_config(config); *config_ptr = config;