This is a discussion on Possible to receive 8O1 data on serial port? within the Linux Networking forums, part of the Linux Forums category; I'm developing an application in C++ on RedHat 7.3 which reads data from a serial port (RS422 - I'...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
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 |
|
|||
|
mcollins@nyx.net (Killans - First And Last And Always) wrote:
>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. >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! >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? ;-) > // 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.) >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. >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. >Thanks very much in advance, > >Mike -- FloydL. Davidson <http://web.newsguy.com/floyd_davidson> Ukpeagvik (Barrow, Alaska) floyd@barrow.com |
|
|||
|
floyd@barrow.com (Floyd L. Davidson) writes:
>mcollins@nyx.net (Killans - First And Last And Always) wrote: >>- 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. > 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 |
|
|||
|
floyd@barrow.com (Floyd L. Davidson) dedi ki:
> mcollins@nyx.net (Killans - First And Last And Always) wrote: >>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. -- Abdullah | aramazan@ | Ramazanoglu | myrealbox | ________________| D-O-T cöm | |
|
|||
|
Floyd L. Davidson wrote:
> Can't possibly work!**You've*only*got*8*data*bits*per*character > frame.**If*you*use*the*high*bit*for*parity,*your*d ata*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) |
![]() |
| Thread Tools | |
| Display Modes | |
|
|