Posix Serial Port Raw Read hanging - c

I'm testing an UART application on the BeagleBone Black and when I try to read from the device it blocks forever. A write works fine. I hooked up a logic analyzer to inspect the line and I can see the data being transmitted and received, but it just always blocks on a read.
int main() {
int res;
struct termios tty;
memset(&tty, 0, sizeof(tty));
int serial = open("/dev/ser2", O_RDWR | O_NOCTTY);
if (!isatty(serial))
return false;
// Setting the Baud rate
cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600);
// 8N1 Mode
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CREAD | CLOCAL;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG);
tty.c_oflag &= ~OPOST;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
if ((tcsetattr(serial, TCSANOW, &tty)) != 0)
return false;
if ((tcflush(serial, TCIOFLUSH)) != 0)
return false;
while (1)
{
uint8_t wrBuff[3] = {0xAA, 0xBB, 0xCC};
uint8_t res = write(serial, wrBuff, 3);
printf("Write = %d", res);
res = read(serial, wrBuff, 3);
printf("Read = %d", res);
}
return 0;
}
I attempted the fix mentioned in the comments below regards the incorrect flag set but this did not fix the issue.

Related

C: Read function does not return error on disconnected serial USB device

I have a C application which opens a /dev/ttyUSB* port
fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
options.c_oflag &= (tcflag_t) ~(OPOST);
options.c_cflag |= CS8;
options.c_cflag |= CRTSCTS;
options.c_lflag &= ~(ICANON | ECHO | ISIG);
tcsetattr(fd, TCSANOW, &options);
struct serial_struct kernel_serial_settings;
if (ioctl(fd, TIOCGSERIAL, &kernel_serial_settings) == 0) {
kernel_serial_settings.flags |= ASYNC_LOW_LATENCY;
kernel_serial_settings..
ioctl(fd, TIOCSSERIAL, &kernel_serial_settings);
}
The port is opened, and I receive data. If however the USB device is disconnected later on, and I call the read function:
nRead = _read(fd, buffer, length);
nRead will return 0. I would expect that it should return a negative number to indicate an error (that the device is no longer available).
How do I detect that the opened device was disconnected?
When read() returns zero, you can call stat() on the device filename. If the USB device is disconnected, the device node has vanished, and stat() will return -1 with errno==ENOENT.

Inverting output of /dev/ttyUSB0

I'm trying to inverted the output of /dev/ttyUSB0.
I'm working "C". I'm new to Linux but you won't hurt my feelings if you tell me this a stupid question.
I have 2 sources of RS485; one from a Raspberry Pi that looks like this:
From Raspberry Pi RS485 "shield"/daughter board (/dev/serial0):
+
|--| |--|
| | | |
____| |_____| |_________
-
The other is from an USB to RS485 converter on an Ubuntu machine (/dev/ttyUSB0):
+
_____ _______ __________
| | | |
| | | |
|--| |--|
-
I'd like to invert the 2nd/Ubuntu version so it looks like the Raspberry Pi version.
Here's my code:
int set_interface_attribs(int fd, int baudRateFlag)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0)
{
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)baudRateFlag);
cfsetispeed(&tty, (speed_t)baudRateFlag);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
// TODO: CRTSCTS isn't defined in termios.h
// but is in "arm-linux-gnueabihf\bits\termios.h"
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0)
{
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}

How to listen on serial port with C using CRTSCTS

I am trying to listen to a serial port with a C program utilizing CRTSCTS (to prevent an independently powered Arduino from rebooting after the computer it is connected to restarts).
I started with the code from here: Canonical Mode Linux Serial Port
After some adaptations it looks like this:
#define SERIALTERMINAL "/dev/ttyUSB0"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
//tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= ~CRTSCTS; //trying to turn on CRTSCTS
tty.c_cflag &= ~HUPCL; //trying turning off HUPCL - it works!
tty.c_lflag |= ICANON | ISIG; /* canonical input */
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
tty.c_iflag &= ~IGNCR; /* preserve carriage return */
tty.c_iflag &= ~INPCK;
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */
//tty.c_iflag |= ~IXON; //try ixon
tty.c_oflag &= ~OPOST;
tty.c_cc[VEOL] = 0;
tty.c_cc[VEOL2] = 0;
tty.c_cc[VEOF] = 0x04;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main()
{
char *portname = SERIALTERMINAL;
int fd;
int wlen;
//fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); original version
fd = open(portname, O_RDONLY | O_NOCTTY);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
/* simple canonical input */
do {
unsigned char buf[700];
unsigned char *p;
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
buf[rdlen] = 0;
printf("%s", buf);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Nothing read. EOF?\n");
}
/* repeat read */
} while (1);
}
When the program is run it doesn't show any output.
Going back out of CRTSCTS mode by swapping:
tty.c_cflag |= ~CRTSCTS;
with
tty.c_cflag &= ~CRTSCTS;
the program will show output but it is then not in the CRTSCTS mode which I need in order to prevent sending a DTR signal which results in an Arduino reset.
I have tried quite a few different options after reading through the Termios documentation: http://man7.org/linux/man-pages/man3/termios.3.html but to no avail.
So the question is what combination of options will allow reading from the serial port without sending a DTR signal?

C program setting port parameters before opening port fails

I am trying to write c code on a Linux system, where I set the serial port parameters then open the serial port, then I have found out that even though the code compiles and runs, I cannot read and write from that serial port (so the serial port was not opened successfully)!
Code that works (not needed):
int fd;
char *portname;
portname = "/dev/ttyUSB0";
struct termios tty;
fd = open(portname, O_RDWR | O_NOCTYY | O_SYNC );
memset(&tty,0,sizeof tty);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOP;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tcsetattr(fd,TCSANOW,&tty);
Code that doesn't work (needed)
int fd;
char *portname;
portname = "/dev/ttyUSB0";
struct termios tty;
memset(&tty,0,sizeof tty);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOP;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tcsetattr(fd,TCSANOW,&tty);
fd = open(portname, O_RDWR | O_NOCTYY | O_SYNC );
Solid question: My application sequence requires me to set serial port parameters then open the serial port. Is there a way to do this? if yes, how?
I appreciate your help.
Update: Removed C++ code noticed by #Alter Mann.
Update: Removed zeroing-out the termios structure noticed by #sawdust.
In first case you get actual file descriptor fd and after use it. In second case you try setting up uninitialized file descriptor fd (probably 0 if it's declared in global scope) and after get actual value of it.
Below is workaround which works for me:
#include <fcntl.h>
#include <termios.h>
#include <strings.h>
#include <stdlib.h>
int main (int argc, char * argv [])
{
struct termios tty;
const char * portname = "/dev/ttyUSB0";
const int fd = open (portname, O_RDONLY);
if (-1 == fd) {
// Problem...
return EXIT_FAILURE;
}
if (tcgetattr (fd, &tty) < 0) {
// Problem...
return EXIT_FAILURE;
}
cfsetospeed (&tty, (speed_t) B9600);
cfsetispeed (&tty, (speed_t) B9600);
tty.c_cflag |= B9600;
tty.c_cflag |= (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= IGNPAR;
tty.c_cflag &= ~(CRTSCTS);
tty.c_cflag &= ~(CSTOPB);
tty.c_iflag |= IGNBRK;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_lflag = 0;
tty.c_oflag = 0;
tcflush (fd, TCIFLUSH);
if (tcsetattr (fd, TCSANOW, &tty) ) {
// Problem...
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

Lost bit in reading from serial port

I'm trying to read data from custom hardware using serial port. I believe the configuration was right. The problem is, I see some of the byte is missing. In the data, length of the data is specified, so I know if some of the data were missing.
My configuration is as follows :
int set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) return -1;
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // raw input
tty.c_cc[VMIN] = 1; // read does block
tty.c_cc[VTIME] = 0; // 0 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl (flow control)
//disable hw flow control
#ifdef CRTSCTS
tty.c_cflag &= ~CRTSCTS;
#endif
#ifdef CNEW_RTSCTS
tty.c_cflag &= ~CNEW_RTSCTS;
#endif
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_iflag &= ~(ISTRIP | IGNCR | INLCR | ICRNL
#ifdef IUCLC
| IUCLC
#endif
);
tty.c_oflag &= ~(OPOST
#ifdef ONLCR
| ONLCR
#endif
#ifdef OCRNL
| OCRNL
#endif
#ifdef ONOCR
| ONOCR
#endif
#ifdef ONLRET
| ONLRET
#endif
);
if (tcsetattr (fd, TCSANOW, &tty) != 0) return -1;
return 0;
}
this is how I read it :
int fd = open (portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
char buf [10];
while(1) {
int n = 0;
while (n = read (fd, buf, sizeof buf) > 0) {
write(STDOUT_FILENO, buf, n); //this printing
.. other job ..
}
}
below is the example of data :
// correct data
#*69880001000800010007003F4530302403322402FE24080524000024012C2400142430303030302452B4FF
// example of lost data (lost data is signed by _ )
#*69880001000800010007003F4530302403322402FE2408092_000_24012C240014243030303030241674FF
#*69880001000800010007003F4530302403312402FF24080524_00024012C240014243030303030244EF9FF
For the configuration, What I'll need is :
baud rate : 19200
data bits : 8
stop bits : 1
parity : none
flow control : none
FYI, my hardware is sending data byte-per-byte. So n in the code above is always 1 (or 0).
When I try using putty, everything is okay. Is there something I missed?
Thank you

Resources