Uncommon baud rate on serial port - Linux
Finally i've found another topic on stackoverflow wich is complete and solve my problem : How to set baud rate to 307200 on Linux?
Here is my code with the modification :
static int rate_to_constant(int baudrate) {
#define B(x) case x: return B##x
switch(baudrate) {
B(50); B(75); B(110); B(134); B(150);
B(200); B(300); B(600); B(1200); B(1800);
B(2400); B(4800); B(9600); B(19200); B(38400);
B(57600); B(115200); B(230400); B(460800); B(500000);
B(576000); B(921600); B(1000000);B(1152000);B(1500000);
B(2000000);B(2500000);B(3000000);B(3500000);B(4000000);
default: return 0;
}
#undef B
}
int Custom_Baudrate(const char* Device, int rate)
{
/*Declaration of all the variables needed*/
struct termios2 options;
struct serial_struct serinfo;
int file=-1;
int speed = 0;
int r=rate;
/* Open and configure serial port */
file = open(Device,O_RDWR|O_NOCTTY);
if(file==-1){printf("\nERROR : Unable to open the serial port\n\n");return 1;}
speed = rate_to_constant(r);
/*Find best Baudrate*/
if (speed == 0) {
/* Custom divisor */
serinfo.reserved_char[0] = 0;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= ASYNC_SPD_CUST;
serinfo.custom_divisor = ((serinfo.baud_base + (r / 2)) / r);
if (serinfo.custom_divisor < 1)
serinfo.custom_divisor = 1;
if (ioctl(file, TIOCSSERIAL, &serinfo) < 0) file=-1;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
if (serinfo.custom_divisor * r != serinfo.baud_base) {
warnx("actual baudrate is %d / %d = %f",
serinfo.baud_base, serinfo.custom_divisor,
(float)
serinfo.baud_base / serinfo.custom_divisor);
}
}
/*Set the best Baudrate (if desired baudrate is unvailable, it's set automatically at 38400)*/
fcntl(file, F_SETFL, 0);
tcgetattr(file, &options);
cfsetispeed(&options, speed ?: B38400);
cfsetospeed(&options, speed ?: B38400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
if (tcsetattr(file, TCSANOW, &options) != 0) file=-1;
/*Read the serial port*/
communicate_Serial_Port(file);
close(file);
return 1;
}
In this code you just have to precise wich baudrate you want and it find the nearest value that you can use. This value is based on the "base baudrate" of your device and it search a divisor to set the best baudrate. However, some baudrate should always being unavailable so this program will put the 38400 as a base (it's a choice).
I've test it with several baudrate and it always work.
I'm new on stackoverflow, i hope this post will complete correctly the question.
C code for non-standard baud rate on Debian/Raspberry Pi
So after a bit more searching I stumbled upon the following code at:
https://jim.sh/ftx/files/linux-custom-baudrate.c
Below, is a copy of the above code which I've dumbed down quite a bit for my purposes however, it should be quite simple to implement now.
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termio.h>
#include <linux/serial.h>
static int rate_to_constant(int baudrate) {
#define B(x) case x: return B##x
switch(baudrate) {
B(50); B(75); B(110); B(134); B(150);
B(200); B(300); B(600); B(1200); B(1800);
B(2400); B(4800); B(9600); B(19200); B(38400);
B(57600); B(115200); B(230400); B(460800); B(500000);
B(576000); B(921600); B(1000000);B(1152000);B(1500000);
default: return 0;
}
#undef B
}
int main() {
struct termios options;
struct serial_struct serinfo;
int fd;
int speed = 0;
int rate = 625000;
/* Open and configure serial port */
if ((fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY)) == -1)
{
return -1;
}
// if you've entered a standard baud the function below will return it
speed = rate_to_constant(rate);
if (speed == 0) {
/* Custom divisor */
serinfo.reserved_char[0] = 0;
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
return -1;
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= ASYNC_SPD_CUST;
serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate;
if (serinfo.custom_divisor < 1)
serinfo.custom_divisor = 1;
if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
return -1;
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
return -1;
if (serinfo.custom_divisor * rate != serinfo.baud_base) {
warnx("actual baudrate is %d / %d = %f",
serinfo.baud_base, serinfo.custom_divisor,
(float)serinfo.baud_base / serinfo.custom_divisor);
}
}
fcntl(fd, F_SETFL, 0);
tcgetattr(fd, &options);
cfsetispeed(&options, speed ?: B38400);
cfsetospeed(&options, speed ?: B38400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
//return -1;
}
//return fd;
char ping_cmd[] = {2,1};
char ping_rec[7];
write(fd,&ping_cmd,sizeof(ping_cmd));
read(fd,&ping_rec,sizeof(ping_rec));
int i;
for (i = 0; i < sizeof(ping_rec); i++)
{
printf("%d ",ping_rec[i]);
}
close(fd);
return 0;
}
As the more astute coders out there will notice, since I pulled this code into my main, the presence of all those "return -1" is almost certainly bad programming practice, however, I'm not sure how I should clean it up and hence I'd love hear your suggestions - I will make edits as suggested.
In the meantime though, should you face a similar problem to me, the above should do nicely.
Specifying non-standard baud rate for FTDI virtual serial port under Linux
You can't change baud base, I suppose it is hardware related. So messing with the module won't do you any good. In your third point you only talk about the first method proposed for setting a custom baudrate, where you need to access the tty->alt_speed
. It seems there is no interface to directly set tty struct from userspace, at least not with the ftdi_sio driver.
However, there is another method explained in the comments :
* 3. You can also set baud rate by setting custom divisor as follows
* - set tty->termios->c_cflag speed to B38400
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as
* follows:
* o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
* o custom_divisor set to baud_base / your_new_baudrate
Did you try it ?
Dealing with serial port at 100 baud rate
You're actually in luck. 100 baud is low enough that you can compute a divisor that will do it (1,152) with typical 16450-compatible serial ports (which is pretty much what everything is) and linux supports custom divisors with the spd_cust
parameter to setserial
.
Related Topics
Common Reasons for Bugs in Release Version Not Present in Debug Mode
How to Use Formatmessage() Properly in C++
Programmatically Reading a Web Page
How to Create a Utf-8 String Literal in Visual C++ 2008
What Are the Differences Between Overriding Virtual Functions and Hiding Non-Virtual Functions
Will Casting Around Sockaddr_Storage and Sockaddr_In Break Strict Aliasing
C++ Filehandling: Difference Between iOS::App and iOS::Ate
In C++11, Does 'I += ++I + 1' Exhibit Undefined Behavior
Are C++ Templates Just MACros in Disguise
How to Give Priority to Privileged Thread in Mutex Locking
When Should You Use the "This" Keyword in C++
Using Std::Bind with Member Function, Use Object Pointer or Not for This Argument
Printing Prime Numbers from 1 Through 100