一、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 <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));
}
當代理有效後,就可以調用接口方法:
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<void(const CommonTypes::CallStatus&, int32_t)> 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<void(const CommonAPI::CallStatus&,
const Methods::stdErrorTypeEnum&,
const int32_t&,
const std::string&)> 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<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);
}
3)關於broadcast的實現
調用fire*()觸發廣播的方法:
void MethodsStubImpl::incBroadcastCounter() {
cnt++;
fireMyStatusEvent((int32_t) cnt);
std::cout << "New counter value = " << cnt << "!" << std::endl;
}
3、服務端編寫
服務的實現與客戶端大致相同。所需的包括以下內容:
#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));
}
註冊成功後,就可以調用接口函數。
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));
}