C++ API Reference
This section contains the automatically generated API documentation for the ros2_medkit C++ codebase.
Note
This documentation is generated from source code comments using Doxygen and Breathe.
Run the “Docs: Build Doxygen” VS Code task or doxygen Doxyfile in the docs/ directory
before building Sphinx locally. In CI, Doxygen XML is generated automatically.
ros2_medkit_gateway
The HTTP/REST gateway that exposes ROS 2 graph via SOVD-compatible API.
Classes
-
class GatewayNode : public rclcpp::Node
Public Functions
-
explicit GatewayNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions{})
-
~GatewayNode() override
-
GatewayNode(const GatewayNode&) = delete
-
GatewayNode &operator=(const GatewayNode&) = delete
-
GatewayNode(GatewayNode&&) = delete
-
GatewayNode &operator=(GatewayNode&&) = delete
-
const ThreadSafeEntityCache &get_thread_safe_cache() const
Get the thread-safe entity cache with O(1) lookups.
- Returns:
Reference to ThreadSafeEntityCache
-
DataAccessManager *get_data_access_manager() const
Get the DataAccessManager instance.
Note
The returned pointer is valid as long as the GatewayNode exists. REST server is stopped before GatewayNode destruction to ensure safe access.
- Returns:
Raw pointer to DataAccessManager (valid for lifetime of GatewayNode)
Attach a TopicDataProvider to route topic sampling through.
Called by main() after the rclcpp::Executor is constructed and the gateway node added to it, so the provider can build its subscription node. Stores the shared_ptr to keep the provider alive for the gateway node’s lifetime and forwards the raw pointer into DataAccessManager. The pool-backed provider is the single sampling path (issue #375 race fix).
-
inline TopicDataProvider *get_topic_data_provider() const
- Returns:
Non-owning pointer to the currently attached TopicDataProvider, or nullptr when no provider has been wired up yet.
-
OperationManager *get_operation_manager() const
Get the OperationManager instance.
- Returns:
Raw pointer to OperationManager (valid for lifetime of GatewayNode)
-
DiscoveryManager *get_discovery_manager() const
Get the DiscoveryManager instance.
- Returns:
Raw pointer to DiscoveryManager (valid for lifetime of GatewayNode)
-
ConfigurationManager *get_configuration_manager() const
Get the ConfigurationManager instance.
- Returns:
Raw pointer to ConfigurationManager (valid for lifetime of GatewayNode)
-
FaultManager *get_fault_manager() const
Get the FaultManager instance.
- Returns:
Raw pointer to FaultManager (valid for lifetime of GatewayNode)
-
BulkDataStore *get_bulk_data_store() const
Get the BulkDataStore instance.
- Returns:
Raw pointer to BulkDataStore (valid for lifetime of GatewayNode)
-
LogManager *get_log_manager() const
Get the LogManager instance.
- Returns:
Raw pointer to LogManager (valid for lifetime of GatewayNode)
-
SubscriptionManager *get_subscription_manager() const
Get the SubscriptionManager instance.
- Returns:
Raw pointer to SubscriptionManager (valid for lifetime of GatewayNode)
-
UpdateManager *get_update_manager() const
Get the UpdateManager instance.
- Returns:
Raw pointer to UpdateManager (valid for lifetime of GatewayNode), or nullptr if disabled
-
LockManager *get_lock_manager() const
Get the LockManager instance.
- Returns:
Raw pointer to LockManager (valid for lifetime of GatewayNode), or nullptr if locking disabled
-
ScriptManager *get_script_manager() const
Get the ScriptManager instance.
- Returns:
Raw pointer to ScriptManager (valid for lifetime of GatewayNode), or nullptr if not initialized
-
PluginManager *get_plugin_manager() const
Get the PluginManager instance.
- Returns:
Raw pointer to PluginManager (valid for lifetime of GatewayNode)
-
ResourceSamplerRegistry *get_sampler_registry() const
Get the ResourceSamplerRegistry instance.
- Returns:
Raw pointer to ResourceSamplerRegistry (valid for lifetime of GatewayNode)
-
TransportRegistry *get_transport_registry() const
Get the TransportRegistry instance.
- Returns:
Raw pointer to TransportRegistry (valid for lifetime of GatewayNode)
-
std::shared_ptr<SSEClientTracker> get_sse_client_tracker() const
Get the SSEClientTracker instance.
- Returns:
Shared pointer to SSEClientTracker
-
ResourceChangeNotifier *get_resource_change_notifier() const
Get the ResourceChangeNotifier instance.
- Returns:
Raw pointer to ResourceChangeNotifier (valid for lifetime of GatewayNode)
-
TriggerManager *get_trigger_manager() const
Get the TriggerManager instance.
- Returns:
Raw pointer to TriggerManager (valid for lifetime of GatewayNode), or nullptr if disabled
-
ConditionRegistry *get_condition_registry() const
Get the ConditionRegistry instance.
- Returns:
Raw pointer to ConditionRegistry (valid for lifetime of GatewayNode)
-
AggregationManager *get_aggregation_manager() const
Get the AggregationManager instance.
- Returns:
Raw pointer to AggregationManager (valid for lifetime of GatewayNode), or nullptr if disabled
-
void handle_entity_change_notification(const EntityChangeScope &scope)
Handle a plugin’s
PluginContext::notify_entities_changedrequest.Runs a single
refresh_cache()pass synchronously. The scope hint is accepted and logged but the current implementation ignores it and always does a full refresh - future work may limit the rediscovery to the indicated area / component. The entry point is safe to call from any thread: refresh passes triggered by plugin notifications, the periodic refresh timer, and startup are serialized by an internal mutex insiderefresh_cache()because refresh touches discovery state (e.g., the merge pipeline cached insideDiscoveryManager) that itself assumes single-threaded execution -ThreadSafeEntityCache’s own mutex is not sufficient.
-
void trigger_reentrant_notification_for_testing(const EntityChangeScope &scope)
Test hook: simulate a plugin calling notify_entities_changed from within its own IntrospectionProvider::introspect() callback.
Sets the per-thread in-refresh flag (the same flag the real refresh path uses) and invokes
handle_entity_change_notification(scope). The gateway is expected to short-circuit the call with a warning log and return without reloading the manifest.Exists purely to let unit tests exercise the reentrancy guard without spinning up a full plugin with a real IntrospectionProvider. Do NOT call this from production code.
Public Static Functions
-
static size_t count_peer_nodes(const std::vector<std::pair<std::string, std::string>> &nodes_and_namespaces, const std::string &self_fqn)
Count application (peer) nodes from (name, namespace) pairs: excludes hidden nodes and the gateway’s own nodes (whose FQN starts with
self_fqn).Static and public so the startup-summary counting logic is unit-testable.
-
static std::string connectable_host(const std::string &bind_host)
Translate a bind address into a connectable address for the sample curl (bind-all “0.0.0.0”/”::”/”” -> loopback).
Static and public for testing.
-
explicit GatewayNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions{})
-
class DiscoveryManager : public ros2_medkit_gateway::ServiceActionResolver
Orchestrates entity discovery using a configurable merge pipeline.
The discovery_mode parameter selects which layers the merge pipeline activates:
RUNTIME_ONLY: ROS 2 graph introspection only (no merge pipeline; the built-in Ros2RuntimeIntrospection provider is queried directly)
MANIFEST_ONLY: Manifest as the sole source of truth
HYBRID: Manifest + runtime + plugin layers merged through the pipeline
The DiscoveryManager provides a unified interface for discovering:
Areas: Logical groupings (manifest-only)
Components: Software/hardware units (HostInfoProvider, manifest, plugins)
Apps: Software applications (manifest, runtime nodes, plugins)
Functions: Functional groupings (manifest, namespaces, plugins)
See also
ros2::Ros2RuntimeIntrospection
See also
discovery::MergePipeline
See also
discovery::ManifestManager
Public Functions
-
explicit DiscoveryManager(rclcpp::Node *node)
Construct the discovery manager.
- Parameters:
node – ROS 2 node for graph introspection (must outlive this manager)
-
bool initialize(const DiscoveryConfig &config)
Initialize with configuration.
Loads manifest if configured, creates appropriate strategy. For RUNTIME_ONLY mode, this is a no-op.
- Parameters:
config – Discovery configuration
- Returns:
true if initialization succeeded
-
std::vector<Component> discover_components()
Discover all components.
- Returns:
Vector of discovered Component entities
-
std::vector<App> discover_apps()
Discover all apps.
- Returns:
Vector of discovered App entities (empty in runtime-only mode)
-
std::vector<Function> discover_functions()
Discover all functions.
- Returns:
Vector of discovered Function entities (empty in runtime-only mode)
-
std::vector<Function> discover_functions(const std::vector<App> &apps)
Discover functions using pre-discovered apps.
Avoids redundant ROS 2 graph introspection when apps have already been discovered in the same refresh cycle. Falls back to the no-arg overload for modes that don’t support this optimization (manifest-only, hybrid).
- Parameters:
apps – Pre-discovered apps (used only in RUNTIME_ONLY mode)
- Returns:
Vector of discovered Function entities
-
std::optional<App> get_app(const std::string &id)
Get app by ID.
- Parameters:
id – App identifier
- Returns:
App if found
-
std::optional<Function> get_function(const std::string &id)
Get function by ID.
- Parameters:
id – Function identifier
- Returns:
Function if found
-
std::vector<Area> get_subareas(const std::string &area_id)
Get subareas of an area.
- Parameters:
area_id – Parent area ID
- Returns:
Vector of child areas
-
std::vector<Component> get_subcomponents(const std::string &component_id)
Get subcomponents of a component.
- Parameters:
component_id – Parent component ID
- Returns:
Vector of child components
-
std::vector<Component> get_components_for_area(const std::string &area_id)
Get components in an area.
- Parameters:
area_id – Area ID
- Returns:
Vector of components in the area
-
std::vector<App> get_apps_for_component(const std::string &component_id)
Get apps for a component.
- Parameters:
component_id – Component ID
- Returns:
Vector of apps associated with the component
-
std::vector<std::string> get_hosts_for_function(const std::string &function_id)
Get host component IDs for a function.
- Parameters:
function_id – Function ID
- Returns:
Vector of component IDs that host the function
-
std::vector<ServiceInfo> discover_services()
Discover all services in the system.
- Returns:
Vector of ServiceInfo with schema information
-
std::vector<ActionInfo> discover_actions()
Discover all actions in the system.
- Returns:
Vector of ActionInfo with schema information
-
virtual std::optional<ServiceInfo> find_service(const std::string &component_ns, const std::string &operation_name) const override
Find a service by component namespace and operation name.
- Parameters:
component_ns – Component namespace
operation_name – Service name
- Returns:
ServiceInfo if found, nullopt otherwise
-
virtual std::optional<ActionInfo> find_action(const std::string &component_ns, const std::string &operation_name) const override
Find an action by component namespace and operation name.
- Parameters:
component_ns – Component namespace
operation_name – Action name
- Returns:
ActionInfo if found, nullopt otherwise
-
void set_topic_data_provider(TopicDataProvider *provider)
Set the topic sampler for component-topic mapping.
- Parameters:
provider – Pointer to TopicDataProvider (must outlive DiscoveryManager)
-
void set_type_introspection(ros2_medkit_serialization::TypeIntrospection *introspection)
Set the type introspection for operation schema enrichment.
- Parameters:
introspection – Pointer to TypeIntrospection (must outlive DiscoveryManager)
-
void refresh_topic_map()
Refresh the cached topic map.
-
bool is_topic_map_ready() const
Check if topic map has been built at least once.
- Returns:
true if topic map is ready, false if not yet built
-
void add_plugin_layer(const std::string &plugin_name, IntrospectionProvider *provider)
Add a plugin layer to the merge pipeline.
Wraps an IntrospectionProvider as a PluginLayer and adds it to the pipeline. Only works in HYBRID mode.
- Parameters:
plugin_name – Name of the plugin
provider – Non-owning pointer to IntrospectionProvider
Register an introspection provider with the merge pipeline.
Equivalent to add_plugin_layer for shared-ownership providers; the manager keeps the provider alive for the lifetime of the pipeline. Only meaningful in HYBRID mode.
-
void refresh_pipeline()
Re-execute the merge pipeline (hybrid mode only)
Call after adding plugin layers to trigger a single pipeline refresh.
-
discovery::ManifestManager *get_manifest_manager()
Get the manifest manager.
- Returns:
Pointer to manifest manager (nullptr if not using manifest)
-
bool has_host_info_provider() const
Check if a host info provider is active.
- Returns:
true if default component is enabled and provider exists
-
std::optional<Component> get_default_component() const
Get the default Component from HostInfoProvider.
- Returns:
Component entity representing the local host, or nullopt if not enabled
-
inline DiscoveryMode get_mode() const
Get current discovery mode.
- Returns:
Active discovery mode
-
std::string get_strategy_name() const
Get a human-readable name for the active discovery configuration.
- Returns:
One of “runtime”, “manifest”, “hybrid”.
-
std::optional<discovery::MergeReport> get_merge_report() const
Get the last merge pipeline report (hybrid mode only)
- Returns:
MergeReport if in hybrid mode, nullopt otherwise
-
std::optional<discovery::LinkingResult> get_linking_result() const
Get the last linking result (hybrid mode only)
- Returns:
LinkingResult if in hybrid mode, nullopt otherwise
-
class DataAccessManager
Application service for topic publish + sample.
Pure C++; ROS-side I/O is performed by the injected TopicTransport adapter (typically Ros2TopicTransport). Type introspection and the per-entity TopicDataProvider pointer remain on the manager because they are consumed directly by handlers and the discovery manager.
Public Functions
- Parameters:
transport – Concrete TopicTransport adapter. Manager takes shared ownership.
topic_sample_timeout_sec – Default sample timeout in seconds. Used when callers pass a negative timeout.
-
~DataAccessManager() = default
-
DataAccessManager(const DataAccessManager&) = delete
-
DataAccessManager &operator=(const DataAccessManager&) = delete
-
DataAccessManager(DataAccessManager&&) = delete
-
DataAccessManager &operator=(DataAccessManager&&) = delete
-
json publish_to_topic(const std::string &topic_path, const std::string &msg_type, const json &data, double timeout_sec = 5.0)
Publish data to a specific topic.
- Parameters:
topic_path – Full topic path (e.g., /chassis/brakes/command).
msg_type – ROS 2 message type (e.g., std_msgs/msg/Float32).
data – JSON data to publish.
timeout_sec – Timeout for the publish operation.
- Returns:
JSON with publish status.
-
json get_topic_sample_with_fallback(const std::string &topic_name, double timeout_sec = -1.0)
Get topic sample with fallback to metadata on timeout.
If the topic is publishing, returns actual data with type info. If the topic times out, returns metadata (type, schema, pub/sub counts) instead of an error.
- Parameters:
topic_name – Full topic path.
timeout_sec – Timeout for data retrieval. Use -1.0 to use the configured default.
-
json get_topic_sample_native(const std::string &topic_name, double timeout_sec = 1.0)
Get single topic sample using the native fast path.
Fast path for single-topic sampling. When no publishers are present, returns metadata-only without calling into the transport.
- Parameters:
topic_name – Full topic path.
timeout_sec – Timeout for sampling (only used if topic has publishers).
-
inline ros2_medkit_serialization::TypeIntrospection *get_type_introspection() const
Get the type introspection instance (used by handlers and discovery).
Forwarded to the transport adapter, which owns the rclcpp-coupled implementation. May return nullptr for transports that do not support introspection.
-
inline void set_topic_data_provider(TopicDataProvider *provider)
Attach a TopicDataProvider for sampling.
The provider owns the pool-backed subscription path. Non-owning pointer; caller retains ownership. Safe to call once at wiring time.
-
inline TopicDataProvider *get_topic_data_provider() const
-
inline double get_topic_sample_timeout() const
Get the configured topic sample timeout in seconds.
-
class OperationManager
Application service for ROS 2 service / action operations.
Pure C++; ROS-side I/O is performed by the injected ServiceTransport and ActionTransport adapters. Goal tracking, UUID generation, type validation and component-namespace resolution remain in the manager body.
Public Types
-
using LogSink = std::function<void(int level, std::string_view message)>
Sink for internal diagnostics (stuck-goal eviction, etc.).
Keeps OperationManager middleware-neutral while preserving observability when the gateway adapter forwards to /rosout. May be null - the sink is then a no-op, which is the production behaviour today.
Public Functions
- Parameters:
service_transport – Concrete ServiceTransport adapter (typically Ros2ServiceTransport).
action_transport – Concrete ActionTransport adapter (typically Ros2ActionTransport).
resolver – Service / action lookup interface (DiscoveryManager implements it). Must outlive this manager. May be nullptr in tests that do not exercise the component-name resolution paths.
service_call_timeout_sec – Timeout in seconds applied to every service / action call.
log_sink – Optional sink for internal diagnostics. Pass nullptr to silence stuck-goal eviction warnings (default).
-
~OperationManager()
-
OperationManager(const OperationManager&) = delete
-
OperationManager &operator=(const OperationManager&) = delete
-
OperationManager(OperationManager&&) = delete
-
OperationManager &operator=(OperationManager&&) = delete
-
void shutdown()
Idempotent teardown.
Clears tracked goals and unsubscribes from status topics. Subsequent calls are no-ops. Transport teardown is owned by the transport destructors.
-
void set_notifier(ResourceChangeNotifier *notifier)
Set optional notifier for broadcasting operation status changes to trigger subsystem.
-
ServiceCallResult call_service(const std::string &service_path, const std::string &service_type, const json &request)
Call a ROS 2 service synchronously through the ServiceTransport.
-
ServiceCallResult call_component_service(const std::string &component_ns, const std::string &operation_name, const std::optional<std::string> &service_type, const json &request)
Find and call a service by component and operation name.
Resolves the path / type via the ServiceActionResolver when type is unset.
-
ActionSendGoalResult send_action_goal(const std::string &action_path, const std::string &action_type, const json &goal, const std::string &entity_id = "")
Send a goal to an action server through the ActionTransport.
-
ActionSendGoalResult send_component_action_goal(const std::string &component_ns, const std::string &operation_name, const std::optional<std::string> &action_type, const json &goal, const std::string &entity_id = "")
Send a goal using component namespace + operation name.
Resolves through the ServiceActionResolver when type is unset.
-
ActionCancelResult cancel_action_goal(const std::string &action_path, const std::string &goal_id)
Cancel a running action goal.
-
ActionGetResultResult get_action_result(const std::string &action_path, const std::string &action_type, const std::string &goal_id)
Get the result of a completed action.
-
std::optional<ActionGoalInfo> get_tracked_goal(const std::string &goal_id) const
Get tracked goal info by goal_id.
-
std::vector<ActionGoalInfo> list_tracked_goals() const
List all tracked goals.
-
std::vector<ActionGoalInfo> get_goals_for_action(const std::string &action_path) const
Get all goals for a specific action path, sorted by created_at (newest first).
-
std::optional<ActionGoalInfo> get_latest_goal_for_action(const std::string &action_path) const
Get the most recent goal for a specific action path.
-
void update_goal_status(const std::string &goal_id, ActionGoalStatus status)
Update goal status in tracking. No-op if the goal is unknown.
-
void update_goal_feedback(const std::string &goal_id, const json &feedback)
Update goal feedback in tracking. No-op if the goal is unknown.
-
void cleanup_old_goals(std::chrono::seconds max_age = std::chrono::seconds(300))
Remove completed goals older than max_age.
Forwards the unsubscribe request to the action transport for each path that becomes empty.
-
void subscribe_to_action_status(const std::string &action_path)
Subscribe (idempotently) to action status updates.
Wires the transport callback into update_goal_status() so external status changes update the tracking map on the transport’s executor thread.
-
void unsubscribe_from_action_status(const std::string &action_path)
Unsubscribe from action status updates. Idempotent.
-
void inject_tracked_goal_for_testing(ActionGoalInfo info)
Test-only helper: inject a fully-formed ActionGoalInfo directly into the tracking map.
Used by unit tests to exercise paths (e.g. stuck-goal eviction) without driving real action server traffic. Not part of the production API.
Public Static Functions
-
static bool is_valid_message_type(const std::string &type)
Validate message type format (package/srv/Type or package/action/Type or package/msg/Type).
-
static bool is_valid_uuid_hex(const std::string &uuid_hex)
Validate UUID hex string format (32 hex characters).
-
static bool is_service_type(const std::string &type)
Check if type is a service type (contains /srv/).
-
static bool is_action_type(const std::string &type)
Check if type is an action type (contains /action/).
Public Static Attributes
-
static constexpr int kLogLevelWarn = 30
Severity used by the OperationManager’s log_sink callback.
Numeric values match rcl/rcutils log levels (30=WARN, 40=ERROR) so an adapter can forward to RCLCPP_* macros without translation. Mirrors LogManager’s kLogLevelWarn / kLogLevelError contract.
-
static constexpr int kLogLevelError = 40
-
using LogSink = std::function<void(int level, std::string_view message)>
-
class ConfigurationManager
Application service for ROS 2 node parameters.
Pure C++; ROS-side I/O is performed by the injected ParameterTransport adapter (typically Ros2ParameterTransport). All rclcpp::SyncParametersClient usage, the rclcpp::Parameter defaults cache, the negative-cache for unreachable nodes, the spin_mutex serialising parameter-client spins, and the JSON <-> rclcpp::ParameterValue conversion helpers live in the adapter.
The manager retains the high-level orchestration:
shutdown ordering contract (idempotent shutdown forwards to transport)
reset orchestration (compose set_parameter with cached default values)
the public CRUD surface consumed by handler_context handlers
Self-node short-circuiting (avoiding IPC for the gateway’s own parameters) is delegated to the transport because identifying the gateway’s own FQN requires the rclcpp node handle.
Public Functions
- Parameters:
transport – Concrete ParameterTransport adapter. Manager takes shared ownership.
-
~ConfigurationManager()
-
ConfigurationManager(const ConfigurationManager&) = delete
-
ConfigurationManager &operator=(const ConfigurationManager&) = delete
-
ConfigurationManager(ConfigurationManager&&) = delete
-
ConfigurationManager &operator=(ConfigurationManager&&) = delete
-
void shutdown()
Idempotent teardown.
Forwards to the transport’s shutdown so cached parameter clients drop their references before rclcpp::shutdown() runs. Must be called before rclcpp::shutdown() to prevent use-after-free of the parameter-client internal node held by the transport.
-
ParameterResult list_parameters(const std::string &node_name)
List all parameters for a node.
- Parameters:
node_name – Fully qualified node name (e.g., “/powertrain/engine/engine_temp_sensor”).
- Returns:
ParameterResult with array of {name, value, type} objects.
-
ParameterResult get_parameter(const std::string &node_name, const std::string ¶m_name)
Get a specific parameter value.
- Parameters:
node_name – Fully qualified node name.
param_name – Parameter name.
- Returns:
ParameterResult with {name, value, type, description, read_only}.
-
ParameterResult set_parameter(const std::string &node_name, const std::string ¶m_name, const json &value)
Set a parameter value.
- Parameters:
node_name – Fully qualified node name.
param_name – Parameter name.
value – New value (JSON type will be converted to the appropriate ROS 2 type by the transport).
- Returns:
ParameterResult with {name, value, type}.
-
ParameterResult reset_parameter(const std::string &node_name, const std::string ¶m_name)
Reset a specific parameter to its default (initial) value.
- Parameters:
node_name – Fully qualified node name.
param_name – Parameter name.
- Returns:
ParameterResult with reset parameter info.
-
ParameterResult reset_all_parameters(const std::string &node_name)
Reset all parameters of a node to their default (initial) values.
- Parameters:
node_name – Fully qualified node name.
- Returns:
ParameterResult with count of reset parameters.
Data Models
-
struct QosProfile
QoS profile information for a topic endpoint.
Public Functions
-
inline json to_json() const
Public Members
-
std::string reliability
“reliable”, “best_effort”, “system_default”, “unknown”
-
std::string durability
“volatile”, “transient_local”, “system_default”, “unknown”
-
std::string history
“keep_last”, “keep_all”, “system_default”, “unknown”
-
size_t depth = {0}
History depth (for keep_last)
-
std::string liveliness
“automatic”, “manual_by_topic”, “system_default”, “unknown”
-
inline json to_json() const
-
struct TopicEndpoint
Information about an endpoint (publisher or subscriber) on a topic.
Public Functions
-
inline std::string fqn() const
Get fully qualified node name.
-
inline json to_json() const
Public Members
-
std::string node_name
Name of the node (e.g., “controller_server”)
-
std::string node_namespace
Namespace of the node (e.g., “/navigation”)
-
std::string topic_type
Message type (e.g., “geometry_msgs/msg/Twist”)
-
QosProfile qos
QoS profile of this endpoint.
-
inline std::string fqn() const
-
struct TopicConnection
Topic with its publishers and subscribers.
Public Functions
-
inline json to_json() const
Public Members
-
std::string topic_name
Full topic path (e.g., “/cmd_vel”)
-
std::string topic_type
Message type.
-
std::vector<TopicEndpoint> publishers
-
std::vector<TopicEndpoint> subscribers
-
inline json to_json() const
-
struct Area
SOVD Area entity - represents a logical grouping (ROS 2 namespace)
Areas are derived from ROS 2 namespaces or defined in manifests. They provide a hierarchical organization of components.
Public Functions
-
inline json to_json() const
Convert to JSON representation.
SOVD EntityReference fields: id, name, href, translation_id, tags ROS 2 extensions in x-medkit: namespace, type, description, parentAreaId
- Returns:
JSON object with area data
-
inline json to_entity_reference(const std::string &base_url) const
Create SOVD EntityReference format (strictly compliant)
- Parameters:
base_url – Base URL for self links
- Returns:
JSON object in EntityReference format: id, name, href, [translationId, tags]
-
inline json to_capabilities(const std::string &base_url) const
Create SOVD Entity Capabilities format (strictly compliant)
- Parameters:
base_url – Base URL for capability links
- Returns:
JSON object listing available sub-resources
Public Members
-
std::string id
Unique identifier (e.g., “powertrain”)
-
std::string name
Human-readable name (e.g., “Powertrain System”)
-
std::string namespace_path
ROS 2 namespace path (e.g., “/powertrain”)
-
std::string type = "Area"
Entity type (always “Area”)
-
std::string translation_id
Internationalization key.
-
std::string description
Human-readable description.
-
std::vector<std::string> tags
Tags for filtering.
-
std::string parent_area_id
Parent area ID for sub-areas.
-
std::string source
Origin of this area (e.g., “manifest”, “heuristic”)
-
std::vector<std::string> contributors
Aggregation provenance: “local” and/or “peer:<name>”.
-
inline json to_json() const
-
struct Component
SOVD Component entity - represents a software/hardware component (ROS 2 node)
Components are derived from ROS 2 nodes or defined in manifests. They expose operations (services/actions), data (topics), and configurations (parameters).
Public Functions
-
inline json to_json() const
Convert to JSON representation.
SOVD EntityReference fields: id, name, href, translation_id, tags ROS 2 extensions in x-medkit: namespace, fqn, entityType, area, source, variant, etc.
- Returns:
JSON object with component data
-
inline json to_entity_reference(const std::string &base_url) const
Create SOVD EntityReference format (strictly compliant)
- Parameters:
base_url – Base URL for self links
- Returns:
JSON object in EntityReference format: id, name, href, [translationId, tags]
-
inline json to_capabilities(const std::string &base_url) const
Create SOVD Entity Capabilities format (strictly compliant)
- Parameters:
base_url – Base URL for capability links
- Returns:
JSON object listing available sub-resources
Public Members
-
std::string id
Unique identifier (node name)
-
std::string name
Human-readable name.
-
std::string namespace_path
ROS 2 namespace path.
-
std::string fqn
Fully qualified name (namespace + id)
-
std::string type = "Component"
Entity type (always “Component”)
-
std::string area
Parent area ID.
-
std::string source = "node"
Discovery source: “node”, “topic”, or “manifest”.
-
std::string translation_id
Internationalization key.
-
std::string description
Human-readable description.
-
std::string variant
Hardware variant identifier.
-
std::vector<std::string> tags
Tags for filtering.
-
std::string parent_component_id
Parent component ID for sub-components.
-
std::vector<std::string> contributors
Aggregation provenance: “local” and/or “peer:<name>”.
-
std::vector<ServiceInfo> services
Services exposed by this component.
-
std::vector<ActionInfo> actions
Actions exposed by this component.
-
ComponentTopics topics
Topics this component publishes/subscribes.
-
std::optional<json> host_metadata
Host system metadata (for runtime default component)
-
inline json to_json() const
ros2_medkit_fault_manager
Central fault storage and management node.
-
class FaultManagerNode : public rclcpp::Node
Central fault manager node.
Provides service interfaces for fault reporting, querying, and clearing. Supports configurable storage backends (memory or SQLite) via ROS parameters.
Parameters:
storage_type (string): “memory” or “sqlite” (default: “sqlite”)
database_path (string): Path to SQLite database file (default: “/var/lib/ros2_medkit/faults.db”) Use “:memory:” for in-memory SQLite database (useful for testing)
Public Functions
-
explicit FaultManagerNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
-
~FaultManagerNode() override
-
FaultManagerNode(const FaultManagerNode&) = delete
-
FaultManagerNode &operator=(const FaultManagerNode&) = delete
-
FaultManagerNode(FaultManagerNode&&) = delete
-
FaultManagerNode &operator=(FaultManagerNode&&) = delete
-
inline const FaultStorage &get_storage() const
Get read-only access to fault storage (for testing)
-
inline const std::string &get_storage_type() const
Get the storage type being used.
-
inline int capture_pool_size_for_test() const
-
inline int capture_queue_depth_for_test() const
-
inline QueueFullPolicy capture_queue_full_policy_for_test() const
Public Static Functions
-
static bool matches_entity(const std::vector<std::string> &reporting_sources, const std::string &entity_id)
Check if entity matches any reporting source.
- Parameters:
reporting_sources – List of reporting sources from fault
entity_id – Entity ID to match (exact match or as suffix of FQN)
- Returns:
true if entity_id matches any source
-
class FaultStorage
Abstract interface for fault storage backends.
Subclassed by ros2_medkit_fault_manager::InMemoryFaultStorage, ros2_medkit_fault_manager::SqliteFaultStorage
Public Functions
-
virtual ~FaultStorage() = default
-
virtual void set_debounce_config(const DebounceConfig &config) = 0
Set debounce configuration.
-
virtual DebounceConfig get_debounce_config() const = 0
Get current debounce configuration.
-
virtual bool report_fault_event(const std::string &fault_code, uint8_t event_type, uint8_t severity, const std::string &description, const std::string &source_id, const rclcpp::Time ×tamp, const DebounceConfig &config) = 0
Report a fault event (FAILED or PASSED)
- Parameters:
fault_code – Global fault identifier
event_type – EVENT_FAILED (0) or EVENT_PASSED (1)
severity – Fault severity level (only used for FAILED events)
description – Human-readable description (only used for FAILED events)
source_id – Reporting source identifier
timestamp – Current time for tracking
config – Debounce configuration to apply for this event (resolved per-entity by the node)
- Returns:
true if this is a new occurrence (new fault or reactivated CLEARED fault), false if existing active fault was updated
-
virtual std::vector<ros2_medkit_msgs::msg::Fault> list_faults(bool filter_by_severity, uint8_t severity, const std::vector<std::string> &statuses) const = 0
Get faults matching filter criteria.
- Parameters:
filter_by_severity – Whether to filter by severity
severity – Severity level to filter (if filter_by_severity is true)
statuses – List of statuses to include (empty = CONFIRMED only)
- Returns:
Vector of matching faults
-
virtual std::optional<ros2_medkit_msgs::msg::Fault> get_fault(const std::string &fault_code) const = 0
Get a single fault by fault_code.
- Parameters:
fault_code – The fault code to look up
- Returns:
The fault if found, nullopt otherwise
-
virtual bool clear_fault(const std::string &fault_code) = 0
Clear a fault by fault_code (manual acknowledgment)
- Parameters:
fault_code – The fault code to clear
- Returns:
true if fault was found and cleared, false if not found
-
virtual size_t size() const = 0
Get total number of stored faults.
-
virtual bool contains(const std::string &fault_code) const = 0
Check if a fault exists.
-
virtual size_t check_time_based_confirmation(const rclcpp::Time ¤t_time) = 0
Check and confirm PREFAILED faults that have been pending too long (time-based confirmation)
- Parameters:
current_time – Current timestamp for age calculation
- Returns:
Number of faults that were confirmed
-
inline virtual void set_max_snapshots_per_fault(size_t)
Set maximum snapshots per fault code (0 = unlimited)
-
virtual void store_snapshot(const SnapshotData &snapshot) = 0
Store a snapshot captured when a fault was confirmed.
- Parameters:
snapshot – The snapshot data to store
-
virtual std::vector<SnapshotData> get_snapshots(const std::string &fault_code, const std::string &topic_filter = "") const = 0
Get snapshots for a fault.
- Parameters:
fault_code – The fault code to get snapshots for
topic_filter – Optional topic filter (empty = all topics)
- Returns:
Vector of snapshots for the fault
-
virtual void store_rosbag_file(const RosbagFileInfo &info) = 0
Store rosbag file metadata for a fault.
- Parameters:
info – The rosbag file info to store (replaces any existing entry for fault_code)
-
virtual std::optional<RosbagFileInfo> get_rosbag_file(const std::string &fault_code) const = 0
Get rosbag file info for a fault.
- Parameters:
fault_code – The fault code to get rosbag for
- Returns:
Rosbag file info if exists, nullopt otherwise
-
virtual bool delete_rosbag_file(const std::string &fault_code) = 0
Delete rosbag file record and the actual file for a fault.
- Parameters:
fault_code – The fault code to delete rosbag for
- Returns:
true if record was deleted, false if not found
-
virtual size_t get_total_rosbag_storage_bytes() const = 0
Get total size of all stored rosbag files in bytes.
- Returns:
Total size in bytes
-
virtual std::vector<RosbagFileInfo> get_all_rosbag_files() const = 0
Get all rosbag files ordered by creation time (oldest first)
- Returns:
Vector of rosbag file info
-
virtual std::vector<RosbagFileInfo> list_rosbags_for_entity(const std::string &entity_fqn) const = 0
Get rosbags for all faults associated with an entity.
- Parameters:
entity_fqn – The entity’s fully qualified name to filter by
- Returns:
Vector of rosbag file info for faults reported by this entity
-
virtual std::vector<ros2_medkit_msgs::msg::Fault> get_all_faults() const = 0
Get all stored faults regardless of status (for filtering)
- Returns:
Vector of all faults in storage
-
virtual ~FaultStorage() = default
-
class InMemoryFaultStorage : public ros2_medkit_fault_manager::FaultStorage
Thread-safe in-memory fault storage implementation.
Public Functions
-
InMemoryFaultStorage() = default
-
virtual void set_debounce_config(const DebounceConfig &config) override
Set debounce configuration.
-
virtual DebounceConfig get_debounce_config() const override
Get current debounce configuration.
-
virtual bool report_fault_event(const std::string &fault_code, uint8_t event_type, uint8_t severity, const std::string &description, const std::string &source_id, const rclcpp::Time ×tamp, const DebounceConfig &config) override
Report a fault event (FAILED or PASSED)
- Parameters:
fault_code – Global fault identifier
event_type – EVENT_FAILED (0) or EVENT_PASSED (1)
severity – Fault severity level (only used for FAILED events)
description – Human-readable description (only used for FAILED events)
source_id – Reporting source identifier
timestamp – Current time for tracking
config – Debounce configuration to apply for this event (resolved per-entity by the node)
- Returns:
true if this is a new occurrence (new fault or reactivated CLEARED fault), false if existing active fault was updated
-
virtual std::vector<ros2_medkit_msgs::msg::Fault> list_faults(bool filter_by_severity, uint8_t severity, const std::vector<std::string> &statuses) const override
Get faults matching filter criteria.
- Parameters:
filter_by_severity – Whether to filter by severity
severity – Severity level to filter (if filter_by_severity is true)
statuses – List of statuses to include (empty = CONFIRMED only)
- Returns:
Vector of matching faults
-
virtual std::optional<ros2_medkit_msgs::msg::Fault> get_fault(const std::string &fault_code) const override
Get a single fault by fault_code.
- Parameters:
fault_code – The fault code to look up
- Returns:
The fault if found, nullopt otherwise
-
virtual bool clear_fault(const std::string &fault_code) override
Clear a fault by fault_code (manual acknowledgment)
- Parameters:
fault_code – The fault code to clear
- Returns:
true if fault was found and cleared, false if not found
-
virtual size_t size() const override
Get total number of stored faults.
-
virtual bool contains(const std::string &fault_code) const override
Check if a fault exists.
-
virtual size_t check_time_based_confirmation(const rclcpp::Time ¤t_time) override
Check and confirm PREFAILED faults that have been pending too long (time-based confirmation)
- Parameters:
current_time – Current timestamp for age calculation
- Returns:
Number of faults that were confirmed
-
virtual void set_max_snapshots_per_fault(size_t max_count) override
Set maximum snapshots per fault code (0 = unlimited)
-
virtual void store_snapshot(const SnapshotData &snapshot) override
Store a snapshot captured when a fault was confirmed.
- Parameters:
snapshot – The snapshot data to store
-
virtual std::vector<SnapshotData> get_snapshots(const std::string &fault_code, const std::string &topic_filter = "") const override
Get snapshots for a fault.
- Parameters:
fault_code – The fault code to get snapshots for
topic_filter – Optional topic filter (empty = all topics)
- Returns:
Vector of snapshots for the fault
-
virtual void store_rosbag_file(const RosbagFileInfo &info) override
Store rosbag file metadata for a fault.
- Parameters:
info – The rosbag file info to store (replaces any existing entry for fault_code)
-
virtual std::optional<RosbagFileInfo> get_rosbag_file(const std::string &fault_code) const override
Get rosbag file info for a fault.
- Parameters:
fault_code – The fault code to get rosbag for
- Returns:
Rosbag file info if exists, nullopt otherwise
-
virtual bool delete_rosbag_file(const std::string &fault_code) override
Delete rosbag file record and the actual file for a fault.
- Parameters:
fault_code – The fault code to delete rosbag for
- Returns:
true if record was deleted, false if not found
-
virtual size_t get_total_rosbag_storage_bytes() const override
Get total size of all stored rosbag files in bytes.
- Returns:
Total size in bytes
-
virtual std::vector<RosbagFileInfo> get_all_rosbag_files() const override
Get all rosbag files ordered by creation time (oldest first)
- Returns:
Vector of rosbag file info
-
virtual std::vector<RosbagFileInfo> list_rosbags_for_entity(const std::string &entity_fqn) const override
Get rosbags for all faults associated with an entity.
- Parameters:
entity_fqn – The entity’s fully qualified name to filter by
- Returns:
Vector of rosbag file info for faults reported by this entity
-
virtual std::vector<ros2_medkit_msgs::msg::Fault> get_all_faults() const override
Get all stored faults regardless of status (for filtering)
- Returns:
Vector of all faults in storage
-
InMemoryFaultStorage() = default
ros2_medkit_fault_reporter
Client library for reporting faults to the fault manager.
-
class FaultReporter
Client library for reporting faults to the central FaultManager.
Provides a simple API for ROS 2 nodes to report faults with optional local filtering to reduce noise from repeated fault occurrences.
Example usage:
class MyNode : public rclcpp::Node { public: MyNode() : Node("my_node") { reporter_ = std::make_unique<FaultReporter>( shared_from_this(), get_fully_qualified_name()); } void on_error() { reporter_->report("SENSOR_FAILURE", Fault::SEVERITY_ERROR, "Sensor timeout"); } private: std::unique_ptr<FaultReporter> reporter_; };
Public Functions
Construct a FaultReporter.
- Parameters:
node – The ROS 2 node to use for service client and parameters
source_id – Identifier for this reporter (typically node’s FQN)
service_name – Name of the ReportFault service (default: /fault_manager/report_fault)
-
void report(const std::string &fault_code, uint8_t severity, const std::string &description)
Report a FAILED event (fault occurrence)
The fault will be forwarded to the FaultManager if local filtering allows it (threshold met within time window, or high severity).
- Parameters:
fault_code – Global fault identifier (e.g., “MOTOR_OVERHEAT”)
severity – Severity level (use Fault::SEVERITY_* constants)
description – Human-readable fault description
-
void report_passed(const std::string &fault_code)
Report a PASSED event (fault condition cleared)
PASSED events bypass local filtering and are always forwarded to FaultManager. Use this when the condition that caused a fault is no longer present.
- Parameters:
fault_code – Global fault identifier (must match a previously reported fault)
-
bool is_service_ready() const
Check if the FaultManager service is available.
-
inline const LocalFilter &filter() const
Get read-only access to the local filter (for testing)
-
class LocalFilter
Local filter for fault reports.
Tracks fault occurrences per fault_code and determines whether a report should be forwarded to the central FaultManager. Implements threshold-based filtering within a sliding time window.
Thread-safe: All public methods can be called from multiple threads.
Public Functions
-
explicit LocalFilter(const FilterConfig &config = FilterConfig{})
-
bool should_forward(const std::string &fault_code, uint8_t severity)
Check if a fault report should be forwarded.
- Parameters:
fault_code – The fault identifier
severity – The fault severity level
- Returns:
true if the report should be sent to FaultManager
-
bool should_forward_passed(const std::string &fault_code)
Check if a PASSED event should be forwarded.
-
void reset(const std::string &fault_code)
Reset tracking for a specific fault code.
-
void reset_all()
Reset all tracking state.
-
inline FilterConfig config() const
Get the current configuration (thread-safe copy)
-
void set_config(const FilterConfig &config)
Update configuration (clears existing state)
-
explicit LocalFilter(const FilterConfig &config = FilterConfig{})
ros2_medkit_diagnostic_bridge
Bridge node that converts ROS 2 /diagnostics messages to FaultManager faults.
-
class DiagnosticBridgeNode : public rclcpp::Node
Bridge node that converts ROS2 /diagnostics messages to FaultManager faults.
Subscribes to /diagnostics topic and forwards diagnostic status messages to the FaultManager via the ReportFault service.
Severity mapping:
OK (0) -> PASSED event (healing)
WARN (1) -> WARN severity (1)
ERROR (2) -> ERROR severity (2)
STALE (3) -> CRITICAL severity (3)
Example launch configuration:
diagnostic_bridge: ros__parameters: diagnostics_topic: "/diagnostics" auto_generate_codes: true # Custom mappings: "name_to_code.<diagnostic_name>": "<FAULT_CODE>" "name_to_code.motor_controller: Status": "MOTOR_001"
Public Functions
-
explicit DiagnosticBridgeNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
-
std::string map_to_fault_code(const std::string &diagnostic_name) const
Map diagnostic name to fault code Uses custom mapping if available, otherwise auto-generates from name.
Public Static Functions
-
static std::optional<uint8_t> map_to_severity(uint8_t diagnostic_level)
Map DiagnosticStatus level to Fault severity Returns std::nullopt if level is OK (should send PASSED instead)
-
static bool is_ok_level(uint8_t diagnostic_level)
Check if diagnostic level indicates OK status.
ros2_medkit_log_bridge
Bridge node that promotes ROS 2 /rosout log entries to FaultManager faults.
-
class LogBridgeNode : public rclcpp::Node
Bridge node that promotes ROS 2 /rosout log entries to FaultManager faults.
Subscribes to /rosout (rcl_interfaces/msg/Log) and forwards entries at or above a configurable severity floor to the FaultManager, attributing each fault to the originating node’s fully-qualified name via a per-source FaultReporter. Drop-in compat adapter, same category as ros2_medkit_diagnostic_bridge: native FaultReporter instrumentation stays the canonical path; this bridge is the fallback for nodes that only log. Level mapping and the WARN/LocalFilter caveat are documented in README.md.
Hard limitation by construction: only sees rclcpp logs that reach /rosout from a still-alive node. Console-only loggers and crash-before-flush are out of reach.
Public Functions
-
explicit LogBridgeNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
-
std::string generate_fault_code(const std::string &source_id, const std::string &message) const
Auto-generate a stable fault code from the originating node’s FQN and the log message.
Numbers/hex/paths in the message are normalized away so the same logical message maps to the same code across occurrences. Format: <PREFIX>_<NODE>_<HASH>, clamped to medkit’s [A-Z0-9_] / 64-char rule.
-
bool node_is_eligible(const std::string &source_id) const
Whether a given originating node should be promoted, honouring the include/exclude lists.
Exposed for unit testing.
-
bool skips_medkit_stack(const std::string &logger_name) const
Whether this log should be skipped because it comes from the medkit stack itself - applies the exclude_medkit_stack toggle to is_medkit_stack_logger.
Exposed for unit testing the toggle.
-
bool cooldown_allows(const std::string &fault_code, uint8_t severity, rclcpp::Time now)
Whether a (fault_code, severity) may be forwarded now under the cooldown (first occurrence passes; same code+severity within report_cooldown_sec is suppressed; 0.0 disables).
Keyed by severity so a WARN never suppresses a same-message ERROR escalation. Exposed for unit testing.
-
ros2_medkit_fault_reporter::FaultReporter *reporter_for(const std::string &source_id)
Fetch (or lazily create) the per-source FaultReporter for an originating node, so the fault’s source_id is the node that logged, not the bridge.
Bounded by max_tracked_nodes_ with LRU eviction. Exposed for unit testing.
-
size_t tracked_reporter_count()
Number of currently tracked per-node reporters. Exposed for unit testing.
Public Static Functions
-
static bool map_level_to_severity(uint8_t log_level, uint8_t severity_floor, uint8_t *severity_out)
Map an rcl_interfaces/msg/Log level to a Fault severity.
Returns false when the level is below the floor / not promotable.
-
static std::string normalize_message(const std::string &message)
Normalize a log message into a stable template (lowercased, digit/hex/path runs stripped, whitespace collapsed, isolated single-letter tokens dropped).
Exposed for unit testing.
-
static bool is_medkit_stack_logger(const std::string &logger_name)
Whether a logger name belongs to the medkit stack’s own infrastructure (fault_manager, gateway, the other bridges).
Matched on the raw logger name so namespaced nodes are caught. Exposed for unit testing.
-
static std::string node_source_id(const std::string &log_name)
Map an rcl_interfaces/msg/Log.name (a logger name, e.g.
“bt_navigator” or “controller_manager.resource_manager”) to the originating node’s fully-qualified name (“/bt_navigator”, “/controller_manager”). The gateway discovers runtime entities by node FQN, so the fault’s source_id must use the same form for faults (and their snapshots / rosbag) to associate with the entity in the SOVD tree. Exposed for unit testing.
-
static std::string fnv1a_hex(const std::string &in)
FNV-1a 32-bit hash, fixed spec, emitted as 8 lowercase hex chars.
Exposed for unit testing so a known input asserts a known constant.
-
explicit LogBridgeNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
ros2_medkit_action_status_bridge
Bridge node that turns terminal ROS 2 action goal states into FaultManager faults.
-
class ActionStatusBridgeNode : public rclcpp::Node
Bridge node that turns terminal ROS 2 action goal states into FaultManager faults.
Generic across every action: it observes the per-action
/<action>/_action/statustopic (action_msgs/msg/GoalStatusArray) that every action server publishes, so no per-project code is needed.This catches the authoritative “the goal failed” verdict that neither the /diagnostics bridge nor the /rosout log bridge can see - e.g. a Nav2 NavigateToPose aborting or a MoveIt MoveGroup goal aborting. The reason (action-specific error code in the result) is a separate enrichment concern; this bridge delivers the generic terminal status.
Status mapping (action_msgs/msg/GoalStatus):
ABORTED (6) -> fault (severity configurable, default ERROR)
CANCELED (5) -> fault only if canceled_is_fault (usually intentional)
SUCCEEDED (4)-> PASSED (heals the per-action fault code) if enabled
Fault state is per-ACTION, not per-goal: every message is scanned for the net state of the whole GoalStatusArray and a fault is raised/healed only on the action-level transition. See
derive_state.Public Types
-
enum class ActionState
Net fault state of an action, derived from a whole GoalStatusArray.
kUnknown: no terminal goal in the array yet (no transition)
kHealthy: array has terminal goals and none of them are failing
kFailed: at least one goal is failing (ABORTED, or CANCELED when canceled_is_fault)
Values:
-
enumerator kUnknown
-
enumerator kHealthy
-
enumerator kFailed
Public Functions
-
explicit ActionStatusBridgeNode(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
-
~ActionStatusBridgeNode() override
-
ActionStatusBridgeNode(const ActionStatusBridgeNode&) = delete
-
ActionStatusBridgeNode &operator=(const ActionStatusBridgeNode&) = delete
-
ActionStatusBridgeNode(ActionStatusBridgeNode&&) = delete
-
ActionStatusBridgeNode &operator=(ActionStatusBridgeNode&&) = delete
-
std::string fault_code_for(const std::string &action_name, bool canceled) const
Build the fault code for an action name and terminal status.
Format: <PREFIX>_<ACTION>_<ABORTED|CANCELED>, charset/length per medkit rules.
canceledselects the CANCELED suffix.
-
ActionState apply_message(const std::string &action_name, const action_msgs::msg::GoalStatusArray &msg, ros2_medkit_fault_reporter::FaultReporter *reporter)
Update the desired per-action state from a message and reconcile it, acting on the transition only.
Returns the state that was reported on (kFailed on raise, kHealthy on heal) or kUnknown when nothing was reported
including when the report could not be delivered yet (the FaultManager service is not discovered), in which case the transition stays pending and is retried on the next rescan. A null
reporteris the unit-test seam: delivery is a no-op treated as successful, so the transition decision and stored per-action state still update and tests assert on the return value.
Public Static Functions
-
static std::string action_name_from_status_topic(const std::string &topic)
Derive the action name from a
/<action>/_action/statustopic name.Returns empty when the topic is not an action status topic.
-
static std::string server_fqn_from_endpoint(const std::string &node_name, const std::string &node_namespace)
Build a node FQN from a publisher endpoint’s node name + namespace, or “” if unresolved.
During DDS discovery rcl reports the placeholders “_NODE_NAME_UNKNOWN_” / “_NODE_NAMESPACE_UNKNOWN_” before the real name propagates; those (and an empty name) are treated as unresolved so a fault is never attributed to the placeholder.
-
static std::string uuid_to_hex(const std::array<uint8_t, 16> &uuid)
Lowercase hex of a 16-byte goal UUID, for dedup keys and short display.
-
static ActionState derive_state(const action_msgs::msg::GoalStatusArray &msg, bool canceled_is_fault)
Scan a whole GoalStatusArray and return the action-level net state.
canceled_is_faultdecides whether CANCELED counts as failing. Order of the goals in the array does not affect the result (any failing goal wins).
ros2_medkit_serialization
Runtime JSON ↔ ROS 2 message serialization library.
-
class JsonSerializer
JSON serializer for ROS 2 messages using dynmsg.
This class provides the main API for converting between JSON and ROS 2 messages at runtime. It uses dynmsg’s YAML capabilities internally and converts between JSON and YAML formats.
Note
This class is stateless and thread-safe.
Public Functions
-
JsonSerializer() = default
-
~JsonSerializer() = default
-
JsonSerializer(const JsonSerializer&) = delete
-
JsonSerializer &operator=(const JsonSerializer&) = delete
-
JsonSerializer(JsonSerializer&&) = default
-
JsonSerializer &operator=(JsonSerializer&&) = default
-
nlohmann::json to_json(const TypeInfo_Cpp *type_info, const void *message_data) const
Convert a ROS 2 message to JSON.
- Parameters:
type_info – Type introspection info
message_data – Pointer to the message data
- Throws:
JsonConversionError – if conversion fails
- Returns:
JSON representation of the message
-
nlohmann::json to_json(const std::string &type_string, const void *message_data) const
Convert a ROS 2 message to JSON using type string.
- Parameters:
type_string – Full type string (e.g., “std_msgs/msg/String”)
message_data – Pointer to the message data
- Throws:
TypeNotFoundError – if type cannot be loaded
JsonConversionError – if conversion fails
- Returns:
JSON representation of the message
-
RosMessage_Cpp from_json(const TypeInfo_Cpp *type_info, const nlohmann::json &json) const
Convert JSON to a ROS 2 message.
Note
Caller is responsible for calling ros_message_destroy_with_allocator
- Parameters:
type_info – Type introspection info
json – JSON data to convert
- Throws:
JsonConversionError – if conversion fails
- Returns:
RosMessage_Cpp containing allocated message data
-
RosMessage_Cpp from_json(const std::string &type_string, const nlohmann::json &json) const
Convert JSON to a ROS 2 message using type string.
Note
Caller is responsible for calling ros_message_destroy_with_allocator
- Parameters:
type_string – Full type string (e.g., “std_msgs/msg/String”)
json – JSON data to convert
- Throws:
TypeNotFoundError – if type cannot be loaded
JsonConversionError – if conversion fails
- Returns:
RosMessage_Cpp containing allocated message data
-
void from_json_to_message(const TypeInfo_Cpp *type_info, const nlohmann::json &json, void *message_data) const
Populate an existing message from JSON.
- Parameters:
type_info – Type introspection info
json – JSON data to convert
message_data – Pointer to pre-allocated message to populate
- Throws:
JsonConversionError – if conversion fails
-
nlohmann::json get_schema(const TypeInfo_Cpp *type_info) const
Generate a JSON schema for a ROS 2 type.
- Parameters:
type_info – Type introspection info
- Returns:
JSON schema object
-
nlohmann::json get_schema(const std::string &type_string) const
Generate a JSON schema using type string.
- Parameters:
type_string – Full type string
- Throws:
TypeNotFoundError – if type cannot be loaded
- Returns:
JSON schema object
-
nlohmann::json get_defaults(const TypeInfo_Cpp *type_info) const
Get default values for a ROS 2 type as JSON.
- Parameters:
type_info – Type introspection info
- Returns:
JSON object with default values
-
nlohmann::json get_defaults(const std::string &type_string) const
Get default values using type string.
- Parameters:
type_string – Full type string
- Throws:
TypeNotFoundError – if type cannot be loaded
- Returns:
JSON object with default values
-
rclcpp::SerializedMessage serialize(const std::string &type_string, const nlohmann::json &json) const
Serialize JSON to CDR format for use with GenericClient.
- Parameters:
type_string – Full type string (e.g., “std_srvs/srv/SetBool_Request”)
json – JSON data to serialize
- Throws:
TypeNotFoundError – if type cannot be loaded
SerializationError – if serialization fails
- Returns:
SerializedMessage containing CDR data
-
nlohmann::json deserialize(const std::string &type_string, const rclcpp::SerializedMessage &serialized_msg) const
Deserialize CDR data to JSON.
- Parameters:
type_string – Full type string
serialized_msg – SerializedMessage containing CDR data
- Throws:
TypeNotFoundError – if type cannot be loaded
SerializationError – if deserialization fails
- Returns:
JSON representation of the message
Public Static Functions
-
static nlohmann::json yaml_to_json(const YAML::Node &yaml)
Convert YAML node to JSON.
- Parameters:
yaml – YAML node to convert
- Returns:
JSON representation
-
static YAML::Node json_to_yaml(const nlohmann::json &json)
Convert JSON to YAML node.
- Parameters:
json – JSON to convert
- Returns:
YAML node representation
-
JsonSerializer() = default
-
class TypeCache
Thread-safe cache for ROS 2 type introspection data.
This class wraps dynmsg’s type loading functions and caches the results to avoid repeated dynamic library lookups. It is implemented as a singleton for global access throughout the gateway.
Note
All public methods are thread-safe.
Public Functions
-
const TypeInfo_Cpp *get_message_type_info(const std::string &package_name, const std::string &type_name)
Get type info for a message type (C++ introspection)
- Parameters:
package_name – Package name (e.g., “std_msgs”)
type_name – Type name without prefix (e.g., “String”)
- Returns:
Pointer to type info, or nullptr if not found
-
const TypeInfo_Cpp *get_message_type_info(const std::string &package_name, const std::string &interface_type, const std::string &type_name)
Get type info for any interface type (msg/srv/action)
- Parameters:
package_name – Package name (e.g., “std_srvs”)
interface_type – Interface type (“msg”, “srv”, or “action”)
type_name – Type name (e.g., “Trigger_Request”)
- Returns:
Pointer to type info, or nullptr if not found
-
const TypeInfo_Cpp *get_message_type_info(const std::string &full_type)
Get type info from full type string.
- Parameters:
full_type – Full type string (e.g., “std_msgs/msg/String” or “std_srvs/srv/Trigger_Request”)
- Returns:
Pointer to type info, or nullptr if not found
-
bool is_cached(const std::string &package_name, const std::string &type_name) const
Check if a type is cached.
- Parameters:
package_name – Package name
type_name – Type name
- Returns:
true if the type is in the cache
-
void clear()
Clear the cache.
-
size_t size() const
Get the number of cached types.
Public Static Functions
-
static std::optional<std::tuple<std::string, std::string, std::string>> parse_type_string(const std::string &full_type)
Parse a full type string into package, interface type, and type name.
- Parameters:
full_type – Full type string (e.g., “std_msgs/msg/String”)
- Returns:
Tuple of (package_name, interface_type, type_name), or nullopt if invalid format
-
const TypeInfo_Cpp *get_message_type_info(const std::string &package_name, const std::string &type_name)
-
class SerializationError : public std::runtime_error
Base class for all serialization errors.
Subclassed by ros2_medkit_serialization::JsonConversionError, ros2_medkit_serialization::MissingFieldError, ros2_medkit_serialization::TypeMismatchError, ros2_medkit_serialization::TypeNotFoundError, ros2_medkit_serialization::YamlConversionError
Public Functions
-
inline explicit SerializationError(const std::string &message)
-
inline explicit SerializationError(const std::string &message)
-
class TypeNotFoundError : public ros2_medkit_serialization::SerializationError
Error when type cannot be found or loaded.
-
class JsonConversionError : public ros2_medkit_serialization::SerializationError
Error during JSON parsing or conversion.
Public Functions
-
inline explicit JsonConversionError(const std::string &message)
-
inline explicit JsonConversionError(const std::string &message)