zerodds_opcua_bridge/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! `zerodds-opcua-bridge` — the OMG DDS-OPCUA Gateway 1.0 as a daemon on
5//! `zerodds-dcps`.
6//!
7//! Crate `zerodds-opcua-bridge`. Safety classification: **STANDARD**.
8//!
9//! The four `no_std + alloc` OPC-UA crates
10//! ([`zerodds_opcua_gateway`], [`zerodds_opcua_uacp`], [`zerodds_opcua_server`],
11//! [`zerodds_opcua_pubsub`]) implement the OMG DDS-OPCUA Gateway 1.0 type
12//! system and AddressSpace mapping, the Part 6 `opc.tcp` framing and
13//! SecureChannel, the Part 4 Client/Server service set, and the Part 14
14//! (UADP) PubSub wire stack — as libraries, with no DDS runtime, no
15//! network listener loop and no configuration file. This crate is the
16//! part that was missing: a running process.
17//!
18//! # What the daemon does
19//!
20//! - **DDS → OPC UA (Gateway 1.0 §9):** DDS topics — named in
21//! [`daemon::config`]'s `opcua.gateway_config` (the Spec §10 XML this
22//! daemon reads via [`zerodds_opcua_gateway::xml::parse_gateway_config`])
23//! — appear in this daemon's own `opc.tcp` [`zerodds_opcua_server::Server`]
24//! AddressSpace: one `ObjectNode` per DDS domain, one per topic, and one
25//! `Variable` per sample field, kept live by a DDS reader pump
26//! ([`address_space_build`]). A write to a `ua_to_dds_connection` node from
27//! any OPC-UA client goes back into DDS.
28//! - **OPC UA → DDS (Gateway 1.0 §8):** the servers named in
29//! `opcua.client.servers` are browsed and subscribed as an OPC-UA client
30//! ([`ua_client`]); their monitored nodes are written into the configured
31//! DDS topics.
32//! - **Part 14 PubSub:** the `opcua.pubsub.connections` named in the config
33//! run a [`zerodds_opcua_pubsub::daemon::Publisher`]/[`zerodds_opcua_pubsub::daemon::Subscriber`]
34//! pair per connection over UDP multicast ([`pubsub_glue`]), publishing
35//! DataSets built from DDS topics and writing received DataSets back into
36//! DDS.
37//!
38//! Types are resolved through the reflective layer
39//! ([`zerodds-dcps::serialized_type::SerializedTypeSupport`], fed by a
40//! `CompleteTypeObject` this daemon builds from an operator-supplied `.idl`
41//! file — [`idl`]) rather than a compiled Rust type, the same primitive
42//! `crates/xrce-agent`'s daemon and `crates/routing-service` use for a topic
43//! whose Rust type is not linked in.
44//!
45//! # Module map
46//!
47//! - [`dynamic_type`] / [`dynamic_value`] — `zerodds_types::dynamic` ↔ the
48//! OPC-UA gateway's own symbolic type/value model
49//! ([`zerodds_opcua_gateway::dds_to_ua::walker::DdsType`] /
50//! [`zerodds_opcua_gateway::data_value::Variant`]).
51//! - [`idl`] — compiles an operator-supplied `.idl` file and builds the
52//! [`zerodds-dcps::serialized_type::SerializedTypeSupport`] for a named
53//! type in it.
54//! - [`dds_bridge`] — the DDS-side port: participant/topic/reader/writer
55//! registration against a real [`zerodds-dcps::runtime::DcpsRuntime`], plus
56//! SEDP-discovered topic enumeration.
57//! - [`address_space_build`] — Gateway 1.0 §9.3 AddressSpace materialization
58//! (`DomainNode`/`TopicNode`/instance nodes) over a live DDS reader.
59//! - [`ua_client`] — the OPC-UA client side of Gateway 1.0 §8.
60//! - [`pubsub_glue`] — the Part 14 UADP Publisher/Subscriber wiring.
61//! - [`daemon`] — the process itself: CLI, YAML config, SIGHUP/SIGTERM,
62//! systemd `Type=notify`, observability.
63//!
64//! Feature `daemon` (default-on) gates the whole crate: the reflective
65//! type layer, the DDS port, the AddressSpace/PubSub glue and the process
66//! itself. Without it the crate is empty — there is no other consumer of
67//! these modules; unlike the four library crates it wires together, this
68//! one is the product, not a component.
69
70#![cfg_attr(not(feature = "std"), no_std)]
71#![forbid(unsafe_code)]
72
73extern crate alloc;
74
75#[cfg(feature = "daemon")]
76pub mod address_space_build;
77#[cfg(feature = "daemon")]
78pub mod daemon;
79#[cfg(feature = "daemon")]
80pub mod dds_bridge;
81#[cfg(feature = "daemon")]
82pub mod dynamic_type;
83#[cfg(feature = "daemon")]
84pub mod dynamic_value;
85#[cfg(feature = "daemon")]
86pub mod idl;
87#[cfg(feature = "daemon")]
88pub mod pubsub_glue;
89#[cfg(feature = "daemon")]
90pub mod ua_client;