How to efficiently convert baudrate from int to speed_t?
Asked Answered
I

2

7

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?

Interlope answered 15/11, 2017 at 15:39 Comment(6)
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....Precipitate
const lookup table?Blackface
Those BXXX things should really have been an enum.Blackface
@MichaelWalz I'm asking about int->size_t, not the opposite.Interlope
@MartinJames Lookup table doesn't make sense because most of the array elements would be blank: lookup[50] = B50, etc.Interlope
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).Niobous
O
9

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;
    }
}
Obtain answered 7/4, 2018 at 19:16 Comment(4)
Careful that speed_t in linux is unsigned so returning -1 might not be what you want. See code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/bits/…Mercaptopurine
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?Fatty
-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.Niobous
Saved a lot of time. ThanksDoublecheck
L
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.

Lamson answered 15/11, 2017 at 16:57 Comment(6)
I would indeed prefer a switch/case here, the compiler can optimize that better.Literature
@Literature 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.Lamson
@Literature beware of premature optimization.Lamson
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.Literature
@Literature not quite sure you understood my point, google "premature optimization"Lamson
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 optimizationLiterature

© 2022 - 2024 — McMap. All rights reserved.