CommonAPI编写代码

一、Methods.fidl

1、编写Methods.fidl文件

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
        }
    }

}

2、编译Methods.fidl文件

执行代码生成器的可执行文件,根据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

二、Methods.fdepl

1、编写Methods.fdepl文件

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
    }
}

2、编译Methods.fdepl文件

执行代码生成器的可执行文件,根据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在项目中创建新的源文件来实现客户端。确保有一个主要方法来启动客户端应用程序。

1、客户端编写

在这里,将需要两个包含项才能访问CommonAPI客户端功能:

#include 

#ifndef _WIN32
#include 
#endif

#include 
#include 

请注意,必须始终包含CommonAPI.hpp用于访问CommonAPI和生成的代理的运行时部分。如果定义的接口具有版本号,则可以在接口类的名称空间和目录结构中找到该版本。
每个CommonAPI应用程序要做的第一件事之一就是获取指向运行时对象的指针:

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

为了能够与特定服务进行通信,我们需要创建一个代理,并实例化:

std::string domain = "local";
std::string instance = "commonapi.methods.Methods";

std::shared_ptr> myProxy = runtime->buildProxy(domain, instance, "client-sample");

通过代理的实例化,客户端已建立并可以使用。在此示例中,我们等待服务可用:

while(!myProxy->isAvailable())
{
    std::this_thread::sleep_for(std::chrono::microseconds(10));
}

当代理有效后,就可以调用接口方法:

1)关于attribute的调用

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 fcb = recv_cb;
myProxy->getXAtrribute().setValueAsync(value, fcb, &info);

2)关于method的调用

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 fcb = recv_cb;
myProxy->fooAsync(inX1, intX2,recv_cb);

3)关于broadcast的调用

关于broadcast的事件,需要对其进行订阅:

myProxy->getMyStatusEvent().subscribe([&](const int32_t& val)
{
    std::cout << "Received status event: " << val << std::endl;
});

2、对于存根实现的代码:

存根实现(MethodsStubImpl)是对存根的一部分代码进行实现,然后供Service调用。

1)关于attribute的实现

调用set()对属性值进行设置,也可以先get()目前的属性值,然后再对其进行设置:

void MethodsStubImpl::incAttributeCounter()
{
    cnt++;
    setXAttribute((int32_t)cnt);
    std::cout << "New counter value = " << cnt << "!" << std::endl;
}

2) 关于method的实现

对定义的method方法进行具体的实现:

void MethodsStubImpl::foo(const std::shared_ptr _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);
}

3)关于broadcast的实现

调用fire*()触发广播的方法:

void MethodsStubImpl::incBroadcastCounter() {
    cnt++;
    fireMyStatusEvent((int32_t) cnt);
    std::cout << "New counter value = " << cnt << "!" << std::endl;
}

3、服务端编写

服务的实现与客户端大致相同。所需的包括以下内容:

#include 
#include 

#include 
#include "MethodsStubImpl.hpp"

在服务的主要功能中,要做的第一件事就是获取运行时对象。

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

我们必须实例化存根实现(在此处MethodsStubImpl),然后注册它:

std::string domain = "local";
std::string instance = "commonapi.methods.Methods";

std::shared_ptr myService = std::make_shared();
while (!runtime->registerService(domain, instance, myService, "service-sample")) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

注册成功后,就可以调用接口函数。

1)关于attribute的调用

调用在存根实现中实现的设置属性的函数:

whild(true)
{
    myService->incAttributeCounter();
    std::cout <<"Waiting for calls....(Abort with CTRL+C)" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

2)关于broadcast的调用

调用在存根实现中实现的触发广播的函数:

while (true) {
    myService->incBroadcastCounter(); 
    std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

你可能感兴趣的:(IPC)