Support custom baudrates on Linux.
This commit is contained in:
parent
31b3a8f5b5
commit
7a6d2196e0
|
@ -24,7 +24,7 @@ AM_CPPFLAGS = -I$(top_srcdir)
|
|||
|
||||
lib_LTLIBRARIES = libserialport.la
|
||||
|
||||
libserialport_la_SOURCES = serialport.c
|
||||
libserialport_la_SOURCES = serialport.c linux_termios.c
|
||||
|
||||
libserialport_la_LIBADD = $(LIBOBJS)
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ AC_CHECK_HEADERS([errno.h fcntl.h stddef.h sys/ioctl.h termios.h])
|
|||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_CHECK_TYPE([struct termios2],[AC_DEFINE(HAVE_TERMIOS2, 1)],[],[[#include <linux/termios.h>]])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_FUNCS([strerror])
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* This file is part of the libserialport project.
|
||||
*
|
||||
* Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/termios.h>
|
||||
#include "linux_termios.h"
|
||||
|
||||
int get_termios_get_ioctl(void)
|
||||
{
|
||||
#ifdef HAVE_TERMIOS2
|
||||
return TCGETS2;
|
||||
#else
|
||||
return TCGETS;
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_termios_set_ioctl(void)
|
||||
{
|
||||
#ifdef HAVE_TERMIOS2
|
||||
return TCSETS2;
|
||||
#else
|
||||
return TCSETS;
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_termios_size(void)
|
||||
{
|
||||
#ifdef HAVE_TERMIOS2
|
||||
return sizeof(struct termios2);
|
||||
#else
|
||||
return sizeof(struct termios);
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_termios_speed(void *data)
|
||||
{
|
||||
#ifdef HAVE_TERMIOS2
|
||||
struct termios2 *term = (struct termios2 *) data;
|
||||
#else
|
||||
struct termios *term = (struct termios *) data;
|
||||
#endif
|
||||
if (term->c_ispeed != term->c_ospeed)
|
||||
return -1;
|
||||
else
|
||||
return term->c_ispeed;
|
||||
}
|
||||
|
||||
void set_termios_speed(void *data, int speed)
|
||||
{
|
||||
#ifdef HAVE_TERMIOS2
|
||||
struct termios2 *term = (struct termios2 *) data;
|
||||
#else
|
||||
struct termios *term = (struct termios *) data;
|
||||
#endif
|
||||
term->c_cflag &= ~CBAUD;
|
||||
term->c_cflag |= BOTHER;
|
||||
term->c_ispeed = term->c_ospeed = speed;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This file is part of the libserialport project.
|
||||
*
|
||||
* Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
int get_termios_get_ioctl(void);
|
||||
int get_termios_set_ioctl(void);
|
||||
int get_termios_size(void);
|
||||
int get_termios_speed(void *data);
|
||||
void set_termios_speed(void *data, int speed);
|
60
serialport.c
60
serialport.c
|
@ -44,6 +44,7 @@
|
|||
#ifdef __linux__
|
||||
#include "libudev.h"
|
||||
#include "linux/serial.h"
|
||||
#include "linux_termios.h"
|
||||
#endif
|
||||
|
||||
#include "libserialport.h"
|
||||
|
@ -94,6 +95,8 @@ const struct std_baudrate std_baudrates[] = {
|
|||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
|
||||
|
||||
#define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
|
||||
|
||||
/* Helper functions. */
|
||||
static enum sp_return validate_port(struct sp_port *port);
|
||||
static struct sp_port **list_append(struct sp_port **list, const char *portname);
|
||||
|
@ -558,6 +561,41 @@ enum sp_return sp_read(struct sp_port *port, void *buf, size_t count)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static enum sp_return get_baudrate(int fd, int *baudrate)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if (!(data = malloc(get_termios_size())))
|
||||
return SP_ERR_MEM;
|
||||
|
||||
if (ioctl(fd, get_termios_get_ioctl(), data) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
|
||||
*baudrate = get_termios_speed(data);
|
||||
|
||||
return SP_OK;
|
||||
}
|
||||
|
||||
static enum sp_return set_baudrate(int fd, int baudrate)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if (!(data = malloc(get_termios_size())))
|
||||
return SP_ERR_MEM;
|
||||
|
||||
if (ioctl(fd, get_termios_get_ioctl(), data) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
|
||||
set_termios_speed(data, baudrate);
|
||||
|
||||
if (ioctl(fd, get_termios_set_ioctl(), data) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
|
||||
return SP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum sp_return get_config(struct sp_port *port, struct port_data *data,
|
||||
struct sp_port_config *config)
|
||||
{
|
||||
|
@ -669,6 +707,8 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data,
|
|||
if (i == NUM_STD_BAUDRATES) {
|
||||
#ifdef __APPLE__
|
||||
config->baudrate = (int)data->term.c_ispeed;
|
||||
#elif defined(__linux__)
|
||||
TRY(get_baudrate(port->fd, &config->baudrate));
|
||||
#else
|
||||
config->baudrate = -1;
|
||||
#endif
|
||||
|
@ -727,7 +767,7 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data,
|
|||
return SP_OK;
|
||||
}
|
||||
|
||||
static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
||||
static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
||||
const struct sp_port_config *config)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -736,6 +776,9 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
|
||||
baud_nonstd = B0;
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
int baud_nonstd = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (config->baudrate >= 0) {
|
||||
|
@ -870,6 +913,8 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
int controlbits;
|
||||
|
||||
if (config->baudrate >= 0) {
|
||||
for (i = 0; i < NUM_STD_BAUDRATES; i++) {
|
||||
if (config->baudrate == std_baudrates[i].value) {
|
||||
|
@ -889,6 +934,8 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
if (cfsetspeed(&data->term, B9600) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
baud_nonstd = config->baudrate;
|
||||
#elif defined(__linux__)
|
||||
baud_nonstd = 1;
|
||||
#else
|
||||
return SP_ERR_ARG;
|
||||
#endif
|
||||
|
@ -971,7 +1018,7 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
if (config->rts == SP_RTS_FLOW_CONTROL) {
|
||||
data->term.c_iflag |= CRTSCTS;
|
||||
} else {
|
||||
int controlbits = TIOCM_RTS;
|
||||
controlbits = TIOCM_RTS;
|
||||
if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
|
||||
&controlbits) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
|
@ -985,7 +1032,7 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
return SP_ERR_ARG;
|
||||
|
||||
if (config->dtr >= 0) {
|
||||
int controlbits = TIOCM_DTR;
|
||||
controlbits = TIOCM_DTR;
|
||||
if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
|
||||
&controlbits) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
|
@ -1023,15 +1070,16 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
|
|||
if (cfsetspeed(&data->term, baud_nonstd) < 0)
|
||||
return SP_ERR_FAIL;
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
#elif defined(__linux__)
|
||||
if (baud_nonstd)
|
||||
TRY(set_baudrate(port->fd, config->baudrate));
|
||||
#endif
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
return SP_OK;
|
||||
}
|
||||
|
||||
#define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
|
||||
|
||||
enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config)
|
||||
{
|
||||
struct port_data data;
|
||||
|
|
Loading…
Reference in New Issue