Skip to content

ajokela/retroshield-sector-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RetroShield Sector Server

A minimal TCP server written in Rust that serves CP/M disk image files over the network to an Arduino Giga R1 WiFi running CP/M 2.2 on a RetroShield Z80.

The server replaces the SD card used in the original Arduino Mega 2560 version of the project. The Arduino connects over WiFi and forwards Z80 BIOS disk I/O operations as TCP messages.

Overview

The RetroShield Z80 CP/M system needs disk I/O for booting (loading CPM.SYS) and for all file operations (DIR, loading programs, reading/writing data files). On the Mega 2560, this went through an SD card. On the Giga R1, the SD card is replaced by this server.

The protocol mirrors the Z80 BIOS I/O port commands exactly. The same command bytes the BIOS uses (0x01–0x08, 0x10–0x11) are sent directly over TCP. Block size is 128 bytes — one CP/M sector.

Protocol

Command Byte Payload Response
OPEN_READ 0x01 filename\0 status
CREATE 0x02 filename\0 status
OPEN_APPEND 0x03 filename\0 status
SEEK_START 0x04 (none) status
CLOSE 0x05 (none) status
DIR 0x06 (none) status + listing\0
OPEN_RW 0x07 filename\0 status
SEEK 0x08 3 bytes LE offset status
READ_BLOCK 0x10 (none) status + 128 bytes
WRITE_BLOCK 0x11 128 bytes status

Status is a single byte: 0x00 = OK, 0x01 = error.

Features

  • Threaded connections — each client runs in its own thread; the accept loop never blocks
  • Read/write timeouts — 30s mid-command, 300s idle; dead connections are dropped automatically
  • SO_REUSEADDR — server can restart instantly without port conflicts
  • Filename sanitization — rejects path traversal and special characters
  • Session metrics — tracks sectors read/written, bytes transferred, command count, errors, and session duration

Prerequisites

  • Rust (stable toolchain)

The only dependency beyond std is socket2 for SO_REUSEADDR.

Build

cargo build --release

The binary is at target/release/sector_server.

Usage

sector_server [directory] [port]
  • directory — path to a folder containing CP/M files (default: current directory)
  • port — TCP port to listen on (default: 9000)

Example:

./target/release/sector_server ./cpm_files 9000

The directory should contain:

File Description
boot.bin Z80 boot loader (loaded first at address 0x0000)
CPM.SYS CP/M system image — CCP + BDOS + BIOS
A.DSK Drive A disk image (256 KB, 77 tracks, 26 sectors/track)
B.DSK Drive B disk image (optional)
C.DSK Drive C disk image (optional)
D.DSK Drive D disk image (optional)

Session Output

When a client disconnects, the server prints session metrics:

Session Summary
---------------
Duration:        00:05:23
Commands:        847
Files opened:    12
Seeks:           89
Sectors read:    634
Sectors written: 42
Bytes read:      81,152 (79.2 KB)
Bytes written:   5,376 (5.2 KB)
Errors:          0

CP/M Disk Format

  • 128 bytes per sector
  • 26 sectors per track
  • 77 tracks per disk
  • 256,256 bytes per disk image (~250 KB)
  • 2 reserved tracks for system area
  • Up to 4 drives supported (A–D)

Related Projects

Blog Posts

This project is documented in a three-part series on tinycomputers.io:

  1. My Experience Using Fiverr for Custom PCB Design: A $468 Arduino Giga Shield
  2. Porting CP/M to the Arduino Giga R1: When Level Converters Fight Back
  3. Playing Zork on a Real Z80: From CP/M Boot to the Great Underground Empire

License

BSD 3-Clause License. See LICENSE.

Author

Alex Jokela — tinycomputers.io

About

Rust TCP server for serving CP/M disk images over WiFi to a RetroShield Z80

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages