9

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);
}
8
  • Is it C or C++ ? If C++, why don't you use std::string ? Commented Feb 18, 2012 at 10:42
  • @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++. Commented Feb 18, 2012 at 10:59
  • 1
    Is it me, or haven't you told us what the error actually says? Commented Feb 18, 2012 at 11:12
  • 1
    a char str[] should be terminated by a null byte \0 Commented Feb 18, 2012 at 13:39
  • 1
    as @BasileStarynkevitch already said, the message should be null terminated, e.g. char str[] = {0x56, 0x45, 0x52, 0x0D, 0x00}; Commented Mar 28, 2018 at 13:19

2 Answers 2

11

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

Sign up to request clarification or add additional context in comments.

Comments

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.

4 Comments

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
and for testing purposes, I tried \n too, which didn't work as well.
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).
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.