CBC Schemas
CBC (Compact Binary Coding) is a bit-packed binary format used in MAPS for extremely compact, deterministic wire formats.
Schemas define:
- the application and version
- one or more messages
- a list of ordered fields for each message
- the bit-width, type, and rules for each field
There is no inference: every bit is accounted for by the schema.
1. Description
CBC is designed for constrained and expensive links such as:
- NTN / satellite transports
- narrowband cellular
- low-power IoT networks
Fields are encoded as a contiguous bitstream:
- integers with custom bit-widths
- bitmasks
- nested structs
- optional fields
- encode/decode expressions for scaling
The CBC schema format is represented in JSON and stored in the schema field of a SchemaConfig with format: "cbc".
2. Schema Format
A CBC schema document has this shape:
{
"application": "exampleApp",
"version": "1.0",
"description": "Example application",
"messages": [
{
"name": "heartbeat",
"direction": "UPLINK",
"messageKey": 65280,
"description": "Device heartbeat",
"fields": [ /* field specs */ ]
}
]
}
2.1 Top-level fields
-
application
Logical application or schema owner. -
version
Human-readable schema version string. -
description
Description of the CBC schema/application. -
messages
Array of message definitions.
2.2 Message definition
Each message contains:
-
name
Message name, unique within the application. -
direction
E.g."UPLINK","DOWNLINK". -
messageKey
Integer identifier used on the wire. -
description
Human-readable description. -
fields
Ordered list of field specifications.
Fields are packed into the bitstream in this order.
3. Field Specification
Fields are generated from FieldSpecification and serialised via toFieldMap(...).
A field object may contain:
-
name(string)
Field name. -
type(string)
Storage/semantic type, for example:uint→ unsigned integerint→ signed integerbitmask→ flag fieldstruct→ nested structure
-
size(integer, bits)
Number of bits used for this field.
Required for numeric/bitmask fields; omitted for some struct usages. -
optional(boolean, only when true)
Iftrue, the field is not guaranteed to be present.
Presence rules are defined by the protocol logic. -
fixed(boolean, only when false)
When omitted, the field is treated as fixed-length.
Whenfixed: false, the field does not occupy a fixed number of bits (e.g. variable-length constructs). -
description(string)
Human-readable description. -
decalc(string)
Expression applied when decoding:logical = f(raw).
Example:"v/1000". -
encalc(string)
Expression applied when encoding:raw = f(logical).
Example:"v*1000". -
min/max(number)
Optional logical minimum and maximum values. -
enum(object)
Mapping from raw numeric value (as string) to label:"enum": {
"0": "UNKNOWN",
"1": "GOOD",
"2": "BAD"
} -
fields(array)
Nested field list fortype: "struct".
3.1 Example field
{
"name": "latitude",
"type": "int",
"size": 18,
"decalc": "v/1000",
"encalc": "v*1000",
"description": "Latitude in degrees, 0.001° resolution"
}
- Raw 18-bit signed integer on the wire.
- Logical value = raw / 1000.
- Encoded value = logical * 1000.
4. CBC SchemaConfig Example
CBC schemas are embedded into SchemaConfig.schema with format: "cbc".
{
"versionId": "1",
"name": "viasat-heartbeat-cbc",
"description": "Viasat NB-NTN heartbeat message (CBC-encoded)",
"labels": {
"uniqueId": "b1dc43de-4c9b-5d86-9425-cf958eeb598d",
"resource": "sensor",
"interface": "sensor.viasat.heartbeat",
"comments": "NB-NTN proof-of-concept CBC schema"
},
"format": "cbc",
"schema": {
"application": "viasatNtnProofOfConcept",
"version": "1.1",
"description": "Viasat NB-NTN proof of concept for efficient binary data transport",
"messages": [{
"description": "A basic health/config status message for NB-NTN devices.",
"direction": "UPLINK",
"name": "heartbeat",
"messageKey": 65280,
"fields": [
{ "name": "secOfDay", "type": "uint", "size": 17 },
{ "name": "location", "type": "struct", "optional": true, "fields": [
{ "name": "latitude", "type": "int", "size": 18, "decalc": "v/1000", "encalc": "v*1000" },
{ "name": "longitude", "type": "int", "size": 19, "decalc": "v/1000", "encalc": "v*1000" }
]},
{ "name": "signal", "type": "struct", "fields": [
{ "name": "rsrp", "type": "int", "size": 9 },
{ "name": "rsrq", "type": "int", "size": 6 },
{ "name": "sinr", "type": "int", "size": 6 },
{ "name": "rssi", "type": "int", "size": 9, "optional": true },
{ "name": "cellId", "type": "uint","size": 32, "optional": true }
]},
{ "name": "psmConfig", "type": "struct", "optional": true, "fields": [
{ "name": "tauT3412", "type": "bitmask", "size": 8 },
{ "name": "actT3324", "type": "bitmask", "size": 8 }
]},
{ "name": "edrxConfig", "type": "struct", "optional": true, "fields": [
{ "name": "edrxCycle", "type": "bitmask", "size": 4 },
{ "name": "edrxPtw", "type": "bitmask", "size": 4 }
]},
{ "name": "counter", "type": "uint", "size": 16, "optional": true }
]
}]
}
}
5. Java Usage
5.1 Registering a CBC schema
SchemaConfig cbcConfig = SchemaConfig.builder()
.name("viasat-heartbeat-cbc")
.format("cbc")
.schema(cbcSchemaJsonObject) // the CBC application/messages JSON
.build();
schemaRepository.register(cbcConfig);
5.2 Processing a CBC payload
At runtime, MAPS:
- Resolves the
SchemaConfig(typically by topic + labels/matchExpression). - Loads and caches the CBC schema.
- Decodes the bitstream:
- walks
messages[].fields[]in order - reads
sizebits per field - applies
decalcexpressions where defined
- walks
- Produces a Typed Event with named, typed fields.
- Passes the Typed Event through:
- filtering
- transformations
- statistics
- format conversion (e.g. CBC → JSON/Avro/Protobuf)
Encoding performs the inverse process using encalc.
6. CBC-Specific Notes
- Bit layout is canonical: no padding, no inferred alignment.
- Use
structto group related fields (e.g.signal,location,psmConfig). - Use
decalc/encalcto avoid wasting bits on floating point; store scaled integers instead. optionalmarks fields that may or may not be present. Actual presence rules must be honoured by encoder/decoder logic.- When evolving CBC schemas:
- Prefer appending new fields at the end.
- Avoid changing existing
sizeor reordering fields. - If incompatible change is required, version the schema separately via
versionand/orversionId.