Possible to receive 8O1 data on serial port?

Possible to receive 8O1 data on serial port?

Post by Killans - First And Last And Alwa » Sat, 21 Aug 2004 00:31:15



I'm developing an application in C++ on RedHat 7.3 which reads data from
a serial port (RS422 - I'm using an Amplicon board) which comes
from another third-party device.  The communication protocol for
the device specified that the device sends data using 8O1 characters
- i.e. 8 data bits, parity bit using odd parity, and 1 stop bit.

However, this has been causing me problems. I'm a relative newcomer to
Linux development, and a complete newcomer to serial programming. I've
been using the "Serial Programming HOWTO" and the "Serial Programming
Guide for POSIX Operating Systems" that Google was good enough to find
for me.

Referring to those documents, I had configured the serial port in
software to use those settings:

    TermIOs portParams;              // Terminal parameters for RS422 port

    // Set to 8-bit odd parity with 1 stop bit and no flow control
    portParams.c_cflag |= PARENB;   // Switch on "enable parity bit" flag
    portParams.c_cflag |= PARODD;   // Switch on "odd parity" flag
    portParams.c_cflag &= ~CSTOPB;  // Switch off "2 stop bits" flag
    portParams.c_cflag &= ~CSIZE;   // Reset the character size bits
    portParams.c_cflag |= CS8;      // 8 data bits
    portParams.c_cflag &= ~CRTSCTS; // Turn off hardware flow control

and to enable the INPCK and ISTRIP settings, as recommended by
those two documents (planning to implement parity error checking later):

    // Enable parity checking, and strip the parity bit
    portParams.c_iflag |= (INPCK | ISTRIP);

However, I've been finding that the data bytes that my application has
received have had the top bit stripped out, effectively reducing them
to 7-bit values containing screwed-up data.

On disabling the ISTRIP setting, everything worked.  However, when I
enabled the PARMRK setting, I was getting a ton of parity error markers
(0xFF) coming through with the data, which suggests that the underlying
serial driver might be interpreting the top data bit as a parity bit.

So, it appears that I can't get 8-bit data and a parity bit via the
serial port. This is inconvenient, because I'd really like to have
genuine parity error checking available.

I'd really appreciate any advice any experts here have.  Have I totally
misunderstood something?  As I said, I'm a newbie at this, so it's entirely
possible that I've screwed up somewhere, so please let me know if I have.

Incidentally, I'm also a newcomer to the comp.os.linux* heirarchy.  My
apologies if I've posted to an inappropriate group - if there's a more
appropriate group I should have posted this to, please let me know.

Thanks very much in advance,

Mike

 
 
 

Possible to receive 8O1 data on serial port?

Post by Floyd L. Davids » Sat, 21 Aug 2004 01:31:32



Quote:>I'm developing an application in C++ on RedHat 7.3 which reads data from
>a serial port (RS422 - I'm using an Amplicon board) which comes
>from another third-party device.  The communication protocol for
>the device specified that the device sends data using 8O1 characters
>- i.e. 8 data bits, parity bit using odd parity, and 1 stop bit.

Can't possibly work!  You've only got 8 data bits per character
frame.  If you use the high bit for parity, your data *necessarily*
must be 7 bit data.

Quote:>However, this has been causing me problems. I'm a relative newcomer to
>Linux development, and a complete newcomer to serial programming. I've
>been using the "Serial Programming HOWTO" and the "Serial Programming
>Guide for POSIX Operating Systems" that Google was good enough to find
>for me.

Be careful of the "Serial Programming HOWTO", as it has a number
of serious flaws.  The guide for POSIX is an excellent resource!

Quote:>Referring to those documents, I had configured the serial port in
>software to use those settings:

>    TermIOs portParams;              // Terminal parameters for RS422 port

You aren't showing your entire code segment here, but I'm
willing to bet, based on what you have shown, that one of the
problems with the HOWTO is built into your code.

Note that POSIX says you must initialize the termios struct by
calling tcgetattr(); however, that does *not* mean what you get
is in any way a valid configuration for your purposes!  Hence
you should not assume that any member of the termios struct is
in any way correct.  Either zero every member, or set it to some
specific value known to be required by your program.

You are only turning on and off certain bits.  What about any
bits that you don't happen to be setting?  They might be right,
and they might be wrong.  Hence, the first of these changes
should be

 portParams.c_cflag = PARENB;   // Switch on "enable parity bit" flag

Which zeros all bits except the ones you are setting.  Obviously
you then have no need to switch any other bits off.  And for that
matter you could set all the required bits with just one statement,

 portParams.c_cflag = (PARENB | PARODD | CS8);

Of course, the first thing you'll discover about the above line is
that it is incomplete, and will *not* work!  You probably want this,

 portParams.c_cflag = (PARENB | PARODD | CS8 | CREAD | CLOCAL);

(Turning on the receiver does seem line a useful idea, eh? ;-)

Quote:>    // Set to 8-bit odd parity with 1 stop bit and no flow control
>    portParams.c_cflag |= PARENB;   // Switch on "enable parity bit" flag
>    portParams.c_cflag |= PARODD;   // Switch on "odd parity" flag
>    portParams.c_cflag &= ~CSTOPB;  // Switch off "2 stop bits" flag
>    portParams.c_cflag &= ~CSIZE;   // Reset the character size bits
>    portParams.c_cflag |= CS8;      // 8 data bits
>    portParams.c_cflag &= ~CRTSCTS; // Turn off hardware flow control

>and to enable the INPCK and ISTRIP settings, as recommended by
>those two documents (planning to implement parity error checking later):

>    // Enable parity checking, and strip the parity bit
>    portParams.c_iflag |= (INPCK | ISTRIP);

The same comments as above go for all of the termios flag members.

Plus, there is one more gotcha that isn't discussed in either of
the resources you are using.  As the POSIX guide mentions, POSIX
requires certain members to exist in the termios, but also
allows the platform to have other "non-standard" members...  and
Linux has one, which is important.  You want something like this
in your configuration section,

  #include <sys/ioctl.h>      /* defines N_TTY        */
  #ifdef __linux__
    /* for linux only */
    tty.c_line      = N_TTY;  /* set line discipline  */
  #endif

The above prevents a common problem where a serial port has be
used previously by another application (for isdn, ppp, or a
mouse are common examples) that sets the line discipline to a
value other than N_TTY (which is 0).  If that program exits and
first resets the original configuration, there perhaps no
problem; but if the program crashes, is killed with SIGKILL, or
simply does not reset the port, it can leave the line discipline
value set to something which absolutely will not work for your
application.  (I'm not sure about the others, but N_PPP is
guaranteed to make your serial port appear to be dead as door
nail for use by a terminal program.)

Quote:>However, I've been finding that the data bytes that my application has
>received have had the top bit stripped out, effectively reducing them
>to 7-bit values containing screwed-up data.

>On disabling the ISTRIP setting, everything worked.  However, when I
>enabled the PARMRK setting, I was getting a ton of parity error markers
>(0xFF) coming through with the data, which suggests that the underlying
>serial driver might be interpreting the top data bit as a parity bit.

>So, it appears that I can't get 8-bit data and a parity bit via the
>serial port. This is inconvenient, because I'd really like to have
>genuine parity error checking available.

It really isn't very useful anyway... ;-)

Parity checking has several problems.  First, it requires too much
overhead to check each and every byte.  Moreover, it can easily miss
certain multibit errors.

Hence you are far better off blocking your data into some type of
a large frame, and using CRCs to validate the blocks, as one example
of a better method.

Quote:>I'd really appreciate any advice any experts here have.  Have I totally
>misunderstood something?  As I said, I'm a newbie at this, so it's entirely
>possible that I've screwed up somewhere, so please let me know if I have.

>Incidentally, I'm also a newcomer to the comp.os.linux* heirarchy.  My
>apologies if I've posted to an inappropriate group - if there's a more
>appropriate group I should have posted this to, please let me know.

I'd say you've made an *excellent* choice by crossposting to two very
applicable newsgroups.

Quote:>Thanks very much in advance,

>Mike

--
FloydL. Davidson           <http://web.newsguy.com/floyd_davidson>


 
 
 

Possible to receive 8O1 data on serial port?

Post by Holger Peterse » Sat, 21 Aug 2004 03:37:12




>>- i.e. 8 data bits, parity bit using odd parity, and 1 stop bit.
>Can't possibly work!  You've only got 8 data bits per character
>frame.

On the Hardware-UART-level it works very well. Try the very old
DOS-utility DIAGS.EXE and this program will show you all received
bytes with a global count of parity-Errors.

Quote:>    If you use the high bit for parity, your data *necessarily*
>must be 7 bit data.

That's true.

One _may_ ask the UART _before_ catching a data-byte on the state
of the Parity-error-bit for that byte. IF one would be interested
in saving that info it must be transferred to the receive-buffer
as well. That would mean a change in the serial Interrupt driver
for Linux; I suppose...

Yours, Holger

 
 
 

Possible to receive 8O1 data on serial port?

Post by Abdullah Ramazanog » Sat, 21 Aug 2004 05:22:02




>>I'm developing an application in C++ on RedHat 7.3 which reads data from
>>a serial port (RS422 - I'm using an Amplicon board) which comes
>>from another third-party device.  The communication protocol for
>>the device specified that the device sends data using 8O1 characters
>>- i.e. 8 data bits, parity bit using odd parity, and 1 stop bit.

> Can't possibly work!  You've only got 8 data bits per character
> frame.  If you use the high bit for parity, your data *necessarily*
> must be 7 bit data.

But this is against the asynchronous serial comms standard AFAIK. Then
again, parity processing is defined in link layer and is/should be
transparent to driver. It is confined to UART-to-UART comms, and completely
handled by UART hardware. Driver only sets the UART for parity (along with
bits/char, number of stop bits etc.) and gets notification when there's a
parity error. Same with the stop bit(s).

So the driver should always send/receive 8 bits (5, 6, 7 or 8 "significant"
bits) per character regardless of parity and stop bit settings.

--

Ramazanoglu     | myrealbox |
________________| D-O-T c?m |

 
 
 

Possible to receive 8O1 data on serial port?

Post by James Knot » Sat, 21 Aug 2004 05:55:35



> Can't possibly work!??You've?only?got?8?data?bits?per?character
> frame.??If?you?use?the?high?bit?for?parity,?your?data?necessarily
> must be 7 bit data.

Parity is not part of the data.  In the 8250 UART (from which most current
PC UARTS are derived) you could set data to 8 bits and have a parity bit.
The parity bit was handled in registers entirely separate from the data.

--

(This space intentionally left blank)

 
 
 

1. How can I send and receive data on the serial port 1 on RedHat 5.2

Hi:
I am currently learning to write serial programs on RedHat Linux 5.2.
I currently do not have any way of connecting to another machine.  As
a result I built a DB-9 Loopback Adapter.

I tied the following pins together to build the adapter:
 Pins 2-3      RXD-TXD
 Pins 7-8      RTS-CTS
 Pins 1-4-6-9  CD-DTR-DSR-RI
 Pin  5        GND (unused)

I was curious if anyone else has attempted this before and has gotten
it to work.  I am trying the adapter with the given program listed
below.  The program will send but not receive data.

Please ignore the fact I am not using select to read the port and
other various infractions.  I just wanted a dirty little program to
make sure I could send and receive before doing something more useful.

Any insight of how to get this running or another method of doing a
loopback-ish trick, I would much appreciate the help.

Please mail to me so I don't miss the message.

Thanks,

====================================================================
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#define PORT "/dev/ttyS1"

#define STR1 "Hello"
#define STR2 "World"

int open_port (char *port)
{
    int    fd;

    fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
        fprintf(stderr,"Open Port: %s - %s\n", port, strerror(errno));
    else
        fprintf(stderr,"Port: %s opened.\n", port);

    return (fd);

void main ()
{
    int    fd;
    char   buf[80];
    int    n;

    if ((fd = open_port(PORT)) > 0)
    {
        printf("Sending: %s %s\n", STR1, STR2);
        n = write(fd, STR1, strlen(STR1));
        printf("Bytes sent: %d\n", n);
        n = write(fd, STR2, strlen(STR2));
        printf("Bytes sent: %d\n\n\n", n);

        while(1)
        {
            if (read(fd,buf,sizeof(buf)) > 0)
                printf("%s",buf);
        }
    }

    close(fd);

2. remote ftp mount

3. serial port data acquisition without data loss?

4. NETSCAPing on Linux

5. How to copy data from serial port to a file (data logging) ?

6. mod_rewrite broken in 1.3.x?

7. Receiving Serial Data

8. Swap slice constraints?

9. Serial: receiving data while under load

10. Receiving TCP ignores sending data when receiving buffer is full???

11. Help receiving signal when data is received on socket

12. How do I send/receive data through the parallel port?

13. Q: How to send/receive raw binary data over serail port?