lcgamboa / tty0tty

Linux null-modem emulator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Baudrate change events & python interface

moefear85 opened this issue · comments

Thanks for this great library, it greatly streamlines my work. However, this is limited by 2 missing features.

Firstly, I frequently flash esp32's, but use a custom monitor written in python. For it to work I need to split the serial stream. So I use two tty0tty links (one for esptool, one for monitor), with a python script that relays data between them and the physical uart device. This indirection however limits the speed of flashing, because when esptool attempts to change the baudrate on the tnt device, this change isn't communicated to the other end of the tnt<->tnt link, so the listening script has no way to know the baudrate changed so can't set this on the physical uart.

I know this is a limitation due to the nature of uart devices/drivers, but there is a workaround. If for example we have /dev/tnt0 <-> /dev/tnt1, then additionally perhaps the tty0tty driver can also create /dev/tnt0_b and /dev/tnt1_b nodes, which are however pure (named) linux pipes. This way when any app connected to tnt0 or tnt1 changes the baudrate on that, this event is communicated to /dev/tnt1_b or /dev/tnt0_b instead. Then any (custom-written) app that needs these events, can open the tnt device and the pipe to detect the baudrate changes "out-of-band" so to speak, and can then relay them to the hardware uart device.
If pipes that aren't accessed/opened end up blocking the driver and this isn't configurable on the pipe to drop data when it isn't open, then one can create separate pairs of tnt links, some with and some without the additional pipes, and the user can then decide which to use.

Another improvement, would be realizing that it is redundant to use full tnt<->tnt links just to allow a custom script to appear as a uart device and communicate with another uart app such as esptool. It would be amazing if there were a (python) library so that a python script can on-demand create individual tnt ports, that then directly relay data and rts/dtr/cts/dsr and baudrate events to/from esptool and the python script (pipes wouldn't be needed). Currently, this is somewhat possible for ptys, but these don't offer rts/dtr/cts/dsr or baudrate events, which is however crucial for the functioning of esptool.

A third improvement would be to allow the user to configure how many tnt's appear in a single link, so for example a user can choose 3 tnt's connected together in star topology, so that any message reaching one tnt, is output on all others, including rts/dtr & baudrate events, so that even users without programming knowledge can setup such a splitter, and avoid reinventing the wheel.

As you said due to the limitations of the nature of uart devices/drivers, the baudrate is normally set when the port is open, so there is no way to read the baudrate of a port in use. I believe the simplest solution for tty0tty is to expose the value of port parameters in the /sys or /proc interface. In that way a non-trivial application like yours can monitor the baudrate value from /proc or /sys even with the port open.

As for the creation of ports by the user space, excluding tty0tty driver, there are only alternatives without the handshake lines (ptys, socat...). I created tty0tty because I needed rts/dtr/cts/dsr to use with my simulator PICSimLab to communicate with serial applications (avrdude, esptool, ...)

I believe that making an application to connect several virtual ports in different configurations, such as a spliter as you mentioned, is simpler and more flexible than implementing this directly in the driver. I believe that adding a script or application in the repository that implements a spliter is a way to help those who need it.

I will study the possibility of using the /proc and /sys interface as soon as I have time.

Yes that is my intention. It is however heavy on resources because of all the indirection. Once I find a pure virtual serial port driver with rts/dtr/baudrate events I can rewrite it into something uploadable to github, or you can merge it into your tool. thx for the time.

I don't see why you wrote a virtual serial driver to virtual serial driver driver for the simulator rather than having the simulator access/provide a single virtual serial driver directly.

if you want, you can write a programmatic interface to virtual serial ports (that can be statically set up in the driver), and I'll manage to write a splitter in C++. But doing so using tnt<->tnt <-> splitter <-> tnt<->tnt is outrageously inefficient i wouldn't bother open-sourcing something like that. I would have done it myself but writing kernel drivers isn't currently my expertise.

Communication synchronization can be done using the poll() function for data and for changing the baud rate of the serial ports. As long as there is no data, the program is in sleep state. The synchronization part of the modem signals can be done with a TIOCMIWAIT ioctl if it is supported by the real port driver (tty0tty's virtual ports already support this ioctl), so it is not inefficient if implemented correctly.

I created the driver because the simulator simulates a real board and communicates with real programs like avrdude and esptool. These programs use the flow control signals to reset the board, thus just creating a driver for that.

Writing kernel drivers isn't currently my expertise too. I made some changes in the driver to externalize the baudrate of the virtual port using sysfs, after the tests I will update the repository.

Hi @moefear85,
In new version 1.4 I have added support in the driver to report the baudrate of virtual ports in sysfs and added a serial sniffer application to the github repository. The virtual sniffer application can be used as a splitter and will solve your application usage problem. I tested it with avrdude and esptool and it worked without problems. I believe the code can be implemented in python without any problems.