ubuntu系统下的vsomeip环境搭建

一种可运行环境配置
vsomeip 3.3.8
cmake 3.27
boost 1.78

  1. 下载源码
    去gitcode/github上下载源码
    vsomeip源码下载
    或者直接执行
    git clone https://gitcode.net/mirrors/COVESA/vsomeip.git
    可以得到最新版本的vsomeip源码。
  2. 安装依赖项
  • cmake
    安装
    sudo apt-get install cmake安装的cmake的版本较老,已经不适用。
    需要我们去官网上找较高版本的cmake进行下载安装。
    cmake官网地址
    可以自行选择下载一个较新的版本。
    也可以直接从github上克隆最新版,目前是3.27。
    git clone https://github.com/Kitware/CMake.git
    下载后打开文件夹,按步骤执行命令

    ./bootstrap
    make
    sudo make install
    make过程大概需要十几二十分钟
    上述全部执行完
    执行cmake -version能查到版本信息就说明安装成功了。
    卸载
    回到文件夹目录下,会发现有一个install_manifest.txt文件,执行命令
    cat install_manifest.txt | sudo xargs rm
    就可以完成卸载。
    此时再执行cmake -version就查不到版本信息了。

  • boost库
    安装
    同样的,用sudo apt-get install libboost安装的boost版本较老,不适用于一些较高版本的vsomeip(但适用于vsomeip3.3.0版本,应该是可以适配vsomeip3.3.0及以下版本),如果使用较高版本的vsomeip,比如最新版,需要自行下载安装较高版本的boost。
    去官网
    boost下载
    下载boost_1_78_0.tar.gz
    解压,进到文件夹,依次执行

    ./bootstrap.sh
    ./b2
    sudo ./b2 install
    卸载
    依次执行

    sudo rm -f /usr/local/lib/libboost*
    sudo rm -rf /usr/local/include/boost
    sudo rm -rf /usr/local/lib/cmake/boost*

  • 其他依赖
    其他依赖asciidoc、source-highlight、doxygen、graphviz安装比较简单,直接执行以下命令
    sudo apt-get install asciidoc source-highlight doxygen graphviz

  1. 搭建编译环境

    mkdir build
    cd build
    cmake …
    make
    sudo make install

至此,vsomeip环境配置完成。

跑通helloworld程序

找到vsomeip根目录下的example中的helloworld文件夹,进入可以看到一个readme文档,根据提示依次执行命令

mkdir build
cd build
cmake ..
make

因为是本机通讯,其实不改配置文件也可以,直接执行

VSOMEIP_CONFIGURATION=../helloworld-local.json \
VSOMEIP_APPLICATION_NAME=hello_world_service \
./hello_world_service

VSOMEIP_CONFIGURATION=../helloworld-local.json \
VSOMEIP_APPLICATION_NAME=hello_world_client \
./hello_world_client

此时应该可以看到和readme文档一样的expected输出。

如果报错:
libboost_thread.so.xxx.xxx.xxx: cannot open shared object file: No such file or directory
执行
sudo ldconfig
即可。

跑通request-sample&&response-sample和notify-sample&&subscribe-sample

本机通讯

进入根目录刚才build的文件夹内,找到examples,进入,执行命令
make
会得到四个可执行文件,分别是request-sample&&response-sample,notify-sample&&subscribe-sample。
回到根目录,直接进入examples,查看readme文件。
可以看到我们可以回到可执行文件目录,执行
请求/响应:

env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample

env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample

发布/订阅:

env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./subscribe-sample

env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./notify-sample

以此来实现请求响应或发布订阅模式。
上述实现了两种模式的本机通讯。

双机通讯

配置双机通讯环境

  1. 让两台主机都加入组播
    route add -net 224.0.0.0/4 dev eth0
  2. 编辑配置文件
    可以copy一份config里的vsomeip-local.json进行修改,放到/build/example目录下。
    修改的内容主要为:
  • 修改unicast为本机ip。
  • 修改routing为本机运行的application的名字,即和配置文件中的application的name匹配上,和程序运行时设置的环境变量VSOMEIP_APPLICATION_NAME也需要匹配上。

运行程序

实现发布/订阅,执行

VSOMEIP_CONFIGURATION=./client.json \
VSOMEIP_APPLICATION_NAME=Hello \
./subscribe-sample

VSOMEIP_CONFIGURATION=./service.json \
VSOMEIP_APPLICATION_NAME=World \
./notify-sample

实现请求/响应改一下文件名就行。
至此,实现双机通讯。

配置文件中一些参数的说明

"unicast":本机ip地址
"logging":日志相关

  • "level" : 默认debug,设置成error可以屏蔽掉除了error外的打印
    "applications":程序中的application设置
  • "name":application名,必须和环境变量对应上
  • "id":applicationID

services

  • service:serviceID
  • instance:instanceID
  • unreliable:表明是UDP传输,对应的reliable是TCP传输,这里的值表示UDP传输端口号,是service必须要有的
  • events:事件,包括eventID和一些其他配置
  • eventgroups:事件组,包括事件组ID、事件组包含的eventID和一些其他配置
    routing:充当路由角色的application的名称,如果没有指定,则本机第一个启动的vsomeip程序充当路由角色。单机通讯时可以任意指定client还是server端充当路由角色,双机通讯时则指定为本机的某个application的名字。

service-discovery:服务发现相关

  • enable:服务发现模块是否可用
  • multicast:服务发现的组播地址
  • port:收发sd消息的端口
  • protocol:组播协议
  • initial_delay_min:初始延迟最小值,用于调整服务实例启动后首次发布服务信息的时间
  • initial_delay-max:初始延迟最大值,同上
  • repetitions_base_delay:每次重复广播sd消息的基础延迟时间。首次广播sd消息,会先重复广播一定次数,之后再进入循环广播。
  • repetitions_max:首次广播sd消息时的最大重发次数
  • ttl:sd消息的生存时间
  • cyclic_offer_delay:循环offer的时间间隔
  • request_response_delay:请求响应延迟时间,控制响应速度

自定义开发

service端

配置信息

service端的app的名字和app的id需要写入配置文件service.json中。以LaneChange为例,例如:

"applications" : 
[
    {    
        "name" : "LaneChange_SP",
        "id" : "0x0202"
    }
]

启动程序时需要把环境变量设置为相同的名字。
需要明确service端的service id,service instance以及udp传输的端口号,即对应词条unreliable,这些信息必须写入配置文件中。例如:

"services" :
[
    {
        "service" : "0x301C",
        "instance" : "0x0001",
        "unreliable" : "33529"
    }
]

将service id和instance id写入sample-ids.hpp头文件中,可以根据其不同的服务内容为其命名,明确各个id可以提供的服务内容。例如:

#define LANE_CHANGE_SERVICE_ID                  0x301C
#define LANE_CHANGE_INSTANCE_ID                 0x0001

RR模式需要相应的method id,notification模式需要相应的event id和eventgroup id。这些需要写入头文件中,可以根据其服务模式为其命名。这些不需要写入配置文件中。例如:

#define LANE_CHANGE_EVENT_ID                    0x8001
#define LANE_CHANGE_EVENTGROUP_ID               0x0001
#define LANE_CHANGE_METHOD_ID                   0x0001

service.cpp程序

程序中的逻辑时序:
application初始化 —— app_->init()
application初始化状态 —— app_->register_state_handler
消息接收回调 —— app_->register_message_handler,为指定的method或event注册处理程序。用户应用程序必须调用此方法来为其注册回调。例如:

    app_->register_message_handler(
            LANE_CHANGE_SERVICE_ID,
            LANE_CHANGE_INSTANCE_ID,
            LANE_CHANGE_METHOD_ID,
            std::bind(&service_sample::on_get, this,
                      std::placeholders::_1));

这里的on_get函数就是自定义的接收到源消息后的处理操作。
注:每个服务(SERVICE)、实例(INSTANCE)、方法/事件(METHOD)组合只能注册一个处理程序。
提供事件源(服务端) —— app_->offer_event,参数列表填入提供事件的service id,instance id,event id和group id。例如:

std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(LANE_CHANGE_EVENTGROUP_ID);
app_->offer_event(
        LANE_CHANGE_SERVICE_ID,
        LANE_CHANGE_INSTANCE_ID,
        LANE_CHANGE_EVENT_ID,
        its_groups,
        vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
        false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);

切换线程到运行模式(run)
同时,app_->start。
提供服务源(服务端) —— app_->offer_service,参数列表填入需要offer的service id和instance id。例如:

app_->offer_service(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID);

然后就是设定stop_offer的触发条件,代码里是用时间控制的。
之后service就循环进行offer了,主要就是通过app_->register_message_handler注册的处理程序来对一些指定方法或事件(method id)进行响应(执行自定义操作)。

client端

配置信息

client端的配置文件不需要配置service id和端口这类信息,只需要配置好client端的app名字和id即可。在头文件内写入所需要的服务信息,用于request,一般和service端共享同一个头文件就可以。

client.cpp程序

程序中的逻辑时序:
application初始化 —— app_->init()
application初始化状态 —— app_->register_state_handler
消息接收回调 —— app_->register_message_handler
服务实例的可用状态 —— app_->register_availability_handler
请求事件并且订阅(客户端) —— app_->request_event,这里明确请求的信息,包括提供所需要事件源的service id,service instance,event id,以及group id。订阅信息包括所需事件源的service id,service instance,group id,因为是以事件组的方式订阅,例如:

std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(LANE_CHANGE_EVENTGROUP_ID);
app_->request_event(
        LANE_CHANGE_SERVICE_ID,
        LANE_CHANGE_INSTANCE_ID,
        LANE_CHANGE_EVENT_ID,
        its_groups,
        vsomeip::event_type_e::ET_FIELD);

订阅事件组(客户端) —— app_->subscibe,订阅信息包括所需事件源的service id,service instance,group id,因为是以事件组的方式订阅,例如:

app_->subscribe(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID, LANE_CHANGE_EVENTGROUP_ID);

之后app_->start。
如果之前app注册成功,则应该请求服务,需要包含请求服务的service id,service instance,例如:

app_->request_service(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID);

然后就是等待offer_service和offer_event,一旦接收到相应的消息,message和availability这两个回调函数会执行相应的自定义操作。