Driving a model railway from Common Lisp
Tags: #commonlisp #networking
Model railways and Common Lisp — two subjects that rarely cross paths…

The Roco Z21 is a command station for digital model railways. It sits on the LAN, listens on UDP port 21105, and speaks a binary protocol. Locomotives, turnouts and track power are all driven by sending it the right bytes.

The protocol is documented, and any language with a UDP socket can drive the layout. Common Lisp seemed a fitting choice — sending an expression from the REPL and watching the train react is exactly the kind of interactive feedback loop for which this language is handy.
cl-z21 is the result: a small 2018 hobby project covering a useful subset of the protocol — system info, track power, turnouts, locomotive drive and functions, CV reading in service mode, and broadcast listening.
A typical session reads like:
(z21-set-track-power-on :verbose t)
(z21-set-loco-drive 3 64 :direction 1 :verbose t) ; loco 3, forward, speed 64/127
(z21-set-loco-function 3 0 #x01 :verbose t) ; light on
(z21-switch-turnout 0 :verbose t)Each form encodes its arguments into a UDP packet, sends it, waits for the reply, and prints the decoded result.
Internally, a small registry of coder structs — one per command — knows how to turn arguments into bytes. The decoding side mirrors it: decoder structs match incoming packets by byte prefix and parse the rest. The function z21-interact ties the two together.
Only runtime dependency: usocket, installed via Quicklisp. Tested under SBCL on Windows.