vsomeip
文章目录
1.vsomeip概述
vsomeip的代码使用http://some-ip.com/[Scalable service-Oriented MiddlewarE over IP (SOME/IP)] protocol。源码包含:
- 一个SOME/IP动态库(
libvsomeip.so
) - 还有一个动态库用于SOME/IP的服务发现(
libvsomeip-sd.so
)。在运行期间如果服务发现功能开启,该动态库就会被加载。
2.构建步骤
2.1构建前准备
- 能够编译c++11编译器,比如5.2版本及以上的gcc
- cmake构建工具
- boost库,版本在1.55及以上
- 如果使用Google的测试架构,你需要从https://code.google.com/p/googletest/[gtest]下载1.7.0及以上版本
- 如果想要构建文档,你需要安装asciidoc, source-highlight, doxygen和 graphviz
2.2构建build
你需要进入到vsomeip的根目录:
2.2.1一般构建
#一般构建步骤
mkdir build
cd build
cmake ..
make
2.2.2自定义路径安装
#如果想要安装在自定义路径(比如 --prefix= ,前提是你需要熟悉autotools。autotools是一些列工具,用于生成makefile),你可以按照如下命令进行cmake
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX:PATH=$YOUR_PATH ..
make
make install
#默认路径会安装到 /usr/local/
#usr 指 Unix System Resource
#/usr:系统级的目录,可以理解为C:/Windows/,/usr/lib理解为C:/Windows/System32。
#/usr/local:用户级的程序目录,可以理解为C:/Progrem Files/。用户自己编译的软件默认会安装到这个目录下。
#/opt:用户级的程序目录,可以理解为D:/Software,opt有可选的意思,这里可以用于放置第三方大型软件(或游戏),当你不需要时,直接rm -rf掉即可。在硬盘容量不够时,也可将/opt单独挂载到其他磁盘上使用。
#源码放哪里?
#/usr/src:系统级的源码目录。
#/usr/local/src:用户级的源码目录
#很多应用都安装在/usr/local下面,那么,这些应用为什么选择这个目录呢?理解了最根源的原因后,也许对你理解linux组织文件的方式有更直观的理解。
#答案是:Automake工具定义了下面的一组变量:
#prefix /usr/local
# exec_prefix ${prefix}
# bindir ${exec_prefix}/bin
# libdir ${exec_prefix}/lib
# includedir ${prefix}/include
# datarootdir ${prefix}/share
# datadir ${datarootdir}
# mandir ${datarootdir}/man
# infodir ${datarootdir}/info
# docdir ${datarootdir}/doc/${PACKAGE}
#关于make install命令,可以参考https://zhuanlan.zhihu.com/p/77813702
2.2.3添加BasePath
#base path为生成的unix domain socket文件的路径
#可以使用cmake执行命令:
cmake -DBASE_PATH=<YOUR BASE PATH> ..
#默认的base path是/tmp
#对于socket是什么,可以参考https://blog.csdn.net/pashanhu6402/article/details/96428887
2.2.4使用unicast and/or diagnosis address进行编译
#预定义unicast,unicast是单播地址,默认为127.0.0.1
cmake -DUNICAST_ADDRESS=<YOUR IP ADDRESS> ..
#预定义diagnosis,diagnosis address只占一个字节,默认为0x01
cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> ..
2.2.5使用DEFAULT_CONFIGURATION_FOLDER
#默认使用的配置文件夹所在路径
cmake -DDEFAULT_CONFIGURATION_FOLDER=<DEFAULT CONFIGURATION FOLDER> ..
#默认的default configuration folder路径是/etc/vsomeip,
#但是本电脑实际位置是/usr/local/etc/vsomeip
2.2.6使用DEFAULT_CONFIGURATION_FILE
#默认使用的配置文件路径
cmake -DDEFAULT_CONFIGURATION_FILE=<DEFAULT CONFIGURATION FILE> ..
#默认的配置文件是/etc/vsomeip.json
2.2.7使用ENABLE_SIGNAL_HANDLING
#如果没有使用自定义去处理信号,可以使用vsomeip自带的信号处理
cmake -DENABLE_SIGNAL_HANDLING=1 ..
#该选项会通过定义宏VSOMEIP_ENABLE_SIGNAL_HANDLING,来启用vsomeip自己的信号处理代码
#对SIGINT等信号的理解,可以参考https://www.cnblogs.com/alexyuyu/articles/3853583.html
2.2.8使用ROUTING_READY_MESSAGE
#可以自定义一些log,当IP路由准备好发送和接收message,可以执行cmake
cmake -DROUTING_READY_MESSAGE=<YOUR MESSAGE> ..
2.2.9使用ENABLE_CONFIGURATION_OVERLAYS
#To compile vsomeip with configuration overlays enabled
cmake -DENABLE_CONFIGURATION_OVERLAYS=1 ..
2.2.10使用ENABLE_COMPAT
#To compile vsomeip with enabled vSomeIP 2 compatibility layer
cmake -DENABLE_COMPAT=1 ..
2.3编译examples
mkdir build
cd build
cmake ..
make examples
2.4编译tests
想要编译tests,首先把gtest解压到自定义路径。有一些测试需要在同一个网段中再加一个节点。有两个cmake变量可以用来自动更改json中的ip来适应当前工作的网络配置。
TEST_IP_MASTER
: test master的ip地址TEST_IP_SLAVE
: test slave(另一个节点)的ip地址
任意一个变量没有被设置,那么测试只能在本地运行,无法进行跨物理机的测试。
当然你也可以设置ENABLE_SIGNAL_HANDLING
,来使单元测试也能够处理信号。
完整的例子如下:
mkdir build
cd build
export GTEST_ROOT=<the path of googletest>
cmake -DENABLE_SIGNAL_HANDLING=1 -DTEST_IP_MASTER=10.0.3.1 -DTEST_IP_SLAVE=10.0.3.125 ..
2.4.1编译check
另有几个make targets可以在test使用
make build_tests
,只编译testsctest
,在build目录执行该命令可以没有冗余输出的执行testsctest -V -R $TESTNAME
,运行单个测试,相当于ctest --verbose --tests-regex $TESTNAME
ctest -N
,列出当前可执行的测试
更多有关测试的信息,可以参考tests
目录下的readme.txt
还有两个变量(默认值都是OFF)用来控制是否json文件和测试脚本需要拷贝或者连接到build:
TEST_SYMLINK_CONFIG_FILES
,控制是否json文件和测试脚本需要拷贝到buildTEST_SYMLINK_CONFIG_FILES_RELATIVE
,控制是否json文件和测试脚本需要连接到build
如果只想编译测试的子集(用于快速的功能检查),可以使用cmake变量TESTS_BAT
(默认值是OFF)
2.5编译vsomeip_ctrl
2.6生成文档
想要生成文档就需要按照<> 中描述执行cmake,之后再执行 make doc
这会生成:
- The README file in html:
$BUILDDIR/documentation/README.html
- A doxygen documentation in
$BUILDDIR/documentation/html/index.html
3.启动vsomeip应用和使用环境变量
vsomeip应用启动时以下的环境变量会被读取:
VSOMEIP_APPLICATION_NAME
,赋予当前程序在vsomeip中使用的名字。vsomeip会通过改名字在配置文件中进行匹配查找。该名字与二进制可执行文件的名字是不一样的。VSOMEIP_CONFIGURATION
,vsomeip默认会使用配置文件/etc/vsomeip.json
或者包含配置文件的文件夹/etc/vsomeip
。你可以通过该变量使vsomeip使用自定义的配置文件。VSOMEIP_MANDATORY_CONFIGURATION_FILES
,vsomeip允许使用mandatory配置文件来加快应用的启动速度(此时,除负责连接某些外部设别的程序之外,其他所有程序运行时都需要按照mandatory配置文件工作)。默认mandatory配置文件是:vsomeip_std.json, vsomeip_app.json和vsomeip_plc.jsonVSOMEIP_CLIENTSIDELOGGING
,
注意:
- 配置文件如果找不到,就会使用默认的配置文件
- vsomeip会读取${VSOMEIP_CONFIGURATION}中所有的配置文件,但不会读取该路径下的文件夹。
4.配置文件的内容
4.1整体架构
vsomeip的配置文件有多个键值对和键值对数组构成。
一个完整的object,以{
开始,以}
结束,每一个键值对用:
连接,多个键值对用,
隔开。如果有array,以[
开始,以]
结束,多个[]用,
隔开。
例如:
{
"unicast" : "192.168.56.101",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" },
"dlt" : "false"
},
"applications" :
[
{
"name" : "client-sample",
"id" : "0x1343"
},
{
"name" : "other-client-sample",
"id" : "0x1344"
},
{
"name" : "service-sample",
"id" : "0x1277"
}
],
"services" :
[
{
"service" : "0x1234",
"instance" : "0x5678",
"reliable" : { "port" : "30509", "enable-magic-cookies" : "false" },
"unreliable" : "31000"
},
{
"service" : "0x1235",
"instance" : "0x5678",
"reliable" : { "port" : "30506", "enable-magic-cookies" : false },
"unreliable" : "31000"
}
],
"routing" : "client-sample",
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.244.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"
}
}
4.2基本元素
4.2.1"unicast"
主机的IP地址。
4.2.2"netmask"
主机的子网掩玛。
4.2.3"device"
该参数可选。如果规定了,IP endpoints会绑定到该设备。endpoints应该是服务端和客户端的进行通信的地方。
4.2.4"diagnosis"
长度为一个字节长,用于构建客户端的标识符(即client ID)。如果没有其他规定(例如:自定义了client ID),diagnosis address会被用做client ID的高位字节。
4.2.5"diagnosis_mask"
长度为两个字节。用于控制一个ECU上最大可容纳vsomeip client数量,并规定了client ID的起始值。
例如,默认值0xFF00
,表示:高位字节为diagnosis address预留,并且client ID的初始值为自定义的diagnosis address。最大的客户端数量是255,因为 Hamming weight of the inverted mask
( Hamming weight:一串符号中非零符号个数。Hamming weight of the inverted mask就是一段字符中值为0的字符个数)是8(2^8-1=255,其中1是留给路由管理的)。生成的client IDs(例如diagnosis address是0x45)会从 0x4501到0x45ff。
当默认值是0xFE00
时,clinet ID的数量为511,因为此时 Hamming weight of the inverted mask为9。当diagnosis address是0x45时,client ID的起始值时0x4401(0x4400作为路由器,因为从0x4500开始会超范围),到0x45ff。
4.2.6"network"
用于一个主机上有多个routing managers的情况。该参数可以更改/dev/shm
中共享内存段的名字以及/tmp/
下的 unix domain sockets名字。
默认情况该参数的值为”vsomeip“,则对应的共享内存被命名为/dev/shm/vsomeip
,unix domain sockets被命名为/tmp/vsomeip-$CLIENTID
。
4.2.7"logging"
4.2.7.1"level"
明确日志的级别,可选的值有六个:trace, debug, info, warning,error, fatal
4.2.7.2"console"
明确log信息是否通过控制台输出,可选的值有:true, false
4.2.7.3"file"
“enable”,决定是否创建一个log文件,可选的值有:true, false
“path”,用于存放生成的日志文件的绝对路径
4.2.7.4"dlt"
决定是否使用Diagnostic Log and Trace (DLT),可选的值有:true, false
4.2.7.5version
vsomeip的版本
4.2.7.5.1’enable’
能否周期的查询vsomeip的版本,可选值有:true(默认值),false
4.2.7.5.2’interval’
周期记录vsomeip版本时的间隔时间,默认是两次记录的间隔为10s
4.2.7.6’memory_log_interval’
routing manager会周期性的记录其使用的内存状况,该参数表示两次记录的时间间隔,单位是秒。当设置参数之比0大时,该参数就会其作用。
4.2.7.7’status_log_interval’
routing manager会周期性的记录其当前状态,该参数表示两次记录的时间间隔,单位是秒。当设置参数之比0大时,该参数就会其作用。
4.3 全部参数配置示例
假设配置文件中使用所有配置参数,那么大概内容为如下所示:
{
"unicast" : "10.0.2.15",
"netmask" : "255.255.0.0",
"device" : "eth0",
"diagnosis" : "0x01",
"diagnosis_mask" : "0xFF00",
"network" : "vsomeip_example",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
"dlt" : "false",
"version" : {"enable" : "false", "interval" : "20"},
"memory_log_interval" : "2",
"status_log_interval" : "2"
},
"tracing" : {
"enable" : "true",
"sd_enable" : "true",
"channels" : [
{
"name" : "",
"id" : "0"
}
],
"filters" : [
{
"channel" : "0",
"matches" : "any",
"type" : "positive"
}
]
},
"applications" :
[
{
"name" : "service-sample",
"id" : "0x1277",
"max_dispatchers" : "12",
"max_dispatch_time" : "100",
"threads" : "2",
"io_thread_nice" : "2",
"request_debounce_time" : "10",
"plugins" : [
{
"name" : "",
"type" : "application_plugin"
}
],
"overlay" : "path_other_configuration",
}
],
"services" :
[
{
"service" : "0x1234",
"instance" : "0x5678",
"protocol" :"someip",
"unicast" : "10.0.2.15",
"reliable" : {
"port" : "30490",
"enable-magic-cookies" : "true",
},
"unreliable" : "30509",
"events" :
[
{
"event" : "0x0777",
"is_field" : "true",
"is_reliable" : "true"
}
],
"eventgroups" :
[
{
"eventgroup" : "0x4455",
"events" : [ "0x777", "0x778" ],
"multicast" :
{
"address" : "224.225.226.233",
"port" : "32344"
},
"threshold" : 0
}
],
"debounce-times" : {
},
"someip-tp" : {
"service-to-client" : [
],
"client-to-service" : [
]
}
}
],
"clients" : [
{
"service" : "0x1234",
"instance" : "0x5678",
"reliable" : [
],
"unreliable" : [
],
"reliable_remote_ports" : "",
"unreliable_remote_ports" : "",
"reliable_client_ports" : "",
"unreliable_client_ports" : "",
"first" : "3333",
"last" : "3335"
}
],
"payload-sizes" : [
{
"unicast" : "10.0.2.15",
"ports" : {
"port" : "30490",
"max-payload-size" : 1000
}
}
],
"max-payload-size-local" : 1000,
"max-payload-size-reliable" : 1000,
"max-payload-size-unreliable" : 1000,
"endpoint-queue-limit-external" : 10,
"endpoint-queue-limit-local" : 10,
"buffer-shrink-threshold" : 100,
"tcp-restart-aborts-max" : 10,
"tcp-connect-time-max" : 10,
"udp-receive-buffer-size" : 100,
"internal_services" : [
{
"first": {
"service" : 1111,
"instance" : "0x5678"
},
"last" : {
"service" : 1111,
"instance" : "0x5678"
}
}
],
"endpoint-queue-limits" : [
{
"unicast" : "10.0.2.15",
"ports" : [
{
"port" : "30490",
"queue-size-limit" : 12,
}
]
}
],
"debounce" : [
{
"service" : "0x1234",
"instance" : "0x5678",
"events" : [
{
"event" : "0x0777",
"on_change" : "true",
"ignore" : [
{
"index" : 1,
"mask" : 1
}
],
"interval" : "20",
"on_change_resets_interval_" : "true"
}
]
}
],
"routing" : "service-sample",
"routing-credentials" : {
"uid" : 111,
"gid" : 111
},
"shutdown_timeout" : 5000,
"warn_fill_level" : 67,
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.244.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"ttl_factor_offers" : [
{
"service" : "0x1234",
"instance" : "0x5678",
"ttl_factor" : 1
}
],
"ttl_factor_subscriptions" : [
{
"service" : "0x1234",
"instance" : "0x5678",
"ttl_factor" : 1
}
],
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500",
"offer_debounce_time" : 500
},
"watchdog" : {
"enable" : "true",
"timeout" : 5000,
"allowed_missing_pongs" : 3,
},
"supports_selective_broadcasts" : [
{
"address" : "224.225.226.233"
}
],
"security" :
{
"policies" :
[
{
"credentials" :
{
"uid" : "44",
"gid" : "any"
},
"allow" :
[
{
"requests" :
[
{
"service" : "0x6731",
"instance" : "0x0001"
}
]
}
]
},
{
"credentials" :
{
"deny" :
[
{
"uid" : [ "1000", { "first" : "1002", "last" : "max" }],
"gid" : [ "0", { "first" : "100", "last" : "243" }, "300"]
},
{
"uid" : ["55"],
"gid" : ["55"]
}
]
},
"allow" :
[
{
"offers" :
[
{
"service" : "0x6728",
"instances" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"]
},
{
"service" : "0x6729",
"instances" : ["0x88"]
},
{
"service" : "0x6730",
"instance" : "any"
}
],
"requests" :
[
{
"service" : "0x6732",
"instances" :
[
{
"ids" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }],
"methods" : [ "0x0001", "0x0003", { "first" : "0x8001", "last" : "0x8006" } ]
},
{
"ids" : [ "0x0009" ],
"methods" : "any"
}
]
},
{
"service" : "0x6733",
"instance" : "0x1"
},
{
"service" : "0x6733",
"instances" : [ "0x0002", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"]
}
]
}
]
}
]
}
}