EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

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 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
<== Date ==> <== Thread ==>

Subject: Re: Configuration of the RGA200 communication baud rate
From: "Dmitry Yu. Bolkhovityanov via Tech-talk" <tech-talk at aps.anl.gov>
To: Michael Davidsaver <mdavidsaver at gmail.com>
Cc: Eric Norum <eric at norum.ca>, "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov>
Date: Tue, 13 Jan 2026 08:53:23 +0700 (+07)
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
ANJ, 19 Mar 2026 · Home · News · About · Talk · Base · Modules · Extensions ·
· Distributions · Download · Documents · Links · Licensing ·