DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
zwave.h
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.h
6 * @brief Z-Wave Serial API frame codec (DETWS_ENABLE_ZWAVE) - Silicon Labs controller.
7 *
8 * The host-side Serial API of a Silicon Labs 500 / 700-series Z-Wave controller reached
9 * over UART: a Z-Wave mesh bridged to the web. The host and the controller exchange **data
10 * frames**:
11 *
12 * SOF (0x01) | LEN | Type | Command | Data... | Checksum
13 *
14 * where LEN counts Type + Command + Data + Checksum, Type is 0x00 (REQ) or 0x01 (RES), and
15 * the checksum is 0xFF XOR-folded over LEN through the last Data byte. Each data frame is
16 * acknowledged by a single-byte **ACK (0x06)**, or rejected with **NAK (0x15)** / **CAN
17 * (0x18)**.
18 *
19 * zwave_build_frame() assembles a data frame carrying a function command, zwave_parse_frame()
20 * frames + verifies one, and zwave_is_ack() / zwave_is_nak() / zwave_is_can() /
21 * zwave_build_ack() handle the flow-control bytes. The per-command payload (GetVersion,
22 * SendData, AddNodeToNetwork, an ApplicationCommandHandler report, ...) is the application's.
23 * Pure - you carry the bytes over your UART - so it is fully host-testable.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef DETERMINISTICESPASYNCWEBSERVER_ZWAVE_H
30#define DETERMINISTICESPASYNCWEBSERVER_ZWAVE_H
31
32#include "ServerConfig.h"
33
34#if DETWS_ENABLE_ZWAVE
35
36#include <stddef.h>
37#include <stdint.h>
38
39/** @brief Z-Wave Serial API control bytes / frame markers. */
40struct Zwave
41{
42 static constexpr uint8_t ZWAVE_SOF = 0x01; ///< start of a data frame
43 static constexpr uint8_t ZWAVE_ACK = 0x06; ///< frame acknowledged
44 static constexpr uint8_t ZWAVE_NAK = 0x15; ///< frame rejected (checksum)
45 static constexpr uint8_t ZWAVE_CAN = 0x18; ///< frame cancelled (retransmit)
46};
47
48/** @brief Data-frame type. */
49enum class zwave_type : uint8_t
50{
51 ZWAVE_REQ = 0x00, ///< request
52 ZWAVE_RES = 0x01, ///< response
53};
54
55/**
56 * @brief Assemble a data frame carrying @p type + @p cmd + @p data into @p out.
57 * @return the total frame length, or 0 if it would not fit @p cap or @p data_len exceeds
58 * DETWS_ZWAVE_MAX_DATA.
59 */
60uint16_t zwave_build_frame(zwave_type type, uint8_t cmd, const uint8_t *data, uint8_t data_len, uint8_t *out,
61 uint16_t cap);
62
63/**
64 * @brief Frame one data frame from the front of @p raw and verify the checksum.
65 * @param[out] type set to the frame type (REQ / RES).
66 * @param[out] cmd set to the function command byte.
67 * @param[out] pdata set to the first payload byte (points into @p raw).
68 * @param[out] pdata_len set to the payload length.
69 * @return the frame length consumed (> 0), 0 if more bytes are needed, or -1 if @p raw[0]
70 * does not start a valid data frame (not SOF / bad length / bad checksum). A single
71 * control byte (ACK / NAK / CAN) is not a data frame - test it with the helpers
72 * below before calling this.
73 */
74int zwave_parse_frame(const uint8_t *raw, uint16_t len, uint8_t *type, uint8_t *cmd, const uint8_t **pdata,
75 uint8_t *pdata_len);
76
77/** @brief True if @p b is the ACK control byte. */
78bool zwave_is_ack(uint8_t b);
79/** @brief True if @p b is the NAK control byte. */
80bool zwave_is_nak(uint8_t b);
81/** @brief True if @p b is the CAN control byte. */
82bool zwave_is_can(uint8_t b);
83
84/** @brief Write the single ACK byte into @p out. @return 1, or 0 if @p cap < 1. */
85uint16_t zwave_build_ack(uint8_t *out, uint16_t cap);
86
87#endif // DETWS_ENABLE_ZWAVE
88
89#endif // DETERMINISTICESPASYNCWEBSERVER_ZWAVE_H
User-facing configuration for DeterministicESPAsyncWebServer.