6

The functions cfsetospeed and cfsetispeed take baud rate as type speed_t:

int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);

The type speed_t is basically an integer, but casting is not a solution, as can be seen from the baudrate definitions in termios.h:

#define B0  0x00000000
#define B50 0x00000001
#define B75 0x00000002
// ...
#define B9600   0x0000000d
#define B19200  0x0000000e
#define B38400  0x0000000f

When I process user input (e.g. from file), I convert a string such as "9600" to integer 9600, and then to B9600. I'm basically looking for a generic way to convert the following:

// 0 -> B0
// 50 -> B50
// 75 -> B75
// ...
// 9600 -> B9600 
// 19200 -> B19200
// 38400 -> B38400

One way to convert from int (such as 9600) to speed_t (such as B9600) is a switch-case structure. Is there a better way to achieve this?

Sparkler
  • 2,581
  • 1
  • 22
  • 41
  • 1
    The switch-case-structure seems like a good solution... maybe encapsuled in a conversion function `speed_t baudrate(int br) { ... }`, then your code looks quite elegant with `cfsetispeed(term, baudrate(19200));` or similar.... – Ctx Nov 15 '17 at 15:46
  • 1
    const lookup table? – Martin James Nov 15 '17 at 15:57
  • 1
    Those BXXX things should really have been an enum. – Martin James Nov 15 '17 at 15:59
  • @MichaelWalz I'm asking about int->size_t, not the opposite. – Sparkler Nov 15 '17 at 16:39
  • @MartinJames Lookup table doesn't make sense because most of the array elements would be blank: lookup[50] = B50, etc. – Sparkler Nov 15 '17 at 16:40
  • Don't use `int` to hold the value of the baud except when you are sure all the platforms your code will ever run on have a large enough `int`. also, a baud rate can not be negative. Better would be `uint_fast32_t`, `uint_least32_t`, `unsigned long` or `uint32_t` (when you are sure this type exist, which is almost everywhere the case). – 12431234123412341234123 Jul 07 '21 at 10:55

2 Answers2

7

I came across needing this. Pasting the switch case statement here for you to copy.

int get_baud(int baud)
{
    switch (baud) {
    case 9600:
        return B9600;
    case 19200:
        return B19200;
    case 38400:
        return B38400;
    case 57600:
        return B57600;
    case 115200:
        return B115200;
    case 230400:
        return B230400;
    case 460800:
        return B460800;
    case 500000:
        return B500000;
    case 576000:
        return B576000;
    case 921600:
        return B921600;
    case 1000000:
        return B1000000;
    case 1152000:
        return B1152000;
    case 1500000:
        return B1500000;
    case 2000000:
        return B2000000;
    case 2500000:
        return B2500000;
    case 3000000:
        return B3000000;
    case 3500000:
        return B3500000;
    case 4000000:
        return B4000000;
    default: 
        return -1;
    }
}
Noel
  • 3,749
  • 3
  • 22
  • 21
  • 2
    Careful that `speed_t` in linux is unsigned so returning -1 might not be what you want. See https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/bits/termios.h.html – Danny Sep 24 '20 at 01:39
  • 1
    I just came across a library that uses `-1` and throws the signed warning in the compiler. So would `B0` be better? `termios.h` defines it. Is there such a thing as zero baud or is this about as good as `-1` was intended? – tresf Jun 04 '21 at 20:20
  • -1 for using an `int` and not a `speed_t`, for using negative values and the inconsistent indention style. Also, `int` is not sufficient for holding the value `38400` or anything above. Better use something like `uint_fast32_t` or `unsigned long`. – 12431234123412341234123 Jul 07 '21 at 10:52
  • 1
    Saved a lot of time. Thanks – Rahul Das Aug 16 '22 at 17:01
4

You need a lookup table, but not a naive one:

#include <stdio.h>    
#include <termios.h>       

struct
{
  int rawrate;
  int termiosrate;
} conversiontable[] =
{
  {0, B0},
  {50, B50},
  {75, B75},
  // you need to complete the table with B110 to B38400
};

int convertbaudrate(int rawrate)
{
  for (int i = 0; i < sizeof(conversiontable) / sizeof(conversiontable[0]); i++)
  {
    if (conversiontable[i].rawrate == rawrate)
    {
      return conversiontable[i].termiosrate;
    }
  }

  return -1;    // invalid baud rate
}

int main()
{
  printf("%d -> %d\n", 50, convertbaudrate(50));
  printf("%d -> %d\n", 75, convertbaudrate(75));
}

That should autoexplain. If not, please comment.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • I would indeed prefer a switch/case here, the compiler can optimize that better. – Karim Nov 16 '17 at 10:56
  • @Karim probably true, but there is probably no need to optimize this unless `convertbaudrate` is called a lot of times which is most likely not the case. – Jabberwocky Nov 16 '17 at 10:58
  • @Karim beware of premature optimization. – Jabberwocky Nov 16 '17 at 11:02
  • 3
    Now this comment isn't fair here, keeping it simple with a switch/case statement and letting the compiler do the optimization is the exact opposite of premature optimization. – Karim Nov 16 '17 at 11:05
  • 1
    @Karim not quite sure you understood my point, google "premature optimization" – Jabberwocky Nov 16 '17 at 11:06
  • 4
    Ok, I did: `"Premature optimization" is a phrase used to describe a situation where a programmer lets performance considerations affect the design of a piece of code. This can result in a design that is not as clean as it could have been or code that is incorrect, because the code is complicated by the optimization and the programmer is distracted by optimizing.` Now, what did I understand wrong? I suggested to leave the code clean and simple and give the compiler the opportunity to optimize, this is exactly the opposite from premature optimization – Karim Nov 16 '17 at 11:10