Reading from serial port on Linux and OSX - c

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

Related

using termios - Cannot set parity to even, get EINVAL error

Summary:
I am currently working on a program on embedded Linux using termios. If I do not enable even parity, my program works fine. I start to have issues when I set PARENB active and PARODD inactive. My program is designed to be 8E1 at 115200 baud.
What happens is that the first time I run the program on a fresh boot with Even parity enabled, it will transmit a message. The transmitted message does send, but it doesn't send with the parity bit. The second time I run the program it fails at the tcsetattr function with the errno == EINVAL.
I am running this program on Raspberry Pi for debugging and then the program will be ported to a yocto environment.
Current Environment:
Raspberry pi: 4B
Debian version: 10.10
GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0.
My Question:
Does anyone have insight into what piece is missing? I have tried to do this myself as well as tried 2 people's online examples I found on GitHub. All of them have this issue.
The code that I am running is:
// C library headers
#include <stdio.h>
#include <string.h>
// Linux headers
#include <errno.h> // Error integer and strerror() function
#include <fcntl.h> // Contains file controls like O_RDWR
#include <stdlib.h>
#include <sys/types.h>
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
#define SERIAL_DEVICE "/dev/ttyS0"
int main() {
struct termios serial_port_settings;
int fd;
int retval;
char buf[] = "hello world \n bye\n";
char ch;
int i;
//SERAIL_DEVICE is "/dev/ttyS0"
fd = open(SERIAL_DEVICE, O_RDWR);
if (fd < 0) {
perror("Failed to open SERIAL_DEVICE");
exit(1);
}
retval = tcgetattr(fd, &serial_port_settings);
if (retval < 0) {
perror("Failed to get termios structure");
exit(2);
}
//setting baud rate to B115200
retval = cfsetospeed(&serial_port_settings, B115200);
if (retval < 0) {
perror("Failed to set 115200 output baud rate");
exit(3);
}
retval = cfsetispeed(&serial_port_settings, B115200);
if (retval < 0) {
perror("Failed to set 115200 input baud rate");
exit(4);
}
//parity and bytes, grabbed from documentation
serial_port_settings.c_cflag |= PARENB; //enable parity
serial_port_settings.c_cflag &= ~PARODD; //disable odd parity, therefore-> even parity
serial_port_settings.c_cflag &= ~CSTOPB; //disable 2 stop bits, therefore-> 1 stop bit
serial_port_settings.c_cflag &= ~CSIZE; //remove size
serial_port_settings.c_cflag |= CS8; //8 data bits
serial_port_settings.c_cflag |= CLOCAL | CREAD; //ignore modem control lines, enable reciever
serial_port_settings.c_lflag |= ICANON; // enable canonical mode
retval = tcsetattr(fd, TCSANOW, &serial_port_settings);
/*************** ERROR HAPPENS HERE ********************/
/* errno is set to EINVAL here */
if (retval < 0) {
perror("Failed to set serial attributes");
exit(5);
}
printf("Successfully set the baud rate\n");
retval = write(fd, buf, 18);
if (retval < 0) {
perror("write on SERIAL_DEVICE failed");
exit(6);
}
retval = tcdrain(fd);
if (retval < 0) {
perror("write on SERIAL_DEVICE failed");
exit(6);
}
close(fd);
return 0;
}
#sawdust and #KamilCuk helped identify my issue. The software was not the problem. It looks like ttyS0 on the Raspberry Pi 4 isn't a fully functional COM port. Because of this trying to add a parity bit would fail.
The code above runs fine on a different Linux machine with a full-featured COM port.

Linux UART transmitting Problems

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.

send and receive data using usb to rs232 interface in Linux C

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

Serial Communication read() Error

This should be fairly straightforward for someone in the know, but I have been struggling for a bit and would appreciate some thoughts. I am writing an application that reads from a serial comm port.
My Setup:
I have a windows machine with putty open and connected to my comm port of interest.
I have a linux (ubuntu) machine in which I am writing this software (in C).
I am typing into putty on the windows machine and trying to read it with my application on the linux machine.
What I have:
So far, using the code below I can successfully write to the putty display on the windows machine from my application on the linux computer, but I cannot read the buffer on my linux machine when I type on the windows machine.
Code:
#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>
int openport()
{
int USB = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY | O_NONBLOCK );
struct termios tty;
struct termios tty_old;
memset(&tty, 0, sizeof tty);
/* Error Handling */
if ( tcgetattr( USB, &tty ) != 0 )
{
printf("Error 1, or something");
}
/* Save old tty parameters */
tty_old = tty;
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);
/* 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; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
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, or something");
}
return USB;
}
int main()
{
int n = 0;
int j = 0;
unsigned char buf[10] = {0,0,0,0,0,0,0,0,0,0};
printf("Hello world!\n");
int USB = openport();
unsigned char cmd[] = "INIT Hey SHanahas \r";
int n_written = 0;
do
{
n_written += write( USB, &cmd[n_written], 1 );
}
while (cmd[n_written-1] != '\r' && n_written > 0);
printf("Here\n\n");
do
{
n = read( USB, &buf, 1 );
printf("%s \n",buf);
printf("%d",n);
}
while( buf != '\r' && n > 0);
printf("Herr2");
return 0;
}
Does anyone have any thoughts on what might be happening? the read() command returns a -1 error.
Thanks!

How to open, read, and write from serial port in C?

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.

Resources