Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Virtual Terminal

The Virtual Terminal — ISO 11783-6 — is the most elaborate service on the bus, and the one that makes ISOBUS visible to a farmer. It is a screen-sharing protocol: an implement with no display of its own ships a complete description of its user interface to the terminal in the cab, and from then on the two cooperate to show controls and react to the operator. This chapter tells that story end to end.

Why this exists

A modern cab cannot grow a new dial and a new screen layout every time a different implement is attached. So the cab terminal is deliberately dumb about implements: it is a general-purpose renderer that knows how to draw rectangles, numbers, strings, bars, and buttons, and how to report touches and key presses. The implement is the one that knows what its UI should look like. The VT protocol is the contract that lets the implement describe its UI once, hand it over, and then drive it — so any implement can present rich controls on any certified terminal.

   IMPLEMENT (VT client)                      CAB (VT server)
   "knows what the UI means"                   "knows how to draw"

     ── object pool (the whole UI) ──────────────►   uploaded once
     ── change_numeric_value(rate, 42) ──────────►   field redraws
     ◄─ soft key 3 pressed ───────────────────────   operator input

Mental model: the object pool

The implement’s UI is a pool of objects, each with a numeric ID, that reference one another to form a tree. A working set object is the root; it points at data masks (full-screen layouts); masks contain containers, output fields, input fields, buttons, bar graphs, and so on; fonts, colours, and pictures are shared leaf objects. machbus models all ~48 object types in isobus::vt.

   WorkingSet ──► DataMask "main" ──► OutputNumber "rate"
       │              │           └─► SoftKeyMask ──► Key 1, Key 2, Key 3
       │              └─► OutputString "status"
       └──► DataMask "settings" ──► InputNumber, InputList …

   shared: Font, Colour, Picture, Macro, … (referenced by ID)

The pool is data, not code. The implement builds it (often exported from a design tool as an .iop file), and machbus’s codec serializes it to the exact wire layout the terminal expects and parses it back — including the per-type length walk that makes the byte stream unambiguous.

The lifecycle: find, upload, activate, run

A VT client moves through a connect state machine. The shape:

  DISCONNECTED
     │  who is a VT?  (look for VT status)
     ▼
  DISCOVERED  ── learns the VT's address + version
     │  send working-set announcement
     ▼
  UPLOADING   ── transfer the whole object pool (big → Transport Protocol)
     │  "End of Object Pool"; VT validates it
     ▼
  ACTIVATING  ── ask the VT to make this pool the active one
     │  activation OK
     ▼
  CONNECTED   ── steady state: push value changes, receive input events

Two realities make this interesting:

  • The pool is large. The upload rides the Transport Protocol from the foundation chapter — often hundreds or thousands of bytes in one connection-mode transfer. A failed transfer means no UI.
  • Versions differ. Terminals advertise a VT version and capabilities (screen size, colour depth, soft-key count, fonts). A good client adapts; machbus exposes the version handshake and capabilities so you can.

Anatomy of the runtime conversation

Once CONNECTED, the protocol is a steady two-way stream:

Client → VT (commands). The implement keeps the displayed UI in sync with its internal state. The common commands, all on the machbus VT client:

CommandEffect on screen
change numeric valueupdate a number/bar/gauge
change string valueupdate text
hide / show, enable / disabletoggle visibility / interactivity
change active maskswitch the whole screen
change soft-key maskswitch the row of soft keys
change attribute / size / colour / positionrestyle or move an object
select input object, lock/unlock maskdrive focus and modality

VT → client (events). The terminal reports what the operator did and what it decided:

EventMeaning
soft-key / button activationoperator pressed a key
numeric / string value changedoperator edited an input field
input object selectedfocus moved / edit started
pool errorthe VT rejected something in the pool
language / units changedoperator changed locale; reload if needed
active working set changedanother implement took the screen

machbus surfaces these as VtEvent variants on the unified event stream.

Doing it with machbus

On the recommended facade, the whole lifecycle is a plugin:

   Session::builder(name, addr)
       .plug(VtClient::new(config, pool, working_set))
       .spawn(transport)
              │
              ▼  driver.poll() each cycle
   ┌────────────────────────────────────────────────────────┐
   │ FSM: discover → upload → activate → run                │
   │ inbound VT frames → VtEvent on the event stream        │
   │ your commands (set_value, …) → buffered, sent next tick│
   └────────────────────────────────────────────────────────┘

You point the client at a VT (connect_to), and once connected push updates with set_value / set_string / etc. through fine control. Soft-key and value-change events arrive on poll() (or drain::<VtEvent>()). The full walkthrough is in the Virtual Terminal client tutorial; the server side (acting as the terminal) is in Virtual Terminal server.

machbus also ships a renderer and a VT server: it can play the terminal, maintain the active pool, apply runtime commands, run macros, and report operator input — useful for simulation, testing, and headless terminals.

Auxiliary control (AUX)

Beyond the screen, ISO 11783-6 defines auxiliary inputs — physical joysticks and switch banks that an operator assigns to implement functions. There are an older (AUX-O) and a newer type-2 (AUX-N) scheme. machbus decodes the status messages and, on the VT-version-5 path, the capability discovery that lets a client learn what auxiliary channels a terminal offers.

Failure modes worth knowing

  • Pool too big or malformed — the VT rejects the upload or returns a pool error; nothing draws. Validate the pool and watch for PoolError.
  • Version mismatch — commands or objects the terminal does not support fail silently or with a pool error; check the advertised version/capabilities first.
  • Lost activation — another working set can become active; handle ActiveWorkingSet so you do not fight for the screen.
  • Editing races — the operator may be editing a field while you push a new value to it; the protocol and a careful client reconcile who wins.
  • Reconnect — if the VT drops, the client must re-discover and re-upload; the pool is not persisted on the terminal across a real power cycle.

From concept to code

You read about…Build it with…See…
VT client (implement side)session::plugins::VtClientVirtual Terminal client
VT server (the terminal)session::plugins::VtServerVirtual Terminal server
Building an object poolisobus::vt (or an .iop export)VT object pools
Pushing UI updatesVtClient::set_value / set_string / …VT updates
Auxiliary discoveryVtClient aux capabilitiesVT auxiliary capabilities

What this proves / does not prove

machbus implements the VT client, server, renderer, and the object-pool codec, and exercises them against real .iop pools and reassembled uploads. That proves the protocol behavior locally; it does not prove pixel-accurate rendering on a specific commercial terminal or AEF VT certification — see Conformity first.

See also