Re: Flow Control on Serial Device



Floyd,
following your recommendations I corrected my program and repeated my tests.
I found out that if I just reboot my pc from Windows to Linux ttyS0 behaves
like I described in my last append:
nothing works at all, the sniffer does not even see the initial character
string.
I have to shutdown, power off, disconnect and reconnect the cable and power
on again.
Then I see in Linux the same status as in WT: rts on, cts off.
When I the execute my program, the result is also like in WT: the sniffer
sees the initial character string,
but now answer comes from the device.
This is my program:

fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0)
{
write_log("Device /dev/ttyS0 ungültig");
abort();
}
else
{
write_log("Device /dev/ttyS0 geöffnet");
fcntl(fd,F_SETFL,FNDELAY);
}

memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = (CLOCAL | CREAD | CS8);
newtio.c_iflag = (IGNBRK | IGNPAR);
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;

rc = cfsetospeed(&newtio, BAUDRATE);
if (rc<0)
{
write_log("cfsetospeed missglückt");
abort();
}
rc = cfsetispeed(&newtio, BAUDRATE);
if (rc<0)
{
write_log("cfsetispeed missglückt");
abort();
}
tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
fcntl(fd, F_SETOWN, getpid());

strcpy(buf,"UUUUU\xFF\xFF\x01\x5b\x8f");
if (write(fd, buf, 10) != 10)
{printf("Fehler beim Schreiben auf tty\n"); abort();}

strcpy(buf,"\x00\x5a\x07\x01\x33\x00\x00\x95");
if (write(fd, buf, 8) != 8)
{printf("Fehler beim Schreiben auf tty\n"); abort();}

Paul


"Floyd L. Davidson" <floyd@xxxxxxxxxx> schrieb im Newsbeitrag
news:87wt04baq7.fld@xxxxxxxxxxxxx
"Paul Pridt" <p.pridt@xxxxxxxxx> wrote:
Floyd,

I re-engineered my cable and connected line 7 (RTS) also.
So the cable now looks like that:
2,3,5,7 and 8 are straight-thru. On the PC-side 6 and 4 are connected (did
not make any difference).
The sniffer ends are connected to 2 and 3 respectively and to 5.
Then I repeated all the tests and noted down the measurements as follows:

W WA WT LS0 LUSB

2 -7,1 -7,1 -7,2 -6,4 -7,2
3 0 -5,3 -5,3 0 -6,9
7 0 -5,3 +5,9 0 -7,3
8 -7,1 -7,1 -7,1 -6,7 -7,2

That means:
W Windows only (no application started)

Note the 0 voltage on pins that are sourced by the PC. That
means your serial port is not active... and is not putting any
"signal" on those pins yet.

WA Windows application program (provided with the device)

Incidentally, I don't believe the voltages are calibrated! I'll bet
you anything that what shows up there as -5 is more like -12. And
your remote device isn't actually -7, but more like -15.

WT Windows perminal program

Note the similarity to WA, which is exactly what it should be.

LS0 Linux ttyS0

This is the same as W, with no signal at all from the PC. The
serial port is not enabled. What happens if you run

/sbin/setserial /dev/ttyS0

LUSB Linux ttyUSB0

The USB to serial port converter always has the RS232 port
enabled.

In all cases the same cable and hardware was used with the following
exception:
in Linux ttyS0 did not work at all (the sniffer program did not even see
the
initial character string sent)

The voltages shown above indicate that it is not enabled, so that
fits. Serial ports may not be enabled in your kernel???

and I have to use an usb-serial adapter, while the Windows application
program runs on com1 only.
In Windows only the application program provided with the device works.
Interesting is that when I use the Windows terminal program to send the
initial character string line 7 shows +5,9 V,
but there is no response from the device either.

That is the RTS line sourced by the PC. It is difficult to know
what response there should be from the device.

Typically the common usage today would be that if RTS is
asserted, the remote device will send data if it wants to and if
RTS is not asserted the device will not send data even if it
wants to. The same effect, in the opposite direction, would be
true of CTS.

So you would not see anything happen when RTS is asserted
_unless_ it just happens that the device has data ready to send
(and of course full hardware flow control is enabled, so that it
was inhibited from sending until RTS was asserted).

It doesn't appear that the RTS line is actually being used.

And I have a sneaking suspician that CTS is not being used for
flow control as such. If you watch pin 8 for awhile when the
Window application is running, does it ever flip to a positive
voltage, even for a moment? If not, they might be using it as
merely the equivalent of DTR, to indicate that the device is
ready.

If that is the case, you could strap pin 8 to the DCD input on
pin 1 and cause the programming task to be easier...

In Linux I made the same test with my application program and serlook.
In both cases the sniffer program sees the initial character string but no
response.

Your serial port is not enabled.

These are the relevant parts of my program:

Unfortunately, that does not include many relevant parts! Don't
make any attempt to edit on a line per line basis. Grab the entire
function, because you probably have all sorts of odd things that
have effects you aren't aware of...

fd = open(tty, O_RDWR | O_NOCTTY | O_NDELAY);

Use O_NONBLOCK rather than O_NDELAY, just to make it more
portable. They are precisely the same on Linux but might be
different on other unix OS's.

But here we don't have any error checking, so there is no way to
tell of the call to open() failed or succeeded. If your serial
port is not enabled in the kernel, it failed and that would
cause exactly the symptoms you describe.

Also, you are not re-enabling O_NONBLOCK, which is going to make
reading data from this serial port a bit complicated.

tcgetattr(fd,&oldtio);

There is no point in saving the original configuration.

bzero(&newtio, sizeof(newtio));

Use memset() instead of bzero().

newtio.c_cflag = CLOCAL | CREAD | CS8;

That is good, but you also probably want a few others,

newtio.c_iflag = (IGNBRK | IGNPAR);

newtio.c_iflag = 0;
newtio.c_cc[VMIN]=0;
newtio.c_cc[VTIME]=0;

Note that you have already zeroed the entire struct, and
these are redundant.

Also, I would not recomment setting both VMIN and VTIME elements
of the c_cc array to zero.

The easiest way to read data from a serial port is with blocking
i/o, and then with one of VMIN/VTIME set to 0 and the other to 1,
depending on the desired effects.

If they are both set to 0, a call to read() will always return
immediately. If VMIN is 1 and VTIME is 0, the call to read()
block forever or until there is at least 1 byte of data or a
interupt signal is received. If VTIME is 1 and VMIN is 0, the
call to read() will return if data is available or will block
for 1/10th of a second before returning with no data.

One of the significant effects of the above is that if each
call to read() can block, the process very nicely gives up its
time slice and does not become a CPU hog. (If you use nonblocking
i/o in a tight loop you'll beat the CPU to death at the needless
expense of every other process running.)

If you set VTIME to 0, then read() should only be called after
the select() function has determined that there is data
available.

cfsetospeed(&newtio, BAUDRATE);
cfsetispeed(&newtio, BAUDRATE);
tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

That needs to have error checking added to make sure that it has
done something. (No error does not mean that it necessarily did
what you wanted, but an error means it didn't do anything.)

fcntl(fd, F_SETOWN, getpid());

ioctl(fd,TIOCMGET,&status);
status |= TIOCM_RTS;
ioctl(fd,TIOCMSET,&status);

write(fd,"UUUUU\xFF\xFF\x01\x5b\x8f\x00\x5A\x07\x01\x33\x00\x00\x95",18);

I hope this all is readable to you.
Thank you very much for your effort.

No problem... other than I haven't been doing much of this in
the last few years, so I'm a bit dull sometimes and miss obvious
things.

--
Floyd L. Davidson <http://www.apaflo.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska) floyd@xxxxxxxxxx


.