Serial port settings

  • Follow


Hi all,

I need to set my serial port to interface with an RS-232 sensor that 
receives and transmits raw data: 8 bytes, no parity, 1 stop bits, no EOF.
I seem to be setting my port incorrectly because it can not read the 
data (doing a "cat" on the port is successful.)

This is the code I am using:
--------------------------------------------------------------------
	portId = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK);
         if (portId != -1)
         {
                 fcntl(portId, F_SETFL, 0);

                 tcgetattr(portId, &oldPortOptions);
                 tcgetattr(portId, &portOptions);

                 cfsetispeed(&portOptions, this->baudRate);
                 cfsetospeed(&portOptions, this->baudRate);
                 portOptions.c_cflag |= (CS8 | CLOCAL | CREAD);
                 portOptions.c_lflag = 0;
                 portOptions.c_iflag = IGNPAR;
                 portOptions.c_oflag = 0;

                 tcsetattr(portId, TCSANOW, &portOptions);
         }
         else
         {
                 perror("Serial was unable to connect to device");
         }
-------------------------------------------------------------------

Can anybody suggest what could be going wrong?

Thanks!

Anthony

0
Reply Anthony 9/11/2003 8:30:47 PM

Anthony Gallagher <anthonyg@cs.cmu.edu> wrote:
> Hi all,

> I need to set my serial port to interface with an RS-232 sensor that 
> receives and transmits raw data: 8 bytes, no parity, 1 stop bits, no EOF.
> I seem to be setting my port incorrectly because it can not read the 
> data (doing a "cat" on the port is successful.)

If "cat" on the device file (I guess that's what you mean with "port")
is successful it looks as if the default settings for the port are
already OK. So write a short program that opens the device file, call
tcgetattr() and look at the settings and you should know what's
required to get the device to talk to you. Then you still can mess
around with the settings until it doesn't work anymore ;-)

> This is the code I am using:
> --------------------------------------------------------------------
> 	portId = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK);
>          if (portId != -1)
>          {
>                  fcntl(portId, F_SETFL, 0);

Why this? Depending on which system you're using this will e.g.
clear the O_NONBLOCK flag you just specified when opening the
device file.

>                  tcgetattr(portId, &oldPortOptions);
>                  tcgetattr(portId, &portOptions);

                   portOptions = oldPortOptions;

could be faster and should produce the same results.

>
>                  cfsetispeed(&portOptions, this->baudRate);
>                  cfsetospeed(&portOptions, this->baudRate);
>                  portOptions.c_cflag |= (CS8 | CLOCAL | CREAD);
>                  portOptions.c_lflag = 0;
>                  portOptions.c_iflag = IGNPAR;

I never needed to set IGNPAR, but an IGNBRK was sometimes required.

>                  portOptions.c_oflag = 0;

>                  tcsetattr(portId, TCSANOW, &portOptions);
>          }
>          else
>          {
>                  perror("Serial was unable to connect to device");
>          }

                                      Regards, Jens
-- 
      _  _____  _____
     | ||_   _||_   _|        Jens.Toerring@physik.fu-berlin.de
  _  | |  | |    | |
 | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
  \___/ens|_|homs|_|oerring
0
Reply Jens 9/12/2003 8:18:23 AM


IGNBRK did it. Thanks so much!

Anthony



Jens.Toerring@physik.fu-berlin.de wrote:
> Anthony Gallagher <anthonyg@cs.cmu.edu> wrote:
> 
>>Hi all,
> 
> 
>>I need to set my serial port to interface with an RS-232 sensor that 
>>receives and transmits raw data: 8 bytes, no parity, 1 stop bits, no EOF.
>>I seem to be setting my port incorrectly because it can not read the 
>>data (doing a "cat" on the port is successful.)
> 
> 
> If "cat" on the device file (I guess that's what you mean with "port")
> is successful it looks as if the default settings for the port are
> already OK. So write a short program that opens the device file, call
> tcgetattr() and look at the settings and you should know what's
> required to get the device to talk to you. Then you still can mess
> around with the settings until it doesn't work anymore ;-)
> 
> 
>>This is the code I am using:
>>--------------------------------------------------------------------
>>	portId = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK);
>>         if (portId != -1)
>>         {
>>                 fcntl(portId, F_SETFL, 0);
> 
> 
> Why this? Depending on which system you're using this will e.g.
> clear the O_NONBLOCK flag you just specified when opening the
> device file.
> 
> 
>>                 tcgetattr(portId, &oldPortOptions);
>>                 tcgetattr(portId, &portOptions);
> 
> 
>                    portOptions = oldPortOptions;
> 
> could be faster and should produce the same results.
> 
> 
>>                 cfsetispeed(&portOptions, this->baudRate);
>>                 cfsetospeed(&portOptions, this->baudRate);
>>                 portOptions.c_cflag |= (CS8 | CLOCAL | CREAD);
>>                 portOptions.c_lflag = 0;
>>                 portOptions.c_iflag = IGNPAR;
> 
> 
> I never needed to set IGNPAR, but an IGNBRK was sometimes required.
> 
> 
>>                 portOptions.c_oflag = 0;
> 
> 
>>                 tcsetattr(portId, TCSANOW, &portOptions);
>>         }
>>         else
>>         {
>>                 perror("Serial was unable to connect to device");
>>         }
> 
> 
>                                       Regards, Jens

0
Reply Anthony 9/12/2003 5:31:16 PM

Anthony Gallagher <anthonyg@cs_dot_cmu.edu> wrote:
>IGNBRK did it. Thanks so much!

There are a few other things you  might want to change to
avoid bugs that will byte you later.

>>>This is the code I am using:
>>>--------------------------------------------------------------------
>>>	portId = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK);
>>>         if (portId != -1)
>>>         {
>>>                 fcntl(portId, F_SETFL, 0);
>> 
>> 
>> Why this? Depending on which system you're using this will e.g.
>> clear the O_NONBLOCK flag you just specified when opening the
>> device file.

That is a good point.  Here is a safer way to accomplish the
same results:

int open_serial_port(char *port)
{
  int fd, oldflags;
  
   /* O_NDELAY allows open even with no carrier detect */
  if (-1 != (fd = open(port, O_RDWR | O_NDELAY))) {
    /* clear O_NDELAY to allow read() to block */
    if ((-1 != (oldflags = fcntl(fd, F_GETFL, 0))) &&
	(-1 != fcntl(fd, F_SETFL, oldflags & ~O_NDELAY))) {
    } else {
      close(fd);
      return -1;
    }
  }
  return fd;
}

>>>                 tcgetattr(portId, &oldPortOptions);
>>>                 tcgetattr(portId, &portOptions);
>> 
>> 
>>                    portOptions = oldPortOptions;
>> 
>> could be faster and should produce the same results.

There are other problems too.

First, there is no need to save the original configuration of
the port unless that port is also your stdin/stdout which you
will be returning to.  Hence oldPortOptions is unnecessary.

Second, depending on *any* of the original configuration to be
correct in any way is asking for trouble.  Use google to find
how many times people have questioned why their program fails
when it is executed after some other specific program (pppd is a
common example)!  If the other program crashes or is killed by
SIGKILL, and it uses some line discipline other than 0, your
program simply won't be able to function because it will have
the wrong configuration.

Here is a typical serial port configuration function.  Note that
the entire termios structure is cleared, and then any bits which
are required to be set are configured.

void init_serial_port(int fd)
{
  struct termios tty;
  int bauds = B9600;       /* default baud */
  
  memset(&tty, 0, sizeof(tty));

  tty.c_iflag |= (IGNBRK | IGNPAR);   /* in flags */
  tty.c_cflag  = CS8 | CREAD | CRTSCTS | CLOCAL | HUPCL; /* out flags */

  tty.c_cc[VMIN]  = 5;	 /* minimum characters to wait for    */
  tty.c_cc[VTIME] = 1;   /* minimum time to wait 1/10 seconds */

  cfsetospeed(&tty, bauds);
  cfsetispeed(&tty, bauds);

  /* set serial port attributes */
  tcsetattr(fd, TCSADRAIN, &tty);

}

>>>                 cfsetispeed(&portOptions, this->baudRate);
>>>                 cfsetospeed(&portOptions, this->baudRate);
>>>                 portOptions.c_cflag |= (CS8 | CLOCAL | CREAD);
>>>                 portOptions.c_lflag = 0;
>>>                 portOptions.c_iflag = IGNPAR;
>> 
>> 
>> I never needed to set IGNPAR, but an IGNBRK was sometimes required.
>> 
>> 
>>>                 portOptions.c_oflag = 0;
>> 
>>>                 tcsetattr(portId, TCSANOW, &

Obviously there are many possible variations on the exact
parameters, depending on what is connected to the serial port.

-- 
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com
0
Reply Floyd 9/12/2003 7:17:48 PM

>>> Anthony Gallagher wrote:

AG>                 cfsetispeed(&portOptions, this->baudRate);
AG>                 cfsetospeed(&portOptions, this->baudRate);
AG>                 portOptions.c_cflag |= (CS8 | CLOCAL | CREAD);
AG>                 portOptions.c_lflag = 0;
AG>                 portOptions.c_iflag = IGNPAR;
AG>                 portOptions.c_oflag = 0;
cfmakeraw() is well-known faster way to prepare for such interaction.


-netch-
0
Reply Valentin 9/12/2003 7:39:41 PM

Floyd Davidson <floyd@barrow.com> wrote:
> There are a few other things you  might want to change to
> avoid bugs that will byte you later.

Floyd, wouldn't you have time to write an improved Serial-Programming-
HOWTO? Even though I read the existing one I never felt that I really
understand what I am doing and since you seem to be *the* expert (at
least as far as I can see from your postings here and in other groups)
everyone could learn a lot from your experience (and, as an additional
bonus, you wouldn't have to repeat yourself that often, a link to your
HOWTO should be enough ;-).
                                   Regards, Jens
-- 
      _  _____  _____
     | ||_   _||_   _|        Jens.Toerring@physik.fu-berlin.de
  _  | |  | |    | |
 | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
  \___/ens|_|homs|_|oerring
0
Reply Jens 9/12/2003 11:04:07 PM

Jens.Toerring@physik.fu-berlin.de wrote:
>Floyd Davidson <floyd@barrow.com> wrote:
>> There are a few other things you  might want to change to
>> avoid bugs that will byte you later.
>
>Floyd, wouldn't you have time to write an improved Serial-Programming-
>HOWTO? Even though I read the existing one I never felt that I really
>understand what I am doing and since you seem to be *the* expert (at
>least as far as I can see from your postings here and in other groups)
>everyone could learn a lot from your experience (and, as an additional
>bonus, you wouldn't have to repeat yourself that often, a link to your
>HOWTO should be enough ;-).
>                                   Regards, Jens

Well, a lot of the stuff I post is cut and pasted from previous
posts.

I do agree that the HOWTO is good only as far as it goes, and
that it is too terse to help even advanced programmers
sometimes.  A little commentary on why things are done, rather
than just example code that does them, might be useful.

Also there is a glaring bug in the Asynchronous IO code example,
where the termios structure is not cleared nor is it initialized
by tcgetattr() either.

Hmmm... come to think of it, there isn't anything in there about
manipulating the modem control lines or the status register.

I'll have to give that idea some thought.  It might be worth
doing.

-- 
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com
0
Reply Floyd 9/13/2003 12:16:38 AM

Floyd Davidson <floyd@barrow.com> writes:

>Second, depending on *any* of the original configuration to be
>correct in any way is asking for trouble.

That advice directly contradicts the POSIX standard, which says:

    "The effect of tcsetattr() is undefined if the value of the termios
    structure pointed to by termios_p was not derived from the result
    of a call to tcgetattr() on fildes; an application should modify
    only fields and flags defined by this volume of IEEE Std
    1003.1-2001 between the call to tcgetattr() and tcsetattr(),
    leaving all other fields and flags unmodified."

-- 
Geoff Clare <nospam@gclare.org.uk>
0
Reply Geoff 9/14/2003 7:15:54 PM

Geoff Clare <geoff@clare.See-My-Signature.invalid> wrote:
>Floyd Davidson <floyd@barrow.com> writes:
>
>>Second, depending on *any* of the original configuration to be
>>correct in any way is asking for trouble.
>
>That advice directly contradicts the POSIX standard, which says:

Actually, that isn't the part that contradicts the Standard.  My
advice to use memset() to clear the entire termios structure is
where the contradiction is.

>    "The effect of tcsetattr() is undefined if the value of the termios
>    structure pointed to by termios_p was not derived from the result
>    of a call to tcgetattr() on fildes; an application should modify
>    only fields and flags defined by this volume of IEEE Std
>    1003.1-2001 between the call to tcgetattr() and tcsetattr(),
>    leaving all other fields and flags unmodified."

Indeed, using memset() to clear the entire structure does not
conform to POSIX.

Unfortunately, in practice the effect is the opposite of what
having a Standard intends, simply because many people don't
realize which fields and flags _must_ be explicitly configured.

But perhaps more unfortunate is that there is no guarantee my
recommendation will continue to work, because it _is_ as you
say, non-conforming to the standard.  It depends upon the fact
that in current implementations setting all existing fields to 0
will work when the well known fields are set appropriately.
That could change.

Perhaps it would best to harp about learning which fields and
flags *necessarily* must be explicitly configured each and every
time.

I'll give it more thought, and try to incorporate that into my
examples and the discussions I post. I appreciate your excellent
point.

-- 
Floyd L. Davidson           <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska)                         floyd@barrow.com
0
Reply Floyd 9/14/2003 9:15:02 PM

8 Replies
176 Views

(page loaded in 0.086 seconds)

Similiar Articles:













7/10/2012 3:25:19 AM


Reply: