mirror of
git://sigrok.org/libserialport
synced 2023-08-10 21:13:24 +03:00
New API for serial control lines.
This commit is contained in:
parent
cbf628c7fe
commit
d514a26f81
@ -60,7 +60,10 @@ struct sp_port_config {
|
|||||||
int stopbits;
|
int stopbits;
|
||||||
int flowcontrol;
|
int flowcontrol;
|
||||||
int rts;
|
int rts;
|
||||||
|
int cts;
|
||||||
int dtr;
|
int dtr;
|
||||||
|
int dsr;
|
||||||
|
int xon_xoff;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return values. */
|
/* Return values. */
|
||||||
@ -95,14 +98,38 @@ enum {
|
|||||||
SP_PARITY_ODD = 2,
|
SP_PARITY_ODD = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flow control settings. */
|
/* RTS pin behaviour. */
|
||||||
enum {
|
enum {
|
||||||
/* No flow control. */
|
SP_RTS_OFF = 0,
|
||||||
SP_FLOW_NONE = 0,
|
SP_RTS_ON = 1,
|
||||||
/* Hardware (RTS/CTS) flow control. */
|
SP_RTS_FLOW_CONTROL = 2
|
||||||
SP_FLOW_HARDWARE = 1,
|
};
|
||||||
/* Software (XON/XOFF) flow control. */
|
|
||||||
SP_FLOW_SOFTWARE = 2,
|
/* CTS pin behaviour. */
|
||||||
|
enum {
|
||||||
|
SP_CTS_IGNORE = 0,
|
||||||
|
SP_CTS_FLOW_CONTROL = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DTR pin behaviour. */
|
||||||
|
enum {
|
||||||
|
SP_DTR_OFF = 0,
|
||||||
|
SP_DTR_ON = 1,
|
||||||
|
SP_DTR_FLOW_CONTROL = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DSR pin behaviour. */
|
||||||
|
enum {
|
||||||
|
SP_DSR_IGNORE = 0,
|
||||||
|
SP_DSR_FLOW_CONTROL = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* XON/XOFF flow control behaviour. */
|
||||||
|
enum {
|
||||||
|
SP_XONXOFF_DISABLED = 0,
|
||||||
|
SP_XONXOFF_IN = 1,
|
||||||
|
SP_XONXOFF_OUT = 2,
|
||||||
|
SP_XONXOFF_INOUT = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr);
|
int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr);
|
||||||
|
161
serialport.c
161
serialport.c
@ -52,7 +52,9 @@ struct sp_port_data {
|
|||||||
#else
|
#else
|
||||||
struct termios term;
|
struct termios term;
|
||||||
int rts;
|
int rts;
|
||||||
|
int cts;
|
||||||
int dtr;
|
int dtr;
|
||||||
|
int dsr;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -727,37 +729,43 @@ static int set_stopbits(struct sp_port_data *data, int stopbits)
|
|||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_flowcontrol(struct sp_port_data *data, int flowcontrol)
|
static int set_rts(struct sp_port_data *data, int rts)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifdef _WIN32
|
||||||
data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
|
switch (rts) {
|
||||||
data->term.c_cflag &= ~CRTSCTS;
|
case SP_RTS_OFF:
|
||||||
switch (flowcontrol) {
|
data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||||
case 0:
|
|
||||||
/* No flow control. */
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case SP_RTS_ON:
|
||||||
data->term.c_cflag |= CRTSCTS;
|
data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SP_RTS_FLOW_CONTROL:
|
||||||
data->term.c_iflag |= IXON | IXOFF | IXANY;
|
data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
data->rts = rts;
|
||||||
#endif
|
#endif
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_rts(struct sp_port_data *data, int rts)
|
static int set_cts(struct sp_port_data *data, int cts)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (rts)
|
switch (cts) {
|
||||||
data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
case SP_CTS_IGNORE:
|
||||||
else
|
data->dcb.fOutxCtsFlow = FALSE;
|
||||||
data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
break;
|
||||||
|
case SP_CTS_FLOW_CONTROL:
|
||||||
|
data->dcb.fOutxCtsFlow = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
data->rts = rts;
|
data->cts = cts;
|
||||||
#endif
|
#endif
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
@ -765,16 +773,88 @@ static int set_rts(struct sp_port_data *data, int rts)
|
|||||||
static int set_dtr(struct sp_port_data *data, int dtr)
|
static int set_dtr(struct sp_port_data *data, int dtr)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (dtr)
|
switch (dtr) {
|
||||||
data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
case SP_DTR_OFF:
|
||||||
else
|
|
||||||
data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||||
|
break;
|
||||||
|
case SP_DTR_ON:
|
||||||
|
data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
||||||
|
break;
|
||||||
|
case SP_DTR_FLOW_CONTROL:
|
||||||
|
data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
data->dtr = dtr;
|
data->dtr = dtr;
|
||||||
#endif
|
#endif
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_dsr(struct sp_port_data *data, int dsr)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
switch (dsr) {
|
||||||
|
case SP_DSR_IGNORE:
|
||||||
|
data->dcb.fOutxDsrFlow = FALSE;
|
||||||
|
break;
|
||||||
|
case SP_DSR_FLOW_CONTROL:
|
||||||
|
data->dcb.fOutxDsrFlow = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
data->dsr = dsr;
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_xon_xoff(struct sp_port_data *data, int xon_xoff)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
switch (xon_xoff) {
|
||||||
|
case SP_XONXOFF_DISABLED:
|
||||||
|
data->dcb.fInX = FALSE;
|
||||||
|
data->dcb.fOutX = FALSE;
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_IN:
|
||||||
|
data->dcb.fInX = TRUE;
|
||||||
|
data->dcb.fOutX = FALSE;
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_OUT:
|
||||||
|
data->dcb.fInX = FALSE;
|
||||||
|
data->dcb.fOutX = TRUE;
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_INOUT:
|
||||||
|
data->dcb.fInX = TRUE;
|
||||||
|
data->dcb.fOutX = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
switch (xon_xoff) {
|
||||||
|
case SP_XONXOFF_DISABLED:
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_IN:
|
||||||
|
data->term.c_iflag |= IXOFF;
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_OUT:
|
||||||
|
data->term.c_iflag |= IXON | IXANY;
|
||||||
|
break;
|
||||||
|
case SP_XONXOFF_INOUT:
|
||||||
|
data->term.c_iflag |= IXON | IXOFF | IXANY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int apply_config(struct sp_port *port, struct sp_port_data *data)
|
static int apply_config(struct sp_port *port, struct sp_port_data *data)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -795,23 +875,32 @@ static int apply_config(struct sp_port *port, struct sp_port_data *data)
|
|||||||
/* Ignore modem status lines; enable receiver */
|
/* Ignore modem status lines; enable receiver */
|
||||||
data->term.c_cflag |= (CLOCAL | CREAD);
|
data->term.c_cflag |= (CLOCAL | CREAD);
|
||||||
|
|
||||||
|
/* Asymmetric use of RTS/CTS not supported yet. */
|
||||||
|
if ((data->rts == SP_RTS_FLOW_CONTROL) != (data->cts == SP_CTS_FLOW_CONTROL))
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
|
||||||
|
/* DTR/DSR flow control not supported yet. */
|
||||||
|
if (data->dtr == SP_DTR_FLOW_CONTROL || data->dsr == SP_DSR_FLOW_CONTROL)
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
|
||||||
|
if (data->rts == SP_RTS_FLOW_CONTROL)
|
||||||
|
data->term.c_iflag |= CRTSCTS;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
controlbits = TIOCM_RTS;
|
||||||
|
if (ioctl(port->fd, data->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
|
||||||
|
&controlbits) < 0)
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
controlbits = TIOCM_DTR;
|
||||||
|
if (ioctl(port->fd, data->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
|
||||||
|
&controlbits) < 0)
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
|
||||||
/* Write the configured settings. */
|
/* Write the configured settings. */
|
||||||
if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
|
if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
|
||||||
return SP_ERR_FAIL;
|
return SP_ERR_FAIL;
|
||||||
|
|
||||||
if (data->rts != -1) {
|
|
||||||
controlbits = TIOCM_RTS;
|
|
||||||
if (ioctl(port->fd, data->rts ? TIOCMBIS : TIOCMBIC,
|
|
||||||
&controlbits) < 0)
|
|
||||||
return SP_ERR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data->dtr != -1) {
|
|
||||||
controlbits = TIOCM_DTR;
|
|
||||||
if (ioctl(port->fd, data->dtr ? TIOCMBIS : TIOCMBIC,
|
|
||||||
&controlbits) < 0)
|
|
||||||
return SP_ERR_FAIL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
@ -828,9 +917,11 @@ int sp_set_config(struct sp_port *port, struct sp_port_config *config)
|
|||||||
TRY_SET(bits);
|
TRY_SET(bits);
|
||||||
TRY_SET(parity);
|
TRY_SET(parity);
|
||||||
TRY_SET(stopbits);
|
TRY_SET(stopbits);
|
||||||
TRY_SET(flowcontrol);
|
|
||||||
TRY_SET(rts);
|
TRY_SET(rts);
|
||||||
|
TRY_SET(cts);
|
||||||
TRY_SET(dtr);
|
TRY_SET(dtr);
|
||||||
|
TRY_SET(dsr);
|
||||||
|
TRY_SET(xon_xoff);
|
||||||
TRY(apply_config(port, &data));
|
TRY(apply_config(port, &data));
|
||||||
|
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
|
Loading…
Reference in New Issue
Block a user