Skip to content

Commit

Permalink
support BOTHER mechanism for arbitrary baud rates
Browse files Browse the repository at this point in the history
This enables setting a serial port baud rate to something other than
the Bxxxxx constants using BOTHER, c_ispeed, and c_ospeed. BOTHER
is only used when needed and only enabled when supported.
  • Loading branch information
asquared committed Nov 8, 2012
1 parent ffe1298 commit 631f375
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions ext/native/posix_serialport_impl.c
Expand Up @@ -22,13 +22,22 @@
/* Check if we are on a posix compliant system. */
#if !defined(OS_MSWIN) && !defined(OS_BCCWIN) && !defined(OS_MINGW)

#ifdef OS_LINUX
/* rename termios to termios_k so it doesn't clash with termios.h */
#define termios termios_k
#include <asm/termbits.h> /* termios2 and BOTHER to support odd baud rates */
#undef termios
#endif

#include <stdio.h> /* Standard input/output definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>



#ifdef CRTSCTS
#define HAVE_FLOWCONTROL_HARD 1
#else
Expand Down Expand Up @@ -59,6 +68,44 @@ static char sTcgetattr[] = "tcgetattr";
static char sTcsetattr[] = "tcsetattr";
static char sIoctl[] = "ioctl";

#ifdef BOTHER
static void set_bother(int fd, int rate) {
struct termios2 params;
int ret;

fprintf(stderr, "BOTHERing %d to %d\n", fd, rate);
ret = ioctl(fd, TCGETS2, &params);
if (ret != 0) {
rb_sys_fail("TCGETS2");
}

params.c_ispeed = rate;
params.c_ospeed = rate;
params.c_cflag &= ~CBAUD;
params.c_cflag |= BOTHER;

ret = ioctl(fd, TCSETS2, &params);
if (ret != 0) {
rb_sys_fail("TCSETS2");
}
}

static int get_bother(int fd) {
struct termios2 params;
int ret;

ret = ioctl(fd, TCGETS2, &params);
if (ret != 0) {
rb_sys_fail("TCGETS2");
}

if ((params.c_cflag & CBAUD) == BOTHER) {
return params.c_ispeed;
} else {
return 0;
}
}
#endif

int get_fd_helper(obj)
VALUE obj;
Expand Down Expand Up @@ -186,6 +233,9 @@ VALUE sp_set_modem_params_impl(argc, argv, self)
VALUE _data_rate, _data_bits, _parity, _stop_bits;
int use_hash = 0;
int data_rate, data_bits;
#ifdef BOTHER
int bother_rate = 0;
#endif
_data_rate = _data_bits = _parity = _stop_bits = Qnil;

if (argc == 0)
Expand Down Expand Up @@ -265,7 +315,11 @@ VALUE sp_set_modem_params_impl(argc, argv, self)
#endif

default:
#ifdef BOTHER
bother_rate = FIX2INT(_data_rate);
#else
rb_raise(rb_eArgError, "unknown baud rate");
#endif
break;
}
cfsetispeed(&params, data_rate);
Expand Down Expand Up @@ -374,6 +428,12 @@ VALUE sp_set_modem_params_impl(argc, argv, self)
{
rb_sys_fail(sTcsetattr);
}

#ifdef BOTHER
if (bother_rate) {
set_bother(fd, bother_rate);
}
#endif
return argv[0];
}

Expand All @@ -383,13 +443,20 @@ void get_modem_params_impl(self, mp)
{
int fd;
struct termios params;
#ifdef BOTHER
int bother_rate;
#endif

fd = get_fd_helper(self);
if (tcgetattr(fd, &params) == -1)
{
rb_sys_fail(sTcgetattr);
}

#ifdef BOTHER
bother_rate = get_bother(fd);
#endif

switch (cfgetospeed(&params))
{
case B50: mp->data_rate = 50; break;
Expand Down Expand Up @@ -436,6 +503,12 @@ void get_modem_params_impl(self, mp)
#endif
}

#ifdef BOTHER
if (bother_rate != 0) {
mp->data_rate = bother_rate;
}
#endif

switch(params.c_cflag & CSIZE)
{
case CS5:
Expand Down

0 comments on commit 631f375

Please sign in to comment.