The code below will read serial strings from the UART at 115200 baud.
This is intended to work with a 2.6.* Linux kernel.
Surprisingly I was unable to locate a simple Linux example to read the port at 115200 reliably and without blocking the port or experiencing buffer lag.
I dug through kernel makefiles and pulled out the needed ioctl parameters, you will find the results of my labours below.
Compiled on gcc 4.4.5.
I use this to receive high speed data from sensors attached to an Arduino.
//=======================================================================================================================
// Linux Serial Comms
//
// Author: Dingo_aus
// Date:
//
//
//=========================================================================================================================
//=========================================================================================================================
#include <iostream>
#include <stdio.h> /* Standard input/output definitions */
#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 <sys/ioctl.h>
//=========================================================================================================================
// NAMESPACE DECLARATIONS
//=========================================================================================================================
//=========================================================================================================================
//FUNCTION PROTOTYPES - some prototypes for serial comms
//=========================================================================================================================
int setup(void); //function to capture all the set up, once off tasks.
int writeport(int fd, char *chars);
int readport(int fd, char *result);
int getbaud(int fd);
int initport(int fd) ;
//=========================================================================================================================
//GLOBALS - GENERAL
//=========================================================================================================================
int fd;
char sBuffer[254];
char sResult[254];
int setup()
{
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); //hard coded port
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyUSB0 - ");
return 1;
} else {
fcntl(fd, F_SETFL, 0);
printf("Serial connection established on /dev/ttyUSB0");
}
printf("baud=%d\n", getbaud(fd));
initport(fd);
printf("baud=%d\n", getbaud(fd));
return 0; //zero is all good
}
//=========================================================================================================================
// MAIN LOOP
//=========================================================================================================================
int main()
{
setup();
//-------------------------------------------------------------------------------------------------------------------------
// Read the serial port and update accordingly
//-------------------------------------------------------------------------------------------------------------------------
fcntl(fd, F_SETFL, O_NONBLOCK); // don't block serial read
//Find out how many bytes are sitting in the serial input buffer and only choose to read them when there are enough.
int bytes;
ioctl(fd, FIONREAD, &bytes); //This line populates the bytes integer with the number of bytes sitting in the serial input buffer - FIONREAD not well documented
if(bytes > 2) //tweak this number to gain performance - lower equals faster read but more likely to have erroneous strings
{
sBuffer[0] = 0x00;
if (!readport(fd,sBuffer))
{
printf("read failed - sBuffer: %s\n", sBuffer);
//close(fd);
//return 1;
}
int sBuffer_length = strlen(sBuffer);
printf("buffer: %s\n", sBuffer);
}
//End of the main running loop -- END
}
//Clean up the Serial Connection too.
close(fd);
return 0;
}
//=========================================================================================================================
//********************** SERIAL FUNCTIONS *************************
//=========================================================================================================================
int initport(int fd) {
struct termios options;
// Get the current options for the port...
tcgetattr(fd, &options);
// Set the baud rates to whatever is needed... (Max 115200)
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Set the new options for the port...
tcsetattr(fd, TCSANOW, &options);
return 1;
}
//=========================================================================================================================
// WRITE PORT
//=========================================================================================================================
int writeport(int fd, char *chars)
{
int len = strlen(chars);
chars[len] = 0x0d; // stick a after the command (0xd == 13 == ASCII CR)
chars[len+1] = 0x00; // terminate the string properly
int n = write(fd, chars, strlen(chars));
if (n < 0)
{
fputs("write failed!\n", stderr);
return 0;
}
return 1;
}
//=========================================================================================================================
// READ PORT
//=========================================================================================================================
int readport(int fd, char *result)
{
int iIn = read(fd, result, 254);
result[iIn-1] = 0x00; //This is needed or the previous contents of the string will appear after the changed characters.
if (iIn < 0)
{
if (errno == EAGAIN)
{
// printf("SERIAL EAGAIN ERROR\n");
return 0;
} else
{
printf("SERIAL read error %d %s\n", errno, strerror(errno));
return 0;
}
}
return 1;
}
//=========================================================================================================================
// GET BAUD
//=========================================================================================================================
int getbaud(int fd)
{
struct termios termAttr;
int inputSpeed = -1;
speed_t baudRate;
tcgetattr(fd, &termAttr);
/* Get the input speed. */
baudRate = cfgetispeed(&termAttr);
switch (baudRate)
{
case B0: inputSpeed = 0; break;
case B50: inputSpeed = 50; break;
case B110: inputSpeed = 110; break;
case B134: inputSpeed = 134; break;
case B150: inputSpeed = 150; break;
case B200: inputSpeed = 200; break;
case B300: inputSpeed = 300; break;
case B600: inputSpeed = 600; break;
case B1200: inputSpeed = 1200; break;
case B1800: inputSpeed = 1800; break;
case B2400: inputSpeed = 2400; break;
case B4800: inputSpeed = 4800; break;
case B9600: inputSpeed = 9600; break;
case B19200: inputSpeed = 19200; break;
case B38400: inputSpeed = 38400; break;
case B115200: inputSpeed = 115200; break;
}
return inputSpeed;
}
This is intended to work with a 2.6.* Linux kernel.
Surprisingly I was unable to locate a simple Linux example to read the port at 115200 reliably and without blocking the port or experiencing buffer lag.
I dug through kernel makefiles and pulled out the needed ioctl parameters, you will find the results of my labours below.
Compiled on gcc 4.4.5.
I use this to receive high speed data from sensors attached to an Arduino.
//=======================================================================================================================
// Linux Serial Comms
//
// Author: Dingo_aus
// Date:
//
//
//=========================================================================================================================
//=========================================================================================================================
#include <iostream>
#include <stdio.h> /* Standard input/output definitions */
#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 <sys/ioctl.h>
//=========================================================================================================================
// NAMESPACE DECLARATIONS
//=========================================================================================================================
//=========================================================================================================================
//FUNCTION PROTOTYPES - some prototypes for serial comms
//=========================================================================================================================
int setup(void); //function to capture all the set up, once off tasks.
int writeport(int fd, char *chars);
int readport(int fd, char *result);
int getbaud(int fd);
int initport(int fd) ;
//=========================================================================================================================
//GLOBALS - GENERAL
//=========================================================================================================================
int fd;
char sBuffer[254];
char sResult[254];
int setup()
{
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); //hard coded port
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyUSB0 - ");
return 1;
} else {
fcntl(fd, F_SETFL, 0);
printf("Serial connection established on /dev/ttyUSB0");
}
printf("baud=%d\n", getbaud(fd));
initport(fd);
printf("baud=%d\n", getbaud(fd));
return 0; //zero is all good
}
//=========================================================================================================================
// MAIN LOOP
//=========================================================================================================================
int main()
{
setup();
//-------------------------------------------------------------------------------------------------------------------------
// Read the serial port and update accordingly
//-------------------------------------------------------------------------------------------------------------------------
fcntl(fd, F_SETFL, O_NONBLOCK); // don't block serial read
//Find out how many bytes are sitting in the serial input buffer and only choose to read them when there are enough.
int bytes;
ioctl(fd, FIONREAD, &bytes); //This line populates the bytes integer with the number of bytes sitting in the serial input buffer - FIONREAD not well documented
if(bytes > 2) //tweak this number to gain performance - lower equals faster read but more likely to have erroneous strings
{
sBuffer[0] = 0x00;
if (!readport(fd,sBuffer))
{
printf("read failed - sBuffer: %s\n", sBuffer);
//close(fd);
//return 1;
}
int sBuffer_length = strlen(sBuffer);
printf("buffer: %s\n", sBuffer);
}
//End of the main running loop -- END
}
//Clean up the Serial Connection too.
close(fd);
return 0;
}
//=========================================================================================================================
//********************** SERIAL FUNCTIONS *************************
//=========================================================================================================================
int initport(int fd) {
struct termios options;
// Get the current options for the port...
tcgetattr(fd, &options);
// Set the baud rates to whatever is needed... (Max 115200)
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Set the new options for the port...
tcsetattr(fd, TCSANOW, &options);
return 1;
}
//=========================================================================================================================
// WRITE PORT
//=========================================================================================================================
int writeport(int fd, char *chars)
{
int len = strlen(chars);
chars[len] = 0x0d; // stick a
chars[len+1] = 0x00; // terminate the string properly
int n = write(fd, chars, strlen(chars));
if (n < 0)
{
fputs("write failed!\n", stderr);
return 0;
}
return 1;
}
//=========================================================================================================================
// READ PORT
//=========================================================================================================================
int readport(int fd, char *result)
{
int iIn = read(fd, result, 254);
result[iIn-1] = 0x00; //This is needed or the previous contents of the string will appear after the changed characters.
if (iIn < 0)
{
if (errno == EAGAIN)
{
// printf("SERIAL EAGAIN ERROR\n");
return 0;
} else
{
printf("SERIAL read error %d %s\n", errno, strerror(errno));
return 0;
}
}
return 1;
}
//=========================================================================================================================
// GET BAUD
//=========================================================================================================================
int getbaud(int fd)
{
struct termios termAttr;
int inputSpeed = -1;
speed_t baudRate;
tcgetattr(fd, &termAttr);
/* Get the input speed. */
baudRate = cfgetispeed(&termAttr);
switch (baudRate)
{
case B0: inputSpeed = 0; break;
case B50: inputSpeed = 50; break;
case B110: inputSpeed = 110; break;
case B134: inputSpeed = 134; break;
case B150: inputSpeed = 150; break;
case B200: inputSpeed = 200; break;
case B300: inputSpeed = 300; break;
case B600: inputSpeed = 600; break;
case B1200: inputSpeed = 1200; break;
case B1800: inputSpeed = 1800; break;
case B2400: inputSpeed = 2400; break;
case B4800: inputSpeed = 4800; break;
case B9600: inputSpeed = 9600; break;
case B19200: inputSpeed = 19200; break;
case B38400: inputSpeed = 38400; break;
case B115200: inputSpeed = 115200; break;
}
return inputSpeed;
}
Comments