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 <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));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章