Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using pipes in bash to buffer data from a serial device

I have a script that looks something like:

while true; do
    read -t10 -d$'\n' input_from_serial_device </dev/ttyS0
    # do some costly processing on the string
done

The problem is that it will miss the next input from the serial device because it is burning CPU cycles doing the costly string processing.

I thought I could fix this by using a pipe, on the principle that bash will buffer the input between the two processes:

( while true; do
     read -d$'\n' input_from_serial_device </dev/ttyS0
     echo $input_from_serial_device
  done ) | ( while true; do
     read -t10 input_from_first_process
     # costly string processing
  done )

I firstly want to check that I've understood the pipes correctly and that this will indeed buffer the input between the two processes as I intended. Is this idea correct?

Secondly, if I get the input I'm looking for in the second process, is there a way to immediately kill both processes, rather than exiting from the second and waiting for the next input before exiting the first?

Finally, I realise bash isn't the best way to do this and I'm currently working on a C program, but I'd quite like to get this working as an intermediate solution.

Thank you!

like image 385
Froskoy Avatar asked Jul 08 '26 01:07

Froskoy


1 Answers

The problem isn't the pipe. It's the serial device.

When you write

while true; do
  read -t10 -d$'\n' input_from_serial_device </dev/ttyS0
  # use a lot of time
done

the consequence is that the serial device is opened, a line is read from it, and it is then closed. Then it is not opened again until # use a lot of time is done. While a serial device is not open, incoming serial input is thrown away.

If the input is truly coming in faster than it can be processed, then buffering isn't enough. You'll have to throw input away. If, on the other hand, it's dribbling in at an average speed which allows for processing, then you should be able to achieve what you want by keeping the serial device open:

while true; do
  read -t10 -r input_from_serial_device
  # process input_from_serial_device
done < /dev/ttyS0

Note: I added -r -- almost certainly necessary -- to your read call, and removed -d$'\n', because that is the default.

like image 58
rici Avatar answered Jul 10 '26 14:07

rici



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!