ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
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 PC_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 {
24 c = (uint8_t)(c ^ from_len[i]);
25 }
26 return c;
27}
28} // namespace
29
30uint16_t pc_zwave_build_frame(pc_zwave_type type, uint8_t cmd, const uint8_t *data, uint8_t data_len, uint8_t *out,
31 uint16_t cap)
32{
33 if (!out || data_len > PC_ZWAVE_MAX_DATA || (data == nullptr && data_len > 0))
34 {
35 return 0;
36 }
37 uint8_t frame_len = (uint8_t)(data_len + 3); // Type + Command + Data + Checksum
38 uint16_t total = (uint16_t)(2 + frame_len); // SOF + LEN + frame_len bytes
39 if (total > cap)
40 {
41 return 0;
42 }
43 out[0] = Zwave::ZWAVE_SOF;
44 out[1] = frame_len;
45 out[2] = (uint8_t)type;
46 out[3] = cmd;
47 for (uint8_t i = 0; i < data_len; i++)
48 {
49 out[4 + i] = data[i];
50 }
51 // Checksum folds LEN..last-data = out[1 .. 1+frame_len-1] = out[1..frame_len].
52 out[1 + frame_len] = checksum(&out[1], frame_len);
53 return total;
54}
55
56int pc_zwave_parse_frame(const uint8_t *raw, uint16_t len, uint8_t *type, uint8_t *cmd, const uint8_t **pdata,
57 uint8_t *pdata_len)
58{
59 if (!raw || len < 1)
60 {
61 return 0;
62 }
63 if (raw[0] != Zwave::ZWAVE_SOF)
64 {
65 return -1; // not a data frame (could be a control byte - test those first)
66 }
67 if (len < 2)
68 {
69 return 0;
70 }
71 uint8_t frame_len = raw[1];
72 if (frame_len < 3 || frame_len > PC_ZWAVE_MAX_DATA + 3)
73 {
74 return -1; // too short for Type+Cmd+Checksum, or implausibly long
75 }
76 uint16_t total = (uint16_t)(2 + frame_len);
77 if (len < total)
78 {
79 return 0; // wait for the rest
80 }
81 if (checksum(&raw[1], frame_len) != raw[1 + frame_len])
82 {
83 return -1; // checksum mismatch
84 }
85 if (type)
86 {
87 *type = raw[2];
88 }
89 if (cmd)
90 {
91 *cmd = raw[3];
92 }
93 if (pdata)
94 {
95 *pdata = &raw[4];
96 }
97 if (pdata_len)
98 {
99 *pdata_len = (uint8_t)(frame_len - 3);
100 }
101 return (int)total;
102}
103
104bool pc_zwave_is_ack(uint8_t b)
105{
106 return b == Zwave::ZWAVE_ACK;
107}
108bool pc_zwave_is_nak(uint8_t b)
109{
110 return b == Zwave::ZWAVE_NAK;
111}
112bool pc_zwave_is_can(uint8_t b)
113{
114 return b == Zwave::ZWAVE_CAN;
115}
116
117uint16_t pc_zwave_build_ack(uint8_t *out, uint16_t cap)
118{
119 if (!out || cap < 1)
120 {
121 return 0;
122 }
123 out[0] = Zwave::ZWAVE_ACK;
124 return 1;
125}
126
127#endif // PC_ENABLE_ZWAVE
#define PC_ZWAVE_MAX_DATA
Reject a Z-Wave frame whose declared length exceeds this data cap (sanity).
Z-Wave Serial API frame codec (PC_ENABLE_ZWAVE) - Silicon Labs controller.