2

I have a device I'm trying to do some testing on. I know it connects at a baud rate of 115200, with 8 data bits, no parity and 1 stop bit.

I'm attempting to prove these settings, or at least get close to showing these are in fact the settings the device is using. The device sends known data at startup, so the testing strategy is connect at correct setting to receive it, then vary a single setting and expect corrupted data.

However, when I vary the parity or stop bit settings with pyserial or termios directly, I do not see corrupted data. Only variation to a data size of 6 bits corrupts the data.

Is there any location or log where issues such a parity or stop bit errors could be recorded? Is there some setting using termios which can be tweaked to note errors with parity or stop bits?

More data: Actual serial traffic is over a FT4232H in a USB-COM422-PLUS4 board, so the black box I'm looking to test shows up as /dev/ttyUSB3

1 Answer 1

2

You should be able to detect parity errors with the right termios settings, and even count them, depending on what the driver provides. The ioctl TIOCGICOUNT (see man 4 tty_ioctl) can retrieve error counters, though this is not documented in the man page. The ioctl is not provided by Python, but the following script getcounts.py does it through a low-level fcntl call that may need modifying for your system. It uses the structure described in the kernel serial.h include file. (Note, the counters for real serial devices can also be seen in /proc/tty/driver/serial, but not for usb devices).

#!/usr/bin/python2
# https://unix.stackexchange.com/a/525261/119298
import sys, fcntl, array
# ioctl to get counters. see /usr/include/linux/serial.h
# struct serial_icounter_struct{
#  int cts, dsr, rng, dcd, rx, tx, frame, overrun, parity, brk,
#      buf_overrun, reserved[9]; }
def getcounts(filename):
    TIOCGICOUNT = 0x545D
    fd = open(filename)
    s = array.array('I',[0 for i in range(20)])
    rc = fcntl.ioctl(fd.fileno(),TIOCGICOUNT,s,True)
    if rc!=0:
        print "rc",rc
    names = "cts,dsr,rng,dcd,rx,tx,frame,overrun,parity,brk,bufo"
    cts,dsr,rng,dcd,rx,tx,frame,overrun,parity,brk,bufo = s[:11]
    for i,name in enumerate(names.split(",")):
        print name,s[i]
    fd.close()

getcounts(sys.argv[1])

For example, with 2 real serial ports connected via a crossover cable the following script will show 3 different results as we change the parity detection settings. Start off by setting both serial devices the same, to generate and detect even parity (-ignpar with - for "not"). The try function is run 3 times to write hello on ttyS1, then to use xxd to read the result from ttyS0, and finally run getcounts.py to print the counters:

#!/bin/bash
try()(
    xxd -l 16 /dev/ttyS0 &
    sleep 1
    for i in 1 2 3 ; do echo hello; done >/dev/ttyS1
    sleep 1
    getcounts.py /dev/ttyS0
)

stty -F /dev/ttyS0 9600 raw -echo clocal
stty -F /dev/ttyS1 9600 raw -echo clocal
stty -F /dev/ttyS0 parenb -ignpar inpck parodd
stty -F /dev/ttyS1 parenb -ignpar inpck parodd
try # should be ok
stty -F /dev/ttyS0 -parodd
try # should get parity errors, lots of null data
stty -F /dev/ttyS0 parmrk
try # should get parity errors, lots of ff 00 prefix to each data

The first try should show us the data coming through ok, and a parity count of 0 (assuming we have just started using these devices):

00000000: 6865 6c6c 6f0a 6865 6c6c 6f0a 6865 6c6c  hello.hello.hell
...
parity 0
...

Before the next try, we change to even parity on ttyS0 and we get the output

00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
parity 16

i.e. a null char for each character with bad parity. The actual count of parity errors is 16 as xxd stops after reading 16 characters.

Before the final try, we ask to mark the parity errors in the data. This makes the kernel put 2 bytes 0xff and 0x00 in front of each bad data character, and we get:

00000000: ff00 68ff 0065 ff00 6cff 006c ff00 6fff  ..h..e..l..l..o.
parity 22

The parity count only goes up by 6 as xxd terminates even earlier.

The data seen above should be the same for a usb driver, but you might not get any change in the counters.

2
  • Is there a way to detect parity errors that won't trigger false positives on literal 0xff 0x00 sequences in the input stream?
    – Maxpm
    Oct 13, 2019 at 0:41
  • If using odd parity, ff 00 are illegal data as they should be 7f 80. If using even parity, after ff 00 check the parity of the next character; if it is odd then we had a marker; if it is even then we had 2 real data characters. If there is no third character yet, then we had real data also, as the kernel puts the marker and bad character out immediately.
    – meuh
    Oct 13, 2019 at 8:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.