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.