参考 (https://github.com/COVESA/vsomeip/wiki/vsomeip-in-10-minutes#prep) (http://www.voycn.com/article/guanyusomeipdelijie)
简介
someip是位于七层网络协议的会话层,其是车载以太网引入的一个协议.与CAN相比,其只有在接收方有需求时,server端才会给client发送消息,因此会减少总线上的负载率. 服务是SOME/IP的最核心概念。在一个服务中,定义了Server和Client两个角色:Server提供服务,Client调用服务。对于同一个服务,只能存在一个Server,但可以同时存在多个Client调用服务。server就是一个提供一组method/event/field的接口
- Method
其包含两种: 带response(request/response)(Request/Response methods allow calls with answers.) 不带response (fire&forget)(Fire&Forgetmethods do not have answer messages.)
-
event 是server向client发送的单向消息,其是server主动向订阅了相关event的client发送的消息.(Events are simple messages from Server to Client.) -
field 其包含3部分: Getter : Request/Response Setter: Request/Response Notifier : Events 上面两种方式的组合,field可以被订阅,用于消息通知,还具有set和get的功能,对消息进行读写操作.(Fields are properties that may include a Getter, a Setter, and a Notification.)
Server端
1. 配置文件(vsomeip.json)(/system/etc)
{
"unicast" : "本机的ip",
"logging" : {
"level" : "trace",
"console" : "true",
"file" : {
"enable" : "false"
},
"dlt" : "false"
},
"applications" : [
{
"name" : "World",
"id" : "0x3489"
}
],
"services" : [
{
"service" : "0x1234",
"instance" : "0x5678",
"reliable" : {
"port" : "40001",
"enable-magic-cookies" : "false"
},
"events" : [
{
"event" : "9001",
"is_field" : "true",
"update-cycle" : 2000
},
{
"event" : "9002",
"is_field" : "true",
"update-cycle" : 2000
}
],
"eventgroups" : [
{
"eventgroup" : "0x5555",
"events" : [
"9001",
"9002"
]
}
]
}
],
"routing" : "vsomeipd",
"service-discovery" : {
"enable" : "true",
"mode" : "unicast",
"unicast" : [
"要通信的ip1","要通信的ip2"
],
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"cyclic_offer_delay":"10000",
"request_response_delay":"1500"
}
}
2. 代码
其主要代码: 1)创建application(world)(vsomeip::runtime::get()->create_application(“World”)),并进行初始化()(app->init()) 2)为特定的service,instance,method/event的消息注册callback(app->register_message_handler()) 3)向路由注册application(world)提供的service(app->offer_service()),为了让其他的application可以发现该service.注:为了向外部网络提供服务,配置必须包含提供的服务实例的端口。如果没有提供这样的端口配置,服务在设备外部是不可见的. 4)向路由注册application(world)提供的event(app->offer_event()),允许其他application订阅event/field,以及获取和设置field值。 5)启动消息处理(app->start()),它将阻塞,直到使用stop方法或通过接收信号终止消息处理。它处理通过套接字接收到的消息,并使用注册的回调函数将它们传递给用户应用程序。
#include <condition_variable>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x07
#define SAMPLE_EVENTGROUP_ID 0x5555
#define SAMPLE_EVENT_ID 9001
std::shared_ptr<vsomeip::application> app;
std::mutex mutex;
std::condition_variable condition;
void on_filed_message(const std::shared_ptr<vsomeip::message>& _request) {
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
std::cout << "SERVICE:Received filed message: " << std::hex << _request->get_method()
<< ". client: " << std::hex << _request->get_client() << ". data: " << std::hex
<< its_payload->get_data() << std::endl;
std::shared_ptr<vsomeip::message> its_response =
vsomeip::runtime::get()->create_response(_request);
its_payload = vsomeip::runtime::get()->create_payload();
const vsomeip::byte_t its_data[] = {0x11};
its_payload = vsomeip::runtime::get()->create_payload();
its_payload->set_data(its_data, sizeof(its_data));
its_response->set_payload(its_payload);
app->send(its_response, true);
}
void on_message(const std::shared_ptr<vsomeip::message>& _request) {
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
vsomeip::length_t l = its_payload->get_length();
std::stringstream ss;
for (vsomeip::length_t i = 0; i < l; i++) {
ss << std::setw(2) << std::setfill('0') << std::hex << (int)*(its_payload->get_data() + i)
<< " ";
}
std::cout << "SERVICE: Received message with Client/Session [" << std::setw(4)
<< std::setfill('0') << std::hex << _request->get_client() << "/" << std::setw(4)
<< std::setfill('0') << std::hex << _request->get_session() << "] " << ss.str()
<< std::endl;
std::shared_ptr<vsomeip::message> its_response =
vsomeip::runtime::get()->create_response(_request);
its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (int i = 9; i >= 0; i--) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
its_response->set_payload(its_payload);
app->send(its_response, true);
const vsomeip::byte_t its_data[] = {0x10};
its_payload = vsomeip::runtime::get()->create_payload();
its_payload->set_data(its_data, sizeof(its_data));
app->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, its_payload);
std::cout << "service: notify over!!" << std::endl;
}
int main() {
app = vsomeip::runtime::get()->create_application("World");
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(SAMPLE_EVENTGROUP_ID);
app->init();
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID,
on_message);
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID,
on_filed_message);
app->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->offer_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, its_groups, true);
app->offer_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID + 1, its_groups, true);
app->start();
}
Client端
1. 配置文件(vsomeip.json)(/system/etc)
{
"unicast":"本机的ip",
"logging":{
"level":"trace",
"console":"true",
"file":{
"enable":"false"
},
"dlt":"false"
},
"performance-measurement": {
"enable":"true",
"client":"true",
"server":"false",
"interval":60
},
"applications" : [
{
"name" : "Hello",
"id" : "0x1210"
}
],
"services" :
[
{
"service" : "0x7788",
"instance" : "0x98",
"reliable" : {
"port" : "40004",
"enable-magic-cookies" : "true"
},
"events" : [
{
"event" : "90",
"is_field" : "true"
},
{
"event" : "91",
"is_field" : "true"
}
],
"eventgroups" : [
{
"eventgroup" : "0x333",
"events" : [
"90",
"91"
]
}
]
}
],
"routing" : "vsomeipd",
"service-discovery" : {
"enable" : "true",
"mode" : "unicast",
"unicast" : [
"要通信的ip1","要通信的ip2"
],
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"cyclic_offer_delay":"10000",
"request_response_delay":"1500"
}
}
2. 代码
其主要代码: 1)创建application(world)(vsomeip::runtime::get()->create_application(“Hello”)),并进行初始化()(app->init()) 2)向路由中注册一个监听application(world)状态的callback (app->register_state_handler()).当其反馈在路由中注册成功后,去请求service(app->request_service()) 3)注册一个要请求的service的状态的监听,当service出现或消失时会被调用(app->register_availability_handler()),当其反馈service可用时,可以创建request( vsomeip::runtime::get()->create_request(true))向service发送消息(app->send()),和向service注册某些event(app->request_event())的监听(app->subscribe()) 4)为特定的service,instance,method/event的消息注册callback(app->register_message_handler()) 5)开启一个发送消息的线程(std::thread sender(run)) 6)启动消息处理(app->start())
#include <condition_variable>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x07
#define SAMPLE_EVENTGROUP_ID 0x5555
#define SAMPLE_EVENT_ID 9001
std::shared_ptr<vsomeip::application> app;
std::mutex mutex;
std::condition_variable condition;
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
condition.wait(its_lock);
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(SAMPLE_EVENTGROUP_ID);
app->request_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, its_groups, true);
app->request_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID + 1, its_groups, true);
app->subscribe(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENTGROUP_ID);
std::shared_ptr<vsomeip::message> request;
request = vsomeip::runtime::get()->create_request(true);
request->set_service(SAMPLE_SERVICE_ID);
request->set_instance(SAMPLE_INSTANCE_ID);
request->set_method(SAMPLE_METHOD_ID);
std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (vsomeip::byte_t i = 0; i < 10; i++) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
request->set_payload(its_payload);
app->send(request, true);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
std::shared_ptr<vsomeip::message> request_filed;
request_filed = vsomeip::runtime::get()->create_request(true);
request_filed->set_service(SAMPLE_SERVICE_ID);
request_filed->set_instance(SAMPLE_INSTANCE_ID);
request_filed->set_method(SAMPLE_EVENT_ID);
std::shared_ptr<vsomeip::payload> filed_payload = vsomeip::runtime::get()->create_payload();
const vsomeip::byte_t its_data[] = {0x12};
filed_payload->set_data(its_data, sizeof(its_data));
request_filed->set_payload(filed_payload);
app->send(request_filed, true);
}
void on_message(const std::shared_ptr<vsomeip::message>& _response) {
std::stringstream its_message;
its_message << "CLIENT: received a notification for event [" << std::setw(4)
<< std::setfill('0') << std::hex << _response->get_service() << "." << std::setw(4)
<< std::setfill('0') << std::hex << _response->get_instance() << "." << std::setw(4)
<< std::setfill('0') << std::hex << _response->get_method()
<< "message_type: " << std::hex << static_cast<int>(_response->get_message_type())
<< "] to Client/Session [" << std::setw(4) << std::setfill('0') << std::hex
<< _response->get_client() << "/" << std::setw(4) << std::setfill('0') << std::hex
<< _response->get_session() << "] = ";
std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
its_message << "(" << std::dec << its_payload->get_length() << ") ";
for (uint32_t i = 0; i < its_payload->get_length(); ++i)
its_message << std::hex << std::setw(2) << std::setfill('0')
<< (int)its_payload->get_data()[i] << " ";
std::cout << its_message.str() << std::endl;
}
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance,
bool _is_available) {
std::cout << "CLIENT: Service [" << std::setw(4) << std::setfill('0') << std::hex << _service
<< "." << _instance << "] is " << (_is_available ? "available." : "NOT available.")
<< std::endl;
if (_is_available) {
condition.notify_one();
}
}
void on_state_cbk(vsomeip::state_type_e _state) {
std::cout << "on_state_cbk, state: " << static_cast<int>(_state) << std::endl;
if (_state == vsomeip::state_type_e::ST_REGISTERED) {
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
}
}
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(SLAVE_EVENTGROUP_ID);
app->init();
app->register_state_handler(on_state_cbk);
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->register_message_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
on_message);
std::thread sender(run);
app->start();
}
android.mk
将上述两个代码编译成bin文件,push进设备中执行
cc_binary {
name: "someipservice_test",
proprietary: true,
srcs: [
"someip_test_service.cpp",
],
include_dirs: [
"external/v_SomeIP/vsomeip/arm64/include",
"external/v_SomeIP/boost/arm64/include",
],
shared_libs: [
"libbase",
"libvsomeip",
],
cflags: [
"-Wall",
"-Wno-unused-parameter",
"-Werror",
"-Wunused-variable",
"-Wno-unused-variable",
"-Wformat",
"-Wc++11-narrowing",
],
}
cc_binary {
name: "someipclient_test",
proprietary: true,
srcs: [
"someip_test_client.cpp",
],
include_dirs: [
"external/v_SomeIP/vsomeip/arm64/include",
"external/v_SomeIP/boost/arm64/include",
],
shared_libs: [
"libbase",
"libvsomeip",
],
cflags: [
"-Wall",
"-Wno-unused-parameter",
"-Werror",
"-Wunused-variable",
"-Wno-unused-variable",
"-Wformat",
"-Wc++11-narrowing",
],
}
|