Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I set the baud rate to 307,200 on Linux?

Basically I'm using the following code to set the baud rate of a serial port:

struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
tcsetattr(fd, TCSANOW, &options);

This works very well. But know I have to communicate with a device that uses a baud rate of 307,200. How can I set that? cfsetispeed(&options, B307200); doesn't work, there is no B307200 defined.

I tried it using a MOXA Uport 1150 (that's actually a USB-to-serial converter) and the standard serial port of an Intel motherboard. I don't know the exact kind of the latter, setserial just reports it as 16550A.

like image 762
cairol Avatar asked Feb 11 '11 11:02

cairol


4 Answers

Linux uses a dirty method for non-standard baud rates, called "baud rate aliasing". Basically, you tell the serial driver to interpret the value B38400 differently. This is controlled with the ASYNC_SPD_CUST flag in serial_struct member flags.

You need to manually calculate the divisor for the custom speed as follows:

// Configure port to use custom speed instead of 38400
ioctl(port, TIOCGSERIAL, &ss);
ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
ss.custom_divisor = (ss.baud_base + (speed / 2)) / speed;
closestSpeed = ss.baud_base / ss.custom_divisor;

if (closestSpeed < speed * 98 / 100 || closestSpeed > speed * 102 / 100) {
    fprintf(stderr, "Cannot set serial port speed to %d. Closest possible is %d\n", speed, closestSpeed));
}

ioctl(port, TIOCSSERIAL, &ss);

cfsetispeed(&tios, B38400);
cfsetospeed(&tios, B38400);

Of course, you need a serial driver with suitable baud_base and divisor settings. The preceding snippet allows for 2% deviation, which should be ok for most purposes.

And to tell the driver to interpret B38400 as 38400 baud again:

ioctl(mHandle, TIOCGSERIAL, &ss);
ss.flags &= ~ASYNC_SPD_MASK;
ioctl(mHandle, TIOCSSERIAL, &ss);

As a word of caution: I'm not sure if this method is portable between other *nix flavors.

like image 142
cyco130 Avatar answered Oct 23 '22 12:10

cyco130


I accomplished this using termios2 and ioctl() commands.

struct termios2 options;
ioctl(fd, TCGETS2, &options);
options.c_cflag &= ~CBAUD;    //Remove current baud rate
options.c_cflag |= BOTHER;    //Allow custom baud rate using int input
options.c_ispeed = 307200;    //Set the input baud rate
options.c_ospeed = 307200;    //Set the output baud rate
ioctl(fd, TCSETS2, &options);

After that, you should be able to query the port settings and see your custom baud rate, as well as the other settings (possible with stty commands).

like image 40
Chef Pharaoh Avatar answered Oct 23 '22 13:10

Chef Pharaoh


On many OSes, the enumerated values are numerically equal to the baud rate. So just skip the macro/enumeration and pass the baud rate you want, e.g.

cfsetispeed(&options, 307200);

Of course you should check the return code to make sure this trick actually worked, furthermore not all baud rates are supported by all UARTs.

You can also try setting the options in struct serial_struct using the TIOCGSERIAL and TIOCSSERIAL ioctl codes.

like image 1
Ben Voigt Avatar answered Oct 23 '22 13:10

Ben Voigt


USB Negotiation has a similar issue. I found this answer for you which might be used as well:

struct serial_struct ser_info; 
ioctl(ser_dev, TIOCGSERIAL, &ser_info); 
ser_info.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY; 
ser_info.custom_divisor = ser_info.baud_base / CUST_BAUD_RATE; 
ioctl(ser_dev, TIOCSSERIAL, &ser_info);
like image 1
Bruce Chidester Avatar answered Oct 23 '22 13:10

Bruce Chidester