← Technical specifications

ROT2PROG protocol

TCP command protocol used by the SPID MD01 rotor controller.

The MD01 controller accepts commands over a TCP connection (default port 23). All packets are 13 bytes in the command direction and 12 bytes in the response direction. Angle digit fields are ASCII in the command direction, but the hardware returns raw digit bytes in responses — see the angle encoding section.

Each command–response exchange completes synchronously: the client sends 13 bytes, then reads a 12-byte response before sending the next command.

SPID's official ROT2PROG Protocol Documentation v2.0 describes the full command set. The protocol exists in two generations: the original commands encode angles as four digits scaled by a divisor byte (0.1° resolution with divisor 10), while later firmware added _100 variants that encode angles as five digits at fixed 0.01° resolution. SALSA uses the _100 commands for get/set; this page documents those, plus the legacy-format calibration command. Where the official document and the actual hardware disagree, this page records the observed hardware behavior.

Command packet (13 bytes)

Byte(s) Field Value Notes
0 S (start) 0x57 Always 'W'
1–5 H1–H5 (azimuth) encoded angle Five digit bytes, see encoding below. Only used by Set position; use 0x00 for Stop and Get position. Restart instead puts its confirm value 0xEF 0xBE 0xAD 0xDE in bytes 1–4.
6–10 V1–V5 (elevation) encoded angle Five digit bytes, see encoding below. Only used by Set position; use 0x00 otherwise.
11 K (command) see table below Determines the command type.
12 END 0x20 Always ' ' (space)
K byte Command
0x0F Stop (ROTn_CMD_STOP) — stop rotation and return current position
0x6F Get position (ROTn_CMD_GET_ANGLES_100) — return current position without moving
0x5F Set position (ROTn_CMD_SET_ANGLES_100) — move to the azimuth/elevation in H1–H5, V1–V5
0xEE Restart (ROTn_CMD_RESTART_DEVICE) — reboot the controller after a 5 second delay; requires confirm value 0xEF 0xBE 0xAD 0xDE in bytes 1–4

Response packet (12 bytes)

Stop, Get position and Set position return a 12-byte position response. Restart instead returns a 12-byte ACK starting with 0x57.

Byte(s) Field Value Notes
0 S (start) 0x58 Always 'X' for a position response. Stop may also respond with 0x57 ('W') as an ACK when the rotor was actively moving.
1–5 H1–H5 (azimuth) encoded angle Current azimuth as five digit bytes. See encoding below.
6–10 V1–V5 (elevation) encoded angle Current elevation as five digit bytes. See encoding below.
11 END 0x20 Always ' ' (space)

Angle encoding

Angles are encoded as a 5-digit integer representing (angle_degrees + 360) × 100, with each byte being one decimal digit of that integer:

value = H1×10000 + H2×1000 + H3×100 + H4×10 + H5
angle_degrees = value / 100.0 − 360.0

For example, azimuth 5.54° is encoded as (5.54 + 360) × 100 = 36554. In the command direction the digits are sent as ASCII (0x33 0x36 0x35 0x35 0x34), as in the official documentation's examples. The official documentation shows ASCII digits in responses too, but the hardware actually returns raw byte values 0–9 ([3, 6, 5, 5, 4]). This holds for both protocol generations: the SALSA backend relies on it when parsing _100 responses, and the pre-2026 control software relied on it when decoding legacy 0x1F responses.

Calibration (legacy format)

The calibration command (ROTn_CMD_CALIBRATION, 0xF9) overwrites the controller's stored current position without moving the rotor. It is used to correct pointing offsets found by observing a strong source such as the Sun. There is no _100 variant of this command; it exists only in the legacy format, where each angle is four ASCII digits (0x300x39) of (angle_degrees + 360) × divisor followed by a divisor byte. Four digits limit the divisor to 10 (0x0A), giving 0.1° calibration resolution:

Byte(s) Field Value Notes
0 S (start) 0x57 Always 'W'
1–4 H1–H4 (azimuth) ASCII digits (azimuth_degrees + 360) × 10 as four ASCII digits
5 PH (divisor) 0x0A Azimuth divisor: 10 units per degree
6–9 V1–V4 (elevation) ASCII digits (elevation_degrees + 360) × 10 as four ASCII digits
10 PV (divisor) 0x0A Elevation divisor: 10 units per degree
11 K (command) 0xF9 Calibration
12 END 0x20 Always ' ' (space)

Example from the official documentation: 0x57 "3610" 0x0A "3590" 0x0A 0xF9 0x20 sets the current position to azimuth 1° and elevation −1°. The response is the legacy 12-byte position frame (start byte 0x57, four digits + divisor per angle, angle = value / divisor − 360) — not the 0x58 frame used by the _100 commands. This is the same command the old SALSA control software used in its _set_current_azel function, verified working on the MD01 hardware.

TCP connection

The controller accepts a single persistent TCP connection on port 23. The SALSA backend keeps the connection alive across commands to avoid re-connection delays during active tracking. A 1-second timeout is applied to both reads and writes. On connection failure the backend reconnects automatically on the next control loop cycle (1 Hz).

A Stop command is issued once when the backend first connects, to ensure the rotor is not moving from a previous session.

References