mirror of
git://sigrok.org/libserialport
synced 2023-08-10 21:13:24 +03:00
Divide sp_set_params into separate helper functions.
This commit is contained in:
parent
767c5ba80e
commit
8094e4a0ce
344
serialport.c
344
serialport.c
@ -46,6 +46,17 @@
|
|||||||
|
|
||||||
#include "libserialport.h"
|
#include "libserialport.h"
|
||||||
|
|
||||||
|
struct sp_port_data {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DCB dcb;
|
||||||
|
#else
|
||||||
|
struct termios term;
|
||||||
|
speed_t baud;
|
||||||
|
int rts;
|
||||||
|
int dtr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
struct sp_port *port;
|
struct sp_port *port;
|
||||||
@ -477,282 +488,345 @@ int sp_read(struct sp_port *port, void *buf, size_t count)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int sp_set_params(struct sp_port *port, int baudrate,
|
static int start_config(struct sp_port *port, struct sp_port_data *data)
|
||||||
int bits, int parity, int stopbits,
|
|
||||||
int flowcontrol, int rts, int dtr)
|
|
||||||
{
|
{
|
||||||
CHECK_PORT();
|
CHECK_PORT();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DCB dcb;
|
if (!GetCommState(port->hdl, &data->dcb))
|
||||||
|
|
||||||
if (!GetCommState(port->hdl, &dcb))
|
|
||||||
return SP_ERR_FAIL;
|
return SP_ERR_FAIL;
|
||||||
|
#else
|
||||||
|
if (tcgetattr(port->fd, &data->term) < 0)
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_baudrate(struct sp_port_data *data, int baudrate)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
switch (baudrate) {
|
switch (baudrate) {
|
||||||
/*
|
/*
|
||||||
* The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
|
* The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
|
||||||
* have documented CBR_* macros.
|
* have documented CBR_* macros.
|
||||||
*/
|
*/
|
||||||
case 110:
|
case 110:
|
||||||
dcb.BaudRate = CBR_110;
|
data->dcb.BaudRate = CBR_110;
|
||||||
break;
|
break;
|
||||||
case 300:
|
case 300:
|
||||||
dcb.BaudRate = CBR_300;
|
data->dcb.BaudRate = CBR_300;
|
||||||
break;
|
break;
|
||||||
case 600:
|
case 600:
|
||||||
dcb.BaudRate = CBR_600;
|
data->dcb.BaudRate = CBR_600;
|
||||||
break;
|
break;
|
||||||
case 1200:
|
case 1200:
|
||||||
dcb.BaudRate = CBR_1200;
|
data->dcb.BaudRate = CBR_1200;
|
||||||
break;
|
break;
|
||||||
case 2400:
|
case 2400:
|
||||||
dcb.BaudRate = CBR_2400;
|
data->dcb.BaudRate = CBR_2400;
|
||||||
break;
|
break;
|
||||||
case 4800:
|
case 4800:
|
||||||
dcb.BaudRate = CBR_4800;
|
data->dcb.BaudRate = CBR_4800;
|
||||||
break;
|
break;
|
||||||
case 9600:
|
case 9600:
|
||||||
dcb.BaudRate = CBR_9600;
|
data->dcb.BaudRate = CBR_9600;
|
||||||
break;
|
break;
|
||||||
case 14400:
|
case 14400:
|
||||||
dcb.BaudRate = CBR_14400; /* Not available on Unix? */
|
data->dcb.BaudRate = CBR_14400; /* Not available on Unix? */
|
||||||
break;
|
break;
|
||||||
case 19200:
|
case 19200:
|
||||||
dcb.BaudRate = CBR_19200;
|
data->dcb.BaudRate = CBR_19200;
|
||||||
break;
|
break;
|
||||||
case 38400:
|
case 38400:
|
||||||
dcb.BaudRate = CBR_38400;
|
data->dcb.BaudRate = CBR_38400;
|
||||||
break;
|
break;
|
||||||
case 57600:
|
case 57600:
|
||||||
dcb.BaudRate = CBR_57600;
|
data->dcb.BaudRate = CBR_57600;
|
||||||
break;
|
break;
|
||||||
case 115200:
|
case 115200:
|
||||||
dcb.BaudRate = CBR_115200;
|
data->dcb.BaudRate = CBR_115200;
|
||||||
break;
|
break;
|
||||||
case 128000:
|
case 128000:
|
||||||
dcb.BaudRate = CBR_128000; /* Not available on Unix? */
|
data->dcb.BaudRate = CBR_128000; /* Not available on Unix? */
|
||||||
break;
|
break;
|
||||||
case 256000:
|
case 256000:
|
||||||
dcb.BaudRate = CBR_256000; /* Not available on Unix? */
|
data->dcb.BaudRate = CBR_256000; /* Not available on Unix? */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
dcb.ByteSize = bits;
|
|
||||||
|
|
||||||
switch (stopbits) {
|
|
||||||
/* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
|
|
||||||
case 1:
|
|
||||||
dcb.StopBits = ONESTOPBIT;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
dcb.StopBits = TWOSTOPBITS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SP_ERR_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (parity) {
|
|
||||||
/* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
|
|
||||||
case SP_PARITY_NONE:
|
|
||||||
dcb.Parity = NOPARITY;
|
|
||||||
break;
|
|
||||||
case SP_PARITY_EVEN:
|
|
||||||
dcb.Parity = EVENPARITY;
|
|
||||||
break;
|
|
||||||
case SP_PARITY_ODD:
|
|
||||||
dcb.Parity = ODDPARITY;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SP_ERR_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rts != -1) {
|
|
||||||
if (rts)
|
|
||||||
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
|
||||||
else
|
|
||||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dtr != -1) {
|
|
||||||
if (dtr)
|
|
||||||
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
|
||||||
else
|
|
||||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetCommState(port->hdl, &dcb))
|
|
||||||
return SP_ERR_FAIL;
|
|
||||||
#else
|
#else
|
||||||
struct termios term;
|
|
||||||
speed_t baud;
|
|
||||||
int controlbits;
|
|
||||||
|
|
||||||
if (tcgetattr(port->fd, &term) < 0)
|
|
||||||
return SP_ERR_FAIL;
|
|
||||||
|
|
||||||
switch (baudrate) {
|
switch (baudrate) {
|
||||||
case 50:
|
case 50:
|
||||||
baud = B50;
|
data->baud = B50;
|
||||||
break;
|
break;
|
||||||
case 75:
|
case 75:
|
||||||
baud = B75;
|
data->baud = B75;
|
||||||
break;
|
break;
|
||||||
case 110:
|
case 110:
|
||||||
baud = B110;
|
data->baud = B110;
|
||||||
break;
|
break;
|
||||||
case 134:
|
case 134:
|
||||||
baud = B134;
|
data->baud = B134;
|
||||||
break;
|
break;
|
||||||
case 150:
|
case 150:
|
||||||
baud = B150;
|
data->baud = B150;
|
||||||
break;
|
break;
|
||||||
case 200:
|
case 200:
|
||||||
baud = B200;
|
data->baud = B200;
|
||||||
break;
|
break;
|
||||||
case 300:
|
case 300:
|
||||||
baud = B300;
|
data->baud = B300;
|
||||||
break;
|
break;
|
||||||
case 600:
|
case 600:
|
||||||
baud = B600;
|
data->baud = B600;
|
||||||
break;
|
break;
|
||||||
case 1200:
|
case 1200:
|
||||||
baud = B1200;
|
data->baud = B1200;
|
||||||
break;
|
break;
|
||||||
case 1800:
|
case 1800:
|
||||||
baud = B1800;
|
data->baud = B1800;
|
||||||
break;
|
break;
|
||||||
case 2400:
|
case 2400:
|
||||||
baud = B2400;
|
data->baud = B2400;
|
||||||
break;
|
break;
|
||||||
case 4800:
|
case 4800:
|
||||||
baud = B4800;
|
data->baud = B4800;
|
||||||
break;
|
break;
|
||||||
case 9600:
|
case 9600:
|
||||||
baud = B9600;
|
data->baud = B9600;
|
||||||
break;
|
break;
|
||||||
case 19200:
|
case 19200:
|
||||||
baud = B19200;
|
data->baud = B19200;
|
||||||
break;
|
break;
|
||||||
case 38400:
|
case 38400:
|
||||||
baud = B38400;
|
data->baud = B38400;
|
||||||
break;
|
break;
|
||||||
case 57600:
|
case 57600:
|
||||||
baud = B57600;
|
data->baud = B57600;
|
||||||
break;
|
break;
|
||||||
case 115200:
|
case 115200:
|
||||||
baud = B115200;
|
data->baud = B115200;
|
||||||
break;
|
break;
|
||||||
case 230400:
|
case 230400:
|
||||||
baud = B230400;
|
data->baud = B230400;
|
||||||
break;
|
break;
|
||||||
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
||||||
case 460800:
|
case 460800:
|
||||||
baud = B460800;
|
data->baud = B460800;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (cfsetospeed(&term, baud) < 0)
|
static int set_bits(struct sp_port_data *data, int bits)
|
||||||
return SP_ERR_FAIL;
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
if (cfsetispeed(&term, baud) < 0)
|
data->dcb.ByteSize = bits;
|
||||||
return SP_ERR_FAIL;
|
#else
|
||||||
|
data->term.c_cflag &= ~CSIZE;
|
||||||
term.c_cflag &= ~CSIZE;
|
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 8:
|
case 8:
|
||||||
term.c_cflag |= CS8;
|
data->term.c_cflag |= CS8;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
term.c_cflag |= CS7;
|
data->term.c_cflag |= CS7;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
term.c_cflag |= CS6;
|
data->term.c_cflag |= CS6;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
term.c_cflag &= ~CSTOPB;
|
static int set_parity(struct sp_port_data *data, int parity)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
switch (parity) {
|
||||||
|
/* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
|
||||||
|
case SP_PARITY_NONE:
|
||||||
|
data->dcb.Parity = NOPARITY;
|
||||||
|
break;
|
||||||
|
case SP_PARITY_EVEN:
|
||||||
|
data->dcb.Parity = EVENPARITY;
|
||||||
|
break;
|
||||||
|
case SP_PARITY_ODD:
|
||||||
|
data->dcb.Parity = ODDPARITY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
data->term.c_iflag &= ~IGNPAR;
|
||||||
|
data->term.c_cflag &= ~(PARENB | PARODD);
|
||||||
|
switch (parity) {
|
||||||
|
case SP_PARITY_NONE:
|
||||||
|
data->term.c_iflag |= IGNPAR;
|
||||||
|
break;
|
||||||
|
case SP_PARITY_EVEN:
|
||||||
|
data->term.c_cflag |= PARENB;
|
||||||
|
break;
|
||||||
|
case SP_PARITY_ODD:
|
||||||
|
data->term.c_cflag |= PARENB | PARODD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_stopbits(struct sp_port_data *data, int stopbits)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
switch (stopbits) {
|
switch (stopbits) {
|
||||||
|
/* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
|
||||||
case 1:
|
case 1:
|
||||||
term.c_cflag &= ~CSTOPB;
|
data->dcb.StopBits = ONESTOPBIT;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
term.c_cflag |= CSTOPB;
|
data->dcb.StopBits = TWOSTOPBITS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
data->term.c_cflag &= ~CSTOPB;
|
||||||
|
switch (stopbits) {
|
||||||
|
case 1:
|
||||||
|
data->term.c_cflag &= ~CSTOPB;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
data->term.c_cflag |= CSTOPB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SP_ERR_ARG;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
term.c_iflag &= ~(IXON | IXOFF | IXANY);
|
static int set_flowcontrol(struct sp_port_data *data, int flowcontrol)
|
||||||
term.c_cflag &= ~CRTSCTS;
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
data->term.c_cflag &= ~CRTSCTS;
|
||||||
switch (flowcontrol) {
|
switch (flowcontrol) {
|
||||||
case 0:
|
case 0:
|
||||||
/* No flow control. */
|
/* No flow control. */
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
term.c_cflag |= CRTSCTS;
|
data->term.c_cflag |= CRTSCTS;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
term.c_iflag |= IXON | IXOFF | IXANY;
|
data->term.c_iflag |= IXON | IXOFF | IXANY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return SP_ERR_ARG;
|
return SP_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
term.c_iflag &= ~IGNPAR;
|
static int set_rts(struct sp_port_data *data, int rts)
|
||||||
term.c_cflag &= ~(PARENB | PARODD);
|
{
|
||||||
switch (parity) {
|
#ifdef _WIN32
|
||||||
case SP_PARITY_NONE:
|
if (rts != -1) {
|
||||||
term.c_iflag |= IGNPAR;
|
if (rts)
|
||||||
break;
|
data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||||
case SP_PARITY_EVEN:
|
else
|
||||||
term.c_cflag |= PARENB;
|
data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||||
break;
|
|
||||||
case SP_PARITY_ODD:
|
|
||||||
term.c_cflag |= PARENB | PARODD;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SP_ERR_ARG;
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
data->rts = rts;
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_dtr(struct sp_port_data *data, int dtr)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (dtr != -1) {
|
||||||
|
if (dtr)
|
||||||
|
data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
||||||
|
else
|
||||||
|
data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
data->dtr = dtr;
|
||||||
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_config(struct sp_port *port, struct sp_port_data *data)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!SetCommState(port->hdl, &data->dcb))
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
#else
|
||||||
|
int controlbits;
|
||||||
|
|
||||||
/* Turn off all serial port cooking. */
|
/* Turn off all serial port cooking. */
|
||||||
term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
|
data->term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
|
||||||
term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
|
data->term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
|
||||||
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||||
term.c_oflag &= ~OFILL;
|
data->term.c_oflag &= ~OFILL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Disable canonical mode, and don't echo input characters. */
|
/* Disable canonical mode, and don't echo input characters. */
|
||||||
term.c_lflag &= ~(ICANON | ECHO);
|
data->term.c_lflag &= ~(ICANON | ECHO);
|
||||||
|
|
||||||
/* Ignore modem status lines; enable receiver */
|
/* Ignore modem status lines; enable receiver */
|
||||||
term.c_cflag |= (CLOCAL | CREAD);
|
data->term.c_cflag |= (CLOCAL | CREAD);
|
||||||
|
|
||||||
/* Write the configured settings. */
|
/* Write the configured settings. */
|
||||||
if (tcsetattr(port->fd, TCSADRAIN, &term) < 0)
|
if (tcsetattr(port->fd, TCSADRAIN, &data->term) < 0)
|
||||||
return SP_ERR_FAIL;
|
return SP_ERR_FAIL;
|
||||||
|
|
||||||
if (rts != -1) {
|
if (cfsetospeed(&data->term, data->baud) < 0)
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
|
||||||
|
if (cfsetispeed(&data->term, data->baud) < 0)
|
||||||
|
return SP_ERR_FAIL;
|
||||||
|
|
||||||
|
if (data->rts != -1) {
|
||||||
controlbits = TIOCM_RTS;
|
controlbits = TIOCM_RTS;
|
||||||
if (ioctl(port->fd, rts ? TIOCMBIS : TIOCMBIC,
|
if (ioctl(port->fd, data->rts ? TIOCMBIS : TIOCMBIC,
|
||||||
&controlbits) < 0)
|
&controlbits) < 0)
|
||||||
return SP_ERR_FAIL;
|
return SP_ERR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtr != -1) {
|
if (data->dtr != -1) {
|
||||||
controlbits = TIOCM_DTR;
|
controlbits = TIOCM_DTR;
|
||||||
if (ioctl(port->fd, dtr ? TIOCMBIS : TIOCMBIC,
|
if (ioctl(port->fd, data->dtr ? TIOCMBIS : TIOCMBIC,
|
||||||
&controlbits) < 0)
|
&controlbits) < 0)
|
||||||
return SP_ERR_FAIL;
|
return SP_ERR_FAIL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return SP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
|
||||||
|
|
||||||
|
int sp_set_params(struct sp_port *port, int baudrate, int bits, int parity,
|
||||||
|
int stopbits, int flowcontrol, int rts, int dtr)
|
||||||
|
{
|
||||||
|
struct sp_port_data data;
|
||||||
|
|
||||||
|
TRY(start_config(port, &data));
|
||||||
|
TRY(set_baudrate(&data, baudrate));
|
||||||
|
TRY(set_bits(&data, bits));
|
||||||
|
TRY(set_parity(&data, parity));
|
||||||
|
TRY(set_stopbits(&data, stopbits));
|
||||||
|
TRY(set_flowcontrol(&data, flowcontrol));
|
||||||
|
TRY(set_rts(&data, rts));
|
||||||
|
TRY(set_dtr(&data, dtr));
|
||||||
|
TRY(apply_config(port, &data));
|
||||||
|
|
||||||
return SP_OK;
|
return SP_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user