(三) 搞定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到系统对应的目录,执行后,即可看到通信正常执行了,如下图。
相关文章:

(三) 搞定SOME/IP通信之CommonAPI库
本章主要介绍在SOME/IP通信过程中的另外一个IPC通信利剑,CommonAPI库,文章将从如下几个角度让读者了解什么是CommonAPI, 以及库在实际工作中的作用 文中资源:vsomeipcommonapi指导文档与demo源码 SOME/IP通信之CommonAPI CommonAPI库是什么C…...
windows bat脚本,使用命令行增加/删除防火墙:入站-出站,规则
常常手动设置防火墙的入站或出站规则,比较麻烦,其实可以用命令行搞定。 下面是禁用BCompare.exe连接网络的例子: ECHO OFF&(PUSHD "%~DP0")&(REG QUERY "HKU\S-1-5-19">NUL 2>&1)||(powershell -Comm…...

Stable Diffusion 告别复制关键词,高质量提示词自动生成插件
在使用SD时,我们经常会遇到心中无想法,或不知如何描述心中所想的图像。有时由于提示词的选择不当,生成的图片质量也不尽如人意。为此,我今天为大家推荐一个高质量的提示词自动生成插件——One Button Prompt。 下面是他生成的一些样图。 文章目录 插件安装插件说明主菜单工…...

【学习日记】【FreeRTOS】任务调度时如何考虑任务优先级——任务的自动切换
写在前面 本文开始为 RTOS 加入考虑任务优先级的自动调度算法,代码大部分参考野火。 本文主要是一篇学习笔记,加入了笔者自己对野火代码的梳理和理解。 一、基本思路 首先我们要知道,在 RTOS 中,优先级越高、越需要被先执行的的…...

C语言暑假刷题冲刺篇——day3
目录 一、选择题 二、编程题 🎈个人主页:库库的里昂 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏✨收录专栏:C语言每日一练✨其他专栏:代码小游戏C语言初阶🤝希望作者的文章能对你有…...
Taro+vue3小程序开启分享他人和分享到朋友圈
import Taro, { useShareAppMessage, useShareTimeline } from tarojs/taro;onMounted(() > {Taro.showShareMenu({withShareTicket: true,menus: [shareAppMessage, shareTimeline]}); }); useShareAppMessage((res) > {console.log(页面转发的回调)return {title: 开票…...

JAVA-Spring中IOC容器是什么?
目录 JAVA-Spring中IOC容器是什么?什么是IOC?什么是IOC容器?IOC和IOC容器的对比Spring框架中的IOC容器是如何工作的?使用XML配置的ApplicationContext使用注解的AnnotationConfigApplicationContext总结 JAVA-Spring中IOC容器是什…...

QT多屏显示程序
多屏显示的原理其实很好理解,就拿横向扩展来说: 计算机把桌面的 宽度扩展成了 w1(屏幕1的宽度) w2(屏幕2的宽度) 。 当一个窗口的起始横坐标 > w1,则 他就被显示在第二个屏幕上了。 多屏虚拟成一个桌面࿰…...

python使用xlwt时,报ValueError: More than 4094 XFs (styles)
在写表格时,遇到如下报错 一、报错原因 xlwt最多只能有4094个样式,超出这个样式数量就报错了。 二、解决办法 (1)去掉样式的要求...
GitHub 打不开解决方案
GitHub 这几年国内普通用户越来越难以访问,github 作为全球最大的开源平台,里面有用的内容很多,不管是对专业用户还是普通用户,无法访问都是很严重的问题。 1.GitHub 加速镜像 kgithub 是一个公益加速项目,仅需在 gi…...

Java网络编程(一)网络基础
概述 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递 网络分类 局域网(LAN) 局域网是一种在小区域内使用的,由多台计算机组成的网络,覆盖范围…...

matlab使用教程(17)—多项式的定义和运算
1.创建并计算多项式 此示例说明如何在 MATLAB 中将多项式表示为向量以及根据相关点计算多项式。 1.1 表示多项式 MATLAB 将多项式表示为行向量,其中包含按降幂排序的系数。例如,三元素向量 p [p2 p1 p0]; 表示多项式 创建一个向量以表示二次多项式…...

华为认证 | 这门HCIA认证正式发布!
华为认证云服务工程师HCIA-Cloud Service V3.5(中文版)自2023年8月11日起,正式在中国区发布。 01 发布概述 基于“平台生态”战略,围绕“云-管-端”协同的新ICT技术架构,华为公司打造了覆盖ICT领域的认证体系…...

【Docker】Docker安装 MySQL 8.0,简洁版-快速安装使用
今天,使用docker安装mysql数据库进行一个测试,结果网上找了一篇文章,然后。。。。坑死我… 特总结本篇安装教程,主打一个废话不多说! 坑:安装成功,客户端工具连接不上数据库》。。。 正文&…...

CSS自己实现一个步骤条
前言 步骤条是一种用于引导用户按照特定流程完成任务的导航条,在各种分步表单交互场景中广泛应用。例如:在HIS系统-门诊医生站中的接诊场景中,我们就可以使用步骤条来实现。她的执行步骤分别是:门诊病历>遗嘱录入>完成接诊…...

Visual Studio 2019 解决scanf函数报错问题
前言 Visual Studio 2019 解决scanf函数报错问题 博主博客链接:https://blog.csdn.net/m0_74014525 关注博主,后期持续更新系列文章 *****感谢观看,希望对你有所帮助***** 系列文章 第一篇:Visual Studio 2019 详细安装教程&…...

亚马逊无限买家号如何注册?
如果想要拥有大批量的亚马逊买家号,可以使用亚马逊鲲鹏系统进行自动注册操作。在注册之前我们需要先准备好账号所需要的资料; 1、Ip:软件系统支持11个亚马逊站点使用,因此注册哪一个国家的买家号时就需要购买相应国家的ip&#x…...
前端框架学习-ES6新特性(尚硅谷web笔记)
ECMASript是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。javaScript也是该规范的一种实现。 新特性目录 笔记出处:b站ES6let 关键字const关键字变量的解构赋值模板字符串简化对象写法箭头函数rest参数spread扩展运算符Promise模块化 ES8async 和 await E…...

普陀发布新规服务元宇宙企业 和数软件发展元宇宙场景落地
近日,数智中国AIGC科技周2023全球元宇宙大会上海站活动现场“半马苏河”元宇宙企业科创政策包正式发布。政策包在普陀原有科创政策基础上进行了叠加升级,一共涵盖了十条专项服务元宇宙企业的专项政策,简称普陀“元十条”。 普陀“元十条”从…...
Kotlin差异化分析,let,run,with,apply及also
作用域函数是Kotlin比较重要的一个特性,共分为以下5种:let、run、with、apply 以及 also,这五个函数的工作方式可以说非常相似,但是我们需要了解的是这5种函数的差异,以便在不同的场景更好的利用它。 读完这篇文章您将…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...