DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
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 DETWS_ENABLE_WAVE
12
13#include <string.h>
14
15size_t detws_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 return 0;
22 out[0] = (uint8_t)psid;
23 return 1;
24 }
25 if (psid < 0x4000)
26 {
27 if (cap < 2)
28 return 0;
29 out[0] = (uint8_t)(0x80 | (psid >> 8));
30 out[1] = (uint8_t)psid;
31 return 2;
32 }
33 if (psid < 0x200000)
34 {
35 if (cap < 3)
36 return 0;
37 out[0] = (uint8_t)(0xC0 | (psid >> 16));
38 out[1] = (uint8_t)(psid >> 8);
39 out[2] = (uint8_t)psid;
40 return 3;
41 }
42 if (cap < 4)
43 return 0;
44 out[0] = (uint8_t)(0xE0 | (psid >> 24));
45 out[1] = (uint8_t)(psid >> 16);
46 out[2] = (uint8_t)(psid >> 8);
47 out[3] = (uint8_t)psid;
48 return 4;
49}
50
51size_t detws_wave_decode_psid(const uint8_t *in, size_t len, uint32_t *psid)
52{
53 if (!in || len < 1 || !psid)
54 return 0;
55 uint8_t b0 = in[0];
56 if ((b0 & 0x80) == 0)
57 {
58 *psid = b0;
59 return 1;
60 }
61 if ((b0 & 0xC0) == 0x80)
62 {
63 if (len < 2)
64 return 0;
65 *psid = (uint32_t)((b0 & 0x3F) << 8) | in[1];
66 return 2;
67 }
68 if ((b0 & 0xE0) == 0xC0)
69 {
70 if (len < 3)
71 return 0;
72 *psid = (uint32_t)((b0 & 0x1F) << 16) | ((uint32_t)in[1] << 8) | in[2];
73 return 3;
74 }
75 if ((b0 & 0xF0) == 0xE0)
76 {
77 if (len < 4)
78 return 0;
79 *psid = (uint32_t)((b0 & 0x0F) << 24) | ((uint32_t)in[1] << 16) | ((uint32_t)in[2] << 8) | in[3];
80 return 4;
81 }
82 return 0;
83}
84
85size_t detws_wsmp_build(uint32_t psid, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t cap)
86{
87 if (!out || (payload_len && !payload) || payload_len > 255)
88 return 0;
89 if (cap < 1)
90 return 0;
91 size_t i = 0;
92 out[i++] = Wave::WSMP_VERSION; // version/subtype (low nibble = version)
93 size_t p = detws_wave_encode_psid(psid, out + i, cap - i);
94 if (!p)
95 return 0;
96 i += p;
97 if (i + 1 + payload_len > cap)
98 return 0;
99 out[i++] = (uint8_t)payload_len; // WSM length
100 if (payload_len)
101 {
102 memcpy(out + i, payload, payload_len);
103 i += payload_len;
104 }
105 return i;
106}
107
108bool detws_wsmp_parse(const uint8_t *frame, size_t len, WsmpFrame *out)
109{
110 if (!frame || !out || len < 3)
111 return false;
112 if ((frame[0] & 0x0F) != Wave::WSMP_VERSION)
113 return false;
114 uint32_t psid = 0;
115 size_t p = detws_wave_decode_psid(frame + 1, len - 1, &psid);
116 if (!p)
117 return false;
118 size_t off = 1 + p;
119 if (off + 1 > len)
120 return false;
121 uint8_t wlen = frame[off++];
122 if (off + wlen > len)
123 return false;
124 out->psid = psid;
125 out->payload = wlen ? (frame + off) : nullptr;
126 out->payload_len = wlen;
127 return true;
128}
129
130size_t detws_wave_1609dot2_wrap(uint8_t content_type, const uint8_t *payload, size_t payload_len, uint8_t *out,
131 size_t cap)
132{
133 if (!out || (payload_len && !payload))
134 return 0;
135 size_t n = 2 + payload_len;
136 if (n > cap)
137 return 0;
138 out[0] = Wave::WAVE_16092_VERSION;
139 out[1] = content_type;
140 if (payload_len)
141 memcpy(out + 2, payload, payload_len);
142 return n;
143}
144
145#endif // DETWS_ENABLE_WAVE
IEEE 1609 WAVE (WSMP + 1609.2 security envelope) codec (DETWS_ENABLE_WAVE).