Protobuf
The Protobuf (Volume III) binary encoding of the HIBW model, and how it maps from the IDL.
BLUF
Protobuf is the compact binary encoding of the HIBW model (Volume III). In
0.3.0-rc4 the model is distributed as OMG IDL (the source of truth for
binary encodings) plus JSON Schema and XSD; the standalone .proto bundle that
shipped with 0.1.0 / 0.2.0 is not part of RC4. So the API generates .proto
from the IDL for every draft, compiles it, and serves the result — the samples
below are faithful proto3 derived from the RC4 model.
You don't have to run the transpiler yourself. The validation API ships the generated bundles and a JSON ⟷ protobuf codec:
- Download a draft's full
.prototree (plus its compiledFileDescriptorSetand union map) fromGET /protobuf/{version}/bundle.zip; list what's available atGET /protobuf. - Encode a JSON message to its protobuf binary with
POST /encode(or the per-typePOST /messages/{slug}/encode). - Decode a protobuf payload back to JSON and re-validate it with
POST /decode(orPOST /messages/{slug}/decode). Protobuf carries no type tag, so the generic/decodetakes a?message_type=query.
The codec translates the STANAG $discriminator on a union to/from the proto
oneof automatically, so a JSON → protobuf → JSON round-trip is lossless.
The CATL message set changed between 0.2.0 and 0.3.0 (e.g. 0.2.0 had
SET_WORLD_MODEL / ADD_NODE / STATUS; 0.3.0 has NODE_DESCRIPTION /
NODE_STATUS / TASK_FEEDBACK / TASK_RESULT). Do not reuse the 0.2.0
.proto files as-is for RC4 — regenerate from the 0.3.0-rc4 IDL.
How Protobuf relates to the model
One logical model, several wire formats (see encodings). The IDL is the canonical definition; JSON Schema, XSD, and Protobuf are projections of it. Mapping conventions from IDL to proto3:
| IDL construct | proto3 |
|---|---|
struct | message |
enum | enum (with a *_UNSPECIFIED = 0 zero value) |
union (discriminated) | message with a oneof |
sequence<T> | repeated T |
typedef scalar (GUID, Time) | string |
optional [0..1] field | optional scalar / message presence |
The envelope
syntax = "proto3";
package catl.hibw.messages.core;
// 0.3.0-rc4 message set. proto3 requires a zero default, so a synthetic
// UNSPECIFIED is added ahead of the model's seven types.
enum MessageTypeEnum {
MessageTypeEnum_UNSPECIFIED = 0;
MessageTypeEnum_TASK_ADMIN = 1;
MessageTypeEnum_NODE_STATUS = 2;
MessageTypeEnum_DYNAMIC_UPDATE = 3;
MessageTypeEnum_CHAT = 4;
MessageTypeEnum_TASK_FEEDBACK = 5;
MessageTypeEnum_NODE_DESCRIPTION = 6;
MessageTypeEnum_TASK_RESULT = 7;
}
message MessageHeader {
MessageTypeEnum message_type = 1;
string source = 2; // GUID of the originating node
string version = 3; // schema version, e.g. "0.3.0"
string time_sent = 4; // ISO-8601 timestamp
}A data element: Track
Track inherits the BaseWhatWhereWhen fields (flattened here) and adds a
lifecycle phase — see base::track::Track.
syntax = "proto3";
package catl.hibw.base.track;
enum TrackPhase {
TrackPhase_UNSPECIFIED = 0;
TrackPhase_DEAD_RECKONED = 1;
TrackPhase_LOST = 2;
TrackPhase_TRACKED = 3;
TrackPhase_INACTIVE = 4;
}
message Track {
string identifier = 1; // GUID, required
optional string source_of_information = 2; // GUID
string timestamp = 3; // ISO-8601
optional Pose pose = 4;
optional Velocity velocity = 5;
TrackPhase track_phase = 6;
repeated string contributing_information = 7; // GUIDs
}A union becomes a oneof
The discriminated unions in the model (for example
TargetOrNode) map to a oneof:
message TargetOrNode {
oneof value {
Contact contact = 1;
Track track = 2;
Plot plot = 3;
Reference reference = 4;
Node node = 5;
}
}Generating and using it
Pull the generated tree for a draft straight from the API and compile it with
protoc for your target language:
# Grab the generated .proto tree for the current draft (also includes the
# compiled descriptor.pb and unions.json):
curl -fsSL http://localhost:8817/protobuf/sd3-rc4/bundle.zip -o proto.zip
unzip proto.zip -d proto
protoc --proto_path=proto \
--python_out=gen \
--cpp_out=gen \
$(find proto -name '*.proto')Or skip code generation entirely and use the codec endpoints — encode a JSON message to binary and decode it back:
# JSON message → protobuf (base64-wrapped, with byte sizes)
curl -fsS -X POST http://localhost:8817/encode \
-H 'content-type: application/json' \
-d '{"message": { ... a NODE_STATUS ... }}'
# protobuf (base64) → JSON, re-validated against the schema
curl -fsS -X POST 'http://localhost:8817/decode?message_type=MessageTypeEnum_NODE_STATUS' \
-H 'content-type: application/json' \
-d '{"base64": "<payload from /encode>"}'Because the constraint annotations carried in the IDL (@min, @max,
@ext::pattern_*, …) have no native proto3 equivalent, enforce them with a
validation layer — the same JSON Schema rules apply to the decoded message (the
/decode endpoint does exactly this and returns the validation result). See
getting started for validation, and
encodings for the JSON and XML projections.