Using FujiNet‐PC‐RS232 with 86Box in Linux - FujiNetWIFI/fujinet-firmware GitHub Wiki

If you want to use or develop FujiNet applications for MS-DOS, and you don't have a FujiNet (yet), you can connect a copy of FujiNet-PC to an emulator, such as QEMU or 86Box via a pseudo-TTY (pty) in Linux. This should be adaptable to MacOS as well, using the appropriate device names. (can someone add them?)

Basic Assumptions

  • The emulator used here is 86Box.
  • 86Box is set up to use a specific .cfg file, instead of using the configuration menu.
  • /bin/bash is installed and available as a shell.

Editor's Note(If you're using Windows, We'd love adapting this example to use a virtual COM port such as com0com! Please add a page!)

How it's connected

flowchart LR 
   A["FUJINET-RS232"] <--> B["/dev/pts/3"]
   B <--> C["86Box"]

To connect Fujinet-pc-rs232 to 86Box, a pseudo-tty (pty) is used. This is a type of virtual device that has some characteristics of a serial connection, as well as some characteristics of a TTY connection. When configured, 86Box will ask Linux to create the pty that fujinet-pc-rs232 can subsequently use.

What is needed

  • 86Box
  • A copy of the 86Box ROMs. (Where to get these is an exercise for the reader, there are many places.)
  • An 86Box configuration file and folder containing your desired system configuration (an example is documented below)
  • FujiNet-PC-RS232; grab a nightly build.
  • The Launcher Script (documented below)

Example 86Box.cfg file

This file should be placed in a folder containing any of its dependencies, such as disk images. This example shows an IBM 5150 PC, with one serial port, and its passthrough attached to a virtual console. The passthrough was configured in this manner:

Field Value
Passthrough Mode Pseudo Terminal/Virtual Console
Host Serial Device None
Data Bits 8
Stop Bits 1
Baud Rate of Passthrough 9600

On my system, this file is placed in "/home/thomc/Vintage/IBM 5150 PC/86box.cfg"

[General]
enable_overscan = 1
host_cpu = AMD Ryzen Threadripper 9960X 24-Cores
uuid = ab2666c6-d62a-5c37-a9b6-94fb30429c32
vid_renderer = qt_vulkan
vid_resize = 1
video_filter_method = 0
video_fullscreen_scale = 4

[Machine]
cpu_family = 8088
cpu_multi = 1
cpu_speed = 4772728
cpu_use_dynarec = 0
machine = ibmpc82
mem_size = 256

[Video]
gfxcard = cga
video_fullscreen_scale_maximized = 1

[Input devices]
keyboard_type = keyboard_pc_xt
mouse_type = none

[Network]
net_01_link = 0
net_02_link = 0
net_03_link = 0
net_04_link = 0

[Storage controllers]
cassette_enabled = 1
fdc = fdc_xt

[Floppy and CD-ROM drives]
fdd_01_fn = Disks/fn-dos21.img
fdd_01_image_history_01 = /home/thomc/Vintage/IBM 5160 PCXT/Disks/IBM PC-DOS 2.10 (5.25)/Disk01.img
fdd_01_image_history_02 = /home/thomc/Vintage/IBM 5160 PCXT/fn-dos21.img
fdd_01_image_history_03 = Disks/Congo Bongo (1984)(Sega)/Congo Bongo (1984)(Sega).img
fdd_01_image_history_04 = Disks/Alley Cat (1984)(IBM - SynSoft)/Alley Cat (1984)(IBM - SynSoft).img
fdd_02_image_history_01 = Disks/fn-dos21.img

[Serial Passthrough Device #1]
mode = 0
data_bits = 8
stop_bits = 1
baudrate = 9600

[Ports (COM & LPT)]
serial1_passthrough_enabled = 1
serial2_enabled = 0

[IBM CGA]
display_type = 0
composite_type = 0
rgb_type = 5
double_type = 2
font = 0
snow_enabled = 1

The Launcher Script

The Launcher script does the following:

  • Launches 86Box
  • Waits for 86Box to emit the /dev/pts/X of the serial port, and captures it.
  • Adapts the fnconfig.ini file in fujinet-pc-rs232 to reflect the serial port
  • Runs fujinet-pc-rs232.

Important Environment Variables

ENV Var Description
CONFIG_DIR The location of your fujinet-pc-rs232's fnconfig.ini file
VM_DIR The location of the directory containing your 86box.cfg file
FUJINET_URL Set to the port number that you wish to access the FujiNet UI e.g. 8000

Place this file in your path, e.g. /usr/local/bin/IBM_5150.sh

#!/bin/bash

## this is /usr/local/bin/IBM_5150.sh

CONFIG_DIR="/home/thomc/Workspace/fujinet-pc-rs232/build/dist"
VM_DIR="/home/thomc/Vintage/IBM 5150 PC"
CONFIG_FILE="$CONFIG_DIR/fnconfig.ini"
VM_CONFIG_FILE="$VM_DIR/86Box.cfg"
FUJINET_BIN="$CONFIG_DIR/fujinet"
FUJINET_URL="0.0.0.0:8005"

LOGFILE=$(mktemp)

cleanup() {
    # Kill FujiNet if still running
    if [ -n "$PID_FN" ](/FujiNetWIFI/fujinet-firmware/wiki/--n-"$PID_FN"-) && kill -0 "$PID_FN" 2>/dev/null; then
        echo "Shutting down FujiNet RS-232 (PID $PID_FN)..."
        kill "$PID_FN"
    fi
    # Optionally: kill 86Box (if not already)
    if [ -n "$PID_86" ](/FujiNetWIFI/fujinet-firmware/wiki/--n-"$PID_86"-) && kill -0 "$PID_86" 2>/dev/null; then
        echo "Shutting down 86Box (PID $PID_86)..."
        kill "$PID_86"
    fi
}

# Ensure cleanup on script exit / interrupt
trap cleanup EXIT

echo "Starting 86Box..."

# Launch 86Box in background, logging output
cd "$VM_DIR"
86Box "$VM_CONFIG_FILE" 2>&1 | tee "$LOGFILE" &
PID_86=$!

# Wait for serial_passthrough message
PTS_DEVICE=""
echo -n "Waiting for 86Box to report PTY device..."

for i in {1..200}; do   # ~20 seconds max
    if grep -q "serial_passthrough: Slave side is /dev/pts/" "$LOGFILE"; then
        PTS_DEVICE=$(grep "serial_passthrough: Slave side is" "$LOGFILE" \
            | tail -n1 | awk '{print $NF}')
        echo " found: $PTS_DEVICE"
        break
    fi
    echo -n "."
    sleep 0.1
done

if [ -z "$PTS_DEVICE" ](/FujiNetWIFI/fujinet-firmware/wiki/--z-"$PTS_DEVICE"-); then
    echo
    echo "ERROR: Could not detect /dev/pts assignment from 86Box."
    exit 1
fi

# Update fnconfig.ini
sed -i "s|^port=.*|port=$PTS_DEVICE|" "$CONFIG_FILE"
echo "Updated $CONFIG_FILE → port=$PTS_DEVICE"

# Wait until PTY appears
echo -n "Waiting for $PTS_DEVICE to appear..."
for i in {1..50}; do
    if [ -e "$PTS_DEVICE" ](/FujiNetWIFI/fujinet-firmware/wiki/--e-"$PTS_DEVICE"-); then
        echo " OK"
        break
    fi
    echo -n "."
    sleep 0.1
done

if [ ! -e "$PTS_DEVICE" ](/FujiNetWIFI/fujinet-firmware/wiki/-!--e-"$PTS_DEVICE"-); then
    echo
    echo "ERROR: $PTS_DEVICE never appeared."
    exit 1
fi

# Start FujiNet RS-232
echo "Starting FujiNet RS-232..."
cd $CONFIG_DIR
"$FUJINET_BIN" -u $FUJINET_URL &
PID_FN=$!

echo "FujiNet RS-232 running with PID $PID_FN"
echo "86Box running with PID $PID_86"
echo "Logfile: $LOGFILE"

# Wait for 86Box to exit; once it does, cleanup() will run via trap.
wait "$PID_86"

# Script will now exit → trap cleanup will kill FujiNet (if running)

A xdg-desktop file

In addition, I have a Desktop file, so that I can launch the emulator directly from my Rofi launcher as "~/.local/share/applications/IBM 5150.desktop":

[Desktop Entry]
Name=IBM 5150 PC
Exec="IBM 5150.sh"
Comment=IBM 5150 PC with FujiNet-PC
Terminal=false
Icon=/home/thomc/Pictures/ibm-5150.png
Type=Application
Path=/home/thomc/Vintage/IBM 5150 PC

The Icon I use is attached here:

Inside the Guest PC

The Guest PC (running inside 86Box) will need a copy of the FUJINET.SYS driver. Here is a PC-DOS 2.10 Boot Disk with FUJINET.SYS

The CONFIG.SYS has a single line to load FUJINET.SYS:

DEVICE=FUJINET.SYS FUJI_PORT=1 FUJI_BPS=9600
Option Description
FUJI_PORT COM Port number (1-4)
FUJI_BPS Baud rate (300-115200)

If everything is set up as expected, the driver should present a banner with your serial port information, and show the time and date as acquired by the FujiNet:

Manipulating Disks

Once the guest PC is started, you can use your web browser to access the web UI to mount disk images. Currently any raw disk image is supported, sector size is assumed to be 512 bytes. Be sure to press the MOUNT ALL button after mounting a disk image.

Using the Settings Menu

If you use the settings menu, you must re-start the emulator immediately after exiting, as 86Box will attempt to completely reset the machine, which will close the existing pty, and attempt to open a new one, that doesn't match with what the launcher script extracted.

Using a different emulator?

If you can, adapt these to your favorite emulator, and write a page, please.