ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
sunspec.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - 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 (PROTOCORE_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 PROTOCORE_SUNSPEC_H
31#define PROTOCORE_SUNSPEC_H
32
33#include "protocore_config.h" // the entry point: protocore_types.h for the widths
34
35#if PROTOCORE_ENABLE_SUNSPEC
36
38
39#define SUNSPEC_MARKER 0x53756E53u ///< "SunS"
40#define SUNSPEC_END_MODEL 0xFFFFu ///< end-model id
41#define SUNSPEC_COMMON_MODEL 1 ///< common model id
42
43/** @brief One model located in the register map. @ref body points INTO the source buffer. */
44typedef struct
45{
46 uint16_t id;
47 uint16_t length; ///< body registers (after the length point)
48 const uint8_t *body; ///< model body, big-endian (id+length header excluded)
49 size_t body_len; ///< length * 2 bytes
50} SunSpecModel;
51
52// ---- reader ----
53
54/** @brief True if the SunS identifier (0x53756E53) is at the head of @p regs. */
55proto_bool protocore_sunspec_check_marker(const uint8_t *regs, size_t len);
56
57/** @brief Begin a walk: verifies the marker and sets *offset just past it (to 4). */
58proto_bool protocore_sunspec_begin(const uint8_t *regs, size_t len, size_t *offset);
59
60/**
61 * @brief Read the model at *offset and advance past it.
62 * @return true and fills @p out for a model; false at the end model (0xFFFF) or on truncation.
63 */
64proto_bool protocore_sunspec_next_model(const uint8_t *regs, size_t len, size_t *offset, SunSpecModel *out);
65
66// Typed point readers at a register offset within a model body (big-endian).
67uint16_t protocore_sunspec_u16(const uint8_t *body, size_t reg);
68int16_t protocore_sunspec_i16(const uint8_t *body, size_t reg);
69uint32_t protocore_sunspec_u32(const uint8_t *body, size_t reg);
70int32_t protocore_sunspec_i32(const uint8_t *body, size_t reg);
71
72/**
73 * @brief Copy a SunSpec string point (@p nregs registers, NUL-padded) into @p out.
74 * @return true on success (NUL-terminated, content up to the first NUL), false on bad args.
75 */
76proto_bool protocore_sunspec_string(const uint8_t *body, size_t reg, size_t nregs, char *out, size_t out_cap);
77
78// ---- writer ----
79
80/** @brief Cursor for building a SunSpec map. Treat the fields as opaque. */
81typedef struct
82{
83 uint8_t *buf;
84 size_t cap;
85 size_t pos;
86 proto_bool error;
87} SunSpecWriter;
88
89void protocore_sunspec_writer_init(SunSpecWriter *w, uint8_t *buf, size_t cap);
90proto_bool protocore_sunspec_write_marker(SunSpecWriter *w); ///< "SunS"
91proto_bool protocore_sunspec_write_model_header(SunSpecWriter *w, uint16_t id, uint16_t length);
92proto_bool protocore_sunspec_write_u16(SunSpecWriter *w, uint16_t v);
93proto_bool protocore_sunspec_write_i16(SunSpecWriter *w, int16_t v);
94proto_bool protocore_sunspec_write_u32(SunSpecWriter *w, uint32_t v);
95proto_bool protocore_sunspec_write_i32(SunSpecWriter *w, int32_t v);
96proto_bool protocore_sunspec_write_string(SunSpecWriter *w, const char *s,
97 size_t nregs); ///< nregs registers, NUL-padded
98proto_bool protocore_sunspec_write_end_model(SunSpecWriter *w); ///< [0xFFFF][0]
99size_t protocore_sunspec_writer_finish(SunSpecWriter *w); ///< bytes written, or 0 on overflow
100
102
103#endif // PROTOCORE_ENABLE_SUNSPEC
104
105#endif // PROTOCORE_SUNSPEC_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97