CommRaT 2.0.0
C++20 Real-Time Messaging Framework
Loading...
Searching...
No Matches
module_config.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4#include <chrono>
5#include <optional>
6#include <vector>
7#include <rfl.hpp>
8
9namespace commrat {
10
11// ============================================================================
12// Input Mode Tags
13// ============================================================================
14
17 std::chrono::milliseconds period{100};
18};
19
21struct LoopInput {};
22
23// ============================================================================
24// Mailbox Configuration
25// ============================================================================
26
27// RACK-style mailbox index allocation
28// CMD mailboxes for outputs start at index 0
29// DATA mailboxes for inputs start after all CMD mailboxes
30// See address_helpers.hpp for address encoding: [type:8][sys:8][inst:8][mbx:8]
31
32// Default mailbox slot counts (configurable per module)
33constexpr uint32_t DEFAULT_CMD_SLOTS = 10; // Command/subscription buffering
34constexpr uint32_t DEFAULT_DATA_SLOTS = 50; // Historical buffering for getData
35
36// TODO Phase 7.5: Remove MailboxType enum once we migrate to pure mailbox_index addressing
37// Temporary compatibility: Old offset-based addressing
38enum class MailboxType : uint8_t {
39 CMD = 0, // Command/subscription mailbox (Phase 7: Should use mailbox_index 0)
40 WORK = 16, // Subscription protocol (Phase 7: Should be removed, use CMD)
41 PUBLISH = 32, // Publishing to subscribers (Phase 7: Should be removed, use CMD)
42 DATA = 48 // Input data reception (Phase 7: Should use mailbox_index N+)
43};
44
45// ============================================================================
46// Output Configuration (TaggedUnion)
47// ============================================================================
48
52 uint8_t system_id{0};
53 uint8_t instance_id{0};
54};
55
59 uint8_t system_id{0};
60 uint8_t instance_id{0};
61};
62
67 uint8_t system_id{0};
68 uint8_t instance_id{0};
69 };
70 std::vector<OutputAddress> addresses; // One per output in Outputs<>
71};
72
73using OutputConfig = rfl::TaggedUnion<"output_type", NoOutputConfig, SimpleOutputConfig, MultiOutputConfig>;
74
75// ============================================================================
76// Input Configuration (TaggedUnion)
77// ============================================================================
78
80struct NoInputConfig {};
81
84 uint8_t source_system_id{0};
86};
87
90 struct InputSource {
91 uint8_t system_id{0};
92 uint8_t instance_id{0};
93 bool is_primary{false}; // Exactly one must be primary (drives execution)
94 mutable size_t input_index{0}; // Auto-populated during subscription
95 };
96 std::vector<InputSource> sources; // Order matches Inputs<T1, T2, ...>
97 size_t history_buffer_size{100}; // Buffer capacity for getData synchronization
98 std::chrono::milliseconds sync_tolerance{50}; // Tolerance for getData calls
99};
100
101using InputConfig = rfl::TaggedUnion<"input_type", NoInputConfig, SingleInputConfig, MultiInputConfig>;
102
103// ============================================================================
104// Module Configuration
105// ============================================================================
106
108 std::string name;
109
110 // Output and input configuration (Variant)
113
114 // Common configuration
115 std::chrono::milliseconds period{100};
116 size_t message_slots{10}; // Legacy: kept for compatibility
118 int priority{10};
119 bool realtime{false};
120
121 // Mailbox-specific slot counts (RACK-style)
122 // Optional fields with defaults for backward compatibility
123 rfl::DefaultVal<uint32_t> cmd_message_slots = DEFAULT_CMD_SLOTS;
124 rfl::DefaultVal<uint32_t> data_message_slots = DEFAULT_DATA_SLOTS;
125
126 // ========================================================================
127 // Output Configuration Accessors
128 // ========================================================================
129
131 [[nodiscard]] uint8_t system_id() const {
132 if (auto* no = rfl::get_if<NoOutputConfig>(&outputs.variant())) {
133 return no->system_id;
134 } else if (auto* simple = rfl::get_if<SimpleOutputConfig>(&outputs.variant())) {
135 return simple->system_id;
136 } else {
137 throw std::logic_error("system_id() without index not valid for MultiOutputConfig - use system_id(index)");
138 }
139 }
140
142 [[nodiscard]] uint8_t instance_id() const {
143 if (auto* no = rfl::get_if<NoOutputConfig>(&outputs.variant())) {
144 return no->instance_id;
145 } else if (auto* simple = rfl::get_if<SimpleOutputConfig>(&outputs.variant())) {
146 return simple->instance_id;
147 } else {
148 throw std::logic_error("instance_id() without index not valid for MultiOutputConfig - use instance_id(index)");
149 }
150 }
151
153 [[nodiscard]] uint8_t system_id(size_t index) const {
154 auto* multi = rfl::get_if<MultiOutputConfig>(&outputs.variant());
155 if (!multi) {
156 throw std::logic_error("system_id(index) only valid for MultiOutputConfig");
157 }
158 if (index >= multi->addresses.size()) {
159 throw std::out_of_range("Output index out of range");
160 }
161 return multi->addresses[index].system_id;
162 }
163
165 [[nodiscard]] uint8_t instance_id(size_t index) const {
166 auto* multi = rfl::get_if<MultiOutputConfig>(&outputs.variant());
167 if (!multi) {
168 throw std::logic_error("instance_id(index) only valid for MultiOutputConfig");
169 }
170 if (index >= multi->addresses.size()) {
171 throw std::out_of_range("Output index out of range");
172 }
173 return multi->addresses[index].instance_id;
174 }
175
176 // ========================================================================
177 // Input Configuration Accessors
178 // ========================================================================
179
181 [[nodiscard]] uint8_t source_system_id() const {
182 auto* single = rfl::get_if<SingleInputConfig>(&inputs.variant());
183 if (!single) {
184 throw std::logic_error("source_system_id() only valid for SingleInputConfig");
185 }
186 return single->source_system_id;
187 }
188
190 [[nodiscard]] uint8_t source_instance_id() const {
191 auto* single = rfl::get_if<SingleInputConfig>(&inputs.variant());
192 if (!single) {
193 throw std::logic_error("source_instance_id() only valid for SingleInputConfig");
194 }
195 return single->source_instance_id;
196 }
197
199 [[nodiscard]] const std::vector<MultiInputConfig::InputSource>& input_sources() const {
200 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
201 if (!multi) {
202 throw std::logic_error("input_sources() only valid for MultiInputConfig");
203 }
204 return multi->sources;
205 }
206
208 [[nodiscard]] std::vector<MultiInputConfig::InputSource>& input_sources() {
209 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
210 if (!multi) {
211 throw std::logic_error("input_sources() only valid for MultiInputConfig");
212 }
213 return multi->sources;
214 }
215
217 [[nodiscard]] std::chrono::milliseconds sync_tolerance() const {
218 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
219 if (!multi) {
220 throw std::logic_error("sync_tolerance() only valid for MultiInputConfig");
221 }
222 return multi->sync_tolerance;
223 }
224
226 [[nodiscard]] size_t history_buffer_size() const {
227 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
228 if (!multi) {
229 throw std::logic_error("history_buffer_size() only valid for MultiInputConfig");
230 }
231 return multi->history_buffer_size;
232 }
233
235 [[nodiscard]] uint8_t input_system_id(size_t index) const {
236 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
237 if (!multi) {
238 throw std::logic_error("input_system_id(index) only valid for MultiInputConfig");
239 }
240 if (index >= multi->sources.size()) {
241 throw std::out_of_range("Input index out of range");
242 }
243 return multi->sources[index].system_id;
244 }
245
247 [[nodiscard]] uint8_t input_instance_id(size_t index) const {
248 auto* multi = rfl::get_if<MultiInputConfig>(&inputs.variant());
249 if (!multi) {
250 throw std::logic_error("input_instance_id(index) only valid for MultiInputConfig");
251 }
252 if (index >= multi->sources.size()) {
253 throw std::out_of_range("Input index out of range");
254 }
255 return multi->sources[index].instance_id;
256 }
257
258 // ========================================================================
259 // Type Checking Helpers
260 // ========================================================================
261
262 [[nodiscard]] bool has_no_output() const { return rfl::get_if<NoOutputConfig>(&outputs.variant()) != nullptr; }
263 [[nodiscard]] bool has_simple_output() const { return rfl::get_if<SimpleOutputConfig>(&outputs.variant()) != nullptr; }
264 [[nodiscard]] bool has_multi_output_config() const { return rfl::get_if<MultiOutputConfig>(&outputs.variant()) != nullptr; }
265
266 [[nodiscard]] bool has_no_input() const { return rfl::get_if<NoInputConfig>(&inputs.variant()) != nullptr; }
267 [[nodiscard]] bool has_single_input() const { return rfl::get_if<SingleInputConfig>(&inputs.variant()) != nullptr; }
268 [[nodiscard]] bool has_multi_input_config() const { return rfl::get_if<MultiInputConfig>(&inputs.variant()) != nullptr; }
269};
270
271} // namespace commrat
CommRaT - Modern C++ Real-Time Communication Framework.
constexpr uint32_t DEFAULT_CMD_SLOTS
rfl::TaggedUnion<"input_type", NoInputConfig, SingleInputConfig, MultiInputConfig > InputConfig
constexpr uint32_t DEFAULT_DATA_SLOTS
rfl::TaggedUnion<"output_type", NoOutputConfig, SimpleOutputConfig, MultiOutputConfig > OutputConfig
Free-running loop - module runs as fast as possible, no input data.
uint8_t input_system_id(size_t index) const
Get source system_id at index (MultiInput only)
std::chrono::milliseconds sync_tolerance() const
Get sync_tolerance (MultiInput only)
rfl::DefaultVal< uint32_t > data_message_slots
rfl::DefaultVal< uint32_t > cmd_message_slots
bool has_single_input() const
uint8_t system_id() const
Get system_id - NoOutput or SimpleOutput only.
uint8_t instance_id() const
Get instance_id - NoOutput or SimpleOutput only.
const std::vector< MultiInputConfig::InputSource > & input_sources() const
Get input sources (MultiInput only)
uint8_t source_system_id() const
Get source_system_id (SingleInput only)
uint8_t system_id(size_t index) const
Get system_id for specific output index (MultiOutput only)
uint8_t instance_id(size_t index) const
Get instance_id for specific output index (MultiOutput only)
uint8_t source_instance_id() const
Get source_instance_id (SingleInput only)
bool has_multi_input_config() const
size_t history_buffer_size() const
Get history_buffer_size (MultiInput only)
std::chrono::milliseconds period
uint8_t input_instance_id(size_t index) const
Get source instance_id at index (MultiInput only)
bool has_multi_output_config() const
bool has_simple_output() const
std::vector< MultiInputConfig::InputSource > & input_sources()
Get mutable input sources (MultiInput only) - for populating input_index.
Multi-input - Multiple synchronized sources.
std::vector< InputSource > sources
std::chrono::milliseconds sync_tolerance
Multi-output - Each output gets its own addressing Use when multiple outputs have same type (would co...
std::vector< OutputAddress > addresses
No input - Periodic or LoopInput modules only.
No output - Module only consumes inputs (logger, monitor, controller) Still needs addressing for CMD/...
Periodic execution - module runs on a timer, no input data.
std::chrono::milliseconds period
Simple output - All outputs share same system_id/instance_id Use when output types are distinct (no c...
Single input - One source module.