├── .clang-format ├── .cmake-format ├── .github └── workflows │ └── makefile.yml ├── .gitignore ├── .gitpod.yml ├── Dockerfile ├── Dockerfile.client ├── Dockerfile.server ├── LICENSE ├── Makefile ├── README.md ├── config ├── init-client.sh ├── init-server.sh ├── vsomeip-client.json └── vsomeip-server.json ├── docker-compose.yml ├── docs └── bridge.png ├── simulation ├── README.md └── gnss-sentences.nmea └── src ├── franca2ros ├── franca2ros │ ├── __init__.py │ ├── scripts │ │ ├── __init__.py │ │ └── fidl2ros.py │ └── translator │ │ ├── __init__.py │ │ ├── templates │ │ ├── message.msg.j2 │ │ └── service.srv.j2 │ │ └── translator.py ├── readme.md ├── setup.py └── tests │ ├── __init__.py │ └── test.py ├── gnss-bridge ├── CMakeLists.txt ├── package.xml └── src │ ├── abstract_someip_client.h │ ├── main.cpp │ └── someip_publisher.h ├── gnss-listener ├── CMakeLists.txt ├── package.xml └── src │ └── main.cpp ├── gnss-provider ├── CMakeLists.txt ├── package.xml └── src │ ├── gnss_someip.h │ ├── gpsd_client.h │ └── main.cpp └── gnss-someip-lib ├── CMakeLists.txt ├── cmake ├── FindCommonAPITools.cmake └── FindFrancaRosTools.cmake ├── config └── commonapi.ini.in ├── package.xml └── src ├── fidl ├── gnss.fdepl ├── gnss.fidl └── types.fidl └── types └── conversion.h /.clang-format: -------------------------------------------------------------------------------- 1 | # Note: let's keep the options sorted in alphabetical order. 2 | 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: true 5 | AlignConsecutiveAssignments: false 6 | AlignEscapedNewlinesLeft: true 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: None 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakAfterDefinitionReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: false 17 | AlwaysBreakTemplateDeclarations: true 18 | 19 | # Note: if BinPackArguments is "true", lambdas may be formatted in a bit ugly way, e.g. 20 | # foo(bla, [](OOO) 21 | # { 22 | # }, 23 | # [](AAA) 24 | # { 25 | # }); 26 | # With "false" the "[](OOO)" part occupies a separate line. 27 | # 28 | # There is a bug report about incorrect formatting of lambdas similar to 29 | # the example above: http://llvm.org/bugs/show_bug.cgi?id=20450 30 | BinPackArguments: false 31 | 32 | BinPackParameters: false 33 | 34 | BreakBeforeBinaryOperators: None 35 | BreakBeforeBraces: Allman 36 | BreakBeforeTernaryOperators: true 37 | BreakConstructorInitializersBeforeComma: true 38 | ColumnLimit: 120 39 | 40 | # A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed. 41 | #CommentPragmas: 42 | 43 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 44 | ConstructorInitializerIndentWidth: 4 45 | ContinuationIndentWidth: 4 46 | Cpp11BracedListStyle: true 47 | DerivePointerAlignment: false 48 | ExperimentalAutoDetectBinPacking: false 49 | ForEachMacros: [BOOST_FOREACH] 50 | IndentCaseLabels: true 51 | IndentWidth: 4 52 | IndentWrappedFunctionNames: false 53 | # There is a bug report about empty lines at the beginning of 54 | # namespaces: http://llvm.org/bugs/show_bug.cgi?id=20449 55 | KeepEmptyLinesAtTheStartOfBlocks: true 56 | Language: Cpp 57 | # A regular expression matching macros that start/stop a block. 58 | #MacroBlockBegin 59 | #MacroBlockEnd 60 | MaxEmptyLinesToKeep: 1 61 | NamespaceIndentation: None 62 | ObjCBlockIndentWidth: 4 63 | ObjCSpaceAfterProperty: true 64 | ObjCSpaceBeforeProtocolList: true 65 | 66 | # Note: these options specify the penalties for certain formatting decisions; for each chunk of code clang-format is 67 | # supposed to try all available combinations and select the one with minimum total penalty. 68 | # Note: it's rather hard to predict the effects that each individual option will have on the code readability in general, 69 | # hence we only use some of the options with big values to effectively disable the corresponding behaviour. 70 | #PenaltyBreakBeforeFirstCallParameter: 71 | #PenaltyBreakComment: 72 | #PenaltyBreakFirstLessLess: 73 | #PenaltyBreakString: 74 | #PenaltyExcessCharacter: 75 | PenaltyReturnTypeOnItsOwnLine: 10000 76 | 77 | PointerAlignment: Left 78 | SpaceAfterCStyleCast: false 79 | SpaceBeforeAssignmentOperators: true 80 | SpaceBeforeParens: ControlStatements 81 | SpaceInEmptyParentheses: false 82 | SpacesBeforeTrailingComments: 1 83 | SpacesInAngles: false 84 | SpacesInCStyleCastParentheses: false 85 | SpacesInContainerLiterals: false 86 | SpacesInParentheses: false 87 | SpacesInSquareBrackets: false 88 | Standard: Cpp11 89 | TabWidth: 4 90 | UseTab: Never -------------------------------------------------------------------------------- /.cmake-format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/.cmake-format -------------------------------------------------------------------------------- /.github/workflows/makefile.yml: -------------------------------------------------------------------------------- 1 | name: ROS to SOME/IP bridge build 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Check out repository 16 | uses: actions/checkout@v3 17 | 18 | - name: Run colcone build 19 | run: make compose 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | install* 3 | log 4 | .vscode 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | cover/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | .pybuilder/ 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # pyenv 91 | # For a library or package, you might want to ignore these files since the code is 92 | # intended to run in multiple environments; otherwise, check them in: 93 | # .python-version 94 | 95 | # pipenv 96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 99 | # install all needed dependencies. 100 | #Pipfile.lock 101 | 102 | # poetry 103 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 104 | # This is especially recommended for binary packages to ensure reproducibility, and is more 105 | # commonly ignored for libraries. 106 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 107 | #poetry.lock 108 | 109 | # pdm 110 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 111 | #pdm.lock 112 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 113 | # in version control. 114 | # https://pdm.fming.dev/#use-with-ide 115 | .pdm.toml 116 | 117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 118 | __pypackages__/ 119 | 120 | # Celery stuff 121 | celerybeat-schedule 122 | celerybeat.pid 123 | 124 | # SageMath parsed files 125 | *.sage.py 126 | 127 | # Environments 128 | .env 129 | .venv 130 | env/ 131 | venv/ 132 | ENV/ 133 | env.bak/ 134 | venv.bak/ 135 | 136 | # Spyder project settings 137 | .spyderproject 138 | .spyproject 139 | 140 | # Rope project settings 141 | .ropeproject 142 | 143 | # mkdocs documentation 144 | /site 145 | 146 | # mypy 147 | .mypy_cache/ 148 | .dmypy.json 149 | dmypy.json 150 | 151 | # Pyre type checker 152 | .pyre/ 153 | 154 | # pytype static type analyzer 155 | .pytype/ 156 | 157 | # Cython debug symbols 158 | cython_debug/ 159 | 160 | # PyCharm 161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 163 | # and can be added to the global gitignore or merged into this file. For a more nuclear 164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 165 | #.idea/ -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | tasks: 6 | - init: make compose 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ros:galactic 2 | 3 | ENV COMMONAPI_CONFIG=/src/install/gnss_someip_lib/etc/commonapi.ini 4 | ENV COMMONAPI_DEFAULT_FOLDER=/src/install/gnss_someip_lib/lib/ 5 | 6 | RUN apt-get update && apt install -y wget unzip git 7 | 8 | # Installation of required tools 9 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata 10 | RUN apt-get install -y openjdk-13-jdk openjdk-13-jre 11 | RUN apt-get install -y g++ gcc cmake libboost-all-dev make doxygen asciidoc 12 | RUN apt-get install -y net-tools iproute2 13 | RUN apt-get install -y python3-pip 14 | 15 | # Installation of required libraries 16 | RUN apt-get install -y libboost-all-dev nlohmann-json3-dev graphviz source-highlight 17 | 18 | RUN wget https://github.com/COVESA/capicxx-core-tools/releases/download/3.2.0.1/commonapi_core_generator.zip -P /opt && \ 19 | cd /opt && unzip commonapi_core_generator.zip -d commonapi_core_generator && \ 20 | ln -s /opt/commonapi_core_generator/commonapi-core-generator-linux-x86_64 /usr/bin/commonapi-core-generator 21 | 22 | RUN wget https://github.com/COVESA/capicxx-someip-tools/releases/download/3.2.0.1/commonapi_someip_generator.zip -P /opt/ && \ 23 | cd /opt/ && unzip commonapi_someip_generator.zip -d commonapi_someip_generator && \ 24 | ln -s /opt/commonapi_someip_generator/commonapi-someip-generator-linux-x86_64 /usr/bin/commonapi-someip-generator 25 | 26 | RUN cd /opt && git clone https://github.com/COVESA/dlt-daemon.git -b v2.18.8 && cd dlt-daemon && \ 27 | mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j$(nproc) && make install 28 | 29 | RUN cd /opt && git clone https://github.com/COVESA/vsomeip.git && cd vsomeip && \ 30 | mkdir build && cd build && cmake -DENABLE_MULTIPLE_ROUTING_MANAGERS=1 -DVSOMEIP_INSTALL_ROUTINGMANAGERD=1 -DCMAKE_INSTALL_PREFIX=/usr .. && \ 31 | make -j$(nproc) && make install 32 | 33 | RUN cd /opt && git clone https://github.com/COVESA/capicxx-core-runtime.git && cd capicxx-core-runtime && \ 34 | mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j$(nproc) && make install 35 | 36 | RUN cd /opt && git clone https://github.com/COVESA/capicxx-someip-runtime.git && cd capicxx-someip-runtime && \ 37 | mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j$(nproc) && make install 38 | 39 | RUN cd /opt && git clone https://github.com/cameron314/concurrentqueue.git && cd concurrentqueue && \ 40 | mkdir build-cmake && cd build-cmake && cmake -DCMAKE_INSTALL_PREFIX=/usr .. && make -j$(nproc) && make install 41 | 42 | RUN pip3 install git+https://github.com/miketsukerman/pyfranca.git 43 | 44 | # install gpsd and gpsfake to simulate real gnss device data 45 | RUN apt-get install -y gpsd gpsd-clients libgps-dev 46 | 47 | RUN rm -rf /src 48 | COPY . /src 49 | RUN rm -rf /src/build /src/install /src/log 50 | 51 | RUN pip3 install -e /src/src/franca2ros 52 | 53 | RUN cd /src && rm -rf build install log && \ 54 | . /opt/ros/galactic/setup.sh && \ 55 | colcon build 56 | 57 | 58 | -------------------------------------------------------------------------------- /Dockerfile.client: -------------------------------------------------------------------------------- 1 | FROM vsomeip-ros-bridge:base 2 | 3 | COPY config/vsomeip-client.json /etc/vsomeip.json 4 | COPY config/init-client.sh /usr/bin/init.sh 5 | 6 | RUN chmod +x /usr/bin/init.sh 7 | -------------------------------------------------------------------------------- /Dockerfile.server: -------------------------------------------------------------------------------- 1 | FROM vsomeip-ros-bridge:base 2 | 3 | # copy gnss sample information which would be used by gpsfake 4 | RUN mkdir /usr/share/nmea 5 | COPY simulation/gnss-sentences.nmea /usr/share/nmea/simulation.nmea 6 | 7 | COPY config/vsomeip-server.json /etc/vsomeip.json 8 | COPY config/init-server.sh /usr/bin/init.sh 9 | 10 | RUN chmod +x /usr/bin/init.sh 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | https://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright 2013-2018 Docker, Inc. 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | https://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | enter-build-env: 4 | docker run -it -v $(shell pwd):/src -w /src vsomeip-ros-bridge:base /bin/bash 5 | 6 | enter-client-env: 7 | docker run -it -v $(shell pwd):/src -w /src vsomeip-ros-bridge_gnss-client:latest /bin/bash 8 | 9 | enter-server-env: 10 | docker run -it -v $(shell pwd):/src -w /src vsomeip-ros-bridge_gnss-server:latest /bin/bash 11 | 12 | compose: 13 | docker build . -t vsomeip-ros-bridge:base 14 | docker-compose build 15 | 16 | run: compose 17 | docker-compose up 18 | 19 | run-force: compose 20 | docker-compose up --force-recreate 21 | 22 | clean: 23 | rm -rf build install log 24 | 25 | colcon-build: 26 | colcon build 27 | 28 | gnss-provider: 29 | colcon build --packages-select gnss_provider 30 | 31 | gnss-bridge: 32 | colcon build --packages-select gnss_bridge 33 | 34 | gnss-someip-lib: 35 | colcon build --packages-select gnss_someip_lib 36 | 37 | gnss-listener: 38 | colcon build --packages-select gnss_listener 39 | 40 | format-code: 41 | find ./src -name "*.cpp" -exec clang-format -f {} \; 42 | find ./src -name "*.h" -exec clang-format -f {} \; 43 | 44 | .PHONY: compose run enter-build-env build-gnss-provider 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ROS SOME/IP bridge 2 | 3 | [![ROS to SOME/IP bridge build](https://github.com/miketsukerman/vsomeip-ros-bridge/actions/workflows/makefile.yml/badge.svg)](https://github.com/miketsukerman/vsomeip-ros-bridge/actions/workflows/makefile.yml) 4 | 5 | Proof of concept project which tries to create a bridge between vsomeip / common-api 6 | and ROS linux environment. 7 | 8 | [![asciicast](https://asciinema.org/a/gVNR0u38fNyX9Xw1i56WNlV4T.svg)](https://asciinema.org/a/gVNR0u38fNyX9Xw1i56WNlV4T) 9 | 10 | # Problem definition 11 | 12 | Make SOME/IP data available in ROS2 natively. 13 | 14 | # Simulation 15 | 16 | To simulate real GPS/GNSS data coming from the receiver we would use `gpsfake` tool together with a text file 17 | containing small set of real NMEA messages. Can be obtained from https://www.nmeagen.org/. 18 | 19 | ## Architecture 20 | 21 | * We would use open source SOME/IP stack implementation (COVESA/GENIVI) 22 | * `gpsd` daemon + `gpsfake` utility 23 | * SOME/IP broadcast's published as ROS2 topics. 24 | 25 | ![bridge](docs/bridge.png) 26 | 27 | UDS = Unix Domain Socket (used by GENIVI stack for communication between router and clients on localhost) 28 | 29 | ### Limitations 30 | 31 | We will limit our scope by making available only SOME/IP broadcast messages as topics, with 32 | string messages which contain data in json format. 33 | 34 | ### Open points 35 | 36 | * Parse FIDL/FDEPL files to generate bridge glue code automatically 37 | * Add support for different data types (i.e. ROS topic datatypes) 38 | * Think of potential configuration (mapping between topics and SOME/IP events) 39 | * Think how to handle outgoing data (requests) 40 | * Think how to handle attributes 41 | # How it works 42 | 43 | To simulate remote ECU which broadcasts GNSS data over the network using 44 | UDP packets with SOME/IP serialised payload we would use dedicated docker container `Docker.server`. 45 | 46 | At the same time to receive those PDUs we would run another dedicated docker container `Docker.client`. 47 | 48 | to run the setup simply execute (tested in ubuntu 20.04): 49 | 50 | ```bash 51 | make run 52 | ``` 53 | 54 | to rebuild the contains without running execute: 55 | 56 | ```bash 57 | make compose 58 | ``` 59 | 60 | # Development 61 | 62 | To simplify compilation and testing of the changes there is possibility 63 | to enter docker container, using: 64 | 65 | ```bash 66 | make enter-build-env 67 | ``` 68 | 69 | then you can use shortcuts like 70 | 71 | ``` 72 | make colcon-build 73 | ``` 74 | 75 | to build all packages in the repository. Or, if you like to build them 76 | separately use 77 | 78 | ```bash 79 | make gnss-provider 80 | make gnss-bridge 81 | make gnss-someip-lib 82 | make gnss-listener 83 | ``` 84 | 85 | # Tips 86 | 87 | I will put here some tips / tricks to not to forget. 88 | ### Cleanup docker networks 89 | 90 | ```bash 91 | docker network prune 92 | ``` 93 | 94 | # Links 95 | 96 | * https://colcon.readthedocs.io/en/released/user/how-to.html 97 | * https://hub.docker.com/_/ros 98 | * https://docs.ros.org/en/foxy/Tutorials/Composition.html 99 | * https://docs.ros.org/en/foxy/Tutorials/Topics/Understanding-ROS2-Topics.html 100 | * https://docs.ros.org/en/foxy/Tutorials/Understanding-ROS2-Nodes.html 101 | -------------------------------------------------------------------------------- /config/init-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dlt-daemon & 4 | routingmanagerd & 5 | 6 | source /src/install/setup.sh 7 | 8 | ros2 daemon start 9 | 10 | VSOMEIP_APPLICATION_NAME=gnss-client ros2 run gnss_bridge gnss-bridge & 11 | 12 | ros2 run gnss_listener gnss-listener 13 | -------------------------------------------------------------------------------- /config/init-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dlt-daemon & 4 | routingmanagerd & 5 | 6 | gpsfake -c 1 -v /usr/share/nmea/simulation.nmea & 7 | 8 | source /src/install/setup.sh 9 | 10 | VSOMEIP_APPLICATION_NAME=gnss-server ros2 run gnss_provider gnss-server 11 | -------------------------------------------------------------------------------- /config/vsomeip-client.json: -------------------------------------------------------------------------------- 1 | { 2 | "unicast" : "192.168.1.3", 3 | "netmask" : "255.255.255.0", 4 | "logging" : 5 | { 6 | "level" : "debug", 7 | "console" : "true", 8 | "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" }, 9 | "dlt" : "true" 10 | }, 11 | "applications" : 12 | [ 13 | { 14 | "name" : "gnss-client", 15 | "id" : "0x1343" 16 | } 17 | ], 18 | "routing" : "routingmanagerd", 19 | "service-discovery" : 20 | { 21 | "enable" : "true", 22 | "multicast" : "224.244.224.245", 23 | "port" : "30490", 24 | "protocol" : "udp", 25 | "initial_delay_min" : "10", 26 | "initial_delay_max" : "100", 27 | "repetitions_base_delay" : "200", 28 | "repetitions_max" : "3", 29 | "ttl" : "3", 30 | "cyclic_offer_delay" : "2000", 31 | "request_response_delay" : "1500" 32 | } 33 | } -------------------------------------------------------------------------------- /config/vsomeip-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "unicast" : "192.168.1.2", 3 | "netmask" : "255.255.255.0", 4 | "logging" : 5 | { 6 | "level" : "debug", 7 | "console" : "true", 8 | "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" }, 9 | "dlt" : "true" 10 | }, 11 | "servicegroups": [ 12 | { 13 | "name" : "gnss", 14 | "services" : 15 | [ 16 | { 17 | "service" : "1234", 18 | "instance" : "1", 19 | "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" }, 20 | "unreliable" : "31000" 21 | } 22 | ] 23 | } 24 | ], 25 | "routing" : "routingmanagerd", 26 | "service-discovery" : 27 | { 28 | "enable" : "true", 29 | "multicast" : "224.244.224.245", 30 | "port" : "30490", 31 | "protocol" : "udp", 32 | "initial_delay_min" : "10", 33 | "initial_delay_max" : "100", 34 | "repetitions_base_delay" : "200", 35 | "repetitions_max" : "3", 36 | "ttl" : "3", 37 | "cyclic_offer_delay" : "2000", 38 | "request_response_delay" : "1500" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | gnss-server: 5 | tty: true 6 | build: 7 | context: ./ 8 | dockerfile: Dockerfile.server 9 | command: init.sh 10 | networks: 11 | mynet: 12 | ipv4_address: 192.168.1.2 13 | 14 | gnss-client: 15 | tty: true 16 | build: 17 | context: ./ 18 | dockerfile: Dockerfile.client 19 | command: init.sh 20 | networks: 21 | mynet: 22 | ipv4_address: 192.168.1.3 23 | networks: 24 | mynet: 25 | driver: bridge 26 | ipam: 27 | config: 28 | - subnet: 192.168.1.0/24 29 | -------------------------------------------------------------------------------- /docs/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/docs/bridge.png -------------------------------------------------------------------------------- /simulation/README.md: -------------------------------------------------------------------------------- 1 | # GNSS NMEA data 2 | 3 | Folder stores `*.nmea` files used to simulate output of the real GNSS device. 4 | 5 | ## Links 6 | 7 | * https://campar.in.tum.de/twiki/pub/Chair/NaviGpsDemon/nmea.html 8 | * https://github.com/esutton/gps-nmea-log-files 9 | * https://gpsd.gitlab.io/gpsd/NMEA.html -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/franca2ros/__init__.py -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/franca2ros/scripts/__init__.py -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/scripts/fidl2ros.py: -------------------------------------------------------------------------------- 1 | from optparse import check_builtin 2 | from franca2ros.translator.translator import FIDLTraslator 3 | import argparse 4 | 5 | from pathlib import Path 6 | 7 | def check_output_dir(output): 8 | path = Path(output) 9 | path.mkdir(parents=True, exist_ok=True) 10 | 11 | def main(): 12 | parser = argparse.ArgumentParser(description="FIDL to ROS IDL translator") 13 | parser.add_argument('-f','--fidl', type=str, nargs="+", required=True) 14 | parser.add_argument('-i','--import', type=str, action="append", dest="import_dirs", metavar="import_dir", required=False) 15 | parser.add_argument('-o','--output', type=str, required=True) 16 | 17 | args = parser.parse_args() 18 | 19 | check_output_dir(args.output) 20 | 21 | for fidl in args.fidl: 22 | f2r = FIDLTraslator(fidl, args.import_dirs) 23 | 24 | f2r.save(args.output) 25 | 26 | if __name__ == "__main__": 27 | main() -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/translator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/franca2ros/translator/__init__.py -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/translator/templates/message.msg.j2: -------------------------------------------------------------------------------- 1 | {% for field in fields %} 2 | {{ rostype(fields[field].type.name) }} {{ field }} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/translator/templates/service.srv.j2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/franca2ros/translator/templates/service.srv.j2 -------------------------------------------------------------------------------- /src/franca2ros/franca2ros/translator/translator.py: -------------------------------------------------------------------------------- 1 | from email import message 2 | from pyfranca import Processor, LexerException, ParserException, ProcessorException 3 | from jinja2 import Template, FileSystemLoader, Environment 4 | 5 | import os 6 | dir_path = os.path.dirname(os.path.realpath(__file__)) 7 | 8 | class FIDLTraslator: 9 | 10 | def __init__(self, fidl, include): 11 | self.fidl = fidl 12 | self.include = include 13 | 14 | templateLoader = FileSystemLoader(searchpath=f"{dir_path}/templates/") 15 | templateEnv = Environment(loader=templateLoader) 16 | 17 | self.message_t = templateEnv.get_template("message.msg.j2") 18 | self.service_t = templateEnv.get_template("service.srv.j2") 19 | 20 | def parse(self): 21 | 22 | processor = Processor() 23 | types = [] 24 | 25 | try: 26 | print(f"importing file {self.fidl}") 27 | processor.import_file(self.fidl) 28 | 29 | for package in processor.packages.values(): 30 | if package.typecollections: 31 | print("\tType collections:") 32 | for typecollection in package.typecollections.values(): 33 | if typecollection.structs: 34 | print("\t\tStructs:") 35 | for item in typecollection.structs.values(): 36 | print("\t\t- {}".format(item.name)) 37 | types.append(item) 38 | 39 | except (LexerException, ParserException, ProcessorException) as e: 40 | print(f"ERROR: {e}") 41 | 42 | return types 43 | 44 | def fildTypes2RosTypes(self,name): 45 | types_map = { 46 | "Float" : "float32", 47 | "Double" : "float32", 48 | "UInt32" : "int32" 49 | } 50 | return types_map[name] if name in types_map else name 51 | 52 | def save(self, output): 53 | 54 | types = self.parse() 55 | 56 | for type in types: 57 | output_file = os.path.join(output,f"{type.name}.msg") 58 | with open(output_file,"w+") as f: 59 | print(f"saving to {output_file}") 60 | print(type.fields) 61 | out = self.message_t.render(fields=type.fields, rostype=self.fildTypes2RosTypes) 62 | f.write(out) 63 | -------------------------------------------------------------------------------- /src/franca2ros/readme.md: -------------------------------------------------------------------------------- 1 | # Franca IDL to ROS2 IDL translator 2 | 3 | Helper tools used to convert FIDL files to ROS2 IDLs. 4 | 5 | # Dependencies 6 | 7 | * argparse 8 | * jinja2 9 | * pyfranca 10 | 11 | # Installation 12 | 13 | To install call 14 | 15 | python3 setup.py install 16 | 17 | or 18 | 19 | pip3 install -e 20 | 21 | # Usage 22 | 23 | fidl2ros -f -o 24 | 25 | with include path 26 | 27 | fidl2ros -i -f -o 28 | -------------------------------------------------------------------------------- /src/franca2ros/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup, find_packages 4 | import os 5 | 6 | def read(fname): 7 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 8 | 9 | setup(name='franca2ros', 10 | version='0.0.1', 11 | description='Franca IDL to ROS2 translator', 12 | author='Mikhail Tsukerman', 13 | packages=find_packages(include=['franca2ros.*','franca2ros.translator.*']), 14 | author_email='miketsukerman@gmail.com', 15 | license="Apache2", 16 | keywords="fidl someip ros2", 17 | long_description=read('readme.md'), 18 | install_requires=[ 19 | 'jinja2', 20 | 'pyfranca', 21 | 'argparse' 22 | ], 23 | entry_points={ 24 | 'console_scripts': ['fidl2ros=franca2ros.scripts.fidl2ros:main'] 25 | } 26 | ) 27 | -------------------------------------------------------------------------------- /src/franca2ros/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/tests/__init__.py -------------------------------------------------------------------------------- /src/franca2ros/tests/test.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miketsukerman/vsomeip-ros-bridge/d11d4dfd6b9cdafc5c6f4090e0293998df97e51d/src/franca2ros/tests/test.py -------------------------------------------------------------------------------- /src/gnss-bridge/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(gnss_bridge VERSION 0.0.1) 4 | 5 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 6 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 8 | 9 | include(GNUInstallDirs) 10 | 11 | find_package(CommonAPI REQUIRED) 12 | find_package(CommonAPI-SomeIP REQUIRED) 13 | find_package(gnss REQUIRED) 14 | find_package(gnss_someip_lib REQUIRED) 15 | 16 | find_package(ament_cmake REQUIRED) 17 | find_package(rclcpp REQUIRED) 18 | 19 | add_library(gnss_someip_lib INTERFACE IMPORTED) 20 | target_link_libraries(gnss_someip_lib 21 | INTERFACE 22 | CommonAPI 23 | CommonAPI-SomeIP 24 | gnss_someip_lib::gnss-msg__rosidl_generator_cpp # TODO: figure out how to define exported targets 25 | gnss_someip_lib::gnss-msg__rosidl_typesupport_cpp # TODO: figure out how to define exported targets 26 | ) 27 | 28 | set(CLIENT_TARGET_NAME gnss-bridge) 29 | add_executable(${CLIENT_TARGET_NAME} 30 | src/main.cpp 31 | ) 32 | target_compile_features(${CLIENT_TARGET_NAME} PRIVATE cxx_std_17) 33 | target_compile_definitions(${CLIENT_TARGET_NAME} PRIVATE -DGNSS_CLIENT_VERSION="${PROJECT_VERSION}") 34 | 35 | target_include_directories(${CLIENT_TARGET_NAME} PRIVATE 36 | ${COMMONAPI_INCLUDE_DIRS} 37 | ) 38 | 39 | target_link_libraries(${CLIENT_TARGET_NAME} PRIVATE 40 | gnss::gnss 41 | rclcpp::rclcpp 42 | gnss_someip_lib 43 | ) 44 | 45 | install(TARGETS ${CLIENT_TARGET_NAME} DESTINATION lib/${PROJECT_NAME}) 46 | 47 | ament_package() 48 | -------------------------------------------------------------------------------- /src/gnss-bridge/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnss_bridge 5 | 0.0.1 6 | Bridge between SOME/IP and ROS 7 | Mikhail Tsukerman 8 | MIT 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | gnss_someip_lib 14 | 15 | rclcpp 16 | 17 | ament_lint_auto 18 | ament_lint_common 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/gnss-bridge/src/abstract_someip_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using GpsDataMsg = gnss_someip_lib::msg::GnssData; 9 | using GnssData = v0::gnss::common::GnssData; 10 | 11 | template class P> 12 | class AbstractSomeIpClient 13 | { 14 | using ProxyClass = P<>; 15 | using ProxyClassPtr = std::shared_ptr; 16 | 17 | public: 18 | AbstractSomeIpClient(std::string domain, std::string instance) 19 | : proxy_(CommonAPI::Runtime::get()->buildProxy

(domain,instance)) 20 | { 21 | init(); 22 | } 23 | 24 | virtual std::optional available() { 25 | return (initialised()) ? std::make_optional(proxy_->isAvailable()) : std::nullopt; 26 | } 27 | 28 | virtual void onAvailable() = 0; 29 | 30 | protected: 31 | ProxyClassPtr proxy() { 32 | return proxy_; 33 | } 34 | 35 | virtual bool initialised() { 36 | return proxy_ != nullptr; 37 | } 38 | 39 | void init() { 40 | if(!proxy_) 41 | { 42 | // RCLCPP_ERROR(this->get_logger(), "Not able to initialize SOME/IP proxy for GNSS"); 43 | //TODO: handle error case correctly 44 | return; 45 | } 46 | 47 | proxy_->getProxyStatusEvent().subscribe(std::bind(&AbstractSomeIpClient

::onAvailablilityStatusChange, this, std::placeholders::_1)); 48 | } 49 | 50 | virtual void onAvailablilityStatusChange(CommonAPI::AvailabilityStatus status) { 51 | // first event is always CommonAPI::AvailabilityStatus::NOT_AVAILABLE 52 | 53 | if (status == CommonAPI::AvailabilityStatus::AVAILABLE) 54 | { 55 | onAvailable(); 56 | } 57 | } 58 | 59 | private: 60 | ProxyClassPtr proxy_; 61 | }; 62 | 63 | using GnssSomeIpProxyWrapper = AbstractSomeIpClient; 64 | 65 | class GnssSomeIpClient : public GnssSomeIpProxyWrapper 66 | { 67 | static constexpr auto domain = "local"; 68 | static constexpr auto instance = "GnssServer"; 69 | 70 | using MessageCallback = std::function; 71 | 72 | public: 73 | GnssSomeIpClient() : GnssSomeIpProxyWrapper(domain, instance) {} 74 | 75 | void setMessageCallback(MessageCallback callback) { 76 | message_callback = std::move(callback); 77 | } 78 | 79 | void onAvailable() override { 80 | proxy()->getDataEvent().subscribe([this](const GnssData & data) { 81 | 82 | auto message = Types::Conversion::from_capi_type(data); 83 | 84 | message_callback(message); 85 | }); 86 | } 87 | 88 | private: 89 | MessageCallback message_callback; 90 | }; 91 | -------------------------------------------------------------------------------- /src/gnss-bridge/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "abstract_someip_client.h" 2 | #include "someip_publisher.h" 3 | 4 | constexpr auto node_name = "GNSS_SOMEIP_Bridge"; 5 | 6 | auto main(int argc, char **argv) -> int 7 | { 8 | rclcpp::init(argc, argv); 9 | rclcpp::spin(std::make_shared>(node_name)); 10 | rclcpp::shutdown(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/gnss-bridge/src/someip_publisher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rclcpp/rclcpp.hpp" 4 | #include "std_msgs/msg/string.hpp" 5 | 6 | #include 7 | 8 | using GpsDataMsg = gnss_someip_lib::msg::GnssData; 9 | using GnssData = v0::gnss::common::GnssData; 10 | template 11 | class SomeIpPublisher : public rclcpp::Node 12 | { 13 | static constexpr auto Topic = "GNSS"; 14 | static constexpr auto QoS = 10; 15 | 16 | public: 17 | SomeIpPublisher(std::string node_name) 18 | : Node(node_name) 19 | { 20 | publisher = this->create_publisher(Topic, QoS); 21 | 22 | someip_client.setMessageCallback(std::bind(&SomeIpPublisher::publish, this, std::placeholders::_1)); 23 | } 24 | 25 | private: 26 | 27 | void publish(const GpsDataMsg & message) { 28 | 29 | RCLCPP_INFO(this->get_logger(), "Publishing SOME/IP message on topic %s", Topic); 30 | 31 | publisher->publish(message); 32 | } 33 | 34 | private: 35 | SomeIpClient someip_client; 36 | 37 | rclcpp::Publisher::SharedPtr publisher; 38 | }; 39 | -------------------------------------------------------------------------------- /src/gnss-listener/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | 3 | project(gnss_listener VERSION 0.0.1) 4 | 5 | find_package(ament_cmake REQUIRED) 6 | find_package(rclcpp REQUIRED) 7 | find_package(gnss_someip_lib REQUIRED) 8 | 9 | set(GNSS_LISTENER_TARGET gnss-listener) 10 | 11 | add_executable(${GNSS_LISTENER_TARGET} src/main.cpp) 12 | 13 | ament_target_dependencies(${GNSS_LISTENER_TARGET} rclcpp gnss_someip_lib) 14 | 15 | target_compile_features(${GNSS_LISTENER_TARGET} PRIVATE cxx_std_17) 16 | 17 | install(TARGETS ${GNSS_LISTENER_TARGET} DESTINATION lib/${PROJECT_NAME}) 18 | 19 | ament_package() 20 | -------------------------------------------------------------------------------- /src/gnss-listener/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnss_listener 5 | 0.0.1 6 | TODO 7 | Mikhail Tsukerman 8 | MIT 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | gnss_someip_lib 14 | 15 | rclcpp 16 | 17 | ament_lint_auto 18 | ament_lint_common 19 | 20 | 21 | ament_cmake 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/gnss-listener/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "rclcpp/rclcpp.hpp" 2 | 3 | #include 4 | 5 | using GpsDataMsg = gnss_someip_lib::msg::GnssData; 6 | 7 | class GnssTopicSubsriber : public rclcpp::Node 8 | { 9 | static constexpr auto node_name = "GNSS_Topic_Subscriber"; 10 | 11 | static constexpr auto topic = "GNSS"; 12 | static constexpr auto qos = 10; 13 | 14 | public: 15 | GnssTopicSubsriber() : Node(node_name) 16 | { 17 | subscription = this->create_subscription(topic, qos, std::bind(&GnssTopicSubsriber::gnss_topic_callback, this, std::placeholders::_1)); 18 | } 19 | 20 | private: 21 | void gnss_topic_callback(const GpsDataMsg & msg) const 22 | { 23 | RCLCPP_INFO(this->get_logger(), "GNSS position latitude %f, longitude %f", 24 | msg.position.fix.latitude, 25 | msg.position.fix.longitude 26 | ); 27 | } 28 | 29 | rclcpp::Subscription::SharedPtr subscription; 30 | }; 31 | 32 | auto main(int argc, char * argv[]) -> int 33 | { 34 | rclcpp::init(argc, argv); 35 | rclcpp::spin(std::make_shared()); 36 | rclcpp::shutdown(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/gnss-provider/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(gnss_provider VERSION 0.0.2) 4 | 5 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 6 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 8 | 9 | include(GNUInstallDirs) 10 | 11 | find_package(PkgConfig REQUIRED) 12 | 13 | pkg_check_modules(gps libgps REQUIRED IMPORTED_TARGET) 14 | 15 | find_package(CommonAPI REQUIRED) 16 | find_package(CommonAPI-SomeIP REQUIRED) 17 | find_package(gnss REQUIRED) 18 | find_package(gnss_someip_lib REQUIRED) 19 | 20 | find_package(concurrentqueue REQUIRED) 21 | 22 | find_package(ament_cmake REQUIRED) 23 | find_package(rclcpp REQUIRED) 24 | 25 | add_library(gnss_someip_lib INTERFACE IMPORTED) 26 | target_link_libraries(gnss_someip_lib 27 | INTERFACE 28 | CommonAPI 29 | CommonAPI-SomeIP 30 | gnss_someip_lib::gnss-msg__rosidl_generator_cpp # TODO: figure out how to define exported targets 31 | gnss_someip_lib::gnss-msg__rosidl_typesupport_cpp # TODO: figure out how to define exported targets 32 | ) 33 | 34 | set(SERVER_TARGET_NAME gnss-server) 35 | add_executable(${SERVER_TARGET_NAME} 36 | src/main.cpp 37 | ) 38 | 39 | target_include_directories(${SERVER_TARGET_NAME} PRIVATE 40 | ${COMMONAPI_INCLUDE_DIRS} 41 | ) 42 | 43 | target_link_libraries(${SERVER_TARGET_NAME} PRIVATE 44 | gnss::gnss 45 | rclcpp::rclcpp 46 | concurrentqueue::concurrentqueue 47 | PkgConfig::gps 48 | gnss_someip_lib 49 | ) 50 | 51 | target_compile_features(${SERVER_TARGET_NAME} PRIVATE cxx_std_17) 52 | target_compile_definitions(${SERVER_TARGET_NAME} PRIVATE -DGNSS_SERVER_VERSION="${PROJECT_VERSION}") 53 | 54 | install(TARGETS ${SERVER_TARGET_NAME} DESTINATION lib/${PROJECT_NAME}) 55 | 56 | ament_package() 57 | -------------------------------------------------------------------------------- /src/gnss-provider/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnss_provider 5 | 0.0.1 6 | TODO 7 | Mikhail Tsukerman 8 | MIT 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | gnss_someip_lib 14 | 15 | rclcpp 16 | 17 | 18 | rosidl_default_runtime 19 | 20 | rosidl_interface_packages 21 | 22 | ament_lint_auto 23 | ament_lint_common 24 | 25 | 26 | ament_cmake 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/gnss-provider/src/gnss_someip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | class GnssSomeIpProvider : public v0::gnss::GnssServerStubDefault { 11 | 12 | public: 13 | GnssSomeIpProvider() = default; 14 | ~GnssSomeIpProvider() = default; 15 | 16 | void fireDataEvent(const GnssDataMsg & gps_data) { 17 | 18 | RCLCPP_INFO(rclcpp::get_logger("GNSS_SOMEIP_Provider"), "Sending gnss data over SOME/IP."); 19 | 20 | auto data = Types::Conversion::to_capi_type(gps_data); 21 | 22 | GnssServerStub::fireDataEvent(data); 23 | } 24 | 25 | }; 26 | 27 | template 28 | class GnssSomeIpReporter : public rclcpp::Node 29 | { 30 | static constexpr auto node_name = "GNSS_SOMEIP_Reporter"; 31 | 32 | static constexpr auto domain = "local"; 33 | static constexpr auto instance = "GnssServer"; 34 | static constexpr auto timer_duration = 2s; 35 | 36 | static constexpr auto topic = "GPSD"; 37 | static constexpr auto qos = 10; 38 | 39 | public: 40 | GnssSomeIpReporter() 41 | : Node(node_name) 42 | , someip_provider(std::make_shared()) 43 | { 44 | if(register_someip_service()) { 45 | RCLCPP_INFO(this->get_logger(), "SOME/IP GnssServer has been registered"); 46 | 47 | gpsd_data_subscription = this->create_subscription(topic, qos, std::bind(&GnssSomeIpReporter::on_gpsd_data, this, std::placeholders::_1)); 48 | 49 | publish_timer = this->create_wall_timer(timer_duration, [this]() { 50 | RCLCPP_INFO(this->get_logger(), "Timer: Broadcast GNSS data over SOME/IP"); 51 | 52 | std::lock_guard guard(mutex); 53 | 54 | someip_provider->fireDataEvent(gps_data); 55 | }); 56 | } 57 | } 58 | 59 | protected: 60 | 61 | bool register_someip_service() { 62 | if(!CommonAPI::Runtime::get()->registerService(domain,instance, someip_provider)) { 63 | //TODO: handle error case correctly 64 | RCLCPP_ERROR(this->get_logger(), "Failed to register SOME/IP GnssServer"); 65 | return false; 66 | } 67 | 68 | return true; 69 | } 70 | 71 | void on_gpsd_data(const GnssDataMsg & msg) 72 | { 73 | std::lock_guard guard(mutex); 74 | 75 | RCLCPP_INFO(this->get_logger(), "Received GPS raw data from GpsdClient node"); 76 | 77 | gps_data = msg; 78 | } 79 | 80 | private: 81 | rclcpp::TimerBase::SharedPtr publish_timer; 82 | std::shared_ptr someip_provider; 83 | 84 | std::mutex mutex; 85 | 86 | GnssDataMsg gps_data; 87 | 88 | rclcpp::Subscription::SharedPtr gpsd_data_subscription; 89 | }; 90 | -------------------------------------------------------------------------------- /src/gnss-provider/src/gpsd_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace Types::Conversion { 11 | 12 | /** 13 | * @brief converts gpsd datatype gps_data_t to ros2 msg generated type 14 | * 15 | * @param gps_data 16 | * @return GnssDataMsg 17 | */ 18 | GnssDataMsg to_gnss_data_msg(const gps_data_t * gps_data) { 19 | GnssDataMsg msg; 20 | 21 | msg.position.fix.latitude = gps_data->fix.latitude; 22 | msg.position.fix.longitude = gps_data->fix.longitude; 23 | msg.position.dop.hdop = gps_data->dop.hdop; 24 | msg.position.dop.vdop = gps_data->dop.vdop; 25 | msg.position.satellites_visible = gps_data->satellites_visible; 26 | msg.position.satellites_used = gps_data->satellites_used; 27 | 28 | return msg; 29 | } 30 | 31 | } // namespace Types::Conversion 32 | 33 | // inspired by https://gist.github.com/ncoder-1/8313815ac387e6757f751dc8960f03d7 34 | class GpsdClient : public rclcpp::Node { 35 | 36 | static constexpr auto node_name = "GPSD_Client_node"; 37 | 38 | static constexpr auto gpsd_host = "localhost"; 39 | static constexpr auto waiting_time = 1000000; 40 | 41 | static constexpr auto topic = "GPSD"; 42 | static constexpr auto qos = 10; 43 | 44 | static constexpr auto gpsd_read_timer_delay = 500ms; 45 | 46 | public: 47 | GpsdClient() 48 | : Node(node_name), 49 | gps_rec(gpsd_host, DEFAULT_GPSD_PORT) 50 | { 51 | publisher = this->create_publisher(topic, qos); 52 | 53 | if(!init()) { 54 | RCLCPP_WARN(this->get_logger(), "No connection to gpsd"); 55 | } 56 | 57 | timer = this->create_wall_timer(gpsd_read_timer_delay, std::bind(&GpsdClient::read, this)); 58 | 59 | //TODO: handle case when there is no connection to gpsd 60 | } 61 | ~GpsdClient() = default; 62 | 63 | bool init() { 64 | if (gps_rec.stream(WATCH_ENABLE | WATCH_JSON) == nullptr) { 65 | return false; 66 | } 67 | 68 | return true; 69 | } 70 | 71 | void read() { 72 | for(;;) 73 | { 74 | std::lock_guard lock_guard(mutex); 75 | 76 | if (!gps_rec.waiting(waiting_time)) { 77 | RCLCPP_WARN(this->get_logger(), "Waiting, failed to read data from gpsd"); 78 | continue; 79 | } 80 | 81 | struct gps_data_t* gpsd_data; 82 | 83 | if ((gpsd_data = gps_rec.read()) == nullptr) { 84 | RCLCPP_WARN(this->get_logger(), "Null, Failed to read data from gpsd"); 85 | continue; 86 | } 87 | 88 | RCLCPP_WARN(this->get_logger(), "Obtained data from gpsd"); 89 | 90 | auto msg = Types::Conversion::to_gnss_data_msg(gpsd_data); 91 | 92 | publisher->publish(msg); 93 | 94 | return; 95 | } 96 | } 97 | 98 | protected: 99 | 100 | private: 101 | gpsmm gps_rec; 102 | 103 | std::mutex mutex; 104 | 105 | rclcpp::TimerBase::SharedPtr timer; 106 | rclcpp::Publisher::SharedPtr publisher; 107 | }; 108 | -------------------------------------------------------------------------------- /src/gnss-provider/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "gnss_someip.h" 4 | #include "gpsd_client.h" 5 | 6 | auto main(int argc, char **argv) -> int 7 | { 8 | rclcpp::init(argc, argv); 9 | 10 | rclcpp::executors::MultiThreadedExecutor executor; 11 | 12 | auto gnss_someip_reporter_node = std::make_shared>(); 13 | auto gpsd_client_node = std::make_shared(); 14 | 15 | executor.add_node(gnss_someip_reporter_node); 16 | executor.add_node(gpsd_client_node); 17 | 18 | executor.spin(); 19 | 20 | rclcpp::shutdown(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(gnss_someip_lib VERSION 0.0.1) 4 | 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 6 | 7 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 8 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 10 | 11 | find_package(ament_cmake REQUIRED) 12 | find_package(rosidl_default_generators REQUIRED) 13 | 14 | find_package(CommonAPITools REQUIRED) 15 | find_package(FrancaRosTools REQUIRED) 16 | 17 | find_package(CommonAPI REQUIRED) 18 | find_package(CommonAPI-SomeIP REQUIRED) 19 | 20 | include(GNUInstallDirs) 21 | include(CMakePackageConfigHelpers) 22 | 23 | 24 | # TODO: find a way to use add_custom_command 25 | # add_custom_command( 26 | # OUTPUT 27 | # ${CMAKE_BINARY_DIR}/ros/msg/Dop.msg 28 | # ${CMAKE_BINARY_DIR}/ros/msg/Fix.msg 29 | # ${CMAKE_BINARY_DIR}/ros/msg/Position.msg 30 | # COMMAND 31 | # ${FIDL2ROS_TRANSLATOR} -i ${CMAKE_CURRENT_SOURCE_DIR}/src/ -f ${CMAKE_CURRENT_SOURCE_DIR}/src/gnss.fidl -o ${CMAKE_BINARY_DIR}/ros/msg/ 32 | # DEPENDS 33 | # ${CMAKE_CURRENT_SOURCE_DIR}/src/gnss.fidl 34 | # ${CMAKE_CURRENT_SOURCE_DIR}/src/types.fidl 35 | # ${CMAKE_CURRENT_SOURCE_DIR}/src/gnss.fdepl 36 | # ) 37 | 38 | execute_process( 39 | COMMAND 40 | ${FIDL2ROS_TRANSLATOR} -i ${CMAKE_CURRENT_SOURCE_DIR}/src/ -f ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/gnss.fidl -o ${CMAKE_BINARY_DIR}/ros/msg/ 41 | ) 42 | 43 | file(RELATIVE_PATH GNSS_DATA_MSG ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/ros/msg/GnssData.msg) 44 | file(RELATIVE_PATH POSITION_MSG ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/ros/msg/Position.msg) 45 | file(RELATIVE_PATH DOP_MSG ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/ros/msg/Dop.msg) 46 | file(RELATIVE_PATH FIX_MSG ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/ros/msg/Fix.msg) 47 | file(RELATIVE_PATH TIME_MSG ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/ros/msg/Time.msg) 48 | 49 | set(GNSS_MSG_TARGET_NAME gnss-msg) 50 | rosidl_generate_interfaces(${GNSS_MSG_TARGET_NAME} 51 | ${DOP_MSG} 52 | ${FIX_MSG} 53 | ${TIME_MSG} 54 | ${POSITION_MSG} 55 | ${GNSS_DATA_MSG} 56 | ) 57 | 58 | set(GNSS_FILES 59 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/common.hpp 60 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServer.hpp 61 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerProxyBase.hpp 62 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerProxy.hpp 63 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerStub.hpp 64 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerSomeIPProxy.cpp 65 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/commonSomeIPDeployment.cpp 66 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/commonSomeIPDeployment.hpp 67 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerSomeIPDeployment.cpp 68 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerSomeIPDeployment.hpp 69 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerSomeIPStubAdapter.cpp 70 | ${CMAKE_BINARY_DIR}/gen/v0/gnss/GnssServerStubDefault.hpp 71 | ) 72 | 73 | add_custom_command( 74 | OUTPUT 75 | ${GNSS_FILES} 76 | COMMAND 77 | ${COMMON_API_CORE_GENERATOR} -sk ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/gnss.fidl -d ${CMAKE_BINARY_DIR}/gen 78 | COMMAND 79 | ${COMMON_API_SOMEIP_GENERATOR} ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/gnss.fdepl -d ${CMAKE_BINARY_DIR}/gen 80 | DEPENDS 81 | ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/gnss.fidl 82 | ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/types.fidl 83 | ${CMAKE_CURRENT_SOURCE_DIR}/src/fidl/gnss.fdepl 84 | ) 85 | 86 | set(GNSS_TARGET_NAME gnss) 87 | add_library(${GNSS_TARGET_NAME} SHARED ${GNSS_FILES}) 88 | target_link_libraries(${GNSS_TARGET_NAME} PUBLIC 89 | CommonAPI 90 | CommonAPI-SomeIP 91 | ) 92 | 93 | set(GNSS_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}/gnss-${PROJECT_VERSION_MAJOR}/) 94 | 95 | target_include_directories(${GNSS_TARGET_NAME} 96 | PRIVATE 97 | $ 98 | ${COMMONAPI_INCLUDE_DIRS} 99 | PUBLIC 100 | $ 101 | ) 102 | 103 | set_target_properties(${GNSS_TARGET_NAME} PROPERTIES 104 | VERSION ${PROJECT_VERSION} 105 | SOVERSION ${PROJECT_VERSION_MAJOR}) 106 | 107 | install(TARGETS 108 | ${GNSS_TARGET_NAME} 109 | EXPORT 110 | ${GNSS_TARGET_NAME}Config 111 | DESTINATION 112 | ${CMAKE_INSTALL_LIBDIR} 113 | ) 114 | 115 | install(DIRECTORY ${CMAKE_BINARY_DIR}/gen/ DESTINATION ${GNSS_INSTALL_INCLUDEDIR}) 116 | 117 | write_basic_package_version_file( 118 | ${CMAKE_CURRENT_BINARY_DIR}/${GNSS_TARGET_NAME}ConfigVersion.cmake 119 | VERSION ${PROJECT_VERSION} 120 | COMPATIBILITY AnyNewerVersion 121 | ) 122 | 123 | set(GNSS_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${GNSS_TARGET_NAME}-${PROJECT_VERSION_MAJOR}/) 124 | 125 | install(FILES 126 | ${CMAKE_CURRENT_BINARY_DIR}/${GNSS_TARGET_NAME}ConfigVersion.cmake 127 | DESTINATION 128 | ${GNSS_INSTALL_CMAKEDIR} 129 | ) 130 | 131 | install(EXPORT 132 | ${GNSS_TARGET_NAME}Config 133 | NAMESPACE 134 | ${GNSS_TARGET_NAME}:: 135 | DESTINATION 136 | ${GNSS_INSTALL_CMAKEDIR} 137 | ) 138 | 139 | export(TARGETS 140 | ${GNSS_TARGET_NAME} 141 | NAMESPACE 142 | ${GNSS_TARGET_NAME}:: 143 | FILE 144 | ${GNSS_TARGET_NAME}Config.cmake 145 | ) 146 | 147 | install(FILES 148 | ${CMAKE_CURRENT_SOURCE_DIR}/src/types/conversion.h 149 | DESTINATION 150 | ${GNSS_INSTALL_INCLUDEDIR}/types/ 151 | ) 152 | 153 | configure_file(config/commonapi.ini.in ${CMAKE_BINARY_DIR}/commonapi.ini) 154 | 155 | install(FILES ${CMAKE_BINARY_DIR}/commonapi.ini DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}) 156 | 157 | ament_export_dependencies(rosidl_default_runtime) 158 | ament_package() 159 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/cmake/FindCommonAPITools.cmake: -------------------------------------------------------------------------------- 1 | if(NOT COMMON_API_GENERATORS_FOUND) 2 | 3 | if(NOT DEFINED COMMON_API_CORE_GENERATOR) 4 | find_program(COMMON_API_CORE_GENERATOR NAMES commonapi-core-generator) 5 | message(STATUS "Core generator: ${COMMON_API_CORE_GENERATOR}") 6 | endif() 7 | 8 | if(NOT DEFINED COMMON_API_SOMEIP_GENERATOR) 9 | find_program(COMMON_API_SOMEIP_GENERATOR NAMES commonapi-someip-generator) 10 | message(STATUS "SOME/IP generator: ${COMMON_API_SOMEIP_GENERATOR}") 11 | endif() 12 | 13 | find_package(PackageHandleStandardArgs REQUIRED) 14 | 15 | find_package_handle_standard_args(CommonAPIGenerators DEFAULT_MSG COMMON_API_CORE_GENERATOR COMMON_API_SOMEIP_GENERATOR) 16 | 17 | mark_as_advanced(COMMON_API_GENERATORS_FOUND COMMON_API_CORE_GENERATOR COMMON_API_SOMEIP_GENERATOR) 18 | endif() 19 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/cmake/FindFrancaRosTools.cmake: -------------------------------------------------------------------------------- 1 | if(NOT FRANCA_ROS_TOOLS_FOUND) 2 | 3 | if(NOT DEFINED FIDL2ROS_TRANSLATOR) 4 | find_program(FIDL2ROS_TRANSLATOR NAMES fidl2ros) 5 | message(STATUS "fidl2ros translator: ${FIDL2ROS_TRANSLATOR}") 6 | endif() 7 | 8 | find_package(PackageHandleStandardArgs REQUIRED) 9 | 10 | find_package_handle_standard_args(FrancaRosTools DEFAULT_MSG FIDL2ROS_TRANSLATOR) 11 | 12 | mark_as_advanced(FRANCA_ROS_TOOLS_FOUND FIDL2ROS_TRANSLATOR) 13 | endif() 14 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/config/commonapi.ini.in: -------------------------------------------------------------------------------- 1 | [default] 2 | binding=someip 3 | 4 | [logging] 5 | console=true 6 | file=/var/log/commonapi.log 7 | dlt=true 8 | level=debug 9 | 10 | [proxy] 11 | local:gnss.GnssServer:v0_1:GnssServer=@CMAKE_INSTALL_FULL_LIBDIR@/lib@GNSS_TARGET_NAME@.so.@PROJECT_VERSION@ 12 | 13 | [stub] 14 | local:gnss.GnssServer:v0_1:GnssServer=@CMAKE_INSTALL_FULL_LIBDIR@/lib@GNSS_TARGET_NAME@.so.@PROJECT_VERSION@ 15 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnss_someip_lib 5 | 0.0.1 6 | TODO 7 | Mikhail Tsukerman 8 | MIT 9 | 10 | ament_cmake 11 | 12 | rclcpp 13 | rclcpp 14 | ament_lint_auto 15 | ament_lint_common 16 | 17 | rosidl_interface_packages 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/src/fidl/gnss.fdepl: -------------------------------------------------------------------------------- 1 | import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl" 2 | import "gnss.fidl" 3 | 4 | define org.genivi.commonapi.someip.deployment for interface gnss.GnssServer { 5 | 6 | SomeIpServiceID = 1234 7 | 8 | broadcast data { 9 | SomeIpEventID = 38002 10 | SomeIpEventGroups = { 7002 } 11 | } 12 | } 13 | 14 | define org.genivi.commonapi.someip.deployment for provider as Service { 15 | 16 | instance gnss.GnssServer { 17 | InstanceId = "GnssServer" 18 | SomeIpInstanceID = 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/src/fidl/gnss.fidl: -------------------------------------------------------------------------------- 1 | package gnss 2 | 3 | import gnss.common.* from "types.fidl" 4 | 5 | interface GnssServer { 6 | version { major 0 minor 1 } 7 | 8 | broadcast data { 9 | out { 10 | GnssData data 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/src/fidl/types.fidl: -------------------------------------------------------------------------------- 1 | package gnss 2 | 3 | typeCollection common { 4 | version {major 0 minor 1} 5 | 6 | struct Time { 7 | UInt32 hours 8 | UInt32 minutes 9 | UInt32 seconds 10 | } 11 | 12 | struct Dop { 13 | Float hdop 14 | Float vdop 15 | Float pdop 16 | } 17 | 18 | struct Fix { 19 | Double latitude 20 | Double longitude 21 | } 22 | 23 | struct Position { 24 | UInt32 satellites_visible 25 | UInt32 satellites_used 26 | UInt32 status 27 | Fix fix 28 | Dop dop 29 | } 30 | 31 | struct GnssData { 32 | Position position 33 | Time time 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/gnss-someip-lib/src/types/conversion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | using namespace std::chrono; 10 | using GnssDataMsg = gnss_someip_lib::msg::GnssData; 11 | using GnssData = v0::gnss::common::GnssData; 12 | 13 | namespace Types::Conversion { 14 | 15 | /** 16 | * @brief converts ROS2 MSG to CommonAPI generated data type 17 | * 18 | * @param gps_data 19 | * @return GnssData 20 | */ 21 | GnssData to_capi_type(const GnssDataMsg & gps_data) { 22 | GnssData gnss_data; 23 | 24 | v0::gnss::common::Position position; 25 | v0::gnss::common::Time time; 26 | v0::gnss::common::Fix fix; 27 | v0::gnss::common::Dop dop; 28 | 29 | fix.setLatitude(gps_data.position.fix.latitude); 30 | fix.setLongitude(gps_data.position.fix.longitude); 31 | 32 | dop.setHdop(gps_data.position.dop.hdop); 33 | dop.setVdop(gps_data.position.dop.vdop); 34 | dop.setPdop(gps_data.position.dop.pdop); 35 | 36 | position.setSatellites_visible(gps_data.position.satellites_visible); 37 | position.setSatellites_used(gps_data.position.satellites_used); 38 | position.setDop(dop); 39 | position.setFix(fix); 40 | 41 | gnss_data.setPosition(position); 42 | gnss_data.setTime(time); 43 | 44 | return gnss_data; 45 | } 46 | 47 | /** 48 | * @brief converts CommonAPI generated data type to ROS2 data type 49 | * 50 | * @param gps_data 51 | * @return GnssData 52 | */ 53 | GnssDataMsg from_capi_type(const GnssData & gnss_data) { 54 | 55 | GnssDataMsg gps_data_msg; 56 | 57 | auto position = gnss_data.getPosition(); 58 | 59 | gps_data_msg.position.fix.latitude = position.getFix().getLatitude(); 60 | gps_data_msg.position.fix.longitude = position.getFix().getLongitude(); 61 | gps_data_msg.position.dop.hdop = position.getDop().getHdop(); 62 | gps_data_msg.position.dop.vdop = position.getDop().getVdop(); 63 | gps_data_msg.position.satellites_visible = position.getSatellites_visible(); 64 | gps_data_msg.position.satellites_used = position.getSatellites_used(); 65 | 66 | return gps_data_msg; 67 | } 68 | 69 | 70 | } // namespace TypeConversion 71 | --------------------------------------------------------------------------------