ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
hislip.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file hislip.h
6 * @brief HiSLIP (High-Speed LAN Instrument Protocol) message codec (PROTOCORE_ENABLE_HISLIP) - a zero-heap
7 * codec for the IVI Foundation's modern LXI instrument transport (IVI-6.1, HiSLIP 2.0) on
8 * TCP port 4880, the successor to VXI-11 that carries SCPI at higher throughput.
9 *
10 * A HiSLIP session runs over TWO TCP connections to the same port 4880 - a synchronous channel
11 * (the ordered SCPI command/response stream: Data / DataEND, Trigger, device-clear) and an
12 * asynchronous channel (out-of-band control: lock, status/SRQ, remote-local, interrupt) - bound by
13 * a 16-bit SessionID negotiated in the handshake.
14 *
15 * Every message is a fixed 16-byte header optionally followed by a payload:
16 * @code
17 * "HS" (2) MessageType (1) ControlCode (1) MessageParameter (4, BE) PayloadLength (8, BE)
18 * @endcode
19 * This codec builds + parses that header (@ref protocore_hislip_build_header / @ref protocore_hislip_parse_header),
20 * the Initialize / AsyncInitialize handshake (the MessageParameter carries the protocol version +
21 * vendor id, then the negotiated version + SessionID), and the Data / DataEND messages that carry a
22 * SCPI payload keyed by a MessageID. Pairs with @c PROTOCORE_ENABLE_SCPI (the payload). Pure codec,
23 * host-tested; the two TCP connections are the application's.
24 *
25 * Reference: IVI-6.1 "IVI High-Speed LAN Instrument Protocol (HiSLIP)" v2.0 (2020-04-23).
26 *
27 * @author Douglas Quigg (dstroy0)
28 * @date 2026
29 */
30
31#ifndef PROTOCORE_HISLIP_H
32#define PROTOCORE_HISLIP_H
33
34#include "protocore_config.h" // the entry point: protocore_types.h for the widths
35
36#if PROTOCORE_ENABLE_HISLIP
37
39
40/** @brief The IANA-assigned HiSLIP TCP port (both channels connect here). */
41#define PROTOCORE_HISLIP_PORT 4880
42
43/** @brief The fixed header length: prologue(2) + type(1) + control(1) + parameter(4) + length(8). */
44#define PROTOCORE_HISLIP_HEADER_LEN 16
45
46/** @brief Protocol version words (`<major><minor>`), encoded in the high 16 bits of the handshake
47 * MessageParameter. The client offers its max; the server returns min(client, server). */
48#define PROTOCORE_HISLIP_VERSION_1_0 0x0100
49#define PROTOCORE_HISLIP_VERSION_1_1 0x0101
50#define PROTOCORE_HISLIP_VERSION_2_0 0x0200
51
52/** @brief The MessageID a client starts at; each subsequent Data/DataEND/Trigger increments by 2
53 * (unsigned 32-bit, wraps). A server response echoes the request's MessageID. */
54#define PROTOCORE_HISLIP_MESSAGE_ID_INIT 0xFFFFFF00u
55
56// ControlCode bits carried by an InitializeResponse:
57#define PROTOCORE_HISLIP_INITRESP_OVERLAP 0x01 ///< bit 0: prefer overlapped (vs synchronized) mode
58#define PROTOCORE_HISLIP_INITRESP_ENC_MANDATORY 0x02 ///< bit 1: encryption mandatory (2.0)
59#define PROTOCORE_HISLIP_INITRESP_ENC_INITIAL 0x04 ///< bit 2: initial encryption required (2.0)
60// ControlCode bit carried by a Data or DataEND message:
61#define PROTOCORE_HISLIP_DATA_RMT_DELIVERED 0x01 ///< bit 0: message delivered following a Response Message Terminator
62
63/** @brief HiSLIP MessageType codes (IVI-6.1). Codes 0-24 are HiSLIP 1.x; 25-38 were added in 2.0. */
64typedef enum PROTO_ENUM_PACKED
65{
66 HISLIP_MSG_INITIALIZE = 0,
67 HISLIP_MSG_INITIALIZE_RESPONSE = 1,
68 HISLIP_MSG_FATAL_ERROR = 2,
69 HISLIP_MSG_ERROR = 3,
70 HISLIP_MSG_ASYNC_LOCK = 4,
71 HISLIP_MSG_ASYNC_LOCK_RESPONSE = 5,
72 HISLIP_MSG_DATA = 6,
73 HISLIP_MSG_DATA_END = 7,
74 HISLIP_MSG_DEVICE_CLEAR_COMPLETE = 8,
75 HISLIP_MSG_DEVICE_CLEAR_ACKNOWLEDGE = 9,
76 HISLIP_MSG_ASYNC_REMOTE_LOCAL_CONTROL = 10,
77 HISLIP_MSG_ASYNC_REMOTE_LOCAL_RESPONSE = 11,
78 HISLIP_MSG_TRIGGER = 12,
79 HISLIP_MSG_INTERRUPTED = 13,
80 HISLIP_MSG_ASYNC_INTERRUPTED = 14,
81 HISLIP_MSG_ASYNC_MAX_MSG_SIZE = 15,
82 HISLIP_MSG_ASYNC_MAX_MSG_SIZE_RESPONSE = 16,
83 HISLIP_MSG_ASYNC_INITIALIZE = 17,
84 HISLIP_MSG_ASYNC_INITIALIZE_RESPONSE = 18,
85 HISLIP_MSG_ASYNC_DEVICE_CLEAR = 19,
86 HISLIP_MSG_ASYNC_SERVICE_REQUEST = 20,
87 HISLIP_MSG_ASYNC_STATUS_QUERY = 21,
88 HISLIP_MSG_ASYNC_STATUS_RESPONSE = 22,
89 HISLIP_MSG_ASYNC_DEVICE_CLEAR_ACKNOWLEDGE = 23,
90 HISLIP_MSG_ASYNC_LOCK_INFO = 24,
91 HISLIP_MSG_ASYNC_LOCK_INFO_RESPONSE = 25,
92 HISLIP_MSG_GET_DESCRIPTORS = 26,
93 HISLIP_MSG_GET_DESCRIPTORS_RESPONSE = 27,
94 HISLIP_MSG_START_TLS = 28,
95 HISLIP_MSG_ASYNC_START_TLS = 29,
96 HISLIP_MSG_ASYNC_START_TLS_RESPONSE = 30,
97 HISLIP_MSG_END_TLS = 31,
98 HISLIP_MSG_ASYNC_END_TLS = 32,
99 HISLIP_MSG_ASYNC_END_TLS_RESPONSE = 33,
100 HISLIP_MSG_GET_SASL_MECHANISM_LIST = 34,
101 HISLIP_MSG_GET_SASL_MECHANISM_LIST_RESPONSE = 35,
102 HISLIP_MSG_AUTHENTICATION_START = 36,
103 HISLIP_MSG_AUTHENTICATION_EXCHANGE = 37,
104 HISLIP_MSG_AUTHENTICATION_RESULT = 38,
105} HislipMsg;
106
107/** @brief A decoded HiSLIP header. */
108typedef struct
109{
110 HislipMsg type;
111 uint8_t control; ///< ControlCode (message-specific flag; 0 when undefined)
112 uint32_t parameter; ///< MessageParameter (message-specific; 0 when undefined)
113 uint64_t payload_len; ///< byte length of the payload that follows the 16-byte header
114} HislipHeader;
115
116/**
117 * @brief Build the 16-byte header into @p buf.
118 * @return 16 (@ref PROTOCORE_HISLIP_HEADER_LEN), or 0 if @p cap < 16 or @p buf is null.
119 */
120size_t protocore_hislip_build_header(uint8_t *buf, size_t cap, HislipMsg type, uint8_t control, uint32_t parameter,
121 uint64_t payload_len);
122
123/**
124 * @brief Parse a 16-byte header from the head of [buf, buf+len).
125 * @return true on a valid `"HS"` prologue with @p len >= 16; false otherwise.
126 * @note The message type is copied through even if beyond 38 (forward-compat); the caller decides.
127 */
128proto_bool protocore_hislip_parse_header(const uint8_t *buf, size_t len, HislipHeader *out);
129
130// ── handshake builders ─────────────────────────────────────────────────────────────────────────
131
132/**
133 * @brief Build an Initialize message (client -> server, sync channel): parameter = (version << 16)
134 * | vendor_id, payload = the sub-address string (e.g. "hislip0").
135 * @return total bytes written (16 + sub-address length), or 0 on overflow / bad input.
136 */
137size_t protocore_hislip_build_initialize(uint8_t *buf, size_t cap, uint16_t protocol_version, uint16_t vendor_id,
138 const char *sub_address);
139
140/**
141 * @brief Build an InitializeResponse (server -> client): control (overlap / encryption bits),
142 * parameter = (negotiated version << 16) | session_id, no payload.
143 * @return 16, or 0 on overflow.
144 */
145size_t protocore_hislip_build_initialize_response(uint8_t *buf, size_t cap, uint8_t control, uint16_t protocol_version,
146 uint16_t session_id);
147
148/**
149 * @brief Build an AsyncInitialize (client -> server, async channel): parameter = session_id, no payload.
150 * @return 16, or 0 on overflow.
151 */
152size_t protocore_hislip_build_async_initialize(uint8_t *buf, size_t cap, uint16_t session_id);
153
154/**
155 * @brief Build an AsyncInitializeResponse (server -> client): parameter = server_vendor_id, no payload.
156 * @return 16, or 0 on overflow.
157 */
158size_t protocore_hislip_build_async_initialize_response(uint8_t *buf, size_t cap, uint8_t control,
159 uint16_t server_vendor_id);
160
161/**
162 * @brief Build a Data (@p is_end false) or DataEND (@p is_end true) message carrying @p payload
163 * keyed by @p message_id (parameter). @p control is usually 0 (set @ref
164 * PROTOCORE_HISLIP_DATA_RMT_DELIVERED on a server response after a terminator).
165 * @return total bytes written (16 + payload_len), or 0 on overflow / bad input.
166 */
167size_t protocore_hislip_build_data(uint8_t *buf, size_t cap, proto_bool is_end, uint8_t control, uint32_t message_id,
168 const uint8_t *payload, size_t payload_len);
169
170/** @brief The next client MessageID (increments by 2, wraps) - see @ref PROTOCORE_HISLIP_MESSAGE_ID_INIT. */
171uint32_t protocore_hislip_next_message_id(uint32_t id);
172
173// ── handshake parsers ──────────────────────────────────────────────────────────────────────────
174
175/** @brief A decoded Initialize message. @ref sub_address points INTO the source buffer. */
176typedef struct
177{
178 uint16_t protocol_version;
179 uint16_t vendor_id;
180 const char *sub_address;
181 size_t sub_address_len;
182} HislipInitialize;
183
184/**
185 * @brief Parse a full Initialize message (header + payload) from [buf, buf+len).
186 * @return true on a complete, well-formed Initialize; false otherwise.
187 */
188proto_bool protocore_hislip_parse_initialize(const uint8_t *buf, size_t len, HislipInitialize *out);
189
190/** @brief A decoded InitializeResponse message. */
191typedef struct
192{
193 uint16_t protocol_version;
194 uint16_t session_id;
195 proto_bool overlap; ///< ControlCode bit 0 (prefer overlapped)
196 proto_bool encryption_mandatory; ///< ControlCode bit 1 (2.0)
197} HislipInitializeResponse;
198
199/**
200 * @brief Parse an InitializeResponse header from [buf, buf+len).
201 * @return true on a well-formed InitializeResponse; false otherwise.
202 */
203proto_bool protocore_hislip_parse_initialize_response(const uint8_t *buf, size_t len, HislipInitializeResponse *out);
204
206
207#endif // PROTOCORE_ENABLE_HISLIP
208
209#endif // PROTOCORE_HISLIP_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97