ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
wave.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 wave.cpp
6 * @brief IEEE 1609 WAVE codec (see wave.h).
7 */
8
10
11#if PC_ENABLE_WAVE
12
13#include <string.h>
14
15size_t pc_wave_encode_psid(uint32_t psid, uint8_t *out, size_t cap)
16{
17 // P-encoding: the number of leading 1 bits in the first octet gives the length.
18 if (psid < 0x80)
19 {
20 if (cap < 1)
21 {
22 return 0;
23 }
24 out[0] = (uint8_t)psid;
25 return 1;
26 }
27 if (psid < 0x4000)
28 {
29 if (cap < 2)
30 {
31 return 0;
32 }
33 out[0] = (uint8_t)(0x80 | (psid >> 8));
34 out[1] = (uint8_t)psid;
35 return 2;
36 }
37 if (psid < 0x200000)
38 {
39 if (cap < 3)
40 {
41 return 0;
42 }
43 out[0] = (uint8_t)(0xC0 | (psid >> 16));
44 out[1] = (uint8_t)(psid >> 8);
45 out[2] = (uint8_t)psid;
46 return 3;
47 }
48 if (cap < 4)
49 {
50 return 0;
51 }
52 out[0] = (uint8_t)(0xE0 | (psid >> 24));
53 out[1] = (uint8_t)(psid >> 16);
54 out[2] = (uint8_t)(psid >> 8);
55 out[3] = (uint8_t)psid;
56 return 4;
57}
58
59size_t pc_wave_decode_psid(const uint8_t *in, size_t len, uint32_t *psid)
60{
61 if (!in || len < 1 || !psid)
62 {
63 return 0;
64 }
65 uint8_t b0 = in[0];
66 if ((b0 & 0x80) == 0)
67 {
68 *psid = b0;
69 return 1;
70 }
71 if ((b0 & 0xC0) == 0x80)
72 {
73 if (len < 2)
74 {
75 return 0;
76 }
77 *psid = (uint32_t)((b0 & 0x3F) << 8) | in[1];
78 return 2;
79 }
80 if ((b0 & 0xE0) == 0xC0)
81 {
82 if (len < 3)
83 {
84 return 0;
85 }
86 *psid = (uint32_t)((b0 & 0x1F) << 16) | ((uint32_t)in[1] << 8) | in[2];
87 return 3;
88 }
89 if ((b0 & 0xF0) == 0xE0)
90 {
91 if (len < 4)
92 {
93 return 0;
94 }
95 *psid = (uint32_t)((b0 & 0x0F) << 24) | ((uint32_t)in[1] << 16) | ((uint32_t)in[2] << 8) | in[3];
96 return 4;
97 }
98 return 0;
99}
100
101size_t pc_wsmp_build(uint32_t psid, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t cap)
102{
103 if (!out || (payload_len && !payload) || payload_len > 255)
104 {
105 return 0;
106 }
107 if (cap < 1)
108 {
109 return 0;
110 }
111 size_t i = 0;
112 out[i++] = Wave::WSMP_VERSION; // version/subtype (low nibble = version)
113 size_t p = pc_wave_encode_psid(psid, out + i, cap - i);
114 if (!p)
115 {
116 return 0;
117 }
118 i += p;
119 if (i + 1 + payload_len > cap)
120 {
121 return 0;
122 }
123 out[i++] = (uint8_t)payload_len; // WSM length
124 if (payload_len)
125 {
126 memcpy(out + i, payload, payload_len);
127 i += payload_len;
128 }
129 return i;
130}
131
132bool pc_wsmp_parse(const uint8_t *frame, size_t len, WsmpFrame *out)
133{
134 if (!frame || !out || len < 3)
135 {
136 return false;
137 }
138 if ((frame[0] & 0x0F) != Wave::WSMP_VERSION)
139 {
140 return false;
141 }
142 uint32_t psid = 0;
143 size_t p = pc_wave_decode_psid(frame + 1, len - 1, &psid);
144 if (!p)
145 {
146 return false;
147 }
148 size_t off = 1 + p;
149 if (off + 1 > len)
150 {
151 return false;
152 }
153 uint8_t wlen = frame[off++];
154 if (off + wlen > len)
155 {
156 return false;
157 }
158 out->psid = psid;
159 out->payload = wlen ? (frame + off) : nullptr;
160 out->payload_len = wlen;
161 return true;
162}
163
164size_t pc_wave_1609dot2_wrap(uint8_t content_type, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t cap)
165{
166 if (!out || (payload_len && !payload))
167 {
168 return 0;
169 }
170 size_t n = 2 + payload_len;
171 if (n > cap)
172 {
173 return 0;
174 }
175 out[0] = Wave::WAVE_16092_VERSION;
176 out[1] = content_type;
177 if (payload_len)
178 {
179 memcpy(out + 2, payload, payload_len);
180 }
181 return n;
182}
183
184#endif // PC_ENABLE_WAVE
IEEE 1609 WAVE (WSMP + 1609.2 security envelope) codec (PC_ENABLE_WAVE).