Inverting output of /dev/ttyUSB0 - c

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;
}

Related

Linux read() not returning bytes immediately from usb serial device

I have a serial device connected via a FTDI serial to usb cable. The device sends 78 bytes every 10 msec. I am calling read() every 1 msec, so I expect read() to return 78 bytes every 10 calls (possibly split over 2 calls), and 0 bytes for 8-9 calls in between (my read() call provides a 2k byte buffer). However, what actually happens is read() returns 496 bytes every ~63 msec. I get all the data, but not as soon as it's available. It seems to be buffered somewhere until 496 bytes are accumulated.
Here's my code snippet that sets termios. Everything should be set for raw data. I believe that somehow, the buffering is happening in the linux USB driver, since VMIN and VTIME are both set to 0. Any ideas on how to get the data as soon as it's available? Possibly by tweaking the USB driver settings?
char *portname = "/dev/ttyUSB0";
fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
printf("Failed to open %s. errno = %d (%s)\n", portname, errno, strerror(errno));
return -1;
}
printf("%s opened successfully\n\n", portname);
struct termios settings;
if (tcgetattr(fd, &settings) < 0)
{
printf("tcgettattr() failed (%i): %s\n", errno, strerror(errno));
return -1;
}
cfsetispeed(&settings, B460800); /* set baud rate */
cfsetospeed(&settings, B460800);
settings.c_cflag &= ~PARENB; /* No parity */
settings.c_cflag &= ~CSTOPB; /* 1 stop bit */
settings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
settings.c_cflag |= CS8; /* Set the data bits = 8 */
settings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
settings.c_cflag |= CREAD | CLOCAL; /* Enable receiver, Ignore Modem Control lines */
settings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
settings.c_iflag &= ~(BRKINT | IGNBRK | ICRNL | INLCR | PARMRK | ISTRIP | IGNCR);
settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG | IEXTEN); /* Non Cannonical mode */
settings.c_lflag |= NOFLSH;
settings.c_oflag &= ~(OPOST | ONLCR); /* No Output Processing */
settings.c_cc[VMIN] = 0;
settings.c_cc[VTIME] = 0;
if ((tcsetattr(fd, TCSANOW, &settings)) != 0) /* Set the attributes to the termios structure */
{
printf("Error setting attributes\n");
return -1;
}

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.

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?

Posix Serial Port Raw Read hanging

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.

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