ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
hislip.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file hislip.cpp
6 * @brief HiSLIP (IVI-6.1) message codec (pure, host-tested).
7 */
8
10
11#if PC_ENABLE_HISLIP
12
14#include <string.h>
15
16size_t pc_hislip_build_header(uint8_t *buf, size_t cap, HislipMsg type, uint8_t control, uint32_t parameter,
17 uint64_t payload_len)
18{
19 if (!buf || cap < PC_HISLIP_HEADER_LEN)
20 {
21 return 0;
22 }
23 buf[0] = 'H';
24 buf[1] = 'S';
25 buf[2] = static_cast<uint8_t>(type);
26 buf[3] = control;
27 pc_wr32be(buf + 4, parameter);
28 pc_wr64be(buf + 8, payload_len);
29 return PC_HISLIP_HEADER_LEN;
30}
31
32bool pc_hislip_parse_header(const uint8_t *buf, size_t len, HislipHeader *out)
33{
34 if (!buf || !out || len < PC_HISLIP_HEADER_LEN || buf[0] != 'H' || buf[1] != 'S')
35 {
36 return false;
37 }
38 out->type = static_cast<HislipMsg>(buf[2]);
39 out->control = buf[3];
40 out->parameter = pc_rd32be(buf + 4);
41 out->payload_len = pc_rd64be(buf + 8);
42 return true;
43}
44
45// Build a header + optional payload into buf; returns total or 0 on overflow / bad input.
46static size_t build_with_payload(uint8_t *buf, size_t cap, HislipMsg type, uint8_t control, uint32_t parameter,
47 const uint8_t *payload, size_t payload_len)
48{
49 if (!buf || (payload_len && !payload))
50 {
51 return 0;
52 }
53 size_t total = PC_HISLIP_HEADER_LEN + payload_len;
54 if (cap < total)
55 {
56 return 0;
57 }
58 pc_hislip_build_header(buf, cap, type, control, parameter, payload_len);
59 if (payload_len)
60 {
61 memcpy(buf + PC_HISLIP_HEADER_LEN, payload, payload_len);
62 }
63 return total;
64}
65
66size_t pc_hislip_build_initialize(uint8_t *buf, size_t cap, uint16_t protocol_version, uint16_t vendor_id,
67 const char *sub_address)
68{
69 size_t sub_len = sub_address ? strnlen(sub_address, cap) : 0;
70 uint32_t parameter = ((uint32_t)protocol_version << 16) | vendor_id;
71 return build_with_payload(buf, cap, HislipMsg::INITIALIZE, 0, parameter, (const uint8_t *)sub_address, sub_len);
72}
73
74size_t pc_hislip_build_initialize_response(uint8_t *buf, size_t cap, uint8_t control, uint16_t protocol_version,
75 uint16_t session_id)
76{
77 uint32_t parameter = ((uint32_t)protocol_version << 16) | session_id;
78 return pc_hislip_build_header(buf, cap, HislipMsg::INITIALIZE_RESPONSE, control, parameter, 0);
79}
80
81size_t pc_hislip_build_async_initialize(uint8_t *buf, size_t cap, uint16_t session_id)
82{
83 return pc_hislip_build_header(buf, cap, HislipMsg::ASYNC_INITIALIZE, 0, session_id, 0);
84}
85
86size_t pc_hislip_build_async_initialize_response(uint8_t *buf, size_t cap, uint8_t control, uint16_t server_vendor_id)
87{
88 return pc_hislip_build_header(buf, cap, HislipMsg::ASYNC_INITIALIZE_RESPONSE, control, server_vendor_id, 0);
89}
90
91size_t pc_hislip_build_data(uint8_t *buf, size_t cap, bool is_end, uint8_t control, uint32_t message_id,
92 const uint8_t *payload, size_t payload_len)
93{
94 HislipMsg type = is_end ? HislipMsg::DATA_END : HislipMsg::DATA;
95 return build_with_payload(buf, cap, type, control, message_id, payload, payload_len);
96}
97
98uint32_t pc_hislip_next_message_id(uint32_t id)
99{
100 return id + 2; // unsigned 32-bit wrap is well-defined
101}
102
103bool pc_hislip_parse_initialize(const uint8_t *buf, size_t len, HislipInitialize *out)
104{
105 HislipHeader h;
106 if (!out || !pc_hislip_parse_header(buf, len, &h) || h.type != HislipMsg::INITIALIZE)
107 {
108 return false;
109 }
110 if (h.payload_len > (uint64_t)(len - PC_HISLIP_HEADER_LEN)) // the sub-address must be fully present
111 {
112 return false;
113 }
114 out->protocol_version = (uint16_t)(h.parameter >> 16);
115 out->vendor_id = (uint16_t)(h.parameter & 0xFFFF);
116 out->sub_address = (const char *)(buf + PC_HISLIP_HEADER_LEN);
117 out->sub_address_len = (size_t)h.payload_len;
118 return true;
119}
120
121bool pc_hislip_parse_initialize_response(const uint8_t *buf, size_t len, HislipInitializeResponse *out)
122{
123 HislipHeader h;
124 if (!out || !pc_hislip_parse_header(buf, len, &h) || h.type != HislipMsg::INITIALIZE_RESPONSE)
125 {
126 return false;
127 }
128 out->protocol_version = (uint16_t)(h.parameter >> 16);
129 out->session_id = (uint16_t)(h.parameter & 0xFFFF);
130 out->overlap = (h.control & PC_HISLIP_INITRESP_OVERLAP) != 0;
131 out->encryption_mandatory = (h.control & PC_HISLIP_INITRESP_ENC_MANDATORY) != 0;
132 return true;
133}
134
135#endif // PC_ENABLE_HISLIP
Fixed-width integer serializers into a raw uint8_t* buffer - one source of truth.
size_t pc_wr64be(uint8_t *p, uint64_t v)
Write v big-endian at p.
Definition endian.h:103
uint32_t pc_rd32be(const uint8_t *p)
Read a big-endian u32 at p.
Definition endian.h:119
uint64_t pc_rd64be(const uint8_t *p)
Read a big-endian u64 at p.
Definition endian.h:125
size_t pc_wr32be(uint8_t *p, uint32_t v)
Write v big-endian at p.
Definition endian.h:93
HiSLIP (High-Speed LAN Instrument Protocol) message codec (PC_ENABLE_HISLIP) - a zero-heap codec for ...