Reputation: 1707
I am using C to open a serial device and send/receive data to/from it. Receiving works without a problem, but any data I send does not reach the device. I open the device like this:
int open_tty() {
int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_CLOEXEC);
struct termios config;
cfsetispeed(&config, B38400);
cfsetospeed(&config, B38400);
config.c_cflag &= ~PARENB;
config.c_cflag &= ~CSTOPB;
config.c_cflag &= ~CSIZE;
config.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &config);
return fd;
}
...
write(fd, data, length)
...
According to strace, everything works just fine:
openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
write(3, "some data.......", 16) = 16
However, the device does not receive any data (it should send an ACK packet). If I do the same thing in python, everything works just fine:
s=serial.Serial('/dev/ttyUSB0', baudrate=9600*4)
s.write('some data.......')
strace:
openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TIOCMBIS, [TIOCM_DTR]) = 0
ioctl(3, TIOCMBIS, [TIOCM_RTS]) = 0
ioctl(3, TCFLSH, TCIFLUSH) = 0
write(3, "some data.......", 16) = 16
Any help would be greatly appreciated.
EDIT: As @abarnert suggested, I set the DTR and RTS bits and flushed the buffer:
char rts = TIOCM_RTS;
char dtr = TIOCM_DTR;
ioctl(fd, TIOCMBIS, &dtr);
ioctl(fd, TIOCMBIS, &rts);
tcflush(fd, TCIFLUSH);
This led to the following additional syscalls being dispatched directly before the write
call:
ioctl(3, TIOCMBIS, [TIOCM_DTR|TIOCM_DSR|0x200]) = 0
ioctl(3, TIOCMBIS, [[TIOCM_RTS|0x30200}) = 0
ioctl(3, TCFLSH, TCIFLUSH) = 0
However, I still don't get any ACK packet back from the device.
The device is a VirtualRobotix GPS uBlox 8 (http://www.virtualrobotix.it/index.php/en/shop/gps/3dr-gps-ublox-8-542015-11-30-13-35-34_-detail) connected using a USB to serial converter.
Upvotes: 0
Views: 379
Reputation: 12668
Hmmmm, I'm afraid you have not followed the correct procedure in setting termios
parameters. First you must use tcgetattrs(3)
to get the actual configured parameters (and to initialize the termios
structure, otherwise uninitialized to garbage in your code, as you have declared it as an automatic variable), then you change what you want, and finally you set the desired configuration.
The correct procedure is:
struct termios param;
res = tcgetattrs(fd, ¶m); /* VERY IMPORTANT: first get the actual parameters */
if (res < 0) {
perror("tegetattrs");
exit(EXIT_FAILURE);
}
cfsetispeed(¶m, B38400);
cfsetospeed(¶m, B38400);
param.c_cflag &= ~PARENB;
/* ... all the needed configuration. */
/* and finally. */
res = tcsetattrs(fd, ¶m);
if (res < 0) { /* error */
perror("tcsetattrs");
exit(EXIT_FAILURE);
}
(Also, it's common to check the return value res
for errors)
as the manual page termios(3)
says in relation to setting the line speed:
Line speed
The baud rate functions are provided for getting and setting the values of the input and output baud rates in the
termios
structure. The new values do not take effect untiltcsetattr()
is successfully called.Setting the speed to
B0
instructs the modem to "hang up". The actual bit rate corresponding toB38400
may be altered withsetserial(8)
.The input and output baud rates are stored in the
termios
structure.
(quotation is mine)
Upvotes: 1