Icarus
Vehicle Simulation as a Transformable Computational Graph, built on Vulcan and Janus
Loading...
Searching...
No Matches
Backplane.hpp
Go to the documentation of this file.
1#pragma once
2
10
16#include <string>
17#include <vector>
18#include <vulcan/time/Epoch.hpp>
19
20namespace icarus {
21
32template <typename Scalar> class Backplane {
33 public:
35
36 // =========================================================================
37 // Context Management
38 // =========================================================================
39
45 void set_context(const std::string &entity, const std::string &component) {
46 entity_ = entity;
47 component_ = component;
48 registry_.set_current_component(full_prefix());
49 }
50
56 void set_epoch(const vulcan::time::Epoch<Scalar> *epoch) { epoch_ = epoch; }
57
64 template <typename ComponentType> void bind_epoch_to(ComponentType &comp) {
65 comp.BindEpoch(epoch_);
66 }
67
72 entity_.clear();
73 component_.clear();
74 registry_.clear_current_component();
75 }
76
80 [[nodiscard]] std::string full_prefix() const {
81 if (entity_.empty())
82 return component_;
83 return entity_ + "." + component_;
84 }
85
86 // =========================================================================
87 // Output Registration (Provision phase)
88 // =========================================================================
89
98 template <typename T>
99 void register_output(const std::string &local_name, T *data_ptr, const std::string &unit = "",
100 const std::string &description = "") {
101 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
102 std::string full_name = make_full_name(local_name);
103 registry_.template register_output<T>(full_name, data_ptr, unit, description);
104 registered_outputs_.push_back(full_name);
105 }
106
110 template <typename S>
111 void register_output_vec3(const std::string &local_name, Vec3<S> *data_ptr,
112 const std::string &unit = "", const std::string &description = "") {
113 std::string full_name = make_full_name(local_name);
114 registry_.template register_output_vec3<S>(full_name, data_ptr, unit, description);
115 registered_outputs_.push_back(full_name + ".x");
116 registered_outputs_.push_back(full_name + ".y");
117 registered_outputs_.push_back(full_name + ".z");
118 }
119
123 template <typename S>
124 void register_output_quat(const std::string &local_name, Vec4<S> *data_ptr,
125 const std::string &unit = "", const std::string &description = "") {
126 std::string full_name = make_full_name(local_name);
127 registry_.template register_output_quat<S>(full_name, data_ptr, unit, description);
128 registered_outputs_.push_back(full_name + ".w");
129 registered_outputs_.push_back(full_name + ".x");
130 registered_outputs_.push_back(full_name + ".y");
131 registered_outputs_.push_back(full_name + ".z");
132 }
133
134 // =========================================================================
135 // Phase 6: State Registration (Unified Signal Model)
136 // =========================================================================
137
151 template <typename T>
152 void register_state(const std::string &local_name, T *value, T *derivative,
153 const std::string &unit = "", const std::string &description = "") {
154 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
155 std::string full_name = make_full_name(local_name);
156 registry_.template register_state<T>(full_name, value, derivative, unit, description);
157 registered_outputs_.push_back(full_name);
158 registered_outputs_.push_back(full_name + "_dot");
159 }
160
166 template <typename S>
167 void register_state_vec3(const std::string &local_name, Vec3<S> *value, Vec3<S> *derivative,
168 const std::string &unit = "", const std::string &description = "") {
169 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
170 std::string full_name = make_full_name(local_name);
171 registry_.template register_state_vec3<S>(full_name, value, derivative, unit, description);
172 // Track the output signals created
173 registered_outputs_.push_back(full_name + ".x");
174 registered_outputs_.push_back(full_name + ".y");
175 registered_outputs_.push_back(full_name + ".z");
176 registered_outputs_.push_back(full_name + "_dot.x");
177 registered_outputs_.push_back(full_name + "_dot.y");
178 registered_outputs_.push_back(full_name + "_dot.z");
179 }
180
186 template <typename S>
187 void register_state_quat(const std::string &local_name, Vec4<S> *value, Vec4<S> *derivative,
188 const std::string &unit = "", const std::string &description = "") {
189 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
190 std::string full_name = make_full_name(local_name);
191 registry_.template register_state_quat<S>(full_name, value, derivative, unit, description);
192 // Track the output signals created
193 registered_outputs_.push_back(full_name + ".w");
194 registered_outputs_.push_back(full_name + ".x");
195 registered_outputs_.push_back(full_name + ".y");
196 registered_outputs_.push_back(full_name + ".z");
197 registered_outputs_.push_back(full_name + "_dot.w");
198 registered_outputs_.push_back(full_name + "_dot.x");
199 registered_outputs_.push_back(full_name + "_dot.y");
200 registered_outputs_.push_back(full_name + "_dot.z");
201 }
202
203 // =========================================================================
204 // Input Resolution (Stage phase)
205 // =========================================================================
206
215 template <typename T> [[nodiscard]] SignalHandle<T> resolve(const std::string &full_name) {
216 resolved_inputs_.push_back(full_name);
217 return registry_.template resolve<T>(full_name);
218 }
219
223 template <typename S> [[nodiscard]] Vec3Handle<S> resolve_vec3(const std::string &full_name) {
224 resolved_inputs_.push_back(full_name + ".x");
225 resolved_inputs_.push_back(full_name + ".y");
226 resolved_inputs_.push_back(full_name + ".z");
227 return registry_.template resolve_vec3<S>(full_name);
228 }
229
233 template <typename S> [[nodiscard]] QuatHandle<S> resolve_quat(const std::string &full_name) {
234 resolved_inputs_.push_back(full_name + ".w");
235 resolved_inputs_.push_back(full_name + ".x");
236 resolved_inputs_.push_back(full_name + ".y");
237 resolved_inputs_.push_back(full_name + ".z");
238 return registry_.template resolve_quat<S>(full_name);
239 }
240
244 [[nodiscard]] bool has_signal(const std::string &full_name) const {
245 return registry_.HasSignal(full_name);
246 }
247
248 // =========================================================================
249 // Phase 2.4: Input Registration
250 // =========================================================================
251
261 template <typename T>
262 void register_input(const std::string &local_name, InputHandle<T> *handle,
263 const std::string &units = "", const std::string &description = "") {
264 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
265 std::string full_name = make_full_name(local_name);
266 handle->set_name(local_name);
267 handle->set_full_name(full_name);
268 registry_.template register_input<T>(full_name, handle, units, description);
269 registered_inputs_.push_back(full_name);
270 }
271
272 // =========================================================================
273 // Phase 2.4: Parameter Registration
274 // =========================================================================
275
279 void register_param(const std::string &local_name, Scalar *storage, Scalar initial_value,
280 const std::string &units = "", const std::string &description = "") {
281 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
282 std::string full_name = make_full_name(local_name);
283 registry_.register_param(full_name, storage, initial_value, units, description);
284 registered_params_.push_back(full_name);
285 }
286
287 // =========================================================================
288 // Phase 2.4: Config Registration
289 // =========================================================================
290
294 void register_config(const std::string &local_name, int *storage, int initial_value,
295 const std::string &description = "") {
296 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
297 std::string full_name = make_full_name(local_name);
298 registry_.register_config(full_name, storage, initial_value, description);
299 registered_config_.push_back(full_name);
300 }
301
305 void register_config(const std::string &local_name, bool *storage, bool initial_value,
306 const std::string &description = "") {
307 ICARUS_ASSERT(!component_.empty(), "Context must be set before registration");
308 std::string full_name = make_full_name(local_name);
309 registry_.register_config(full_name, storage, initial_value, description);
310 registered_config_.push_back(full_name);
311 }
312
313 // =========================================================================
314 // Phase 2.4: Wiring
315 // =========================================================================
316
320 template <typename T>
321 void wire_input(const std::string &input_name, const std::string &source_name) {
322 registry_.template wire_input<T>(input_name, source_name);
323 }
324
325 // =========================================================================
326 // Phase 4.0: Semantic Port Declaration
327 // =========================================================================
328 // These are semantic aliases for register_output/register_input that
329 // clarify the Phase 4.0 pattern: components DECLARE ports, SignalRouter WIRES them.
330
342 template <typename T>
343 void declare_output(const std::string &local_name, T *data_ptr, const std::string &unit = "",
344 const std::string &description = "") {
345 register_output<T>(local_name, data_ptr, unit, description);
346 }
347
351 template <typename S>
352 void declare_output_vec3(const std::string &local_name, Vec3<S> *data_ptr,
353 const std::string &unit = "", const std::string &description = "") {
354 register_output_vec3<S>(local_name, data_ptr, unit, description);
355 }
356
368 template <typename T>
369 void declare_input(const std::string &local_name, InputHandle<T> *handle,
370 const std::string &unit = "", const std::string &description = "") {
371 register_input<T>(local_name, handle, unit, description);
372 }
373
374 // =========================================================================
375 // Phase 4.0: Wiring with Gain
376 // =========================================================================
377
388 template <typename T>
389 void WireWithGain(const std::string &input_path, const std::string &output_path,
390 double gain = 1.0) {
391 registry_.template wire_input_with_gain<T>(input_path, output_path, gain);
392 }
393
399 void WireWithGain(const std::string &input_path, const std::string &output_path,
400 double gain = 1.0) {
401 registry_.wire_input_with_gain(input_path, output_path, gain);
402 }
403
404 // =========================================================================
405 // Phase 4.0: Signal Validation
406 // =========================================================================
407
411 [[nodiscard]] bool HasOutput(const std::string &full_name) const {
412 return registry_.HasOutput(full_name);
413 }
414
418 [[nodiscard]] bool HasInput(const std::string &full_name) const {
419 return registry_.HasInput(full_name);
420 }
421
427 [[nodiscard]] std::vector<std::string> GetDeclaredInputs() const {
428 return registry_.GetAllInputPaths();
429 }
430
434 [[nodiscard]] std::vector<std::string> GetDeclaredOutputs() const {
435 return registry_.GetAllOutputPaths();
436 }
437
438 // =========================================================================
439 // Dependency Tracking
440 // =========================================================================
441
445 [[nodiscard]] const std::vector<std::string> &registered_outputs() const {
446 return registered_outputs_;
447 }
448
452 [[nodiscard]] const std::vector<std::string> &registered_inputs() const {
453 return registered_inputs_;
454 }
455
459 [[nodiscard]] const std::vector<std::string> &resolved_inputs() const {
460 return resolved_inputs_;
461 }
462
466 [[nodiscard]] const std::vector<std::string> &registered_params() const {
467 return registered_params_;
468 }
469
473 [[nodiscard]] const std::vector<std::string> &registered_config() const {
474 return registered_config_;
475 }
476
481 registered_outputs_.clear();
482 registered_inputs_.clear();
483 resolved_inputs_.clear();
484 registered_params_.clear();
485 registered_config_.clear();
486 }
487
488 // =========================================================================
489 // Direct Registry Access (for Simulator)
490 // =========================================================================
491
492 [[nodiscard]] SignalRegistry<Scalar> &registry() { return registry_; }
493 [[nodiscard]] const SignalRegistry<Scalar> &registry() const { return registry_; }
494
495 private:
496 [[nodiscard]] std::string make_full_name(const std::string &local_name) const {
497 std::string prefix = full_prefix();
498 if (prefix.empty())
499 return local_name;
500 return prefix + "." + local_name;
501 }
502
503 SignalRegistry<Scalar> &registry_;
504 std::string entity_;
505 std::string component_;
506 std::vector<std::string> registered_outputs_;
507 std::vector<std::string> registered_inputs_; // Phase 2.4
508 std::vector<std::string> resolved_inputs_;
509 std::vector<std::string> registered_params_; // Phase 2.4
510 std::vector<std::string> registered_config_; // Phase 2.4
511 const vulcan::time::Epoch<Scalar> *epoch_ = nullptr;
512};
513
514} // namespace icarus
Core type definitions, concepts, and configuration for Icarus.
#define ICARUS_ASSERT(cond, msg)
Definition CoreTypes.hpp:258
Type-safe SignalHandle for zero-overhead hot path access.
Input signal port handle for components.
Signal Registry (Backplane) for Icarus.
Vector and matrix handles for structured signal access.
void register_input(const std::string &local_name, InputHandle< T > *handle, const std::string &units="", const std::string &description="")
Register an input port.
Definition Backplane.hpp:262
void register_output(const std::string &local_name, T *data_ptr, const std::string &unit="", const std::string &description="")
Register a scalar output signal.
Definition Backplane.hpp:99
void register_output_vec3(const std::string &local_name, Vec3< S > *data_ptr, const std::string &unit="", const std::string &description="")
Register a Vec3 output signal (expands to .x/.y/.z).
Definition Backplane.hpp:111
bool has_signal(const std::string &full_name) const
Check if a signal exists.
Definition Backplane.hpp:244
void register_state_vec3(const std::string &local_name, Vec3< S > *value, Vec3< S > *derivative, const std::string &unit="", const std::string &description="")
Register a Vec3 state with its derivative.
Definition Backplane.hpp:167
void declare_output_vec3(const std::string &local_name, Vec3< S > *data_ptr, const std::string &unit="", const std::string &description="")
Declare a Vec3 output port.
Definition Backplane.hpp:352
std::vector< std::string > GetDeclaredInputs() const
Get all declared input paths.
Definition Backplane.hpp:427
SignalRegistry< Scalar > & registry()
Definition Backplane.hpp:492
void declare_output(const std::string &local_name, T *data_ptr, const std::string &unit="", const std::string &description="")
Declare an output port (Phase 4.0 semantic alias for register_output).
Definition Backplane.hpp:343
const std::vector< std::string > & resolved_inputs() const
Get legacy resolved inputs by current component.
Definition Backplane.hpp:459
void register_config(const std::string &local_name, bool *storage, bool initial_value, const std::string &description="")
Register a bool config value.
Definition Backplane.hpp:305
Vec3Handle< S > resolve_vec3(const std::string &full_name)
Resolve a Vec3 signal.
Definition Backplane.hpp:223
void WireWithGain(const std::string &input_path, const std::string &output_path, double gain=1.0)
Wire an input to a source with a gain factor.
Definition Backplane.hpp:389
void set_epoch(const vulcan::time::Epoch< Scalar > *epoch)
Set epoch reference for component binding.
Definition Backplane.hpp:56
void register_output_quat(const std::string &local_name, Vec4< S > *data_ptr, const std::string &unit="", const std::string &description="")
Register a quaternion output signal (expands to .w/.x/.y/.z).
Definition Backplane.hpp:124
const std::vector< std::string > & registered_params() const
Get parameters registered by current component (Phase 2.4).
Definition Backplane.hpp:466
void set_context(const std::string &entity, const std::string &component)
Set current component context.
Definition Backplane.hpp:45
SignalHandle< T > resolve(const std::string &full_name)
Resolve a signal by full path.
Definition Backplane.hpp:215
bool HasOutput(const std::string &full_name) const
Check if an output signal exists.
Definition Backplane.hpp:411
void register_state(const std::string &local_name, T *value, T *derivative, const std::string &unit="", const std::string &description="")
Register a scalar state with its derivative.
Definition Backplane.hpp:152
Backplane(SignalRegistry< Scalar > &registry)
Definition Backplane.hpp:34
void wire_input(const std::string &input_name, const std::string &source_name)
Wire an input to a source signal.
Definition Backplane.hpp:321
void bind_epoch_to(ComponentType &comp)
Bind epoch reference to a component.
Definition Backplane.hpp:64
void clear_tracking()
Clear tracking for next component.
Definition Backplane.hpp:480
void clear_context()
Clear the current context.
Definition Backplane.hpp:71
std::vector< std::string > GetDeclaredOutputs() const
Get all declared output paths.
Definition Backplane.hpp:434
const std::vector< std::string > & registered_inputs() const
Get inputs registered by current component (Phase 2.4).
Definition Backplane.hpp:452
QuatHandle< S > resolve_quat(const std::string &full_name)
Resolve a quaternion signal.
Definition Backplane.hpp:233
void register_config(const std::string &local_name, int *storage, int initial_value, const std::string &description="")
Register an int config value.
Definition Backplane.hpp:294
const std::vector< std::string > & registered_config() const
Get config registered by current component (Phase 2.4).
Definition Backplane.hpp:473
std::string full_prefix() const
Get full prefix: entity.component (or just component if no entity).
Definition Backplane.hpp:80
void declare_input(const std::string &local_name, InputHandle< T > *handle, const std::string &unit="", const std::string &description="")
Declare an input port (Phase 4.0 semantic alias for register_input).
Definition Backplane.hpp:369
const std::vector< std::string > & registered_outputs() const
Get outputs registered by current component.
Definition Backplane.hpp:445
void register_state_quat(const std::string &local_name, Vec4< S > *value, Vec4< S > *derivative, const std::string &unit="", const std::string &description="")
Register a quaternion state with its derivative.
Definition Backplane.hpp:187
void register_param(const std::string &local_name, Scalar *storage, Scalar initial_value, const std::string &units="", const std::string &description="")
Register a Scalar parameter (optimizable).
Definition Backplane.hpp:279
bool HasInput(const std::string &full_name) const
Check if an input port exists.
Definition Backplane.hpp:418
void WireWithGain(const std::string &input_path, const std::string &output_path, double gain=1.0)
Wire with gain (type-erased version for SignalRouter).
Definition Backplane.hpp:399
const SignalRegistry< Scalar > & registry() const
Definition Backplane.hpp:493
Handle to an input signal port.
Definition InputHandle.hpp:35
Type-safe handle for accessing a signal value.
Definition Handle.hpp:41
Central registry for all simulation signals.
Definition Registry.hpp:37
Concept for types that can serve as Icarus components.
Definition CoreTypes.hpp:189
Definition AggregationTypes.hpp:13
Handle for accessing a quaternion signal as four scalar components.
Definition VecHandle.hpp:74
Handle for accessing a Vec3 signal as three scalar components.
Definition VecHandle.hpp:39