Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing STRINGS to serial port in C++ linux

I know this question is scattered all over the internet, but still, nothing is getting me completely there yet. I want to write data to a serial port in C++ (linux) for a a Propeller board. Program works fine when taking input from the console, but when I write strings to it always return: ERROR - Invalid command from the device. I tried creating array of char with Hex values then it worked. here's a working code, below. But how will i be able to just provide a string variable of command and send it to the serial port? perhaps, how do you I convert it to hex values if it's the only way? Thanks everyone

note: the loop is to use user input from console. What i need is a way to send a string variable to the serial port.

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

int main(int argc,char** argv){
    struct termios tio;
    struct termios stdio;
    int tty_fd;
    fd_set rdset;

    unsigned char c='D';

    printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
    memset(&stdio,0,sizeof(stdio));
    stdio.c_iflag=0;
    stdio.c_oflag=0;
    stdio.c_cflag=0;
    stdio.c_lflag=0;
    stdio.c_cc[VMIN]=1;
    stdio.c_cc[VTIME]=0;
    tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
    tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking

    memset(&tio,0,sizeof(tio));
    tio.c_iflag=0;
    tio.c_oflag=0;
    tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
    tio.c_lflag=0;
    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=5;

    tty_fd=open(argv[1], O_RDWR | O_NONBLOCK);      
    cfsetospeed(&tio,B115200);            // 115200 baud
    cfsetispeed(&tio,B115200);            // 115200 baud

    tcsetattr(tty_fd,TCSANOW,&tio);

    //char str[] = {'V','E','R','\r'};
    //the above str[] doesn't work although it's exactly the same as the following
    char str[] = {0x56, 0x45, 0x52, 0x0D}; 
    write(tty_fd,str,strlen(str));
    if (read(tty_fd,&c,1)>0)
        write(STDOUT_FILENO,&c,1);

    while (c!='q')
    {
            if (read(tty_fd,&c,1)>0)        write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
            if (read(STDIN_FILENO,&c,1)>0) 
                if(c!='q')
                    write(tty_fd,&c,1);        // if new data is available on the console, send it to the serial port
    }

    close(tty_fd);
}
like image 937
haikalpribadi Avatar asked Feb 18 '12 10:02

haikalpribadi


2 Answers

I'm happy to solve my own solution but yet disappointed to not have seen the trivial matter much sooner. char by default are signed in c++, which makes it holding the range -128 to 127. However, we are expecting the ASCII values which are 0 to 255. Hence it's as simple as declaring it to be unsigned char str[] and everything else should work. Silly me, Silly me.

Still, Thank you everyone for helping me!!!

like image 113
haikalpribadi Avatar answered Nov 10 '22 02:11

haikalpribadi


Are you sure you should end with '\r'? When entering text from console the return key will result in a '\n' character (on Linux) and not '\r'

Also error checking is missing on most functions (open(), fcntl(), etc.). Maybe one of these functions fail. To find out how to check for errors read the man page (for example man 2 open for the open() command. In case of open() the man page explains it returns -1 when it could not open the file/port.

After your edit you wrote:

char str[] = {0x56, 0x45, 0x52, 0x0D}; 
write(tty_fd,str,strlen(str));

which is wrong. strlen expects a '\0' terminated string which str is obviously not so now it sends your data and whatever there is in memory until it sees a '\0'. You need to add 0x00 to your str array.

like image 30
rve Avatar answered Nov 10 '22 02:11

rve