feat(soa_server):initial version of soa_server

This commit is contained in:
2026-06-24 17:31:17 +08:00
parent 85fbb3188c
commit f006c77b37
31 changed files with 2202 additions and 3 deletions

View File

@@ -49,7 +49,7 @@ else
echo "--- build boost, target host: ${TARGET_HOST} ----"
fi
${BASE_DIR}/build_boost.sh
#${BASE_DIR}/build_boost.sh
if [ "rk3576" = ${TARGET_HOST} ];then
echo "--- cross build vsomeip, target host: ${TARGET_HOST} ----"
@@ -70,9 +70,10 @@ else
echo "--- build vsomeip, target host: ${TARGET_HOST} ----"
fi
${BASE_DIR}/build_vsomeip.sh
#${BASE_DIR}/build_vsomeip.sh
${BASE_DIR}/build_example.sh
#${BASE_DIR}/build_example.sh
${BASE_DIR}/build_soa_server.sh
echo "--- build finished ---"
sleep 1
exit

61
build_soa_server.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/sh
#TARGET_HOST=rk3576
BASE_DIR=`pwd`
BOOST=boost_1_75_0
VSOMEIP=vsomeip-3.7.3
SOASERVER=soa_server
SOURCE_DIR=${BASE_DIR}/source
INSTALL_DIR=${BASE_DIR}/install
#检测source_code
cd ${SOURCE_DIR}
if [ ! -d ${SOURCE_DIR}/${SOASERVER} ];then
echo "error : no soa_server code"
exit
fi
# clean install dir
rm -rf ${INSTALL_DIR}/${SOASERVER}/${TARGET_HOST}
mkdir -p ${INSTALL_DIR}/${SOASERVER}/${TARGET_HOST}
#预编译 camke
echo "--- start to cmake ---"
cd ${SOURCE_DIR}/${SOASERVER}
if [ -d ./build_${TARGET_HOST} ];then
rm -rf ./build_${TARGET_HOST}
echo "--- delete build folder ---"
fi
mkdir -p build_${TARGET_HOST}
cd build_${TARGET_HOST}
if [ ${BUILD_HOST} != ${TARGET_HOST} ];then
cmake -DBOOST_ROOT=${INSTALL_DIR}/${BOOST} \
-DBoost_INCLUDE_DIR=${INSTALL_DIR}/${BOOST}/include \
-DBOOST_LIBRARY_DIR=${INSTALL_DIR}/${BOOST}/lib \
-DVSOMEIP_LIBRARY_DIR=${INSTALL_DIR}/${VSOMEIP}/lib \
-DVSOMEIP_INCLUDE_DIR=${INSTALL_DIR}/${VSOMEIP}/include \
-DCMAKE_INSTALL_PREFIX:PATH=${INSTALL_DIR}/${SOASERVER} \
-DENABLE_SIGNAL_HANDLING=1 \
..
else
cmake ..
fi
#编译
echo "--start to make--"
make clean
make -j12
if [ ${BUILD_HOST} != ${TARGET_HOST} ];then
cp *server* ${INSTALL_DIR}/${SOASERVER}/${TARGET_HOST}
else
sudo cp *server* ${INSTALL_DIR}/${SOASERVER}/${TARGET_HOST}
fi
cd ..
rm -rf build_${TARGET_HOST}
# make install
#rm -rf ${SOURCE_DIR}/${VSOMEIP}
cd ${BASE_DIR}
echo "--- build soa_server finished ---"

Binary file not shown.

Binary file not shown.

BIN
install/tmp/lib.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
libboost_filesystem.so.1.75.0

Binary file not shown.

View File

@@ -0,0 +1 @@
libboost_system.so.1.75.0

Binary file not shown.

View File

@@ -0,0 +1 @@
libvsomeip3-cfg.so.3

View File

@@ -0,0 +1 @@
libvsomeip3-cfg.so.3.7.3

Binary file not shown.

View File

@@ -0,0 +1 @@
libvsomeip3-sd.so.3

View File

@@ -0,0 +1 @@
libvsomeip3-sd.so.3.7.3

Binary file not shown.

View File

@@ -0,0 +1 @@
libvsomeip3.so.3

View File

@@ -0,0 +1 @@
libvsomeip3.so.3.7.3

Binary file not shown.

View File

@@ -0,0 +1,5 @@
{
"files.associations": {
"*.tcc": "cpp"
}
}

View File

@@ -0,0 +1,22 @@
cmake_minimum_required (VERSION 2.8.7)
project (example)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
find_package(Threads REQUIRED)
include_directories(${BOOST_INCLUDE_DIR})
include_directories(${VSOMEIP_INCLUDE_DIR})
link_directories(${BOOST_LIBRARY_DIR})
link_directories(${VSOMEIP_LIBRARY_DIR})
# add_executable(someip_service ../someip_service.cpp)
# target_link_libraries(someip_service vsomeip3 vsomeip3-cfg vsomeip3-sd pthread boost_filesystem boost_system)
# add_executable (someip_client ../someip_client.cpp)
# target_link_libraries(someip_client vsomeip3 vsomeip3-cfg vsomeip3-sd pthread boost_filesystem boost_system)
add_executable(soa_server ../soa_server.cpp ../someip_server.cpp ../spi_server.cpp ../spi_protocol.cpp)
target_link_libraries(soa_server vsomeip3 vsomeip3-cfg vsomeip3-sd pthread boost_filesystem boost_system)

View File

@@ -0,0 +1,231 @@
/*============================================================================*/
/* Copyright (C) huaxu (2026).
*
* All rights reserved. This software is huaxu property. Duplication
* or disclosure without huaxu written authorization is prohibited.
*
* @file your_app.cpp
* @brief main entry of your_app
* @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
*/
/*============================================================================*/
/*=======[I N C L U D E S]====================================================*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include "someip_server_cfg.hpp"
#include "spi_server.hpp"
#include <list>
//#include "location_mgt_api.h"
using namespace vsomeip;
/*=======[G L O B A L D A T A]==============================================*/
/*=======[M A C R O S]========================================================*/
/*=======[I N T E R N A L D A T A]==========================================*/
/*=======[L O C A L F U N C T I O N D E C L A R A T I O N S]==============*/
/*=======[L O C A L F U N C T I O N I M P L E M E N T A T I O N S]========*/
/*=======[G L O B A L F U N C T I O N I M P L E M E N T A T I O N S]======*/
// methods' data functions
#if 0
std::vector<byte_t> rr_method_example1(void){
/* 1.receive this example, and add your code do your action here */
//...
/* 2.And than give response data */
std::string example_string = "Hello China.";
std::vector<byte_t> data;
data.assign(example_string.begin(),example_string.end());
return data;
}
// events' data functions
std::vector<byte_t> rr_method_example2(void){
/* 1.receive this example, and add your code do your action here */
//...
/* 2.And than give response data */
std::string example_string = "Hello GuangZhou.";
std::vector<byte_t> data;
data.assign(example_string.begin(),example_string.end());
return data;
}
std::vector<byte_t> ff_method_example1(void){
/* 1.Add your code do your action here */
//...
/* reserve,no need data to reponse*/
std::vector<byte_t> data;
return data;
}
std::vector<byte_t> ff_method_example2(void){
/* 1.Add your code do your action here */
//...
/* reserve,no need data to reponse*/
std::vector<byte_t> data;
return data;
}
std::vector<byte_t> getter_example1(void){
std::vector<byte_t> data;
/* 1.Add your code do get a feature value */
//...
/* 2.And than response value to data */
std::string example_string = "This is an getter example.";
data.assign(example_string.begin(),example_string.end());
return data;
}
std::vector<byte_t> getter_example2(void){
std::vector<byte_t> data;
/* 1.Add your code do get a feature value */
//...
/* 2.And than response value to data */
std::string example_string = "This is an getter example2.";
data.assign(example_string.begin(),example_string.end());
return data;
}
std::vector<byte_t> setter_example1(void){
std::vector<byte_t> data;
/* 1.Add your code do set a feature value */
//...
/* 2.And than response state to client */
std::string example_string = "Setter xxx is success.";
data.assign(example_string.begin(),example_string.end());
/* 3. If need, you can add your Notify response here */
// ...
return data;
}
std::vector<byte_t> setter_example2(void){
std::vector<byte_t> data;
/* 1.Add your code do set a feature value */
//...
/* 2.And than response state to client */
std::string example_string = "Setter xxx is success2.";
data.assign(example_string.begin(),example_string.end());
/* 3. If need, you can add your Notify response here */
// ...
return data;
}
std::vector<byte_t> event_example1(void){
std::vector<byte_t> data;
/* Add your handle logic here for data to notify */
// ...
std::string example_string = "info is empty.";
data.assign(example_string.begin(),example_string.end());
return data;
}
std::vector<byte_t> event_example2(void){
std::vector<byte_t> data;
/* Add your handle logic here for data to notify */
// ...
std::string example_string = "info is empty.";
data.assign(example_string.begin(),example_string.end());
return data;
}
#endif
std::vector<byte_t> notifier_can0(void){
std::lock_guard<std::mutex> lock(g_can_mutex[0]);
return g_can_data[0];
}
std::vector<byte_t> notifier_can1(void){
std::lock_guard<std::mutex> lock(g_can_mutex[1]);
return g_can_data[1];
}
std::vector<byte_t> notifier_can2(void){
std::lock_guard<std::mutex> lock(g_can_mutex[2]);
return g_can_data[2];
}
std::vector<byte_t> notifier_can3(void){
std::lock_guard<std::mutex> lock(g_can_mutex[3]);
return g_can_data[3];
}
std::vector<byte_t> notifier_can4(void){
std::lock_guard<std::mutex> lock(g_can_mutex[4]);
return g_can_data[4];
}
std::vector<byte_t> notifier_can5(void){
std::lock_guard<std::mutex> lock(g_can_mutex[5]);
return g_can_data[5];
}
bool epsilon_func(std::shared_ptr<vsomeip::payload> _old, std::shared_ptr<vsomeip::payload> _new)
{
// TODO: add your logic here to compare _old and _new
return false;
};
// #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
// //service *server_ptr(nullptr);
// void handle_signal(int _signal)
// {
// if (server_ptr != nullptr &&
// (_signal == SIGINT || _signal == SIGTERM
// || _signal == SIGKILL))
// server_ptr->stop();
// }
// #endif
// service server;
// someip_log_i("start someip server");
// #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
// server_ptr = &server;
// signal(SIGINT, handle_signal);
// signal(SIGTERM, handle_signal);
// signal(SIGKILL, handle_signal);
// #endif
int main(int argc, char **argv) {
printf("start your_app\r\n");
try {
std::thread server_thread(my_someip_server_thread_func, nullptr);
std::thread spi_server_thread(my_spi_server_thread_func, nullptr);
// wait for threads stop
server_thread.join();
std::cout << "server_thread stopped." << std::endl;
spi_server_thread.join();
std::cout << "spi_server_thread stopped." << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Thread creation failed: " << e.what() << std::endl;
return 1;
}
return 0;
}

View File

@@ -0,0 +1,24 @@
{
"unicast": "127.0.0.1",
"logging": {
"level": "debug",
"console": "true"
},
"applications": [
{
"name": "soa_server",
"id": "0x1234"
}
],
"services": [
{
"service": "0x0005",
"instance": "0x0001",
"reliable": "30509"
}
],
"routing": "soa_server",
"service-discovery": {
"enable": "false"
}
}

View File

@@ -0,0 +1,122 @@
/*============================================================================*/
/* Copyright (C) huaxu (2026).
*
* All rights reserved. This software is huaxu property. Duplication
* or disclosure without huaxu written authorization is prohibited.
*
* @file someip_server.cpp
* @brief main entry of someip_server
* @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
*/
/*============================================================================*/
/*=======[I N C L U D E S]====================================================*/
#include "someip_server_cfg.hpp"
//#include "someip_server.hpp"
#include <list>
//#include "location_mgt_api.h"
using namespace vsomeip;
/*=======[G L O B A L D A T A]==============================================*/
/*=======[M A C R O S]========================================================*/
/*=======[I N T E R N A L D A T A]==========================================*/
/*=======[L O C A L F U N C T I O N D E C L A R A T I O N S]==============*/
/*=======[L O C A L F U N C T I O N I M P L E M E N T A T I O N S]========*/
/*=======[G L O B A L F U N C T I O N I M P L E M E N T A T I O N S]======*/
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
service *server_ptr(nullptr);
void server_handle_signal(int _signal)
{
if (server_ptr != nullptr &&
(_signal == SIGINT || _signal == SIGTERM
|| _signal == SIGKILL))
server_ptr->stop();
}
#endif
void my_someip_server_thread_func(void* arg)
{
service server;
someip_log_i("start someip server");
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
server_ptr = &server;
signal(SIGINT, server_handle_signal);
signal(SIGTERM, server_handle_signal);
signal(SIGKILL, server_handle_signal);
#endif
someip_log_i("start initial.");
if (server.init())
{
someip_log_i("start offer method/events.");
/* register/offer server */
for (auto const&service: my_servers){
server.start_offer_service(service._service, service._instance,
service._major, service._minor);
}
#if 0
/* register R/R methods */
for (auto const&method: offer_rr_methods){
server.register_method(method._service,method._instance,method._method,method._method_type,method._get_response_data_func);
}
/* register F/F methods */
for (auto const&method: offer_ff_methods){
server.register_method(method._service,method._instance,method._method,method._method_type,method._get_response_data_func);
}
/* register setters */
for (auto const&method: offer_setters){
server.register_method(method._service,method._instance,method._method,method._method_type,method._get_response_data_func);
}
/* register getters */
for (auto const&method: offer_getters){
server.register_method(method._service,method._instance,method._method,method._method_type,method._get_response_data_func);
}
/* register Events */
for (auto const&event: offer_events){
server.register_event(event._service, event._instance, event._eventgroup,
event._event, event._type, event._cycle, event._change_resets_cycle,
event._update_on_change, event._epsilon_change_func,
event._reliability, event._notify_data_func);
}
#endif
/* register Notifiers */
for (auto const&event: offer_notifiers){
server.register_event(event._service, event._instance, event._eventgroup,
event._event, event._type, event._cycle, event._change_resets_cycle,
event._update_on_change, event._epsilon_change_func,
event._reliability, event._notify_data_func);
}
/* To start server, after method/event is registered */
server.start(); //block function
/* stop server */
for (auto const&service: my_servers){
server.stop_offer_service(service._service, service._instance,
service._major, service._minor);
}
server.stop();
return;
}else{
return;
}
}

View File

@@ -0,0 +1,420 @@
/*============================================================================*/
/* Copyright (C) huaxu (2022).
*
* All rights reserved. This software is huaxu property. Duplication
* or disclosure without huaxu written authorization is prohibited.
*
* @file someip_server.hpp
* @brief head file of someip service
* @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 SOMEIP_SERVER_HPP
#define SOMEIP_SERVER_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 <mutex>
#include <vsomeip/vsomeip.hpp>
using namespace std;
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_server"
#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_server"
#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)> get_response_data_func_t;
// typedef std::function<std::vector<byte_t>(const std::shared_ptr<bool> &)> get_notify_data_func_t;
typedef std::function<std::vector<byte_t>(void)> get_notify_data_func_t;
// typedef std::function<
// bool (const std::shared_ptr<payload> &,
// const std::shared_ptr<payload> &) > epsilon_change_func_t;
typedef struct
{
service_t _service;
instance_t _instance;
method_t _method;
message_type_e _method_type;
get_response_data_func_t _get_response_data_func;
} offer_method_t;
typedef struct
{
service_t _service;
instance_t _instance;
method_t _method;
} stop_method_t;
typedef struct
{
service_t _service;
instance_t _instance;
eventgroup_t _eventgroup;
event_t _event;
event_type_e _type;
uint32_t _cycle; /*ms*/
bool _change_resets_cycle;
bool _update_on_change;
epsilon_change_func_t _epsilon_change_func;
reliability_type_e _reliability;
get_notify_data_func_t _notify_data_func;
} offer_event_t;
typedef struct
{
service_t _service;
instance_t _instance;
event_t _event;
} stop_event_t;
typedef struct
{
service_t _service;
instance_t _instance;
major_version_t _major;
minor_version_t _minor;
} offer_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_server_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 service
{
public:
service() :
app_(vsomeip::runtime::get()->create_application("soa_server"))
, is_registered_(false)
, running_(true)
, service_is_offered_(false){
}
bool init()
{
// std::lock_guard<std::mutex> its_lock(mutex_);
if (!app_->init())
{
someip_log_e("Couldn't initialize application");
return false;
}
app_->register_state_handler(
std::bind(&service::on_state, this, std::placeholders::_1));
// {
// std::lock_guard<std::mutex> its_lock(payload_mutex_);
// payload_ = runtime::get()->create_payload();
// }
// condition_.notify_one();
someip_log_i("Server app init done.");
return true;
}
void start()
{
someip_log_i("Server app[%s] start.",app_->get_name().c_str());
app_->start();
}
void register_method(service_t _service, instance_t _instance, method_t _method,
message_type_e _method_type, const get_response_data_func_t &_get_response_data_func)
{
someip_log_i("Start a method [0x%04x/0x%04x/0x%04x]",_service, _instance, _method);
app_->register_message_handler(_service, _instance, _method,
std::bind(&service::on_method_receive, this, std::placeholders::_1, _method_type, _get_response_data_func));
}
void on_method_receive(const std::shared_ptr<message> &_request, message_type_e _method_type,
const get_response_data_func_t &_get_response_data_func)
{
someip_log_i("Received a request from client[0x%04x/0x%04x] to service[0x%04x/0x%04x]",
_request->get_client(), _request->get_session(),
_request->get_service(), _request->get_instance());
if ((nullptr != _get_response_data_func) && (_method_type != message_type_e::MT_REQUEST_NO_RETURN))
{
std::shared_ptr<message> _response = runtime::get()->create_response(_request);
std::shared_ptr<payload> _payload = runtime::get()->create_payload();
std::vector<byte_t> data = _get_response_data_func();
/* _response->set_message_type(message_type_e::MT_RESPONSE);*/
_payload->set_data(data);
_response->set_payload(_payload);
app_->send(_response);
someip_log_i("Send response from [0x%04x/0x%04x] to [0x%04x/0x%04x] length[%d]",
_request->get_service(), _request->get_instance(),
_request->get_client(), _request->get_session(),_payload->get_length());
}
else
{
/* to execute F/F-method callback function */
someip_log_i("Execcute F/F-method request from [0x%04x/0x%04x]", _request->get_service(), _request->get_instance());
_get_response_data_func();
}
}
void unregister_method(service_t _service, instance_t _instance,
method_t _method){
someip_log_w("Stop a method [0x%04x/0x%04x/0x%04x]",_service, _instance, _method);
app_->unregister_message_handler(_service, _instance, _method);
}
// TODO : _type, _cycle, _reliability define by config file
void register_event(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, event_t _event, event_type_e _type,
uint32_t _cycle, bool _change_resets_cycle,
bool _update_on_change, epsilon_change_func_t _epsilon_change_func,
reliability_type_e _reliability, get_notify_data_func_t _notify_data_func)
{
std::set<eventgroup_t> groups;
groups.insert(_eventgroup);
if (!_epsilon_change_func) {
std::cerr << "epsilon_change_func is null!" << std::endl;
}
if (!_notify_data_func)
{
std::cerr << "_notify_data_func is null!" << std::endl;
}
app_->offer_event(_service, _instance, _event, groups, _type,
std::chrono::milliseconds(_cycle),
_change_resets_cycle, _update_on_change,
_epsilon_change_func, _reliability);
someip_log_i("Start a event [0x%04x/0x%04x/0x%04x/0x%04x], type[%d], cycle[%dms]",
_service, _instance, _eventgroup, _event, _type, _cycle);
std::thread _notify_event(std::bind(&service::notify_event, this,
_service, _instance, _event, _cycle, _update_on_change, _notify_data_func));
_notify_event.detach();
}
void notify_event(service_t _service, instance_t _instance, event_t _event,
uint32_t _cycle, bool _update_on_change, get_notify_data_func_t _notify_data_func)
{
someip_log_i("Start event [0x%04x] notify thread.",_event);
while (running_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
/* wait for service offer */
while (!service_is_offered_ && running_)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (service_is_offered_ && running_)
{
if (_update_on_change || (0U == _cycle))
{
// for update on change
/* If data is not empty and changed, to notify */
static std::vector<byte_t> lastData;
std::vector<byte_t> notify_data;
notify_data.clear();
notify_data = _notify_data_func();
if ((nullptr != _notify_data_func) && (lastData != notify_data))
{
lastData = notify_data;
std::shared_ptr<payload> _payload = runtime::get()->create_payload();
_payload->set_data(notify_data);
someip_log_d("Notify event[0x%04x] with data size[%d] payload length[%d].", _event,notify_data.size(), _payload->get_length());
app_->notify(_service, _instance, _event, _payload);
}
}
else // for cycle update
{
if (nullptr != _notify_data_func)
{
std::vector<byte_t> notify_data;
std::shared_ptr<payload> _payload = runtime::get()->create_payload();
notify_data.clear();
notify_data = _notify_data_func();
_payload->set_data(notify_data);
someip_log_d("Notify cycle event[0x%04x] with data size[%d] payload length[%d].", _event,notify_data.size(), _payload->get_length());
app_->notify(_service, _instance, _event, _payload);
}
else{
someip_log_e("event[0x%04x]_notify_data_func is nullptr!!", _event);
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(_cycle - 1));
}
}
}
someip_log_w("Stop event [0x%04x] notify thread.",_event);
return;
}
void unregister_event(service_t _service, instance_t _instance, event_t _event)
{
app_->stop_offer_event(_service, _instance, _event);
someip_log_i("Stop a event [0x%04x/0x%04x/0x%04x].",_service, _instance, _event);
}
void start_offer_service(service_t _service, instance_t _instance,
major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR)
{
// std::lock_guard<std::mutex> its_lock(notify_mutex_);
app_->offer_service(_service, _instance, _major, _minor); // offer service (SD)
service_is_offered_ = true;
// notify_condition_.notify_one();
someip_log_i("Start offer service [0x%04x/0x%04x].",_service, _instance);
}
void stop_offer_service(service_t _service, instance_t _instance,
major_version_t _major = DEFAULT_MAJOR, minor_version_t _minor = DEFAULT_MINOR)
{
app_->stop_offer_service(_service, _instance, _major, _minor);
service_is_offered_ = false;
someip_log_w("Stop offer service [0x%04x/0x%04x].",_service, _instance);
}
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"));
if (_state == state_type_e::ST_REGISTERED)
{
if (!is_registered_)
{
is_registered_ = true;
//condition_.notify_one();
}
}
else
{
is_registered_ = false;
}
}
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
/*
* Handle signal to shutdown
*/
void stop()
{
running_ = false;
//condition_.notify_one();
//notify_condition_.notify_one();
app_->clear_all_handler();
//notify_thread_.join();
for (auto &th: notify_threads_)th.join();
app_->stop();
someip_log_w("Service app stopped.");
}
#endif
private:
std::shared_ptr<application> app_;
bool is_registered_;
//std::mutex mutex_;
//std::condition_variable condition_;
bool running_;
//std::mutex notify_mutex_;
//std::condition_variable notify_condition_;
bool service_is_offered_;
//std::mutex payload_mutex_;
//std::shared_ptr<payload> payload_;
// blocked_ / service_is_offered_ must be initialized before starting the threads!
// std::thread offer_thread_;
// std::thread notify_thread_;
std::vector<std::thread> notify_threads_;
};
#endif // SOMEIP_SERVER_HPP

View File

@@ -0,0 +1,174 @@
/*============================================================================*/
/* Copyright (C) huaxu (2026).
*
* All rights reserved. This software is huaxu property. Duplication
* or disclosure without huaxu written authorization is prohibited.
*
* @file someip_server_cfg.hpp
* @brief head file of someip ids
* @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 SOMEIP_SERVER_CFG_HPP
#define SOMEIP_SERVER_CFG_HPP
/*=======[I N C L U D E S]====================================================*/
#include "someip_server.hpp"
/*=======[M A C R O S]========================================================*/
/*--- TOOLS GENERATE BEGIN ---*/
#define VSOMEIP_CONFIGURATION "/etc/vsomeip/tbox_service.json"
#define APP_NAME "my_app"
#define USE_TCP (1u)
#define USE_UDP (2u)
#define USE_PROTOCAL USE_TCP
#define USE_STATIC_ROUTING false
#define OFFER_F_F_METHOD false
#define OFFER_R_R_METHOD true
#define OFFER_SETTER true
#define OFFER_GETTER true
#define OFFER_EVENT true
/* These IDs is just an example, please refer to SomeIp Matrix */
/* ServiceID */
#define S_SYSTEM_SERVER_ID 0x0001
#define S_SYSTEM_INSTANCE_ID 0x0001
#define S_AC_SERVER_ID 0x0002
#define S_AC_INSTANCE_ID 0x0001
#define S_CAN_SERVER_ID 0x0005
#define S_CAN_INSTANCE_ID 0x0001
#define R_SYSTEM_SERVER_ID 0x8001
#define R_SYSTEM_INSTANCE_ID 0x0001
#define R_AC_SERVER_ID 0x8002
#define R_AC_INSTANCE_ID 0x0001
/* MethodID */
#define RR_METHOD_EXAMPLE1 0x0001
#define RR_METHOD_EXAMPLE2 0x0002
#define FF_METHOD_EXAMPLE1 0x1001
#define FF_METHOD_EXAMPLE2 0x1002
#define GETTER_EXAMPLE1 0x2001
#define GETTER_EXAMPLE2 0x2002
#define SETTER_EXAMPLE1 0x3001
#define SETTER_EXAMPLE2 0x3002
#define EVENT_EXAMPLE1 0x4001
#define EVENT_EXAMPLE2 0x4002
#define EVENTGROUP_EXAMPLE1 0x0001
#define NOTIFIER_EXAMPLE1 0x5001
#define NOTIFIER_EXAMPLE2 0x5002
#define EVENTGROUP_EXAMPLE2 0x0002
#define NOTIFIER_CAN0 0x0000
#define NOTIFIER_CAN1 0x0001
#define NOTIFIER_CAN2 0x0002
#define NOTIFIER_CAN3 0x0003
#define NOTIFIER_CAN4 0x0004
#define NOTIFIER_CAN5 0x0005
#define EVENTGROUP_CAN 0x0005
/*=======[P A R A M T Y P E D E F]==========================================*/
/*=======[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]============*/
#if 0
extern std::vector<byte_t> rr_method_example1(void);
extern std::vector<byte_t> rr_method_example2(void);
extern std::vector<byte_t> ff_method_example1(void);
extern std::vector<byte_t> ff_method_example2(void);
extern std::vector<byte_t> getter_example1(void);
extern std::vector<byte_t> getter_example2(void);
extern std::vector<byte_t> setter_example1(void);
extern std::vector<byte_t> setter_example2(void);
extern std::vector<byte_t> event_example1(void);
extern std::vector<byte_t> event_example2(void);
#endif
extern std::vector<byte_t> notifier_can0(void);
extern std::vector<byte_t> notifier_can1(void);
extern std::vector<byte_t> notifier_can2(void);
extern std::vector<byte_t> notifier_can3(void);
extern std::vector<byte_t> notifier_can4(void);
extern std::vector<byte_t> notifier_can5(void);
extern std::vector<byte_t> notifier_example2(void);
extern bool epsilon_func(std::shared_ptr<vsomeip::payload> _old, std::shared_ptr<vsomeip::payload> _new);
// my_servers
inline std::vector<offer_service_t> my_servers = {
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, DEFAULT_MAJOR, DEFAULT_MINOR}
//,{S_AC_SERVER_ID, S_AC_INSTANCE_ID, DEFAULT_MAJOR, DEFAULT_MINOR}
};
#if 0
// R/R Methods /* usage eg: receive action */
inline std::vector<offer_method_t> offer_rr_methods = {
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, RR_METHOD_EXAMPLE1, message_type_e::MT_REQUEST, &rr_method_example1},
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, RR_METHOD_EXAMPLE2, message_type_e::MT_REQUEST, &rr_method_example2}
};
// F/F Methods /* usage eg: receive action without respons */
inline std::vector<offer_method_t> offer_ff_methods = {
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, FF_METHOD_EXAMPLE1, message_type_e::MT_REQUEST_NO_RETURN, &ff_method_example1},
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, FF_METHOD_EXAMPLE2, message_type_e::MT_REQUEST_NO_RETURN, &ff_method_example2}
};
// Getter /* usage eg: for client get infomation */
inline std::vector<offer_method_t> offer_getters = {
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, GETTER_EXAMPLE1, message_type_e::MT_REQUEST, &getter_example1},
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, GETTER_EXAMPLE2, message_type_e::MT_REQUEST, &getter_example2}
};
// Setter /* usage eg: for client set infomation */
inline std::vector<offer_method_t> offer_setters = {
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, SETTER_EXAMPLE1, message_type_e::MT_REQUEST, &setter_example1},
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, SETTER_EXAMPLE2, message_type_e::MT_REQUEST, &setter_example2}
};
// Event /* usage eg: offer event massage */
inline std::vector<offer_event_t> offer_events = {
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, EVENTGROUP_EXAMPLE1,
EVENT_EXAMPLE1, event_type_e::ET_EVENT, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_UNRELIABLE, &event_example1},
{S_SYSTEM_SERVER_ID, S_SYSTEM_INSTANCE_ID, EVENTGROUP_EXAMPLE1,
EVENT_EXAMPLE2, event_type_e::ET_EVENT, 1000U, false, true, /* cycle */
&epsilon_func, reliability_type_e::RT_UNRELIABLE, &event_example2}
};
#endif
// Notifier /* usage eg: offer event massage (with initial state))*/
inline std::vector<offer_event_t> offer_notifiers = {
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN0, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_UNRELIABLE, &notifier_can0},
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN1, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_RELIABLE, &notifier_can1},
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN2, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_RELIABLE, &notifier_can2},
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN3, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_RELIABLE, &notifier_can3},
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN4, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_RELIABLE, &notifier_can4},
{S_CAN_SERVER_ID, S_CAN_INSTANCE_ID, EVENTGROUP_CAN,
NOTIFIER_CAN5, event_type_e::ET_FIELD, 0U, false, true, /* active on change */
&epsilon_func, reliability_type_e::RT_RELIABLE, &notifier_can5}
};
/*--- TOOLS GENERATE END ---*/
#endif // SOMEIP_SERVER_CFG_HPP

View File

@@ -0,0 +1,428 @@
/*==================================================================================================
* Project : S32K3_miniEvb
* Platform : CORTEXM
* Peripheral : S32K3XX
* Dependencies : spi_protocol.h
*
* Autosar Version : 4.7.0
* Autosar Revision : ASR_REL_4_7_REV_0000
* Autosar Conf.Variant :
* SW Version : 0.1.0
* Build Version :
*
* Copyright 2026 - 20xx HuaXu
*
* HuaXu Confidential. This software is owned or controlled by HuaXu and may only be
* used strictly in accordance with the applicable license terms. By expressly
* accepting such terms or by downloading, installing, activating and/or otherwise
* using the software, you are agreeing that you have read, and that you agree to
* comply with and are bound by, such license terms. If you do not agree to be
* bound by the applicable license terms, then you may not retain, install,
* activate or otherwise use the software.
==================================================================================================*/
/*==================================================================================================
* File version history:
* 0.1.0 initial version
==================================================================================================*/
/**
* @file spi_protocol.c
* @version 0.1.0
* @brief SPI Protocol v2.0 — 组包/解包实现
*
* 帧结构 (Big Endian):
* ┌──────┬──────┬──────┬────────┬──────────┬─────┬────────┬─────~──────┬───────┬──────┬──────────┐
* │ SOF │ Ver │FType │ Seq │Timestamp │PktCnt│TotalLen│ TLVs... │ CRC16 │ EOF │ 0x00... │
* │ 1B │ 1B │ 1B │ 2B │ 4B │ 1B │ 2B │ variable │ 2B │ 1B │ pad │
* └──────┴──────┴──────┴────────┴──────────┴─────┴────────┴─────~──────┴───────┴──────┴──────────┘
* ↑ ↑
* └──── CRC 计算范围 ───────────────┘
* (HEAD + TLVs, 不含 SOF/EOF/Padding)
*
* @addtogroup SPI
* @{
*/
/*==================================================================================================
INCLUDE FILES
==================================================================================================*/
#include "spi_protocol.hpp"
#include <string.h>
/*==================================================================================================
LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
static void SpiProtocol_WriteBe16(uint8_t *buf, uint16_t val);
static void SpiProtocol_WriteBe32(uint8_t *buf, uint32_t val);
static uint16_t SpiProtocol_ReadBe16(const uint8_t *buf);
static uint32_t SpiProtocol_ReadBe32(const uint8_t *buf);
/*==================================================================================================
LOCAL FUNCTION DEFINITIONS
==================================================================================================*/
/**
* @brief 写入 16 位大端值
*/
static void SpiProtocol_WriteBe16(uint8_t *buf, uint16_t val)
{
buf[0] = (uint8_t)((val >> 8) & 0xFFu);
buf[1] = (uint8_t)(val & 0xFFu);
}
/**
* @brief 写入 32 位大端值
*/
static void SpiProtocol_WriteBe32(uint8_t *buf, uint32_t val)
{
buf[0] = (uint8_t)((val >> 24) & 0xFFu);
buf[1] = (uint8_t)((val >> 16) & 0xFFu);
buf[2] = (uint8_t)((val >> 8) & 0xFFu);
buf[3] = (uint8_t)(val & 0xFFu);
}
/**
* @brief 读取 16 位大端值
*/
static uint16_t SpiProtocol_ReadBe16(const uint8_t *buf)
{
return (uint16_t)(((uint16_t)buf[0] << 8) | (uint16_t)buf[1]);
}
/**
* @brief 读取 32 位大端值
*/
static uint32_t SpiProtocol_ReadBe32(const uint8_t *buf)
{
return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[2] << 8) | (uint32_t)buf[3];
}
/*==================================================================================================
GLOBAL FUNCTION DEFINITIONS
==================================================================================================*/
/**
* @brief CRC-16/XMODEM 查表(多项式 0x1021初始值 0x0000不取反
* @note 如需 CRC-16/CCITT初始 0xFFFF修改 crc 初值即可
*/
uint16_t SpiProtocol_CalcCrc16(const uint8_t *data, uint16_t len)
{
static const uint16_t crc_table[256] =
{
0x0000u, 0x1021u, 0x2042u, 0x3063u, 0x4084u, 0x50A5u, 0x60C6u, 0x70E7u,
0x8108u, 0x9129u, 0xA14Au, 0xB16Bu, 0xC18Cu, 0xD1ADu, 0xE1CEu, 0xF1EFu,
0x1231u, 0x0210u, 0x3273u, 0x2252u, 0x52B5u, 0x4294u, 0x72F7u, 0x62D6u,
0x9339u, 0x8318u, 0xB37Bu, 0xA35Au, 0xD3BDu, 0xC39Cu, 0xF3FFu, 0xE3DEu,
0x2462u, 0x3443u, 0x0420u, 0x1401u, 0x64E6u, 0x74C7u, 0x44A4u, 0x5485u,
0xA56Au, 0xB54Bu, 0x8528u, 0x9509u, 0xE5EEu, 0xF5CFu, 0xC5ACu, 0xD58Du,
0x3653u, 0x2672u, 0x1611u, 0x0630u, 0x76D7u, 0x66F6u, 0x5695u, 0x46B4u,
0xB75Bu, 0xA77Au, 0x9719u, 0x8738u, 0xF7DFu, 0xE7FEu, 0xD79Du, 0xC7BCu,
0x48C4u, 0x58E5u, 0x6886u, 0x78A7u, 0x0840u, 0x1861u, 0x2802u, 0x3823u,
0xC9CCu, 0xD9EDu, 0xE98Eu, 0xF9AFu, 0x8948u, 0x9969u, 0xA90Au, 0xB92Bu,
0x5AF5u, 0x4AD4u, 0x7AB7u, 0x6A96u, 0x1A71u, 0x0A50u, 0x3A33u, 0x2A12u,
0xDBFDu, 0xCBDCu, 0xFBBFu, 0xEB9Eu, 0x9B79u, 0x8B58u, 0xBB3Bu, 0xAB1Au,
0x6CA6u, 0x7C87u, 0x4CE4u, 0x5CC5u, 0x2C22u, 0x3C03u, 0x0C60u, 0x1C41u,
0xEDAEu, 0xFD8Fu, 0xCDECu, 0xDDCDu, 0xAD2Au, 0xBD0Bu, 0x8D68u, 0x9D49u,
0x7E97u, 0x6EB6u, 0x5ED5u, 0x4EF4u, 0x3E13u, 0x2E32u, 0x1E51u, 0x0E70u,
0xFF9Fu, 0xEFBEu, 0xDFDDu, 0xCFFCu, 0xBF1Bu, 0xAF3Au, 0x9F59u, 0x8F78u,
0x9188u, 0x81A9u, 0xB1CAu, 0xA1EBu, 0xD10Cu, 0xC12Du, 0xF14Eu, 0xE16Fu,
0x1080u, 0x00A1u, 0x30C2u, 0x20E3u, 0x5004u, 0x4025u, 0x7046u, 0x6067u,
0x83B9u, 0x9398u, 0xA3FBu, 0xB3DAu, 0xC33Du, 0xD31Cu, 0xE37Fu, 0xF35Eu,
0x02B1u, 0x1290u, 0x22F3u, 0x32D2u, 0x4235u, 0x5214u, 0x6277u, 0x7256u,
0xB5EAu, 0xA5CBu, 0x95A8u, 0x8589u, 0xF56Eu, 0xE54Fu, 0xD52Cu, 0xC50Du,
0x34E2u, 0x24C3u, 0x14A0u, 0x0481u, 0x7466u, 0x6447u, 0x5424u, 0x4405u,
0xA7DBu, 0xB7FAu, 0x8799u, 0x97B8u, 0xE75Fu, 0xF77Eu, 0xC71Du, 0xD73Cu,
0x26D3u, 0x36F2u, 0x0691u, 0x16B0u, 0x6657u, 0x7676u, 0x4615u, 0x5634u,
0xD94Cu, 0xC96Du, 0xF90Eu, 0xE92Fu, 0x99C8u, 0x89E9u, 0xB98Au, 0xA9ABu,
0x5844u, 0x4865u, 0x7806u, 0x6827u, 0x18C0u, 0x08E1u, 0x3882u, 0x28A3u,
0xCB7Du, 0xDB5Cu, 0xEB3Fu, 0xFB1Eu, 0x8BF9u, 0x9BD8u, 0xABBBu, 0xBB9Au,
0x4A75u, 0x5A54u, 0x6A37u, 0x7A16u, 0x0AF1u, 0x1AD0u, 0x2AB3u, 0x3A92u,
0xFD2Eu, 0xED0Fu, 0xDD6Cu, 0xCD4Du, 0xBDAAu, 0xAD8Bu, 0x9DE8u, 0x8DC9u,
0x7C26u, 0x6C07u, 0x5C64u, 0x4C45u, 0x3CA2u, 0x2C83u, 0x1CE0u, 0x0CC1u,
0xEF1Fu, 0xFF3Eu, 0xCF5Du, 0xDF7Cu, 0xAF9Bu, 0xBFBAu, 0x8FD9u, 0x9FF8u,
0x6E17u, 0x7E36u, 0x4E55u, 0x5E74u, 0x2E93u, 0x3EB2u, 0x0ED1u, 0x1EF0u
};
uint16_t crc = 0x0000u;
uint16_t i;
for (i = 0u; i < len; i++)
{
crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)((crc >> 8) ^ data[i])]);
}
return crc;
}
/*==================================================================================================
* SpiProtocol_Pack — 组包
*==================================================================================================*/
int32_t SpiProtocol_Pack(uint8_t *frame, uint16_t frame_size,
SpiProtocol_FrameType frame_type, uint16_t seq, uint32_t timestamp,
const SpiProtocol_TlvType *tlvs, uint8_t tlv_count)
{
uint16_t total_len = 0u;
uint16_t payload_bytes;
uint16_t crc_offset;
uint16_t crc_val;
uint8_t i;
uint16_t offset;
/*———— 参数校验 ————*/
if ((frame == NULL) || ((tlvs == NULL) && (tlv_count > 0u)))
{
return SPI_PROTO_ERR_PARAM;
}
if ((frame_size != SPI_PROTO_FRAME_64) &&
(frame_size != SPI_PROTO_FRAME_128) &&
(frame_size != SPI_PROTO_FRAME_256) &&
(frame_size != SPI_PROTO_FRAME_512) &&
(frame_size != SPI_PROTO_FRAME_1024))
{
return SPI_PROTO_ERR_SIZE;
}
if (tlv_count > SPI_PROTO_MAX_TLV_COUNT)
{
return SPI_PROTO_ERR_PKTCOUNT_OVF;
}
/* 计算 TotalLen所有 TLV value 长度之和) */
for (i = 0u; i < tlv_count; i++)
{
total_len = (uint16_t)(total_len + tlvs[i].length);
}
/* Payload 总字节数 = PacketCount * 4 + TotalLen */
payload_bytes = (uint16_t)((uint16_t)tlv_count * SPI_PROTO_TLV_HEAD_LEN) + total_len;
/* 检查是否超出帧容量 */
if (payload_bytes > (uint16_t)(frame_size - SPI_PROTO_OVERHEAD))
{
return SPI_PROTO_ERR_TOTALLEN_OVF;
}
/*———— 写入帧 ————*/
(void)memset(frame, 0x00u, frame_size);
/* SOF */
frame[0] = SPI_PROTO_SOF;
/* HEAD从偏移 1 开始) */
frame[1] = SPI_PROTO_VERSION; /* Version */
frame[2] = frame_type; /* FrameType */
SpiProtocol_WriteBe16(&frame[3], seq); /* Seq */
SpiProtocol_WriteBe32(&frame[5], timestamp); /* Timestamp */
frame[9] = tlv_count; /* PacketCount */
SpiProtocol_WriteBe16(&frame[10], total_len); /* TotalLen */
/* Payload — 逐 TLV 写入 */
offset = SPI_PROTO_OVERHEAD - 1u; /* 11 + 4 - 1 = offset of first TLV after SOF+HEAD = offset 11 */
/* 实际上 SOF(1) + HEAD(11) = 12 字节在 SOF+HEAD 区域Payload 从 offset 110-based开始 */
/* offset 11 = SOF(1) + HEAD(11) */
offset = 1u + SPI_PROTO_HEAD_LEN; /* = 12 */
for (i = 0u; i < tlv_count; i++)
{
frame[offset] = tlvs[i].service_id;
frame[offset + 1u] = tlvs[i].method_id;
SpiProtocol_WriteBe16(&frame[offset + 2u], tlvs[i].length);
offset = (uint16_t)(offset + SPI_PROTO_TLV_HEAD_LEN);
if (tlvs[i].length > 0u)
{
(void)memcpy(&frame[offset], tlvs[i].value, tlvs[i].length);
offset = (uint16_t)(offset + tlvs[i].length);
}
}
/* CRC16 — 计算 HEAD + Payload */
crc_offset = offset; /* offset 当前指向 CRC 写入位置 */
crc_val = SpiProtocol_CalcCrc16(&frame[1], (uint16_t)(crc_offset - 1u));
SpiProtocol_WriteBe16(&frame[crc_offset], crc_val);
offset = (uint16_t)(crc_offset + 2u);
/* EOF */
frame[offset] = SPI_PROTO_EOF;
/* offset = (uint16_t)(offset + 1u); — padding 已在 memset 中填充 */
/* 返回帧长(= frame_size已 memset 填充 0x00 至末尾) */
return (int32_t)frame_size;
}
/*==================================================================================================
* SpiProtocol_Unpack — 解包
*==================================================================================================*/
int32_t SpiProtocol_Unpack(const uint8_t *frame, uint16_t frame_len,
uint16_t frame_size,
SpiProtocol_RxResultType *result)
{
uint16_t calc_crc;
uint16_t recv_crc;
uint16_t total_len;
uint8_t packet_count;
SpiProtocol_FrameType frame_type;
uint16_t seq;
uint32_t timestamp;
uint16_t offset;
uint16_t min_frame_len;
uint16_t payload_bytes;
uint16_t crc_pos;
uint16_t eof_pos;
uint8_t i;
uint16_t t;
/*———— 参数校验 ————*/
if ((frame == NULL) || (result == NULL))
{
return SPI_PROTO_ERR_PARAM;
}
/* 帧至少要有 SOF + HEAD + CRC + EOF = 15 字节 */
min_frame_len = SPI_PROTO_OVERHEAD;
if (frame_len < min_frame_len)
{
return SPI_PROTO_ERR_FRAME_SHORT;
}
/* SOF 校验 */
if (frame[0] != SPI_PROTO_SOF)
{
return SPI_PROTO_ERR_SOF_MISMATCH;
}
/* Version 校验 */
if (frame[1] != SPI_PROTO_VERSION)
{
return SPI_PROTO_ERR_VERSION_MISMATCH;
}
/* 解析 HEAD 字段 */
frame_type = (SpiProtocol_FrameType)frame[2];
seq = SpiProtocol_ReadBe16(&frame[3]);
timestamp = SpiProtocol_ReadBe32(&frame[5]);
packet_count = frame[9];
total_len = SpiProtocol_ReadBe16(&frame[10]);
/* PacketCount 校验 */
if (packet_count > SPI_PROTO_MAX_TLV_COUNT)
{
return SPI_PROTO_ERR_PKTCOUNT_OVF;
}
/* 计算 Payload 字节数 */
payload_bytes = (uint16_t)((uint16_t)packet_count * SPI_PROTO_TLV_HEAD_LEN) + total_len;
/* 计算 CRC / EOF 位置 */
crc_pos = (uint16_t)(1u + SPI_PROTO_HEAD_LEN + payload_bytes);
eof_pos = (uint16_t)(crc_pos + 2u);
/* 检查帧长度是否足够 */
if ((uint16_t)(eof_pos + 1u) > frame_len)
{
return SPI_PROTO_ERR_FRAME_SHORT;
}
/* EOF 校验 */
if (frame[eof_pos] != SPI_PROTO_EOF)
{
return SPI_PROTO_ERR_EOF_MISMATCH;
}
/* CRC 校验 */
recv_crc = SpiProtocol_ReadBe16(&frame[crc_pos]);
calc_crc = SpiProtocol_CalcCrc16(&frame[1], crc_pos - 1u);
if (recv_crc != calc_crc)
{
return SPI_PROTO_ERR_CRC_MISMATCH;
}
/* Padding 校验EOF 之后到 frame_len 或 frame_size 必须是 0x00 */
{
uint16_t pad_end = (frame_size > 0u) ? frame_size : frame_len;
if (pad_end > (uint16_t)(eof_pos + 1u))
{
for (t = (uint16_t)(eof_pos + 1u); t < pad_end; t++)
{
if (t < frame_len)
{
if (frame[t] != 0x00u)
{
return SPI_PROTO_ERR_PADDING_NZ;
}
}
}
}
}
/*———— 填充结果 ————*/
result->frame_type = frame_type;
result->seq = seq;
result->timestamp = timestamp;
result->tlv_count = packet_count;
result->nack_error_code = 0u;
/* 解析 TLV */
offset = 1u + SPI_PROTO_HEAD_LEN; /* 跳过 SOF + HEAD */
for (i = 0u; i < packet_count; i++)
{
result->tlvs[i].service_id = frame[offset];
result->tlvs[i].method_id = frame[offset + 1u];
result->tlvs[i].length = SpiProtocol_ReadBe16(&frame[offset + 2u]);
result->tlvs[i].value = &frame[offset + SPI_PROTO_TLV_HEAD_LEN];
offset = (uint16_t)(offset + SPI_PROTO_TLV_HEAD_LEN + result->tlvs[i].length);
}
/* 如果是 NACK 帧,提取错误码 */
if ((frame_type == SPI_PROTO_FRAME_NACK) && (packet_count == 1u))
{
if ((result->tlvs[0].service_id == SPI_PROTO_SID_ERROR) &&
(result->tlvs[0].length >= 1u))
{
result->nack_error_code = result->tlvs[0].value[0];
}
}
return (int32_t)packet_count;
}
/*==================================================================================================
* SpiProtocol_PackAck — 构造 ACK 帧
*==================================================================================================*/
int32_t SpiProtocol_PackAck(uint8_t *frame, uint16_t frame_size, uint16_t ack_seq)
{
/* ACK: FrameType=ACK, PacketCount=0, TotalLen=0, 无 TLV */
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_ACK, ack_seq, 0u,
NULL, 0u);
}
/*==================================================================================================
* SpiProtocol_PackNack — 构造 NACK 帧
*==================================================================================================*/
int32_t SpiProtocol_PackNack(uint8_t *frame, uint16_t frame_size,
uint16_t ack_seq, uint8_t error_code)
{
SpiProtocol_TlvType tlv;
tlv.service_id = SPI_PROTO_SID_ERROR;
tlv.method_id = 0x00u;
tlv.length = 1u;
tlv.value = &error_code;
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_NACK, ack_seq, 0u,
&tlv, 1u);
}
/*==================================================================================================
* SpiProtocol_PackHeartbeat — 构造心跳帧
*==================================================================================================*/
int32_t SpiProtocol_PackHeartbeat(uint8_t *frame, uint16_t frame_size, uint16_t seq)
{
return SpiProtocol_Pack(frame, frame_size,
SPI_PROTO_FRAME_HEARTBEAT, seq, 0u,
NULL, 0u);
}
/** @} */

View File

@@ -0,0 +1,243 @@
/*==================================================================================================
* Project : S32K3_miniEvb
* Platform : CORTEXM
* Peripheral : S32K3XX
* Dependencies : none
*
* Autosar Version : 4.7.0
* Autosar Revision : ASR_REL_4_7_REV_0000
* Autosar Conf.Variant :
* SW Version : 0.1.0
* Build Version :
*
* Copyright 2026 - 20xx HuaXu
*
* HuaXu Confidential. This software is owned or controlled by HuaXu and may only be
* used strictly in accordance with the applicable license terms. By expressly
* accepting such terms or by downloading, installing, activating and/or otherwise
* using the software, you are agreeing that you have read, and that you agree to
* comply with and are bound by, such license terms. If you do not agree to be
* bound by the applicable license terms, then you may not retain, install,
* activate or otherwise use the software.
==================================================================================================*/
/*==================================================================================================
* File version history:
* 0.1.0 initial version
==================================================================================================*/
/**
* @file spi_protocol.hpp
* @version 0.1.0
* @brief SPI Protocol v2.0 — SOC/MCU 通信组包/解包
*
* @addtogroup SPI
* @{
*/
#ifndef SPI_PROTOCOL_HPP
#define SPI_PROTOCOL_HPP
#ifdef __cplusplus
extern "C"{
#endif
/*==================================================================================================
INCLUDE FILES
==================================================================================================*/
#include <stdint.h>
/*==================================================================================================
CONSTANTS
==================================================================================================*/
/* 帧固定字段 */
#define SPI_PROTO_SOF 0xAAu
#define SPI_PROTO_EOF 0x55u
#define SPI_PROTO_VERSION 0x01u
/* 帧长配置4 选 1 */
#define SPI_PROTO_FRAME_64 64u
#define SPI_PROTO_FRAME_128 128u
#define SPI_PROTO_FRAME_256 256u
#define SPI_PROTO_FRAME_512 512u
#define SPI_PROTO_FRAME_1024 1024u
/* 默认帧长 */
#define SPI_PROTO_FRAME_SIZE SPI_PROTO_FRAME_128
/* HEAD 长度 = Version(1) + FrameType(1) + Seq(2) + Timestamp(4) + PacketCount(1) + TotalLen(2) */
#define SPI_PROTO_HEAD_LEN 11u
/* 帧开销 = SOF(1) + HEAD(11) + CRC16(2) + EOF(1) */
#define SPI_PROTO_OVERHEAD 15u
/* 最大 Payload 字节数 */
#define SPI_PROTO_MAX_PAYLOAD (SPI_PROTO_FRAME_SIZE - SPI_PROTO_OVERHEAD)
/* 最大 TLV 数量 */
#define SPI_PROTO_MAX_TLV_COUNT 16u
/* TLV 头部长度 = ServiceID(1) + MethodID(1) + Length(2) */
#define SPI_PROTO_TLV_HEAD_LEN 4u
/* ——— FrameType ——— */
typedef enum
{
SPI_PROTO_FRAME_DATA = 0x00u, /* MCU→SOC 常规上报 */
SPI_PROTO_FRAME_CTRL = 0x01u, /* SOC→MCU 控制/配置 */
SPI_PROTO_FRAME_ACK = 0x02u, /* 通用确认 */
SPI_PROTO_FRAME_NACK = 0x03u, /* 错误应答 */
SPI_PROTO_FRAME_HEARTBEAT = 0x04u /* 心跳 */
} SpiProtocol_FrameType;
/* ——— ServiceID ——— */
#define SPI_PROTO_SID_SYSTEM 0x01u
#define SPI_PROTO_SID_AC 0x02u
#define SPI_PROTO_SID_KEY 0x03u
#define SPI_PROTO_SID_VEHICLE 0x04u
#define SPI_PROTO_SID_CAN 0x05u
#define SPI_PROTO_SID_UPDATE 0x06u
#define SPI_PROTO_SID_CLUSTER 0x07u
#define SPI_PROTO_SID_LOG 0x08u
#define SPI_PROTO_SID_TEST 0x09u
#define SPI_PROTO_SID_DIAG 0x0Au
#define SPI_PROTO_SID_PASS 0x0Bu
#define SPI_PROTO_SID_AUDIO 0x0Cu
#define SPI_PROTO_SID_AVM 0x0Du
#define SPI_PROTO_SID_BSD 0x0Eu
#define SPI_PROTO_SID_DMS 0x0Fu
#define SPI_PROTO_SID_ADAS 0x10u
#define SPI_PROTO_SID_THEME 0x11u
#define SPI_PROTO_SID_POWERMANAGER 0x12u
#define SPI_PROTO_SID_RVC 0x13u
#define SPI_PROTO_SID_ERROR 0xFEu /* NACK 错误信息 */
/* ——— NACK 错误码 ——— */
#define SPI_PROTO_ERR_NONE 0x00u
#define SPI_PROTO_ERR_CRC 0x01u
#define SPI_PROTO_ERR_VERSION 0x02u
#define SPI_PROTO_ERR_SOF 0x03u
#define SPI_PROTO_ERR_EOF 0x04u
#define SPI_PROTO_ERR_TOTALLEN 0x05u
#define SPI_PROTO_ERR_TLV_PARSE 0x06u
#define SPI_PROTO_ERR_PKTCOUNT 0x07u
#define SPI_PROTO_ERR_FRAMETYPE 0x08u
#define SPI_PROTO_ERR_PADDING 0x09u
#define SPI_PROTO_ERR_TRUNCATED 0x0Au
/* ——— 解包返回码 ——— */
#define SPI_PROTO_OK 0
#define SPI_PROTO_ERR_PARAM (-1)
#define SPI_PROTO_ERR_SIZE (-2)
#define SPI_PROTO_ERR_SOF_MISMATCH (-3)
#define SPI_PROTO_ERR_EOF_MISMATCH (-4)
#define SPI_PROTO_ERR_CRC_MISMATCH (-5)
#define SPI_PROTO_ERR_VERSION_MISMATCH (-6)
#define SPI_PROTO_ERR_TOTALLEN_OVF (-7)
#define SPI_PROTO_ERR_PKTCOUNT_OVF (-8)
#define SPI_PROTO_ERR_TLV_TRUNC (-9)
#define SPI_PROTO_ERR_PADDING_NZ (-10)
#define SPI_PROTO_ERR_FRAME_SHORT (-11)
/*==================================================================================================
TYPEDEFS
==================================================================================================*/
/**
* @brief TLV 子包描述
* @note value 指针由调用方管理,组包时指向待发送数据,解包时指向 frame 内数据
*/
typedef struct
{
uint8_t service_id; /**< 业务大类 */
uint8_t method_id; /**< 业务子类 */
uint16_t length; /**< Value 字节数(不含 T+L */
const uint8_t *value; /**< Value 数据指针 */
} SpiProtocol_TlvType;
/**
* @brief 解包输出结果
*/
typedef struct
{
SpiProtocol_FrameType frame_type; /**< 帧类型 */
uint16_t seq; /**< 帧序号 */
uint32_t timestamp; /**< 时间戳 (ms) */
uint8_t tlv_count; /**< 实际 TLV 数量 */
SpiProtocol_TlvType tlvs[SPI_PROTO_MAX_TLV_COUNT]; /**< TLV 列表 */
uint8_t nack_error_code; /**< NACK 帧时有效 */
} SpiProtocol_RxResultType;
/*==================================================================================================
GLOBAL FUNCTION PROTOTYPES
==================================================================================================*/
/**
* @brief 计算 CRC16HEAD + Payload 范围)
* @param data 数据起始指针(指向 HEAD 首字节 Version
* @param len 数据长度
* @return CRC16 值
*/
uint16_t SpiProtocol_CalcCrc16(const uint8_t *data, uint16_t len);
/**
* @brief 组包:将 TLV 列表打包为完整帧
* @param frame 输出帧缓冲区(调用方分配,大小 ≥ SPI_PROTO_FRAME_SIZE
* @param frame_size 帧长配置128/256/512/1024
* @param frame_type 帧类型
* @param seq 帧序号
* @param timestamp 时间戳 (ms)
* @param tlvs TLV 数组
* @param tlv_count TLV 数量
* @return >=0: 实际帧字节数(= frame_size; <0: 错误码
*/
int32_t SpiProtocol_Pack(uint8_t *frame, uint16_t frame_size,
SpiProtocol_FrameType frame_type, uint16_t seq, uint32_t timestamp,
const SpiProtocol_TlvType *tlvs, uint8_t tlv_count);
/**
* @brief 解包:解析接收帧,输出 TLV 列表
* @param frame 接收帧缓冲区
* @param frame_len 接收数据长度
* @param frame_size 预期帧长配置128/256/512/1024
* @param result 输出解析结果
* @return >=0: 成功(返回 TLV 数量); <0: 错误码
*/
int32_t SpiProtocol_Unpack(const uint8_t *frame, uint16_t frame_len,
uint16_t frame_size,
SpiProtocol_RxResultType *result);
/**
* @brief 构造 ACK 帧(确认指定 seq 的帧)
* @param frame 输出帧缓冲区
* @param frame_size 帧长配置
* @param ack_seq 被确认帧的序号
* @return >=0: 实际帧字节数; <0: 错误码
*/
int32_t SpiProtocol_PackAck(uint8_t *frame, uint16_t frame_size, uint16_t ack_seq);
/**
* @brief 构造 NACK 帧
* @param frame 输出帧缓冲区
* @param frame_size 帧长配置
* @param ack_seq 被否定应答帧的序号
* @param error_code 错误码(见 SPI_PROTO_ERR_xxx
* @return >=0: 实际帧字节数; <0: 错误码
*/
int32_t SpiProtocol_PackNack(uint8_t *frame, uint16_t frame_size,
uint16_t ack_seq, uint8_t error_code);
/**
* @brief 构造心跳帧
* @param frame 输出帧缓冲区
* @param frame_size 帧长配置
* @param seq 帧序号
* @return >=0: 实际帧字节数; <0: 错误码
*/
int32_t SpiProtocol_PackHeartbeat(uint8_t *frame, uint16_t frame_size, uint16_t seq);
#ifdef __cplusplus
}
#endif
#endif /* SPI_PROTOCOL_HPP */
/** @} */

View File

@@ -0,0 +1,202 @@
//#include "someip_client.hpp"
//#include "someip_client_cfg.hpp"
#include "spi_server.hpp"
#include "spi_protocol.hpp"
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
// client *my_client_ptr(nullptr);
// void client_handle_signal(int _signal) {
// if (my_client_ptr != nullptr &&
// (_signal == SIGINT || _signal == SIGTERM
// || _signal == SIGKILL))
// my_client_ptr->stop();
// }
#endif
/*
* spi_slave_recv_loop.c - SPI从设备持续接收程序
*
* 功能SoC作为SPI从设备配置与MCU主设备对齐循环接收并打印数据
* MCU每秒发送一帧8字节
*
* MCU主设备配置需对齐
* Mode : SPI_MODE_0 (CPOL=0, CPHA=0)
* Bits/Word : 8
* Speed : 1 MHz
* 发送数据 : {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
*
* 编译aarch64-linux-gnu-gcc -o spi_slave_recv_loop spi_slave_recv_loop.c
* 运行:./spi_slave_recv_loop
* 退出:按 Ctrl+C
*/
#include <mutex>
#include <vector>
/* CAN 数据缓冲区 — SPI 线程写入notifier 线程读取 */
std::vector<uint8_t> g_can_data[CAN_CHANNEL_COUNT];
std::mutex g_can_mutex[CAN_CHANNEL_COUNT];
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
/* ========== SPI配置必须与MCU主设备完全一致========== */
#define SPI_DEVICE "/dev/spidev4.0"
#define SPI_MODE SPI_MODE_3 /* CPOL=1, CPHA=1 */
#define SPI_BITS 8
#define SPI_SPEED 1000000 /* 1MHz */
#define FRAME_LEN SPI_PROTO_FRAME_SIZE /* 每帧SPI_PROTO_FRAME_SIZE字节 */
/* ===================================================== */
static volatile int keep_running = 1;
void sigint_handler(int sig) {
(void)sig;
keep_running = 0;
printf("\n[INFO] User interrupted, exiting...\n");
}
void my_spi_server_thread_func(void* arg) {
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
// signal(SIGINT, client_handle_signal);
// signal(SIGTERM, client_handle_signal);
// signal(SIGKILL, client_handle_signal);
#endif
uint8_t buf[FRAME_LEN];
int fd, ret;
unsigned int frame_count = 0;
/* 注册退出信号 */
signal(SIGINT, sigint_handler);
/* 1. 打开 SPI 设备 */
fd = open(SPI_DEVICE, O_RDWR);
if (fd < 0) {
perror("open " SPI_DEVICE);
return;
}
/* 2. 配置 SPI 模式 */
uint8_t mode = SPI_MODE;
mode |= SPI_LSB_FIRST;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
perror("SPI_IOC_WR_MODE");
close(fd);
return;
}
/* 3. 配置每字位数 */
uint8_t bits = SPI_BITS;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
perror("SPI_IOC_WR_BITS_PER_WORD");
close(fd);
return;
}
/* 4. 配置最大时钟频率 */
uint32_t speed = SPI_SPEED;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
perror("SPI_IOC_WR_MAX_SPEED_HZ");
close(fd);
return;
}
/* 5. 回读验证配置 */
ioctl(fd, SPI_IOC_RD_MODE, &mode);
ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
printf("========================================\n");
printf("SPI Slave Config (aligned with MCU)\n");
printf("========================================\n");
printf("Device : %s\n", SPI_DEVICE);
printf("Mode : %d (CPOL=%d, CPHA=%d)\n",
mode, (mode & SPI_CPOL) ? 1 : 0, (mode & SPI_CPHA) ? 1 : 0);
printf("Bits/Word : %d\n", bits);
printf("Max Speed : %d Hz\n", speed);
printf("Frame length: %d bytes\n", FRAME_LEN);
printf("========================================\n");
printf("Waiting for MCU (master) to send data...\n");
printf("Press Ctrl+C to stop.\n\n");
/* 6. 循环接收数据 */
while (keep_running) {
memset(buf, 0, FRAME_LEN);
ret = read(fd, buf, FRAME_LEN);
if (ret < 0) {
perror("read");
break;
} else if (ret == 0) {
/* 非阻塞模式可能返回0但这里用了阻塞模式一般不会出现 */
//continue;
}
frame_count++;
printf("\n========== Frame #%u (%d bytes) ==========\n", frame_count, ret);
printf("HEX : ");
for (int i = 0; i < ret; i++)
printf("0x%02X ", buf[i]);
printf("\n");
printf("ASCII: ");
for (int i = 0; i < ret; i++)
printf(" %c ", (buf[i] >= 0x20 && buf[i] < 0x7F) ? buf[i] : '.');
printf("\n");
printf("DEC : ");
for (int i = 0; i < ret; i++)
printf("%3d ", buf[i]);
printf("\n");
printf("=========================================\n");
// 调用SpiProtocol_Unpack解析SPI数据
SpiProtocol_RxResultType result;
int32_t unpack_ret = SpiProtocol_Unpack(buf, sizeof(buf), SPI_PROTO_FRAME_SIZE, &result);
if (unpack_ret != SPI_PROTO_ERR_NONE)
{
printf("SpiProtocol_Unpack error: %d\n", unpack_ret);
continue;
}
printf("SpiProtocol_Unpack success\n");
// 处理解包后的数据:提取 CAN0~CAN5 数据分发到对应缓冲区
for (uint8_t i = 0; i < result.tlv_count; i++)
{
if (result.tlvs[i].service_id == SPI_PROTO_SID_CAN)
{
uint8_t can_ch = result.tlvs[i].method_id; /* method_id 对应 CAN0~CAN5 */
if (can_ch < CAN_CHANNEL_COUNT)
{
std::lock_guard<std::mutex> lock(g_can_mutex[can_ch]);
g_can_data[can_ch].assign(result.tlvs[i].value,
result.tlvs[i].value + result.tlvs[i].length);
printf("CAN%d data updated, length=%u\n", can_ch, result.tlvs[i].length);
}
else
{
printf("WARNING: CAN channel %u out of range (max %u)\n", can_ch, CAN_CHANNEL_COUNT - 1);
}
}
}
}
close(fd);
return;
}

View File

@@ -0,0 +1,119 @@
/*============================================================================*/
/* 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 SPI_SERVER_HPP
#define SPI_SERVER_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 <mutex>
#include <vector>
/*=======[M A C R O S]========================================================*/
#define CAN_CHANNEL_COUNT 6
#ifdef USE_LOG_MODULE
#include "log_mgt_api.h"
#ifdef LOG_TAG_SOMEIP
#undef LOG_TAG_SOMEIP
#endif
#define LOG_TAG_SOMEIP "spi_server"
#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 "spi_server"
#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]==========================================*/
/*=======[E X P O R T D A T A]==============================================*/
/* CAN 数据缓冲区 — SPI 线程写入notifier 线程读取 */
extern std::vector<uint8_t> g_can_data[CAN_CHANNEL_COUNT];
extern std::mutex g_can_mutex[CAN_CHANNEL_COUNT];
/*=======[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_spi_server_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]==========================*/
#endif // SPI_SERVER_HPP

BIN
source/spi_dev/spi4test Executable file

Binary file not shown.

139
source/spi_dev/spi4test.c Executable file
View File

@@ -0,0 +1,139 @@
/*
* spi_slave_recv_loop.c - SPI从设备持续接收程序
*
* 功能SoC作为SPI从设备配置与MCU主设备对齐循环接收并打印数据
* MCU每秒发送一帧8字节
*
* MCU主设备配置需对齐
* Mode : SPI_MODE_0 (CPOL=0, CPHA=0)
* Bits/Word : 8
* Speed : 1 MHz
* 发送数据 : {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
*
* 编译aarch64-linux-gnu-gcc -o spi_slave_recv_loop spi_slave_recv_loop.c
* 运行:./spi_slave_recv_loop
* 退出:按 Ctrl+C
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
/* ========== SPI配置必须与MCU主设备完全一致========== */
#define SPI_DEVICE "/dev/spidev4.0"
#define SPI_MODE SPI_MODE_0 /* CPOL=1, CPHA=1 */
#define SPI_BITS 8
#define SPI_SPEED 1000000 /* 1MHz */
#define FRAME_LEN 128 /* 每帧64字节 */
/* ===================================================== */
static volatile int keep_running = 1;
void sigint_handler(int sig) {
(void)sig;
keep_running = 0;
printf("\n[INFO] User interrupted, exiting...\n");
}
int main(void)
{
uint8_t buf[FRAME_LEN];
int fd, ret;
unsigned int frame_count = 0;
/* 注册退出信号 */
signal(SIGINT, sigint_handler);
/* 1. 打开 SPI 设备 */
fd = open(SPI_DEVICE, O_RDWR);
if (fd < 0) {
perror("open " SPI_DEVICE);
return 1;
}
/* 2. 配置 SPI 模式 */
uint8_t mode = SPI_MODE;
mode |= SPI_LSB_FIRST;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
perror("SPI_IOC_WR_MODE");
close(fd);
return 1;
}
/* 3. 配置每字位数 */
uint8_t bits = SPI_BITS;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
perror("SPI_IOC_WR_BITS_PER_WORD");
close(fd);
return 1;
}
/* 4. 配置最大时钟频率 */
uint32_t speed = SPI_SPEED;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1) {
perror("SPI_IOC_WR_MAX_SPEED_HZ");
close(fd);
return 1;
}
/* 5. 回读验证配置 */
ioctl(fd, SPI_IOC_RD_MODE, &mode);
ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
printf("========================================\n");
printf("SPI Slave Config (aligned with MCU)\n");
printf("========================================\n");
printf("Device : %s\n", SPI_DEVICE);
printf("Mode : %d (CPOL=%d, CPHA=%d)\n",
mode, (mode & SPI_CPOL) ? 1 : 0, (mode & SPI_CPHA) ? 1 : 0);
printf("Bits/Word : %d\n", bits);
printf("Max Speed : %d Hz\n", speed);
printf("Frame length: %d bytes\n", FRAME_LEN);
printf("========================================\n");
printf("Waiting for MCU (master) to send data...\n");
printf("Press Ctrl+C to stop.\n\n");
/* 6. 循环接收数据 */
while (keep_running) {
memset(buf, 0, FRAME_LEN);
ret = read(fd, buf, FRAME_LEN);
if (ret < 0) {
perror("read");
break;
} else if (ret == 0) {
/* 非阻塞模式可能返回0但这里用了阻塞模式一般不会出现 */
//continue;
}
frame_count++;
printf("\n========== Frame #%u (%d bytes) ==========\n", frame_count, ret);
printf("HEX : ");
for (int i = 0; i < ret; i++)
printf("0x%02X ", buf[i]);
printf("\n");
printf("ASCII: ");
for (int i = 0; i < ret; i++)
printf(" %c ", (buf[i] >= 0x20 && buf[i] < 0x7F) ? buf[i] : '.');
printf("\n");
printf("DEC : ");
for (int i = 0; i < ret; i++)
printf("%3d ", buf[i]);
printf("\n");
printf("=========================================\n");
}
close(fd);
return 0;
}