Files
vt1200/reference/keyboard-mouse/PROTOCOL.md
T

279 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VT1200 keyboard & mouse serial protocol — distilled specification
Everything here is attributed to a source in `SOURCES.md`, and each fact is tagged
**[confirmed]**, **[probable]** or **[unknown]**.
## 0. Bottom line
There is **no VT1200-specific protocol document**. What exists is documentation for the
**LK201 keyboard** (and its successor the **LK401**) and for the **VSXXX-AA/-GA mouse /
VSXXX-AB tablet**. The evidence that these *are* the VT1200's parts — and therefore that
their protocols apply — is strong and is laid out in §1. The two facts the level-1
Keyboard/Mouse tests need (the self-test command and its reply) **are** covered by public
sources: it is `FD` → `01 00 00 00` for the keyboard and `T` → a 4-byte report for the mouse.
See §3.5 and §4.4.
Status of the question in the brief: **closest-part-only**. The VT1200's own manuals never
describe the wire protocol.
---
## 1. Which parts the VT1200 uses — the evidence
| Fact | Value | Confidence | Source |
|---|---|---|---|
| Keyboard family | **LK400 series**; `LK401-XX` standard, `LK402-XX` word-processing | **[confirmed]** | `EK-V1000-SV-002_service-guide.txt` §1.1.3 |
| Keyboard, ROM side | Terminal firmware source file is named **`LK401.C`**; ROM strings *"The keyboard ROM reported a fault at power-up"*, *"A key was held down during power-up"* | **[confirmed]** | `../rom-strings.txt` (offsets 0x0E4AB9, 0x0E4B2A, 0x0E4B58) |
| Keyboard, model designation | `LK401 Keyboard` appears as a heading in the VT1200 user guide | **[confirmed]** | `../../docs/EK-V1200-UG-001_installing-VT1200.txt` (TOC §"The Keyboard") |
| LK401 electrical/firmware relation to LK201 | "not intended to be a direct replacement for the LK201, but is **electrically and firmware functionally compatible**" | **[confirmed]** | `vt100net-lk401.txt` line 239 |
| LK401 host protocol = LK201 protocol | LK401 spec says the terminal→keyboard protocol "can be found in the LK400 Keyboard Firmware Requirements"; `lkkbd.c` and `elkay` implement one driver for both, and `lkkbd.c` enables extra LK401 keys with one added command | **[probable]** | `vt100net-lk401.txt` line 678; `linux-lkkbd.c` lines 39–46; `elkay/docs/protocol.md` |
| Mouse / tablet | 3-button pointing device; service guide calls the device test "mouse **or tablet**"; a `VSXXX-AB` tablet is the optional alternative | **[confirmed]** device type / **[probable]** exact model `VSXXX-AA` | `EK-V1000-SV-002_service-guide.txt`; `vcb02-az-glgab-mn-feb86-text.txt` App. C/D |
So: **keyboard = LK401, which speaks the LK201 serial protocol; mouse = VSXXX-AA
(hockey-puck), with the VSXXX-AB tablet as the alternate the firmware also supports.**
---
## 2. Topology — separate ports, NOT daisy-chained
This is the one place the VT1200 differs from the common LK201/VSXXX picture (where the
mouse hangs off the keyboard).
* The terminal ROM's own test list names **two separate DUART2 channels**:
`H - DUART2, CHANNEL A (KEYBOARD)` and `I - DUART2, CHANNEL B (MOUSE)`. **[confirmed]**
(`../rom-strings.txt`, offsets 0x179795 / nearby; `../level1-test-sequence.md`).
* The service guide tells the technician to "Disconnect the keyboard, mouse, or printer
**from the rear of the system box**"; the VT1200 user guide says "The keyboard cable
connects to the system box" and "The mouse connects to the system box". **[confirmed]**
* The service guide provides a **separate mouse-port loopback connector** (12-25628-01) and a
distinct *Mouse Port Test* (19) vs *Keyboard Port Test* (18). **[confirmed]**
* The VCB02 (the architectural ancestor, same Q-bus/DUART design) likewise keeps the keyboard
on DUART **channel A** and the pointing device on **channel B**, with "the other port …
for any other serial device, probably a mouse or a tablet". **[confirmed]**
(`vcb02-az-glgab-mn-feb86-text.txt` lines ~9635, and the DUART reset-default table.)
**Conclusion [confirmed]: on the VT1200 the keyboard is on DUART2-A and the mouse is on
DUART2-B, as two independent serial links. The mouse is NOT daisy-chained through the
keyboard.** This matches the already-wired MAME SCN2681 at both DUART windows.
---
## 3. Keyboard (LK401, LK201 protocol)
### 3.1 Wire parameters
| Parameter | Value | Confidence | Source |
|---|---|---|---|
| Baud | **4800** | **[confirmed]** | `netbsd-lk201-interface.html`; `vt100net-lk401.txt` §3.5.4 "4800 baud only"; MAME `lk201.cpp` `set_rate(4800)` |
| Data bits | **8** | **[confirmed]** | LK401 §3.5.5 "start bit, 8 data bits, stop bit"; `vt100net-lk401.txt` |
| Parity | **none** | **[confirmed]** | LK401 §3.5.5 has no parity element (8N1); `netbsd-lk201-interface.html` ("8N1"); MAME `set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1)` |
| Stop bits | **1** | **[confirmed]** | as above |
| Levels | **EIA RS-423**, ±5 V, powered from +12 V | **[confirmed]** | `netbsd-lk201-interface.html`; `elkay/docs/protocol.md` |
| Connector | 4P4C modular: 1=host TX→kbd, 2=GND, 3=+12 V, 4=kbd→host RX | **[probable]** (pin order differs between write-ups; verify at the cable) | `linux-lkkbd.c` header; `elkay/docs/protocol.md` |
### 3.2 Framing / command encoding
Host→keyboard: a command is one or more bytes. **Bit 7 of the last byte of every command is
set** (the "PARAMS" flag); bit 7 of a non-final byte is clear, and byte bit 0 is the
"TYPE" flag (0 = transmission command, 1 = peripheral command). **[confirmed]**
(`vcb02-az-glgab-mn-feb86-text.txt` §B.5.5.1–B.5.5.2.) Keyboard→host: single bytes.
### 3.3 Host → keyboard command set (VCB02 Table B-7, cross-checked against drivers)
| Bytes | Meaning | Conf. | Source |
|---|---|---|---|
| `FD` | **Jump to Power-Up / Reinitiate Keyboard** — keyboard runs its self-test and sends the 4-byte power-up sequence (§3.5) | **[confirmed]** | VCB02 B.5.5.3 "The jump to power-up command is FD (hexadecimal)"; `linux-lkkbd.c` `LK_CMD_POWERCYCLE_RESET 0xfd`; `vt100net-lk201-keyboard.html` trace |
| `AB` | Request keyboard ID — returns the 2-byte ID, does not jump to power-up | **[confirmed]** | VCB02 Table B-7; `linux-lkkbd.c`; `netbsd-lk201-interface.html` |
| `D3` | Reinstate defaults | **[confirmed]** | VCB02 Table B-7; `linux-lkkbd.c` |
| `CB` | Jump to test mode (factory) → replies `B8` | **[confirmed]** | VCB02 Table B-7; `netbsd-lk201-interface.html` |
| `13 p` / `11 p` | LEDs on / off; `p` bitmask: `01` Wait, `02` Compose, `04` Lock, `08` Hold Screen (parameter high bit set, e.g. `8F` = all) | **[confirmed]** | VCB02 Table B-7 + Fig. B-11; `netbsd-lk201-interface.html` |
| `99` | Disable keyclick | **[confirmed]** | VCB02 Table B-7 |
| `1B v` | Enable keyclick, volume `v` (`0x80`\|0–7, 0 = loudest) | **[confirmed]** | VCB02 Table B-7 + Fig. B-13 |
| `B9` | Disable Ctrl-key click | **[confirmed]** | VCB02 Table B-7 |
| `BB v` | Enable Ctrl-key click | **[confirmed]** | VCB02 Table B-7 |
| `9F` | Sound a keyclick | **[confirmed]** | VCB02 Table B-7 |
| `A1` | Disable bell | **[confirmed]** | VCB02 Table B-7 |
| `23 v` | Enable bell, volume | **[confirmed]** | VCB02 Table B-7 |
| `A7` | Sound bell | **[confirmed]** | VCB02 Table B-7 |
| `D1` | Temporary auto-repeat inhibit | **[confirmed]** | VCB02 Table B-7 |
| `E3` / `E1` | Enable / disable auto-repeat across keyboard | **[confirmed]** | VCB02 Table B-7 |
| `D9` | Change all auto-repeat to down-only | **[confirmed]** | VCB02 Table B-7 |
| `8B` | Resume keyboard transmission | **[confirmed]** | VCB02 Table B-7 |
| `89` (VCB02 OCR) / `B9` (NetBSD) | Inhibit keyboard transmission | **[unknown]** — the two sources disagree (`89` vs `B9`); treat as unresolved | VCB02 Table B-7; `netbsd-lk201-interface.html` |
| `0x86 \| d<<3` | Set division *d* (1–14) to a mode: low bits `00` down, `10` auto-down, `11` down/up | **[confirmed]** | VCB02 B.5.5.4; `netbsd-lk201-interface.html`; `elkay/docs/protocol.md` |
| `E9` | **LK401 mode**: enables the extra keys (LAlt, RAlt, RCompose, RShift). LK401-only. | **[confirmed]** | `linux-lkkbd.c` `LK_CMD_ENABLE_LK401`; `elkay/docs/protocol.md` |
> ⚠ The level-0 I/O data-path anomaly recorded in `../level1-test-sequence.md` says the
> firmware writes `0xE1` to DUART2-A and expects a **10-byte** reply. `0xE1` is documented as
> "disable auto-repeat across keyboard", which has **no reply** in any source here. So either
> that level-0 write is not what it looks like, or `0xE1` is a transcription error. **[unknown]**
> — flag it for the ROM/Ghidra side; it is not the keyboard *self-test*.
### 3.4 Keyboard → host special codes (single bytes)
`B3` All-Up (last down/up key released) · `B4` Metronome/auto-repeat tick · `B5` Output Error
(buffer overflow) · `B6` Input Error (bad command) · `B7` KBD-locked ACK · `B8` Test-mode ACK ·
`B9` Prefix-to-keys-down · `BA` Mode-change ACK · `7F` reserved. **[confirmed]**
(VCB02 Table B-4; `netbsd-lk201-interface.html`; `linux-lkkbd.c`.) Ordinary keycodes are
single bytes `> 0x40`; every key has one unique code, no shift/ctrl variants. **[confirmed]**
Full keycode table: `netbsd-lk201-keycodes.html` (14 divisions).
### 3.5 Power-up / self-test — **what the level-1 Keyboard Test (error 27) exercises**
On power-up, **or on receiving `FD`**, the keyboard runs a self-test in ≤70 ms and sends a
**4-byte** result. **[confirmed]** (VCB02 §B.5.4.3; NetBSD; LK401 §3.3.4.6; and the captured
VT320 trace in `vt100net-lk201-keyboard.html`.)
| Byte | Meaning | Value |
|---|---|---|
| 1 | Keyboard ID — firmware | `01` (`lkkbd.c` also accepts `02` = LK401 from the `AB` reply) |
| 2 | Keyboard ID — hardware | `00` |
| 3 | **Error code** | `00` = OK · `3D` = key held down at power-up · `3E` = ROM/RAM self-test failure |
| 4 | Keycode of the key held down, else `00` | e.g. `AE` in the stuck-shift trace |
* Healthy reply: **`01 00 00 00`**. Captured live on a VT320/LK201 in
`vt100net-lk201-keyboard.html`; emulated identically by `lk201emu` (`resetkb()` sends
`1,0,0,0`) and expected by `linux-lkkbd.c`. **[confirmed]**
* On a stuck key the reply becomes `01 00 3D <keycode>` and the terminal re-issues `FD`.
**[confirmed]** (`vt100net-lk201-keyboard.html`.)
* "If the self-test fails and the error is fatal, the keyboard is unable to transmit."
**[confirmed]** (VCB02 §B.5.4.3.)
**⇒ Implement the device-test model to: on receiving `FD`, reply `01 00 00 00`.** The
terminal's own display of the error code (message *"Keyboard Error - 27"*) comes from its
interpretation of byte 3; "any error code" from the device is what the service guide means by
"display any error code".
### 3.6 Wire parameters under test — does the terminal's test override them?
No source shows the Keyboard/Mouse tests changing baud/parity. The self-test is a normal
command on the already-configured port. **[probable]** — the VCB02 DUART reset-default table
sets channel A to "8 data, parity Off, 4800" and channel B to "8 data, parity **Odd**, 4800"
(`vcb02-az-glgab-mn-feb86-text.txt` §5.5.2.5, Table 5-9). Treat 4800/8N1 (kbd) and 4800/8O1
(mouse) as the port defaults; the VT1200's SCN2681 should be programmed the same way. **[probable]**
---
## 4. Mouse / tablet (VSXXX-AA / VSXXX-AB)
### 4.1 Wire parameters
| Parameter | Value | Confidence | Source |
|---|---|---|---|
| Baud | **4800** | **[confirmed]** | VCB02 §C.4; `linux-vsxxxaa.c` |
| Data bits | **8** | **[confirmed]** | VCB02 §C.6.1 |
| Parity | **ODD** | **[confirmed]** | VCB02 §C.6.1; `allpinouts-dec-7pin.html`; `linux-vsxxxaa.c` ("4800, 8o1") |
| Stop bits | **1** | **[confirmed]** | VCB02 §C.6.1 |
| Levels | RS-232-compatible (mark < −6 V, space > +4.6 V) | **[confirmed]** | VCB02 §C.5 |
| Connector | 7-pin micro-DIN: 1 GND, 2 TxD(mouse out), 3 RxD(into mouse), 4 −12 V, 5 +5 V, 6 n/c, 7 device-present→pin1 | **[confirmed]** | VCB02 Table C-1; `vaxarchive-vsxxx.html` |
| Duplex | half-duplex; a host byte during a mouse transmission aborts it | **[confirmed]** | VCB02 §C.6.1 |
### 4.2 Host → mouse commands (printable ASCII)
`R` (0x52) incremental stream mode · `D` (0x44) prompt mode (power-up default) · `P` (0x50)
request position (also enters prompt mode) · **`T` (0x54) self-test & identify** ·
`S` (0x53) select report format · `Z` (0x5A) reserved. Invalid commands are ignored.
**[confirmed]** (VCB02 Table C-2; `linux-vsxxxaa.c`; `vaxarchive-vsxxx.html`.)
### 4.3 Mouse → host position report (3 bytes, incremental mode)
```
bit 7 6 5 4 3 2 1 0
1 0 0 SX SY L M R byte 1 (header 100)
0 X6 X5 X4 X3 X2 X1 X0 byte 2
0 Y6 Y5 Y4 Y3 Y2 Y1 Y0 byte 3
```
`SX/SY` sign (1 = positive), `L/M/R` buttons (1 = depressed), X/Y in resolution units since
last report. **[confirmed]** (VCB02 Fig. C-4; `linux-vsxxxaa.c`; `vaxarchive-vsxxx.html`.)
### 4.4 Power-up / self-test — **what the level-1 Mouse Test (error 26) exercises**
On power-up, **or on receiving `T`**, the device sends a **4-byte self-test report**, starting
bits `101` (0xA0). **[confirmed]** (VCB02 §C.6.5 and Fig. C-5; `linux-vsxxxaa.c`; captured in
`vaxarchive-vsxxx.html`.)
```
byte 1: 1 0 1 0 R3 R2 R1 R0 revision
byte 2: 0 M2 M1 M0 D3 D2 D1 D0 M = manufacturer loc.; device code D: 0010 = mouse, 0100 = tablet
byte 3: 0 E6 E5 E4 E3 E2 E1 E0 error code
byte 4: 0 0 0 0 0 L M R button state, or the failed button if byte 3 = 3D
```
* Byte-3 error codes: `00` = OK; **`3E` = ROM/RAM checksum error**; **`3D` = button error**;
**codes ≥ 0x20 are fatal, < 0x20 non-fatal**. **[confirmed]** (VCB02 §C.6.5; `vsxxxaa.c`
treats ≤0x1f as "no serious error".)
* Self-test leaves the device in the reset/power-up state; data sent during self-test is
ignored. Self-test completes within 500 ms (power-up within 1 s). **[confirmed]** (VCB02 §C.6.4/§C.6.7.)
* Recommended host init (VCB02 §C.7.1): configure port for `4800 8O1`; read the power-up
self-test report; if none within 1 s, send `T`; then `S`; then `R` (or `D`). **[confirmed]**
**⇒ Implement the device-test model to: on receiving `T`, reply a well-formed self-test
report (e.g. header `0xA0|rev`, device byte `0x02`, error `00`, buttons `00`).** This is
exactly "firmware requests that the mouse do its self-test and display any error code".
### 4.5 Tablet (VSXXX-AB) — for completeness
Same connector, same serial parameters, same command set plus extras; power-up self-test differs
only in device code (`0100`) and a 5-byte absolute-position report (header `110`/0xC0).
**[confirmed]** (VCB02 App. D, §C.7.4; `linux-vsxxxaa.c` ABS branch.) Not needed for the level-1
mouse test unless a tablet is what's attached.
**Coordinate range:** the absolute position spans **`0..2199`** over the active area
(VCB02 App. D.1). **[confirmed]**
**How the terminal chooses** — there is no separate command and no setup record. The **device
code in the `T` reply is the whole discriminator**, and the host then frames **3-byte relative**
reports for a mouse (`0010`) or **5-byte absolute** ones for a tablet (`0100`). **[confirmed]**
against the running OS in the harness: it sends `T`, reads `A0 04 00 00` from a tablet, and then
reads RHRB in **groups of 5** — groups of 3 with a mouse.
---
## 5. How a device failure is reported back (both devices)
The terminal displays an error code it derived from the device's self-test reply: keyboard
error byte 3 (`3E`/`3D`), mouse error byte 3 (`3E`/`3D`, or ≥0x20 fatal). The service guide's
troubleshooting table then says, for **error 27**, "Replace the keyboard"; for **error 26**,
"run the Mouse Port Test with external loopback … otherwise replace the mouse". **[confirmed]**
(`EK-V1000-SV-002_service-guide.txt` Table 3-1.)
---
## 6. MAME relevance (drop-in candidates)
* **Keyboard: MAME already has a DEC LK201 device.** `DECLARE_DEVICE_TYPE(LK201, lk201_device)`,
device name `"lk201"`, "DEC LK201 Keyboard", in
`src/mame/dec/lk201.h` / `src/mame/dec/lk201.cpp`. It is a
`device_t + device_serial_interface`, i.e. **it expects a DUART-style serial channel** — it
would attach to the same SCN2681 channel A we already wired. It models the 68HC05 keyboard
MCU and **executes the real keyboard firmware ROM** (`23-001s9-00.bin`), so the protocol
behaviour (including the `FD` self-test reply) comes from that ROM, not from C. It wires as
`m_lk201->tx_handler()...`/`m_lk201->rx_w()` (see `src/mame/dec/vt240.cpp`, which places it
behind an i8251). **It does NOT model the mouse.**
* **Mouse: no DEC mouse device exists in MAME** (checked `src/mame/dec/` and the tree; no
`vsxxx*`). We would need a small HLE model, but §4 gives the complete protocol, so this is
low-risk.
* **Caveat / gap:** MAME's `lk201` wants the **6805** LK201 ROM `23-001s9-00.bin`, which is
**not** in the bitsavers zip we have (that is the **8051** `23-004M2`). Running MAME's device
therefore needs that ROM sourced first; otherwise implement a HLE keyboard that answers `FD`
with `01 00 00 00` (and optionally honours `AB`, `13/11`, mode-set `BA` ACKs). For merely
passing level-1 tests 26/27, an HLE keyboard + HLE mouse driven off DUART2-A/B is the
smallest sufficient model and needs no ROMs at all.
---
## 7. Confidence summary
| Item | Status |
|---|---|
| VT1200 uses LK401 keyboard / VSXXX-AA mouse | **confirmed** (service guide + ROM) |
| Keyboard LK401 speaks LK201 protocol | **probable** (LK401 spec: "firmware functionally compatible"; shared drivers) |
| Keyboard wire: 4800 8N1, RS-423 | **confirmed** |
| Keyboard self-test command `FD` → `01 00 00 00` (+ `3D`/`3E` errors) | **confirmed** |
| Mouse wire: 4800 8O1, RS-232, 7-pin DIN | **confirmed** |
| Mouse self-test command `T` → 4-byte report (`3D`/`3E`, ≥0x20 fatal) | **confirmed** |
| Separate ports (DUART2-A kbd, DUART2-B mouse); no daisy chain | **confirmed** |
| Exact LK401 firmware protocol (LK400 Firmware Requirements) | **unknown** — document not public |
| `0xE1`+10-byte level-0 anomaly | **unknown** — not explained by any source here |
| Inhibit-transmission opcode (`89` vs `B9`) | **unknown** — sources disagree |
| 4P4C keyboard pin order | **probable** — verify at cable |