Search code examples
serial-portrs485multiplexingzephyr-rtos

How to implement a bus type serial link using Zephyr on native_sim (possibly using socat)?


I'm an electrical engineer currently getting into Zephyr with regards to automated testing (I'd like to use native_sim to make application logic development + testing a bit more separate from hardware development) as a hobby interest. The physical board features a RS485 bus connection to string multiple boards together.

Running Zephyr as a Linux application allows to allocate a PTY for its serial connection. However, if I let my (test) supervisor spin up all neccessary 16 instances I'm left with 16 PTY devices and a need to connect all of them in a 'bus type' manner. Bus type in this case means 'anything sent by Zephyr ptyN gets received by all other Zephyr pty instances'. The higher level protocol theoretically excludes an overlap of transmissions which should take care of the problem of concurrent writes to a buffer.

People seem to use two common approaches to connect multiple serial ports together: socat and tty0tty. Hoewever, tty0tty only connects two data streams together, so this is not really an option.

I might be able to use socat on a per instance basis to attach itself to the Zephyr pty and on the other end to a relay server based on TCP connection, perhaps also a socat instance. A file cannot be opened more than once, hence a local filebinding won't work either. This means managing the state of two programs for a single instance which isn't really preferable.

From what I have learned searching the internet, no such 'shared buffer' solution seems to be doable using tools commonly available on Linux platforms. This is where I would turn to Python to create a small fixture (basically a relay server) exactly the above:

  • Take a list of file descriptors (PTY filenames can be forced in Zephyr) from the supervisor, open them and wait for input
  • Once an input is received, copy the input into all other file descriptors output buffer
  • Listen to the shutdown signal of the supervisor

This is where I'm hitting the limits of my knowledge of Linux/Unix. I know I'm able to implement it this way but if possible I prefer a solution that doesn't rely on home-cooked code when there probably is a more basic Linux based approach out there. I can't be the only one that needs to 'clone traffic' between serial interfaces:

Is there another, possibly simpler/reduced way, getting around all of this and simply using socat to implement a bus type serial connection?


Solution

  • Socat version 1.8 contains a shell script socat-broker.sh that might do what you need. Start it in a way like:

    socat-broker.sh TCP-L:1234

    Then start connectors for each pty N:

    socat /dev/ptyN TCP:localhost:1234

    Please note that this script requires socat 1.8.0.0; it works internally with UDP/IPv4 broadcast on the loopback interface to do the data copying. Communications are not protected from local users and processes!