437 lines
16 KiB
C++
437 lines
16 KiB
C++
|
|
/*============================================================================*/
|
||
|
|
/* Copyright (C) huaxu (2022).
|
||
|
|
*
|
||
|
|
* All rights reserved. This software is huaxu property. Duplication
|
||
|
|
* or disclosure without huaxu written authorization is prohibited.
|
||
|
|
*
|
||
|
|
* @file someip_client.hpp
|
||
|
|
* @brief head file of someip client
|
||
|
|
* @author LiuZhimin
|
||
|
|
* @date 2026-02-24 15:20:00
|
||
|
|
*/
|
||
|
|
/*============================================================================*/
|
||
|
|
/*=======[R E V I S I O N H I S T O R Y]====================================*/
|
||
|
|
/* <VERSION> <DATE> <AUTHOR> <REVISION LOG>
|
||
|
|
* V0.0.1 20260606 Liuzhimin Initial Version
|
||
|
|
*/
|
||
|
|
/*============================================================================*/
|
||
|
|
|
||
|
|
#ifndef AG_VSOMEIP_CLIENT_HPP
|
||
|
|
#define AG_VSOMEIP_CLIENT_HPP
|
||
|
|
|
||
|
|
/*=======[I N C L U D E S]====================================================*/
|
||
|
|
|
||
|
|
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
|
||
|
|
#include <csignal>
|
||
|
|
#endif
|
||
|
|
#include <chrono>
|
||
|
|
#include <condition_variable>
|
||
|
|
#include <iomanip>
|
||
|
|
#include <iostream>
|
||
|
|
#include <sstream>
|
||
|
|
#include <thread>
|
||
|
|
|
||
|
|
#include <vsomeip/vsomeip.hpp>
|
||
|
|
|
||
|
|
#include "someip_server_cfg.hpp"
|
||
|
|
|
||
|
|
using namespace vsomeip;
|
||
|
|
/*=======[M A C R O S]========================================================*/
|
||
|
|
#ifdef USE_LOG_MODULE
|
||
|
|
#include "log_mgt_api.h"
|
||
|
|
#ifdef LOG_TAG_SOMEIP
|
||
|
|
#undef LOG_TAG_SOMEIP
|
||
|
|
#endif
|
||
|
|
#define LOG_TAG_SOMEIP "someip_client"
|
||
|
|
|
||
|
|
#define someip_log_d(...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
Log.d(LOG_TAG_SOMEIP, ##__VA_ARGS__); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_i(...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
Log.i(LOG_TAG_SOMEIP, ##__VA_ARGS__); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_w(...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
Log.w(LOG_TAG_SOMEIP, ##__VA_ARGS__); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_e(...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
Log.e(LOG_TAG_SOMEIP, ##__VA_ARGS__); \
|
||
|
|
} while (0)
|
||
|
|
#else
|
||
|
|
#ifdef LOG_TAG_SOMEIP
|
||
|
|
#undef LOG_TAG_SOMEIP
|
||
|
|
#endif
|
||
|
|
#define LOG_TAG_SOMEIP "someip_client"
|
||
|
|
#define someip_log_d(format, ...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
printf("D %s ", LOG_TAG_SOMEIP); \
|
||
|
|
printf(format, ##__VA_ARGS__); \
|
||
|
|
printf("\n"); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_i(format, ...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
printf("I %s ", LOG_TAG_SOMEIP); \
|
||
|
|
printf(format, ##__VA_ARGS__); \
|
||
|
|
printf("\n"); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_w(format, ...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
printf("W %s ", LOG_TAG_SOMEIP); \
|
||
|
|
printf(format, ##__VA_ARGS__); \
|
||
|
|
printf("\n"); \
|
||
|
|
} while (0)
|
||
|
|
#define someip_log_e(format, ...) \
|
||
|
|
do \
|
||
|
|
{ \
|
||
|
|
printf("E %s ", LOG_TAG_SOMEIP); \
|
||
|
|
printf(format, ##__VA_ARGS__); \
|
||
|
|
printf("\n"); \
|
||
|
|
} while (0)
|
||
|
|
|
||
|
|
#endif
|
||
|
|
/*=======[P A R A M T Y P E D E F]==========================================*/
|
||
|
|
|
||
|
|
typedef std::function<std::vector<byte_t>(void)> request_method_func_t;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
service_t _service;
|
||
|
|
instance_t _instance;
|
||
|
|
method_t _method;
|
||
|
|
request_method_func_t _request_method_func;
|
||
|
|
message_type_e _message_type;
|
||
|
|
message_handler_t _massage_handle_func;
|
||
|
|
} request_method_t;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
service_t _service;
|
||
|
|
instance_t _instance;
|
||
|
|
eventgroup_t _eventgroup;
|
||
|
|
event_t _event;
|
||
|
|
event_type_e _type;
|
||
|
|
message_handler_t _massage_handle_func;
|
||
|
|
} request_event_t;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
service_t _service;
|
||
|
|
instance_t _instance;
|
||
|
|
} request_service_t;
|
||
|
|
/*=======[E X P O R T D A T A]==============================================*/
|
||
|
|
|
||
|
|
/*=======[E X P O R T F U N C T I O N D E C L A R A T I O N S]============*/
|
||
|
|
extern void my_someip_client_thread_func(void* arg);
|
||
|
|
|
||
|
|
/*=======[L O C A L D A T A]================================================*/
|
||
|
|
|
||
|
|
/*=======[C L A S S I M P L E M E N T A T I O N S]==========================*/
|
||
|
|
|
||
|
|
class client {
|
||
|
|
public:
|
||
|
|
client(bool _use_tcp, bool _be_quiet, uint32_t _cycle) :
|
||
|
|
app_(runtime::get()->create_application("your_client")),
|
||
|
|
request_(runtime::get()->create_request()),
|
||
|
|
use_tcp_(_use_tcp), //TCP OR UDP
|
||
|
|
be_quiet_(_be_quiet),
|
||
|
|
cycle_(_cycle),
|
||
|
|
running_(true),
|
||
|
|
blocked_(false),
|
||
|
|
is_available_(false),
|
||
|
|
sender_(std::bind(&client::run, this)) {
|
||
|
|
}
|
||
|
|
|
||
|
|
bool init() {
|
||
|
|
if (!app_->init()) {
|
||
|
|
someip_log_e("Couldn't initialize application");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
someip_log_i("Client settings [protocol=%s:quiet=%s:cycle=%d]",
|
||
|
|
(use_tcp_ ? "TCP" : "UDP"),(be_quiet_ ? "true" : "false"), cycle_);
|
||
|
|
|
||
|
|
app_->register_state_handler(
|
||
|
|
std::bind(&client::on_state, this,
|
||
|
|
std::placeholders::_1));
|
||
|
|
|
||
|
|
//any feed back message
|
||
|
|
app_->register_message_handler(
|
||
|
|
ANY_SERVICE, ANY_INSTANCE, ANY_METHOD,
|
||
|
|
std::bind(&client::on_message, this,
|
||
|
|
std::placeholders::_1));
|
||
|
|
|
||
|
|
someip_log_i("Client app init done.");
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void start_request_method(service_t _service, instance_t _instance, method_t _method,
|
||
|
|
const request_method_func_t &_request_method_func, message_type_e _message_type,
|
||
|
|
const message_handler_t &_massage_handle_func){
|
||
|
|
|
||
|
|
app_->register_availability_handler(_service, _instance,
|
||
|
|
std::bind(&client::on_availability, this,
|
||
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||
|
|
|
||
|
|
someip_log_i("Send a requset register to method [0x%04x/0x%04x/0x%04x]",
|
||
|
|
_service, _instance, _method);
|
||
|
|
|
||
|
|
if ((message_type_e::MT_REQUEST_NO_RETURN != _message_type) && (nullptr != _massage_handle_func))
|
||
|
|
{
|
||
|
|
/* register response massage handler */
|
||
|
|
app_->register_message_handler(_service, _instance, _method, _massage_handle_func);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* request thread */
|
||
|
|
std::thread req_method(std::bind(&client::request_method_func, this,
|
||
|
|
_service, _instance, _method, _message_type, _request_method_func));
|
||
|
|
req_method.detach();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void request_method_func(service_t _service, instance_t _instance, method_t _method,
|
||
|
|
message_type_e _message_type, const request_method_func_t &_request_method_func)
|
||
|
|
{
|
||
|
|
if (is_available_){ /* TODO :this available should be one server available, change it bind to server */
|
||
|
|
if (nullptr != _request_method_func)
|
||
|
|
{
|
||
|
|
std::vector<byte_t> data = _request_method_func();
|
||
|
|
if (data[0] != byte_t{0}) /* data[0] is request flag */
|
||
|
|
{
|
||
|
|
std::shared_ptr< message > request = runtime::get()->create_request();
|
||
|
|
request->set_service(_service);
|
||
|
|
request->set_instance(_instance);
|
||
|
|
request->set_method(_method);
|
||
|
|
|
||
|
|
request->set_message_type(_message_type);
|
||
|
|
|
||
|
|
std::shared_ptr<payload> payload;
|
||
|
|
std::vector<byte_t> req_data;
|
||
|
|
req_data.assign(data[1],data.size()-1); /* request data: data[1]~... */
|
||
|
|
payload->set_data(req_data);
|
||
|
|
request->set_payload(payload);
|
||
|
|
|
||
|
|
app_->send(request);
|
||
|
|
|
||
|
|
someip_log_i("Client/session [0x%04x/0x%04x] sent a request to Service/instance/method [0x%04x/0x%04x/0x%04x]",
|
||
|
|
request->get_client(),request->get_session(),
|
||
|
|
request->get_service(),request->get_instance(),request->get_method());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
/* code */
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void start_request_event(service_t _service, instance_t _instance,
|
||
|
|
eventgroup_t _eventgroup, event_t _event, event_type_e _type,
|
||
|
|
const message_handler_t &_massage_handle_func, major_version_t _major = DEFAULT_MAJOR){
|
||
|
|
|
||
|
|
app_->register_availability_handler(_service, _instance,
|
||
|
|
std::bind(&client::on_availability, this,
|
||
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||
|
|
|
||
|
|
if (nullptr != _massage_handle_func)
|
||
|
|
{
|
||
|
|
/* register response massage handler */
|
||
|
|
app_->register_message_handler(_service, _instance, _event, _massage_handle_func);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
someip_log_w("Event [0x%04x/0x%04x/0x%04x/0x%04x] handle function is null",
|
||
|
|
_service, _instance, _eventgroup, _event);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::set<eventgroup_t> its_groups;
|
||
|
|
its_groups.insert(_eventgroup);
|
||
|
|
app_->request_event(_service, _instance, _event,its_groups,_type);
|
||
|
|
app_->subscribe(_service, _instance, _eventgroup, _major);
|
||
|
|
|
||
|
|
someip_log_i("Send a request to event [0x%04x/0x%04x/0x%04x/0x%04x]",
|
||
|
|
_service, _instance, _eventgroup, _event);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void stop_request_event(service_t _service, instance_t _instance, event_t _event){
|
||
|
|
app_->release_event(_service, _instance, _event);
|
||
|
|
someip_log_i("Stop request event [0x%04x/0x%04x/0x%04x]",
|
||
|
|
_service, _instance, _event);
|
||
|
|
}
|
||
|
|
|
||
|
|
void stop_request_event_group(service_t _service, instance_t _instance,
|
||
|
|
eventgroup_t _eventgroup){
|
||
|
|
app_->unsubscribe( _service, _instance, _eventgroup);
|
||
|
|
someip_log_i("Stop request event-group [0x%04x/0x%04x/0x%04x]",
|
||
|
|
_service, _instance, _eventgroup);
|
||
|
|
}
|
||
|
|
|
||
|
|
void start_request_service(service_t _service, instance_t _instance,
|
||
|
|
major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = 0U){
|
||
|
|
app_->request_service(_service, _instance, _major, _minor); // find_service (SD)
|
||
|
|
//msg_threads_.push_back(std::thread(&client::on_message, this));
|
||
|
|
// app_->register_message_handler(_service, _instance, ANY_METHOD,
|
||
|
|
// std::bind(&client::on_message, this, std::placeholders::_1));
|
||
|
|
// app_->register_message_handler(
|
||
|
|
// ANY_SERVICE, _instance, ANY_METHOD,
|
||
|
|
// std::bind(&client::on_message, this,
|
||
|
|
// std::placeholders::_1));
|
||
|
|
someip_log_i("Start request service [0x%04x/0x%04x].",_service, _instance);
|
||
|
|
}
|
||
|
|
|
||
|
|
void stop_request_service(service_t _service, instance_t _instance)
|
||
|
|
{
|
||
|
|
app_->release_service(_service, _instance);
|
||
|
|
//is_offered_ = false;
|
||
|
|
someip_log_w("Stop request service [0x%04x/0x%04x].",_service, _instance);
|
||
|
|
}
|
||
|
|
|
||
|
|
void start() {
|
||
|
|
someip_log_i("Client app[%s] start.",app_->get_name().c_str());
|
||
|
|
app_->start();
|
||
|
|
}
|
||
|
|
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
|
||
|
|
/*
|
||
|
|
* Handle signal to shutdown
|
||
|
|
*/
|
||
|
|
void stop() {
|
||
|
|
app_->clear_all_handler();
|
||
|
|
//app_->unsubscribe(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENTGROUP_ID);
|
||
|
|
//app_->release_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID);
|
||
|
|
//app_->release_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
|
||
|
|
condition_.notify_one();
|
||
|
|
sender_.join();
|
||
|
|
//for (auto &th: msg_threads_)th.join();
|
||
|
|
app_->stop();
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void on_state(state_type_e _state) {
|
||
|
|
someip_log_i("Application [%s] is %s.",app_->get_name().c_str(),
|
||
|
|
(_state == state_type_e::ST_REGISTERED ? "registered" : "deregistered"));
|
||
|
|
app_state_ = _state;
|
||
|
|
if (_state == state_type_e::ST_REGISTERED) {
|
||
|
|
// TODO : ...
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_availability(service_t _service, instance_t _instance, bool _is_available){
|
||
|
|
someip_log_i("Service [0x%04x.0x%04x] is %s", _service, _instance,
|
||
|
|
(_is_available ? "available." : "NOT available."));
|
||
|
|
|
||
|
|
if (is_available_ && !_is_available){
|
||
|
|
is_available_ = false;
|
||
|
|
}
|
||
|
|
else if (_is_available && !is_available_){
|
||
|
|
is_available_ = true;
|
||
|
|
// send();
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_message(const std::shared_ptr<message> &_response) {
|
||
|
|
|
||
|
|
std::shared_ptr<payload> its_payload =_response->get_payload();
|
||
|
|
//someip_log_i("Received a message [0x%04x.0x%04x.0x%04x] to Client/Session [0x%04x.0x%04x].",
|
||
|
|
// _response->get_service(), _response->get_instance(), _response->get_method(),
|
||
|
|
// _response->get_client(), _response->get_session());
|
||
|
|
|
||
|
|
switch (_response->get_method())
|
||
|
|
{
|
||
|
|
//case 0x8001:
|
||
|
|
// someip_log_i("------------0x8001---------");
|
||
|
|
// break;
|
||
|
|
case 0x8002:
|
||
|
|
someip_log_i("------------0x8002---------");
|
||
|
|
break;
|
||
|
|
case 0x8003:
|
||
|
|
someip_log_i("------------0x8003---------");
|
||
|
|
break;
|
||
|
|
case 0x8004:
|
||
|
|
someip_log_i("------------0x8004---------");
|
||
|
|
break;
|
||
|
|
case 0x8005:
|
||
|
|
someip_log_i("------------0x8005---------");
|
||
|
|
break;
|
||
|
|
case 0x8006:
|
||
|
|
someip_log_i("------------0x8006---------");
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// // TODO : here is received_data
|
||
|
|
// std::vector<byte_t> received_data;
|
||
|
|
// received_data.assign(its_payload->get_data(),its_payload->get_data()+its_payload->get_length());
|
||
|
|
// std::string data_to_str;
|
||
|
|
// data_to_str.assign(received_data.begin(), received_data.end());
|
||
|
|
// someip_log_i("Received message lenght[%d] [%s].",its_payload->get_length(), data_to_str.c_str());
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void send() {
|
||
|
|
if (!be_quiet_)
|
||
|
|
{
|
||
|
|
std::lock_guard< std::mutex > its_lock(mutex_);
|
||
|
|
blocked_ = true;
|
||
|
|
condition_.notify_one();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//bind with std::thread sender_, below function is send requset to sevice
|
||
|
|
void run() {
|
||
|
|
while (running_) {
|
||
|
|
{
|
||
|
|
std::unique_lock<std::mutex> its_lock(mutex_);
|
||
|
|
while (!blocked_) condition_.wait(its_lock);
|
||
|
|
if (is_available_) {
|
||
|
|
app_->send(request_);
|
||
|
|
|
||
|
|
someip_log_i("Client/Session [0x%04x/0x%04x] sent a request to Service [0x%04x/0x%04x]",
|
||
|
|
request_->get_client(),request_->get_session(),
|
||
|
|
request_->get_service(),request_->get_instance());
|
||
|
|
blocked_ = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(cycle_));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::shared_ptr< application > app_;
|
||
|
|
std::shared_ptr< message > request_;
|
||
|
|
bool use_tcp_;
|
||
|
|
bool be_quiet_;
|
||
|
|
uint32_t cycle_;
|
||
|
|
session_t session_;
|
||
|
|
std::mutex mutex_;
|
||
|
|
std::condition_variable condition_;
|
||
|
|
bool running_;
|
||
|
|
bool blocked_;
|
||
|
|
bool is_available_;
|
||
|
|
state_type_e app_state_;
|
||
|
|
|
||
|
|
std::thread sender_;
|
||
|
|
//std::vector<std::thread> msg_threads_;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // AG_VSOMEIP_CLIENT_HPP
|