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详细介绍可以参考以下链接:
Franca的GitHub: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.examples
interface E02Attributes {
version { major 1 minor 0 }
attribute Int32 x
attribute CommonTypes.a1Struct a1
}
typeCollection CommonTypes {
version { major 1 minor 0 }
struct a1Struct {
String s
a2Struct a2
}
struct a2Struct {
Int32 a
Boolean b
Double d
}
}
类别 | 诠释 |
---|---|
package | 组织和命名空间化接口定义的关键字 |
interface | 用于声明一个接口 |
version | 版本号,同命名空间有关,必须包含 |
attribute | 通常用于定义读取和写入的属性 |
typeCollection | 定义自定义的数据类型集合 |
struct | 类似C中的结构体 |
下面我们看一下fidl(Franca Interface Definition Language
)的基本类型.
基本类型 | 对应C++类型 |
---|---|
UInt8 | uint8_t |
Int8 | int8_t |
UInt16 | uint16_t |
Int16 | int16_t |
UInt32 | uint32_t |
Int32 | int32_t |
UInt64 | uint64_t |
Int64 | int64_t |
Integer | 整数属性(这个我也没搞明白啥意思) |
Boolean | bool |
Float | float |
Double | double |
String | std::string |
ByteBuffer | std::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 x
attribute CommonTypes.a1Struct a1
}
使用interface定义了一个接口E02Attributes,这个接口通过attribute修饰了两个属性,x和a1。attribute就表示我们可以通过set或get方法来设置和获取这两个属性
。
第一个属性
:x的数据类型为Int32类型。
typeCollection CommonTypes {
version { major 1 minor 0 }
struct a1Struct {
String s
a2Struct a2
}
struct a2Struct {
Int32 a
Boolean b
Double 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.hpp
3 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 = 4660
attribute x {
SomeIpGetterID = 3000
SomeIpSetterID = 3001
SomeIpNotifierID = 33010
SomeIpNotifierEventGroups = { 33010 }
SomeIpAttributeReliable = true
}
attribute a1 {
SomeIpGetterID = 3002
SomeIpSetterID = 3003
SomeIpNotifierID = 33011
SomeIpNotifierEventGroups = { 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 = 22136
SomeIpUnicastAddress = "192.168.0.2"
SomeIpReliableUnicastPort = 30499
SomeIpUnreliableUnicastPort = 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 = 3000
SomeIpSetterID = 3001
SomeIpNotifierID = 33010
SomeIpNotifierEventGroups = { 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 = 3002
SomeIpSetterID = 3003
SomeIpNotifierID = 33011
SomeIpNotifierEventGroups = { 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 = 22136
SomeIpUnicastAddress = "192.168.0.2"
SomeIpReliableUnicastPort = 30499
SomeIpUnreliableUnicastPort = 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.hpp
3 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.hpp
3 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 implementation
std::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 implementation
std::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 values
myProxy->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 service
std::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 service
CommonTypes::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
如有错误,感谢指正。
!!!!禁止转载
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!