# Remote IMSAI FIF Disk Server — User Guide
Complete reference for fdcServer.
# Table of Contents
- Installation
- Running the Server
- Disk Map Configuration
- Drive Modes
- Drive Management
- Display & Visualization
- Disk Image Utilities
- Supported Disk Formats
- Architecture Overview
- Troubleshooting
# Installation
# Upgrading from fifDirSrv
If you previously installed fifDirSrv, uninstall it first to avoid conflicts:
pip uninstall fifDirSrv
# From a wheel (recommended)
If you received a .whl file, install it with pip. Place the wheel in a directory (e.g., dist/) and use --find-links to point pip at it:
pip install fdcServer --find-links path/to/wheel # Core (includes web UI)
pip install "fdcServer[all]" --find-links path/to/wheel # Everything (+ directory watching)
You can also install the wheel file directly by path, but extras cannot be specified this way:
pip install path/to/fdcServer-X.Y.Z-py3-none-any.whl # Core only (no extras syntax)
All dependencies are installed automatically. To upgrade to a newer version, use --upgrade. To do a clean reinstall (e.g., if something seems broken), use --force-reinstall:
pip install --upgrade "fdcServer[all]" --find-links path/to/wheel # Upgrade
pip install --force-reinstall "fdcServer[all]" --find-links path/to/wheel # Fresh reinstall
# From source
Clone the repository and install with pip:
pip install .
This installs all core dependencies automatically (including web UI and windows-curses on Windows).
To include optional features:
pip install ".[watch]" # Auto-detect external file changes in DIR mode
pip install ".[all]" # Everything
After installation, three commands are available: fdcServer, fdc-pack, and fdc-unpack.
# Manual dependency install
If you prefer to run directly from the source tree without installing:
pip install -r requirements.txt
python fdcServer.py
The requirements.txt covers core dependencies only. For optional features, install manually:
pip install watchfiles # Directory watching
# Notes
- On macOS and Linux, curses is included in the Python standard library. On Windows, the
windows-cursespackage is installed automatically. - When
watchfilesis installed, DIR-mode floppy drives automatically detect external filesystem changes and rebuild their in-memory directory. Without it, the server still works normally but won't detect changes made outside the server. - The terminal must be at least 80 columns x 24 rows for the curses UI.
# Running the Server
The entry point is the fdcServer command (or python fdcServer.py when running from source). One transport backend (serial or socket) runs at a time.
# Transport Auto-Detection (Default)
When neither --serial nor --socket is specified, the server automatically scans for an FDC USB device (VID 0xCAFE, bus description SDH-100 FDC). If found, it connects via serial at 2 Mbaud. If no device is found, it falls back to TCP socket transport on port 13740.
# Auto-detect FDC USB device; fall back to socket
fdcServer
The auto-detect result is printed to stderr:
Auto-detected FDC on COM3— serial device foundNo FDC serial device found, listening to socket on port 13740— using socket
# Serial Transport
# Specify port (skip auto-detection)
fdcServer --serial COM3
# Specify port and baud rate
fdcServer --serial COM3 --baud 115200
The serial transport runs in a background thread and automatically reconnects if the connection drops.
# TCP Socket Transport
# Default port: 13740
fdcServer --socket
# Specify port
fdcServer --socket 9000
The socket transport accepts a single client connection at a time. The --baud option cannot be used with --socket.
# Disk Timing Simulation
# Enable timing simulation with socket transport
fdcServer --socket --timing
The --timing flag enables realistic disk access timing on the server side. When enabled, the server delays each response to simulate the mechanical behavior of the original disk hardware:
- Seek time — Head stepping delay proportional to the number of tracks traversed
- Rotational latency — Waiting for the target sector to rotate under the head
- Sector transfer time — Time for one sector to pass under the head
Each drive maintains its own independent head position, so sequential accesses to nearby tracks are faster than random seeks across the disk.
Timing parameters are per-geometry:
| Parameter | DSK (floppy) | HDD (hard disk) |
|---|---|---|
| RPM | 360 | 3000 |
| Track step time | 8 ms | 1 ms |
| Worst-case access | ~781 ms | ~274 ms |
Timing is disabled by default. When using the web UI, timing can also be toggled at runtime via the Timing LED toggle in the toolbar — no server restart required. Toggling takes effect immediately on the next disk command.
# Web Interface (Default)
The web UI launches by default at http://localhost:8000. It provides drive management (insert/eject, mount/unmount, save, reload), real-time disk access visualization, a trace log viewer with log level control, a dark/light theme toggle, and a Timing LED toggle. See Drive Management — Web UI for details on the drive panel controls.
# Web UI on a specific port with socket transport
fdcServer --web 9000 --socket
Use --web PORT to override the default web UI port.
# Terminal Interface
# Terminal (curses) UI with serial transport
fdcServer --text
# Terminal UI with socket transport
fdcServer --text --socket
The --text flag selects the curses terminal UI instead of the web UI (which runs by default). --text and --web cannot be combined.
# Command-Line Reference
| Argument | Default | Description |
|---|---|---|
--serial [PORT] | COM5 | Use serial transport on the specified port (skip auto-detection) |
--socket [PORT] | 13740 | Use TCP socket transport on the specified port (skip auto-detection) |
--baud RATE | 2000000 | Baud rate (serial only; requires --serial) |
--text | off | Use terminal (curses) UI instead of web UI |
--web [PORT] | 8000 | Override web UI port |
--timing | off | Enable disk timing simulation (seek, rotational latency, sector transfer) |
--serial and --socket are mutually exclusive. If neither is specified, the server auto-detects the FDC USB device and falls back to socket transport if not found. --text and --web are mutually exclusive. If neither is specified, the web UI launches on port 8000.
# Logging
All debug output is written to trace.log (overwritten on each start). The terminal display is reserved for the curses UI.
# Disk Map Configuration
Drive assignments are stored in diskmap.json in the working directory. This is a simple JSON object mapping drive letters to file or directory paths:
{
"A": "cpm22d01.dsk",
"B": "cpm22d01.unpacked",
"C": "work.dsk",
"I": "harddisk.hdd"
}
- Keys are drive letters:
A,B,C,D, orI - Values are paths to
.dskfiles,.hddfiles, or directories (unpacked format) - Drives not listed in the map default to
LOCALmode (passed through to the IMSAI's own disk handling)
The disk map is loaded on startup. You can reload it at any time (Ctrl+R in the terminal UI, or the Reload button in the web UI) and save the current state (Ctrl+P or the Save button).
If no diskmap.json file is found, the server starts with all drives in LOCAL mode and displays a warning.
# Drive Modes
Each drive operates in one of three modes:
| Mode | Display | Description |
|---|---|---|
| IMG | DSK:A: = IMG:cpm22d01.dsk | Raw disk image file. Reads and writes go directly to the binary image. |
| DIR | DSK:B: = DIR:cpm22d01.unpacked | Host directory. The server synthesizes a CP/M disk in memory and mirrors file operations (create, delete, write) to the host filesystem in real time. If watchfiles is installed, floppy drives (A–D) also detect external changes to the host directory and rebuild automatically. |
| LOCAL | DSK:C: = LOCAL: | Not mounted by the server. The IMSAI handles this drive using its own local storage. |
The mode is determined automatically:
- A path pointing to a regular file (
.dskor.hdd) uses IMG mode - A path pointing to a directory uses DIR mode
- Drives with no entry in the disk map use LOCAL mode
# Filename Shortening (DIR Mode)
CP/M filenames are limited to 8 characters for the name and 3 for the extension (the "8.3" format). When a host directory is mounted in DIR mode — or packed into a disk image with fdc-pack — any filenames that don't fit this format are automatically shortened and renamed on the host filesystem.
The shortening rules are:
- Case — The filename is converted to uppercase.
- Invalid characters — Characters not allowed in CP/M filenames (
< > . , ; : = ? * [ ] % | ( ) / \ _) are removed. - Truncation — Names longer than 8 characters are truncated to 6 characters followed by
~1(e.g.,VERYLONGNAME.TXTbecomesVERYLO~1.TXT). Extensions longer than 3 characters are truncated to 3. - Collision handling — If the shortened name already exists in the same user area, the trailing digit is incremented in hexadecimal:
~2,~3, ... up to~F(15 variants). If all 15 slots are exhausted, the file is skipped with an error.
Important: The rename is permanent — the original long filename on the host filesystem is replaced with the shortened version. A warning is logged for each rename (e.g., RENAMED FILE: VeryLongName.txt to VERYLO~1.TXT). If you need to preserve the original filenames, make a copy of the directory before mounting it.
# Drive Management
Both UIs support the same core drive operations. The web UI uses buttons and dropdowns; the terminal UI uses keyboard commands.
# Web UI
In the web UI (the default), each drive panel includes a context-sensitive control area that adapts to the drive's current state. All controls update in real time via server-sent events (SSE) — no page refresh is needed.
# Insert/Eject and Mount/Unmount
Each drive panel shows a single button that changes based on drive state:
- Floppy drives (A–D) use Insert / Eject labels
- Hard disk drive (I) uses Mount / Unmount labels
When a drive is unmounted, clicking the Insert/Mount button reveals a file selector inline. Select a file or directory to mount it automatically. Press Escape or click away to cancel and return to the button. When a drive is mounted, the Eject/Unmount button (styled with a red border) shows a browser confirmation dialog before unmounting.
After any mount or unmount operation, all drive panels update immediately: the button switches state, the drive label reflects the new assignment, and the file selectors on other drives are refreshed.
# File Selector
The file selector appears inline when you click Insert/Mount. It lists all .dsk and .hdd files plus all non-hidden subdirectories in the working directory, sorted alphabetically. Selecting a file immediately mounts it — no separate confirm button needed. Disks already mounted on other drives are filtered out automatically.
The file list is cached for 5 seconds. Mounting or unmounting any drive invalidates the cache immediately, ensuring selectors on all drive panels stay current.
# Duplicate Mount Prevention
Mounting the same path on two drives simultaneously is not allowed. If a path is already mounted on another drive, the mount is rejected and a status message appears: *** <path> already mounted on drive <X> ***. The file selector normally prevents this by hiding mounted paths, but the check also guards against race conditions.
# Save and Reload
The web UI toolbar includes Save and Reload buttons that are equivalent to Ctrl+P and Ctrl+R in the terminal UI. Save persists the current drive assignments to diskmap.json; Reload re-reads diskmap.json and remounts all drives.
# Terminal UI
All drive interaction in the terminal UI uses a two-step keyboard pattern: first select a drive, then issue a command.
# Drive Selection
Press a drive letter key to select it for the next command:
| Key | Drive | Geometry |
|---|---|---|
A | Drive A (unit 1) | Standard 8" floppy (DSK) |
B | Drive B (unit 2) | Standard 8" floppy (DSK) |
C | Drive C (unit 4) | Standard 8" floppy (DSK) |
D | Drive D (unit 8) | Standard 8" floppy (DSK) |
I | Drive I (unit 15) | Hard disk (HDD) |
The selected drive is shown in the status bar at the bottom of the screen: DRIVE: DSK:A:
Drive selection is consumed by the next command — after any command key is processed, the selection resets. Drive letters are case-sensitive (uppercase only).
# Drive Commands
These require a drive to be selected first (press a drive letter, then the command):
| Key | Action |
|---|---|
Ctrl+L | Load — Opens a text input prompt where you type a file path or directory path to mount on the selected drive. Press Enter to confirm or Ctrl+G to submit. |
Ctrl+U | Unload — Unmounts the selected drive, reverting it to LOCAL mode. Requires a drive to be selected first, and only works if the drive currently has something loaded. |
# Save and Reload
| Key | Action |
|---|---|
Ctrl+P | Persist — Save the current disk map to diskmap.json |
Ctrl+R | Reload — Reload diskmap.json from disk and remount all drives |
# Text Input (during Ctrl+L)
When loading a drive path, a text input field appears at the bottom of the screen. This uses standard curses textpad editing keys:
| Key | Action |
|---|---|
| Printable characters | Insert at cursor position |
Enter / Ctrl+J | Submit the path |
Ctrl+G | Submit the path (alternative) |
Backspace / Ctrl+H | Delete character before cursor |
Ctrl+D | Delete character under cursor |
Ctrl+A | Move cursor to start of input |
Ctrl+E | Move cursor to end of input |
Ctrl+F / Right Arrow | Move cursor right |
Ctrl+B / Left Arrow | Move cursor left |
Ctrl+K | Clear from cursor to end of input |
# Workflows
# Mount a disk image on drive B
- Press
Bto select drive B - Press
Ctrl+Lto open the load prompt - Type the path:
cpm22d01.dsk - Press
Enter - Cold boot or warm boot the IMSAI to recognize the new drive
# Mount a directory on drive C
- Press
Cto select drive C - Press
Ctrl+L - Type the path:
myfiles.unpacked - Press
Enter - Reboot the IMSAI
# Unload drive B
- Press
Bto select drive B - Press
Ctrl+U
# Save your drive layout
Press Ctrl+P to persist the current drive assignments to diskmap.json. This ensures your configuration survives server restarts.
# Edit files externally on a DIR drive
If watchfiles is installed, changes made to the host directory by external tools (text editors, cp, rm, etc.) are detected automatically:
- Mount a directory on a floppy drive (e.g., drive B)
- Edit, add, or remove files in the host directory using any tool
- The server detects the change and rebuilds the in-memory directory
- The description row shows
<HOST> Host filesystem changed — directory rebuilt - Warm boot or cold boot the IMSAI to pick up the new directory
Notes:
- Automatic watching is only available for floppy drives (A–D), not the hard disk drive (I)
- Rapid external changes (e.g., pasting multiple files) are debounced into a single rebuild
- Directory-only metadata events are filtered out — only actual file changes trigger a rebuild
- Server-initiated filesystem changes (from CP/M writes) are suppressed automatically. The watcher stays suppressed while the write buffer is non-empty, so cross-drive operations like
PIP B:=A:FILEare handled safely - Without
watchfilesinstalled, you can still manually reload by unloading and re-loading the drive
# Reload after editing diskmap.json
If you edit diskmap.json externally (e.g., in a text editor), press Ctrl+R to reload and remount all drives without restarting the server.
# Display & Visualization
Both UIs provide real-time feedback on drive activity, connection state, and disk access, rendering the same underlying event stream differently.
# Web Display
The browser-based interface provides a dashboard with real-time updates via server-sent events (SSE). A dark/light theme toggle (sun/moon icon) in the top-right corner lets you switch themes — the choice is remembered across sessions and also applies to the User Guide page. The main display includes:
- Connection status bar — Green when connected, red when disconnected
- RECV indicator — Flashes during packet processing
- Drive panels — One per drive (A/B/C/D/I), each showing the drive label, command status (READ in green, WRITE in yellow), and a red LED indicator that lights when the drive is accessed. The hard disk drive (I) uses a neutral grey panel to distinguish it from the blue-tinted floppy drive panels
- Disk access visualization — An SVG rendering of the disk surface showing track rings, sector divisions, and animated arcs for recent access operations (reads in green, writes in yellow). The visualization switches to a grey palette when showing hard disk activity
- 7-segment display — Shows TRK, SEC, DMA, and RES values as retro LED digits with dark backgrounds, updated after each command
- Trace log panel — A collapsible panel that shows trace output in real time with auto-scrolling, capped at 10,000 lines for browser performance. Includes a Clear button and log level selector (INFO, WARN, ERROR) with LED indicators to dynamically change server log verbosity. Controls are hidden when the panel is collapsed
- Timing toggle — A green LED toggle in the toolbar to enable or disable disk timing simulation at runtime (no server restart needed)
# Terminal Display
The curses UI is organized as a bordered panel with the title [ Remote IMSAI FIF - fdcServer ] centered at the top.
# Screen Layout
+----------------------[ Remote IMSAI FIF - fdcServer ]-----------------------+
|FDC listening on COM5 @ 2000000 baud |
|***You must COLD BOOT the IMSAI to recognize the remote FIF*** |
|RECV |
|DSK:A: = IMG:cpm22d01.dsk READ TRK: 5 SEC: 3 DMA: 0080h RES: 01h|
|...........R.................................................................|
| D |
|0: ASM .COM |
|DSK:B: = DIR:cpm22d01.unpacked Login/Warm boot to reload disk |
|..W..........................................................................|
| E |
|0: DUMP .COM |
| ... more drives ... |
| KEY: <^P> DRIVE: DSK:A: |
+-----------------------------------------------------------------------------+
# Row Descriptions
| Row | Content |
|---|---|
| Row 0 | Transport status — green when connected, red when disconnected, yellow when listening for connections |
| Row 1 | Startup message / disconnect warning |
| Row 2 | Activity indicator — flashes RECV in reverse-video green during packet processing; also shows diskmap load/save confirmations |
| Drive rows (repeating groups of 4 per drive) | |
| Label row | Drive assignment (e.g., DSK:A: = IMG:cpm22d01.dsk) with command status and result |
| Track row | Head position visualized as dots with R (read) or W (write) at the active track |
| Sector type row | Sector classification at active position: B (boot), D (directory), E (data) |
| Description row | File/extent info (e.g., 0: ASM.COM), directory action (e.g., <DIR> - CREATE FILE: 0:ASM.COM), or host watcher notification (<HOST> Host filesystem changed — directory rebuilt) |
| Bottom row | Key press feedback and selected drive |
# Color Coding
| Color | Meaning |
|---|---|
| Green | Transport connected / RECV indicator |
| Red | Transport disconnected |
| Yellow | Warnings, hints (e.g., "Login/Warm boot to reload disk") |
| Cyan | Key press feedback |
| Reverse green | RECV activity indicator |
| Dim yellow | Secondary hints |
# Track Position Display
The track bar shows a row of dots (.) representing all tracks on the disk. The current head position is marked with a letter:
R— Read operation in progressW— Write operation in progress
For high-track-count disks (e.g., HDD with 255 tracks), the display is scaled down with a [x2] or similar suffix indicating the scale factor.
# Command Status
Each drive's label row shows the current command at column 35 (e.g., READ TRK: 5 SEC: 3 DMA: 0080h) and the result at column 69 as a hex FIF result code (e.g., RES: 01h for OK, RES: 00h for IGNORED, RES: C5h for bad track).
# Trace Log Overlay
Press Ctrl+T to toggle the trace log overlay. Shows a scrollable view of trace.log with ANSI colors. Use Up/Down arrows to scroll one line, PgUp/PgDn to scroll one page, Home/End to jump to the start/end. The overlay auto-follows new output; scrolling up switches to manual mode, End re-enables auto-follow. Press Ctrl+T again to close.
# Other Commands
| Key | Action |
|---|---|
? | Help — Show a popup with all keyboard commands and drive mappings. Press any key to dismiss. |
Ctrl+W | Redraw — Refresh the entire terminal display (useful if the screen becomes garbled) |
Ctrl+C | Quit — Shut down the server cleanly (closes all drives, stops transport) |
# Key Feedback
Every key press is displayed in cyan at the bottom-left of the window as KEY: <x>, providing immediate visual confirmation of input.
# Disk Image Utilities
Two utility scripts convert between raw disk images and the unpacked directory format used by DIR mode.
# Unpacking a Disk Image
Extract a .dsk or .hdd image to a host directory:
fdc-unpack cpm22d01
This looks for cpm22d01.dsk (then cpm22d01.hdd) and creates cpm22d01.unpacked/ containing:
cpm22d01.unpacked/
$BOOT # Boot track data (if present)
$ATTR # File attribute sidecar (if any non-default attributes)
0/ # CP/M user area 0
ASM.COM
DDT.COM
DUMP.COM
...
1/ # CP/M user area 1
...
Files are named in CP/M 8.3 uppercase format. User area subdirectories (0 through 15) correspond to CP/M user numbers.
# The $BOOT File
The $BOOT file contains the raw binary data from the disk image's boot tracks (tracks 0 and 1 for DSK format — 6656 bytes total). It is only created during unpacking if the boot tracks contain actual data (i.e., the first byte is not the CP/M empty marker 0xE5).
When a directory is mounted in DIR mode, the server reads $BOOT to serve boot track requests from the IMSAI. If the IMSAI writes to the boot tracks, the server creates or updates the $BOOT file in the unpacked directory.
When packing a directory back to an image with fdc-pack, the $BOOT file's contents are written to the boot tracks of the new image.
HDD format has no boot tracks (offset=0), so $BOOT is not used with .hdd images.
# The $ATTR File and File Attributes
CP/M 2.2 stores 11 attribute bits in each directory entry: T1' (R/O), T2' (SYS), T3' (Archive), and F1'–F8' (application-defined). In DIR mode and across fdc-pack/fdc-unpack, these bits are preserved via two host-side mechanisms:
- R/O (T1') maps to the host file's write permission. The server reads the bit from the host file and, when CP/M toggles R/O (e.g.,
STAT FOO.TXT $R/O), it callschmodto match. This is cross-platform: standard Unix permissions on Linux/macOS, and theFILE_ATTRIBUTE_READONLYflag on Windows. - SYS, Archive, and F1'–F8' are stored in a JSON sidecar named
$ATTRat the root of the unpacked directory, keyed byuser/FILENAME.EXT:
{
"0/ASM.COM": { "sys": true, "arc": true },
"0/HELP.HLP": { "sys": true },
"1/TOOL.COM": { "app": "0x80" }
}
The sidecar is sparse — only files with at least one non-default non-R/O bit appear. Missing entries mean "all default bits." An empty directory is written as {}. The app field packs F1'–F8' into a single byte with F1' as the most significant bit.
External changes are detected. If watchfiles is installed, changing a file's R/O state on the host (with chmod, file-properties dialogs, attrib on Windows, etc.) or editing $ATTR directly triggers a rebuild so the new bits are reflected on the CP/M side at the next directory read.
$ATTR is treated like $BOOT — it does not appear in CP/M directory listings.
# Packing a Directory to a Disk Image
Create a new disk image from an unpacked directory:
fdc-pack cpm22d01.dsk
This reads from cpm22d01.unpacked/ and writes a fresh cpm22d01.dsk image. Use .hdd extension for hard disk format.
A CP/M directory listing is printed to stdout after both operations. If the unpacked directory contains more files or data than the target format can hold, fdc-pack reports a clear "DISK FULL" or "DIRECTORY FULL" error and exits without creating the image.
Both utilities pause with "Press Enter to exit..." before closing so you can read the output. The pause is skipped automatically when the utilities are run in a script or pipe (non-interactive use).
# Supported Disk Formats
# Standard Floppy (DSK)
Used for drives A, B, C, and D.
| Parameter | Value |
|---|---|
| Tracks | 77 |
| Sectors per track | 26 |
| Sector size | 128 bytes |
| Block size | 1 KB |
| Directory entries | 64 |
| Boot tracks | 2 |
| Disk capacity | ~243 KB |
| Sector translation | IBM 3740 (8" floppy) |
| File extension | .dsk |
This matches the standard CP/M 2.2 single-density 8-inch floppy format.
# Hard Disk (HDD)
Used for drive I.
| Parameter | Value |
|---|---|
| Tracks | 255 |
| Sectors per track | 128 |
| Sector size | 128 bytes |
| Block size | 2 KB |
| Directory entries | 1024 |
| Boot tracks | 0 |
| Disk capacity | ~4 MB |
| Sector translation | None (1:1) |
| File extension | .hdd |
# Architecture Overview
The server is organized as a layered Python package (fdc/):
fdcServer.py Entry point (thin wrapper)
fdc/
server.py CLI parsing, component wiring, startup
events.py Event types and DriveObserver protocol
disk/
constants.py CP/M constants (sector size, extent size, etc.)
geometry.py Disk geometry definitions (DSK, HDD)
fif/
drive.py DriveMap — drive orchestration, command execution
image.py ImageDisk — raw binary image read/write, pack/unpack
filesystem/
directory.py CP/M directory entry parsing and formatting
dirfs.py DirDisk — virtual disk backed by host directory
watcher.py Directory watcher for external change detection
transport/
detect.py USB device auto-detection (Win/macOS/Linux)
protocol.py Wire framing (base64 + CRC-16) and command parsing
serial_transport.py Serial port transport with auto-reconnect
socket_transport.py TCP socket transport (single client)
ui/
curses/
curses_ui.py Terminal display and keyboard input handling
trace_overlay.py Scrollable trace log overlay for curses UI
web/
web_ui.py FastHTML-based web UI with SSE live updates
palette.py Centralised colour palette (functional + themeable)
disk_svg.py SVG disk access visualization
seg7_svg.py SVG 7-segment display rendering
# Layers
- Presentation (
ui/) — Curses terminal UI or FastHTML web UI, keyboard/browser input, event rendering - Orchestration (
server.py,drive.py) — CLI, component wiring, drive management, command dispatch - Domain (
disk/) — CP/M disk geometry, directory structures, image and directory filesystem backends - Transport (
transport/) — Wire protocol framing, serial and socket I/O
# Observer Pattern
Components communicate through a DriveObserver protocol. The DriveMap and transport backends emit DiskEvent objects for disk activity, connection state changes, and status updates. Both CursesUI and WebUI implement this protocol, queuing events thread-safely for display on the main thread.
# Wire Protocol
Commands from the IMSAI arrive as base64-encoded frames with CRC-16 (IBM 3740 / CRC-CCITT) checksums. The server responds with:
&+ base64 data — Success (with optional read data)#— Error@IGNORED— Drive is LOCAL, no action taken
# Management Commands
In addition to disk I/O, the wire protocol supports management commands that allow a connected client to query and modify the drive configuration without the web UI:
- Diskmap — Get the current drive assignments
- List — List available disk images and directories, with their mount status
- Eject — Unmount a drive
- Insert — Mount a disk image or directory to a drive
Management changes are in-memory only and are not saved to diskmap.json. Use the web UI Save button or Ctrl+P in the terminal UI to persist changes.
# Disk-Change Notification
When the drive configuration changes — from any source (web UI, management command, or diskmap reload) — the server notifies the connected client on its next disk command. The client can then update its view of the drive state before continuing. Management commands themselves are not affected by this notification.
# Drive Letter Mapping
| Drive | Unit Number | Geometry |
|---|---|---|
| A | 1 | DSK (floppy) |
| B | 2 | DSK (floppy) |
| C | 4 | DSK (floppy) |
| D | 8 | DSK (floppy) |
| I | 15 | HDD (hard disk) |
# Troubleshooting
# General
# "Warning: no diskmap.json file found"
No diskmap.json exists in the working directory. The server starts with all drives in LOCAL mode. Create a diskmap.json or load drives interactively (via Ctrl+L in the terminal UI or the Insert/Mount button in the web UI), then save (Ctrl+P or the Save button).
# IMSAI doesn't see the remote drives
You must cold boot the IMSAI after starting the server for it to recognize the remote FIF. A warm boot may also work for reloading individual drives.
# Serial connection drops
The serial transport automatically attempts to reconnect after 1 second. The display will show a red disconnection message and a yellow restart notice. Reconnection is automatic — no user action is needed.
# Changes not persisted after restart
Drive changes made at runtime (via Ctrl+L/Ctrl+U in the terminal UI, or Insert/Eject/Mount/Unmount in the web UI) are in-memory only until you save to diskmap.json (Ctrl+P or the Save button).
# "Error: DISK FULL" or "Error: DIRECTORY FULL" when packing
The unpacked directory contains more data or more files than the target disk format supports. Remove files from the unpacked directory, or use a larger format (.hdd instead of .dsk).
When this error occurs during a DIR-mode mount (e.g., after external files are added to the host directory), the drive falls back to LOCAL mode and a status message is displayed. Remove files from the host directory to bring it within capacity, then remount.
# "already mounted on drive X" / "Duplicate: ... skipped"
Each disk image or directory can only be mounted on one drive at a time. This message appears in two situations:
- Interactive mount (web UI): You attempted to mount a path that is already loaded on another drive. Eject/unmount it from the other drive first.
- Diskmap reload: Your
diskmap.jsonassigns the same path to multiple drives. The server keeps the first occurrence (in A, B, C, D, I order) and skips duplicates. Editdiskmap.jsonto remove the duplicate entry.
# External file changes not detected
Directory watching requires the optional watchfiles package. Install it with pip install watchfiles. Without it, the server logs a warning at startup (watchfiles not installed — directory watching disabled) and DIR-mode drives won't detect external changes. Watching is also only supported on floppy drives (A–D); the hard disk drive (I) does not use directory watching.
# Terminal
# "Curses error: Try making the viewport larger (>= 80x24)"
The terminal window is too small. Resize it to at least 80 columns by 24 rows.
# Display is garbled
Press Ctrl+W to redraw the entire screen.