Last active
March 12, 2025 13:18
-
-
Save valgur/0970e3ddaf148fbc7f8d8832b2d61659 to your computer and use it in GitHub Desktop.
Create a virtual TTY device to log traffic on a physical serial port
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Default device path | |
DEFAULT_DEVICE="/dev/ttyUSB0" | |
DEFAULT_VIRT_DEVICE="/tmp/virtual_tty" | |
# Function to display usage information | |
usage() { | |
echo "Usage: $0 [OPTIONS]" | |
echo "Creates a virtual TTY connected to a real serial device with bidirectional logging." | |
echo "" | |
echo "Options:" | |
echo " -d, --device PATH Serial device to connect to (default: $DEFAULT_DEVICE)" | |
echo " -v, --virtdev PATH Virtual TTY device path (default: $DEFAULT_VIRT_DEVICE)" | |
echo " -b, --baud RATE Baud rate (default: auto-detect from device)" | |
echo " -l, --logdir DIR Directory to store logs (default: /tmp/tty_logs)" | |
echo " -h, --help Display this help and exit" | |
echo "" | |
echo "Example: $0 --device /dev/ttyACM0 --baud 115200" | |
exit 1 | |
} | |
# Parse command line arguments | |
DEVICE=$DEFAULT_DEVICE | |
VIRT_DEVICE=$DEFAULT_VIRT_DEVICE | |
BAUD_RATE=115200 | |
LOG_DIR="/tmp/tty_logs" | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-d|--device) | |
DEVICE="$2" | |
shift 2 | |
;; | |
-v|--virtdev) | |
VIRT_DEVICE="$2" | |
shift 2 | |
;; | |
-b|--baud) | |
BAUD_RATE="$2" | |
shift 2 | |
;; | |
-l|--logdir) | |
LOG_DIR="$2" | |
shift 2 | |
;; | |
-h|--help) | |
usage | |
;; | |
*) | |
echo "Unknown option: $1" | |
usage | |
;; | |
esac | |
done | |
# Check if device exists | |
if [ ! -c "$DEVICE" ]; then | |
echo "Error: $DEVICE does not exist or is not a character device" | |
exit 1 | |
fi | |
# Create log directory | |
mkdir -p "$LOG_DIR" | |
timestamp=$(date +"%Y%m%d_%H%M%S") | |
# Auto-detect baud rate if not specified | |
if [ -z "$BAUD_RATE" ]; then | |
BAUD_RATE=$(stty -F "$DEVICE" speed) | |
echo "Detected baud rate: $BAUD_RATE" | |
else | |
echo "Using specified baud rate: $BAUD_RATE" | |
fi | |
echo "Taking ownership of $DEVICE..." | |
sudo chown $USER $DEVICE | |
# Create FIFOs for logging | |
TX_FIFO="/tmp/tx_fifo_$$" | |
RX_FIFO="/tmp/rx_fifo_$$" | |
mkfifo $TX_FIFO | |
mkfifo $RX_FIFO | |
# Function to clean up on exit | |
cleanup() { | |
echo -e "\nCleaning up and exiting..." | |
# Kill background processes | |
[[ -n $SOCAT_PID ]] && kill $SOCAT_PID 2>/dev/null | |
[[ -n $TX_LOGGER_PID ]] && kill $TX_LOGGER_PID 2>/dev/null | |
[[ -n $RX_LOGGER_PID ]] && kill $RX_LOGGER_PID 2>/dev/null | |
# Remove temporary files | |
rm -f $TX_FIFO $RX_FIFO | |
echo "Logs saved to:" | |
echo "TX log: $LOG_DIR/${timestamp}_tx.log" | |
echo "RX log: $LOG_DIR/${timestamp}_rx.log" | |
exit 0 | |
} | |
# Set up trap for Ctrl+C and other signals | |
trap cleanup SIGINT SIGTERM EXIT | |
# Start TX and RX loggers | |
echo "Setting up bidirectional TTY with logging..." | |
# Use a simpler socat approach - one instance for the virtual TTY | |
socat -d PTY,raw,echo=0,link=$VIRT_DEVICE,mode=777 \ | |
OPEN:$DEVICE,raw,echo=0,crnl,b$BAUD_RATE & | |
SOCAT_PID=$! | |
# Wait for the virtual device to be ready | |
sleep 1 | |
# Check if socat started successfully | |
if ! ps -p $SOCAT_PID > /dev/null; then | |
echo "Error: Failed to create virtual TTY. Check permissions and device availability." | |
cleanup | |
exit 1 | |
fi | |
# Set up TX logging (data to device) | |
socat -u OPEN:$VIRT_DEVICE,rdonly OPEN:$TX_FIFO,creat,append & | |
TX_SOCAT_PID=$! | |
# Set up RX logging (data from device) | |
socat -u OPEN:$DEVICE,rdonly OPEN:$RX_FIFO,creat,append & | |
RX_SOCAT_PID=$! | |
# Start log file writers | |
cat $TX_FIFO > "$LOG_DIR/${timestamp}_tx.log" & | |
cat $RX_FIFO > "$LOG_DIR/${timestamp}_rx.log" & | |
echo -e "\nSetup complete!" | |
echo "Virtual TTY: $VIRT_DEVICE → $DEVICE" | |
echo "Baud rate: $BAUD_RATE" | |
echo "TX log (to device): $LOG_DIR/${timestamp}_tx.log" | |
echo "RX log (from device): $LOG_DIR/${timestamp}_rx.log" | |
echo -e "\nWaiting for communication (press Ctrl+C to exit)...\n" | |
# Keep script running until Ctrl+C | |
while true; do | |
sleep 1 | |
# Check if socat is still running | |
if ! ps -p $SOCAT_PID > /dev/null; then | |
echo "Error: socat process terminated unexpectedly" | |
exit 1 | |
fi | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment