How to isolate pty buffers created with socat and tee from tty? - linux

I'm trying to clone a tty that is connected to a serial device, so that I can have two programs reading the data simultaneously (one program occasionally writes to the serial device as well).
I'm using socat to clone the tty, which works fine:
socat /dev/ttyACM0 SYSTEM:'tee >(socat - "PTY,rawer,link=/tmp/myPTY1") | socat - "PTY,rawer,link=/tmp/myPTY2"'
However, these PTYs are not isolated. When myPTY1 doesn't get read, after some time myPTY2 won't receive any new data. Only when I then read from myPTY1 (clearing all the buffered data) then myPTY2 receives new data. I suspect this is about how socat buffers data, it seems like both PTYs are connected to the same buffer.
I would like both PTYs to be completely isolated, so that when one PTY doesn't get read (buffer runs full), the other isn't stuck, but continues receiving new data. Any idea how to do this?
I tried some socat options like nonblock, wait-slave, ctty but none have the desired effect.

Related

Sending to a serial device via socat only shows up if I'm actively reading -- I need the data to be cached

I have socat creating two serial ports: ttyclient and ttyserver, ttyclient will be called by an application and I have a script listening to ttyserver. The sequence of events I need is
My socat creates the two via /usr/bin/socat -d -d PTY,link=./ttyserver,raw,echo=0 PTY,link=./ttyclient,raw,echo=0
My script writes a few bytes to ttyserver (to be read by ttyclient)
At some later point in time the application runs, reads the bytes from ttyclient and goes to work.
The problem I am having is the bytes are only readable if something is read during step 2. If I run minicom -D ./ttyclient before step 2 I see the bytes being transmitted as expected, but afterwards shows nothing. The data appears to be discarded.
Is this expected behavior? I'm unsure of how to keep the data around so when something reads it is presented with those bytes. Alternatively I'd happy if I had some way to know ttyclient has been opened and send data on that event.
The issue is that I was using Minicom to read ttyclient. For whatever reason Minicom won't display cached data like that... If I just use cat I get my desired behavior.

Virtual Serial Port with Socat (Linux) and allow buffer overflow

When writing from a laptop to an external serial device that I am using, it is possible for the laptop to be writing faster than the program running on the device can actually clear its serial read buffer, leading to data being lost do to the buffer overflowing.
Is there a way to simulate this behavior using a virtual serial port with socat? For my testing so far, I have used the following command:
socat -d -d pty,raw,echo=0 pty,raw,echo=0
(For the sake of the example, lets say it creates /dev/pts/2 and /dev/pts/3, referred to as A and B respectively).
Which creates two virtual serial ports that I can send data across. However, if I start writing a large amount of data to A without reading any from B, the writing to A will eventually block until I read from B and make room in its read buffer.
It is unclear to me whether there is some internal feedback between the read buffer of B, or if the actual blocking is occurring in the write buffer of A due to some other internal feedback within whatever socat setup that tells blocks the writing because there is no room in the read buffer of B.
Is there any way to avoid this blocking and have it overflow the read buffer of B?
Hopefully my question makes sense. Thank you for the help.

Reading data from the serial port of a STM32 using the Linux terminal

I'm trying to read and send data with a STM32F429ZI using a RS232-USB cable.
For the hardware, I'm using a RS232 DB9 to TTL MAX3232 converter connected to the UART2 ports PA2 and PA3 of the STM32. I don't know if this is relevant, but I'm using a couple of 10 cm long cables to connect the TX-RX of the RS232 module to the STM32.
Then, I'm trying to use the Linux terminal on Kubuntu to send and read data from the uC. These are the steps I'm following to configure the connection:
Using ls -lah /dev/ I look where the RS232-USB is connected. In my case, I can see that it connects to /dev/ttyUSB0.
Then I give my user permissions to read and write the USB port using sudo chmod o+rw /dev/ttyUSB0.
After that, I configure the baud rate of the connection with the stty command. In my case, I'm configuring the STM32 to work at 9600 bauds per second, so stty -F /dev/ttyUSB0 9600. Using stty -F /dev/ttyUSB0 -a, I can see that the speed is actually 9600 bauds per second.
So far so good. I can send data from my computer to the STM32 with no problems. To test this, I'm doing the following:
I have a 2x16 LCD display connected to the STM32, where I print the data I send from my computer.
To send data from the terminal, I'm just doing echo -n 'a' > /dev/ttyUSB. This seems to work just fine, as I can print the data in the LCD display correctly.
I have even tested a program to count the characters on a file and the time the operations takes, in order to corroborate the 9600 baud rate. To do this, I created a file with 9600 characters and I used cat test.txt | tr '\n' '#' > /dev/ttyUSB0 to send the file to the STM32. This is working mostly fine, I usually get the correct answer but other times I don't. Nonetheless, the times it doesn't work are quite low, so I'm assuming it is due to noise.
So, having tested I can actually send data from my computer to the STM32, I tried to do the opposite: to send data from the STM32 to my computer. But this doesn't seem to work, as I can't really read anything in my computer.
I have read in several forums that to read data from the serial on the Linux console, one just has to use the cat command on the device. So, I tried that in several ways but I just couldn't read anything:
cat /dev/ttyUSB0 shows nothing and I have to quit with Ctrl+C.
cat -v /dev/ttyUSB0 shows nothing and I have to quit with Ctrl+C.
cat < /dev/ttyUSB0 shows nothing and I have to quit with Ctrl+C.
cat /dev/ttyUSB0 & just shows a number and it finishes.
So, I don't know if I'm just using the cat command wrong or if it is a hardware problem or why I can send data from my computer but not read.
Here is the part of the program (in C) I'm using in the STM32 to read and send data:
while(1)
{
if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) != RESET)
{
Data = USART_ReceiveData(USART2);
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
USART_SendData(USART2, Data);
}
}
If someones needs it, I can upload the configuration of the USART ports, but I don't know if it will be relevant considering I can read data just fine.
Any help is appreciated.
Thanks in advance.
Edit: here's the current project - https://github.com/AugustoRiedinger/06TP_E02 ; and the project to read data https://github.com/AugustoRiedinger/06TP_E01
Your loop says "as long as it is not possible to send a byte, repeatedly try to send it anyway, as soon as it is possible to send a byte, discard it without sending"
Change:
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
USART_SendData(USART2, Data);
To:
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, Data);

Linux: Read data from serial port with one process and write to it with another

I've ecountered a problem using a serial GPS/GNSS device on a Raspberry Pi. The device in question is a u-blox GNSS receiver symlinked to /dev/gps.
I try to achieve logging the output data from this device and simultaneously sending correction data to it.
To be more specific, I use RTKLIBs (http://www.rtklib.com/) str2str tool for sending NTRIP/RTCM correction data to the GNSS receiver in order to get better position estimations using DGNSS/RTK.
The receiver's output data will be logged by a python script which is based on the GPS deamon (gpsd).
However, I guess the main issue is related to the serial port control.
When I run the writing process (str2str) first and afterwards any reading process (my python script/gpsd frontends (e.g. cgps) /cat) at the same time, the reading process will output data for a few seconds and freeze then. It doesn't matter which tool I use for reading the data.
I found this question: https://superuser.com/questions/488908/sharing-a-serial-port-between-two-processes. Therefore I made sure that the processes got rw access to the device and even tried running them as superuser. Furthermore I stumbled upon socat and virtual serial ports, but didn't find any use for it. (Virtual Serial Port for Linux)
Is there any way to read data from a serial port with one process and write to it with another? The only solution I know of right now might be to rewrite the read and write process in python using pySerial. This would allow to only have one process accessing the serial device, but would mean plenty of work.
Finally I found a soultion using a construction somehow similar to this: https://serverfault.com/questions/453032/socat-to-share-a-serial-link-between-multiple-processes
A first socat instance (A) gets GNSS correction data from a TCP connection, which is piped to socat B. Socat B manages the connection to the serial device and pipes output data to another socat instance C, which allows other processes such as gpsd to connect and get the receiver's output from TCP port.
In total, this looks like:
socat -d -d -d -u -lpA TCP4:127.0.0.1:10030 - 2>>log.txt |
socat -d -d -d -t3 -lpB - /dev/gps,raw 2>>log.txt|
socat -d -d -d -u -lpC - TCP4-LISTEN:10031,forever,reuseaddr,fork 2>>log.txt
With only one process managing the serial connection, it doesn't block anymore.

How can I monitor data on a serial port in Linux?

I'm debugging communications with a serial device, and I need to see all the data flowing both directions.
It seems like this should be easy on Linux, where the serial port is represented by a file. Is there some way that I can do a sort of "bi-directional tee", where I tell my program to connect to a pipe that copies the data to a file and also shuffles it to/from the actual serial port device?
I think I might even know how to write such a beast, but it seems non-trivial, especially to get all of the ioctls passed through for port configuration, etc.
Has anyone already built such a thing? It seems too useful (for people debugging serial device drivers) not to exist already.
strace is very useful for this. You have a visualisation of all ioctl calls, with the corresponding structure decoded. The following options seems particularly useful in your case:
-e read=set
Perform a full hexadecimal and ASCII dump of all the data read from
file descriptors listed in the
specified set. For example, to see all
input activity on file descriptors 3
and 5 use -e read=3,5. Note that this
is independent from the normal tracing
of the read(2) system call which is
controlled by the option -e
trace=read.
-e write=set
Perform a full hexadecimal and ASCII
dump of all the data written to file
descriptors listed in the specified
set. For example, to see all output
activity on file descriptors 3 and 5
use -e write=3,5. Note that this is
independent from the normal tracing of
the write(2) system call which is
controlled by the option -e
trace=write.
I have found pyserial to be quite usable, so if you're into Python it shouldn't be too hard to write such a thing.
A simple method would be to write an application which opened
the master side of a pty and the tty under test. You would then
pass your tty application the slave side of the pty as the 'tty device'.
You would have to monitor the pty attributes with tcgetattr() on the pty
master and call tcsetattr() on the real tty, if the attributes changed.
The rest would be a simple select() on both fd's copying data bi-directionally and copying it to a log.
I looked at a lot of serial sniffers. All of them are based on the idea of making a virtual serial port and sniff data from that port. However, any baud/parity/flow changes will break connection.
So, I wrote my own sniffer :). Most of the serial ports now are just USB-to-serial converters. My sniffer collects data from USB through debugfs, parse it and output to the console. Also any baudrate changes, flow control, line events, and serial errors are also recorded. The project is in the early stage of development and for now, only FTDI is supported.
http://code.google.com/p/uscmon/
Much like #MBR, I was looking into serial sniffers, but the ptys broke the parity check. However, his sniffer was not helping me, as I'm using a CP2102, and not a FT232. So I wrote my own sniffer, by following this, and now I have one that can record file I/O on arbitrary files: I called it tracie.

Resources