diff --git a/build_all.sh b/build_all.sh index a659639..c281820 100755 --- a/build_all.sh +++ b/build_all.sh @@ -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 diff --git a/build_soa_server.sh b/build_soa_server.sh new file mode 100755 index 0000000..4572eed --- /dev/null +++ b/build_soa_server.sh @@ -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 ---" diff --git a/install/example/rk3576/your_app b/install/example/rk3576/your_app index 2192bfa..c9be3ec 100755 Binary files a/install/example/rk3576/your_app and b/install/example/rk3576/your_app differ diff --git a/install/soa_server/rk3576/soa_server b/install/soa_server/rk3576/soa_server new file mode 100755 index 0000000..8d3f6bb Binary files /dev/null and b/install/soa_server/rk3576/soa_server differ diff --git a/install/tmp/lib.zip b/install/tmp/lib.zip new file mode 100644 index 0000000..1ab8af6 Binary files /dev/null and b/install/tmp/lib.zip differ diff --git a/install/tmp/lib/libboost_filesystem.so b/install/tmp/lib/libboost_filesystem.so new file mode 120000 index 0000000..4021fae --- /dev/null +++ b/install/tmp/lib/libboost_filesystem.so @@ -0,0 +1 @@ +libboost_filesystem.so.1.75.0 \ No newline at end of file diff --git a/install/tmp/lib/libboost_filesystem.so.1.75.0 b/install/tmp/lib/libboost_filesystem.so.1.75.0 new file mode 100755 index 0000000..a615c34 Binary files /dev/null and b/install/tmp/lib/libboost_filesystem.so.1.75.0 differ diff --git a/install/tmp/lib/libboost_system.so b/install/tmp/lib/libboost_system.so new file mode 120000 index 0000000..1c6e9cf --- /dev/null +++ b/install/tmp/lib/libboost_system.so @@ -0,0 +1 @@ +libboost_system.so.1.75.0 \ No newline at end of file diff --git a/install/tmp/lib/libboost_system.so.1.75.0 b/install/tmp/lib/libboost_system.so.1.75.0 new file mode 100755 index 0000000..c255bbb Binary files /dev/null and b/install/tmp/lib/libboost_system.so.1.75.0 differ diff --git a/install/tmp/lib/libvsomeip3-cfg.so b/install/tmp/lib/libvsomeip3-cfg.so new file mode 120000 index 0000000..f33b1d8 --- /dev/null +++ b/install/tmp/lib/libvsomeip3-cfg.so @@ -0,0 +1 @@ +libvsomeip3-cfg.so.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3-cfg.so.3 b/install/tmp/lib/libvsomeip3-cfg.so.3 new file mode 120000 index 0000000..589b8b5 --- /dev/null +++ b/install/tmp/lib/libvsomeip3-cfg.so.3 @@ -0,0 +1 @@ +libvsomeip3-cfg.so.3.7.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3-cfg.so.3.7.3 b/install/tmp/lib/libvsomeip3-cfg.so.3.7.3 new file mode 100644 index 0000000..8148b77 Binary files /dev/null and b/install/tmp/lib/libvsomeip3-cfg.so.3.7.3 differ diff --git a/install/tmp/lib/libvsomeip3-sd.so b/install/tmp/lib/libvsomeip3-sd.so new file mode 120000 index 0000000..9177525 --- /dev/null +++ b/install/tmp/lib/libvsomeip3-sd.so @@ -0,0 +1 @@ +libvsomeip3-sd.so.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3-sd.so.3 b/install/tmp/lib/libvsomeip3-sd.so.3 new file mode 120000 index 0000000..7a0f65a --- /dev/null +++ b/install/tmp/lib/libvsomeip3-sd.so.3 @@ -0,0 +1 @@ +libvsomeip3-sd.so.3.7.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3-sd.so.3.7.3 b/install/tmp/lib/libvsomeip3-sd.so.3.7.3 new file mode 100644 index 0000000..cbfe082 Binary files /dev/null and b/install/tmp/lib/libvsomeip3-sd.so.3.7.3 differ diff --git a/install/tmp/lib/libvsomeip3.so b/install/tmp/lib/libvsomeip3.so new file mode 120000 index 0000000..0047810 --- /dev/null +++ b/install/tmp/lib/libvsomeip3.so @@ -0,0 +1 @@ +libvsomeip3.so.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3.so.3 b/install/tmp/lib/libvsomeip3.so.3 new file mode 120000 index 0000000..e4414aa --- /dev/null +++ b/install/tmp/lib/libvsomeip3.so.3 @@ -0,0 +1 @@ +libvsomeip3.so.3.7.3 \ No newline at end of file diff --git a/install/tmp/lib/libvsomeip3.so.3.7.3 b/install/tmp/lib/libvsomeip3.so.3.7.3 new file mode 100644 index 0000000..6889ac2 Binary files /dev/null and b/install/tmp/lib/libvsomeip3.so.3.7.3 differ diff --git a/source/soa_server/.vscode/settings.json b/source/soa_server/.vscode/settings.json new file mode 100644 index 0000000..a44d314 --- /dev/null +++ b/source/soa_server/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.tcc": "cpp" + } +} \ No newline at end of file diff --git a/source/soa_server/CMakeLists.txt b/source/soa_server/CMakeLists.txt new file mode 100644 index 0000000..34f3547 --- /dev/null +++ b/source/soa_server/CMakeLists.txt @@ -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) diff --git a/source/soa_server/soa_server.cpp b/source/soa_server/soa_server.cpp new file mode 100644 index 0000000..84a1ba9 --- /dev/null +++ b/source/soa_server/soa_server.cpp @@ -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]====================================*/ +/* + * V0.0.1 20260606 Liuzhimin Initial version + */ +/*============================================================================*/ + +/*=======[I N C L U D E S]====================================================*/ + +#include +#include +#include + +#include "someip_server_cfg.hpp" +#include "spi_server.hpp" +#include +//#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 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 data; + data.assign(example_string.begin(),example_string.end()); + return data; +} + +// events' data functions +std::vector 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 data; + data.assign(example_string.begin(),example_string.end()); + return data; +} + +std::vector ff_method_example1(void){ + /* 1.Add your code do your action here */ + //... + + /* reserve,no need data to reponse*/ + std::vector data; + return data; +} + +std::vector ff_method_example2(void){ + /* 1.Add your code do your action here */ + //... + + /* reserve,no need data to reponse*/ + std::vector data; + return data; +} + +std::vector getter_example1(void){ + std::vector 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 getter_example2(void){ + std::vector 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 setter_example1(void){ + std::vector 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 setter_example2(void){ + std::vector 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 event_example1(void){ + + std::vector 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 event_example2(void){ + + std::vector 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 notifier_can0(void){ + std::lock_guard lock(g_can_mutex[0]); + return g_can_data[0]; +} + +std::vector notifier_can1(void){ + std::lock_guard lock(g_can_mutex[1]); + return g_can_data[1]; +} +std::vector notifier_can2(void){ + std::lock_guard lock(g_can_mutex[2]); + return g_can_data[2]; +} +std::vector notifier_can3(void){ + std::lock_guard lock(g_can_mutex[3]); + return g_can_data[3]; +} +std::vector notifier_can4(void){ + std::lock_guard lock(g_can_mutex[4]); + return g_can_data[4]; +} +std::vector notifier_can5(void){ + std::lock_guard lock(g_can_mutex[5]); + return g_can_data[5]; +} + +bool epsilon_func(std::shared_ptr _old, std::shared_ptr _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; +} \ No newline at end of file diff --git a/source/soa_server/soa_server.json b/source/soa_server/soa_server.json new file mode 100644 index 0000000..8adc788 --- /dev/null +++ b/source/soa_server/soa_server.json @@ -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" + } +} \ No newline at end of file diff --git a/source/soa_server/someip_server.cpp b/source/soa_server/someip_server.cpp new file mode 100644 index 0000000..e81051b --- /dev/null +++ b/source/soa_server/someip_server.cpp @@ -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]====================================*/ +/* + * 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 +//#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; + } + +} diff --git a/source/soa_server/someip_server.hpp b/source/soa_server/someip_server.hpp new file mode 100644 index 0000000..6f3d3b8 --- /dev/null +++ b/source/soa_server/someip_server.hpp @@ -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]====================================*/ +/* + * 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 +#endif +#include +#include +#include +#include +#include +#include +#include + +#include + +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(void)> get_response_data_func_t; +// typedef std::function(const std::shared_ptr &)> get_notify_data_func_t; +typedef std::function(void)> get_notify_data_func_t; +// typedef std::function< +// bool (const std::shared_ptr &, +// const std::shared_ptr &) > 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 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 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 &_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 _response = runtime::get()->create_response(_request); + std::shared_ptr _payload = runtime::get()->create_payload(); + std::vector 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 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 lastData; + std::vector 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 = 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 notify_data; + std::shared_ptr _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 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 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_; + + // blocked_ / service_is_offered_ must be initialized before starting the threads! + // std::thread offer_thread_; + // std::thread notify_thread_; + std::vector notify_threads_; +}; + +#endif // SOMEIP_SERVER_HPP \ No newline at end of file diff --git a/source/soa_server/someip_server_cfg.hpp b/source/soa_server/someip_server_cfg.hpp new file mode 100644 index 0000000..2c702a3 --- /dev/null +++ b/source/soa_server/someip_server_cfg.hpp @@ -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]====================================*/ + /* + * 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 rr_method_example1(void); +extern std::vector rr_method_example2(void); +extern std::vector ff_method_example1(void); +extern std::vector ff_method_example2(void); +extern std::vector getter_example1(void); +extern std::vector getter_example2(void); +extern std::vector setter_example1(void); +extern std::vector setter_example2(void); +extern std::vector event_example1(void); +extern std::vector event_example2(void); +#endif +extern std::vector notifier_can0(void); +extern std::vector notifier_can1(void); +extern std::vector notifier_can2(void); +extern std::vector notifier_can3(void); +extern std::vector notifier_can4(void); +extern std::vector notifier_can5(void); +extern std::vector notifier_example2(void); +extern bool epsilon_func(std::shared_ptr _old, std::shared_ptr _new); + +// my_servers +inline std::vector 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_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_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_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_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_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_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 diff --git a/source/soa_server/spi_protocol.cpp b/source/soa_server/spi_protocol.cpp new file mode 100755 index 0000000..6abfbba --- /dev/null +++ b/source/soa_server/spi_protocol.cpp @@ -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 + +/*================================================================================================== + 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); +} + +/** @} */ diff --git a/source/soa_server/spi_protocol.hpp b/source/soa_server/spi_protocol.hpp new file mode 100755 index 0000000..c4b473f --- /dev/null +++ b/source/soa_server/spi_protocol.hpp @@ -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 + +/*================================================================================================== + 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 */ +/** @} */ diff --git a/source/soa_server/spi_server.cpp b/source/soa_server/spi_server.cpp new file mode 100644 index 0000000..395e172 --- /dev/null +++ b/source/soa_server/spi_server.cpp @@ -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 +#include + +/* CAN 数据缓冲区 — SPI 线程写入,notifier 线程读取 */ +std::vector g_can_data[CAN_CHANNEL_COUNT]; +std::mutex g_can_mutex[CAN_CHANNEL_COUNT]; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ========== 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 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; +} diff --git a/source/soa_server/spi_server.hpp b/source/soa_server/spi_server.hpp new file mode 100644 index 0000000..fc6e422 --- /dev/null +++ b/source/soa_server/spi_server.hpp @@ -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]====================================*/ +/* + * 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 +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/*=======[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 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 diff --git a/source/spi_dev/spi4test b/source/spi_dev/spi4test new file mode 100755 index 0000000..dc45c6a Binary files /dev/null and b/source/spi_dev/spi4test differ diff --git a/source/spi_dev/spi4test.c b/source/spi_dev/spi4test.c new file mode 100755 index 0000000..04ad170 --- /dev/null +++ b/source/spi_dev/spi4test.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* ========== 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; +}