Session and terminal¶
A BTP session defines the protocol state shared by two peers while they communicate.
The session establishes:
- which BTP envelope version will be used;
- the effective communication limits;
- the session inactivity timeout;
- the identity and role of each peer;
- the configuration revision announced by each peer.
The session begins with HELLO / HELLO_RESULT and ends through SESSION_CLOSE, timeout, or loss of the underlying transport.
The terminal channel operates inside an established session but remains logically separate from telemetry, commands and control traffic.
The reference library's btp::messages encodes and decodes the HELLO, HELLO_RESULT, SESSION_CLOSE and SESSION_CLOSE_RESULT payloads and computes the effective limits (btp::negotiate); btp::Session runs the responder state machine on top -- the HELLO → active lifetime, the inactivity watchdog and the fall back to console on close or timeout. The initiator side (sending ENTER / HELLO, awaiting HELLO_RESULT) and the plain-ASCII serial console↔protocol text stay the integration's (Using the library §11.1). Command deduplication is a separate library mechanism again, btp::DedupCache (§5.3, Using the library §13).
1. HELLO¶
HELLO is the first BTP message used to establish a session.
No application message may be exchanged before a successful HELLO_RESULT.
The logical payload is:
| Offset | Size | Field | Wire type |
|---|---|---|---|
| 0 | 1 | role |
uint8 |
| 1 | 1 | version_count |
uint8 |
| 2 | 2 | flags |
uint16_le, zero |
| 4 | 4 | max_logical_payload |
uint32_le |
| 8 | 2 | max_inflight_reassemblies |
uint16_le |
| 10 | 2 | max_subscriptions |
uint16_le |
| 12 | 4 | max_dedup_entries |
uint32_le |
| 16 | 4 | session_timeout_ms |
uint32_le |
| 20 | 16 | peer_uuid |
16 octets |
| 36 | 4 | config_revision |
uint32_le |
| 40 | V | versions |
version_count × uint8 |
The message announces the capabilities of the sender.
Conceptually:
Peer A Peer B
| |
|--------------- HELLO -------------->|
| |
| versions |
| limits |
| role |
| UUID |
| config revision |
| |
The receiver uses these values to determine whether a compatible session can be established.
1.1 peer_uuid¶
peer_uuid is a stable opaque identity containing exactly:
16 octets
It is compared byte for byte.
No byte-order conversion is applied.
The all-zero UUID is invalid.
BTP does not assign additional structure to these 16 octets.
1.2 config_revision¶
config_revision identifies the currently announced configuration of the peer.
A value of:
0
means that the peer does not publish a manifest.
When a peer publishes a manifest, the revision starts at:
1
and increases monotonically when the described configuration changes.
config_revision tracks the object catalog: topics, schemas, fields and
actions. It does not track the source_info block
(Commands and discovery), which is informational
and is always delivered in full.
The manifest itself is defined in Commands and discovery.
1.3 Announced limits¶
The following capabilities must all be non-zero:
max_logical_payload
max_inflight_reassemblies
max_subscriptions
max_dedup_entries
session_timeout_ms
They describe the maximum values supported by the sender.
For example:
Peer A
max_logical_payload = 16384
max_inflight_reassemblies = 4
max_subscriptions = 16
max_dedup_entries = 32
session_timeout_ms = 10000
does not require the other peer to support those same maximums.
The effective session values are determined by HELLO_RESULT.
On a communication path containing an ESP-NOW hop:
max_logical_payload <= 53550
On a communication path containing a BLE hop:
max_logical_payload <= 120360
because of the transport limits defined in Getting it across the link.
1.4 Supported versions¶
versions contains exactly:
version_count
BTP envelope version values.
They appear:
- in increasing order;
- without duplicates;
- without zero.
The currently defined envelope versions are:
0x01
0x02
For example:
version_count = 2
versions:
0x01
0x02
announces support for both versions.
Version negotiation is completed by HELLO_RESULT.
1.5 Roles¶
The role field uses the following values:
| Value | Role |
|---|---|
0x01 |
producer |
0x02 |
gateway |
0x03 |
consumer |
0x04 |
consumer, diagnostic tool |
The following values are reserved:
0x00
0x05 .. 0xFF
The role transmitted on the wire is the numeric value.
Both:
0x03
and:
0x04
represent consumers from the protocol perspective.
BTP defines no different message behavior for these two roles.
The distinction allows the peer to identify that one consumer announced itself specifically as a diagnostic tool.
2. HELLO_RESULT¶
HELLO_RESULT completes session negotiation.
Its logical payload is:
| Offset | Size | Field | Wire type |
|---|---|---|---|
| 0 | 12 | request reference | Commands and discovery |
| 12 | 1 | status |
SUCCESS, UNSUPPORTED, or BUSY |
| 13 | 1 | selected_version |
uint8 |
| 14 | 2 | error_code |
uint16_le |
| 16 | 4 | max_logical_payload |
effective value |
| 20 | 2 | max_inflight_reassemblies |
effective value |
| 22 | 2 | max_subscriptions |
effective value |
| 24 | 4 | max_dedup_entries |
effective value |
| 28 | 4 | session_timeout_ms |
effective value |
| 32 | 16 | peer_uuid |
responder UUID |
| 48 | 4 | config_revision |
responder revision |
A successful exchange is:
Peer A Peer B
| |
|--------------- HELLO -------------->|
| |
|<----------- HELLO_RESULT ------------|
| |
| session established |
2.1 Version selection¶
The responder selects the highest mutually supported envelope version that can be used across the complete session path.
For example:
Peer A supports:
0x01
0x02
Peer B supports:
0x01
selected_version:
0x01
A gateway must also respect the versions supported by every link participating in the session.
A version cannot be selected if another required hop cannot carry it.
2.2 Effective limits¶
btp::negotiate(local, remote) computes the peer-to-peer part of this: the field-by-field minimum and the highest common version. A gateway on a path with a tighter limit than either peer clamps the result further itself.
Every negotiated session limit is the minimum of the capabilities available to the peers and the communication path.
Conceptually:
Peer A maximum
|
v
Peer B maximum
|
v
path maximum
|
v
effective session limit
For example:
Peer A max_logical_payload = 32768
Peer B max_logical_payload = 8192
produces:
effective max_logical_payload = 8192
The larger peer cannot force the smaller peer to accept a value beyond its announced capability.
This rule applies to:
max_logical_payload
max_inflight_reassemblies
max_subscriptions
max_dedup_entries
session_timeout_ms
On success, all effective limits are non-zero.
2.3 No compatible version¶
If the peers have no supported version in common:
status = UNSUPPORTED
error_code = UNSUPPORTED_VERSION
selected_version = 0
All negotiated limits are zero.
After transmitting the result, the session is closed.
No application traffic follows an unsuccessful HELLO_RESULT.
2.4 Second concurrent session (TCP)¶
A responder that already has an active session for a given robot and receives a HELLO for a second, concurrent control session over TCP (§3.4) rejects it with:
status = BUSY
error_code = CAPACITY_EXHAUSTED
reusing the existing generic result vocabulary (Commands and discovery §1.4) rather than defining a new one for this case.
selected_version is set to the version the responder would otherwise have selected, since the rejection is about session admission, not version compatibility.
As with §2.3, all negotiated limits are zero, no application traffic follows, and the session -- which never became active -- is closed immediately after the result is sent.
This status value only applies where a transport can present the responder with more than one simultaneous connection attempt for the same robot in the first place. Serial has exactly one physical port, and BLE's single-peripheral role refuses a second link before it can reach HELLO (Getting it across the link §8.6); TCP is, at the time of writing, the only transport where this case is reachable at the BTP level.
3. Entering protocol mode on serial¶
Serial has an additional state because the same physical port may operate as a human-readable console before BTP begins.
The serial port starts in:
console mode
BTP binary framing does not begin automatically when frame-like bytes are observed.
The transition to protocol mode uses an explicit text exchange.
The client sends:
BTP/1 ENTER NNNNNNNNNNNNNNNN\r\n
where:
NNNNNNNNNNNNNNNN
contains exactly 16 hexadecimal digits chosen by the client.
Uppercase and lowercase hexadecimal digits are accepted.
For example:
BTP/1 ENTER A10F22CC8899ABCD\r\n
The port owner responds using the same nonce converted to lowercase:
BTP/1 READY a10f22cc8899abcd\r\n
The sequence is:
Client Port owner
| |
| BTP/1 ENTER <nonce>\r\n ------------>|
| |
|<---- BTP/1 READY <nonce>\r\n --------|
| |
| protocol mode |
Binary BTP framing begins only after the final:
\n
of the READY response.
At that moment, the serial COBS decoder state is cleared.
The client must then transmit HELLO within:
2000 ms
No other BTP message may precede it.
3.1 Invalid entry lines¶
A line that does not exactly match the ENTER syntax remains ordinary console input.
For example:
BTP ENTER
or an incomplete:
BTP/1 ENTER 1234
does not switch the port into protocol mode.
BTP frames are never automatically detected inside console traffic.
The state transition is explicit:
console
|
| valid ENTER / READY
v
BTP protocol
not:
console bytes
|
| "looks like a BTP frame"
v
BTP protocol
This keeps console data and protocol framing unambiguous.
3.2 Other transports¶
ESP-NOW, USB HID, and TCP do not define the serial console state.
They operate directly in protocol mode.
Once the link becomes available -- for TCP, once the TCP connection completes -- they must be ready to begin the BTP session with HELLO. §3.4 covers the TCP-specific details (default port, the connect-to-HELLO deadline, session admission, and reconnection); BLE (§3.3) is the one direct transport that does not fit this diagram, because it has GATT preconditions to satisfy first.
Conceptually:
Serial
console
|
ENTER / READY
|
v
HELLO
|
v
session
ESP-NOW / USB HID / TCP
link available
|
v
HELLO
|
v
session
3.3 BLE¶
BLE also has no ENTER / READY exchange -- there is no serial console state to leave, and once the underlying GATT connection exists the peer does not send BTP/1 ENTER text. However, "the link exists" means something narrower for BLE than it does for ESP-NOW or USB HID: a GATT connection being open does not by itself mean the RX and TX characteristics defined in Getting it across the link §8.1 are usable yet.
HELLO must not be sent until all of the following have completed, in order:
GATT connection established
|
v
BTP service discovered
|
v
RX characteristic located
|
v
TX characteristic located
|
v
TX notifications enabled (CCCD written)
|
v
HELLO
|
v
session
The TX notification precondition is not a stylistic preference: if HELLO were sent before the central enables notifications on TX (by writing its Client Characteristic Configuration Descriptor), the peripheral's HELLO_RESULT notification could be generated while the peer is not yet subscribed and would then be silently dropped by the BLE stack rather than queued -- there is no BTP-level retransmission of HELLO_RESULT to recover from that. Once all four discovery/enablement steps are complete, HELLO is sent immediately, exactly as it would be over ESP-NOW or USB HID -- there is no additional BLE-specific delay or nonce exchange after that point, and no BLE-specific watchdog window distinct from the one described in section 5.
A BLE disconnection at the link layer always ends the session outright, the same way losing any other transport does (section 5); there is no partial or "console" state to fall back into. A subsequent connection -- reconnection by the same peer or a connection from another peer -- repeats the full sequence above and produces a new session; it does not resume the previous one. Getting it across the link §8.6 defines the accompanying one-session-per-robot policy, and §8.7 defines what happens to any state held for the previous connection.
Compatibility¶
Version negotiation (§1.4, §2.1) is unchanged over BLE, for the same reason it is unchanged over TCP (§3.4): HELLO / HELLO_RESULT carry the supported and selected envelope versions the same way regardless of which transport carried them, and BLE adds no transport-level version of its own to negotiate. A future bally_OS or TraceView release continues to advertise its supported versions exactly as it would over any other transport, and §2.3's "No compatible version" applies unchanged if an incompatible pairing is ever attempted.
3.4 TCP connections¶
TCP also has no ENTER / READY exchange -- there is no serial console state to leave, and unlike BLE (§3.3) there is no GATT discovery step to wait for either. The moment the TCP three-way handshake completes, the connection is in BTP protocol mode. Getting it across the link §9 defines the transport itself -- roles, default port, framing, kTcpTransport limits, and the mandatory-encryption rule; this subsection defines what that means for session establishment.
TCP connect completes
|
v
HELLO
|
v
session
The client must transmit HELLO immediately once the connection completes. If no valid HELLO arrives within:
2000 ms
the server closes the socket without a reply -- the same bound already used after serial's READY response (§5.1), applied here to the TCP connect event in place of READY. Because every frame on a TCP connection, HELLO included, must be encrypted, an unencrypted first frame never reaches this deadline at all -- it is dropped as a protocol violation on arrival.
One control session per robot¶
A bally_OS TCP server accepts only one active BTP control session per robot at a time. The TCP connection itself is still accepted at the socket level when a second one arrives -- the server does not refuse the accept() -- but if that second connection reaches HELLO while a session is already active for the same robot, the responder rejects it as defined in §2.4: HELLO_RESULT with status = BUSY, no application traffic follows, and the server closes the TCP socket right after.
Rejecting at the BTP session level, rather than refusing the TCP connection outright, is the deliberate choice here: it gives the second client (in practice, TraceView reporting "this robot already has an active session" to the user) a structured, versioned reason instead of an opaque connection refusal or timeout, and it keeps the policy expressed in BTP -- where HELLO_RESULT already has a place for it -- rather than adding new out-of-band TCP-level signaling, which is exactly what this transport otherwise avoids by skipping ENTER / READY.
This differs from BLE's approach to the same rule (§3.3, Getting it across the link §8.6), where the GAP layer itself prevents a second connection from forming at all. A TCP server socket has no equivalent single-connection primitive -- refusing the accept() would still leave the door open to a raw connection flood and would give the second client no diagnosable reason -- so TCP enforces the rule one layer up, in BTP, instead.
Session end and reconnection¶
Closing the TCP socket -- whether the client disconnects deliberately, the connection drops, or bally_OS reboots -- is transport loss for BTP purposes and ends the session exactly as §5 already describes for any other transport loss; there is no TCP-specific close sequence beyond that. An orderly shutdown still uses SESSION_CLOSE / SESSION_CLOSE_RESULT (§4) before the socket closes, when time allows.
A new TCP connection is always a new session: it repeats the full HELLO / HELLO_RESULT exchange and receives a freshly negotiated set of limits. It does not resume or inherit any state from a previous TCP connection to the same robot. This is the same rule already stated for session loss in general (§5.3): command deduplication stays scoped to the executor's boot, not to the session or the TCP connection, so reconnecting does not -- and must not be used to -- retrigger execution of a command already accepted in a previous TCP session.
A new connection also does not carry over trust in whatever peer answered last: TraceView must re-validate peer_uuid on every TCP connection, including a reconnect to a previously-known address, exactly as it does for BLE (Getting it across the link §9.6).
Compatibility¶
Version negotiation (§1.4, §2.1) is unchanged over TCP: a future bally_OS or TraceView release continues to advertise its supported envelope versions in HELLO / HELLO_RESULT, and the responder still selects the highest mutually supported version. TCP does not add a transport-level version of its own to negotiate.
4. Leaving protocol mode¶
An established session is closed using BTP messages.
The protocol does not scan binary data for a special escape sequence.
A normal close uses:
SESSION_CLOSE
|
v
SESSION_CLOSE_RESULT
4.1 SESSION_CLOSE¶
The logical payload contains:
| Offset | Size | Field | Wire type |
|---|---|---|---|
| 0 | 1 | reason |
uint8 |
| 1 | 3 | reserved |
zero |
| 4 | 4 | drain_timeout_ms |
uint32_le |
The defined close reasons are:
| Value | Name |
|---|---|
0x00 |
NORMAL |
0x01 |
VERSION_MISMATCH |
0x02 |
CLIENT_SHUTDOWN |
0x03 |
PROTOCOL_ERROR |
Unassigned values are reserved.
drain_timeout_ms defines the requested time available to complete the close exchange.
4.2 SESSION_CLOSE_RESULT¶
The result contains:
request reference
status:uint8
reserved:uint8
error_code:uint16_le
For a valid close, the port owner:
- stops accepting new work;
- transmits the close result within the allowed drain interval;
- discards incomplete reassemblies;
- terminates protocol mode.
The maximum drain interval is:
min(drain_timeout_ms, 2000 ms)
For serial, after cleanup completes, the port owner emits exactly:
BTP/1 CONSOLE\r\n
The serial state becomes:
BTP protocol
|
| SESSION_CLOSE
v
drain
|
v
SESSION_CLOSE_RESULT
|
v
BTP/1 CONSOLE\r\n
|
v
console
The console transition happens only after the BTP session has been terminated.
5. The watchdog¶
Every established session has an inactivity watchdog.
Its timeout is:
session_timeout_ms
as negotiated during the HELLO exchange.
The watchdog is renewed when a valid BTP frame is received.
If no valid frame arrives before the timeout expires, the session is terminated.
For serial, the same cleanup used by a normal session close is performed before returning to console mode.
5.1 Initial serial timeout¶
After the serial READY response, HELLO must arrive within:
2000 ms
If it does not, protocol mode is abandoned.
Conceptually:
READY
|
v
wait for HELLO
|
+---- valid HELLO within 2000 ms ---> session
|
`---- timeout ----------------------> console
5.2 Invalid traffic¶
Invalid traffic does not renew the watchdog.
Examples include:
- malformed frames;
- invalid CRC;
- invalid envelope;
- other traffic that does not constitute a valid BTP frame.
Therefore:
valid frame
|
v
watchdog renewed
while:
invalid bytes
|
v
watchdog unchanged
A continuous stream of invalid data cannot keep a BTP session active indefinitely.
5.3 Session loss and command deduplication¶
Ending a session or losing the underlying transport does not clear command deduplication state.
Command deduplication is scoped to the executor boot, not to one session.
Therefore:
session lost
|
v
new session
|
v
same executor boot
|
v
previous command identities
remain protected
The deduplication rules are defined in Commands and discovery.
A session reconnect does not authorize execution of an already processed command a second time.
This is why the reference library's btp::DedupCache
(Using the library §13) is built with no
clock and no tie to session state: it is cleared only on an executor reboot.
6. Timeouts¶
BTP defines bounded lifetimes for operations that cannot remain incomplete indefinitely.
These include:
- fragmented-message reassembly;
- session inactivity;
- command execution.
The applicable timeout depends on the operation.
6.1 Reassembly timeout¶
Fragmented logical messages use the reassembly rules and timeout defined in Getting it across the link.
An incomplete logical message is not retained indefinitely.
When its reassembly timeout expires, the incomplete message is discarded.
6.2 Session timeout¶
Session inactivity uses:
session_timeout_ms
negotiated through HELLO_RESULT.
Expiration terminates the session as described in The watchdog.
6.3 Command execution timeout¶
Each synchronous action may announce:
execution_timeout_ms
in its manifest descriptor.
When execution exceeds this limit, the command completes with:
TIMEOUT
EXECUTION_TIMEOUT
After that result, the action must not continue producing effects as part of that command execution.
The timeout belongs to the action descriptor and is therefore known before the corresponding COMMAND_REQUEST is executed.
7. The terminal¶
BTP defines two terminal message objects:
TERMINAL_IN
TERMINAL_OUT
They provide a bidirectional opaque byte channel inside the BTP session.
The complete logical payload is the terminal data itself.
There is:
- no terminal-specific header;
- no text length prefix;
- no terminator;
- no encoding requirement.
btp::messages has no TERMINAL type for this reason -- there is nothing to decode. The payload of a reassembled TERMINAL message is the bytes.
The payload boundary is determined only by the BTP logical message size.
Conceptually:
BTP envelope
+---------------------------------------+
| type = TERMINAL |
| object_id = TERMINAL_IN / OUT |
+---------------------------------------+
| |
| opaque terminal bytes |
| |
+---------------------------------------+
7.1 Direction¶
TERMINAL_IN flows toward the source terminal input:
session controller
|
| TERMINAL_IN
v
source terminal
TERMINAL_OUT flows in the opposite direction:
source terminal
|
| TERMINAL_OUT
v
session controller
The two object IDs therefore identify the direction of the terminal stream.
7.2 Opaque payload¶
Terminal data is not required to be UTF-8.
All byte values are valid, including:
0x00
CR
LF
and byte sequences that happen to resemble encoded BTP data.
For example, all of these are valid terminal payloads:
hello\r\n
00 01 02 ff 7e
or:
invalid UTF-8 bytes
BTP does not inspect or reinterpret the contents.
The terminal layer carries bytes.
7.3 Fragmentation¶
A terminal logical message may use normal BTP fragmentation when required.
Fragments are not exposed individually as terminal data.
The receiver first performs:
fragment 0
fragment 1
fragment 2
|
v
reassembly
|
v
complete TERMINAL payload
|
v
terminal delivery
An incomplete fragmented terminal message is not partially delivered.
7.4 Sequence ordering¶
Complete terminal messages from the same origin use the normal BTP envelope sequence.
This sequence may assist in ordering received terminal messages.
However, BTP sequence numbers are shared by all message types from the same source.
For example:
sequence 100 -> TERMINAL_OUT
sequence 101 -> TELEMETRY
sequence 102 -> COMMAND_RESULT
sequence 103 -> TERMINAL_OUT
From the terminal perspective, receiving:
100
103
does not mean that terminal messages:
101
102
were lost.
Those sequence values may belong to other BTP channels.
Therefore, a terminal receiver must not fabricate missing terminal bytes based only on sequence gaps.
No padding or replacement data is generated.
7.5 Separation from telemetry¶
Terminal and telemetry are different BTP message types.
Terminal bytes remain terminal bytes.
Telemetry payloads remain telemetry payloads.
There is no implicit conversion between them.
For example:
TERMINAL_OUT
|
v
terminal channel
and:
TELEMETRY
|
v
telemetry decoder
follow separate logical paths.
A TELEMETRY message is not terminal output.
A TERMINAL_OUT message is not a telemetry sample.
This distinction remains true even if both happen to contain human-readable text.
8. Priority¶
BTP defines a logical priority order for outgoing traffic under congestion.
Messages are grouped into six classes.
Within one class, messages use FIFO order.
The priority classes are:
| Priority | Traffic |
|---|---|
| 1 | Session messages and COMMAND_RESULT |
| 2 | COMMAND_REQUEST and control results |
| 3 | Subscription control and STATUS with DEGRADED |
| 4 | TERMINAL_IN and TERMINAL_OUT |
| 5 | MANIFEST_DATA, periodic STATUS and LOG |
| 6 | TELEMETRY |
Priority 1 is the highest.
Priority 6 is the lowest.
Conceptually:
highest priority
1 session / COMMAND_RESULT
|
2 COMMAND_REQUEST / control results
|
3 subscriptions / DEGRADED status
|
4 terminal
|
5 manifest / normal status / log
|
6 telemetry
lowest priority
This order allows control and completion traffic to remain serviceable when the communication channel is congested.
8.1 FIFO within a class¶
Priority does not reorder messages within the same class.
For example:
TERMINAL_OUT A
TERMINAL_OUT B
TERMINAL_OUT C
remain:
A
B
C
inside the terminal priority class.
8.2 Sequence values¶
Scheduling priority does not modify envelope sequence numbers.
A message retains the sequence assigned when it was created.
The scheduler does not renumber messages according to the order in which they eventually reach the transport.
8.3 Frames already in flight¶
Priority does not interrupt a frame that has already begun transmission.
A higher-priority message may be selected before the next message or eligible fragment, but it does not modify an already transmitted partial frame.
8.4 Reliability¶
Priority does not change the reliability properties of the underlying transport.
A best-effort transport remains best-effort.
For example:
high priority
does not imply:
guaranteed delivery
The priority mechanism determines which traffic is serviced first when capacity is limited.
It does not provide acknowledgement or retransmission by itself.
8.5 Congestion behavior¶
A sender reserves enough capacity to service at least one message from priority classes:
1
2
Under pressure, telemetry is the first defined traffic class to be dropped.
Dropped telemetry contributes to the corresponding protocol counters.
Large lower-priority traffic, including:
MANIFEST_DATA
TERMINAL
must be scheduled so that it does not indefinitely block higher-priority command traffic.
Conceptually:
large MANIFEST_DATA
fragment 0
fragment 1
fragment 2
fragment 3
fragment 4
command arrives
fragment 0
fragment 1
COMMAND_RESULT
fragment 2
fragment 3
fragment 4
The exact transport scheduling mechanism is implementation-dependent, but it must preserve the BTP priority rules.
9. Session lifecycle¶
The complete session lifecycle can be represented as:
link available
|
v
+------------------+
| pre-session |
+------------------+
|
| HELLO
v
+------------------+
| negotiation |
+------------------+
|
| HELLO_RESULT
| SUCCESS
v
+------------------+
| active session |
+------------------+
| |
| |
SESSION_CLOSE | timeout /
| | transport loss
v v
+------------------+
| cleanup |
+------------------+
|
v
session ended
For serial, an additional console transition surrounds the BTP session:
console
|
| ENTER / READY
v
pre-session
|
| HELLO / HELLO_RESULT
v
active session
|
| close or timeout
v
cleanup
|
| BTP/1 CONSOLE
v
console
For ESP-NOW, USB HID, and TCP, there is no console state:
link available
|
v
HELLO
|
v
session
For BLE, there is no console state either, but an additional GATT discovery/enablement step precedes HELLO (section 3.3), and a lost connection always ends the session -- reconnection never resumes it:
GATT connection
|
v
service + RX + TX discovery
|
v
TX notifications enabled
|
v
HELLO
|
v
active session
|
| disconnect (any cause)
v
session ended
|
v
advertising resumes
10. Summary¶
A BTP session begins by negotiating a common protocol version and effective communication limits.
The basic exchange is:
HELLO
|
v
HELLO_RESULT
A successful result establishes:
selected envelope version
max logical payload
max inflight reassemblies
max subscriptions
max dedup entries
session timeout
peer identities
configuration revisions
Serial additionally uses an explicit:
ENTER
|
v
READY
exchange before binary protocol mode begins.
BLE additionally requires completing GATT service/characteristic discovery and enabling TX notifications before HELLO may be sent (section 3.3); a BLE disconnection always ends the session outright, and reconnecting always starts a new one rather than resuming the previous session.
TCP has neither a console state nor GATT preconditions: HELLO is sent immediately once the TCP connection completes, and every frame on that connection, HELLO included, must be encrypted (section 3.4, Getting it across the link §9). A second TCP connection attempted while a session is already active for the same robot is accepted at the socket level but rejected with HELLO_RESULT status = BUSY; closing the TCP socket always ends the session outright, and a new TCP connection always starts a new one.
Protocol mode ends through:
SESSION_CLOSE
|
v
SESSION_CLOSE_RESULT
or through a timeout or transport failure.
A valid frame renews the session watchdog.
Invalid traffic does not.
The terminal channel carries opaque bytes through:
TERMINAL_IN
TERMINAL_OUT
and remains separate from telemetry and other BTP message classes.
Under congestion, BTP uses six logical priority classes so that session and command traffic are serviced before lower-priority data such as telemetry.
These rules define the lifecycle and multiplexing behavior of a BTP session without changing the framing, fragmentation or message identities defined by the rest of the protocol.