vsomeip与commonAPI的移植与应用
vsomeip与CommonAPI的移植与应用
1. vsomeip 交叉编译与安装
1.1 说明
vsomeip是一个SOME/IP开源协议栈。如图1所示,boost库为vsomeip的必须依赖项,因此编译安装vsomeip的前提是将boost依赖库交叉编译完成。
![image-20230414132002059](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414132002059.png)
图1 vsomeip编译安装步骤
1.2 安装版本与资源下载
本次编译安装的软件版本是boost1.74和vsomeip3.1.20。如图2所示。
![image-20230414132216749](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414132216749.png)
图2 下载boost库
进入boost压缩包放置文件夹,使用以下指令解压boost压缩包
1 |
|
打开终端,输入以下指令下载vsomeip源文件
1 |
|
1.3 交叉编译boost库
运行 sh ./bootstrap.sh
,程序将在boost文件夹生成b2可执行程序和配置文件project-config.jam
![image-20230414144307974](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414144307974.png)
图3 在终端中运行bootstrap.sh
然后编辑project-config.jam,修改地方有两处,第一处为将工具链设置为S32G处理器的arm64编译工具链;第二处为简化安装,只编译vsomeip所依赖的库,log,thread和system。
tips:请注意空格
1 |
|
运行b2程序
1 |
|
安装完成后,install文件夹将包含include与lib两个文件夹。
使用file指令可以查看是否正确编译为arm架构boost库
1.4 交叉编译vsomeip库
修改CMakeLists.txt,如下所示,也可以将boost库的安装路径添加到环境变量PATH中。
1 |
|
然后将工具链设置为S32G处理器的arm64编译工具链,可以在终端中输入如下指令,临时修改系统默认编译器,这种方法在关闭终端后,需要重新设置。用户也可以修改.bashrc
文件来永久将S32G编译器设置为系统默认编译器。使用指令sudo vim ~/.bashrc
,然后在bashrc中输入上述指令。
1 |
|
cmake编译,编译安装完成后,install文件夹包含 etc, include与lib三个文件夹。
1 |
|
编译测试例程并测试
1 |
|
1.5 S32G开发板例程演示
将文件导入开发板有两种方式,用户选择其中之一即可,如图4所示。(scp命令亦可)
![image-20230414134333961](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414134333961.png)
图4 传输文件的两种方式
通过filezilla传输文件时,连接网线后,输入开发板的IP地址和登录用户名,点击下方的连接即可,如图5。需要注意的是,开发板IP地址和PC的IP地址需要在同一网段。与此同时,建议将需传输文件打包成压缩包,否则可能会出现程序动态链接库强制转换为静态库问题。
![image-20230414134456367](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414134456367.png)
图5 filezilla连接设置
将boost和vsomeip中的库文件添加到系统 /usr/lib下,然后分终端同时打开hello_world_service和hello_world_client,运行结果如图6所示。
![image-20230414134538447](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414134538447.png)
图6 例程运行结果
2. vsomeip跨设备通信
2.1 说明
vsomeip的通信过程如图7所示。在上一节的例程中,服务端与客户端位于同一台主机上,两者的通信过程即图中的左半部分,底层为通过socket完成的进程间通信。本节将简述使用vsomeip进行两台嵌入式linux设备之间的通信例程,演示真正意义上的SOME/IP通信。
![image-20230414134804582](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414134804582.png)
图7 vsomeip通信过程
本次使用的两台嵌入式设备分别为NXP S32G开发板以及基于NXP iMX8芯片的飞凌嵌入式开发板。S32G作为客户端,iMX8作为服务端。使用一台TP-Link路由器将两者连接,再使用一根网线连接路由器至电脑,如图8所示。
![image-20230414134854586](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414134854586.png)
图8 设备连接图
2.2 IP设置与通信测试
将各设备分别设置为以下IP地址:
笔记本电脑:192.168.100.50
S32G开发板:192.168.100.100
iMX8开发板:192.168.100.60
IP地址可通过ifconfig设置。硬件连接与IP地址设置完成后,使用ping和arping指令进行通信测试,然后使用ssh指令分别远程登录2台嵌入式linux设备。
2.3 vsomeip通信参数设置
服务端与客户端分别需要配置一个json文件。以iMX8服务端为例,service.json文件如下。其中192.168.100.50
为当前嵌入式设备的IP地址。
“name” : “World”:名称需要与VSOMEIP_APPLICATION_NAME读入的名称一致,注意不是程序文件名称。
“service” : “0x1234”, “instance” : “0x5678” :需要与程序中的地址对应。
1 |
|
为了方便运行,可以参考如下写一个快速运行的脚本。touch run_service.sh
1 |
|
其中,第一行的作用为设置多播地址,enxd03745a6a072为设备网卡名称,通过ifconfig查看,并做对应修改。
2.4 实例演示
在服务端终端中输入 sudo sh ./run_service.sh
启动vsomeip服务端程序。类似的在另一个设备中启动客户端程序。需要传输的数据自行在程序中设定,本程序运行结果如下。
![image-20230414135716470](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414135716470.png)
图9 程序运行结果
3. commonAPI交叉编译与安装
3.1 说明
CommonAPI是一个开源的RPC(远程过程调用)框架,其封装了底层通信协议,使得上层应用接口与底层通信协议解耦,具体原理可参考官方文档。目前底层可以支持SOME/IP和D-Bus两种协议,本文进行底层为SOME/IP协议的CommonAPI编译安装与演示。
整体编译安装过程如图10所示,首先通过官方提供的代码生成器commonapi_core_generator和commonapi_someip_generator将FDL接口描述文件转换为C++文件,此步在X86_64平台上完成;然后将boost、vsomeip、capicxx-core-runtime以及capicxx-someip-runtime交叉编译至ARM64平台上;最后借助ARM交叉编译工具链,即可编译出可在S32G开发板上运行的程序。
![image-20230414135941356](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414135941356.png)
图10 交叉编译安装CommonAPI流程
3.2 安装版本与资源下载
时间 | 2021-08-25 |
---|---|
安装软件版本 | capicxx-core-runtime 版本 3.2.0 capicxx-someip-runtime 版本 3.2.0 commonapi_core_generator 版本 3.2.0.1 commonapi_someip_generator 版本 3.2.0.1 vsomeip 3.1.20.3 |
下载地址:
3.3 交叉编译capicxx-core-runtime
首先需要设置交叉编译工具链,如下。
1 |
|
然后进行构建,如下。
1 |
|
编译完成后,使用tree指令查看arm64_core_install文件下,如下。
![image-20230414140718046](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414140718046.png)
图11 install目录
3.4 交叉编译capicxx-someip-runtime
capicxx-someip-runtime依赖于boost库与vsomeip库,因此需要修改CMakeLists.txt文件,使之可以顺利找到交叉编译完成的boost和vsomeip库。参照1.3节及1.4节。
然后进行构建,如下。
1 |
|
3.5 安装Java环境
commonapi_core_generator和commonapi_someip_generator代码生成器依赖于JAVA8环境,因此首先需要安装jdk,在终端中输入下述指令。
1 |
|
使用 java -version可以查看当前安装的java版本,若已安装高版本java,请降级,高版本java会导致代码生成出错。仅针对目前安装版本
3.6 S32G开发板例程演示
本例程为helloworld演示。建立helloworld例程目录如下,将代码生成器commonapi_core_generator
和commonapi_someip_generator
放置在cgen文件夹下,新建HelloWorld.fidl
和HelloWorld.fdel
文件并放置于fidl文件,src-gen文件夹在运行代码生成器后自动生成,相关信息参考图12。
![image-20230414141549265](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414141549265.png)
图12 helloworld例程目录释义
- FDL文件代码生成
1 |
|
1 |
|
代码生成器commonapi_core_generator目录如图13所示,可根据平台选择对应的生成器,64位ubuntu选择commonapi-core-generator-linux-x86_64。然后运行如下指令,生成C++代码。
1 |
|
![image-20230414142107302](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414142107302.png)
图13 commonapi_core_generator目录
- 指定交叉编译工具链
修改CMakeLists.txt,如图14所示。
![image-20230414144023413](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414144023413.png)
图14 helloworld CMakeLists.txt文件
修改arm_linux_setup.cmake,ARM_DIR等针对修改。
![image-20230414143909525](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414143909525.png)
图15 helloworld arm_linux_setup.cmake文件
- 可执行文件生成及运行
安装如下指令构建可执行文件
1 |
|
可使用file指令查看可执行文件类型信息
将文件传输至开发板中,并将编译好的库文件添加到开发板 /usr/lib文件夹中,然后分终端同时打开HelloWorldService和HelloWorldClient,运行结果如图14所示
![image-20230414142807201](/2023/04/14/vsomeip%E4%B8%8EcommonAPI%E7%9A%84%E7%A7%BB%E6%A4%8D%E4%B8%8E%E5%BA%94%E7%94%A8/image-20230414142807201.png)
图14 helloworld运行结果
4. 附录1—问题及解决方案
本节将记录在vsomeip和commonAPI的安装编译过程中,碰到的一些问题及对应的解决方案,仅供参考。
- 可执行文件生成及运行X86-64环境下安装libboost库时的boost版本问题
vsomeip官方安装文档过旧,ubuntu20.04源中boost版本已经更新,不能直接使用文档中的指令。解决方案有两个,其一是在boost库中下载对应版本,编译运行;其二则是在终端中使用 sudo apt-cache search libboost
查找新版本并安装。
- 在终端中 “ctrl+c” 停止vsomeip程序后,再次启动程序,提示vsomeip无法初始化成功
原因是在停止程序后,/tmp/vsomeip.lck
没有被正确删除。解决方案有以下几种,其一是手动删除与/tmp文件下与vsomeip相关的内容;其二是关闭shell,在重新打开;最后是在安装vsomeip时,cmake阶段使能ENABLE_SIGNAL_HANDLING
,这一步在前述安装指南中已默认操作。
- 启动vsomeip,程序报
configuration module could not be load
错误
其原因是新安装vsomeip后 ,没有在动态链接库配置目录中创建连接及缓存文件,可以使用 sudo ldconfig
命令刷新库缓存。
CMakeList中
find_package()
提示找不到vsomeip包其原因是vsomeip3.x版本后,包名变更为vsomeip3,因此可使用
find_package(vsomeip3 REQUIRED)
CommonAPI中,使用代码生成器无法将FDL文件转换为C++代码,或者转换后,工程无法编译通过
其原因是CommonAPI C++代码生成器与CommonAPI runtime的版本不匹配,此原因非常隐蔽,程序不会给出任何关于此方面的提示。解决方案是不要在GENIVI官网下载,去github上均下载最新版本。
- CommonAPI官方例程中,FDL接口描述文件出错,无法顺利生成C++代码
原因是例程FDL文件中语法有误,按照前述文档中红色标记代码修改。
- CommonAPI Java版本问题
目前CommonAPI代码生成器只支持java8环境,若安装java高版本,则需要手动降级,相关教程可参考:
- CommonAPI 直接运行例程,无法通过cmake生成makefile
CMakeLists.txt附加了需要D-Bus相关内容,而系统中未安装,可以对应修改删减CMakeLists.txt,也可参考如下:
1 |
|
- 可执行文件传输问题
如前所述,可执行文件通过filezilla直接传输文件时,会不明原因的将动态链接库转换为静态链接库,运行时提示“格式错误”。使用file指令查看时,可发现如下差异。
1 |
|
解决方案则是使用压缩包传输或者直接通过TF卡拷贝。
- 部分网络经验
在编写fdepl文件时,要先写attribute,在写method,再写broadcast,不能像fidl文件,穿插着写,否则编译不过。
在运行程序时,有时候会遇到无法连接的问题,需要把 /tmp/vsomeip-0
这一系列文件删除,否则无法连接。
5. 附录2—vsomeip与commonAPI的对比
commonAPI | vsomeip | |
---|---|---|
基本描述 | 基于vsomeip(可选)实现的RPC框架(远程过程调用) CommonAPI C++是用于开发分布式应用程序的标准C++ API规范,该分布式应用程序通过中间件进行进程间通信 |
实现了SOME/IP协议栈,构建了SOME/IP的共享库(libvsomeip3.so) |
依赖项 | 多,以vsomeip底层为例: 1. vsomeip 2. commonAPI runtime 3. commonAPI-SomeIP runtime 4. C++代码生成工具 |
少 boost |
接口描述语言 | 需要 FrancalDL接口描述语言 |
不需要 |
优劣势对比 | 优点: 1. 接口使用IDL描述,基本通信不需要联调,主要开发工作是实现服务的接口,相当于填充业务逻辑,工作量小 2. 封装通信协议与中间件,使得应用程序的C++接口独立于底层IPC,也就是IP Common API允许针对开发的应用程序(即使用C++的客户端和服务器)可以与不同的IPC后端链接(someip,或D-Bus),而无需更改应用程序代码 3. 屏蔽了网络通信的实现,让客户端可以像调用本地接口一样调用服务端提供的接口 缺点: 依赖项多,自由度低 |
优点: 依赖项少,自由度高 劣势: 1. 没有实现数据结构的序列化,仅仅涵盖了一些IP协议与服务发现,即Payload的打包与解析需要自己写,传递消息内容为复杂数据结构时,打包、解析和联调麻烦,且工作量大 2. 对于AUTOSAR系统,Payload要遵循AUTOSAR规范进行序列化,对于非AUTOSAR系统,可以遵循AUTOSAR规范进行序列化,也可以采用其他序列化方式如常用的Google Protocol Buffer、JSON等 |
6. 附录3—如何写fidl和fdepl文件
主要参考Franca语法以及官方提供的7个例程
- 写fidl和fdepl文件的最好方法是下载一个 Eclipse,并使用它的自动配置功能,它将插入所有必须的元素,剩下的自己填一下即可。
- 方法标识符:SomeIpMethodID,SomeIpGetterID,SomeIpSetterID 必须唯一,且在1~32767之间。
- 事件标识符:SomeIpEventID,SomeIpNotifierID,唯一,且在 32769~65534之间。
- SomeIpEventGroups 至少为1