DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
zwave.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 zwave.cpp
6 * @brief Z-Wave Serial API frame codec - implementation.
7 *
8 * Data frame: SOF | LEN | Type | Command | Data | Checksum, where LEN counts Type..Checksum
9 * and Checksum = 0xFF XOR-folded over LEN..last-data (Silicon Labs Serial API spec).
10 */
11
13
14#if DETWS_ENABLE_ZWAVE
15
16namespace
17{
18// Checksum: 0xFF XORed with every byte from LEN through the last data byte.
19uint8_t checksum(const uint8_t *from_len, uint16_t n)
20{
21 uint8_t c = 0xFF;
22 for (uint16_t i = 0; i < n; i++)
23 c = (uint8_t)(c ^ from_len[i]);
24 return c;
25}
26} // namespace
27
28uint16_t zwave_build_frame(zwave_type type, uint8_t cmd, const uint8_t *data, uint8_t data_len, uint8_t *out,
29 uint16_t cap)
30{
31 if (!out || data_len > DETWS_ZWAVE_MAX_DATA || (data == nullptr && data_len > 0))
32 return 0;
33 uint8_t frame_len = (uint8_t)(data_len + 3); // Type + Command + Data + Checksum
34 uint16_t total = (uint16_t)(2 + frame_len); // SOF + LEN + frame_len bytes
35 if (total > cap)
36 return 0;
37 out[0] = Zwave::ZWAVE_SOF;
38 out[1] = frame_len;
39 out[2] = (uint8_t)type;
40 out[3] = cmd;
41 for (uint8_t i = 0; i < data_len; i++)
42 out[4 + i] = data[i];
43 // Checksum folds LEN..last-data = out[1 .. 1+frame_len-1] = out[1..frame_len].
44 out[1 + frame_len] = checksum(&out[1], frame_len);
45 return total;
46}
47
48int zwave_parse_frame(const uint8_t *raw, uint16_t len, uint8_t *type, uint8_t *cmd, const uint8_t **pdata,
49 uint8_t *pdata_len)
50{
51 if (!raw || len < 1)
52 return 0;
53 if (raw[0] != Zwave::ZWAVE_SOF)
54 return -1; // not a data frame (could be a control byte - test those first)
55 if (len < 2)
56 return 0;
57 uint8_t frame_len = raw[1];
58 if (frame_len < 3 || frame_len > DETWS_ZWAVE_MAX_DATA + 3)
59 return -1; // too short for Type+Cmd+Checksum, or implausibly long
60 uint16_t total = (uint16_t)(2 + frame_len);
61 if (len < total)
62 return 0; // wait for the rest
63 if (checksum(&raw[1], frame_len) != raw[1 + frame_len])
64 return -1; // checksum mismatch
65 if (type)
66 *type = raw[2];
67 if (cmd)
68 *cmd = raw[3];
69 if (pdata)
70 *pdata = &raw[4];
71 if (pdata_len)
72 *pdata_len = (uint8_t)(frame_len - 3);
73 return (int)total;
74}
75
76bool zwave_is_ack(uint8_t b)
77{
78 return b == Zwave::ZWAVE_ACK;
79}
80bool zwave_is_nak(uint8_t b)
81{
82 return b == Zwave::ZWAVE_NAK;
83}
84bool zwave_is_can(uint8_t b)
85{
86 return b == Zwave::ZWAVE_CAN;
87}
88
89uint16_t zwave_build_ack(uint8_t *out, uint16_t cap)
90{
91 if (!out || cap < 1)
92 return 0;
93 out[0] = Zwave::ZWAVE_ACK;
94 return 1;
95}
96
97#endif // DETWS_ENABLE_ZWAVE
#define DETWS_ZWAVE_MAX_DATA
Reject a Z-Wave frame whose declared length exceeds this data cap (sanity).
Z-Wave Serial API frame codec (DETWS_ENABLE_ZWAVE) - Silicon Labs controller.