feat(soa_server):initial version of soa_server
This commit is contained in:
@@ -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
61
build_soa_server.sh
Executable 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.
BIN
install/soa_server/rk3576/soa_server
Executable file
BIN
install/soa_server/rk3576/soa_server
Executable file
Binary file not shown.
BIN
install/tmp/lib.zip
Normal file
BIN
install/tmp/lib.zip
Normal file
Binary file not shown.
1
install/tmp/lib/libboost_filesystem.so
Symbolic link
1
install/tmp/lib/libboost_filesystem.so
Symbolic link
@@ -0,0 +1 @@
|
||||
libboost_filesystem.so.1.75.0
|
||||
BIN
install/tmp/lib/libboost_filesystem.so.1.75.0
Executable file
BIN
install/tmp/lib/libboost_filesystem.so.1.75.0
Executable file
Binary file not shown.
1
install/tmp/lib/libboost_system.so
Symbolic link
1
install/tmp/lib/libboost_system.so
Symbolic link
@@ -0,0 +1 @@
|
||||
libboost_system.so.1.75.0
|
||||
BIN
install/tmp/lib/libboost_system.so.1.75.0
Executable file
BIN
install/tmp/lib/libboost_system.so.1.75.0
Executable file
Binary file not shown.
1
install/tmp/lib/libvsomeip3-cfg.so
Symbolic link
1
install/tmp/lib/libvsomeip3-cfg.so
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3-cfg.so.3
|
||||
1
install/tmp/lib/libvsomeip3-cfg.so.3
Symbolic link
1
install/tmp/lib/libvsomeip3-cfg.so.3
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3-cfg.so.3.7.3
|
||||
BIN
install/tmp/lib/libvsomeip3-cfg.so.3.7.3
Normal file
BIN
install/tmp/lib/libvsomeip3-cfg.so.3.7.3
Normal file
Binary file not shown.
1
install/tmp/lib/libvsomeip3-sd.so
Symbolic link
1
install/tmp/lib/libvsomeip3-sd.so
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3-sd.so.3
|
||||
1
install/tmp/lib/libvsomeip3-sd.so.3
Symbolic link
1
install/tmp/lib/libvsomeip3-sd.so.3
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3-sd.so.3.7.3
|
||||
BIN
install/tmp/lib/libvsomeip3-sd.so.3.7.3
Normal file
BIN
install/tmp/lib/libvsomeip3-sd.so.3.7.3
Normal file
Binary file not shown.
1
install/tmp/lib/libvsomeip3.so
Symbolic link
1
install/tmp/lib/libvsomeip3.so
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3.so.3
|
||||
1
install/tmp/lib/libvsomeip3.so.3
Symbolic link
1
install/tmp/lib/libvsomeip3.so.3
Symbolic link
@@ -0,0 +1 @@
|
||||
libvsomeip3.so.3.7.3
|
||||
BIN
install/tmp/lib/libvsomeip3.so.3.7.3
Normal file
BIN
install/tmp/lib/libvsomeip3.so.3.7.3
Normal file
Binary file not shown.
5
source/soa_server/.vscode/settings.json
vendored
Normal file
5
source/soa_server/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.tcc": "cpp"
|
||||
}
|
||||
}
|
||||
22
source/soa_server/CMakeLists.txt
Normal file
22
source/soa_server/CMakeLists.txt
Normal 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)
|
||||
231
source/soa_server/soa_server.cpp
Normal file
231
source/soa_server/soa_server.cpp
Normal 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;
|
||||
}
|
||||
24
source/soa_server/soa_server.json
Normal file
24
source/soa_server/soa_server.json
Normal 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"
|
||||
}
|
||||
}
|
||||
122
source/soa_server/someip_server.cpp
Normal file
122
source/soa_server/someip_server.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
420
source/soa_server/someip_server.hpp
Normal file
420
source/soa_server/someip_server.hpp
Normal 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
|
||||
174
source/soa_server/someip_server_cfg.hpp
Normal file
174
source/soa_server/someip_server_cfg.hpp
Normal 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, ¬ifier_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, ¬ifier_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, ¬ifier_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, ¬ifier_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, ¬ifier_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, ¬ifier_can5}
|
||||
};
|
||||
|
||||
/*--- TOOLS GENERATE END ---*/
|
||||
|
||||
#endif // SOMEIP_SERVER_CFG_HPP
|
||||
428
source/soa_server/spi_protocol.cpp
Executable file
428
source/soa_server/spi_protocol.cpp
Executable 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 11(0-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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
243
source/soa_server/spi_protocol.hpp
Executable file
243
source/soa_server/spi_protocol.hpp
Executable 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 计算 CRC16(HEAD + 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 */
|
||||
/** @} */
|
||||
202
source/soa_server/spi_server.cpp
Normal file
202
source/soa_server/spi_server.cpp
Normal 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;
|
||||
}
|
||||
119
source/soa_server/spi_server.hpp
Normal file
119
source/soa_server/spi_server.hpp
Normal 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
BIN
source/spi_dev/spi4test
Executable file
Binary file not shown.
139
source/spi_dev/spi4test.c
Executable file
139
source/spi_dev/spi4test.c
Executable 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;
|
||||
}
|
||||
Reference in New Issue
Block a user