SomeIP/CommonAPI与Franca IDL使用教程(一)

回顾

SomeIP/CommonAPI环境搭建可以看我上一篇博客:Ubuntu环境下SomeIP/CommonAPI环境搭建详细步骤

什么是SomeIP

SOME/IP(Service-Oriented Middleware over IP)是一种基于IP网络的通信协议,旨在支持汽车电子系统和嵌入式系统之间的通信。它属于AUTOSAR(Automotive Open System Architecture)标准的一部分,被设计用于构建汽车电子领域的分布式系统。

SOME/IP 使用底层的 Socket(套接字)机制来进行通信。SOME/IP的消息是通过UDP或TCP协议传输的

什么是CommonAPI

CommonAPI 是一种用于实现分布式服务的通用框架,旨在促使不同模块或组件之间的通信更加容易。它是一种跨平台的通信框架,适用于嵌入式系统、汽车电子等领域。

我们可以将 CommonAPI 视为一种接口规范,CommonAPI 实际上包括两个层面的概念:

1、CommonAPI 接口规范(IDL): CommonAPI 提供了一种接口定义语言(IDL),用于描述服务接口的结构,包括服务的方法、属性、事件等。这种 IDL 类似于 FIDL(Franca Interface Definition Language),用于规范化描述接口。

2、CommonAPI 运行时环境: CommonAPI 还提供了一个运行时环境,负责实际的服务注册、发现、通信等功能。这个运行时环境是 CommonAPI 框架的核心部分,确保不同的组件可以协同工作,实现松耦合的通信。
在这里插入图片描述

• CommonAPI C++ is divided up in a middleware-independent part (CommonAPI Core) and in a middleware-specific part(CommonAPI Binding).

• CommonAPI uses the interface description language FrancaIDL for the specification of interfaces (logical interface specifica-tion). Code generation from FrancaIDL is an integrated part of CommonAPI.

• The code generator for CommonAPI C++ bindings needs middleware-specific parameters (deployment parameters). These
parameters are defined in Franca deployment files (*.fdepl).

在这里插入图片描述

SomeIP/CommonAPI?

我们可以这样理解:
CommonAPI是一套接口规范,通.fidl文件定义接口,使用CommonAPI Core Runtime代码生成工具来解析fidl文件获得接口文件即(.cpp和.hpp)

someIP是一个利用Socket(套接字)机制的协议库。

我们通过解析fidl文件获得接口文件,并没有IPC通讯功能,为了实现其IPC通讯,引入了fdepl部署文件。

fdepl根据.fidl中的接口,设置每个接口的网络服务ID、网络地址、端口号、通信协议等。然后通过CommonAPI SomeIP Runtime代码生成工具解析fdepl文件,生成可以通过someIP协议通信的接口文件(.cpp和.hpp)。

记要

本文参考sample:E02Attributes

接口的生成

CommonAPI其使用的接口语言为:Franca IDL 语言规范。

什么是Franca?

在这里插入图片描述

Franca 是一个用于定义和转换软件接口的框架。它用于集成来自不同供应商的基于各种运行时框架、平台和IPC(进程间通信)机制构建的软件组件。

在这里插入图片描述

Franca背景简述

接口是任何类型的软件架构中的重要工件。它们代表组件、子系统或系统之间以及组织单位(如团队、部门或公司)之间的合同。因此,在许多开发环境中,使用接口定义语言(简称:IDL)将接口建模为一流实体。然而,对于构建大型平台或系统,现有的IDL至少存在两个缺点:

1、为了集成来自不同来源的软件系统,有必要将一个 IDL 中定义的接口映射到使用另一个 IDL 的软件模型。例如,在国际 GENIVI 联盟中 ,正在通过集成各种开源项目、公司和机构提供的软件组件(如 GENIVI 本身)来开发汽车/信息娱乐系统平台。这些构建块的接口要么根本没有建模(例如,纯 C 或 C++ 标头),要么以几种方法之一正式建模,其中包括 UML、D-Bus Introspection XML、带注释的 Java API。模型级别上所有贡献的集成只能通过在所有这些 IDL 之间建立映射来完成。

2、大多数现有 IDL 方法的另一个常见缺点是接口动态建模缺乏正式性。大多数 IDL 提供了对接口的静态方面(例如,数据类型、信号、方法、属性)进行建模的方法,而不是动态方面(例如,接口上允许的事件序列),动态方面通常被视为可选的附加组件到静态接口定义。
然而,复杂软件系统中的许多严重错误是由接口动态方面的不匹配引起的。这些错误尤其会在项目后期阶段(系统集成期间甚至客户交付后)发生,难以识别且修复成本高昂。因此,动态方面有必要成为原始接口定义的一部分,从而允许对接口的实现和使用进行广泛的形式验证。这可以通过静态分析或在运行时完成。

为了解决这两个问题,GENIVI 启动了 Franca 项目,该项目可以作为 IDL 转换的中心,并允许将动态行为规范作为每个建模接口的组成部分。Franca 的一部分是技术和平台中立的 IDL。Franca 最初由Harman贡献 ,并于 2012 年 3 月在 EclipseLabs 上发布 (根据 Eclipse Public License 1.0)。

Franca目前的应用

Franca 自 2012 年 3 月起就是一个开源项目。因此,无法提供完整的应用程序列表。不过,我们将列出一些示例,以展示 Franca 社区的一部分:

1、GENIVI 联盟将 Franca 用作 IDL 和集成工具.

2、CommonAPI C++ 项目使用 Franca 模型作为所有代码生成器的起点。

3、Joynr基于 Web 的通信框架使用 Franca 作为 IDL 及其 Java 和 C++ 代码生成器的基础。开源 Joynr 框架支持部署在消费设备、车辆或后端基础设施上的应用程序的交互。

4、Yamaica 项目是一个 Eclipse IDE 扩展,为处理 Franca 模型提供了方便的 UI 。

5、多家公司(包括非汽车公司)正在使用或评估 Franca 作为其内部软件平台的 IDL。 <----说还是车企用的多hhhhhh

Franca IDL详细介绍可以参考以下链接:
FrancaGitHub:https://github.com/franca/franca
eclipse给出的说明:https://www.eclipse.org/proposals/modeling.franca/
Franca官方文档下载:download

fidl

.fidl文件

在这里插入图片描述

这是一个接口定义文件 (Franca Interface Definition Language) 的扩展,用于描述 CommonAPI 接口。它定义了服务接口相关的数据结构。这里使用E02Attributes例子中的fidl来解释。

E02Attributes.fidl

package commonapi.examplesinterface E02Attributes {version { major 1 minor 0 }attribute Int32 xattribute CommonTypes.a1Struct a1
}typeCollection CommonTypes {version { major 1 minor 0 }struct a1Struct {String sa2Struct a2}struct a2Struct {Int32 aBoolean bDouble d}
}
类别诠释
package组织和命名空间化接口定义的关键字
interface用于声明一个接口
version版本号,同命名空间有关,必须包含
attribute通常用于定义读取和写入的属性
typeCollection定义自定义的数据类型集合
struct类似C中的结构体

下面我们看一下fidl(Franca Interface Definition Language)的基本类型.

基本类型对应C++类型
UInt8uint8_t
Int8int8_t
UInt16uint16_t
Int16int16_t
UInt32uint32_t
Int32int32_t
UInt64uint64_t
Int64int64_t
Integer整数属性(这个我也没搞明白啥意思)
Booleanbool
Floatfloat
Doubledouble
Stringstd::string
ByteBufferstd::vector<uint8_t>

全部类型详细解释可参阅:Franca官方文档中5. Franca IDL Reference章节

上述我们已经大概对fidl有了基础的了解,下面我们详细解释一下:E02Attributes.fidl

package commonapi.examples

通俗点的说就是,我们定义的这些接口都在commonapi.examples命名空间下。
生成的C++结构如下:

namespace commonapi
{namespace examples{//接口代码在其中}
}
version { major 1 minor 0 }

使用version说明了这个接口版本主版本是1,次版本是0。生成的C++结构如下:

namespace V1
{namespace commonapi{namespace examples{//接口代码在其中}}}
interface E02Attributes {version { major 1 minor 0 }attribute Int32 xattribute CommonTypes.a1Struct a1
}

使用interface定义了一个接口E02Attributes,这个接口通过attribute修饰了两个属性,x和a1。attribute就表示我们可以通过set或get方法来设置和获取这两个属性

第一个属性:x的数据类型为Int32类型。

typeCollection CommonTypes {version { major 1 minor 0 }struct a1Struct {String sa2Struct a2}struct a2Struct {Int32 aBoolean bDouble d}
}

使用typeCollection定义了一个数据集合CommonTypes,这个集合里面有俩结构体。这就很简单明了和C/C++一样,就不赘述了。

第二个属性: a1类型为struct类型。

整个E02Attributes.fidl就表述完成了,那么这个.fidl文件主要做什么呢?

简单通俗的说就是定义了一个接口E02Attributes,这个接口有两个属性x和a1。我们可以通过接口生成的接口文件中的get方法或者set方法来获取/设置这俩属性。

上述对E02Attributes.fidl解释就完成了。下面我们使用Ubuntu环境下SomeIP/CommonAPI环境搭建详细步骤中下载的,CommonAPI Core Runtime代码生成工具 commonapi_core_generator解析fidl文件,生成接口文件。

./commonapi_core_generator/commonapi-core-generator-linux-x86_64 -sk ./fidl/E02Attributes.fidl

解析完成会在当前目录下生成src-gen文件夹。

./src-gen/
└── v1└── commonapi└── examples├── CommonTypes.hpp├── E02Attributes.hpp├── E02AttributesProxyBase.hpp├── E02AttributesProxy.hpp├── E02AttributesStubDefault.hpp└── E02AttributesStub.hpp3 directories, 6 files

生成后我们先放着,后面在说使用。下面我们要了解.fdepl文件

fdepl

.fdepl 文件

重述一下:fdepl 文件通常是 CommonAPI 的部署描述文件,用于配置和定义 CommonAPI 服务的运行时参数以及服务的部署信息。这个文件通常包含了与服务的实际运行有关的配置信息,例如服务的ID、网络地址、端口号、通信协议等。

下面我们看一下和E02Attributes.fidl适配的E02Attributes-SomeIP.fdepl文件。

E02Attributes-SomeIP.fdepl

import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl"
import "E02Attributes.fidl"define org.genivi.commonapi.someip.deployment for interface commonapi.examples.E02Attributes {SomeIpServiceID = 4660attribute x {SomeIpGetterID = 3000SomeIpSetterID = 3001SomeIpNotifierID = 33010SomeIpNotifierEventGroups = { 33010 }SomeIpAttributeReliable = true}attribute a1 {SomeIpGetterID = 3002SomeIpSetterID = 3003SomeIpNotifierID = 33011SomeIpNotifierEventGroups = { 33011 }SomeIpAttributeReliable = true}
}define org.genivi.commonapi.someip.deployment for typeCollection commonapi.examples.CommonTypes {struct a1Struct {}struct a2Struct {}}define org.genivi.commonapi.someip.deployment for provider as Service {instance commonapi.examples.E02Attributes {InstanceId = "commonapi.examples.Attributes"SomeIpInstanceID = 22136SomeIpUnicastAddress = "192.168.0.2"SomeIpReliableUnicastPort = 30499SomeIpUnreliableUnicastPort = 30500}
}

注意!!!!fdepl我也不是很熟悉,我尽力诠释

import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-4-SOMEIP_deployment_spec.fdepl"

第一行导入了 CommonAPI 中 SOME/IP 协议相关的一些规范。

import "E02Attributes.fidl"

导入了FIDL 文件,即 E02Attributes.fidl。

define org.genivi.commonapi.someip.deployment for interface commonapi.examples.E02Attributes
{}

定义了一个 CommonAPI SOME/IP 部署规范,针对接口 commonapi.examples.E02Attributes

SomeIpServiceID = 4660

定了服务的唯一标识符(Service ID),即 4660。在 SOME/IP 中,这是服务在网络中的唯一标识。

具体来说,SomeIpServiceID 是一个整数值,通常在范围 0x0001 到 0xFFFE 之间。每个服务都应该有一个不同的 ID,以确保在网络中不会发生冲突。这个 ID 会随着服务的注册而分配给服务,并在网络中广播,使得其他节点可以识别它。

    attribute x {SomeIpGetterID = 3000SomeIpSetterID = 3001SomeIpNotifierID = 33010SomeIpNotifierEventGroups = { 33010 }SomeIpAttributeReliable = true}

这部分配置是针对接口中的属性 x 的一些设置,特别是针对 SOME/IP 协议的相关设置。让我逐项解释:

SomeIpGetterID = 3000: 指定了属性 x 的 Getter 方法的 ID。当其他节点希望获取这个属性的值时,会使用这个 ID 进行请求。

SomeIpSetterID = 3001: 指定了属性 x 的 Setter 方法的 ID。当其他节点希望设置这个属性的值时,会使用这个 ID 进行请求。

SomeIpNotifierID = 33010: 指定了属性 x 的 Notifier(通知器)的 ID。通知器用于在属性值发生变化时通知其他节点。

SomeIpNotifierEventGroups = { 33010 }: 指定了 Notifier 所属的 Event Groups。Event Groups 用于在通知时进行分组,这里的设置表示 Notifier 属于 Event Group 33010。

SomeIpAttributeReliable = true: 表示对属性 x 进行通信时要求可靠性。这意味着在进行属性值的读取和写入时,要使用可靠的通信方式,以确保数据的正确传输。

这些设置确保了在 SOME/IP 协议中,对属性 x 的读取、写入和通知等操作有明确的标识和规范,以便其他节点能够正确地进行与该属性相关的通信。

注意:
Setter 操作: 当有节点调用 Setter 方法设置了属性 x 的新值时,如果设置成功,属性的值会更新。

Notifier 发送通知: 如果设置操作导致属性值发生变化,系统会使用指定的 Notifier ID 向订阅了该属性变化的其他节点发送通知。

Getter 操作: 在任何时候,其他节点都可以使用相应的 Getter 方法来获取属性 x 的当前值。这并不要求在属性值发生变化后才能获取,而是可以随时获取当前的属性值。

    attribute a1 {SomeIpGetterID = 3002SomeIpSetterID = 3003SomeIpNotifierID = 33011SomeIpNotifierEventGroups = { 33011 }SomeIpAttributeReliable = true}

属性a1解释同属性x

define org.genivi.commonapi.someip.deployment for typeCollection commonapi.examples.CommonTypes {struct a1Struct {}struct a2Struct {}}

这部分的配置是为类型集合 commonapi.examples.CommonTypes 中的结构体定义 SOME/IP 部署规范.

因为CommonTypes只是一个类型集合,不是一个方法。因此不需要设置ID等属性。

define org.genivi.commonapi.someip.deployment for provider as Service {instance commonapi.examples.E02Attributes {InstanceId = "commonapi.examples.Attributes"SomeIpInstanceID = 22136SomeIpUnicastAddress = "192.168.0.2"SomeIpReliableUnicastPort = 30499SomeIpUnreliableUnicastPort = 30500}
}

这部分我们依次解释

define org.genivi.commonapi.someip.deployment for provider as Service 
{}

这一行的配置指定了服务提供者的 SOME/IP 部署规范,为提供服务的实体进行了配置
provider as Service: 这表明接下来的配置是为服务提供者定义的,它将提供某项服务。

instance commonapi.examples.E02Attributes 
{}

instance commonapi.examples.E02Attributes: 这一行指定了服务提供者的服务实例,即服务的具体实现。在这里,服务实例的类型是 commonapi.examples.E02Attributes。

InstanceId = "commonapi.examples.Attributes"

InstanceId = “commonapi.examples.Attributes”: 指定了服务实例的唯一标识符,即实例ID。这是服务在网络中的唯一标识。

SomeIpInstanceID = 22136

SomeIpInstanceID = 22136: 指定了服务实例在 SOME/IP 协议中的唯一标识符,即实例的 SOME/IP 实例ID。在网络中,通过这个ID来唯一标识服务。

SomeIpUnicastAddress = "192.168.0.2"

SomeIpUnicastAddress = “192.168.0.2”: 指定了服务的网络地址,即服务提供者在网络中的 IP 地址。

SomeIpReliableUnicastPort = 30499

SomeIpReliableUnicastPort = 30499: 指定了服务提供者使用的可靠单播端口号。可靠单播用于确保通信的可靠性,即保证消息的完整传递。

SomeIpUnreliableUnicastPort = 30500

SomeIpUnreliableUnicastPort = 30500: 指定了服务提供者使用的不可靠单播端口号。不可靠单播通常用于一些对通信可靠性要求较低的情况。

这些配置项共同定义了服务提供者的运行时参数,包括服务实例的唯一标识、网络地址、端口号等信息。这些参数确保了服务能够在网络中被正确注册、定位和访问。

下面我们使用CommonAPI SomeIP Runtime代码生成工具解析E02Attributes-SomeIP.fdepl文件。

./commonapi_someip_generator/commonapi-someip-generator-linux-x86_64 -ll verbose ./fidl/E02Attributes-SomeIP.fdepl

解析完成会在当前目录下生成如下接口文件

./src-gen/
└── v1└── commonapi└── examples├── CommonTypesSomeIPDeployment.cpp├── CommonTypesSomeIPDeployment.hpp├── E02AttributesSomeIPCatalog.json├── E02AttributesSomeIPDeployment.cpp├── E02AttributesSomeIPDeployment.hpp├── E02AttributesSomeIPProxy.cpp├── E02AttributesSomeIPProxy.hpp├── E02AttributesSomeIPStubAdapter.cpp└── E02AttributesSomeIPStubAdapter.hpp3 directories, 9 files

接口文件分析

我们解析完fidl文件和fdepl文件后当前目录下的src-gen目录中文件结构如下

./src-gen/
└── v1└── commonapi└── examples├── CommonTypes.hpp├── CommonTypesSomeIPDeployment.cpp├── CommonTypesSomeIPDeployment.hpp├── E02Attributes.hpp├── E02AttributesProxyBase.hpp├── E02AttributesProxy.hpp├── E02AttributesSomeIPCatalog.json├── E02AttributesSomeIPDeployment.cpp├── E02AttributesSomeIPDeployment.hpp├── E02AttributesSomeIPProxy.cpp├── E02AttributesSomeIPProxy.hpp├── E02AttributesSomeIPStubAdapter.cpp├── E02AttributesSomeIPStubAdapter.hpp├── E02AttributesStubDefault.hpp└── E02AttributesStub.hpp3 directories, 15 files

*.fdepl文件生成的粘合代码,凡是带有SomeIP的一般都是我们不需要动的,直接放到项目里面参与编译即可。


├── CommonTypes.hpp   类型集合接口类,不需要动用于客户端开发:代理是一个提供方法调用的类,
该方法调用将导致对服务的远程方法调用,以及服务可以广播的事件的注册方法。
├── E02Attributes.hpp
├── E02AttributesProxyBase.hpp
├── E02AttributesProxy.hpp服务器开发:存根是服务的一部分,当来自客户端的远程方法调用到达时,
存根将被调用,它还包含将事件(广播)激发到几个或所有客户端的方法。├── E02AttributesStubDefault.hpp
└── E02AttributesStub.hpp

阅读接口我们可以发现E02Attributes和E02AttributesProxyBase是E02AttributesProxy的父类
E02AttributesStub是E02AttributesStubDefault的父类。这样我们是不是可以认为有以下关系。

服务器端:以xxxxStubDefault为父类,重写接口
客户端 :以xxxProxy为父类,重写接口。

代码演示

服务端
E02AttributesStubImpl.h

#ifndef E02ATTRIBUTESSTUBIMPL_HPP_
#define E02ATTRIBUTESSTUBIMPL_HPP_#include <CommonAPI/CommonAPI.hpp>
#include <v1/commonapi/examples/E02AttributesStubDefault.hpp>class E02AttributesStubImpl: public v1_0::commonapi::examples::E02AttributesStubDefault {public:E02AttributesStubImpl();virtual ~E02AttributesStubImpl();virtual void incCounter();private:int cnt;
};#endif // E02ATTRIBUTESSTUBIMPL_HPP_

E02AttributesStubImpl.cpp

#include "E02AttributesStubImpl.hpp"E02AttributesStubImpl::E02AttributesStubImpl() {cnt = 0;
}E02AttributesStubImpl::~E02AttributesStubImpl() {
}void E02AttributesStubImpl::incCounter() {cnt++;setXAttribute((int32_t)cnt);std::cout <<  "New counter value = " << cnt << "!" << std::endl;
}

可以看到sample重写了E02AttributesStubDefault类,封装了incCounter函数来更改属性X的数值。

E02AttributesService.cpp

#include <thread>
#include <iostream>#include <CommonAPI/CommonAPI.hpp>
#include "E02AttributesStubImpl.hpp"int main() {CommonAPI::Runtime::setProperty("LogContext", "E02S");CommonAPI::Runtime::setProperty("LogApplication", "E02S");CommonAPI::Runtime::setProperty("LibraryBase", "E02Attributes");std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();std::string domain = "local";std::string instance = "commonapi.examples.Attributes";std::string connection = "service-sample";std::shared_ptr<E02AttributesStubImpl> myService = std::make_shared<E02AttributesStubImpl>();while (!runtime->registerService(domain, instance, myService, connection)) {std::cout << "Register Service failed, trying again in 100 milliseconds..." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cout << "Successfully Registered Service!" << std::endl;while (true) {myService->incCounter(); // Change value of attribute, see stub implementationstd::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));}return 0;
}

服务端写的比较简单,首先获取运行环境

std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();

然后注册service

    std::string domain = "local";std::string instance = "commonapi.examples.Attributes";std::string connection = "service-sample";std::shared_ptr<E02AttributesStubImpl> myService = std::make_shared<E02AttributesStubImpl>();while (!runtime->registerService(domain, instance, myService, connection)) {std::cout << "Register Service failed, trying again in 100 milliseconds..." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cout << "Successfully Registered Service!" << std::endl;

然后循环设置属性X的数值

    while (true) {myService->incCounter(); // Change value of attribute, see stub implementationstd::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));}

官方sample写的太抽象了,我们精简一下。我对服务端做了如下修改
E02AttributesStubImpl.cpp

#include "E02AttributesStubImpl.hpp"E02AttributesStubImpl::E02AttributesStubImpl() {cnt = 0;
}E02AttributesStubImpl::~E02AttributesStubImpl() {
}void E02AttributesStubImpl::incCounter() {cnt++;setXAttribute((int32_t)cnt);std::cout <<  "server set X : New counter value = " << cnt << "!" << std::endl;std::string s_string = getA1Attribute().getS();std::cout<<" Rev S val = " << s_string << std::endl;}

E02AttributesService.cpp 修改如下

#include <thread>
#include <iostream>#include <CommonAPI/CommonAPI.hpp>
#include "E02AttributesStubImpl.hpp"
#include "v1/commonapi/examples/CommonTypes.hpp"int main() {CommonAPI::Runtime::setProperty("LogContext", "E02S");CommonAPI::Runtime::setProperty("LogApplication", "E02S");CommonAPI::Runtime::setProperty("LibraryBase", "E02Attributes");std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();std::string domain = "local";std::string instance = "commonapi.examples.Attributes";std::string connection = "service-sample";std::shared_ptr<E02AttributesStubImpl> myService = std::make_shared<E02AttributesStubImpl>();while (!runtime->registerService(domain, instance, myService, connection)) {std::cout << "Register Service failed, trying again in 100 milliseconds..." << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cout << "Successfully Registered Service!" << std::endl;v1::commonapi::examples::CommonTypes::a1Struct valueStruct;valueStruct.setS("abc");v1::commonapi::examples::CommonTypes::a2Struct a2Struct = valueStruct.getA2();a2Struct.setA(123);a2Struct.setB(true);a2Struct.setD(1234);valueStruct.setA2(a2Struct);int i = 0;while (true) {i++;myService->incCounter();if(i==10){myService->setA1Attribute(valueStruct);}std::this_thread::sleep_for(std::chrono::seconds(2));}return 0;
}

客户端
E02AttributesClient.cpp

#include <iostream>
#include <thread>#ifndef _WIN32
#include <unistd.h>
#endif#include <CommonAPI/CommonAPI.hpp>
#include <CommonAPI/AttributeCacheExtension.hpp>
#include <v1/commonapi/examples/E02AttributesProxy.hpp>using namespace v1::commonapi::examples;int main() {CommonAPI::Runtime::setProperty("LogContext", "E02C");CommonAPI::Runtime::setProperty("LogApplication", "E02C");CommonAPI::Runtime::setProperty("LibraryBase", "E02Attributes");std::shared_ptr < CommonAPI::Runtime > runtime = CommonAPI::Runtime::get();std::string domain = "local";std::string instance = "commonapi.examples.Attributes"; std::string connection = "client-sample";//auto myProxy = runtime->buildProxyWithDefaultAttributeExtension<E02AttributesProxy, CommonAPI::Extensions::AttributeCacheExtension>(domain, instance, connection);auto myProxy = runtime->buildProxy<E02AttributesProxy>(domain,instance,connection);std::cout << "Waiting for service to become available." << std::endl;while (!myProxy->isAvailable()){std::this_thread::sleep_for(std::chrono::microseconds(10));}// Subscribe for receiving valuesmyProxy->getXAttribute().getChangedEvent().subscribe([&](const int32_t& val){std::cout << "Received change message: " << val << std::endl;});myProxy->getA1Attribute().getChangedEvent().subscribe([&](const CommonTypes::a1Struct& val){std::cout << "Received change message for A1" << std::endl;std::cout << "a1Struct.s = " << val.getS()<<std::endl;std::cout << "a1Struct.a1.a2.a = " << val.getA2().getA()<<std::endl;std::cout << "a1Struct.a1.a2.b = " << val.getA2().getB()<<std::endl;std::cout << "a1Struct.a1.a2.d = " << val.getA2().getD()<<std::endl;});while (true){std::this_thread::sleep_for(std::chrono::microseconds(1000000));}
}

这就不需要解释了,对照着service分析,客户端就 “见码知意” 了。

如果想要在client端修改属性可参考下面代码

    // Asynchronous call to set attribute of servicestd::function<void(const CommonAPI::CallStatus&, int32_t)> fcb = recv_cb;myProxy->getXAttribute().setValueAsync(value, fcb, &info);// Asynchronous call to set attribute of type structure in serviceCommonTypes::a1Struct valueStruct;valueStruct.setS("abc");CommonTypes::a2Struct a2Struct = valueStruct.getA2();a2Struct.setA(123);a2Struct.setB(true);a2Struct.setD(1234);valueStruct.setA2(a2Struct);std::function<void(const CommonAPI::CallStatus&, CommonTypes::a1Struct)> fcb_s = recv_cb_s;myProxy->getA1Attribute().setValueAsync(valueStruct, fcb_s, &info);

运行

service刚启动时
在这里插入图片描述
client刚启动时
在这里插入图片描述
service启动10s后
在这里插入图片描述
client启10s后
在这里插入图片描述

结语

SomeIP/CommonAPI这个系列我会坚持更下去,本文只粗浅的使用了一下,更多内容后续会出教程(二)

如需要源码资料可联系QQ:918619587

如有错误,感谢指正。

!!!!禁止转载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/593339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WSL 与真实 linux 环境区别有多大?

随着 Windows 系统的不断发展和完善&#xff0c;WSL&#xff08;Windows Subsystem for Linux&#xff09;作为 Windows 10 的一个功能&#xff0c;为 Windows 用户提供了一个可以在 Windows 环境下运行 Linux 二进制可执行文件的环境。然而&#xff0c;尽管 WSL 为用户提供了一…

海外SaaS应用加速难题如何破解?

随着云计算和软件即服务&#xff08;SaaS&#xff09;的发展&#xff0c;海外SaaS软件展现的优势逐渐体现&#xff0c;越来越多企业开始利用其进行降本增效。但是&#xff0c;海外SaaS软件的使用过程中常有问题出现&#xff0c;下文将介绍这些难题以及如何进行海外SaaS应用加速…

Java项目:107SpringBoot房屋租赁网站

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 房屋租赁网站基于SpringBootMybatis开发&#xff0c;系统分为管理员和普通用户两种角色。 管理员功能如下&#xff1a; 登录修改密码查看用户房屋管理图…

图像的腐蚀与膨胀

图像的腐蚀与膨胀 设集合 B B B的反射为 B ^ \hat{B} B^&#xff0c;其定义如下 B ^ { w ∣ w − b , b ∈ B } \hat{B}\begin{Bmatrix}w|w-b,b\in B\end{Bmatrix} B^{w∣w−b,b∈B​} 设集合 B B B按照点 z ( z 1 , z 2 ) z(z_1,z_2) z(z1​,z2​)平移得到集合 ( B ) z (…

数据结构学习 jz46把数字翻译成字符串

关键词&#xff1a;动态规划 字符串 数组 滚动数组优化 这道题还算简单&#xff0c;调滚动数组废了点时间&#xff0c;dp状态和转移方程比较容易推出。 用时28mins。 题目&#xff1a; 思路&#xff1a; 把ciphertext拆成一个一个数字的方法&#xff1a; 求10的余数得到最…

AI边缘计算智能分析网关V4如何配置周界入侵检测算法

旭帆科技的智能分析网关V4内含近40种智能分析算法&#xff0c;包括人体、车辆、消防、环境卫生、异常检测等等&#xff0c;在消防安全、生产安全、行为检测等场景应用十分广泛&#xff0c;如常见的智慧工地、智慧校园、智慧景区、智慧城管等等&#xff0c;还支持抓拍、记录、告…

一个人去广东怎么找工作

广东这么大&#xff0c;不用怕没有学历活不下去。没有学历想好好活下去&#xff0c;就得卖力气。 广东找工作上 吉鹿力招聘网 打开 吉鹿力招聘网 “注册账号”&#xff0c;然后输入个人基本信息&#xff0c;进行注册&#xff08;可使用手机号注册&#xff0c;也可以使用邮箱注…

stable diffusion 基础教程-提示词之光的用法

基图 prompt: masterpiece,best quality,1girl,solo,looking at viewer,brown hair,hair between eyes,bangs,very long hair,red eyes,blush,bare shoulders,(white sundress),full body,leaning forward,medium breasts,unbuttoned clothes,Negative prompt: EasyNegativ…

【MPC学习笔记】02:MPC详细简介(Lecture 1_1 Unconstrained MPC)

本笔记来自北航诸兵老师的课程 课程地址&#xff1a;模型预测控制&#xff08;2022春&#xff09;lecture 1-1 Unconstrained MPC 接上一篇&#xff1a;【MPC学习笔记】01&#xff1a;MPC简介&#xff08;Lecture 1_1 Unconstrained MPC&#xff09; 文章目录 1 详细介绍1.1 状…

用python实现调用海康SDK

海康威视&#xff08;Hikvision&#xff09;提供了Python SDK&#xff0c;用于与他们的摄像头和其他设备进行交互。为了使用这些SDK&#xff0c;首先需要在你的系统上安装海康威视的Python库。 下面是如何在Python中使用海康威视的SDK来调用摄像头的方法&#xff1a; python复…

BUUCTF——Reverse——Java逆向解密

1、题目 2、工具 jd-gui&#xff1a;Java反汇编器。 ​python&#xff1a;编写自动化脚本。 3、方法 下载压缩包&#xff0c;解压得到一个.class文件。 ​题目已经说了是java逆向&#xff0c;所以使用jd-gui打开该文件。 代码如下&#xff1a; import java.io.PrintStream; …

大模型笔记 【1】 大模型初探

以下是Andrej Karpathy一小时讲解chatgpt的笔记。 Andrej Karpathy做自动驾驶的人应该比较熟悉&#xff0c;他是李飞飞的学生。在openAI做了一年半的科学家之后&#xff0c;去了特斯拉。在Tesla AI day讲解tesla自动驾驶方案的就是他。 这里我的主要收获是两个 大模型是一个有…

王道考研计算机组成原理——数据的表示和运算

数制转换 任意进制》十进制&#xff1a;位权*位数即可 整数部分补0是补在头部&#xff0c;小数部分补0是补在尾部 一般都是先把十进制》二进制&#xff1b;然后二进制再转换成8/16进制这样子 一种更快的方法->拼凑法&#xff1a;小数部分整数部分都可以这样求 一般都是先…

挑战Python100题(9)

100+ Python challenging programming exercises 9 Question 81 Please write a program to randomly print a integer number between 7 and 15 inclusive. Hints: Use random.randrange() to a random integer in a given range. 请编写一个程序,随机打印一个介于7和15之间…

Single-Image Crowd Counting via Multi-Column Convolutional Neural Network

Single-Image Crowd Counting via Multi-Column Convolutional Neural Network 论文背景人群密度方法过去的发展历史早期方法基于轨迹聚类的方法基于特征回归的方法基于图像的方法 Multi-column CNN用于人群计数基于密度图的人群计数通过几何自适应核生成密度图密度图估计的多列…

【论文+在线运行】AnyText:能准确写汉字的AI绘图工具

源码&#xff1a;https://github.com/tyxsspa/AnyText 阿里在线运行: https://modelscope.cn/studios/damo/studio_anytext/summary 论文&#xff1a;2311.AnyText: Multilingual Visual Text Generation And Editing 一、AnyTexT是什么&#xff1f; 是一个基于扩散模型的&am…

ATE自动测试设备是什么?如何帮助测试电源反复短路?

什么是电源反复短路测试? 反复短路测试是电源极限测试项目之一&#xff0c;是在各种输入和输出状态下将电源输出短路&#xff0c;反复多次短路测试&#xff0c;检测电源是否可以实现保护或回缩&#xff0c;测试结束后之后&#xff0c;电源是否可以自动恢复正常运行。反复短路测…

Java原生启动Tomcat

文章目录 引入依赖启动Tomcat代码示例将嵌入式 Tomcat 服务器用于已有的 WAR 文件为现有的 Java Web 应用程序嵌入 Tomcat 服务器 相关APITomcat APIContonxt API 启动错误springboot底层Tomcat的实现学习博客 引入依赖 maven: <dependency><groupId>org.apache.…

python 深度学习 记录遇到的报错问题10

本篇继python 深度学习 解决遇到的报错问题9_module d2l.torch has no attribute train_ch3-CSDN博客 一、CUDA error: no kernel image is available for execution on the device CUDA kernel errors might be asynchronously reported at some other API call,so the stackt…

数据结构【图篇】

数据结构【图篇】 文章目录 数据结构【图篇】前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f; 目录一、图(一)、图的存储(二)、图的基本操作(三)、最短路径问题 二、拓扑排序三、结语 前言 为什么突然想学算法了&#xff1f; > 用较为“官方…