Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
73fa3da
Add custom transport tutorial
pablogs9 Mar 1, 2021
ed3349f
Update
pablogs9 Mar 1, 2021
d60e95d
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
5f372ee
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
45d6a5a
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
e5baab1
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
c5170e7
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
6c799f1
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
c70db56
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
d781e87
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
383b6be
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
9288e35
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
de7239f
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
e2b4cd5
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
0d6016e
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
86b5096
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
3bbb2e6
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
bf78a56
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
98625d6
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
43fbbb9
Add jose's endpoints
pablogs9 Mar 1, 2021
7c29608
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
9de8ecd
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
806eba6
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
1eefe2b
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
4255a4e
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
9f1a2bc
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
99d1700
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
25a8921
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
d7b6193
Update _docs/tutorials/advanced/create_custom_transports/index.md
pablogs9 Mar 1, 2021
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
1 change: 1 addition & 0 deletions _data/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
- tutorials/advanced/benchmarking
- tutorials/advanced/zephyr_emulator
- tutorials/advanced/create_custom_static_library
- tutorials/advanced/create_custom_transports

- title: Demos
docs:
Expand Down
241 changes: 241 additions & 0 deletions _docs/tutorials/advanced/create_custom_transports/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
---
title: Creating custom micro-ROS transports
permalink: /docs/tutorials/advanced/create_custom_transports/
---

This tutorial aims at providing step-by-step guidance for those users interested in creating micro-ROS custom transports, instead of using the ones provided by default in the micro-ROS tools set.

This tutorial starts from a previously created micro-ROS environment. Check the first steps of [**First micro-ROS application on an RTOS**](../../core/first_application_rtos/) for instructions on how to create a micro-ROS environment for embedded platforms.

The micro-ROS middleware, *eProsima Micro XRCE-DDS*, provides a user API that allows interfacing with the lowest level transport layer at runtime,
which enables users to implement their own transports in both the micro-ROS Client and micro-ROS Agent libraries.
Thanks to this, the Micro XRCE-DDS wire protocol can be transmitted over virtually any protocol, network or communication
mechanism. In order to do so, two general communication modes are provided:

* **Stream-oriented mode**: the communication mechanism implemented does not have the concept of packet.
[HDLC framing](https://micro-xrce-dds.docs.eprosima.com/en/latest/transport.html?highlight=hdlc#custom-serial-transport) will be used.
* **Packet-oriented mode**: the communication mechanism implemented is able to send a whole packet that includes an XRCE message.

These two modes can be selected by activating and deactivating the `framing` parameter in both the micro-ROS Client and the micro-ROS Agent functions.

## micro-ROS Client

An example on how to set these external transport callbacks in the micro-ROS Client API is:

```c
#include <rmw_uros/options.h>

...

struct custom_args {
...
}

struct custom_args args;

rmw_uros_set_custom_transport(
true, // Framing enabled here. Using Stream-oriented mode.
(void *) &args,
my_custom_transport_open,
my_custom_transport_close,
my_custom_transport_write,
my_custom_transport_read
);
```

It is important to notice that in `rmw_uros_set_custom_transport` a pointer to custom arguments is set. This reference will be available to every callbacks call.

In general, four functions must be implemented. The behaviour of these functions is slightly different, depending on the selected mode:

### Open function

```c
bool my_custom_transport_open(uxrCustomTransport* transport)
{
...
}
```
This function should open and init the custom transport. It returns a boolean indicating if the opening was successful.
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.

### Close function
```c
bool my_custom_transport_close(uxrCustomTransport* transport)
{
...
}
```
This function should close the custom transport. It returns a boolean indicating if closing was successful.
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.

### Write function
```c
size_t my_custom_transport_write(
uxrCustomTransport* transport,
const uint8_t* buffer,
size_t length,
uint8_t* errcode)
{
...
}
```
This function should write data to the custom transport. It returns the number of bytes written.
`transport->args` holds the arguments passed through `uxr_init_custom_transport`.

* **Stream-oriented mode:** The function can send up to `length` bytes from `buffer`.

* **Packet-oriented mode:** The function should send `length` bytes from `buffer`. If less than `length` bytes are written, `errcode` can be set.

### Read function
```c
size_t my_custom_transport_read(
uxrCustomTransport* transport,
uint8_t* buffer,
size_t length,
int timeout,
uint8_t* errcode)
{
...
}
```
This function should read data from the custom transport. It returns the number of bytes read.
`transport->args` have the arguments passed through `uxr_init_custom_transport`.

* **Stream-oriented mode:** The function should retrieve up to `length` bytes from the transport
and write them into `buffer` in `timeout` milliseconds.

* **Packet-oriented mode:** The function should retrieve `length` Bytes from transport
and write them into `buffer` in `timeout` milliseconds. If less than `length` bytes are read, `errcode` can be set.



## Micro XRCE-DDS Agent

The micro-ROS Agent profile for custom transports is enabled by default.

An example on how to set the external transport callbacks in the micro-ROS Agent API is:

```cpp
eprosima::uxr::Middleware::Kind mw_kind(eprosima::uxr::Middleware::Kind::FASTDDS);
eprosima::uxr::CustomEndPoint custom_endpoint;

// Add transport endpoing parameters
custom_endpoint.add_member<uint32_t>("param1");
custom_endpoint.add_member<uint16_t>("param2");
custom_endpoint.add_member<std::string>("param3");

eprosima::uxr::CustomAgent custom_agent(
"my_custom_transport",
&custom_endpoint,
mw_kind,
true, // Framing enabled here. Using Stream-oriented mode.
my_custom_transport_open,
my_custom_transport_close,
my_custom_transport_write
my_custom_transport_read);

custom_agent.start();
```
As in the *Client* API, four functions should be implemented. The behavior of these functions is sightly different
depending on the selected mode.

### CustomEndPoint
Comment thread
pablogs9 marked this conversation as resolved.

The `custom_endpoint` is an object of type `eprosima::uxr::CustomEndPoint` and it is in charge of handling the endpoint parameters. The *Agent*, unlike the *Client*, can receive
messages from multiple *Clients* so it must be able to differentiate between them.
Therefore, the `eprosima::uxr::CustomEndPoint` should be provided with information about the origin of the message
in the read callback, and with information about the destination of the message in the write callback.

In general, the members of a `eprosima::uxr::CustomEndPoint` object can be unsigned integers and strings.

`CustomEndPoint` defines three methods:

Add member
```cpp
bool eprosima::uxr::CustomEndPoint::add_member<*KIND*>(const std::string& member_name);
```
This function allows to dynamically add a new member to the endpoint definition.

Ir returns ``true`` if the member was correctly added, ``false`` if something went wrong (for example, if the member already exists).

- **KIND**: To be chosen from: `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.
- **member_name**: The tag used to identify the endpoint member.

Set member value
```cpp
void eprosima::uxr::CustomEndPoint::set_member_value(const std::string& member_name, const *KIND* & value);
```

This function sets the specific value (numeric or string) for a certain member, which must previously exist in the `CustomEndPoint`.

- **member_name**: The member whose value is going to be modified.
- **value**: The value to be set, of `KIND`: `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.

Get member
```cpp
const *KIND* & eprosima::uxr::CustomEndPoint::get_member(const std::string& member_name);
```

This function gets the current value of the member registered with the given parameter.
The retrieved value might be an `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `uint128_t` or `std::string`.

- **member_name**: The `CustomEndPoint` member name whose current value is requested.

### Open function
```cpp
eprosima::uxr::CustomAgent::InitFunction my_custom_transport_open = [&]() -> bool
{
...
}
```
This function should open and init the custom transport. It returns a boolean indicating if the opening was successful.

### Close function
```cpp
eprosima::uxr::CustomAgent::FiniFunction my_custom_transport_close = [&]() -> bool
{
...
}
```
This function should close the custom transport. It returns a boolean indicating if the closing was successful.

### Write function
```cpp
eprosima::uxr::CustomAgent::SendMsgFunction my_custom_transport_write = [&](
const eprosima::uxr::CustomEndPoint* destination_endpoint,
uint8_t* buffer,
size_t length,
eprosima::uxr::TransportRc& transport_rc) -> ssize_t
{
...
}
```
This function should write data to the custom transport. It must use
the `destination_endpoint` members to set the data destination. It returns the number of bytes written.
It should set `transport_rc` indicating the result of the operation.

* **Stream-oriented mode:** The function can send up to `length` Bytes from `buffer`.

* **Packet-oriented mode:** The function should send `length` Bytes from `buffer`. If less than `length` bytes are written, `transport_rc` can be set.

### Read function
```cpp
eprosima::uxr::CustomAgent::RecvMsgFunction my_custom_transport_read = [&](
eprosima::uxr::CustomEndPoint* source_endpoint,
uint8_t* buffer,
size_t length,
int timeout,
eprosima::uxr::TransportRc& transport_rc) -> ssize_t
{
...
}
```
This function should read data to the custom transport. It must fill `source_endpoint` members with data source.
It returns the number of bytes read.
It should set `transport_rc` indicating the result of the operation.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not totally clear what this means.


* **Stream-oriented mode:** The function should retrieve up to `length` bytes from the transport
and write them into `buffer` in `timeout` milliseconds.

* **Packet-oriented mode:** The function should retrieve `length` bytes from the transport
and write them into `buffer` in `timeout` milliseconds. If less than `length` bytes are read, `transport_rc` can be set.