DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
sunspec.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 sunspec.h
6 * @brief SunSpec Modbus device-information-model codec (DETWS_ENABLE_SUNSPEC) - zero-heap
7 * model-chain walker + register-point readers and a map builder, layered on the
8 * holding-register model so a solar inverter / meter / battery is interoperable.
9 *
10 * A SunSpec map (SunSpec Device Information Model) lives in a contiguous holding-register
11 * block and is laid out as raw big-endian 16-bit registers:
12 * @code
13 * "SunS" (0x53756E53, 2 registers) // well-known identifier
14 * [Model ID][Length L][L body registers] // repeated, one per model
15 * ...
16 * [0xFFFF][0] // end model terminates the map
17 * @endcode
18 * Length L is the number of registers after the length point (the model body). Models are
19 * contiguous (no gap between them). Common model = ID 1.
20 *
21 * The reader is a cursor over the received register bytes (big-endian, 2 bytes/register):
22 * verify the marker, then walk each model and read typed points by register offset. The
23 * writer emits the same layout (marker, model headers + points, end model) for a device
24 * exposing its own map. Marker / header format verified against the SunSpec spec.
25 *
26 * @author Douglas Quigg (dstroy0)
27 * @date 2026
28 */
29
30#ifndef DETERMINISTICESPASYNCWEBSERVER_SUNSPEC_H
31#define DETERMINISTICESPASYNCWEBSERVER_SUNSPEC_H
32
33#include "ServerConfig.h"
34
35#if DETWS_ENABLE_SUNSPEC
36
37#include <stddef.h>
38#include <stdint.h>
39
40#define SUNSPEC_MARKER 0x53756E53u ///< "SunS"
41#define SUNSPEC_END_MODEL 0xFFFFu ///< end-model id
42#define SUNSPEC_COMMON_MODEL 1 ///< common model id
43
44/** @brief One model located in the register map. @ref body points INTO the source buffer. */
45struct SunSpecModel
46{
47 uint16_t id;
48 uint16_t length; ///< body registers (after the length point)
49 const uint8_t *body; ///< model body, big-endian (id+length header excluded)
50 size_t body_len; ///< length * 2 bytes
51};
52
53// ---- reader ----
54
55/** @brief True if the SunS identifier (0x53756E53) is at the head of @p regs. */
56bool sunspec_check_marker(const uint8_t *regs, size_t len);
57
58/** @brief Begin a walk: verifies the marker and sets *offset just past it (to 4). */
59bool sunspec_begin(const uint8_t *regs, size_t len, size_t *offset);
60
61/**
62 * @brief Read the model at *offset and advance past it.
63 * @return true and fills @p out for a model; false at the end model (0xFFFF) or on truncation.
64 */
65bool sunspec_next_model(const uint8_t *regs, size_t len, size_t *offset, SunSpecModel *out);
66
67// Typed point readers at a register offset within a model body (big-endian).
68uint16_t sunspec_u16(const uint8_t *body, size_t reg);
69int16_t sunspec_i16(const uint8_t *body, size_t reg);
70uint32_t sunspec_u32(const uint8_t *body, size_t reg);
71int32_t sunspec_i32(const uint8_t *body, size_t reg);
72
73/**
74 * @brief Copy a SunSpec string point (@p nregs registers, NUL-padded) into @p out.
75 * @return true on success (NUL-terminated, content up to the first NUL), false on bad args.
76 */
77bool sunspec_string(const uint8_t *body, size_t reg, size_t nregs, char *out, size_t out_cap);
78
79// ---- writer ----
80
81/** @brief Cursor for building a SunSpec map. Treat the fields as opaque. */
82struct SunSpecWriter
83{
84 uint8_t *buf;
85 size_t cap;
86 size_t pos;
87 bool error;
88};
89
90void sunspec_writer_init(SunSpecWriter *w, uint8_t *buf, size_t cap);
91bool sunspec_write_marker(SunSpecWriter *w); ///< "SunS"
92bool sunspec_write_model_header(SunSpecWriter *w, uint16_t id, uint16_t length);
93bool sunspec_write_u16(SunSpecWriter *w, uint16_t v);
94bool sunspec_write_i16(SunSpecWriter *w, int16_t v);
95bool sunspec_write_u32(SunSpecWriter *w, uint32_t v);
96bool sunspec_write_i32(SunSpecWriter *w, int32_t v);
97bool sunspec_write_string(SunSpecWriter *w, const char *s, size_t nregs); ///< nregs registers, NUL-padded
98bool sunspec_write_end_model(SunSpecWriter *w); ///< [0xFFFF][0]
99size_t sunspec_writer_finish(SunSpecWriter *w); ///< bytes written, or 0 on overflow
100
101#endif // DETWS_ENABLE_SUNSPEC
102
103#endif // DETERMINISTICESPASYNCWEBSERVER_SUNSPEC_H
User-facing configuration for DeterministicESPAsyncWebServer.