(三) 搞定SOME/IP通信之CommonAPI库

本章主要介绍在SOME/IP通信过程中的另外一个IPC通信利剑,CommonAPI库,文章将从如下几个角度让读者了解什么是CommonAPI, 以及库在实际工作中的作用

文中资源:vsomeip+commonapi+指导文档与demo源码

SOME/IP通信之CommonAPI

  • CommonAPI库是什么
  • CommonAPI库的编译
  • 写个Demo实战一下

CommonAPI库是什么

CommonAPI是GENIVI组织开发的一个基于C++的应用API库,没错,跟vsomeip协议栈是一个爹。其主要提供给使用通讯中间件传输数据的分布式应用来操作通讯中间件的接口。主要的作用是使使用CommonAPI进行IPC通信的的应用能够隔离底层协议栈的差异。比如使用CommonAPI时,我们的底层协议栈可以是vsomeip,也可以是DBUS等. 他的架构如下:
在这里插入图片描述
从图中可以看到,CommonAPI C++ 框架分为两个主要部分:

CommonAPI Core: 这部分与中间件无关,包含了跨不同中间件技术共享的基本 API、类和组件。它提供了构建应用程序所需的基本通信机制和抽象,而不与特定的中间件协议绑定。

CommonAPI Binding: 这部分与特定中间件相关,并包含了每种支持的中间件协议的实现细节。

通过将Core与Binding分开,CommonAPI C++ 允许开发人员使用与中间件无关的核心编写他们的应用程序逻辑,使其代码更具可移植性,不会紧密绑定到特定的中间件。然后,他们可以选择特定的绑定,将他们的应用程序适配到所需的中间件技术,而无需重写整个应用程序逻辑。

这种关注点分离使得开发更容易,可以在具有不同中间件要求的各种汽车系统中部署应用程序。它通过在中间件无关逻辑和特定中间件实现细节之间提供明确的分离,促进了可重用性和模块化。

图右边的四个框架,分别代表了Core层的代码生成工具,以及接口描述语言(fidl), Binding层的代码生成工具,以及接口描述语言(fdepl),即:

Code Generator Tools  <-->   *.fidl
Code Generator Binding Tools <--> *.fdepl

关于fidl跟fdepl文件是什么,如果你做过android开发,那么对aidl文件以及hidl文件会比较熟悉,这个fidl跟fdepl文件也是跟aidl&hidl的作用类似,我们将通信行为的接口以及参数定义在文件中,通过CommonAPI提供的Code Generators,即可将这些文件转成对应的C++接口。上层在在进行IPC接口时,只需要调用这些C++中的接口即可

CommonAPI库的编译

因为我们是基于android系统来使用CommonAPI通信,故使用ndk+gradle来编译库

编译环境

操作系统:win11
Gradle: 7.3.3
cmake版本:3.18.1

下载源码
这里包含两部分,一个是CommonAPI Core,一个是CommonAPI Binding分别对应如下两个库:

capicxx-core-runtime
capicxx-someip-runtime

下载完成后,将文件夹拷贝到上一篇文章提供的附件工程中的external目录下面,放好后如下所示:
在这里插入图片描述

修改CMakeList
然后我们需要修改工程根目录下的CMakeLists.txt文件, 注意是工程根目录,不是模块根目录,修改后内容如下所示:

cmake_minimum_required(VERSION 3.10)project(SOMEIP)list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/output/${ANDROID_ABI})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/output/${ANDROID_ABI})
set(FETCHCONTENT_SOURCE_DIR_BOOST ${CMAKE_CURRENT_SOURCE_DIR}/external/boost_1_71_0)
add_subdirectory(external/boost-cmake)
add_subdirectory(external/vsomeip)
add_subdirectory(external/capicxx-core-runtime-master)
add_subdirectory(external/capicxx-someip-runtime-master)
add_subdirectory(app/src/main/cpp)

external/capicxx-core-runtime-master/CMakeLists.txt

#添加编译标记,不然会编译报错(-Wno-ignored-attributes -Wno-deprecated-declarations)
IF(MSVC)message("using MSVC Compiler")add_definitions(-DCOMMONAPI_INTERNAL_COMPILATION -DCOMMONAPI_DLL_COMPILATION)add_compile_options(/EHsc /wd4996)
ELSE ()set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wformat -Wformat-security -Wconversion -fexceptions -fstrict-aliasing -fstack-protector -fasynchronous-unwind-tables -fno-omit-frame-pointer -Werror -DCOMMONAPI_INTERNAL_COMPILATION -fvisibility=hidden -Wno-ignored-attributes -Wno-deprecated-declarations")
ENDIF(MSVC)

external/capicxx-core-runtime-master/CMakeLists.txt

if ("${USE_INSTALLED_COMMONAPI}" STREQUAL "ON")FIND_PACKAGE(CommonAPI 3.2.0 REQUIRED CONFIG NO_CMAKE_PACKAGE_REGISTRY)
else()
# 注释掉REQUIRED
#    FIND_PACKAGE(CommonAPI 3.2.0 REQUIRED CONFIG NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH)FIND_PACKAGE(CommonAPI 3.2.0)
endif()# maintainer-clean target去掉
if(NOT ANDROID)
add_custom_target(maintainer-clean COMMAND rm -rf *)
endif()

在根目录的cmake文件夹下再按照cmake的find_package规则添加两个文件,FindCommonAPI.cmake, 跟FindCommonAPI-SomeIP.cmake 两个文件

然后启动编译,就可以在工程根目录的output目录下看到库基本已经全部输出了
在这里插入图片描述

写个Demo实战一下

上面库编译完成了,书接上回的vsomeip demo,我们需要将someip_server跟someip_client这两个库改造以下,不直接使用vsomeip协议栈的API, 改为CommonAPI的方式来实现。

在写代码之前,咱们来回顾一下之前使用vsomeip协议栈API写的例子,我们定义了一个天气服务,然后服务中提供了一个获取温度的方法,参数如下:

//服务ID
static vsomeip::service_t  weather_service_id = 0x1001;
//服务实例ID
static vsomeip::instance_t weather_service_instance_id = 0x0001;
//方法ID
static vsomeip::method_t   weather_get_temp_method_id = 0x0001;

这里我们把它改造成CommonAPI的方式,首先在cpp目录下创建如下两个文件,并填入内容:

IWeatherService.fidl

package com.commapi.testinterface IWeatherService {version { major 0 minor 1 }method getTemp {out {Int32 temp}}
}

IWeatherService.fdepl

import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl"
import "IWeatherService.fidl"define org.genivi.commonapi.someip.deployment for interface com.commapi.test.IWeatherService {SomeIpServiceID = 4097 //0x1001method getTemp {SomeIpMethodID = 1 //0x0001SomeIpReliable = true}
}define org.genivi.commonapi.someip.deployment for provider as Service {instance com.commapi.test.IWeatherService {InstanceId = "com.commapi.test.IWeatherService"SomeIpInstanceID = 1 //0x0001}
}

我们这里只展示使用方式,fidl&fdepl的语法,我们后面会专门起文章来介绍。

写好后,需要下载如下两个工具:
commonapi_core_generator-3.2.0
commonapi_someip_generator-3.2.0.1

下载完成后,解压到执行的目录, 然后启动cmd窗口,跳转到我们的fidl & fdepl文件所在目录,然后输入如下命令,即可:

commonapi-core-generator-windows-x86_64.exe -sk  *.fidl
commonapi-someip-generator-windows-x86_64.exe  *.fdepl

在这里插入图片描述
这里我们会发现我们的fidl文件夹下多了自动生成了一个src-gen的文件夹,内容如下:
在这里插入图片描述
接下来改造server端跟client端,第一步先把cpp跟.h文件加入到编译源文件中, 修改cpp目录下的CMakeLists.txt如下:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.18.1)# Declares and names the project.
project("someip")find_package (vsomeip3 3.3.8 REQUIRED)
find_library(log-lib log)
include_directories(${VSOMEIP3_INCLUDE_DIRS})# CommonAPI
find_package(CommonAPI 3.2.0 REQUIRED)
include_directories(${COMMONAPI_INCLUDE_DIRS})# CommonAPI-SomeIP
find_package(CommonAPI-SomeIP 3.2.0 REQUIRED)
include_directories(${CommonAPI-SomeIP_INCLUDE_DIRS})# SRC-GEN
include_directories(fidl/src-gen)
file(GLOB SRC-GEN fidl/src-gen/v0/com/commapi/test/*.cpp)add_executable(someip_server# Provides a relative path to your source file(s).someip_server.cpp${SRC-GEN})target_link_libraries(someip_server ${log-lib} vsomeip3 vsomeip3-e2e vsomeip3-sd CommonAPI CommonAPI-SomeIP)add_executable(someip_client# Provides a relative path to your source file(s).someip_client.cpp${SRC-GEN})target_link_libraries(someip_client ${log-lib} vsomeip3 vsomeip3-e2e vsomeip3-sd CommonAPI CommonAPI-SomeIP)

编译文件修改完成后,再将我们之前的vsomeip的两个端代码修改为CommonAPI方式,对应两个文件如下:

服务端实现:someip_server.cpp

#include <string>
#include <csignal>
#include <unistd.h>
#include "CommonAPI/CommonAPI.hpp"
#include "v0/com/commapi/test/IWeatherServiceStubDefault.hpp"using namespace v0::com::commapi::test;class WeatherServiceStub : public IWeatherServiceStubDefault {
private:int temp = -32;
public:WeatherServiceStub() = default;~WeatherServiceStub() override = default;void getTemp(const std::shared_ptr<CommonAPI::ClientId> _client, getTempReply_t _reply) override{printf("%s : gid[%d], uid[%d]\n", __func__ , _client->getGid(), _client->getUid());_reply(temp++);}
};int main(int args, char** argc){//设置配置文件路径setenv("COMMONAPI_CONFIG", "vendor/etc/commonapi.ini",1);setenv("VSOMEIP_CONFIGURATION", "/vendor/etc/local_server.json", 1);auto runtime = CommonAPI::Runtime::get();auto weather_service = std::make_shared<WeatherServiceStub>();auto server_register = runtime->registerService("local","com.commapi.test.IWeatherService",weather_service,"someip_server");printf("register weather service : %d\n", server_register);while(true){usleep(1000 * 1000);}return 1;
}

客户端实现:someip_client.cpp

#include <string>
#include <csignal>
#include <unistd.h>
#include "thread"
#include "CommonAPI/CommonAPI.hpp"
#include "v0/com/commapi/test/IWeatherService.hpp"
#include "v0/com/commapi/test/IWeatherServiceProxy.hpp"using namespace v0::com::commapi::test;int main(int args, char** argc){setenv("COMMONAPI_CONFIG", "vendor/etc/commonapi.ini",1);setenv("VSOMEIP_CONFIGURATION", "/vendor/etc/local_client.json", 1);auto runtime = CommonAPI::Runtime::get();auto app = runtime->buildProxy<IWeatherServiceProxy>("local","com.commapi.test.IWeatherService","someip_client");while(true){if(!app->isAvailable()){printf("connecting failed, retry\n");sleep(1);continue;}break;}app->getProxyStatusEvent().subscribe([&app](CommonAPI::AvailabilityStatus status){if(status == CommonAPI::AvailabilityStatus::AVAILABLE){printf("service available\n");std::thread t1([&app]{for(int i=0; i<10; i++){CommonAPI::CallStatus callStatus;int32_t temp;CommonAPI::CallInfo callInfo;app->getTemp(callStatus, temp, &callInfo);printf("CallStatus = %d, getTemp: %d\n",callStatus, temp);}});t1.detach();}});while(true){usleep(1000 * 1000);}return 1;
}

我这里为了方便仅测试单机模式(双机模式一样的,只是配置不一样)
修改服务端配置local_server.json

{"unicast":"127.0.0.1","logging":{"level":"debug","console":"true"},"applications":[{"name":"someip_server","id":"0x1000"}],"services" :[{"service" : "0x1001","instance" : "0x0001","reliable" : { "port" : "30509", "enable-magic-cookies" : "false" }}],"routing":"someip_server","service-discovery" :{"enable" : "true","multicast" : "239.224.224.245","port" : "30490","protocol" : "udp","initial_delay_min" : "10","initial_delay_max" : "100","repetitions_base_delay" : "200","repetitions_max" : "3","ttl" : "3","cyclic_offer_delay" : "2000","request_response_delay" : "1500"}
}

修改客户端配置:local_client.json

{"unicast":"127.0.0.1","netmask" : "255.255.255.0","logging":{"level":"debug","console":"true"},"applications":[{"name":"someip_client","id":"0x1001"}],"clients" :[{"service" : "0x1001","instance" : "0x0001","reliable" : [ "41234" ]}],"service-discovery" :{"enable" : "false"}
}

然后按照上一篇vsomeip的方式,把库跟文件分别push到系统对应的目录,执行后,即可看到通信正常执行了,如下图。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/94719.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Jetpack Compose 中的分页与缓存展示

Android Jetpack Compose 中的分页与缓存展示 在几乎任何类型的移动项目中&#xff0c;移动开发人员在某个时候都会处理分页数据。如果数据列表太大&#xff0c;无法一次从服务器检索完毕&#xff0c;这就是必需的。因此&#xff0c;我们的后端同事为我们提供了一个端点&#…

基于YOLOv5n/s/m不同参数量级模型开发构建茶叶嫩芽检测识别模型,使用pruning剪枝技术来对模型进行轻量化处理,探索不同剪枝水平下模型性能影响【续】

这里主要是前一篇博文的后续内容&#xff0c;简单回顾一下&#xff1a;本文选取了n/s/m三款不同量级的模型来依次构建训练模型&#xff0c;所有的参数保持同样的设置&#xff0c;之后探索在不同剪枝处理操作下的性能影响。 在上一篇博文中保持30的剪枝程度得到的效果还是比较理…

异步更新队列 - Vue2 响应式

前言 这篇文章分析了 Vue 更新过程中使用的异步更新队列的相关代码。通过对异步更新队列的研究和学习&#xff0c;加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子&#xff1a; <div id"app"><div id"div" v-if"isShow&…

Vue的鼠标键盘事件

Vue的鼠标键盘事件 原生 鼠标事件(将v-on简写为) click // 点击 dblclick // 双击 mousedown // 按下 mousemove // 移动 mouseleave // 离开 mouseout // 移出 mouseenter // 进入 mouseover // 鼠标悬浮mousedown.left 键盘事件 keydown //键盘按下时触发 keypress …

C#工程建立后修改工程文件名与命名空间

使用之前的项目做二次开发&#xff0c;项目快结束的时候&#xff0c;需要把主项目的名称修改成我们想要的。 之前从来没有这么干过&#xff0c;记录一下。 步骤如下&#xff1a; 1&#xff1a;打开vs2010项目解决方案&#xff0c;重命名&#xff0c;如下图所示&#xff1a; …

微服务-Nacos(配置管理)

配置更改热更新 在Nacos中添加配置信息&#xff1a; 在弹出表单中填写配置信息&#xff1a; 配置获取的步骤如下&#xff1a; 1.引入Nacos的配置管理客户端依赖&#xff08;A、B服务&#xff09;&#xff1a; <!--nacos的配置管理依赖--><dependency><groupId&…

Git使用教程

一&#xff1a;Git是什么&#xff1f; Git是目前世界上最先进的分布式版本控制系统。文章下面有Git常用所有命令 二&#xff1a;SVN与Git的最主要的区别&#xff1f; SVN是集中式版本控制系统&#xff0c;版本库是集中放在中央服务器的&#xff0c;而干活的时候&#xff0c;用…

SQL Developer中的Data Redaction

SQL Developer中的Data Redaction用起来比命令行方便多了。可以选定表或视图&#xff0c;右键点击“遮盖保护”菜单。 但赋权方面有需要注意的地方。 假设Redact Admin是SYS&#xff0c;Redact User是HR。虽然SYS具备所有权限&#xff0c;但还是报以下错误。其实这个错误是针…

使用 PyTorch 进行高效图像分割:第 4 部分

一、说明 在这个由 4 部分组成的系列中&#xff0c;我们将使用 PyTorch 中的深度学习技术从头开始逐步实现图像分割。本部分将重点介绍如何实现基于视觉转换器的图像分割模型。 图 1&#xff1a;使用视觉转换器模型架构运行图像分割的结果。 从上到下&#xff0c;输入图像、地面…

Linux系列讲解 —— 【debugfs】交互式文件系统调试器

手册上说debugfs可以用于检查和更改ext2、ext3或ext4文件系统的状态。似乎很牛的样子&#xff0c;但是我并没有试验出来它多么强大的功能&#xff0c;无非就是在某些文件损坏导致无法删除的时候&#xff0c;我用debugfs来删除这些文件而已&#xff0c;如果有人知道它其他的妙用…

laravel-admin之 解决上传图片不显示 $form->image(‘image‘); 及 $grid->column(‘image‘);

参考 https://blog.csdn.net/u013164285/article/details/106017464 $grid->column(‘image’)->image(‘http://wuyan.cn’, 100, 100); // //设置服务器和宽高 图片上传的域名 上传的图片不显示 在 这里设置了图片的上传路径 在这里设置 域名 就可以回显图片

地理测绘基础知识(3)-观测与遮挡

在上一篇文章中&#xff0c;我们介绍了椭球模型下的一系列基础的坐标操作。本节&#xff0c;介绍观测与遮挡问题。 观测主要用于从观察点A观测大地标准点B&#xff0c;用来解决观测的仰角、方位角与大地坐标系之间的关系。 在没有GPS卫星的时代&#xff0c;为了测量一个位置的…

Unity小项目__小球吃零食

// Player脚本文件源代码 public class Player : MonoBehaviour {public Rigidbody rd; // 定义了一个刚体组件public int score 0; // 定义了一个计分器public Text scoreText; // 定义了一个文本组件public GameObject winText; // 定义了一个游戏物体用于检验游戏结束// S…

WPF显示初始界面--SplashScreen

WPF显示初始界面–SplashScreen 前言 WPF应用程序的运行速度快&#xff0c;但并不能在瞬间启动。当第一次启动应用程序时&#xff0c;会有一些延迟&#xff0c;因为公共语言运行时&#xff08;CLR&#xff09;首先需要初始化.NET环境&#xff0c;然后启动应用程序。 对于WPF中…

【数据结构与算法】队列

文章目录 一&#xff1a;队列1.1 队列的概念1.2 队列的介绍1.3 队列示意图 二&#xff1a;数组模拟队列2.1 介绍2.2 思路2.3 代码实现2.3.1 定义队列基本信息2.3.2 初始化队列2.3.3 判断队列是否满&#xff0c;是否为空2.3.4 添加数据到队列2.3.5 获取队列数据&#xff0c;出队…

Shell学习笔记之基础部分

Shell基础&#xff1a; 查看操作系统支持的shell&#xff1a; [rootrhel9 ansible]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bashShell的基本元素&#xff1a; 声明&#xff1a;声明用哪个命令解释器来解释并执行当前脚本文件中的语句&#xff0c;一般写的…

浅谈5G技术会给视频监控行业带来的一些变革情况

5G是第五代移动通信技术&#xff0c;能够提供更高的带宽和更快的传输速度&#xff0c;这将为视频技术的发展带来大量机会。随着5G技术的逐步普及与商用&#xff0c;人们将能够享受到更加流畅的高清视频体验&#xff0c;并且5G技术还拥有更低的延迟和更高的网络容量。这些优势不…

Vue中实现自动匹配搜索框内容 关键字高亮文字显示

实现效果如下: 1.首先需要给输入框进行双向绑定 2.拿到搜索的结果去渲染页面 将返回的结果和搜索的关键字进行比对 如果相同的 就变红 上代码 html部分 //输入框<div class"search"><div class"shuru"><input type"请输入要查询的…

论文阅读——Imperceptible Adversarial Attack via Invertible Neural Networks

Imperceptible Adversarial Attack via Invertible Neural Networks 作者&#xff1a;Zihan Chen, Ziyue Wang, Junjie Huang*, Wentao Zhao, Xiao Liu, Dejian Guan 解决的问题&#xff1a;虽然视觉不可感知性是对抗性示例的理想特性&#xff0c;但传统的对抗性攻击仍然会产…

机器学习:基本介绍

机器学习介绍 Hnad-crafted rules Hand-crafted rules&#xff0c;叫做人设定的规则。那假设今天要设计一个机器人&#xff0c;可以帮忙打开或关掉音乐&#xff0c;那做法可能是这样&#xff1a; 设立一条规则&#xff0c;就是写一段程序。如果输入的句子里面看到**“turn of…