Check out the new projects site for A-i-S www.adventuresinsilicon.com

Thursday, April 7, 2011

Ubuntu: Sending and receiving serial under Linux (Ubuntu)

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, &amp;bytes);        //This line populates the bytes integer with the number of bytes sitting in the serial input buffer - FIONREAD not well documented
        if(bytes &gt; 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, &amp;options);
    // Set the baud rates to whatever is needed... (Max 115200)
    cfsetispeed(&amp;options, B115200);
    cfsetospeed(&amp;options, B115200);
    // Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);

    options.c_cflag &amp;= ~PARENB;
    options.c_cflag &amp;= ~CSTOPB;
    options.c_cflag &amp;= ~CSIZE;
    options.c_cflag |= CS8;

    // Set the new options for the port...
    tcsetattr(fd, TCSANOW, &amp;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 &lt; 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 &lt; 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, &amp;termAttr);
    /* Get the input speed.                              */
    baudRate = cfgetispeed(&amp;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;
}



No comments: