Serial ports are for distinct machines to communicate with each other, not for IPC within the same machine. You can configure serial hardware for loopback, but the highest data rates supported by serial port hardware do not come anywhere close to the speed of any modern interconnect -- not USB or eSATA (for other interfaces with "serial" in their names) nor network interconnects such as ethernet (even wireless). Serial port speed is not even in the same solar system as a FIFO's.

As far as other characteristics go,

  • serial ports will be presented to the system as device files, and FIFOs also will be presented as files
  • as such, each can be opened concurrently by multiple unrelated processes, for both reading and writing
  • however, you need special privileges to create a serial port special file, plus actual hardware behind it for it to be useful, whereas anyone can make a FIFO
  • communication through serial ports is bi-directional; it can be full-duplex, but half-duplex modes are available as well.
  • FIFOs are unidirectional, but you can use them in pairs if necessary. In principle, one process could both write to and read from a FIFO, but it would need to be very careful if it wanted to avoid consuming its own messages and to avoid deadlocking.

Bottom line: for bidirectional IPC within one machine, FIFOs are far superior to serial ports. You should also consider a socket interface.

Answer from John Bollinger on Stack Overflow
🌐
Serialport
serialport.io › 📦 serialport
📦 serialport | Node SerialPort
November 8, 2024 - const { SerialPort, ReadlineParser } = require('serialport') const port = new SerialPort({ path, baudRate }) const parser = new ReadlineParser() port.pipe(parser) parser.on('data', console.log) port.write('ROBOT PLEASE RESPOND\n') // ROBOT ONLINE // Creating the parser and piping can be shortened to const parser = port.pipe(new ReadlineParser()) SerialPort ·
🌐
GitHub
github.com › weltling › convey
GitHub - weltling/convey: Communication through a serial port or named pipe · GitHub
Using convey, it is possible to connect to a virtual machine's virtual serial port from the host system using the exposed named pipe.
Starred by 56 users
Forked by 11 users
Languages   C++ 98.8% | Makefile 1.2%
🌐
GitHub
github.com › JanneMattila › serialport2namedpipe
GitHub - JanneMattila/serialport2namedpipe: Serial port (e.g., COM3) to named pipe (e.g., \\.\pipe\com2) connector · GitHub
sequenceDiagram autonumber Zigbee dongle->>+Windows: USB Serial device (COM3) Windows->>+SerialPort2NamedPipeConnector: Read from serial port Note left of Hyper-V: Set-VMFirmware –Vmname "home assistant"<br/>–EnableSecureBoot Off Note left of Hyper-V: Set-VMComPort -VMName "home assistant"<br/>-Number 2 -Path \\.\pipe\com2 SerialPort2NamedPipeConnector->>+Hyper-V: Write to named pipe<br/>\\.\pipe\com2 Hyper-V->>+Home Assistant OS: /dev/ttyS0 Home Assistant OS->>+Zigbee Home Automation: Read from serial port Note right of Zigbee Home Automation: Home Assistant<br/>Integration Zigbee Home Automation->>+Home Assistant OS: Write to serial port Home Assistant OS->>+Hyper-V: /dev/ttyS0 Hyper-V->>+SerialPort2NamedPipeConnector: Read from named pipe<br/>\\.\pipe\com2 SerialPort2NamedPipeConnector->>+Windows: Write to serial port Windows->>+Zigbee dongle: USB Serial device (COM3)
Author   JanneMattila
Top answer
1 of 2
7

Why doesn't the below work?

# in one terminal:
echo "asdf" > /dev/ttyUSB0

# in another terminal, this hangs and does nothing
cat < /dev/ttyS0

Because, as a rule, serial ports don't buffer data. If there's no client app to receive the bytes landing on the serial port, they will simply be discarded.

As an experiment, try launching minicom or cu or another serial terminal program on the receiving computer, then run the echo command again on the transmitting computer. Assuming the baud rate and framings line up, you should see "asdf" appear at the destination.

2 of 2
3

I want to be able to simply send bytes into one end and come out the other end, and vice versa. Why doesn't the below work?

I think it's because you simply need to switch the order: start the listener first and then send the data (just like you did in your own pipe example--you started listening first):

# Absolutely first, configure each port using `stty`, as you already
# do:

# set both serial ports to 9600 8n1
# `-parenb` means no parity,
# `-cstopb` means 1 stop bit
# cs8 means 8 bits at a time 
stty -F /dev/ttyUSB0 cs8 -cstopb -parenb 9600
stty -F /dev/ttyS0 cs8 -cstopb -parenb 9600

# THEN, do in this order

# first, in the receiving terminal, start listening
cat < /dev/ttyS0

# then, in a separate terminal for sending, send the data
echo "asdf" > /dev/ttyUSB0

I am pretty confident my answer is procedurally correct, meaning: if you blindly follow it, it will work.

But, the question still remains: why? Why do you have to start listening first? Doesn't the Linux kernel buffer for you? If so, shouldn't the data just be sitting there in the buffer ready to be read? Clearly it isn't, else writing first and reading second would work. But, it doesn't.

I'm guessing here, but I think the answer here is that when the driver receives data, it first checks to see if the receiving pseudo-file at /dev/ttyUSB0 is in an opened state, held open by another process. If not, the driver discards the data, since no one is there to receive it. If the file is open, it allows the process which has the file open to read the buffered data.

Key differences between sending over a serial port and sending over an inter-process-communication (IPC) pipe

This is different from your pipe example where you make a pipe with mkfifo. I just checked, and in the pipe example, you can either start listening in one terminal first or send to the pipe in the other terminal first. It doesn't matter. It works in both cases.

If you write first, the write blocks and waits until a process reads from the pipe. If you read first, the read blocks and waits until a process writes to the pipe. This is confirmed by the Linux documentation for C's mkfifo() function, which the bash mkfifo is almost certainly based on. See man 3 mkfifo (emphasis added):

Once you have created a FIFO special file in this way, any process can open it for reading or writing, in the same way as an ordinary file. However, it has to be open at both ends simultaneously before you can proceed to do any input or output operations on it. Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa.

This is different from how serial ports behave, however, probably because the serial ports on each end are expected to be controlled from different machines, unlike FIFO pipes, whose read and write ends are expected to be controlled from the same machine. In the latter case, the kernel can easily track when one process tries to read and another tries to write, since it controls both ends of the pipe...hence, it allows either to block.

In the serial port case, however, the kernel has no idea if another device is listening or going to send, so it won't block on sending. To be clear: when writing to a pipe, the write is blocked until a listener is present. But, when writing to a serial port, the computer has no means of checking if a listener is present, so it never blocks! It just sends. Instead of blocking if no listener is present, data sent over serial while no-one is listening is just lost. Again, this is different from pipes, where my experiment and the documentation above both confirm that a process trying to send data over a pipe is blocked until a listener is present to read that data.

References and "see also":

  1. I'm actively learning as I write this, documenting various findings in my eRCaGuy_dotfiles repo here, in case you're interested: serial_terminals_README.md.
  2. My demo code: eRCaGuy_hello_world/bash/ipc_pipe_fifo.sh
  3. man 3 mkfifo: https://man7.org/linux/man-pages/man3/mkfifo.3.html
🌐
Stack Overflow
stackoverflow.com › questions › 50889873 › connecting-c-sharp-serialport-to-hyper-v-named-pipe-just-like-putty-can
linux - Connecting C# SerialPort to Hyper-V named pipe (Just Like PuTTy can) - Stack Overflow
I am working on an Application to Connect to virtual machines(using Hyper-V). (I am using Virtual Machines now for Development, but the end-product will be physical Serial Connected Machines. not VM's) I have created a named pipe with the COM adaptor like this. I am able to connect with PuTTy Like so. Running a CentOS Build on the Hyper-V · I then wrote a simple Application to connect to it with C# my_Serial_Port = new SerialPort(); my_Serial_Port.PortName = @"\\.\pipe\ttyS0"; my_Serial_Port.BaudRate = m_BaudRate; my_Serial_Port.DataBits = 8; my_Serial_Port.Parity = Parity.None; my_Serial_Por
🌐
GitHub
github.com › tdhoward › COMpipe
GitHub - tdhoward/COMpipe: Links a serial COM port to a named pipe · GitHub
Usage: COMpipe [-b <baud rate>] [-d <data bits>] [-r <parity>] [-s <stop bits>] [-f] -c <COM port name> -p <pipe name> Examples: COMpipe -c \\.\COM8 -p \\.\pipe\MyLittlePipe COMpipe -b 19200 -c \\.\COM8 -p \\.\pipe\MyLittlePipe Notes: 1. COMpipe does not create a named pipe, it only uses an existing named pipe.
Starred by 78 users
Forked by 17 users
Languages   C++
🌐
Hhdsoftwaredocs
hhdsoftwaredocs.online › vspt › configuration-utility › creating-pipe-ports.html
Create Pipe-connected Serial Ports/VSPT Online Documentation
Pipe port is connected to a given named pipe, for which it is either a creator, or a client. First, specify the name of the pipe. Valid pipe names must conform to the following pattern: \\servername\pipe\pipename, where servername is either the name of the remote server or “.” for local server.
Find elsewhere
🌐
GitHub
github.com › serialport › node-serialport › issues › 2258
Correct way to "detach" a piped parser after use? · Issue #2258 · serialport/node-serialport
June 2, 2021 - const port = new SerialPort(path) const parser = new Regex({ regex: /SpecialDelimiterHandlingHere/ }) port.pipe(parser) parser.once('data', (buffer: Buffer) => { // Do stuff port.unpipe(parser); }) port.write('Special command') port.once('data', (buffer: Buffer) => { // Something }) port.write('Non-special command') I can see that "Non-special command" is having an effect on the device side, but the data event never fires.
Author   serialport
🌐
Iobuster
framework-api.iobuster.com › serialport.html
serialport - Documentation - ioBuster
logger.create('serial', 'serial.log') serialport.pipe(index, 'serial') Send a message to a serial port. Send a file to a serial port. The number of transferred bytes · Type · number · Send a message with a newline character to a serial port. Stop sending read data to a file.
🌐
Tabnine
tabnine.com › home page › code › javascript › serialport
serialport.SerialPort.pipe JavaScript and Node.js code examples | Tabnine
this._serialPort.pipe(this._parser); SerialPort.on · SerialPort.list · SerialPort.write · SerialPort.close · SerialPort.parsers ·
🌐
Serialport
serialport.io › serialport usage
SerialPort Usage | Node SerialPort
November 8, 2024 - // Read data that is available but keep the stream in "paused mode" port.on('readable', function () { console.log('Data:', port.read()) }) // Switches the port into "flowing mode" port.on('data', function (data) { console.log('Data:', data) }) // Pipe the data into another stream (like a parser or standard out) const lineStream = port.pipe(new Readline())
🌐
MIT
stuff.mit.edu › afs › sipb › project › vmdialup › lib › vmware-console › help › server › devices_serial.htm
Configuring a Serial Port
Use named pipe — Select this setting to set up a direct connection between two virtual machines or a connection between a virtual machine and an application on the host computer.
🌐
Serialport
serialport.io › what are parsers?
What are Parsers? | Node SerialPort
November 8, 2024 - const { SerialPort } = require('serialport') const { ReadlineParser } = require('@serialport/parser-readline') const port = new SerialPort({ path: '/dev/ROBOT', baudRate: 14400 }) const parser = new ReadlineParser() port.pipe(parser) parser.on('data', console.log) port.write('ROBOT PLEASE RESPOND\n')
🌐
GitHub
github.com › albertjan › PipeToCom
GitHub - albertjan/PipeToCom: Couple your Hyper-V namedpipe comport to a real one.
January 22, 2019 - NP2COMS is a windows service that reads n config files like above and creates as many named-pipe serialport connections as you want.
Starred by 56 users
Forked by 21 users
Languages   C# 100.0% | C# 100.0%