-1

I've two application software running (sender and receiver) on 2 different booard comunicating beetween then via rs232 links The rs232 port on boths side has been configuarte in same way and sender side I've 2 second sleep between 2 trasmission. The data send is a simple counter and the sender increase its value every 2 seconds

What happens? it happens that after few packets recived the read() on receiver side return 0 with errno set to "Success" and none error on sender side. When the trasmission delay is 1 second, the read() return 0 after 9 or 10 messages and when set at 2 seconds this delay, the number of events before return 0 is around 4 or 5

Below the settings :

int Set_RS232_Params(int fd, speed_t speed)
{
    int error = 0;
    int v_ret = -1;
    struct termios attribs;

    /*get attributes */
    v_ret = tcgetattr(fd, &attribs);
    if (v_ret != 0)
    {
        error = 1;
        printf("ERROR\n");
    }
    else
    {
        error = 0;
    }

    /*set output baudrate */
    if (error == 0)
    {
        v_ret = -1;
        v_ret = cfsetospeed(&attribs, speed);
        if (v_ret != 0)
        {
            error = 1;
            printf("ERROR\n");
        }
    }

    /*set input baudrate */
    if (error == 0)
    {
        v_ret = -1;
        v_ret = cfsetispeed(&attribs, speed);
        if (v_ret != 0)
        {
            error = 1;
            printf("ERROR\n");
        }
    }

    /*modify and save attributes */
    if (error == 0)
    {
        /*CFLAG */
        attribs.c_cflag &= ~PARENB;
        attribs.c_cflag &= ~CSTOPB;
        attribs.c_cflag &= ~CSIZE;
        attribs.c_cflag |= CS8;
        attribs.c_cflag &= ~CRTSCTS;
        attribs.c_cflag |= CREAD;
        attribs.c_cflag |= CLOCAL;
        /*LFLAG */
        attribs.c_lflag &= ~ECHO;
        attribs.c_lflag &= ~ECHOE;
        attribs.c_lflag &= ~ECHONL;
        attribs.c_lflag &= ~ICANON;
        attribs.c_lflag &= ~ISIG;
        /*IFLAG */
        attribs.c_iflag &= ~(IXON | IXOFF | IXANY);
        attribs.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
        /*OFLAG */
        attribs.c_oflag &= ~OPOST;
        attribs.c_oflag &= ~ONLCR;

        /*VMIN and VTIME */
        attribs.c_cc[VMIN] = 0;
        attribs.c_cc[VTIME] = 0;

        /*save attributes */
        v_ret = -1;
        v_ret = tcsetattr(fd, TCSANOW, &attribs);
        if (v_ret != 0)
        {
            error = 1;
            printf("ERROR\n");
        }
    }

    return error;
}

Thanks

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
H2O
  • 153
  • 1
  • 1
  • 13
  • "*Yocto*" is a build tool, and it's not an OS or runtime environment. You used Yocto to build a Linux kernel and root filesystem for your target system. – sawdust Jul 05 '23 at 19:59
  • 2
    "*Below the settings ...*" -- That's not sufficient. You're expected to provide a minimal, reproducible example. A clue to your problem is that you're using VMIN and VTIME both set to zero (although blocking mode is unknown). That's a problematic setting that requires proper handling (which you probably didn't implement), Study https://stackoverflow.com/questions/25996171/linux-blocking-vs-non-blocking-serial-read Your receive program is "polling" the serial terminal, and read() returning zero simply means that there's no data available. – sawdust Jul 05 '23 at 21:27

1 Answers1

0

If you are going to assign all the parameters and flags in the termios structure, then you had better to do normal assignments, instead of using &= and |= operators individually for each field.

Should I have to do this full initialization, I should a static struct termios variable already initialized with the full set of flags, and should not modify all the values one by one.

For this you have two approaches:

  1. Just do all the &= at once, as in:
        /*CFLAG */
        attribs.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
        attribs.c_cflag |= CS8 | CREAD | CLOCAL;
        /*LFLAG */
        attribs.c_lflag &= ~(ECHO | ECHOE | ECHONL | ICANON | ISIG);
        /*IFLAG */
        attribs.c_iflag &= ~(IXON | IXOFF | IXANY | IGNBRK 
                           | BRKINT | PARMRK | ISTRIP | INLCR
                           | IGNCR | ICRNL);
        /*OFLAG */
        attribs.c_oflag &= ~(OPOST | ONLCR);

and you'll augment readability of your code. Or

  1. have a static definition, in case you are touching all configuration flags (I don't recommend you to use this approach, as it is not portable between different tty implementations)
     static struct termios new_config = {
        .c_cflag = CS8 | CREAD | CLOCAL,
     };

and then use it in your code.

... return 0 with errno set to "Success"

Read() returns -1 on error, and then (and only then, in portable code) you can ask errno about the success/failure of a system call. A return value of 0 is only given by read() in case the end of input has been detected. As you have (supposedly) set your terminal to raw mode, Ctrl-D is no longer the END OF FILE control character, so you should never receive 0 as return (except if you have specified 0 as the size of the buffer to read() or if your tcsetattr() call failed (which is something you don't say is happening)

There's a case (which you actually are configuring) is when you assign both VMIN and VTIME equal to zero (both) you will get the behaviour you describe in case you read the input line and there's no data already stored in the buffer. If you want to return only the available data, but block if there's no such available data, you have to use VMIN == 1 and VTIME = 0 (this is described in termios(3) manual page). That will return the available data if some is, but will block until data arrives (the first byte arriving will trigger the unblock into the read system call)

You are recommended by this page on why you should send a complete, and verifiable example, so we can play around with your failing code in order to make a diagnostic, but I cannot go further, and it seems to me that the problem is not in this function, but elsewhere. Please read the page referenced above, as I cannot make a diagnostic without a full working program to test.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • Useless advice and false statements. (1) The OP does clear the CSIZE bits before setting CS8. (2) There is nothing improper in how the OP modifies termios attributes; it conforms to the recommended method. You never quite explain what is "*normal assignments*". (3) Suggesting a pre-initialized termios struct is contrary to recommended practice. See [Setting Terminal Modes Properly](https://www.gnu.org/software/libc/manual/html_node/Setting-Modes.html) (4) The man page for termios clearly states that read() could return 0. – sawdust Jul 06 '23 at 18:50
  • 1
    Oh yes.... I didn't see it. You are right... deserved downvote... let me change it. It's good to punish people when they make mistakes..... your words have been very helpful.... let me change the advice. But the rest is ok.... and useful. Don't you think so? Normal assingments are just assignments not involving another operator, but I think you are a bit short understanding. Error corrected, my apologies for being so bad.... And I'm used to program termios structure since 1987. Than you for the advice. – Luis Colorado Jul 07 '23 at 05:09
  • @sawdust, you should be a bit more positive, and not so negative in your hints. Instead of just directly downvoting people and saying things like _Useles advice and false statements_, you had better sugesting better procedures and not criticizing other people help (more when you have not suggested anything nor answered the question). Punishing people by downvoting directly is extremely hostile. You are probably the perfect C programmer, but without seeing your code, that's actually more useless than my (erroneous) answer. I've corrected it, so let's see how do you take off the downvote:) – Luis Colorado Jul 07 '23 at 05:27
  • @sawdust, you have edited the question, to eliminate `yocto` tag, and have introduced a non specific tag also (the question is not `linux` specific, as every posix system --e.g. hp-ux, qnx, aix, digital-ux, sco unix, solaris, linux, freebsd, openbsd, netbsd, etc.) include a `termios` interface. Should I downvote you for that? that's a false assertion, you have not realized that your edit was erroneous, but relax, I'm not going to do such a thing, but please be more user friendly in the future. – Luis Colorado Jul 07 '23 at 05:34
  • @sawdust, a normal assignment is one that is done using the plain `=` operator, if you don't understand this, I'm not going to explain that to you, but you need help to proceed helping people this way. :) – Luis Colorado Jul 07 '23 at 05:38
  • for (3) in your comment above, You are welcome to write an answer, just showing the proper way to do it, that will be welcome and probably I won't downvote it. :) Termios structure is present in unix well before the POSIX standard, and I've seen profesional code using that approach. I also recommend not to using this approach (as it is non portable) but is a far faster solution that doesn't require any runtime code to be run, that can be applicable when you are not portability concerned. Why your criterion should be taken into account and not mine? – Luis Colorado Jul 07 '23 at 05:43
  • When you post an "answer" full of incorrect or contradictory advice, an incorrect (& unnecessary) evaluation of the code, and information contrary to a Linux man page and GNU libc manual, then expect a downvote from me. You call that unjustified "*punishment*", but I think of it as a flag to warn others of the very low quality of this "answer". This downvote merely offsets my upvote of [your old answer](https://stackoverflow.com/questions/56203882/i-o-error-when-trying-to-change-serial-baud-in-c-program-after-changing-with-uni/56209560#56209560), which I would now retract if I could. – sawdust Jul 07 '23 at 22:58
  • @Luis Colorado thanks for the response and suggestion and apologize for incomplete information about the code and for the altercation. Anyway, seems is not possible add here the scratch example code but I try to explain. The RS232 sender code is made with a poll syscall with 2 second timeout.Every 2 seconds the sender call a write() function to send a int value (errno=success). On other saide the receiver is made with a poll on RS232 device file descriptor set blocking mode (fcntl(fd_rs232, F_SETFL, 0), but the problem still again – H2O Jul 11 '23 at 07:04
  • @H2O, the `VMIN` & `VTIME` features only control internal driver behavior (and this is *only* specific to tty drivers). They are not affected by `poll()` or `select()` so I suggest you to configure the driver with `VMIN==1` & `VTIME==0` so no timeout is handled by the driver, and processes get unlocked only when some data is available. This will make poll to awake only when data is available and you will read > 0. If you configure both as 0, the driver will never block, and select will see it as always ready to read, as `poll` is a generic interface available for all drivers or sockets. – Luis Colorado Jul 11 '23 at 07:37