moddef-cpp
Idiomatic C++ runtime for ModDef
Loading...
Searching...
No Matches
moddef-cpp

Idiomatic C++ runtime for ModDef (spec v0.4) — a thin, header-only wrapper over the moddef-c core (vendored as a submodule). The C engine does the in-place binary parsing and codec; C++ adds RAII, std::expected error handling, a typed Value, and a virtual Transport. Requires C++23; exception-free (builds under -fno-exceptions).

auto doc = moddef::Document::view(flash_bytes).value(); // zero-copy over flash
MyTransport transport; // : moddef::Transport
auto dev = moddef::Device::open(doc, "growatt-sph", transport).value();
if (auto v = dev->read("pv1_voltage"); v && v->as_f64())
printf("%.1f V\n", *v->as_f64()); // 230.5
dev->write_f64("stop_soc", 80.0); // §11.4 validated
static Result< Device > open(const Document &doc, std::string_view device_id, Transport &transport)
Bind transport to the named profile in doc (empty id = first).
Definition device.hpp:36
static Result< Document > view(std::span< const std::uint8_t > bytes)
View over external bytes (no copy).
Definition document.hpp:36
moddef-cpp — idiomatic C++ runtime for ModDef (spec v0.4).

moddef::Transport is an abstract base with six std::span-based methods — implement them over your Modbus stack:

struct MyTransport : moddef::Transport {
moddef::Result<void> read_holding(uint16_t off, std::span<uint16_t> out) override { /* ... */ }
// read_input, read_coils, read_discrete, write_holding, write_coil
};
Blocking register-level transport.
Definition transport.hpp:28
virtual Result< void > read_holding(std::uint16_t offset, std::span< std::uint16_t > out)=0
std::expected< T, Error > Result
The canonical result type across the API; Result<void> for actions.
Definition error.hpp:53

An unavailable reading (§8.4 sentinel) is a Value state, not an error:

auto v = dev->read("battery_soc");
if (v && v->is_unavailable()) log("no data: %s", v->unavailable_meaning().data());

Building

git clone --recursive https://github.com/ModDefOrg/moddef-cpp
# or: git submodule update --init --recursive

CMake is the supported consumer path:

add_subdirectory(moddef-cpp)
target_link_libraries(app PRIVATE moddef::cpp) # header-only C++ + moddef-c sources

Development:

make test # host tests over binary docs + a mock transport
make examples # superloop sketch
make thumb # arm-none-eabi-g++ Cortex-M4 build (-fno-exceptions -fno-rtti)

Tests convert small fixtures to binary with moddef-py (a sibling checkout with a .venv), the same host tooling the C runtime uses.

Scope

Point and string reads/writes, constrained writes, and SunSpec discovery — mirroring moddef-c. See DESIGN.md for the wrapper's design and the move-safety notes. For older toolchains without C++23, use moddef-c directly.

License of generated output

Code generated from a ModDef document (for example by moddef gen) is not a derivative work of the ModDef tooling or runtime. You may license the generated output under any terms you choose. The runtime it imports (this library) is Apache-2.0 licensed; see the LICENSE file for its terms, which apply only to the runtime, not to your generated code.

License

Apache-2.0. See [LICENSE](LICENSE), [NOTICE](NOTICE), and CONTRIBUTING.md.