Re: RS485/COM2 Error in SBC84500 documentation

From: Floyd L. Davidson (floyd_at_barrow.com)
Date: 06/20/05


Date: Mon, 20 Jun 2005 12:51:32 -0800

Frencia <jean.pierre.frencia@wanadoo.fr> wrote:
>Hi
>
>There is an error in the SBC84500 documentation concerning RS485/COM2 pins
>assignment.
>The signal is between pin 1 (DATA-) and pin 2 (DATA+) instead of pin 1 and
>pin 3 as stated page 29 of the documentation.
>
>I also have removed CRTSCTS flag when tuning the termios.
>
>Here is my OpenDevice routine (if it could be helpful for somebody else).

Here's a *very* pedantic (but also very useful) commentary on your
code.

>int OpenDevice (char* device)
>{
> int fd;
>
> fd = open(device, O_RDWR | O_NOCTTY );
> if(fd<=0) {

That should be "if (fd < 0) {", because 0 is a valid fd.

> fprintf(stderr, "Error opening %s\n", device);
> exit(-1);

The argument for exit() is an int, but its value is taken as an
unsigned character. Hence, -1 is not -1, but 255.

Useful arguments are in the range 0 to 255.

> }
> tcgetattr(fd,&oldtio); /* save current port settings */
> tcgetattr(fd,&newtio); /* get current port settings */

You could just as well save the second function call, and
do

    newtio = oldtio;

But at that point there is another problem. POSIX says that the
above is the one and only correct way to initialize a termios
structure. (Which rules out using something like memset() to
clear it entirely.) But, that also means you *must* set each
and every element of the structure to an appropriate value for
your application, because whatever just happens to be in "oldtio"
might not be compatible with your app. That sounds easy, but
POSIX doesn't specify _everything_ that might be there! It says
certain things must exist, but each implementation is allowed to
add non-POSIX specified members to termios. So, for a portable
program, it is *impossible* to know how to initialize termios!

It happens that Linux has such an addition to termios, the
c_line member, which is not POSIX, does not exist in any other
OS, and if set to the wrong value will cause a port to appear
to be dead.

So you are left with, in my opinion, two options. One is to
use something like this:

#if __linux__
#include <sys/ioctl.h> /* defines N_TTY */
  newtio.c_line = NTTY; /* or skip the header, and set it to 0 */
#endif

*and* make sure that you set each and every POSIX member of
the termios structure.

The other way, which is not POSIXly correct, is easier and
more likely to always be right!

  memset(&newtio, 0, sizeof newtio);

> newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
> // BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD does NOT work

You probably shouldn't put the BAUDRATE there either; and
regardless of whether it is there or not, you should use
cfsetispeed() and cfsetospeed() to set the bitrate.

> newtio.c_cflag &= ~PARENB; /* no generation of parity bit */
> newtio.c_cflag &= ~CSTOPB; /* 1 Stop bit */

The above are unnecessary. You properly *set* (using '=') only
some of the bits above, and all others are cleared. Clearing
them again won't make the twice as cleared, eh? :-)

> newtio.c_iflag &= ~INPCK; /* no input parity check */
> newtio.c_iflag = IGNPAR;

That doesn't make sense either. Just do the second line, and it
will also do the first at the same time. I'm not sure what is
implemented in the driver you are using, but commonly for the
c_iflag on RS-232 ports one would also set IGNBRK.

> newtio.c_oflag = 0;
>
> /* set input mode (non-canonical, no echo,...) */
> newtio.c_lflag = 0;
>
> newtio.c_cc[VTIME] = 10;
> newtio.c_cc[VMIN]= 0;

Wow, that's a pretty hefty wait interval!

> tcflush(fd, TCIFLUSH);

You might want to change that to TCIOFLUSH, so that both input
and output are flushed before continuing.

> tcsetattr(fd,TCSANOW,&newtio);

You should check this for an error. But also note that if it
returns -1, that means *nothing* worked. And if anything at all
was set as requested, it will return 0. That means most of it
might be other than what you expect, and the error return won't
indicate it. (The only way to know for sure, is obnoxious...
you'd have to use tcgetattr() again, and compare what you get
to the newtio struct, and even that isn't easy because the bitrate
bits won't be the same and have to be compared separately from
the rest of the struct.)

> return(fd);

There is no need to put parens around fd in the return
statement, though it doesn't hurt anything. (I said it was a
pedantic commentary... :-)

   return fd;

>}

-- 
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com


Relevant Pages

  • Re: Serial custom speed deprecated?
    ... - ioctl is called to set specific board rate ... OR termios values for tty speed change ... from my reading of POSIX. ... the termios settings, you get the actual settings in use. ...
    (Linux-Kernel)
  • Re: Serial port: tcgetattr and tcsetattr
    ... POSIX only guarantees that ... >line and left it in a state where some non-POSIX flags are set ... or elements to be added to the termios struct. ... does not limit how a serial port behaves. ...
    (comp.unix.programmer)
  • Re: Serial port: tcgetattr and tcsetattr
    ... >POSIX then obviously POSIX no longer makes any guarantee about what ... >whenever a conforming application is run in a conforming environment. ... >POSIX-defined flags and are run in a conforming environment). ... *must* *ignore* the way HP-UX set termios options on close, ...
    (comp.unix.programmer)
  • Re: RS485/COM2 Error in SBC84500 documentation
    ... there is a lack of material on serial port programming for newbies. ... >>I also have removed CRTSCTS flag when tuning the termios. ... > add non-POSIX specified members to termios. ... > cfsetispeedand cfsetospeedto set the bitrate. ...
    (comp.os.linux.embedded)