Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/guide/advanced.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Advanced operations

This section collects less common operations that are still useful in
production applications.

## Write parameters

[`crate::Output::write_with_params`] accepts a [`crate::WriteParams`] struct
that can change the write action (`write`, `dispose`, `unregister`) and attach
identity or timestamp metadata.

The available constructors are:

* [`crate::WriteParams::write`]
* [`crate::WriteParams::dispose`]
* [`crate::WriteParams::unregister`]

## Waiting and matching

* [`crate::Connector::wait_for_data`]: wait for any input to have data.
* [`crate::Input::wait_for_publications`]: wait for matched writers.
* [`crate::Output::wait_for_subscriptions`]: wait for matched readers.
* [`crate::Output::wait`]: wait for acknowledgments.

Both `Input` and `Output` provide JSON helpers to inspect matches:

* [`crate::Input::display_matched_publications`]
* [`crate::Output::display_matched_subscriptions`]

## Loan management

If you call [`crate::Input::take`], you can return the loan with
[`crate::Input::return_loan`] after processing to release native resources.
121 changes: 121 additions & 0 deletions docs/guide/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Configuration

RTI Connector for Rust uses an XML configuration file to define participants,
readers, writers, topics, types, and QoS. The XML schema is the same one used
by RTI Connext DDS XML-Based Application Creation.

For background on the XML format, see the
[RTI XML-Based Application Creation guide](https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_professional/xml_application_creation/index.htm).

## Loading a configuration

Create a connector by passing a participant name and the XML file path:

```rust
use rtiddsconnector::Connector;

fn load_config() -> rtiddsconnector::ConnectorFallible {
let _connector = Connector::new("MyLibrary::MyParticipant", "App.xml")?;
Ok(())
}
```

The `config_name` must match a `<domain_participant>` element in the XML.

## XML tags and Connector API mapping

The table below summarizes the most common XML tags and how they map to the
Connector API:

| XML Tag | DDS Concept | Connector API |
| --- | --- | --- |
| `<types>` | Data types | Types used by `Input` and `Output` |
| `<domain_library>`, `<domain>`, `<register_type>`, `<topic>` | Domain, Topic | Defines the domain and topics used by `Connector` |
| `<domain_participant_library>`, `<domain_participant>` | DomainParticipant | Loaded by `Connector::new` |
| `<publisher>`, `<data_writer>` | Publisher, DataWriter | Each `<data_writer>` defines an `Output` |
| `<subscriber>`, `<data_reader>` | Subscriber, DataReader | Each `<data_reader>` defines an `Input` |
| `<qos_library>`, `<qos_profile>` | QoS | QoS for `Connector`, `Output`, and `Input` |

## Types

Types are defined under `<types>` and associated with topics. Example:

```xml
<types>
<struct name="ShapeType">
<member name="color" type="string" stringMaxLength="128" key="true"/>
<member name="x" type="int32"/>
<member name="y" type="int32"/>
<member name="shapesize" type="int32"/>
</struct>
</types>
```

You can define types in IDL and convert them to XML with `rtiddsgen`:

```
rtiddsgen -convertToXml MyTypes.idl
```

## Domain and topics

Domains register types and define topics:

```xml
<domain_library name="MyDomainLibrary">
<domain name="MyDomain" domain_id="0">
<register_type name="ShapeType" type_ref="ShapeType"/>
<topic name="Square" register_type_ref="ShapeType"/>
</domain>
</domain_library>
```

## Participants, readers, and writers

Participants contain publishers and subscribers, which in turn manage individual
writers and readers:

```xml
<domain_participant_library name="MyParticipantLibrary">
<domain_participant name="MyPubParticipant" domain_ref="MyDomainLibrary::MyDomain">
<publisher name="MyPublisher">
<data_writer name="MySquareWriter" topic_ref="Square" />
</publisher>
</domain_participant>

<domain_participant name="MySubParticipant" domain_ref="MyDomainLibrary::MyDomain">
<subscriber name="MySubscriber">
<data_reader name="MySquareReader" topic_ref="Square" />
</subscriber>
</domain_participant>
</domain_participant_library>
```

## QoS profiles

QoS can be configured at the profile level or per-entity. Example profile:

```xml
<qos_library name="MyQosLibrary">
<qos_profile name="MyQosProfile" is_default_qos="true">
<datareader_qos>
<reliability>
<kind>RELIABLE_RELIABILITY_QOS</kind>
</reliability>
</datareader_qos>
<datawriter_qos>
<reliability>
<kind>RELIABLE_RELIABILITY_QOS</kind>
</reliability>
</datawriter_qos>
</qos_profile>
</qos_library>
```

## Examples in this repo

This repository includes XML examples you can adapt. For an example
configuration file, see `examples/shapes/Shapes.xml`:

* `examples/MyApplication.xml`
* `examples/shapes/Shapes.xml`
70 changes: 70 additions & 0 deletions docs/guide/connector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Connector lifecycle
Comment thread
alexcamposruiz marked this conversation as resolved.

This chapter covers creating a connector, acquiring inputs and outputs, and
cleaning up native resources.

[`crate::Connector`] represents a DDS `DomainParticipant` configured from XML.
Comment thread
alexcamposruiz marked this conversation as resolved.
It owns native resources and creates `Input` and `Output` handles.

## Importing the crate

To import the crate:

```rust
use rtiddsconnector::{self, Connector};
```

## Creating a connector

To create a connector, pass an XML file and a configuration name to
[`crate::Connector::new`]:

```rust
use rtiddsconnector::Connector;

fn create_connector() -> rtiddsconnector::ConnectorFallible {
let _connector = Connector::new("MyLibrary::MyParticipant", "App.xml")?;
Ok(())
}
```

The XML file defines your types, QoS profiles, and DDS entities. The call above
loads a `<domain_participant>` from a `<domain_participant_library>`. For example:

```xml
<domain_participant_library name="MyParticipantLibrary">
<domain_participant name="MyParticipant" domain_ref="MyDomainLibrary::MyDomain">
...
</domain_participant>
</domain_participant_library>
```

See a complete example in `examples/MyApplication.xml`.

> **Note:** Operations on the same `Connector` or its contained entities are not
> protected for multi-threaded access. See
> [Threading and ownership](crate::guide::threading) for guidance.

## Closing a connector

There is no explicit `close()` method in Rust. Instead, `Connector`, `Input`, and
`Output` are released when they go out of scope. The crate uses RAII to free
native resources.

To force cleanup of Connext global resources at the end of a scope (for example,
in tests), use [`crate::GlobalsDropGuard`].

## Getting inputs and outputs

Once you have created a connector, use [`crate::Connector::get_input`] and
[`crate::Connector::get_output`] to retrieve inputs and outputs.

> **Note:** If the `<domain_participant>` you load contains both `<data_writer>`
> and `<data_reader>` tags for the same topic and they have matching QoS, inputs
> may receive data before you call `get_input`. To avoid this, configure the
> `<subscriber>` that contains the `<data_reader>` with
> `<subscriber_qos>/<entity_factory>/<autoenable_created_entities>` set to
> `false`. Then inputs will only receive data after you call `get_input`.

See [Publishing data](crate::guide::output) and [Reading data](crate::guide::input)
for the workflow that follows.
96 changes: 96 additions & 0 deletions docs/guide/data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Data access and Serde

RTI Connector exposes data as JSON under the hood, while also providing typed
accessors for common primitive fields.

## Complex types and XML definitions

The types you read and write can include nested structs, sequences, arrays, and
unions. These types are defined in XML following RTI's XML-Based Application
Creation format. For details, see
[RTI XML-Based Application Creation](https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_professional/xml_application_creation/xml_based_app_creation_guide/UnderstandingXMLBased/XMLTagsConfigEntities.htm).

## JSON vs member access

You can access data member-by-member or as JSON. JSON access is convenient when
working with large structures; member access is convenient when you only need a
few fields.

* Set with JSON: [`crate::Instance::set_as_json`]
* Get JSON: [`crate::Sample::get_value_json`]
* Member access: [`crate::Instance::set_number`], [`crate::Instance::set_string`],
[`crate::Sample::get_number`], [`crate::Sample::get_string`]

## Accessing basic members

Use typed setters/getters for numbers, booleans, and strings:

```rust
use rtiddsconnector::{Instance, Sample};

fn set_basic(instance: &mut Instance) -> rtiddsconnector::ConnectorFallible {
instance.set_number("my_long", 2.0)?;
instance.set_boolean("my_boolean", true)?;
instance.set_string("my_string", "Hello, World!")?;
Ok(())
}

fn get_basic(sample: &Sample) -> rtiddsconnector::ConnectorFallible {
let _n = sample.get_number("my_long")?;
let _b = sample.get_boolean("my_boolean")?;
let _s = sample.get_string("my_string")?;
Ok(())
}
```

## Accessing complex members

Examples of field-name syntax for nested members, arrays, sequences, and unions
are available in the [Accessing the data (field-name syntax examples)](https://community.rti.com/static/documentation/connector/current/api/javascript/data.html#)
chapter of the Connector for JavaScript API documentation.

## Type-independent access with SelectedValue

For dynamic access, use [`crate::Instance::set_value`] and
[`crate::Sample::get_value`], which operate on [`crate::SelectedValue`]:

```rust
use rtiddsconnector::{Instance, Sample, SelectedValue};

fn set_dynamic(instance: &mut Instance) -> rtiddsconnector::ConnectorFallible {
instance.set_value("my_double", SelectedValue::Number(2.14))?;
instance.set_value("my_boolean", SelectedValue::Boolean(true))?;
instance.set_value("my_string", SelectedValue::String("Hello".to_string()))?;
Ok(())
}

fn get_dynamic(sample: &Sample) -> rtiddsconnector::ConnectorFallible {
let _value = sample.get_value("my_double")?;
Ok(())
}
```

## Performance guidance

Typed getters and setters are generally faster than dynamic access with
`SelectedValue`. If you intend to access most or all members of a sample,
using JSON (`set_as_json`/`get_value_json`) can be more convenient and efficient
than setting or getting fields one by one.

## 64-bit integer limitations

RTI Connector uses a single number representation internally. This means that
64-bit integers may lose precision when converted to the internal numeric type.
If you need exact 64-bit integer values, consider representing them as strings
in your data model and converting explicitly in your application.

## Typed serialization

If you want to work with Rust structs, use Serde:

* [`crate::Instance::serialize`]: serialize a struct and set it into the
instance.
* [`crate::Sample::deserialize`]: deserialize a sample into a struct.

These methods allow you to keep strongly-typed models in your application while
still using the dynamic RTI Connector API.
52 changes: 52 additions & 0 deletions docs/guide/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Error handling

Most operations return [`crate::ConnectorResult<T>`] or
[`crate::ConnectorFallible`]. When an operation fails, you receive a
[`crate::ConnectorError`].

## Common patterns

```rust
use rtiddsconnector::{Connector, ConnectorError};

fn try_connect() -> Result<(), ConnectorError> {
let _connector = Connector::new("MyLibrary::MyParticipant", "App.xml")?;
Ok(())
}
```

Use helper methods to detect common cases:

* [`crate::ConnectorError::is_timeout`]
* [`crate::ConnectorError::is_entity_not_found`]
* [`crate::ConnectorError::is_field_not_found`]
* [`crate::ConnectorError::is_native_error`]

To inspect the last native error message, call
[`crate::ConnectorError::last_error_message`].

## Timeout example
Comment thread
alexcamposruiz marked this conversation as resolved.

This example waits for data and treats a timeout as a non-fatal outcome.

```rust
use rtiddsconnector::Input;

fn wait_with_timeout(input: &Input) -> rtiddsconnector::ConnectorFallible {
match input.wait_with_timeout(std::time::Duration::from_secs(2)) {
Ok(()) => Ok(()),
Err(e) if e.is_timeout() => {
println!("Timed out waiting for data");
Ok(())
}
Err(e) => Err(e),
}
}
```

## Native error details

If an operation fails because of a native RTI Connector error, the
[`crate::ConnectorError`] will include the last error message from the native library.
This can provide additional context when debugging configuration or data access
issues.
Loading