소스 검색

增加micro-ROS-Agent源码,可以直接编译安装,省去单独下载编译的步骤,现在一起编译

zhangzhijie 6 일 전
부모
커밋
31a11e09f8
31개의 변경된 파일3767개의 추가작업 그리고 0개의 파일을 삭제
  1. 35 0
      offline_voice_module/src/micro-ROS-Agent/.gitignore
  2. 4 0
      offline_voice_module/src/micro-ROS-Agent/3rd-party-licenses.txt
  3. 107 0
      offline_voice_module/src/micro-ROS-Agent/CONTRIBUTING.md
  4. 201 0
      offline_voice_module/src/micro-ROS-Agent/LICENSE
  5. 27 0
      offline_voice_module/src/micro-ROS-Agent/NOTICE
  6. 58 0
      offline_voice_module/src/micro-ROS-Agent/README.md
  7. 55 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/CHANGELOG.rst
  8. 270 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/CMakeLists.txt
  9. 31 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/README.md
  10. 30 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/bin/Xml_interface_gen.py
  11. 26 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/bin/Xml_read_default_profiles.py
  12. 68 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/cmake/SuperBuild.cmake
  13. 55 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/Agent.hpp
  14. 317 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp
  15. 127 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/graph_manager/graph_typesupport.hpp
  16. 125 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/utils/demangle.hpp
  17. 12 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/launch/micro_ros_agent_launch.py
  18. 35 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/package.xml
  19. 24 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/resource/StaticValues.xml
  20. 29 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/resource/rclcpp.xml
  21. 313 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/Agent.cpp
  22. 768 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp
  23. 213 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/graph_manager/graph_typesupport.cpp
  24. 191 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/utils/demangle.cpp
  25. 93 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/main.cpp
  26. 216 0
      offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/utils/__init__.py
  27. 104 0
      offline_voice_module/src/micro-ROS-Agent/snap/hooks/configure
  28. 19 0
      offline_voice_module/src/micro-ROS-Agent/snap/hooks/install
  29. 19 0
      offline_voice_module/src/micro-ROS-Agent/snap/local/fastdds_no_shared_memory.xml
  30. 27 0
      offline_voice_module/src/micro-ROS-Agent/snap/local/micro-ros-agent-daemon
  31. 168 0
      offline_voice_module/src/micro-ROS-Agent/snap/snapcraft.yaml

+ 35 - 0
offline_voice_module/src/micro-ROS-Agent/.gitignore

@@ -0,0 +1,35 @@
+
+# Created by https://www.gitignore.io/api/qtcreator
+# Edit at https://www.gitignore.io/?templates=qtcreator
+
+### QtCreator ###
+# gitignore for Qt Creator like IDE for pure C/C++ project without Qt
+#
+# Reference: http://doc.qt.io/qtcreator/creator-project-generic.html
+
+
+
+# Qt Creator autogenerated files
+
+
+# A listing of all the files included in the project
+*.files
+
+# Include directories
+*.includes
+
+# Project configuration settings like predefined Macros
+*.config
+
+# Qt Creator settings
+*.creator
+
+# User project settings
+*.creator.user*
+
+# Qt Creator backups
+*.autosave
+
+# End of https://www.gitignore.io/api/qtcreator
+
+CMakeLists.txt.user

+ 4 - 0
offline_voice_module/src/micro-ROS-Agent/3rd-party-licenses.txt

@@ -0,0 +1,4 @@
+Third Party Licenses
+====================
+
+This repository does not directly contain 3rd party source code. 

+ 107 - 0
offline_voice_module/src/micro-ROS-Agent/CONTRIBUTING.md

@@ -0,0 +1,107 @@
+# Contributing
+
+Want to contribute? Great! You can do so through the standard GitHub pull
+request model. For large contributions we do encourage you to file a ticket in
+the GitHub issues tracking system prior to any code development to coordinate
+with the system_modes development team early in the process. Coordinating up
+front helps to avoid frustration later on.
+
+Your contribution must be licensed under the Apache-2.0 license, the license
+used by this project.
+
+## Add / retain copyright notices
+
+Include a copyright notice and license in each new file to be contributed,
+consistent with the style used by this project. If your contribution contains
+code under the copyright of a third party, document its origin, license, and
+copyright holders.
+
+## Sign your work
+
+This project tracks patch provenance and licensing using a modified Developer
+Certificate of Origin (DCO; from [OSDL][DCO]) and Signed-off-by tags initially
+developed by the Linux kernel project.
+
+```
+system_modes Developer's Certificate of Origin.  Version 1.0
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the "Apache License, Version 2.0"
+    ("Apache-2.0"); or
+
+(b) The contribution is based upon previous work that is covered by
+    an appropriate open source license and I have the right under
+    that license to submit that work with modifications, whether
+    created in whole or in part by me, under the Apache-2.0 license;
+    or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a) or (b) and I have not modified it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    metadata and personal information I submit with it, including my
+    sign-off) is maintained indefinitely and may be redistributed
+    consistent with this project and the requirements of the Apache-2.0
+    license or any open source license(s) involved, where they are
+    relevant.
+
+(e) I am granting the contribution to this project under the terms of
+    Apache-2.0.
+
+    http://www.apache.org/licenses/LICENSE-2.0
+```
+
+With the sign-off in a commit message you certify that you authored the patch
+or otherwise have the right to submit it under an open source license. The
+procedure is simple: To certify above system_modes Developer's Certificate of
+Origin 1.0 for your contribution just append a line
+
+    Signed-off-by: Random J Developer <random@developer.example.org>
+
+to every commit message using your real name or your pseudonym and a valid
+email address.
+
+If you have set your `user.name` and `user.email` git configs you can
+automatically sign the commit by running the git-commit command with the `-s`
+option.  There may be multiple sign-offs if more than one developer was
+involved in authoring the contribution.
+
+For a more detailed description of this procedure, please see
+[SubmittingPatches][] which was extracted from the Linux kernel project, and
+which is stored in an external repository.
+
+### Individual vs. Corporate Contributors
+
+Often employers or academic institution have ownership over code that is
+written in certain circumstances, so please do due diligence to ensure that
+you have the right to submit the code.
+
+If you are a developer who is authorized to contribute to system_modes on
+behalf of your employer, then please use your corporate email address in the
+Signed-off-by tag. Otherwise please use a personal email address.
+
+## Maintain Copyright holder / Contributor list
+
+Each contributor is responsible for identifying themselves in the
+[NOTICE](NOTICE) file, the project's list of copyright holders and authors.
+Please add the respective information corresponding to the Signed-off-by tag
+as part of your first pull request.
+
+If you are a developer who is authorized to contribute to system_modes on
+behalf of your employer, then add your company / organization to the list of
+copyright holders in the [NOTICE](NOTICE) file. As author of a corporate
+contribution you can also add your name and corporate email address as in the
+Signed-off-by tag.
+
+If your contribution is covered by this project's DCO's clause "(c) The
+contribution was provided directly to me by some other person who certified
+(a) or (b) and I have not modified it", please add the appropriate copyright
+holder(s) to the [NOTICE](NOTICE) file as part of your contribution.
+
+
+[DCO]: http://web.archive.org/web/20070306195036/http://osdlab.org/newsroom/press_releases/2004/2004_05_24_dco.html
+
+[SubmittingPatches]: https://github.com/wking/signed-off-by/blob/7d71be37194df05c349157a2161c7534feaf86a4/Documentation/SubmittingPatches

+ 201 - 0
offline_voice_module/src/micro-ROS-Agent/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 27 - 0
offline_voice_module/src/micro-ROS-Agent/NOTICE

@@ -0,0 +1,27 @@
+ 
+# This is the official list of copyright holders and authors.
+#
+# Often employers or academic institutions have ownership over code that is
+# written in certain circumstances, so please do due diligence to ensure that
+# you have the right to submit the code.
+#
+# When adding J Random Contributor's name to this file, either J's name on its
+# own or J's name associated with J's organization's name should be added,
+# depending on whether J's employer (or academic institution) has ownership
+# over code that is written for this project.
+#
+# How to add names to this file:
+#     Individual's name <submission email address>.
+#
+# If Individual's organization is copyright holder of her contributions add the
+# organization's name, optionally also the contributor's name:
+#
+#     Organization's name
+#         Individual's name <submission corporate email address>
+#
+# Please keep the list sorted.
+
+eProsima
+    Jose Antonio Moral <joseantoniomoralparras@eprosima.com>
+    Pablo Garrido <pablogarrido@eprosima.com>
+

+ 58 - 0
offline_voice_module/src/micro-ROS-Agent/README.md

@@ -0,0 +1,58 @@
+# micro-ROS Agent
+
+[![GitHub license](https://img.shields.io/github/license/microROS/micro-ROS-Agent.svg)](https://github.com/microROS/micro-ROS-Agent)
+[![GitHub release](https://img.shields.io/github/release/microROS/micro-ROS-Agent.svg)](https://github.com/microROS/micro-ROS-Agent/releases)
+
+ROS 2 package using Micro XRCE-DDS Agent.
+
+## Overview
+
+This repository contains the Micro-ROS Agent package.
+Micro-ROS Agent is a ROS 2 node that wraps the Micro XRCE-DDS Agent.
+For further information about Micro XRCE-DDS Agent click [here](https://github.com/eProsima/Micro-XRCE-DDS-Agent)
+This package is a part of the Micro-ROS project stack.
+For more information about Micro-ROS project click [here](https://micro-ros.github.io/).
+
+The node acts as a server between DDS Network and Micro-ROS nodes inside MCU.
+It receives and send messages from Micro-ROS nodes, and keep track of the Micro-ROS nodes exposing them to the ROS 2 network.
+The node interacts with DDS Global Data Space on behalf of the Micro-ROS nodes.
+
+## Package features
+
+### XML generation
+
+During the build process, the package looks for all ROS 2 messages to generate an initial list of XML profiles.
+These profiles can are referenced in the Agent-Client communication to avoid sending the full XML content.
+This reference mechanism can be switched on and off from the Micro XRCE-DDS middleware layer.
+
+### Agent-Client communication mechanism
+
+Communication between the Micro-ROS Agent and the Micro-ROS nodes supports two types of transport:
+
+- UDP and TCP over IPv4 and IPv6.
+- Serial Port transports.
+
+All available configurations are supported directly by the Micro XRCE-DDS agent.
+
+## Purpose of the Project
+
+This software is not ready for production use. It has neither been developed nor
+tested for a specific use case. However, the license conditions of the
+applicable Open Source licenses allow you to adapt the software to your needs.
+Before using it in a safety relevant setting, make sure that the software
+fulfills your requirements and adjust it according to any applicable safety
+standards, e.g., ISO 26262.
+
+## License
+
+This repository is open-sourced under the Apache-2.0 license. See the [LICENSE](LICENSE) file for details.
+
+For a list of other open-source components included in this repository,
+see the file [3rd-party-licenses.txt](3rd-party-licenses.txt).
+
+## Known Issues/Limitations
+
+Please notice the following issues/limitations:
+
+* There is an unknown issue when dealing with serial ports shared with the micro-ROS agent running inside a Docker. Sometimes it works with a remarkable packet loss.
+* There is an known issues with serial port communication on micro-ros-agent snap version. It is recommended to use the dockerized version or build it from source.

+ 55 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/CHANGELOG.rst

@@ -0,0 +1,55 @@
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Changelog for package micro-ros_agent
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+3.0.6 (2024-01-29)
+------------------
+* Fix thread include (backport `#216 <https://github.com/micro-ROS/micro-ROS-Agent/issues/216>`_) (`#217 <https://github.com/micro-ROS/micro-ROS-Agent/issues/217>`_)
+
+3.0.5 (2023-06-06)
+------------------
+
+3.0.4 (2022-09-28)
+------------------
+* Fix Datawriter destruction (`#169 <https://github.com/micro-ROS/micro-ROS-Agent/issues/169>`_)
+* Synchronise predicate (`#160 <https://github.com/micro-ROS/micro-ROS-Agent/issues/160>`_)
+
+3.0.3 (2022-06-13)
+------------------
+* Fix memory leak in graph manager (`#147 <https://github.com/micro-ROS/micro-ROS-Agent/issues/147>`_)
+
+3.0.2 (2022-05-25)
+------------------
+
+3.0.1 (2022-03-25)
+------------------
+* Add services to graph manager (`#127 <https://github.com/micro-ROS/micro-ROS-Agent/issues/127>`_) (`#129 <https://github.com/micro-ROS/micro-ROS-Agent/issues/129>`_)
+* Add used missing includes (`#116 <https://github.com/micro-ROS/micro-ROS-Agent/issues/116>`_) (`#124 <https://github.com/micro-ROS/micro-ROS-Agent/issues/124>`_)
+* Add system logger flag (`#118 <https://github.com/micro-ROS/micro-ROS-Agent/issues/118>`_) (`#119 <https://github.com/micro-ROS/micro-ROS-Agent/issues/119>`_)
+* Add condition variable include (`#113 <https://github.com/micro-ROS/micro-ROS-Agent/issues/113>`_) (`#114 <https://github.com/micro-ROS/micro-ROS-Agent/issues/114>`_)
+* pass system name to xrceagent (`#110 <https://github.com/micro-ROS/micro-ROS-Agent/issues/110>`_) (`#112 <https://github.com/micro-ROS/micro-ROS-Agent/issues/112>`_)
+* Fix memory leak in FastDDS datawriter (`#107 <https://github.com/micro-ROS/micro-ROS-Agent/issues/107>`_) (`#109 <https://github.com/micro-ROS/micro-ROS-Agent/issues/109>`_)
+
+3.0.0 (2021-09-13)
+------------------
+
+1.0.1 (2021-09-13)
+------------------
+* Remove XRCE dependency and add superbuild (`#97 <https://github.com/micro-ROS/micro-ROS-Agent/issues/97>`_)
+* Fixed launch file by using a list for arguments. Ensures order of items is kept. (`#93 <https://github.com/micro-ROS/micro-ROS-Agent/issues/93>`_) (`#94 <https://github.com/micro-ROS/micro-ROS-Agent/issues/94>`_)
+* Modify argument type (`#91 <https://github.com/micro-ROS/micro-ROS-Agent/issues/91>`_)
+* Fix graph manager datawriters behaviour (`#84 <https://github.com/micro-ROS/micro-ROS-Agent/issues/84>`_)
+* Graph manager: Fix participant mask for listener callbacks (`#81 <https://github.com/micro-ROS/micro-ROS-Agent/issues/81>`_)
+* Fix agent launch (`#78 <https://github.com/micro-ROS/micro-ROS-Agent/issues/78>`_)
+* Fix graph manager node namespaces (`#75 <https://github.com/micro-ROS/micro-ROS-Agent/issues/75>`_)
+* Fix Rolling agent (`#61 <https://github.com/micro-ROS/micro-ROS-Agent/issues/61>`_)
+* Add multi domain graph manager (`#69 <https://github.com/micro-ROS/micro-ROS-Agent/issues/69>`_)
+* Add ros2 launch capabilities and example launch file (`#47 <https://github.com/micro-ROS/micro-ROS-Agent/issues/47>`_)
+* Snap build for the micro-ROS-Agent (`#43 <https://github.com/micro-ROS/micro-ROS-Agent/issues/43>`_)
+* Create graph manager after checking passed CLI arguments and launch xrce-dds server (`#41 <https://github.com/micro-ROS/micro-ROS-Agent/issues/41>`_)
+* Contributors: Antonio Cuadros, Jose Antonio Moral, Pablo Garrido, mergify[bot]
+
+0.0.1 (2019-04-24)
+-----------------
+* Initial release
+

+ 270 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/CMakeLists.txt

@@ -0,0 +1,270 @@
+# Copyright 2018-present Proyectos y Sistemas de Mantenimiento SL (eProsima).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+cmake_minimum_required(VERSION 3.5)
+
+option(UROSAGENT_GENERATE_PROFILE
+  "Generates agent.refs according to the .msgs provided in the .repos" OFF
+  )
+set(CMAKE_C_CLANG_TIDY clang-tidy -checks=*)
+
+option(MICROROSAGENT_SUPERBUILD "Enable superbuild compilation." ON)
+option(UAGENT_USE_SYSTEM_LOGGER "Force use of system installed spdlog logger on superbuild." OFF)
+
+if(NOT MICROROSAGENT_SUPERBUILD)
+    project(micro_ros_agent LANGUAGES CXX)
+else()
+    project(uagent_superbuild NONE)
+    include(${PROJECT_SOURCE_DIR}/cmake/SuperBuild.cmake)
+    return()
+endif()
+
+find_package(ament_cmake REQUIRED)
+find_package(microxrcedds_agent REQUIRED)
+find_package(rosidl_cmake REQUIRED)
+find_package(fastcdr REQUIRED)
+find_package(fastrtps REQUIRED)
+find_package(fastrtps_cmake_module REQUIRED)
+find_package(rmw_dds_common REQUIRED)
+find_package(rmw REQUIRED)
+find_package(rcutils REQUIRED)
+find_package(rmw_fastrtps_shared_cpp REQUIRED)
+
+find_package(ament_lint_auto REQUIRED)
+
+find_package(rosidl_typesupport_fastrtps_cpp REQUIRED)
+find_package(rosidl_runtime_cpp REQUIRED)
+find_package(rosidl_typesupport_cpp REQUIRED)
+find_package(ament_cmake_gtest REQUIRED)
+
+find_package(micro_ros_msgs REQUIRED)
+
+add_executable(${PROJECT_NAME}
+  src/main.cpp
+  src/agent/Agent.cpp
+  src/agent/graph_manager/graph_manager.cpp
+  src/agent/graph_manager/graph_typesupport.cpp
+  src/agent/utils/demangle.cpp
+  )
+
+target_include_directories(${PROJECT_NAME}
+  PRIVATE
+    include
+  )
+
+ament_target_dependencies(${PROJECT_NAME}
+  rosidl_typesupport_fastrtps_cpp
+  rosidl_runtime_cpp
+  rosidl_typesupport_cpp
+  fastcdr
+  fastrtps
+  rmw_dds_common
+  rmw
+  rmw_fastrtps_shared_cpp
+  micro_ros_msgs
+  )
+
+target_link_libraries(${PROJECT_NAME}
+  microxrcedds_agent
+  fastcdr
+  fastrtps
+  $<$<BOOL:$<PLATFORM_ID:Linux>>:rt>
+  $<$<BOOL:$<PLATFORM_ID:Linux>>:dl>
+  )
+
+target_compile_options(${PROJECT_NAME}
+  PRIVATE
+    $<$<C_COMPILER_ID:GNU>:-Wall>
+    $<$<C_COMPILER_ID:GNU>:-Wextra>
+    $<$<C_COMPILER_ID:GNU>:-pedantic>
+  )
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+  CXX_STANDARD
+    14
+  CXX_STANDARD_REQUIRED
+    YES
+  )
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+  CXX_STANDARD
+    14
+  CXX_STANDARD_REQUIRED
+    YES
+  )
+
+target_compile_options(${PROJECT_NAME}
+  PRIVATE
+    $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wall>
+    $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wextra>
+    $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wpedantic>
+  )
+
+ament_export_dependencies(microxrcedds_agent)
+
+ament_package()
+
+install(
+  TARGETS
+    ${PROJECT_NAME}
+  DESTINATION
+    lib/${PROJECT_NAME}
+  )
+
+install(
+  DIRECTORY
+    launch
+  DESTINATION
+    share/${PROJECT_NAME}
+  )
+
+if(UROSAGENT_GENERATE_PROFILE)
+  set(_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/python")
+
+  set(_XML_INTERFACE_GEN_BIN "${_OUTPUT_PATH}/bin/Xml_interface_gen.py")
+  normalize_path(_XML_INTERFACE_GEN_BIN "${_XML_INTERFACE_GEN_BIN}")
+
+  set(_XML_DEFAULT_READ_BIN "${_OUTPUT_PATH}/bin/Xml_read_default_profiles.py")
+  normalize_path(_XML_DEFAULT_READ_BIN "${_XML_DEFAULT_READ_BIN}")
+
+  set(_PYTHON_PKG_TOOL utils)
+
+  set(_RESOURCE_DIR "${_OUTPUT_PATH}/resource")
+  normalize_path(_RESOURCE_DIR "${_RESOURCE_DIR}")
+
+  set(_DEFAULT_FASTRTPS_PROFILES_PATH "${_OUTPUT_PATH}/gen/DEFAULT_FASTRTPS_PROFILES.xml")
+  normalize_path(_DEFAULT_FASTRTPS_PROFILES_PATH "${_DEFAULT_FASTRTPS_PROFILES_PATH}")
+
+  get_filename_component(_COLCON_CALL_DIR "${PROJECT_BINARY_DIR}" DIRECTORY)
+  get_filename_component(_COLCON_CALL_DIR "${_COLCON_CALL_DIR}" DIRECTORY)
+
+  set(_PYTHON_SCRIPT_HEAD
+"import os
+import sys
+sys.path.append('${_OUTPUT_PATH}')
+from ${_PYTHON_PKG_TOOL} import *
+"
+    )
+
+  file(
+    COPY
+      "bin" "${_PYTHON_PKG_TOOL}" "resource"
+    DESTINATION
+      "${CMAKE_CURRENT_BINARY_DIR}/python"
+    )
+
+  execute_process(
+    COMMAND
+      "${PYTHON_EXECUTABLE}"
+      "-c"
+      "${_PYTHON_SCRIPT_HEAD}for package in GetInterfacePackages(GetPackageList('${_COLCON_CALL_DIR}')): print ('%s,%s' % (package, GetPackageName(package)))"
+    OUTPUT_VARIABLE
+      _packages
+    RESULT_VARIABLE
+      _result
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+
+  if(NOT _result EQUAL 0)
+    message(FATAL_ERROR "Error finding XML packages")
+  endif()
+
+  string(REPLACE "\n" ";" _packages ${_packages})
+
+  set(ALL_MSG_FILES "")
+  foreach(package ${_packages})
+
+    string(REPLACE "," ";" package ${package})
+    list(GET package 0 package_file)
+    list(GET package 1 package)
+
+    execute_process(
+      COMMAND
+        "${PYTHON_EXECUTABLE}"
+        "-c"
+        "${_PYTHON_SCRIPT_HEAD}for msg in GetInterfacePackageMsgs('${package_file}'): print ('%s' % msg)"
+      OUTPUT_VARIABLE
+        ${package}_MSG_FILES
+      RESULT_VARIABLE
+        _result
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      )
+
+    if(NOT _result EQUAL 0)
+      message(FATAL_ERROR "Error finding .msg files")
+    endif()
+
+    if(${package}_MSG_FILES STREQUAL "")
+      continue()
+    endif()
+
+    string(REPLACE "\n" ";" ${package}_MSG_FILES ${${package}_MSG_FILES})
+
+  endforeach()
+
+  execute_process(
+    COMMAND
+      "${PYTHON_EXECUTABLE}" "${_XML_DEFAULT_READ_BIN}" "--default-xml-path" "${_RESOURCE_DIR}"
+    OUTPUT_VARIABLE
+      _XmlDoc
+    RESULT_VARIABLE
+      _result
+    )
+
+  if(NOT _result EQUAL 0)
+    message(FATAL_ERROR "Error in typesupport generation")
+  endif()
+
+  foreach(package ${_packages})
+    string(REPLACE "," ";" package ${package})
+    list(GET package 0 package_file)
+    list(GET package 1 package)
+
+    if(${package}_MSG_FILES STREQUAL "")
+      continue()
+    endif()
+
+    set(generator_arguments_file "${_OUTPUT_PATH}/XML_ArgFiles/${package}_Args.json")
+    rosidl_write_generator_arguments(
+      "${generator_arguments_file}"
+      PACKAGE_NAME "${package}"
+      ROS_INTERFACE_FILES "${${package}_MSG_FILES}"
+      ROS_INTERFACE_DEPENDENCIES "NULL"
+      OUTPUT_DIR "NULL"
+      TEMPLATE_DIR "NULL"
+      TARGET_DEPENDENCIES "NULL"
+      ADDITIONAL_FILES ""
+    )
+
+     execute_process(
+      COMMAND
+        "${PYTHON_EXECUTABLE}" "${_XML_INTERFACE_GEN_BIN}" --generator-arguments-file "${generator_arguments_file}"
+      OUTPUT_VARIABLE
+        _XmlGen
+      RESULT_VARIABLE
+        _result
+      )
+
+    if(NOT _result EQUAL 0)
+      message(FATAL_ERROR "Error in typesupport generation")
+    endif()
+
+    set(_XmlDoc "${_XmlDoc}${_XmlGen}")
+
+  endforeach()
+
+  set (_XmlDoc "<profiles>\n${_XmlDoc}</profiles>\n")
+
+  file(WRITE "${_DEFAULT_FASTRTPS_PROFILES_PATH}" "${_XmlDoc}")
+endif()

+ 31 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/README.md

@@ -0,0 +1,31 @@
+# Micro ROS Agent
+
+## Overview
+
+This repository contains the Micro-ROS Agent package.
+Micro-ROS Agent is a ROS 2 node that wraps the Micro XRCE-DDS Agent.
+For further information about Micro XRCE-DDS Agent click [here](https://github.com/eProsima/Micro-XRCE-DDS-Agent)
+This package is a part of the Micro-ROS project stack.
+For more information about Micro-ROS project click [here](https://microros.github.io/micro-ROS/).
+
+The node acts as a server between DDS Network and Micro-ROS nodes inside MCU.
+It receives and send messages from Micro-ROS nodes, and keep track of the Micro-ROS nodes exposing them to the ROS 2 network.
+The node interacts with DDS Global Data Space on behalf of the Micro-ROS nodes.
+
+## Package features
+
+### XML generation
+
+During the build process, the package looks for all ROS 2 messages to generate an initial list of XML profiles.
+These profiles can are referenced in the Agent-Client communication to avoid sending the full XML content.
+This reference mechanism can be switched on and off from the Micro XRCE-DDS middleware layer.
+
+### Agent-Client communication mechanism
+
+Communication between the Micro-ROS Agent and the Micro-ROS nodes supports two types of transport:
+
+- UDP.
+- SerialPort.
+
+All available configurations are supported directly by the Micro XRCE-DDS agent.
+For further information on how to configure the agent click [here](TODO).

+ 30 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/bin/Xml_interface_gen.py

@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..'))
+
+from rosidl_cmake import read_generator_arguments
+from rosidl_adapter.parser import UnknownMessageType
+from micro_ros_agent import generate_XML
+
+
+def main(argv=sys.argv[1:]):
+    parser = argparse.ArgumentParser(
+        description='Generate the C interfaces for Micro RTPS.',
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument(
+        '--generator-arguments-file',
+        required=True,
+        help='The location of the file containing the generator arguments')
+    args = parser.parse_args(argv)
+
+    generator_args = read_generator_arguments(args.generator_arguments_file)
+    rc = generate_XML(generator_args)
+    return rc
+
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 26 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/bin/Xml_read_default_profiles.py

@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import argparse
+import xml.etree.ElementTree
+
+sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..'))
+
+from micro_ros_agent import *
+
+def main(argv=sys.argv[1:]):
+    parser = argparse.ArgumentParser(
+        description='Import default xml files',
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument(
+        '--default-xml-path',
+        required=True,
+        help='The location of the default profiles')
+    args = parser.parse_args(argv)
+    ReadDefaultXMLs(args.default_xml_path)
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())

+ 68 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/cmake/SuperBuild.cmake

@@ -0,0 +1,68 @@
+# Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include(ExternalProject)
+
+unset(_deps)
+
+enable_language(C)
+enable_language(CXX)
+
+unset(xrceagent_DIR CACHE)
+find_package(xrceagent 2 EXACT QUIET)
+if(NOT xrceagent_FOUND)
+    ExternalProject_Add(xrceagent
+            GIT_REPOSITORY
+                https://github.com/eProsima/Micro-XRCE-DDS-Agent.git
+            GIT_TAG
+                v2.4.2
+            PREFIX
+                ${PROJECT_BINARY_DIR}/agent
+            INSTALL_DIR
+                ${CMAKE_INSTALL_PREFIX}
+            CMAKE_CACHE_ARGS
+                -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
+                -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
+                -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+                -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
+                -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+                -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
+                -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
+                -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+                -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+                -DCMAKE_PREFIX_PATH:PATH=<INSTALL_DIR>
+                -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
+                -DUAGENT_USE_SYSTEM_FASTDDS:BOOL=ON
+                -DUAGENT_USE_SYSTEM_FASTCDR:BOOL=ON
+                -DUAGENT_USE_SYSTEM_LOGGER:BOOL=${UAGENT_USE_SYSTEM_LOGGER}
+                -DUAGENT_CED_PROFILE:BOOL=OFF
+                -DUAGENT_P2P_PROFILE:BOOL=OFF
+                -DUAGENT_BUILD_EXECUTABLE:BOOL=OFF
+                -DUAGENT_ISOLATED_INSTALL:BOOL=OFF
+            )
+endif()
+
+# Main project.
+ExternalProject_Add(micro_ros_agent
+    SOURCE_DIR
+        ${PROJECT_SOURCE_DIR}
+    BINARY_DIR
+        ${CMAKE_CURRENT_BINARY_DIR}
+    CMAKE_CACHE_ARGS
+        -DMICROROSAGENT_SUPERBUILD:BOOL=OFF
+    INSTALL_COMMAND
+        ""
+    DEPENDS
+        xrceagent
+    )

+ 55 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/Agent.hpp

@@ -0,0 +1,55 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UROS_AGENT_AGENT_HPP
+#define _UROS_AGENT_AGENT_HPP
+
+#include <uxr/agent/AgentInstance.hpp>
+#include <uxr/agent/middleware/Middleware.hpp>
+#include <uxr/agent/middleware/utils/Callbacks.hpp>
+
+#include <agent/graph_manager/graph_manager.hpp>
+
+#include <map>
+#include <memory>
+
+// TODO(jamoralp): class Documentation
+namespace uros {
+namespace agent {
+
+class Agent
+{
+public:
+
+    Agent();
+
+    ~Agent() = default;
+
+    bool create(
+            int argc,
+            char** argv);
+
+    void run();
+
+private:
+
+    eprosima::uxr::AgentInstance& xrce_dds_agent_instance_;
+    std::map<eprosima::fastdds::dds::DomainId_t, std::shared_ptr<graph_manager::GraphManager>> graph_manager_map_;
+
+    std::shared_ptr<graph_manager::GraphManager> find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id);
+};
+
+}  // namespace agent
+}  // namespace uros
+#endif  // _UROS_AGENT_AGENT_HPP

+ 317 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp

@@ -0,0 +1,317 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UROS_AGENT_GRAPH_MANAGER_HPP
+#define _UROS_AGENT_GRAPH_MANAGER_HPP
+
+#include "fastrtps/Domain.h"
+#include <fastrtps/TopicDataType.h>
+#include "fastrtps/attributes/ParticipantAttributes.h"
+#include "fastrtps/participant/Participant.h"
+#include "fastrtps/participant/ParticipantListener.h"
+#include "fastrtps/attributes/PublisherAttributes.h"
+#include "fastrtps/publisher/Publisher.h"
+#include <fastrtps/publisher/PublisherListener.h>
+#include <fastrtps/rtps/common/MatchingInfo.h>
+
+#include <fastdds/dds/domain/DomainParticipant.hpp>
+#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
+#include <fastdds/dds/domain/DomainParticipantListener.hpp>
+#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
+#include <fastdds/dds/publisher/DataWriter.hpp>
+#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
+#include <fastdds/dds/publisher/Publisher.hpp>
+#include <fastdds/dds/subscriber/DataReader.hpp>
+#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
+#include <fastdds/dds/subscriber/SampleInfo.hpp>
+#include <fastdds/dds/subscriber/Subscriber.hpp>
+#include <fastdds/dds/subscriber/DataReaderListener.hpp>
+
+#include "rmw/types.h"
+#include "rmw/names_and_types.h"
+#include "rmw/impl/cpp/key_value.hpp"
+#include "rmw_dds_common/graph_cache.hpp"
+#include "rmw_fastrtps_shared_cpp/create_rmw_gid.hpp"
+#include "rmw_fastrtps_shared_cpp/qos.hpp"
+
+#include "rcutils/types.h"
+#include "rcutils/types/string_array.h"
+
+#include "rosidl_typesupport_cpp/message_type_support.hpp"
+#include "rosidl_typesupport_fastrtps_cpp/message_type_support.h"
+
+#include "rmw_dds_common/msg/participant_entities_info.hpp"
+#include "micro_ros_msgs/msg/graph.hpp"
+#include "micro_ros_msgs/msg/node.hpp"
+#include "micro_ros_msgs/msg/entity.hpp"
+
+#include <uxr/agent/types/XRCETypes.hpp>
+
+#include <agent/graph_manager/graph_typesupport.hpp>
+#include <agent/utils/demangle.hpp>
+
+#include <condition_variable>
+#include <string>
+#include <memory>
+#include <map>
+#include <thread>
+
+namespace uros {
+namespace agent {
+namespace graph_manager {
+
+/**
+ * @brief   Class that keeps track of the existing entities in the ROS 2 world,
+ *          both coming from micro-ROS or from external ROS 2 applications.
+ */
+class GraphManager
+{
+public:
+    /**
+     * @brief   Default constructor.
+     */
+    GraphManager(eprosima::fastdds::dds::DomainId_t domain_id);
+
+    /**
+     * @brief   Default destructor.
+     */
+    ~GraphManager() = default;
+
+    /**
+     * @brief   Implementation of the notification logic that updates the micro-ROS graph.
+     */
+    void publish_microros_graph();
+
+    /**
+     * @brief   Adds a DDS participant to the graph tree.
+     * @param   participant eprosima::fastdds::dds::DomainParticipant to be added.
+     * @param   from_microros if this participant has been added from micro-ROS.
+     * @param   enclave ROS 2 enclave.
+     */
+    void add_participant(
+            const eprosima::fastdds::dds::DomainParticipant* participant,
+            bool from_microros = true,
+            const std::string& enclave = "/");
+
+    /**
+     * @brief   Removes a DDS participant from the graph tree.
+     * @param   participant eprosima::fastdds::dds::DomainParticipant to be removed.
+     */
+    void remove_participant(
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        bool from_microros = true);
+
+    /**
+     * @brief   Getter for the graph cache.
+     * @return  Reference to inner graph cache
+     */
+    rmw_dds_common::GraphCache& get_graph_cache() { return graphCache_; }
+
+    /**
+     * @brief   Adds a DDS datawriter to the graph tree.
+     * @param   datawriter_guid rtps::GUID_t of the datawriter to be added.
+     * @param   participant Pointer to the participant which owns this datawriter.
+     * @param   datawriter Pointer to the datawriter to be added.
+     */
+    void add_datawriter(
+            const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
+            const eprosima::fastdds::dds::DomainParticipant* participant,
+            const eprosima::fastdds::dds::DataWriter* datawriter);
+
+    /**
+     * @brief   Adds a DDS datawriter to the graph tree.
+     * @param   datawriter_guid rtps::GUID_t of the datawriter to be added.
+     * @param   topic_name Name of the topic to which the datawriter sends information to.
+     * @param   type_name Type name of the sent topic.
+     * @param   participant_guid rtps::GUID_t of the participant which owns this datawriter.
+     * @param   writer_qos QOS of the datawriter to be included into the graph tree.
+     */
+    void add_datawriter(
+            const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
+            const std::string& topic_name,
+            const std::string& type_name,
+            const eprosima::fastrtps::rtps::GUID_t& participant_guid,
+            const eprosima::fastdds::dds::DataWriterQos& writer_qos);
+
+    /**
+     * @brief   Removes a DDS datawriter from the graph tree.
+     * @param   datawriter_guid rtps::GUID_t of the datawriter to be removed.
+     */
+    void remove_datawriter(
+            const eprosima::fastrtps::rtps::GUID_t& datawriter_guid);
+
+    /**
+     * @brief   Adds a DDS datareader to the graph tree.
+     * @param   datareader_guid rtps::GUID_t of the datareader to be added.
+     * @param   participant Pointer to the participant which owns this datareader.
+     * @param   datareader Pointer to the datareader to be added.
+     */
+    void add_datareader(
+            const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
+            const eprosima::fastdds::dds::DomainParticipant* participant,
+            const eprosima::fastdds::dds::DataReader* datareader);
+
+    /**
+     * @brief   Adds a DDS datareader to the graph tree.
+     * @param   datareader_guid rtps::GUID_t of the datareader to be added.
+     * @param   topic_name Name of the topic to which the datareader sends information to.
+     * @param   type_name Type name of the sent topic.
+     * @param   participant_guid rtps::GUID_t of the participant which owns this datareader.
+     * @param   writer_qos QOS of the datareader to be included into the graph tree.
+     */
+    void add_datareader(
+            const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
+            const std::string& topic_name,
+            const std::string& type_name,
+            const eprosima::fastrtps::rtps::GUID_t& participant_guid,
+            const eprosima::fastdds::dds::DataReaderQos& reader_qos);
+
+    /**
+     * @brief   Removes a DDS datareader from the graph tree.
+     * @param   datareader_guid rtps::GUID_t of the datareader to be removed.
+     */
+    void remove_datareader(
+            const  eprosima::fastrtps::rtps::GUID_t& datareader_guid);
+
+    /**
+     * @brief   Associates a certain DDS entity with a provided participant.
+     * @param   guid rtps::GUID_t identifier of the entity.
+     * @param   participant Participant to be associated with.
+     * @param   entity_kind Kind of the DDS entity.
+     */
+    void associate_entity(
+            const eprosima::fastrtps::rtps::GUID_t& entity_guid,
+            const eprosima::fastdds::dds::DomainParticipant* participant,
+            const dds::xrce::ObjectKind& entity_kind);
+
+private:
+
+    /**
+     * @brief   Implementation of FastDDS' DomainParticipantListener abstract class.
+     */
+    class ParticipantListener : public eprosima::fastdds::dds::DomainParticipantListener
+    {
+    public:
+
+        /**
+         * @brief   Constructor.
+         * @param   graph_manager Pointer to the GraphManager object which owns this ParticipantListener.
+         */
+        ParticipantListener(
+                GraphManager* graph_manager);
+    private:
+
+        template <typename Info>
+        void process_discovery_info(
+                const Info& proxyData);
+
+        void on_participant_discovery(
+                eprosima::fastdds::dds::DomainParticipant* participant,
+                eprosima::fastrtps::rtps::ParticipantDiscoveryInfo&& info) override;
+
+        void on_subscriber_discovery(
+                eprosima::fastdds::dds::DomainParticipant* /*participant*/,
+                eprosima::fastrtps::rtps::ReaderDiscoveryInfo&& info) override;
+
+        void on_publisher_discovery(
+                eprosima::fastdds::dds::DomainParticipant* /*participant*/,
+                eprosima::fastrtps::rtps::WriterDiscoveryInfo&& info) override;
+
+        GraphManager* graphManager_from_;
+    };
+
+    /**
+     * @brief   Implementation of FastDDS' DomainReaderListener abstract class.
+     */
+    class DatareaderListener : public eprosima::fastdds::dds::DataReaderListener
+    {
+    public:
+
+        /**
+         * @brief   Constructor.
+         * @param   graph_manager Pointer to the GraphManager object which owns this DataReaderListener.
+         */
+        DatareaderListener(
+                GraphManager* graph_manager);
+
+    private:
+
+        void on_data_available(
+                eprosima::fastdds::dds::DataReader* /*sub*/) override;
+
+        GraphManager* graphManager_from_;
+    };
+
+    /**
+     * @brief   Convert FastDDS QOS object instance to RMW instance.
+     * @param   fastdds_qos QOS instance to be converted.
+     * @returns RMW object representation of the given FastDDS QOS.
+     */
+    template <typename FastDDSQos>
+    const rmw_qos_profile_t fastdds_qos_to_rmw_qos(
+            const FastDDSQos& fastdds_qos);
+
+    /**
+     * @brief   Update micro-ROS graph information upon new data
+     *          received in the 'ros_discovery_info' topic.
+     */
+    void update_node_entities_info();
+
+    /**
+     * @brief   Retrieves node name and namespace from
+     *          participant.
+     * @param   participant_name DDS participant name.
+     * @param   node_name ROS2 Node name.
+     * @param   namespace ROS2 Node namespace.
+     */
+    void get_name_and_namespace(
+            std::string participant_name,
+            std::string& node_name,
+            std::string& node_namespace);
+
+    eprosima::fastdds::dds::DomainId_t domain_id_;
+    bool graph_changed_;
+    bool display_on_change_;
+    std::thread microros_graph_publisher_;
+    std::mutex mtx_;
+    std::condition_variable cv_;
+
+    eprosima::fastdds::dds::DataWriterQos datawriter_qos_;
+
+    rmw_dds_common::GraphCache graphCache_;
+    std::unique_ptr<ParticipantListener> participant_listener_;
+    std::unique_ptr<DatareaderListener> datareader_listener_;
+
+    std::unique_ptr<eprosima::fastdds::dds::TypeSupport> participant_info_typesupport_;
+    std::unique_ptr<eprosima::fastdds::dds::TypeSupport> microros_graph_info_typesupport_;
+    std::unique_ptr<eprosima::fastdds::dds::DomainParticipant> participant_;
+    std::unique_ptr<eprosima::fastdds::dds::Publisher> publisher_;
+    std::unique_ptr<eprosima::fastdds::dds::Subscriber> subscriber_;
+    std::unique_ptr<eprosima::fastdds::dds::Topic> ros_discovery_topic_;
+    std::unique_ptr<eprosima::fastdds::dds::Topic> ros_to_microros_graph_topic_;
+    std::unique_ptr<eprosima::fastdds::dds::DataWriter> ros_to_microros_graph_datawriter_;
+    std::unique_ptr<eprosima::fastdds::dds::DataReader> ros_discovery_datareader_;
+
+    // Store a auxiliary publishers and datawriter for each participant created in micro-ROS
+    std::map<
+        const eprosima::fastdds::dds::DomainParticipant*,
+        eprosima::fastdds::dds::DataWriter*
+    > micro_ros_graph_datawriters_;
+};
+
+}  // namespace graph_manager
+}  // namespace agent
+}  // namespace uros
+
+#endif  // _UROS_AGENT_GRAPH_MANAGER_HPP

+ 127 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/graph_manager/graph_typesupport.hpp

@@ -0,0 +1,127 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_
+#define UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_
+
+#include "fastrtps/Domain.h"
+#include <fastrtps/TopicDataType.h>
+#include "fastrtps/attributes/ParticipantAttributes.h"
+#include "fastrtps/participant/Participant.h"
+#include "fastrtps/participant/ParticipantListener.h"
+#include "fastrtps/attributes/PublisherAttributes.h"
+#include "fastrtps/publisher/Publisher.h"
+#include <fastrtps/publisher/PublisherListener.h>
+#include <fastrtps/rtps/common/MatchingInfo.h>
+
+#include <fastdds/dds/domain/DomainParticipant.hpp>
+#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
+
+#include "rmw/types.h"
+#include "rmw/impl/cpp/key_value.hpp"
+#include "rmw_dds_common/graph_cache.hpp"
+#include "rmw_fastrtps_shared_cpp/create_rmw_gid.hpp"
+#include "rmw_fastrtps_shared_cpp/qos.hpp"
+
+#include "rcutils/types.h"
+
+#include "rosidl_typesupport_cpp/message_type_support.hpp"
+#include "rosidl_typesupport_fastrtps_cpp/message_type_support.h"
+
+#include "rmw_dds_common/msg/participant_entities_info.hpp"
+
+#include "micro_ros_msgs/msg/graph.hpp"
+
+namespace uros {
+namespace agent {
+namespace graph_manager {
+
+/**
+ * @brief   Implementation of virtual class eprosima::fastdds::dds::TopicDataType.
+ *          Is used to gather and send information about the entities present within a DDS domain,
+ *          in the Agent's context.
+ */
+class ParticipantEntitiesInfoTypeSupport : public eprosima::fastdds::dds::TopicDataType
+{
+public:
+
+    ParticipantEntitiesInfoTypeSupport();
+
+    virtual bool serialize(
+            void* data,
+            eprosima::fastrtps::rtps::SerializedPayload_t* payload) override;
+
+    virtual bool deserialize(
+            eprosima::fastrtps::rtps::SerializedPayload_t* payload,
+            void* data) override;
+
+    virtual std::function<uint32_t()> getSerializedSizeProvider(
+            void* data) override;
+
+    virtual void* createData() override;
+
+    virtual void deleteData(void* data) override;
+
+    virtual bool getKey(
+            void* data,
+            eprosima::fastrtps::rtps::InstanceHandle_t* handle,
+            bool force_md5) override;
+
+private:
+
+    const message_type_support_callbacks_t* callbacks_;
+    const rosidl_message_type_support_t* type_support_;
+};
+
+/**
+ * @brief   Implementation of virtual class eprosima::fastdds::dds::TopicDataType.
+ *          Is used to send graph information to Micro-ROS.
+ */
+class MicrorosGraphInfoTypeSupport : public eprosima::fastdds::dds::TopicDataType
+{
+public:
+
+    MicrorosGraphInfoTypeSupport();
+
+    virtual bool serialize(
+            void* data,
+            eprosima::fastrtps::rtps::SerializedPayload_t* payload) override;
+
+    virtual bool deserialize(
+            eprosima::fastrtps::rtps::SerializedPayload_t* payload,
+            void* data) override;
+
+    virtual std::function<uint32_t()> getSerializedSizeProvider(
+            void* data) override;
+
+    virtual void* createData() override;
+
+    virtual void deleteData(void* data) override;
+
+    virtual bool getKey(
+            void* data,
+            eprosima::fastrtps::rtps::InstanceHandle_t* handle,
+            bool force_md5) override;
+
+private:
+
+    const message_type_support_callbacks_t* callbacks_;
+    const rosidl_message_type_support_t* type_support_;
+};
+
+}  // namespace graph_manager
+}  // namespace agent
+}  // namespace uros
+
+#endif  // UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_

+ 125 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/include/agent/utils/demangle.hpp

@@ -0,0 +1,125 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef UROS_AGENT_UTILS_DEMANGLE_HPP_
+#define UROS_AGENT_UTILS_DEMANGLE_HPP_
+
+#include <string>
+
+namespace uros {
+namespace agent {
+namespace utils {
+
+class Demangle
+{
+private:
+    /**
+     * @brief   Default constructor. Creating instances of this class is not allowed.
+     */
+    Demangle() = default;
+
+    /**
+     * @brief   Default destructor.
+     */
+    ~Demangle() = default;
+
+    /**
+     * @brief   Demangle service name for a given topic, prefix and service suffix,
+     *          if the topic is part of a service; otherwise, return blank.
+     * @param   prefix The ROS service prefix.
+     * @param   topic_name Topic to be demangled.
+     * @param   suffix The ROS service suffix.
+     * @returns The demangled service name.
+     */
+    static std::string _demangle_service_from_topic(
+            const std::string& prefix,
+            const std::string& topic_name,
+            const std::string& suffix);
+
+public:
+    /**
+     * @brief   Demangle if passed topic is a ROS topic; otherwise, keep it intact.
+     * @param   topic_name Topic to be demangled.
+     * @returns The demangled topic.
+     */
+    static std::string demangle_if_ros_topic(
+            const std::string& topic_name);
+
+    /**
+     * @brief   Demangle if passed type is a ROS type; otherwise, keep it intact.
+     * @param   dds_type_string Type to be demangled.
+     * @returns The demangled type.
+     */
+    static std::string demangle_if_ros_type(
+            const std::string& dds_type_string);
+
+    /**
+     * @brief   Demangle topic name for a given topic if it is part of one;
+     *          otherwise, return empty.
+     * @param   topic_name Topic to be demangled.
+     * @returns The demangled topic name.
+     */
+    static std::string demangle_ros_topic_from_topic(
+            const std::string& topic_name);
+
+    /**
+     * @brief   Demangle the service name for a given topic if it is part of a service;
+     *          otherwise, return empty.
+     * @param   topic_name Topic to be demangled.
+     * @returns The demangled service name.
+     */
+
+    static std::string demangle_service_from_topic(
+            const std::string& topic_name);
+
+    /**
+     * @brief   Demangle the service name for a given topic if it is part
+     *          of a service request; otherwise, return empty.
+     * @param   topic_name Topic to be demangled.
+     * @returns The demangled service request name.
+     */
+    static std::string demangle_service_request_from_topic(
+            const std::string& topic_name);
+
+    /**
+     * @brief   Demangle the service name for a given topic if it is part
+     *          of a service reply; otherwise, return empty.
+     * @param   topic_name Topic to be demangled.
+     * @returns The demangled service reply name.
+     */
+    static std::string demangle_service_reply_from_topic(
+            const std::string& topic_name);
+
+    /**
+     * @brief   Demangle the service type name if it is a ROS srv type; otherwise, return empty.
+     * @param   dds_type_name Type to be demangled.
+     * @returns The demangled service type.
+     */
+    static std::string demangle_service_type_only(
+            const std::string& dds_type_name);
+
+    /**
+     * @brief   Generic demangle function, used when ROS names are not mangled.
+     * @param   name Generic name to be demangled.
+     * @returns The demangled name.
+     */
+    static std::string identity_demangle(
+            const std::string& name);
+};
+
+}  // namespace utils
+}  // namespace agent
+}  // namespace uros
+
+#endif  // UROS_AGENT_UTILS_DEMANGLE_HPP_

+ 12 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/launch/micro_ros_agent_launch.py

@@ -0,0 +1,12 @@
+from launch import LaunchDescription
+from launch_ros.actions import Node
+
+def generate_launch_description():
+    return LaunchDescription([
+        Node(
+            package='micro_ros_agent',
+            executable='micro_ros_agent',
+            name='micro_ros_agent',
+            arguments=["udp4", "-p", "8888", "-v6"]
+        )
+    ])

+ 35 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/package.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
+<package format="3">
+  <name>micro_ros_agent</name>
+  <version>3.0.6</version>
+  <description>micro-ROS Agent package</description>
+  <maintainer email="eugeniocollado@eprosima.com">Eugenio Collado</maintainer>
+  <maintainer email="davidlaseca@eprosima.com">David Laseca</maintainer>
+  <license>Apache License 2.0</license>
+
+  <buildtool_depend>ament_cmake</buildtool_depend>
+
+  <test_depend>rosidl_default_generators</test_depend>
+
+  <test_depend>ament_lint_auto</test_depend>
+  <test_depend>ament_lint_common</test_depend>
+
+  <depend>rmw</depend>
+  <depend>rcutils</depend>
+  <depend>rmw_fastrtps_shared_cpp</depend>
+  <depend>rmw_dds_common</depend>
+  <depend>micro_ros_msgs</depend>
+
+  <test_depend>rosidl_typesupport_fastrtps_cpp</test_depend>
+  <test_depend>ament_cmake_gtest</test_depend>
+  <test_depend>builtin_interfaces</test_depend>
+
+  <export>
+    <build_type>ament_cmake</build_type>
+  </export>
+</package>
+
+
+
+

+ 24 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/resource/StaticValues.xml

@@ -0,0 +1,24 @@
+    <participant profile_name="participant_profile">
+        <rtps>
+            <name>participant_profile</name>
+        </rtps>
+    </participant>
+    <data_writer profile_name="shapetype_data_writer">
+        <topic>
+            <kind>WITH_KEY</kind>
+            <name>Square</name>
+            <dataType>ShapeType</dataType>
+        </topic>
+    </data_writer>
+    <data_reader profile_name="shapetype_data_reader">
+        <topic>
+            <kind>WITH_KEY</kind>
+            <name>Square</name>
+            <dataType>ShapeType</dataType>
+        </topic>
+    </data_reader>
+    <topic profile_name="shapetype_topic">
+        <kind>WITH_KEY</kind>
+        <name>Square</name>
+        <dataType>ShapeType</dataType>
+    </topic>

+ 29 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/resource/rclcpp.xml

@@ -0,0 +1,29 @@
+    <topic profile_name="parameter_events_t">
+        <name>rt/parameter_events</name>
+        <dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
+    </topic>
+     <topic profile_name="clock_t">
+        <name>rt/clock</name>
+        <dataType>rosgraph_msgs::msg::dds_::Clock_</dataType>
+    </topic>
+    <data_writer profile_name="parameter_events_p">
+        <topic>
+            <kind>NO_KEY</kind>
+            <name>rt/parameter_events</name>
+            <dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
+        </topic>
+    </data_writer>
+    <data_reader profile_name="clock_s">
+        <topic>
+            <kind>NO_KEY</kind>
+            <name>rt/clock</name>
+            <dataType>rosgraph_msgs::msg::dds_::Clock_</dataType>
+        </topic>
+    </data_reader>
+    <data_reader profile_name="parameter_events_s">
+        <topic>
+            <kind>NO_KEY</kind>
+            <name>rt/parameter_events</name>
+            <dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
+        </topic>
+    </data_reader>

+ 313 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/Agent.cpp

@@ -0,0 +1,313 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UROS_AGENT_AGENT_CPP
+#define _UROS_AGENT_AGENT_CPP
+
+#include <agent/Agent.hpp>
+
+#include <utility>
+#include <memory>
+
+namespace uros {
+namespace agent {
+
+Agent::Agent()
+    : xrce_dds_agent_instance_(xrce_dds_agent_instance_.getInstance())
+{
+}
+
+bool Agent::create(
+        int argc,
+        char** argv)
+{
+    bool result = xrce_dds_agent_instance_.create(argc, argv);
+    if (result)
+    {
+        /**
+         * Add CREATE_PARTICIPANT callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *)> on_create_participant
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+                graph_manager_->add_participant(participant);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::CREATE_PARTICIPANT,
+            std::move(on_create_participant));
+
+        /**
+         * Add REMOVE_PARTICIPANT callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *)> on_delete_participant
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+                graph_manager_->remove_participant(participant);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::DELETE_PARTICIPANT,
+            std::move(on_delete_participant));
+
+        /**
+         * Add CREATE_DATAWRITER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *)> on_create_datawriter
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
+                graph_manager_->associate_entity(
+                    datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::CREATE_DATAWRITER,
+            std::move(on_create_datawriter));
+
+        /**
+         * Add DELETE_DATAWRITER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *)> on_delete_datawriter
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter) -> void
+            {
+
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->remove_datawriter(datawriter->guid());
+            });
+
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::DELETE_DATAWRITER,
+            std::move(on_delete_datawriter));
+
+        /**
+         * Add CREATE_DATAREADER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataReader*)> on_create_datareader
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataReader* datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                // TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->add_datareader(datareader_guid, participant, datareader);
+                graph_manager_->associate_entity(
+                    datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::CREATE_DATAREADER,
+            std::move(on_create_datareader));
+
+        /**
+         * Add DELETE_DATAREADER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataReader *)> on_delete_datareader
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataReader* datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                // TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->remove_datareader(datareader_guid);
+            });
+
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::DELETE_DATAREADER,
+            std::move(on_delete_datareader));
+
+        /**
+         * Add CREATE_REQUESTER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *,
+            const eprosima::fastdds::dds::DataReader *)> on_create_requester
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter,
+                const eprosima::fastdds::dds::DataReader * datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
+                graph_manager_->associate_entity(
+                    datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
+
+                // TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->add_datareader(datareader_guid, participant, datareader);
+                graph_manager_->associate_entity(
+                    datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::CREATE_REQUESTER,
+            std::move(on_create_requester));
+
+        /**
+         * Add DELETE_REQUESTER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *,
+            const eprosima::fastdds::dds::DataReader *)> on_delete_requester
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter,
+                const eprosima::fastdds::dds::DataReader * datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->remove_datawriter(datawriter->guid());
+
+                // TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->remove_datareader(datareader_guid);
+            });
+
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::DELETE_REQUESTER,
+            std::move(on_delete_requester));
+
+        /**
+         * Add CREATE_REPLIER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *,
+            const eprosima::fastdds::dds::DataReader *)> on_create_replier
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter,
+                const eprosima::fastdds::dds::DataReader * datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
+                graph_manager_->associate_entity(
+                    datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
+
+                // TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->add_datareader(datareader_guid, participant, datareader);
+                graph_manager_->associate_entity(
+                    datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
+            });
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::CREATE_REPLIER,
+            std::move(on_create_replier));
+
+        /**
+         * Add DELETE_REPLIER callback.
+         */
+        std::function<void (
+            const eprosima::fastdds::dds::DomainParticipant *,
+            const eprosima::fastdds::dds::DataWriter *,
+            const eprosima::fastdds::dds::DataReader *)> on_delete_replier
+            ([&](
+                const eprosima::fastdds::dds::DomainParticipant* participant,
+                const eprosima::fastdds::dds::DataWriter* datawriter,
+                const eprosima::fastdds::dds::DataReader * datareader) -> void
+            {
+                auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
+
+                graph_manager_->remove_datawriter(datawriter->guid());
+
+                // TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
+                const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
+                    datareader->get_instance_handle();
+                const eprosima::fastrtps::rtps::GUID_t datareader_guid =
+                    eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
+                graph_manager_->remove_datareader(datareader_guid);
+            });
+
+        xrce_dds_agent_instance_.add_middleware_callback(
+            eprosima::uxr::Middleware::Kind::FASTDDS,
+            eprosima::uxr::middleware::CallbackKind::DELETE_REPLIER,
+            std::move(on_delete_replier));
+    }
+
+    return result;
+}
+
+void Agent::run()
+{
+    return xrce_dds_agent_instance_.run();
+}
+
+std::shared_ptr<graph_manager::GraphManager> Agent::find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id)
+{
+
+auto it = graph_manager_map_.find(domain_id);
+
+    if (it != graph_manager_map_.end()) {
+        return it->second;
+    }else{
+        return graph_manager_map_.insert(
+            std::make_pair(
+                domain_id,
+                std::make_shared<graph_manager::GraphManager>(domain_id)
+            )
+        ).first->second;
+    }
+}
+
+}  // namespace agent
+}  // namespace uros
+#endif  // _UROS_AGENT_AGENT_CPP

+ 768 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp

@@ -0,0 +1,768 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UROS_AGENT_GRAPH_MANAGER_CPP
+#define _UROS_AGENT_GRAPH_MANAGER_CPP
+
+#include <agent/graph_manager/graph_manager.hpp>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace uros {
+namespace agent {
+namespace graph_manager {
+
+GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id)
+    : domain_id_(domain_id)
+    , graph_changed_(false)
+    , display_on_change_(false)
+    , mtx_()
+    , cv_()
+    , graphCache_()
+    , participant_listener_(std::make_unique<ParticipantListener>(this))
+    , datareader_listener_(std::make_unique<DatareaderListener>(this))
+    , participant_info_typesupport_(std::make_unique<
+        eprosima::fastdds::dds::TypeSupport>(new graph_manager::ParticipantEntitiesInfoTypeSupport()))
+    , microros_graph_info_typesupport_(std::make_unique<
+        eprosima::fastdds::dds::TypeSupport>(new graph_manager::MicrorosGraphInfoTypeSupport()))
+{
+    eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->load_profiles();
+
+    // Create DomainParticipant
+    eprosima::fastdds::dds::DomainParticipantQos participant_qos =
+        eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->get_default_participant_qos();
+
+    const char * enclave = "/";
+    size_t length = snprintf(nullptr, 0, "enclave=%s;", enclave) + 1;
+    participant_qos.user_data().resize(length);
+    snprintf(reinterpret_cast<char *>(participant_qos.user_data().data_vec().data()),
+        length, "enclave=%s;", enclave);
+
+    participant_qos.name(enclave);
+    participant_qos.wire_protocol().builtin.readerHistoryMemoryPolicy =
+        eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
+    participant_qos.wire_protocol().builtin.writerHistoryMemoryPolicy =
+        eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
+
+    eprosima::fastdds::dds::StatusMask par_mask = eprosima::fastdds::dds::StatusMask::none();
+    participant_.reset(eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->
+        create_participant(domain_id_, participant_qos, participant_listener_.get(), par_mask));
+
+    // Register participant within typesupport
+    participant_->register_type(*participant_info_typesupport_);
+    participant_->register_type(*microros_graph_info_typesupport_);
+
+    // Create publisher
+    publisher_.reset(participant_->create_publisher(
+        eprosima::fastdds::dds::PUBLISHER_QOS_DEFAULT));
+
+    // Create subscriber
+    subscriber_.reset(participant_->create_subscriber(
+        eprosima::fastdds::dds::SUBSCRIBER_QOS_DEFAULT));
+
+    // Create topics
+    ros_discovery_topic_.reset(participant_->create_topic("ros_discovery_info",
+        participant_info_typesupport_->get_type_name(),
+        eprosima::fastdds::dds::TOPIC_QOS_DEFAULT));
+
+    ros_to_microros_graph_topic_.reset(participant_->create_topic("ros_to_microros_graph",
+        microros_graph_info_typesupport_->get_type_name(),
+        eprosima::fastdds::dds::TOPIC_QOS_DEFAULT));
+
+    // Create datawriters
+    datawriter_qos_ =
+        eprosima::fastdds::dds::DATAWRITER_QOS_DEFAULT;
+
+    datawriter_qos_.history().kind =
+        eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
+    datawriter_qos_.history().depth = 1;
+    datawriter_qos_.endpoint().history_memory_policy =
+        eprosima::fastrtps::rtps::MemoryManagementPolicy::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
+    datawriter_qos_.publish_mode().kind =
+        eprosima::fastdds::dds::PublishModeQosPolicyKind::ASYNCHRONOUS_PUBLISH_MODE;
+    datawriter_qos_.reliability().kind =
+        eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
+    datawriter_qos_.durability().kind =
+        eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS;
+
+    eprosima::fastdds::dds::DataWriterQos ros_to_microros_datawriter_qos_ = datawriter_qos_;
+    ros_to_microros_datawriter_qos_.history().kind =
+        eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
+    ros_to_microros_graph_datawriter_.reset(
+        publisher_->create_datawriter(ros_to_microros_graph_topic_.get(), ros_to_microros_datawriter_qos_));
+
+    // Create datareaders
+
+    eprosima::fastdds::dds::DataReaderQos datareader_qos =
+        eprosima::fastdds::dds::DATAREADER_QOS_DEFAULT;
+    datareader_qos.history().kind =
+        eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
+    datareader_qos.history().depth = 1;
+    datareader_qos.endpoint().history_memory_policy =
+        eprosima::fastrtps::rtps::MemoryManagementPolicy::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
+    datareader_qos.reliability().kind =
+        eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
+    datareader_qos.durability().kind =
+        eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS;
+
+    ros_discovery_datareader_.reset(
+        subscriber_->create_datareader(ros_discovery_topic_.get(),
+            datareader_qos, datareader_listener_.get()));
+
+    // Set graph cache on change callback function
+    graphCache_.set_on_change_callback([this]()
+    {
+        {
+            std::unique_lock<std::mutex> lock(this->mtx_);
+            this->graph_changed_ = true;
+        }
+        this->cv_.notify_one();
+    });
+
+    microros_graph_publisher_ = std::thread(&GraphManager::publish_microros_graph, this);
+}
+
+inline void GraphManager::publish_microros_graph()
+{
+    while (true)
+    {
+        {
+            std::unique_lock<std::mutex> lock(mtx_);
+            cv_.wait(lock, [this]()
+            {
+                return this->graph_changed_;
+            });
+            graph_changed_ = false;
+        }
+
+        if (display_on_change_)
+        {
+            std::cout << "Updated uros Graph: graph changed" << std::endl;
+            std::cout << graphCache_ << std::endl;
+        }
+
+        micro_ros_msgs::msg::Graph graph_message;
+
+        rcutils_string_array_t node_names = rcutils_get_zero_initialized_string_array();
+        rcutils_string_array_t node_namespaces = rcutils_get_zero_initialized_string_array();
+        rcutils_allocator_t allocator = rcutils_get_default_allocator();
+
+        graphCache_.get_node_names(&node_names, &node_namespaces, nullptr, &allocator);
+
+        for (size_t i = 0; i < node_names.size; ++i)
+        {
+            const std::string node_name(node_names.data[i]);
+            const std::string node_namespace(node_namespaces.data[i]);
+
+            micro_ros_msgs::msg::Node node_message;
+            node_message.node_namespace = std::move(node_namespace);
+            node_message.node_name = std::move(node_name);
+
+            // Get publishers info
+            rmw_names_and_types_t writer_names_and_types =
+                rmw_get_zero_initialized_names_and_types();
+            if (RMW_RET_OK != graphCache_.get_writer_names_and_types_by_node(node_name, node_namespace,
+                uros::agent::utils::Demangle::demangle_ros_topic_from_topic,
+                uros::agent::utils::Demangle::demangle_if_ros_type,
+                &allocator, &writer_names_and_types))
+            {
+                break;
+            }
+
+            for (size_t i = 0; i < writer_names_and_types.names.size; ++i)
+            {
+                micro_ros_msgs::msg::Entity entity_message;
+                entity_message.entity_type = micro_ros_msgs::msg::Entity::PUBLISHER;
+                entity_message.name = std::move(std::string(writer_names_and_types.names.data[i]));
+
+                for (size_t j = 0; j < writer_names_and_types.types[i].size; ++j)
+                {
+                    entity_message.types.emplace_back(writer_names_and_types.types[i].data[j]);
+                }
+
+                node_message.entities.emplace_back(std::move(entity_message));
+            }
+
+            // Get subscribers info
+            rmw_names_and_types_t reader_names_and_types =
+                rmw_get_zero_initialized_names_and_types();
+            if (RMW_RET_OK != graphCache_.get_reader_names_and_types_by_node(node_name, node_namespace,
+                uros::agent::utils::Demangle::demangle_ros_topic_from_topic,
+                uros::agent::utils::Demangle::demangle_if_ros_type,
+                &allocator, &reader_names_and_types))
+            {
+                break;
+            }
+
+            for (size_t i = 0; i < reader_names_and_types.names.size; ++i)
+            {
+                micro_ros_msgs::msg::Entity entity_message;
+                entity_message.entity_type = micro_ros_msgs::msg::Entity::SUBSCRIBER;
+                entity_message.name = std::move(std::string(reader_names_and_types.names.data[i]));
+
+                for (size_t j = 0; j < reader_names_and_types.types[i].size; ++j)
+                {
+                    entity_message.types.emplace_back(reader_names_and_types.types[i].data[j]);
+                }
+
+                node_message.entities.emplace_back(std::move(entity_message));
+            }
+
+            // Get services
+            //// Get servers
+            rmw_names_and_types_t service_server_names_and_types =
+              rmw_get_zero_initialized_names_and_types();
+            if (RMW_RET_OK != graphCache_.get_names_and_types(
+                uros::agent::utils::Demangle::demangle_service_request_from_topic,
+                uros::agent::utils::Demangle::demangle_service_type_only,
+                &allocator, &service_server_names_and_types))
+            {
+                break;
+            }
+
+            for (size_t i = 0; i < service_server_names_and_types.names.size; ++i)
+            {
+                micro_ros_msgs::msg::Entity entity_message;
+                entity_message.entity_type = micro_ros_msgs::msg::Entity::SERVICE_SERVER;
+                entity_message.name = std::move(std::string(service_server_names_and_types.names.data[i]));
+
+                for (size_t j = 0; j < service_server_names_and_types.types[i].size; ++j)
+                {
+                    entity_message.types.emplace_back(service_server_names_and_types.types[i].data[j]);
+                }
+
+                node_message.entities.emplace_back(std::move(entity_message));
+            }
+
+            //// Get clients
+            rmw_names_and_types_t service_client_names_and_types =
+              rmw_get_zero_initialized_names_and_types();
+            if (RMW_RET_OK != graphCache_.get_names_and_types(
+                uros::agent::utils::Demangle::demangle_service_reply_from_topic,
+                uros::agent::utils::Demangle::demangle_service_type_only,
+                &allocator, &service_client_names_and_types))
+            {
+              break;
+            }
+
+            for (size_t i = 0; i < service_client_names_and_types.names.size; ++i)
+            {
+                micro_ros_msgs::msg::Entity entity_message;
+                entity_message.entity_type = micro_ros_msgs::msg::Entity::SERVICE_CLIENT;
+                entity_message.name = std::move(std::string(service_client_names_and_types.names.data[i]));
+
+                for (size_t j = 0; j < service_client_names_and_types.types[i].size; ++j)
+                {
+                    entity_message.types.emplace_back(service_client_names_and_types.types[i].data[j]);
+                }
+
+                node_message.entities.emplace_back(std::move(entity_message));
+            }
+
+            graph_message.nodes.emplace_back(std::move(node_message));
+
+            if (RMW_RET_OK != rmw_names_and_types_fini(&writer_names_and_types) ||
+                RMW_RET_OK != rmw_names_and_types_fini(&reader_names_and_types) ||
+                RMW_RET_OK != rmw_names_and_types_fini(&service_server_names_and_types) ||
+                RMW_RET_OK != rmw_names_and_types_fini(&service_client_names_and_types))
+            {
+                std::cerr << "Problem while freeing resources in Micro-ROS Graph Manager"
+                          << ", file: '" << __FILE__ << "', line: '" << __LINE__ << "'." << std::endl;
+                return;
+            }
+        }
+
+        ros_to_microros_graph_datawriter_->write(static_cast<void *>(&graph_message));
+
+        if (RCUTILS_RET_OK != rcutils_string_array_fini(&node_names) ||
+            RCUTILS_RET_OK != rcutils_string_array_fini(&node_namespaces))
+        {
+            std::cerr << "Problem while freeing resources in Micro-ROS Graph Manager"
+                      << ", file: '" << __FILE__ << "', line: '" << __LINE__ << "'." << std::endl;
+            break;
+        }
+    }
+}
+
+void GraphManager::add_participant(
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        bool from_microros,
+        const std::string& enclave)
+{
+    const eprosima::fastdds::dds::DomainParticipantQos qos = participant->get_qos();
+    const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", participant->guid());
+
+    graphCache_.add_participant(gid, enclave);
+
+    // Do not add root node and
+    // do not announce non-micro-ROS participants
+    if (qos.name().to_string() != "/" && from_microros)
+    {
+        std::string isolated_node_name, isolated_namespace;
+        get_name_and_namespace(qos.name().to_string(), isolated_node_name, isolated_namespace);
+
+        rmw_dds_common::msg::ParticipantEntitiesInfo info =
+            graphCache_.add_node(gid, isolated_node_name, isolated_namespace);
+
+        auto it = micro_ros_graph_datawriters_.find(participant);
+        if (it == micro_ros_graph_datawriters_.end())
+        {
+            // Create datawriter
+            eprosima::fastdds::dds::DataWriter * datawriter = publisher_->create_datawriter(ros_discovery_topic_.get(), datawriter_qos_);
+
+            it = micro_ros_graph_datawriters_.insert(
+                std::make_pair(participant, datawriter)).first;
+        }
+
+        it->second->write(static_cast<void *>(&info));
+    }
+}
+
+void GraphManager::remove_participant(
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        bool from_microros)
+{
+    const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", participant->guid());
+    graphCache_.remove_participant(gid);
+
+    if (from_microros)
+    {
+        rmw_dds_common::msg::ParticipantEntitiesInfo info;
+        rmw_dds_common::convert_gid_to_msg(&gid, &info.gid);
+        auto it = micro_ros_graph_datawriters_.find(participant);
+        it->second->write(static_cast<void *>(&info));
+        publisher_->delete_datawriter(it->second);
+        micro_ros_graph_datawriters_.erase(participant);
+    }
+}
+
+void GraphManager::add_datawriter(
+        const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        const eprosima::fastdds::dds::DataWriter* datawriter)
+{
+    const std::string& topic_name = datawriter->get_topic()->get_name();
+    const std::string& type_name = datawriter->get_topic()->get_type_name();
+    this->add_datawriter(datawriter_guid, topic_name, type_name,
+        participant->guid(), datawriter->get_qos());
+}
+
+void GraphManager::add_datawriter(
+        const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
+        const std::string& topic_name,
+        const std::string& type_name,
+        const eprosima::fastrtps::rtps::GUID_t& participant_guid,
+        const eprosima::fastdds::dds::DataWriterQos& writer_qos)
+{
+    const rmw_gid_t datawriter_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", datawriter_guid);
+    const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", participant_guid);
+    const rmw_qos_profile_t qos_profile = fastdds_qos_to_rmw_qos(writer_qos);
+
+    graphCache_.add_entity(datawriter_gid, topic_name,
+        type_name, participant_gid, qos_profile, false);
+}
+
+void GraphManager::remove_datawriter(
+        const eprosima::fastrtps::rtps::GUID_t& datawriter_guid)
+{
+    const rmw_gid_t datawriter_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", datawriter_guid);
+
+    graphCache_.remove_entity(datawriter_gid, false);
+}
+
+void GraphManager::add_datareader(
+        const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        const eprosima::fastdds::dds::DataReader* datareader)
+{
+    const std::string& topic_name = datareader->get_topicdescription()->get_name();
+    const std::string& type_name = datareader->get_topicdescription()->get_type_name();
+    this->add_datareader(datareader_guid, topic_name, type_name,
+        participant->guid(), datareader->get_qos());
+}
+
+void GraphManager::add_datareader(
+        const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
+        const std::string& topic_name,
+        const std::string& type_name,
+        const eprosima::fastrtps::rtps::GUID_t& participant_guid,
+        const eprosima::fastdds::dds::DataReaderQos& reader_qos)
+{
+    const rmw_gid_t datareader_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", datareader_guid);
+    const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", participant_guid);
+    const rmw_qos_profile_t qos_profile = fastdds_qos_to_rmw_qos(reader_qos);
+
+    graphCache_.add_entity(datareader_gid, topic_name,
+        type_name, participant_gid, qos_profile, true);
+}
+
+void GraphManager::remove_datareader(
+        const eprosima::fastrtps::rtps::GUID_t& datareader_guid)
+{
+    const rmw_gid_t datareader_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", datareader_guid);
+
+    graphCache_.remove_entity(datareader_gid, true);
+}
+
+void GraphManager::associate_entity(
+        const eprosima::fastrtps::rtps::GUID_t& entity_guid,
+        const eprosima::fastdds::dds::DomainParticipant* participant,
+        const dds::xrce::ObjectKind& entity_kind)
+{
+    const rmw_gid_t entity_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", entity_guid);
+    const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
+        "rmw_fastrtps_cpp", participant->guid());
+
+    eprosima::fastdds::dds::DomainParticipantQos qos = participant->get_qos();
+    rmw_dds_common::msg::ParticipantEntitiesInfo info;
+
+    switch (entity_kind)
+    {
+        case dds::xrce::OBJK_DATAWRITER:
+        {
+            std::string isolated_node_name, isolated_namespace;
+            get_name_and_namespace(qos.name().c_str(), isolated_node_name, isolated_namespace);
+            info = graphCache_.associate_writer(
+                entity_gid, participant_gid, isolated_node_name, isolated_namespace);
+            break;
+        }
+        case dds::xrce::OBJK_DATAREADER:
+        {
+            std::string isolated_node_name, isolated_namespace;
+            get_name_and_namespace(qos.name().c_str(), isolated_node_name, isolated_namespace);
+            info = graphCache_.associate_reader(
+                entity_gid, participant_gid, isolated_node_name, isolated_namespace);
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    auto it = micro_ros_graph_datawriters_.find(participant);
+    it->second->write(static_cast<void *>(&info));
+}
+
+
+template <typename FastDDSQos>
+const rmw_qos_profile_t GraphManager::fastdds_qos_to_rmw_qos(
+        const FastDDSQos& fastdds_qos)
+{
+    rmw_qos_profile_t rmw_qos = rmw_qos_profile_unknown;
+    switch (fastdds_qos.reliability().kind)
+    {
+        case eprosima::fastdds::dds::ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS:
+        {
+            rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
+            break;
+        }
+        case eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS:
+        {
+            rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
+            break;
+        }
+        default:
+        {
+            rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
+            break;
+        }
+    }
+
+    switch (fastdds_qos.durability().kind)
+    {
+        case eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS:
+        {
+            rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
+            break;
+        }
+        case eprosima::fastdds::dds::DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS:
+        {
+            rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
+            break;
+        }
+        default:
+        {
+            rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
+            break;
+        }
+    }
+
+    rmw_qos.deadline.sec = fastdds_qos.deadline().period.seconds;
+    rmw_qos.deadline.nsec = fastdds_qos.deadline().period.nanosec;
+
+    rmw_qos.lifespan.sec = fastdds_qos.lifespan().duration.seconds;
+    rmw_qos.lifespan.nsec = fastdds_qos.lifespan().duration.nanosec;
+
+    switch (fastdds_qos.liveliness().kind)
+    {
+        case eprosima::fastdds::dds::LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS:
+        {
+            rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
+            break;
+        }
+        case eprosima::fastdds::dds::LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS:
+        {
+            rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
+            break;
+        }
+        default:
+        {
+            rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
+            break;
+        }
+    }
+
+    rmw_qos.liveliness_lease_duration.sec = fastdds_qos.liveliness().lease_duration.seconds;
+    rmw_qos.liveliness_lease_duration.nsec = fastdds_qos.liveliness().lease_duration.nanosec;
+
+    return rmw_qos;
+}
+
+void GraphManager::update_node_entities_info()
+{
+    rmw_dds_common::msg::ParticipantEntitiesInfo entities_info;
+    eprosima::fastdds::dds::SampleInfo sample_info;
+    if (ros_discovery_datareader_->take_next_sample(&entities_info, &sample_info) ==
+        eprosima::fastrtps::types::ReturnCode_t::RETCODE_OK)
+    {
+        if (sample_info.instance_state == eprosima::fastdds::dds::InstanceStateKind::ALIVE_INSTANCE_STATE)
+        {
+            graphCache_.update_participant_entities(entities_info);
+        }
+    }
+}
+
+void GraphManager::get_name_and_namespace(
+    std::string participant_name,
+    std::string& node_name,
+    std::string& node_namespace)
+{
+    // Remove first / if exists
+    if (participant_name.rfind("/", 0) == 0)
+    {
+        participant_name.erase(participant_name.begin());
+    }
+
+    // Split node name in domain and node name
+    std::istringstream iss(participant_name);
+    std::vector<std::string> result;
+    std::string token;
+
+    while(std::getline(iss, token, '/'))
+    {
+        result.push_back(token);
+    }
+
+    if (result.size() > 1)
+    {
+        node_namespace = "/" + result[0];
+        for (size_t i = 1; i < result.size(); i++)
+        {
+            node_name.append(result[i] + "/");
+        }
+        node_name.pop_back();
+    }
+    else
+    {
+        node_name = participant_name;
+        node_namespace = "/";
+    }
+}
+
+GraphManager::ParticipantListener::ParticipantListener(
+        GraphManager* graph_manager)
+    : eprosima::fastdds::dds::DomainParticipantListener()
+    , graphManager_from_(graph_manager)
+{
+}
+
+void GraphManager::ParticipantListener::on_participant_discovery(
+        eprosima::fastdds::dds::DomainParticipant* /* participant */,
+        eprosima::fastrtps::rtps::ParticipantDiscoveryInfo&& info)
+{
+    switch (info.status)
+    {
+        case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DISCOVERED_PARTICIPANT:
+        {
+            auto map = rmw::impl::cpp::parse_key_value(info.info.m_userData);
+            auto name_found = map.find("enclave");
+
+            if (map.end() == name_found)
+            {
+                return;
+            }
+            const std::string enclave =
+                std::string(name_found->second.begin(), name_found->second.end());
+
+            const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", info.info.m_guid);
+            graphManager_from_->get_graph_cache().add_participant(gid, enclave);
+            break;
+        }
+        case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::REMOVED_PARTICIPANT:
+        case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DROPPED_PARTICIPANT:
+        {
+            const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", info.info.m_guid);
+            graphManager_from_->get_graph_cache().remove_participant(gid);
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+static eprosima::fastdds::dds::DataWriterQos writer_qos_conversion(
+    const eprosima::fastdds::dds::WriterQos& writer_qos)
+{
+    eprosima::fastdds::dds::DataWriterQos datawriter_qos;
+    datawriter_qos.durability(writer_qos.m_durability);
+    datawriter_qos.durability_service(writer_qos.m_durabilityService);
+    datawriter_qos.deadline(writer_qos.m_deadline);
+    datawriter_qos.latency_budget(writer_qos.m_latencyBudget);
+    datawriter_qos.liveliness(writer_qos.m_liveliness);
+    datawriter_qos.reliability(writer_qos.m_reliability);
+    datawriter_qos.destination_order(writer_qos.m_destinationOrder);
+    datawriter_qos.lifespan(writer_qos.m_lifespan);
+    datawriter_qos.user_data(writer_qos.m_userData);
+    datawriter_qos.ownership(writer_qos.m_ownership);
+    datawriter_qos.ownership_strength(writer_qos.m_ownershipStrength);
+    datawriter_qos.publish_mode(writer_qos.m_publishMode);
+    datawriter_qos.representation(writer_qos.representation);
+    datawriter_qos.data_sharing(writer_qos.data_sharing);
+
+    return datawriter_qos;
+}
+
+static eprosima::fastdds::dds::DataReaderQos reader_qos_conversion(
+    const eprosima::fastdds::dds::ReaderQos& reader_qos)
+{
+    eprosima::fastdds::dds::DataReaderQos datareader_qos;
+
+    datareader_qos.durability(reader_qos.m_durability);
+    datareader_qos.deadline(reader_qos.m_deadline);
+    datareader_qos.latency_budget(reader_qos.m_latencyBudget);
+    datareader_qos.liveliness(reader_qos.m_liveliness);
+    datareader_qos.reliability(reader_qos.m_reliability);
+    datareader_qos.destination_order(reader_qos.m_destinationOrder);
+    datareader_qos.user_data(reader_qos.m_userData);
+    datareader_qos.ownership(reader_qos.m_ownership);
+    datareader_qos.time_based_filter(reader_qos.m_timeBasedFilter);
+    datareader_qos.lifespan(reader_qos.m_lifespan);
+    datareader_qos.durability_service(reader_qos.m_durabilityService);
+    eprosima::fastdds::dds::TypeConsistencyQos consistency;
+    consistency.type_consistency = reader_qos.type_consistency;
+    datareader_qos.type_consistency(consistency);
+    datareader_qos.data_sharing(reader_qos.data_sharing);
+
+    return datareader_qos;
+}
+
+template <>
+void GraphManager::ParticipantListener::process_discovery_info<eprosima::fastrtps::rtps::ReaderDiscoveryInfo>(
+        const eprosima::fastrtps::rtps::ReaderDiscoveryInfo& reader_info)
+{
+    switch (reader_info.status)
+    {
+        case eprosima::fastrtps::rtps::ReaderDiscoveryInfo::CHANGED_QOS_READER:
+        {
+            return;
+        }
+        case eprosima::fastrtps::rtps::ReaderDiscoveryInfo::DISCOVERED_READER:
+        {
+            const std::string topic_name = reader_info.info.topicName().to_string();
+            const std::string type_name = reader_info.info.typeName().to_string();
+
+            graphManager_from_->add_datareader(reader_info.info.guid(), topic_name, type_name,
+                iHandle2GUID(reader_info.info.RTPSParticipantKey()), reader_qos_conversion(reader_info.info.m_qos));
+            break;
+        }
+        default:
+        {
+            graphManager_from_->remove_datareader(reader_info.info.guid());
+            break;
+        }
+    }
+}
+
+template <>
+void GraphManager::ParticipantListener::process_discovery_info<eprosima::fastrtps::rtps::WriterDiscoveryInfo>(
+        const eprosima::fastrtps::rtps::WriterDiscoveryInfo& writer_info)
+{
+    switch (writer_info.status)
+    {
+        case eprosima::fastrtps::rtps::WriterDiscoveryInfo::CHANGED_QOS_WRITER:
+        {
+            return;
+        }
+        case eprosima::fastrtps::rtps::WriterDiscoveryInfo::DISCOVERED_WRITER:
+        {
+            const std::string topic_name = writer_info.info.topicName().to_string();
+            const std::string type_name = writer_info.info.typeName().to_string();
+
+            graphManager_from_->add_datawriter(writer_info.info.guid(), topic_name, type_name,
+                iHandle2GUID(writer_info.info.RTPSParticipantKey()), writer_qos_conversion(writer_info.info.m_qos));
+            break;
+        }
+        default:
+        {
+            graphManager_from_->remove_datawriter(writer_info.info.guid());
+            break;
+        }
+    }
+}
+
+void GraphManager::ParticipantListener::on_subscriber_discovery(
+        eprosima::fastdds::dds::DomainParticipant* /*participant*/,
+        eprosima::fastrtps::rtps::ReaderDiscoveryInfo&& info)
+{
+    process_discovery_info<eprosima::fastrtps::rtps::ReaderDiscoveryInfo>(info);
+}
+
+void GraphManager::ParticipantListener::on_publisher_discovery(
+        eprosima::fastdds::dds::DomainParticipant* /*participant*/,
+        eprosima::fastrtps::rtps::WriterDiscoveryInfo&& info)
+{
+    process_discovery_info<eprosima::fastrtps::rtps::WriterDiscoveryInfo>(info);
+}
+
+GraphManager::DatareaderListener::DatareaderListener(
+        GraphManager* graph_manager)
+    : eprosima::fastdds::dds::DataReaderListener()
+    , graphManager_from_(graph_manager)
+{
+}
+
+void GraphManager::DatareaderListener::on_data_available(
+        eprosima::fastdds::dds::DataReader* /*sub*/)
+{
+    graphManager_from_->update_node_entities_info();
+}
+
+}  // namespace graph_manager
+}  // namespace agent
+}  // namespace uros
+
+#endif  // _UROS_AGENT_GRAPH_MANAGER_CPP

+ 213 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/graph_manager/graph_typesupport.cpp

@@ -0,0 +1,213 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_
+#define UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_
+
+#include <agent/graph_manager/graph_typesupport.hpp>
+
+#include <string>
+
+namespace uros {
+namespace agent {
+namespace graph_manager {
+
+ParticipantEntitiesInfoTypeSupport::ParticipantEntitiesInfoTypeSupport()
+    : TopicDataType()
+{
+    type_support_ = rosidl_typesupport_cpp::get_message_type_support_handle<
+        rmw_dds_common::msg::ParticipantEntitiesInfo>();
+    type_support_ = get_message_typesupport_handle(type_support_,
+        "rosidl_typesupport_fastrtps_cpp");
+    callbacks_ = static_cast<const message_type_support_callbacks_t *>(type_support_->data);
+
+    std::ostringstream ss;
+    const std::string message_namespace(callbacks_->message_namespace_);
+    const std::string message_name(callbacks_->message_name_);
+
+    if (!message_namespace.empty())
+    {
+        ss << message_namespace << "::";
+    }
+    ss << "dds_::" << message_name << "_";
+    this->setName(ss.str().c_str());
+
+    char full_bounded;
+    m_typeSize = 4 + callbacks_->max_serialized_size(full_bounded);
+}
+
+bool ParticipantEntitiesInfoTypeSupport::serialize(
+        void * data,
+        eprosima::fastrtps::rtps::SerializedPayload_t * payload)
+{
+    eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
+        payload->max_size);
+    eprosima::fastcdr::Cdr scdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
+        eprosima::fastcdr::Cdr::DDS_CDR);
+
+    scdr.serialize_encapsulation();
+    if (callbacks_->cdr_serialize(data, scdr))
+    {
+        payload->encapsulation = (scdr.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS) ?
+            CDR_BE : CDR_LE;
+        payload->length = static_cast<uint32_t>(scdr.getSerializedDataLength());
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+bool ParticipantEntitiesInfoTypeSupport::deserialize(
+        eprosima::fastrtps::rtps::SerializedPayload_t * payload,
+        void * data)
+{
+    eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
+        payload->length);
+    eprosima::fastcdr::Cdr dcdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
+        eprosima::fastcdr::Cdr::DDS_CDR);
+
+    dcdr.read_encapsulation();
+    return callbacks_->cdr_deserialize(dcdr, data);
+}
+
+std::function<uint32_t()> ParticipantEntitiesInfoTypeSupport::getSerializedSizeProvider(
+        void * data)
+{
+    return [data, this]() -> uint32_t
+    {
+        return static_cast<uint32_t>(4 + callbacks_->get_serialized_size(data));
+    };
+}
+
+void * ParticipantEntitiesInfoTypeSupport::createData()
+{
+    return static_cast<void *>(nullptr);
+}
+
+void ParticipantEntitiesInfoTypeSupport::deleteData(
+        void * data)
+{
+    (void) data;
+}
+
+bool ParticipantEntitiesInfoTypeSupport::getKey(
+        void * data,
+        eprosima::fastrtps::rtps::InstanceHandle_t * handle,
+        bool force_md5)
+{
+    (void) data;
+    (void) handle;
+    (void) force_md5;
+    return m_isGetKeyDefined;
+}
+
+
+MicrorosGraphInfoTypeSupport::MicrorosGraphInfoTypeSupport()
+    : TopicDataType()
+{
+    type_support_ = rosidl_typesupport_cpp::get_message_type_support_handle<
+        micro_ros_msgs::msg::Graph>();
+    type_support_ = get_message_typesupport_handle(type_support_,
+        "rosidl_typesupport_fastrtps_cpp");
+    callbacks_ = static_cast<const message_type_support_callbacks_t *>(type_support_->data);
+
+    std::ostringstream ss;
+    const std::string message_namespace(callbacks_->message_namespace_);
+    const std::string message_name(callbacks_->message_name_);
+
+    if (!message_namespace.empty())
+    {
+        ss << message_namespace << "::";
+    }
+    ss << "dds_::" << message_name << "_";
+    this->setName(ss.str().c_str());
+
+    char full_bounded;
+    m_typeSize = 4 + callbacks_->max_serialized_size(full_bounded);
+}
+
+bool MicrorosGraphInfoTypeSupport::serialize(
+        void * data,
+        eprosima::fastrtps::rtps::SerializedPayload_t * payload)
+{
+    eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
+        payload->max_size);
+    eprosima::fastcdr::Cdr scdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
+        eprosima::fastcdr::Cdr::DDS_CDR);
+
+    scdr.serialize_encapsulation();
+    if (callbacks_->cdr_serialize(data, scdr))
+    {
+        payload->encapsulation = (scdr.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS) ?
+            CDR_BE : CDR_LE;
+        payload->length = static_cast<uint32_t>(scdr.getSerializedDataLength());
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+bool MicrorosGraphInfoTypeSupport::deserialize(
+        eprosima::fastrtps::rtps::SerializedPayload_t * payload,
+        void * data)
+{
+    eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
+        payload->length);
+    eprosima::fastcdr::Cdr dcdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
+        eprosima::fastcdr::Cdr::DDS_CDR);
+
+    dcdr.read_encapsulation();
+    return callbacks_->cdr_deserialize(dcdr, data);
+}
+
+std::function<uint32_t()> MicrorosGraphInfoTypeSupport::getSerializedSizeProvider(
+        void * data)
+{
+    return [data, this]() -> uint32_t
+    {
+        return static_cast<uint32_t>(4 + callbacks_->get_serialized_size(data));
+    };
+}
+
+void * MicrorosGraphInfoTypeSupport::createData()
+{
+    return static_cast<void *>(nullptr);
+}
+
+void MicrorosGraphInfoTypeSupport::deleteData(
+        void * data)
+{
+    (void) data;
+}
+
+bool MicrorosGraphInfoTypeSupport::getKey(
+        void * data,
+        eprosima::fastrtps::rtps::InstanceHandle_t * handle,
+        bool force_md5)
+{
+    (void) data;
+    (void) handle;
+    (void) force_md5;
+    return m_isGetKeyDefined;
+}
+
+}  // namespace graph_manager
+}  // namespace agent
+}  // namespace uros
+
+#endif  // UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_

+ 191 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/agent/utils/demangle.cpp

@@ -0,0 +1,191 @@
+// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef UROS_AGENT_UTILS_DEMANGLE_CPP_
+#define UROS_AGENT_UTILS_DEMANGLE_CPP_
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <rcpputils/find_and_replace.hpp>
+#include <rcutils/logging_macros.h>
+#include <rcutils/types.h>
+
+#include <rmw_fastrtps_shared_cpp/namespace_prefix.hpp>
+
+#include <agent/utils/demangle.hpp>
+
+namespace uros {
+namespace agent {
+namespace utils {
+
+std::string Demangle::demangle_if_ros_topic(
+        const std::string& topic_name)
+{
+    return _strip_ros_prefix_if_exists(topic_name);
+}
+
+std::string Demangle::demangle_if_ros_type(
+        const std::string& dds_type_string)
+{
+    if ('_' != dds_type_string[dds_type_string.size() - 1])
+    {
+        // not a ROS type
+        return dds_type_string;
+    }
+
+    const std::string dds_prefix("dds_::");
+    size_t dds_prefix_pos = dds_type_string.find(dds_prefix);
+    if (std::string::npos == dds_prefix_pos)
+    {
+        // not a ROS type
+        return dds_type_string;
+    }
+
+    std::string type_namespace = dds_type_string.substr(0, dds_prefix_pos);
+    type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
+    size_t start = dds_prefix_pos + dds_prefix.size();
+    const std::string type_name =
+        dds_type_string.substr(start, dds_type_string.length() - start - 1);
+    return type_namespace + type_name;
+}
+
+std::string Demangle::demangle_ros_topic_from_topic(
+        const std::string& topic_name)
+{
+    return _resolve_prefix(topic_name, ros_topic_prefix);
+}
+
+std::string Demangle::_demangle_service_from_topic(
+        const std::string& prefix,
+        const std::string& topic_name,
+        const std::string& suffix)
+{
+    const std::string service_name = _resolve_prefix(topic_name, prefix);
+    if (service_name.empty())
+    {
+        return std::string();
+    }
+
+    size_t suffix_position = service_name.rfind(suffix);
+    if (std::string::npos == suffix_position)
+    {
+        RCUTILS_LOG_WARN_NAMED(
+            "rmw_fastrtps_shared_cpp",
+            "service topic has prefix but no suffix; report this: '%s'",
+            topic_name.c_str());
+        return std::string();
+    }
+    else
+    {
+        if (0 != (service_name.length() - suffix_position - suffix.length()))
+        {
+            RCUTILS_LOG_WARN_NAMED(
+                "rmw_fastrtps_shared_cpp",
+                "service topic has service prefix and a suffix"
+                ", but not at the end; report this: '%s'",
+                topic_name.c_str());
+            return std::string();
+        }
+    }
+    return service_name.substr(0, suffix_position);
+}
+
+std::string Demangle::demangle_service_from_topic(
+        const std::string& topic_name)
+{
+    const std::string demangled_topic = demangle_service_reply_from_topic(topic_name);
+
+    if (!demangled_topic.empty())
+    {
+        return demangled_topic;
+    }
+    return demangle_service_request_from_topic(topic_name);
+}
+
+std::string Demangle::demangle_service_request_from_topic(
+        const std::string& topic_name)
+{
+    return _demangle_service_from_topic(ros_service_requester_prefix, topic_name, "Request");
+}
+
+std::string Demangle::demangle_service_reply_from_topic(
+        const std::string& topic_name)
+{
+    return _demangle_service_from_topic(ros_service_response_prefix, topic_name, "Reply");
+}
+
+std::string Demangle::demangle_service_type_only(
+        const std::string& dds_type_name)
+{
+    const std::string dds_prefix("dds_::");
+    auto suffixes = {std::string("_Response_"), std::string("_Request_")};
+    size_t dds_prefix_pos = dds_type_name.find(dds_prefix);
+
+    // Perform checks
+    if (std::string::npos == dds_prefix_pos)
+    {
+        // not a ROS service type
+        return std::string();
+    }
+
+    size_t suffix_position = std::string::npos;
+    for (const auto& suffix : suffixes)
+    {
+        suffix_position = dds_type_name.rfind(suffix);
+        if (std::string::npos != suffix_position)
+        {
+            if (0 != (dds_type_name.length() - suffix_position - suffix.length()))
+            {
+                RCUTILS_LOG_WARN_NAMED(
+                    "rmw_fastrtps_shared_cpp",
+                    "service type contains 'dds_::' and a suffix"
+                    ", but not at the end; repor this: '%s'",
+                    dds_type_name.c_str());
+                continue;
+            }
+            break;
+        }
+    }
+    if (std::string::npos == suffix_position)
+    {
+        RCUTILS_LOG_WARN_NAMED(
+            "rmw_fastrtps_shared_cpp",
+            "service type contains 'dds_::' but"
+            " does not have a suffix; report this: '%s'",
+            dds_type_name.c_str());
+        return std::string();
+    }
+
+    // Everything is OK. Reformat it from '[type_namespace::]dds_::<type><suffix>'
+    // to '[type_namespace/]<type>'
+    std::string type_namespace = dds_type_name.substr(0, dds_prefix_pos);
+    type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
+    size_t start = dds_prefix_pos + dds_prefix.length();
+    const std::string type_name = dds_type_name.substr(start, suffix_position - start);
+    return type_namespace + type_name;
+}
+
+std::string Demangle::identity_demangle(
+        const std::string& name)
+{
+    return name;
+}
+
+}  // namespace utils
+}  // namespace agent
+}  // namespace uros
+
+#endif  // UROS_AGENT_UTILS_DEMANGLE_CPP_

+ 93 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/src/main.cpp

@@ -0,0 +1,93 @@
+// Copyright 2017-present Proyectos y Sistemas de Mantenimiento SL (eProsima).
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <agent/Agent.hpp>
+
+#include <string>
+#include <vector>
+
+int main(int argc, char** argv)
+{
+    uros::agent::Agent micro_ros_agent;
+
+    /** Bypass '--ros-args' flag, as we use our own CLI parser.
+      * As a workaround for launch files, arguments will be passed from
+      * ros2launch as a single token with spaces,
+      * to preserve the correct argument order; split it here.
+      * TODO(jamoralp): investigate ROS2 tools for properly parsing params from launch
+      **/
+    std::vector<std::string> params;
+    for (int i = 0; i < argc; ++i)
+    {
+        if(strcmp("--ros-args", argv[i]) == 0)
+        {
+            argc = i;
+            break;
+        }
+        params.emplace_back(std::string(argv[i]));
+    }
+
+    auto it = std::find(params.begin(), params.end(), "--ros-args");
+    if (params.end() != it)
+    {
+        if ((it - params.begin()) != 2)
+        {
+            std::ostringstream ss;
+            ss << "Error: when using ros2 launch, please specify ";
+            ss << "your arguments in a single variable." << std::endl;
+            ss << "Instead of 'arguments: {'udp4', '-p', '8888'}', do ";
+            ss << "'arguments: {'udp4 -p 8888'}" << std::endl;
+
+            std::cerr << ss.str();
+            return 1;
+        }
+        const std::string& agent_args(params.at(1));
+        std::istringstream iss(agent_args);
+        std::vector<std::string> agent_args_split(
+            std::istream_iterator<std::string>{iss},
+            std::istream_iterator<std::string>());
+
+        char** agent_argv = new char*[agent_args_split.size() + 1];
+        agent_argv[0] = argv[0];
+        char** agent_argv_it = &agent_argv[1];
+
+        for (const auto& arg : agent_args_split)
+        {
+            *agent_argv_it = new char[arg.length() + 1];
+            strcpy(*agent_argv_it, arg.c_str());
+            agent_argv_it++;
+        }
+
+        bool success = micro_ros_agent.create(agent_args_split.size() + 1, agent_argv);
+
+        for (size_t i = 1; i <= agent_args_split.size(); ++i)
+        {
+            delete [] agent_argv[i];
+        }
+        delete [] agent_argv;
+
+        if (!success)
+        {
+            return 1;
+        }
+    }
+    else if (!micro_ros_agent.create(argc, argv))
+    {
+        return 1;
+    }
+
+    micro_ros_agent.run();
+
+    return 0;
+}

+ 216 - 0
offline_voice_module/src/micro-ROS-Agent/micro_ros_agent/utils/__init__.py

@@ -0,0 +1,216 @@
+# Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+import xml.etree.ElementTree
+
+from rosidl_cmake import convert_camel_case_to_lower_case_underscore
+from rosidl_cmake import expand_template
+from rosidl_cmake import get_newest_modification_time
+from rosidl_adapter.parser import parse_message_file
+from rosidl_adapter.parser import parse_service_file
+from rosidl_adapter.parser import validate_field_types
+
+from rosidl_cmake import generate_files
+
+def GetPackage(Dir):
+    
+    # ignore?
+    for f in os.listdir(Dir):
+        full_path = os.path.join(Dir, f)
+        if os.path.isfile(full_path):
+            if f == "COLCON_IGNORE":
+                return "COLCON_IGNORE"
+
+    # found package
+    found_package_path = ""
+    for f in os.listdir(Dir):
+        if f == "package.xml":
+            found_package_path = os.path.join(Dir, f)
+            found_package_path = os.path.abspath(found_package_path)
+            break
+
+
+    return found_package_path.replace("\\", "/")
+
+
+def GetPackageList(Dir):
+    package_list = []
+    package_path = GetPackage(Dir)
+
+    if package_path == "":
+        for f in os.listdir(Dir):
+            full_path = os.path.join(Dir, f)
+            if os.path.isdir(full_path):
+                for l in GetPackageList(full_path):
+                    package_list.append(l)
+    elif package_path != "COLCON_IGNORE":
+        package_list.append(package_path)
+
+    return package_list
+
+
+def GetInterfacePackages(packages_list):
+    package_interface_list = []
+    for package in packages_list:
+        xml_root = xml.etree.ElementTree.parse(package).getroot()
+        for element in xml_root.findall('member_of_group'):
+            if element.text == "rosidl_interface_packages":
+                package_interface_list.append(package)
+    return package_interface_list
+
+
+def GetPackageName(package_path):
+    xml_root = xml.etree.ElementTree.parse(package_path).getroot()
+    xml_name_elements = xml_root.findall('name')
+    if len(xml_name_elements) != 1:
+        return ""
+    else:
+        return xml_name_elements[0].text
+
+
+def GetInterfacePackageMsgs(package_path):
+    msg_list = []
+    package_dir = os.path.dirname(package_path)
+    for root, dirs, files in os.walk(package_dir):
+        for file in files:
+            if file.endswith(".msg"):
+                full_path = os.path.join(root, file)
+                msg_list.append(full_path.replace("\\", "/"))
+
+    return msg_list
+
+def GetInterfacePackageSrvs(package_path):
+    msg_list = []
+    package_dir = os.path.dirname(package_path)
+    for root, dirs, files in os.walk(package_dir):
+        for file in files:
+            if file.endswith(".srv"):
+                full_path = os.path.join(root, file)
+                msg_list.append(full_path.replace("\\", "/"))
+
+    return msg_list
+
+
+def ReadDefaultXMLs(Path):
+    for f in os.listdir(Path):
+        full_path = os.path.join(Path, f)
+        if os.path.isfile(full_path) and f.endswith(".xml"):
+            #xml_root = xml.etree.ElementTree.parse(full_path).getroot()
+            #if xml_root.iselement():
+            fd = open(full_path)
+            print ("%s" % fd.read())
+            fd.close()
+
+
+
+def generate_XML(args):    
+    pkg_name = args['package_name']
+    #known_msg_types = extract_message_types(
+    #    pkg_name, args['ros_interface_files'], args.get('ros_interface_dependencies', []))
+
+    functions = {
+        'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore,
+    }
+
+
+    # Set file format
+    ros2_prefix = "rt/"
+
+
+    # Check destination dir
+    dest_dir = args['output_dir']
+    if not os.path.exists(dest_dir):
+        os.makedirs(dest_dir)
+
+
+    # Check source dir
+    srcs_dir = os.path.join(dest_dir, "srcs")
+    if not os.path.exists(srcs_dir):
+        os.makedirs(srcs_dir)
+
+        
+        
+    # Iterate throw all msgs/srvs
+    for idl_file in args['ros_interface_files']:
+        extension = os.path.splitext(idl_file)[1]
+        if extension == '.msg':
+            spec = parse_message_file(pkg_name, idl_file)
+            #validate_field_types(spec, known_msg_types)
+            subfolder = os.path.basename(os.path.dirname(idl_file))
+
+            data = {
+                'spec': spec,
+                'pkg': spec.base_type.pkg_name,
+                'msg': spec.msg_name,
+                'type': spec.base_type.type,
+                'subfolder': subfolder,
+            }
+            data.update(functions)
+
+
+            # Generate source file path
+            src_file = os.path.join(srcs_dir, "%s_%s_%s.xml" % (spec.base_type.pkg_name, subfolder, spec.msg_name))
+
+            # Data writer
+            file_content  = "   <dds>\n"
+            file_content += "       <data_writer profile_name=\"%s_%s_%s_p\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "               <kind>NO_KEY</kind>\n"
+            file_content += "               <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "               <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           </topic>\n"
+            file_content += "       </data_writer>\n"
+            file_content += "   </dds>\n"
+
+
+            # Data reader
+            file_content += "   <dds>\n"
+            file_content += "       <data_reader profile_name=\"%s_%s_%s_s\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "               <kind>NO_KEY</kind>\n"
+            file_content += "               <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "               <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           </topic>\n"
+            file_content += "       </data_reader>\n"
+            file_content += "   </dds>\n"
+
+
+            # Topic
+            file_content += "   <dds>\n"
+            file_content += "       <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "           <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
+            file_content += "       </topic>\n"
+            file_content += "   </dds>\n"
+
+
+            # Write file content
+            print ("%s" % file_content)
+
+
+
+        #elif extension == '.srv':
+
+            #data = {'spec': spec}
+            #data.update(functions)
+
+            #if not os.path.exists(args['output_dir']):
+            #    os.makedirs(args['output_dir'])
+
+            #f = open(os.path.join(args['output_dir'], 'demofile.txt'), 'w+')
+            #f.write("%s\n" % spec)
+            #f.close()
+    return 0

+ 104 - 0
offline_voice_module/src/micro-ROS-Agent/snap/hooks/configure

@@ -0,0 +1,104 @@
+#!/bin/sh -e
+
+# Confirm that the transport is valid
+transport="$(snapctl get transport)"
+case "$transport" in
+	udp4) ;;
+	udp6) ;;
+	tcp4) ;;
+	tcp6) ;;
+	serial) ;;
+	pseudoterminal) ;;
+	*)
+		echo "'$transport' is not a supported transport" >&2
+		return 1
+		;;
+esac
+
+# Confirm that the middleware is valid
+middleware="$(snapctl get middleware)"
+case "$middleware" in
+	dds) ;;
+	rtps) ;;
+	ced) ;;
+	*)
+		echo "'$middleware' is not a supported middleware" >&2
+		return 1
+		;;
+esac
+
+if [ "$transport" = "serial" ] || [ "$transport" = "pseudoterminal" ]; then
+	# A serial transport if being used, which requires a valid baud rate
+	# as well as a valid device
+	baudrate="$(snapctl get baudrate)"
+	if ! expr "$baudrate" : '^[0-9]\+$' > /dev/null; then
+		echo "'$baudrate' is not a valid baud rate" >&2
+		return 1
+	fi
+
+	device="$(snapctl get device)"
+	if [ -z "$device" ]; then
+		echo "Device must be specified" >&2
+		return 1
+	fi
+else
+	port="$(snapctl get port)"
+	if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
+		echo "'$port' is not a valid port" >&2
+		return 1
+	fi
+fi
+
+# Confirm that discovery is a boolean
+discovery="$(snapctl get discovery)"
+case "$discovery" in
+	true)
+		# Confirm that discovery port is valid
+		port="$(snapctl get discovery-port)"
+		if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
+			echo "'$port' is not a valid discovery port" >&2
+			return 1
+		fi
+		;;
+	false) ;;
+	*)
+		echo "'$discovery' is not a valid boolean for discovery" >&2
+		return 1
+		;;
+esac
+
+# Confirm that the verbosity is valid
+verbosity="$(snapctl get verbosity)"
+if ! expr "$verbosity" : '^[0-6]$' > /dev/null; then
+	echo "'$verbosity' is not a valid verbosity" >&2
+	return 1
+fi
+
+# Confirm that p2p port is valid (assuming it's set)
+p2p_port="$(snapctl get p2p-port)"
+if [ -n "$p2p_port" ]; then
+	port="$(snapctl get p2p-port)"
+	if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
+		echo "'$port' is not a valid p2p port" >&2
+		return 1
+	fi
+fi
+
+# Confirm that daemon is a boolean, and enable the service if true
+daemon="$(snapctl get daemon)"
+case "$daemon" in
+	true)
+		snapctl start --enable "$SNAP_INSTANCE_NAME.daemon"
+
+		# In case it was alraedy started and the configuration changed,
+		# restart the service
+		snapctl restart "$SNAP_INSTANCE_NAME.daemon"
+		;;
+	false)
+		snapctl stop --disable "$SNAP_INSTANCE_NAME.daemon"
+		;;
+	*)
+		echo "'$daemon' is not a valid boolean for daemon" >&2
+		return 1
+		;;
+esac

+ 19 - 0
offline_voice_module/src/micro-ROS-Agent/snap/hooks/install

@@ -0,0 +1,19 @@
+#!/bin/sh -e
+
+# Set default configuration values
+snapctl set transport=udp4
+snapctl set middleware=dds
+snapctl set verbosity=4
+snapctl set discovery=false
+snapctl set discovery-port=7400
+snapctl set p2p-port!  # unset
+
+# Network-specific things
+snapctl set port=8888
+
+# Serial-specific things
+snapctl set baudrate=115200
+snapctl set device!  # unset
+
+# By default the daemon is disabled
+snapctl set daemon=false

+ 19 - 0
offline_voice_module/src/micro-ROS-Agent/snap/local/fastdds_no_shared_memory.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+    <profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" >
+        <transport_descriptors>
+            <transport_descriptor>
+                <transport_id>CustomUdpTransport</transport_id>
+                <type>UDPv4</type>
+            </transport_descriptor>
+        </transport_descriptors>
+
+        <participant profile_name="participant_profile" is_default_profile="true">
+            <rtps>
+                <userTransports>
+                    <transport_id>CustomUdpTransport</transport_id>
+                </userTransports>
+
+                <useBuiltinTransports>false</useBuiltinTransports>
+            </rtps>
+        </participant>
+    </profiles>

+ 27 - 0
offline_voice_module/src/micro-ROS-Agent/snap/local/micro-ros-agent-daemon

@@ -0,0 +1,27 @@
+#!/bin/sh -e
+
+set -- --middleware "$(snapctl get middleware)" "$@"
+set -- --verbose "$(snapctl get verbosity)" "$@"
+
+transport="$(snapctl get transport)"
+if [ "$transport" = "serial" ] || [ "$transport" = "pseudoterminal" ]; then
+	set -- --dev "$(snapctl get device)" "$@"
+else
+	set -- --port "$(snapctl get port)" "$@"
+fi
+
+if [ "$(snapctl get discovery)" = "true" ]; then
+	set -- --discovery "$@"
+
+	discovery_port="$(snapctl get discovery-port)"
+	if [ -n "$discovery_port" ]; then
+		set -- --disport "$discovery_port" "$@"
+	fi
+fi
+
+p2p_port="$(snapctl get p2p-port)"
+if [ -n "$p2p_port" ]; then
+	set -- --p2p "$p2p_port" "$@"
+fi
+
+exec "$SNAP/opt/ros/snap/lib/micro_ros_agent/micro_ros_agent" "$transport" "$@"

+ 168 - 0
offline_voice_module/src/micro-ROS-Agent/snap/snapcraft.yaml

@@ -0,0 +1,168 @@
+name: micro-ros-agent
+base: core20
+version: git
+summary: Bridge between Micro ROS client applications and ROS 2
+description: |
+  Micro-ROS, whose default implementation is based on eProsima's
+  Micro XRCE-DDS middleware, is composed of client applications
+  which interact with the ROS 2 world by means of an Agent.
+  This agent keeps tracks of the entities created by means of
+  requests performed on the microcontroller side, and uses them
+  to communicate with the ROS 2 dataspace.
+
+  Being an extension of the Micro XRCE-DDS Agent, the micro-ROS
+  agent supports being run by the user like this:
+
+      $ micro-ros-agent --help
+
+  In addition, the Agent supports running as a service that can be
+  enabled with:
+
+      $ snap set micro-ros-agent daemon=true
+
+  If the service is enabled, by default it uses the `udp4` transport on
+  port 8888. The following parameters can be changed (these are
+  specific to the service, the `micro-ros-agent` command simply
+  takes command-line arguments, but the capabilities are the same):
+
+  * `transport`. Supported transports are `udp4`, `udp6`, `tcp4`,
+    `tcp6`, `serial`, and `pseudoterminal`. Default is `udp4`. Change
+    with:
+
+        $ snap set micro-ros-agent transport="new transport"
+
+  * `middleware`. Supported kinds of middleware are `ced`, `rtps`, and
+    `dds`. Default is `dds`. Change with:
+
+        $ snap set micro-ros-agent middleware="new middleware"
+
+  * `verbosity`. Supported verbosity levels are 0-6, defaulting to 4.
+    Change with:
+
+        $ snap set micro-ros-agent verbosity="selected verbosity"
+
+  * `discovery`. Enable or disable the discovery server. Defaults to
+    "false". Change with:
+
+        $ snap set micro-ros-agent discovery="true or false"
+
+  * `discovery-port`. Port on which the discovery server (see above)
+    listens. Defaults to 7400. Change with:
+
+        $ snap set micro-ros-agent discovery-port="selected port"
+
+  * `p2p-port`. Port to use for the P2P profile. Change with:
+
+        $ snap set micro-ros-agent p2p-port="selected port"
+
+  * `port`. Port on which the agent listens. Only applicable to one of
+    the UDP or TCP transports (see above). Defaults to 8888. Change with:
+
+        $ snap set micro-ros-agent port="selected port"
+
+  * `baudrate`. Baud rate to use when accessing serial ports. Only
+    applicable when using the `serial` or `pseudoterminal` transport.
+    Defaults to 115200. Change with:
+
+        $ snap set micro-ros-agent baudrate="baud rate"
+
+  * `device`. The serial device to use. Only applicable when using the
+    `serial` or `pseudoterminal` transport. Change with:
+
+        $ snap set micro-ros-agent device="device path"
+
+  When using the snap with a serial device, some steps need to be taken
+  in order to establish a successful connection:
+
+  * Refresh your local installation of the snap `core` package:
+
+        $ sudo snap refresh core --edge
+
+  * Enable the hotplug feature and restart the `snapd` daemon:
+
+        $ sudo snap set core experimental.hotplug=true
+        $ sudo systemctl restart snapd
+
+  * After plugging the microcontroller to the serial port, execute
+    the `snap interface serial-port` command. You should see something
+    like this:
+
+          name:    serial-port
+          summary: allows accessing a specific serial port
+          plugs:
+            - micro-ros-agent
+          slots:
+          - snapd:cp2102cp2109uartbrid (allows accessing a specific serial port)
+
+  * Connect your snap image to the desired serial port (replace accordingly):
+
+        $ snap connect micro-ros-agent:serial-port snapd:cp2102cp2109uartbrid
+
+  After this, you can execute your snap as usual,
+  using `sudo micro-ros-agent serial -d <serial-dev>`.
+
+grade: stable
+confinement: strict
+
+architectures:
+  - build-on: amd64
+  - build-on: arm64
+  - build-on: armhf
+  - build-on: ppc64el
+
+package-repositories:
+- components: [main]
+  formats: [deb]
+  key-id: C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
+  key-server: keyserver.ubuntu.com
+  suites: [focal]
+  type: apt
+  url: http://repo.ros2.org/ubuntu/main
+
+parts:
+  ros2-foxy-extension:
+    build-packages: [ros-foxy-ros-core]
+    override-build: install -D -m 0755 launch ${SNAPCRAFT_PART_INSTALL}/snap/command-chain/ros2-launch
+    plugin: nil
+    source: $SNAPCRAFT_EXTENSIONS_DIR/ros2
+
+  uros-agent:
+    plugin: colcon
+    source: .
+    colcon-cmake-args:
+      - -DMICROROSAGENT_SUPERBUILD=ON
+      - --cmake-force-configure
+    override-pull: |
+        snapcraftctl pull
+
+        version="$(git describe --always --tags| sed -e 's/^v//;s/-/+git/;y/-/./')"
+        [ -n "$(echo $version | grep "+git")" ] && grade=devel || grade=stable
+        snapcraftctl set-version "$version"
+        snapcraftctl set-grade "$grade"
+
+    build-packages: [make, gcc, g++]
+    stage-packages: [ros-foxy-ros2launch]
+    build-environment:
+    - ROS_VERSION: '2'
+    - ROS_DISTRO: foxy
+
+  runner:
+    plugin: dump
+    source: snap/local/
+    organize:
+      'micro-ros-agent-daemon': usr/bin/
+      'fastdds_no_shared_memory.xml': usr/share/
+
+apps:
+  micro-ros-agent:
+    command: opt/ros/snap/lib/micro_ros_agent/micro_ros_agent
+    environment:
+        FASTRTPS_DEFAULT_PROFILES_FILE: ${SNAP}/usr/share/fastdds_no_shared_memory.xml
+    plugs: [network, network-bind, serial-port]
+
+  daemon:
+    command: usr/bin/micro-ros-agent-daemon
+    environment:
+        FASTRTPS_DEFAULT_PROFILES_FILE: ${SNAP}/usr/share/fastdds_no_shared_memory.xml
+    daemon: simple
+    plugs: [network, network-bind, serial-port]