Skip to content

Interface file reference

Location: chosen by your project, for example protos/reading/interface.toml beside reading.proto. An interface describes the message and delivery policy used by a service port. It does not choose which services run; the unit does that.

Complete message and interface

Create protos/reading/reading.proto:

syntax = "proto3";
message Reading {
  uint32 value = 1;
}

Beside it, create protos/reading/interface.toml:

[interface]
interface = "example.reading"
schema = "reading.proto"

[delivery]
policy = "latest"

These files define a message contract. To actually send/receive values, implement service behavior and add the service ports and unit channel shown below.

Fields

Section / field Required / default Meaning
[interface].interface Required string Message contract identity, such as example.reading
[interface].schema Required path Protobuf file, relative to this interface file
[interface].max_payload Default: computed encoded maximum Optional byte capacity, at least the computed maximum and at most 256
[delivery].policy Required latest or stream
[delivery].kind Optional; ordinary channel when omitted Advanced coordination kind: state, event, or action

Modern interfaces require the [delivery] table. Do not author major/minor versions or accepts_minor: connected endpoints require matching interface identity and schema. Service-local named types are not shared message schemas.

Choose a delivery policy

Policy Retains Channel depth Consumer behavior
latest Most recent message Exactly 1 Intermediate values may be skipped
stream Bounded sequence of messages 1–8 Slow consumers can lose messages; handle the loss indication

For stream delivery, change the interface's policy to "stream". The unit can choose depth = 4 or another valid capacity meeting all port minima. Policy stays in the interface so producers and consumers cannot silently disagree.

Payload bounds come from the protobuf schema. Unbounded variable-length data needs explicit bounds accepted by the protobuf tooling; start with the scalar example above. max_payload cannot make an oversized schema fit. The encoded maximum is a storage bound, not a sampling interval or throughput promise.

Connect a producer and a consumer

In services/sensor/service.toml, add this fragment:

[service.publications.reading]
interface = "../../protos/reading/interface.toml"

In services/display/service.toml, add:

[service.subscriptions.reading]
interface = "../../protos/reading/interface.toml"

In the unit selecting both services, add:

[channels.reading]

The matching name reading attaches both ports. Each service also needs its own identity, build definition, and implementation. This is wiring configuration, not supplied sensor/display code. The connection walkthrough covers generation and the callbacks you implement.

A port may add min_depth = 4 if it requires stream retention. An explicit unit depth below that minimum fails validation. A channel with no enabled port also fails validation. Distinct message groups need distinct channel names.

Advanced coordination

kind = "state", "event", or "action" requires policy = "latest" and payload capacity no greater than 64 bytes. Coordination ports currently require the manual coordination adapter; hook lifecycle services cannot use them. Leave kind out for ordinary publisher/subscriber messaging. See Coordination before choosing this option.

Validate

./micros generate
./micros compose -d host

For board wiring, substitute -d HARDWARE_ID. Generation checks the referenced schemas; composition checks the enabled service endpoints and chosen channel depths together. Neither command sends messages or validates physical behavior.