Writing STRINGS to serial port in C++ linux

15,963

Solution 1

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!!!

Solution 2

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.

Share:
15,963
haikalpribadi
Author by

haikalpribadi

Computer Scientist, creator of TypeDB and TypeQL, Founder and CEO of Vaticle

Updated on July 25, 2022

Comments

  • haikalpribadi
    haikalpribadi almost 2 years

    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);
    }
    
    • Basile Starynkevitch
      Basile Starynkevitch about 12 years
      Is it C or C++ ? If C++, why don't you use std::string ?
    • haikalpribadi
      haikalpribadi about 12 years
      @BasileStarynkevitch: I've tried doing it: std::string str="VER\r"; write(tty_fd,str.data(),str.size()); it still returns error. i've tried many ways but only those hex works. do you have any idea? The code is from C, but my program is actually C++.
    • Mr Lister
      Mr Lister about 12 years
      Is it me, or haven't you told us what the error actually says?
    • haikalpribadi
      haikalpribadi about 12 years
      the serial port just return ERROR - Invalid command. So i guess the data reaches the device, but not in the valid format.
    • haikalpribadi
      haikalpribadi about 12 years
      @BasileStarynkevitch Even when I do, char str[] = {'V', 'E', 'R', '\r'}; write(tty_fd,str,strlen(str)); --it still doesn't work. But again, this works: char str[] = {0x56, 0x45, 0x52, 0x0D}; write(tty_fd,str,strlen(str));
    • rve
      rve about 12 years
      Sorry, but your solution does not make sense. You are saying (char)'V' != 0x56 and that (int)'V' == 0x56 ??? What platform and compiler are you using???
    • Basile Starynkevitch
      Basile Starynkevitch about 12 years
      a char str[] should be terminated by a null byte \0
    • fiorentinoing
      fiorentinoing about 6 years
      as @BasileStarynkevitch already said, the message should be null terminated, e.g. char str[] = {0x56, 0x45, 0x52, 0x0D, 0x00};
  • haikalpribadi
    haikalpribadi about 12 years
    I agree, i haven't done those error checking. But I dont think it's the cause of the problem cause the current commands work (which means the connection is fine). However, it would be really nice if you could point out to me where i should do the checking - all these low level IO is completely new to me, first time. about the \r, i dont think it's the issue, cause i even tested this following code and it still returns the same error. char str[] = {'V', 0x45, 0x52, 0x0D}; write(tty_fd,str,strlen(str)); .. and also, i checked on the ASCII table that 0x0D is exactly \r
  • haikalpribadi
    haikalpribadi about 12 years
    and for testing purposes, I tried \n too, which didn't work as well.
  • Martin James
    Martin James about 12 years
    OK, you need to stop looking at the code now. Connect your serial port to another port on another box and use a terminal app to read what is being sent in both these cases, (which should be the same, but are not).
  • haikalpribadi
    haikalpribadi about 12 years
    @rve, thanks, but I solved my problem. In regard to your solution, i even tried hard coding the exact value (4) which is suppose to work and it still doesn't. But thanks, really. Anyways, please see my updated question, it has the solution. I can't post it as a solution for now, cause i dont have enough reputation points.