I'm trying to communicate with an external IC via UART/tty in C. I'm using a nanoPI neo2 (allwinner h5) and friendlyARM's own Linux OS (which is a modified Ubuntu core).
I'v tried to get it working, but the TX output of the pi is ?logical inverted?. You can see what I mean in the oscilloscope pictures. There you can see if I select the "Polarity Invert"- Mode the data is ok, but in normal mode it isn't working.
In the past, I got around that by setting the invert Bit of the MCU (e.g. PIC MCU), but the IC I'm using now doesn't support this feature.
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_NEO2
oscilloscope picture 1
oscilloscope picture 2
c source
#include <stdio.h>
//#include <errno.h>
//#include <termios.h>
//#include <unistd.h>
#include <string.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h>/* POSIX Terminal Control Definitions*/
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <unistd.h>
#include <sys/types.h>
#include <sys/signal.h>
/* source : http://stackoverflow.com/a/6947758 */
int fd;
int set_interface_attribs (int fd, int speed, int parity) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) {
perror ("error from tcgetattr");
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
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_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0) {
perror ("error from tcsetattr");
return -1;
}
return 0;
}
void set_blocking (int fd, int should_block) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
perror ("error from tggetattr");
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
perror ("error setting term attributes");
}
int main()
{
char *portname = "/dev/ttyS0";
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
//perror ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
write (fd, "hello!\n", 7); // send 7 character greeting
usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit
char buf [100];
int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read
}
Thanks in advance
Axel
The picture on the scope looks fine - it is an UART signal. The problem here is not programming-related, but failure to understand the difference between UART and RS-232.
You have picked RS-232 encoding on your scope, and RS-232 uses a different, inverted polarity compared to UART.
UART idles high voltage=Vdd, RS-232 idles at negative voltage < -3V.
On UART, a high voltage=Vdd bit means 1 and low voltage=0V means 0.
On RS-232, a high voltage > +3V bit means 0, and negative voltage < -3V means 1.
So when you try to decode a UART signal with RS-232 encoding, it works when you inverse the polarity. Apparently Rigol isn't picky about the actual voltage levels, since it doesn't understand that the signal is not RS-232 at all.
Related
I am writing c code to send and receive characters to and from an Ergometer using FTDI USB to RS232 Cable in Linux. The write function is working properly but the read function has failed. I am not getting any data back from the Ergometer. I have posted my code here:
#include <stdio.h> // standard input / output functions
#include <stdlib.h>
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdbool.h>
#define SOH 0x01 // Start of Header
#define ETB 0x17 // End of transmission block
#define ACK 0x06 // Acknowledged
#define NAK 0x15 // Not Acknowledged
#define GS 0x1D // Group separator
#define FP_WATT1_PROG 0x13
#define FP_CARDIO 0x2F
int main(){
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY );
/* Error Handling */
if ( USB < 0 )
{
printf("Error beim oeffnen");
}
// Configure Port
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
// Error Handling
if ( tcgetattr ( USB, &tty ) != 0 ) {
printf("error beim tcgetattr");
}
// Save old tty parameters
tty_old = tty;
// Set Baud Rate of 9600 Bps
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);
// 8 Bits, No Parity and 1 Stop bit settings
tty.c_cflag &= ~PARENB; // No Parity
tty.c_cflag &= ~CSTOPB; // 1 Stop Bit
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; // 8 Bits
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= (CLOCAL | CREAD ); // turn on READ & ignore ctrl lines
// Make raw
cfmakeraw(&tty);
// Flush Port, then apply attributes
tcflush( USB, TCIFLUSH );
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0)
{
printf("from tcsetattr");
}
// WRITE
// Set the Ergometer language.
char cmd[255] = {0x60,0x01}; // Ergometer Cockpit Adresse
int n_written = write( USB, cmd, sizeof(cmd));
printf("%s\n",cmd);
// Allocate memory for read buffer
int bb = 0;
int i,x = 0;
bool cmdOK=false;
char marr[10];
do
{
if((bb = read(USB, &marr[x], sizeof( marr )-x )) > 0)
{
for (i=x;i<x+bb;i++)
{
//printf("0x%02x",marr[i]);
if ((marr[i]==ACK)||(marr[i]==NAK)) cmdOK=true;
}
x+=bb;
//printf("\n");
//printf("x=%d\n",x);
}
}while(!cmdOK);
printf("-Ausgabe---------------------\n");
for (i=0; i<x; i++)
{
printf("0x%02x",marr[i]);
}
close(USB);
// ttyUSB0 auf alten Wert setzen
tcflush(USB,TCIFLUSH);
if (tcsetattr(USB, TCSANOW, &tty) != 0) return(-1);
exit(0);
return 0;
}
I am writing simple CLI application for reading data from serial port. I have USB to serial converter with CP2102 and every few seconds, I am receiving 200 B long string.
Edit: I made a mistake. It is not a CP2102, but Profilic PL2303. I also found strange behavior when I use stty -- I cannot change baud rate and it's randomly changing:
$ stty -F /dev/ttyUSB5 57600 # Set baudrate
$ stty -F /dev/ttyUSB5 # Read configuration
speed 1200 baud;
.....
$$ stty -F /dev/ttyUSB5 # Read configuration
speed 9600 baud;
.....
End-of-edit
When I compile my application under Mac OS X, it works without any problem. But when I compile this code for Linux (cheap Android tablet with ARM CPU, I use Android NDK for compilation) I receive some data, then garbage:
~|?>?lq?43??d??2~??O?$?$??c??Hello World, good data.
???5??l??!???????x?????????????fx???~????????????x??????`???????~???f?x???~????`f??f???~?????x??????#ף???????x?????????????fx???~????????????x??????`???????~???f?x???~????`f??f???~??3?
It looks like I set wrong baud rate, but I am 100% sure the baud rate is 57600 bauds.
Is the problem in my code (differences in POSIX, Unix, Linux, etc.) or should I look for problems in hardware (CP2102, etc)?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // string function definitions
#include <errno.h> // Error number definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <termios.h> // POSIX terminal control definitions
int main(int argc, char *argv[]) {
printf("Opening device... ");
int USB = open("/dev/ttyUSB5", O_RDONLY | O_NOCTTY | O_NONBLOCK);
printf("opened.\n");
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Error Handling */
if (tcgetattr(USB, &tty) != 0) {
printf("Error %d from tcgetattr: %s!\n", errno, strerror(errno));
}
/* Save old tty parameters */
tty_old = tty;
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B57600);
cfsetispeed (&tty, (speed_t)B57600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
/* Make raw */
cfmakeraw(&tty);
/* Flush Port, then applies attributes */
tcflush(USB, TCIFLUSH);
if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) {
printf("Error %d from tcgetattr: %s!\n", errno, strerror(errno));
}
int n = 0;
char buf [256];
printf("Starting to read data...\n");
do {
n = read( USB, &buf, sizeof buf);
if (n > 0) {
printf("%s", buf);
memset(&buf, '\0', sizeof buf);
}
usleep(100000); /* sleep for 100 milliSeconds */
} while(1);
}
I'm using the following C code borrowed from here: how to open, read, and write from serial port in C
with some slight modifications so that the program waits for keyboard input, then writes this data to a serial port and waits to read it back. Here's my code:
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
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_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
int main{
char *portname = "/dev/tty0"
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
while (1){
char data[20];
if (fgets(data, sizeof data, stdin)){
int m = write(fd, data, sizeof data);
printf("%d chars written\n", m);
char buf[100];
sleep(10);
int n = read (fd, buf, sizeof buf);
printf("%d chars read", n);
}
}
}
The problem is that while the keyboard input is successfully written to serial file, after sleeping for 10 seconds the program still reports that it has read 0 chars. Why is this? Do I need to actually have a physical device waiting on the other end of the port which receives the data and returns something, or is it fine to write to and read from the serial port with the same program? Thanks in advance for any help!
EDIT:
Ok so now I've created a second program which waits for data on the serial port sent by the above program, but this program is still unable to read the data sent to it. Here's the code:
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
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_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
int main{
char *portname = "/dev/tty0"
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
char buf[20];
int n = 0;
while (n == 0){
n = read(fd, buf, sizeof buf);
}
printf("%d chars read\n", n);
return 0;
}
When I run this and right afterwards run the first program and write some data to the serial port, this program just stays in the while loop forever and never reads in any data. Help?
No, you do not need to actually have a physical device waiting on the other end of the port which receives the data.
Yes, you need to actually have a physical device waiting on the other end of the port to return something. (It could be a wire looping transmit and receive (pins 2 & 3 on 9-pin.)
Yes, it fine to write to and read from the serial port with the same program.
As to "Why is this?": there is nothing sending data to your program via the serial interface.
I am looking to know if it is possible to read from a serial port at 100 baud rate. As per termio.h there is no provision to set 100 as baud rate. I am working in Linux. The communicating device on the other end is sending data at 100 baud rate and it is fixed. I would like to know if my baud rate is set to 110, would it guarantee that the data I am receiving is correct? or is there any solution for this?
Kindly guide.
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.
Hmmm.... 110 bps is unique among serial port speeds in that it conventionally has two stop bits (all other speeds use one stop bit), so that sending one character requires 10 bits for 7-bit data, or 11 bits for 8-bit data.
If the communication protocol was communicated as ten characters per second and someone ignorant of 1950s protocols might convert cps to baud by assuming only one stop bit and 8-bit data, they would conclude that 100 baud is the result.
If the custom setting for a true 100 baud doesn't work, try setting standard 110 baud.
Excerpted from a related answer:
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
if (speed == B110)
tty.c_cflag |= CSTOPB; // 2 stop bits for 110
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
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_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
...
char *portname = "/dev/ttyUSB1"
...
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B110, 0); // set speed to 115,200 bps, 8n2 (no parity)
I am a little bit confused about reading and writing to a serial port. I have a USB device in Linux that uses the FTDI USB serial device converter driver. When I plug it in, it creates: /dev/ttyUSB1.
I thought itd be simple to open and read/write from it in C. I know the baud rate and parity information, but it seems like there is no standard for this?
Am I missing something, or can someone point me in the right direction?
I wrote this a long time ago (from years 1985-1992, with just a few tweaks since then), and just copy and paste the bits needed into each project.
You must call cfmakeraw on a tty obtained from tcgetattr. You cannot zero-out a struct termios, configure it, and then set the tty with tcsetattr. If you use the zero-out method, then you will experience unexplained intermittent failures, especially on the BSDs and OS X. "Unexplained intermittent failures" include hanging in read(3).
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
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_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
error_message ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
error_message ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
error_message ("error %d setting term attributes", errno);
}
...
char *portname = "/dev/ttyUSB1"
...
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
error_message ("error %d opening %s: %s", errno, portname, strerror (errno));
return;
}
set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (fd, 0); // set no blocking
write (fd, "hello!\n", 7); // send 7 character greeting
usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus
// receive 25: approx 100 uS per char transmit
char buf [100];
int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read
The values for speed are B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc. The values for parity are 0 (meaning no parity), PARENB|PARODD (enable parity and use odd), PARENB (enable parity and use even), PARENB|PARODD|CMSPAR (mark parity), and PARENB|CMSPAR (space parity).
"Blocking" sets whether a read() on the port waits for the specified number of characters to arrive. Setting no blocking means that a read() returns however many characters are available without waiting for more, up to the buffer limit.
Addendum:
CMSPAR is needed only for choosing mark and space parity, which is uncommon. For most applications, it can be omitted. My header file /usr/include/bits/termios.h enables definition of CMSPAR only if the preprocessor symbol __USE_MISC is defined. That definition occurs (in features.h) with
#if defined _BSD_SOURCE || defined _SVID_SOURCE
#define __USE_MISC 1
#endif
The introductory comments of <features.h> says:
/* These are defined by the user (or the compiler)
to specify the desired environment:
...
_BSD_SOURCE ISO C, POSIX, and 4.3BSD things.
_SVID_SOURCE ISO C, POSIX, and SVID things.
...
*/
For demo code that conforms to POSIX standard as described in Setting Terminal Modes Properly
and Serial Programming Guide for POSIX Operating Systems, the following is offered.
This code should execute correctly using Linux on x86 as well as ARM (or even CRIS) processors.
It's essentially derived from the other answer, but inaccurate and misleading comments have been corrected.
This demo program opens and initializes a serial terminal at 115200 baud for non-canonical mode that is as portable as possible.
The program transmits a hardcoded text string to the other terminal, and delays while the output is performed.
The program then enters an infinite loop to receive and display data from the serial terminal.
By default the received data is displayed as hexadecimal byte values.
To make the program treat the received data as ASCII codes, compile the program with the symbol DISPLAY_STRING, e.g.
cc -DDISPLAY_STRING demo.c
If the received data is ASCII text (rather than binary data) and you want to read it as lines terminated by the newline character, then see this answer for a sample program.
#define TERMINAL "/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); /* 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 */
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;
}
void set_mincount(int fd, int mcount)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error tcgetattr: %s\n", strerror(errno));
return;
}
tty.c_cc[VMIN] = mcount ? 1 : 0;
tty.c_cc[VTIME] = 5; /* half second timer */
if (tcsetattr(fd, TCSANOW, &tty) < 0)
printf("Error tcsetattr: %s\n", strerror(errno));
}
int main()
{
char *portname = TERMINAL;
int fd;
int wlen;
char *xstr = "Hello!\n";
int xlen = strlen(xstr);
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
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);
//set_mincount(fd, 0); /* set to pure timed read */
/* simple output */
wlen = write(fd, xstr, xlen);
if (wlen != xlen) {
printf("Error from write: %d, %d\n", wlen, errno);
}
tcdrain(fd); /* delay for output */
/* simple noncanonical input */
do {
unsigned char buf[80];
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
#ifdef DISPLAY_STRING
buf[rdlen] = 0;
printf("Read %d: \"%s\"\n", rdlen, buf);
#else /* display hex */
unsigned char *p;
printf("Read %d:", rdlen);
for (p = buf; rdlen-- > 0; p++)
printf(" 0x%x", *p);
printf("\n");
#endif
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
/* repeat read to get full message */
} while (1);
}
For an example of an efficient program that provides buffering of received data yet allows byte-by-byte handing of the input, then see this answer.