Hi guys!
Setting non-standard baud rates is tricky (as it is poorly documented),
however I've managed to get though it some time ago (not for EPICS) and
such setting should work reliably since Linux kernel 2.6.0.
I used PicoCom terminal emulator sources for reference, see
https://urldefense.us/v3/__https://github.com/npat-efault/picocom/blob/master/termios2.c__;!!G_uCfscf7eWS!cKSRpZwLVot9cUcgFgCyKPu1XBIzaNM5bhgYzBGmbpTOcDrTLGFxoqSE60Tlfy-SfXwVAkYC3g36NVWUr-FxXyMaPWrkNyhfaJg$
Attached are the code to set arbitrary baud rate
(set_tty_speed_via_termios2.c) and a sample program to test it (ttycat.c).
In my tests such non-standard setting works not only for hardware serial
ports, but for USB-232/485 adapters too. Looking into kernel sources
suggests that Linux uses bitrate numbers internally, while Bnnnnn are for
compatibility only and, AFAIR, translation between Bnnnnn and baudrates
occur on the userspace/kernelspace border.
BTW, recent glibc 2.42 changelog (see
https://urldefense.us/v3/__https://elixir.bootlin.com/glibc/glibc-2.42.9000/source/NEWS__;!!G_uCfscf7eWS!cKSRpZwLVot9cUcgFgCyKPu1XBIzaNM5bhgYzBGmbpTOcDrTLGFxoqSE60Tlfy-SfXwVAkYC3g36NVWUr-FxXyMaPWrkz6ln3SA$ ) contains
following statement:
* On Linux, the <termios.h> interface now supports arbitrary baud rates;
speed_t is redefined to simply be the baud rate specified as an
unsigned int, which matches the kernel interface.
With best regards,
Dmitry
On Mon, 12 Jan 2026, Michael Davidsaver via Tech-talk wrote:
On 1/12/26 11:26 AM, Johnson, Andrew N. via Tech-talk wrote:
This blog post
<https://urldefense.us/v3/__https://gcc02.safelinks.protection.outlook.com/?url=https*3A*2F*2Fwww.downtowndougbrown.com*2F2013*2F11*2Flinux-custom-serial-baud-rates*2F&data=05*7C02*7Ctech-talk*40aps.anl.gov*7Ca3836f92114248b786c808de52108515*7C0cfca18525f749e38ae7704d5326e285*7C0*7C0*7C639038428051304183*7CUnknown*7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ*3D*3D*7C0*7C*7C*7C&sdata=XQMOLbcC0dzIVGEFDyotqFGAC*2B65cr8Qv*2Fr3188e0io*3D&reserved=0__;JSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSU!!G_uCfscf7eWS!bTCnxDZJfSsva3HtMnmfiFOH98GYpHn8QhyD8XV1R2Iw5jme4gFhbhJxsC1rv4xujo4gVHPVQiXMcaMT$> might
be helpful on how to modify Asyn to request non-standard baud rates on
some Linux systems at least.
A quick glance at "man termios" makes mention of "ioctl(TCSETS2)" in
conjunction with "c_cflag |= BOTHER" (a great name!) to request arbitrary
baud rates. Might make a nice codeathon project to add this as a fallback,
if only for Linux.
See EXAMPLES from:
https
://https://urldefense.us/v3/__http://www.man7.org/linux/man-pages/man2/tcsets2.2const.html__;!!G_uCfscf7eWS!dbq7XA-2qQHA82PjWanr52eEDuu_YD7tR8vkfGlbuwQZ9IUjv5XNpMROUgbYZlcqbJPXLf0GevpB_mB0iknfIIqBQw$
- Andrew
--
Complexity comes for free, Simplicity you have to work for.
On 1/12/26, 12:26?PM, "Tech-talk" <tech-talk-bounces at aps.anl.gov> wrote:
My quick google search suggests that it?s necessary to write a program to
do this.
For python it recommends:
import serial
ser = serial.Serial('/dev/ttyS0', 28800)
print(ser.baudrate)
I tried this on Debian and it ran with no complaints.
On Jan 12, 2026, at 9:53?AM, Mark Rivers <rivers at cars.uchicago.edu>
wrote:
Hi Eric,
I have an RHEL 9 system. How do I set an arbitrary baud rate using
termios2 from the shell? When I use stty I get an error:
[epics@13idd ~]$ stty -F /dev/ttyUSB0 28800
stty: invalid argument ?28800?
Try 'stty --help' for more information.
Thanks,
Mark
?
Eric Norum
eric at norum.ca
#ifndef __SET_TTY_SPEED_VIA_TERMIOS2
#define __SET_TTY_SPEED_VIA_TERMIOS2
int set_tty_speed_via_termios2(int fd, unsigned int cflag, int speed);
#endif /* __SET_TTY_SPEED_VIA_TERMIOS2 */
#ifdef __linux__
// Check copied from https://github.com/npat-efault/picocom/blob/master/termios2.c
#include <linux/version.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)
#warning "Linux kernel is too old for termios2"
#else
#include <stdio.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <asm/termbits.h>
#include "set_tty_speed_via_termios2.h"
int set_tty_speed_via_termios2(int fd, unsigned int cflag, int speed)
{
struct termios2 t2;
int r;
bzero(&t2, sizeof(t2));
t2.c_cflag = (cflag &~ (CBAUD | CBAUDEX)) | BOTHER;
t2.c_iflag = IGNPAR;
t2.c_oflag = 0;
t2.c_lflag = 0;
t2.c_cc[VTIME] = 0;
t2.c_cc[VMIN] = 1;
t2.c_ispeed = speed;
t2.c_ospeed = speed;
r = ioctl(fd, TCSETS2, &t2);
#ifdef DEBUG_TERMIOS2 // Use "-DDEBUG_TERMIOS2" switch in compiler commandline
{
struct termios2 t2_rb;
ioctl(fd, TCGETS2, &t2_rb);
fprintf(stderr, "i=%d o=%d\n", t2_rb.c_ispeed, t2_rb.c_ospeed);
}
#endif
return r;
}
#endif /* LINUX_VERSION_CODE */
#endif /* __linux__ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#ifdef __linux__
#include <linux/version.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)
#warning "Linux kernel is too old for termios2"
#else
#include "set_tty_speed_via_termios2.h"
#define MAY_USE_TERMIOS2 1
#endif
#endif /* __linux__ */
int set_fd_flags (int fd, int mask, int onoff)
{
int r;
int flags;
/* Get current flags */
flags = r = fcntl(fd, F_GETFL, 0);
if (r < 0) return -1;
/* Modify the value */
flags &=~ mask;
if (onoff != 0) flags |= mask;
/* And try to set it */
r = fcntl(fd, F_SETFL, flags);
if (r < 0) return -1;
return 0;
}
int main(int argc, char *argv[])
{
enum {N_CON = 0, N_TTY = 1};
int fdpair[2]; // FDs for select() and read()
int wrpair[2]; // fds for write()
fd_set rfds;
int n;
int maxfd;
int r;
char buf[100];
struct termios newtio;
if (argc < 3)
{
fprintf(stderr, "Usage: %s /dev/ttySOME_TTY_NAME SPEED_IN_BAUDS_PER_SECOND\n", argv[0]);
return 1;
}
fdpair[N_CON] = 0; // stdin
if (isatty(fdpair[N_CON]) && argc <= 3) // Switch to noncanonical mode (so that input is available immediately) if we are at terminal and this switch is NOT explicitly forbidden by argv[3] presence
{
tcgetattr(fdpair[N_CON], &newtio);
//cfmakeraw (&newtio); // Use with caution! Ctrl+C,Ctrl+Z, etc. stop working and these changes remain in effect even after program termination
newtio.c_lflag |= ECHO;
newtio.c_lflag &=~ ICANON;
tcsetattr(fdpair[N_CON], TCSANOW, &newtio);
}
set_fd_flags(fdpair[N_CON], O_NONBLOCK, 1);
fdpair[N_TTY] = open(argv[1], O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fdpair[N_TTY] < 0)
{
perror("open()");
return 2;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
tcflush(fdpair[N_TTY], TCIOFLUSH);
#if MAY_USE_TERMIOS2
r = set_tty_speed_via_termios2(fdpair[N_TTY], newtio.c_cflag, atoi(argv[2]));
#else
r = tcsetattr(fdpair[N_TTY], TCSANOW, &newtio);
#endif
if (r != 0)
{
perror("tcsetattr()");
}
wrpair[N_CON] = 1; // stdout
wrpair[N_TTY] = fdpair[N_TTY];
while (1)
{
FD_ZERO(&rfds);
for (maxfd = -1, n = 0; n < 2; n++)
if (fdpair[n] >= 0)
{
FD_SET(fdpair[n], &rfds);
if (maxfd < fdpair[n])
maxfd = fdpair[n];
}
if (maxfd < 0) return 0;
r = select(maxfd + 1, &rfds, NULL, NULL, NULL);
if (r < 0)
{
perror("select()");
return 3;
}
for (n = 0; n < 2; n++)
if (fdpair[n] >= 0 && FD_ISSET(fdpair[n], &rfds))
{
r = read(fdpair[n], &buf, sizeof(buf));
if (n == N_TTY && r <= 0) return 0; // Nothing more to do if serial link is inoperational (r==0 means "USB-485 adapter plugged out", so we must release the /dev/ttyUSB* file for adapter to get the same /dev/ file upon re-plugging)
if (r < 0)
{
fdpair[n] = -1;
}
else
write(wrpair[1-n], &buf, r);
}
}
return 0;
}
- References:
- Configuration of the RGA200 communication baud rate LONG FENG via Tech-talk
- Re: Configuration of the RGA200 communication baud rate Eric Norum via Tech-talk
- Re: Configuration of the RGA200 communication baud rate Mark Rivers via Tech-talk
- Re: Configuration of the RGA200 communication baud rate Eric Norum via Tech-talk
- Re: Configuration of the RGA200 communication baud rate Johnson, Andrew N. via Tech-talk
- Re: Configuration of the RGA200 communication baud rate Michael Davidsaver via Tech-talk
- Navigate by Date:
- Prev:
Re: Configuration of the RGA200 communication baud rate Michael Davidsaver via Tech-talk
- Next:
Re: Problems with clang under MacOS Torsten Bögershausen via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
<2026>
- Navigate by Thread:
- Prev:
Re: Configuration of the RGA200 communication baud rate Michael Davidsaver via Tech-talk
- Next:
Re: Configuration of the RGA200 communication baud rate Érico Nogueira Rolim via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
<2026>
|