package commonapi.mthd
interface Methods {
version {major 1 minor 0}
attribute Int32 x
method foo {
in {
Int32 x1
String x2
}
out {
Int32 y1
String y2
}
error {
stdErrorTypeEnum
}
}
method newFoo fireAndForget {
in {
String MessageName
}
}
enumeration stdErrorTypeEnum {
NO_FAULT
MY_FAULT
}
broadcast myStatus {
out {
Int32 myCurrentValue
}
}
broadcast statusSpecial selective {
out {
Int32 NewCurrentValue
}
}
}
执行代码生成器的可执行文件,根据Method.fidl文件生成CommonAPI级别的接口代码:
编译命令 :
./cgen/commonapi-generator/commonapi-generator-linux-x86_86 -sk ./fidl/Method.fidl
编译生成的接口代码:
Methods.hpp
MethodsProxyBase.hpp
MethodsProxy.hpp
MethodsStub.hpp
MethodsStubDefault.hpp
MethodsStubDefault.cpp
import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-SOMEIP_deployment_spec.fdepl"
import "Method.fidl"
define org.genivi.commonapi.someip.deployment for interface commonapi.mthd.Method {
SomeIpServiceID = 4660
attribute x {
SomeIpGetterID = 3000
SomeIpSetterID = 3001
SomeIpNotifierID = 33010
SomeIpEventGroups = { 33010 }
}
method foo {
SomeIpMethodID = 30000
SomeIpReliable = false
in {
x2 {
SomeIpStringEncoding = utf16le
}
}
out {
y2 {
SomeIpStringEncoding =utf16le
}
}
}
method newFoo {
SomeIpMethodID = 30001
SomeIpReliable = false
in {
x2 {
SomeIpStringEncoding = utf16le
}
}
}
broadcast myStatus {
SomeIpEventID = 33020
SomeIpEventGroups = { 33020 }
}
broadcast statusSpecial {
SomeIpEventID = 33030
SomeIpEventGroups = { 33030 }
}
enumeration stdErrorTypeEnum {
NO_FAULT {
}
MY_FAULT {
}
}
}
define org.genivi.commonapi.someip.deployment for provider MyService {
instance commonapi.mthd.Method {
InstanceId = "commonapi.mthd.Method"
SomeIpInstanceID = 22136
SomeIpUnicastAddress = "192.168.0.2"
SomeIpReliableUnicastPort = 30500
SomeIpUnreliableUnicastPort = 30501
}
}
执行代码生成器的可执行文件,根据Method.fdepl文件生成所需的粘合代码。
编译命令 :
./cgen/commonapi_someip_generator/commonapi-someip-generator-linux-x86_64 -ll verbose ./fidl/Method.fdepl
编译生成的粘合代码:
MethodsSomeIPProxy.hpp
MethodsSomeIPProxy.cpp
MethodsSomeIPStubDeployment.hpp
MethodsSomeIPStubDeployment.cpp
MethodsSomeIPStubAdapter.hpp
MethodsSomeIPStubAdapter.cpp
在本教程中,我们将创建一个客户端和一个服务,以便能够看到正在进行的通信。
首先通过MethodsProxy.cpp在项目中创建新的源文件来实现客户端。确保有一个主要方法来启动客户端应用程序。
在这里,将需要两个包含项才能访问CommonAPI客户端功能:
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <CommonAPI/CommonAPI.hpp>
#include <v1/commonapi/mthd/MethodsProxy.hpp>
请注意,必须始终包含CommonAPI.hpp用于访问CommonAPI和生成的代理的运行时部分。如果定义的接口具有版本号,则可以在接口类的名称空间和目录结构中找到该版本。
每个CommonAPI应用程序要做的第一件事之一就是获取指向运行时对象的指针:
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
为了能够与特定服务进行通信,我们需要创建一个代理,并实例化:
std::string domain = "local";
std::string instance = "commonapi.methods.Methods";
std::shared_ptr<MethodsProxy<>> myProxy = runtime->buildProxy<MethodsProxy>(domain, instance, "client-sample");
通过代理的实例化,客户端已建立并可以使用。在此示例中,我们等待服务可用:
while(!myProxy->isAvailable())
{
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
当代理有效后,就可以调用接口方法:
Franca属性表示服务的状态变量或服务的数据集,服务的客户端可用访问它们。
获取属性值:
CommonAPI::CallStatus callStatus;
int32_t value = 0;
CommonAPI::CallInfo info(1000);
info.sender_ = 5678;
std::cout << "Getting attribute value: " << value << std::endl;
myProxy->getXAtrribute().getValue(callStatus, value, &info);
关注属性更改的事件状态,所有需要对事件进行订阅:
myProxy->getXAtrribute().getChangeEvent().subscribe([&](const int32_t& val)
{
std::cout <<"Received change message: " << val << std::endl;
});
异步设置属性值,需要将一个函数调用的返回值包装在一个函数对象中:
void recv_cb(const CommonAPI::CallStatus& callStatus, const int32_t& val)
{
std::cout << "Receive callback: " << val << std::endl;
}
这允许它将此对象传递给其他函数,以便在stub端实现异步行为。
value = 100;
std::function<void(const CommonTypes::CallStatus&, int32_t)> fcb = recv_cb;
myProxy->getXAtrribute().setValueAsync(value, fcb, &info);
Method的同步调用:
int32_t inX1 = 5;
std::string inX2 = "abc";
CommonAPI::CallStatus callStatus;
Methods::stdErrorTypeEnum methodError;
in32_t outY1;
std::string outY2;
std::cout <<"Call foo with synchronous semantics ..." << std::endl;
myProxy->foo(inX1, inX2, callStatus, methodError, outY1, outY2);
异步调用method,需要将一个函数调用的返回值包装在一个函数对象中:
void recv_cb(const CommonAPI::CallStatus& callStatus,
const Methods::stdErrorTypeEnum& methodError,
const int32_t& y1.
const std::string& y2)
{
std::cout << "Result of asynchronous call of foo: " << std::endl;
std::cout << "callStatus: " ((callStatus == CommonAPI::CallStatus::SUCCESS) ? "SUCCESS" : "NO_SUCESS")
<< std::endl;
std::cout << " error: "
<< ((methodError == Methods::stdErrorTypeEnum::NO_FAULT) ? "NO_FAULT" :
"MY_FAULT") << std::endl;
std::cout << " Output values: y1 = " << y1 << ", y2 = " << y2 << std::endl;
}
这允许它将此对象传递给其他函数,以便在stub端实现异步行为。
std::function<void(const CommonAPI::CallStatus&,
const Methods::stdErrorTypeEnum&,
const int32_t&,
const std::string&)> fcb = recv_cb;
myProxy->fooAsync(inX1, intX2,recv_cb);
关于broadcast的事件,需要对其进行订阅:
myProxy->getMyStatusEvent().subscribe([&](const int32_t& val)
{
std::cout << "Received status event: " << val << std::endl;
});
存根实现(MethodsStubImpl)是对存根的一部分代码进行实现,然后供Service调用。
调用set()对属性值进行设置,也可以先get()目前的属性值,然后再对其进行设置:
void MethodsStubImpl::incAttributeCounter()
{
cnt++;
setXAttribute((int32_t)cnt);
std::cout << "New counter value = " << cnt << "!" << std::endl;
}
对定义的method方法进行具体的实现:
void MethodsStubImpl::foo(const std::shared_ptr<CommonAPI::ClientId> _client,
int32_t _x1,
std::string _x2,
fooReply_t _reply) {
std::cout << "foo called, setting new values." << std::endl;
Methods::stdErrorTypeEnum methodError = Methods::stdErrorTypeEnum::MY_FAULT;
int32_t y1 = 42;
std::string y2 = "xyz";
_reply(methodError, y1, y2);
}
调用fire*()触发广播的方法:
void MethodsStubImpl::incBroadcastCounter() {
cnt++;
fireMyStatusEvent((int32_t) cnt);
std::cout << "New counter value = " << cnt << "!" << std::endl;
}
服务的实现与客户端大致相同。所需的包括以下内容:
#include <thread>
#include <iostream>
#include <CommonAPI/CommonAPI.hpp>
#include "MethodsStubImpl.hpp"
在服务的主要功能中,要做的第一件事就是获取运行时对象。
std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
我们必须实例化存根实现(在此处MethodsStubImpl),然后注册它:
std::string domain = "local";
std::string instance = "commonapi.methods.Methods";
std::shared_ptr<MethodsStubImpl> myService = std::make_shared<MethodsStubImpl>();
while (!runtime->registerService(domain, instance, myService, "service-sample")) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
注册成功后,就可以调用接口函数。
调用在存根实现中实现的设置属性的函数:
whild(true)
{
myService->incAttributeCounter();
std::cout <<"Waiting for calls....(Abort with CTRL+C)" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
}
调用在存根实现中实现的触发广播的函数:
while (true) {
myService->incBroadcastCounter();
std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
}