diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f20412..4148431 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.15) -project(extern_interface CXX) +project(external_interface CXX) set(CMAKE_CXX_STANDARD 11) if (NOT CMAKE_CROSSCOMPILING) @@ -8,7 +8,7 @@ if (NOT CMAKE_CROSSCOMPILING) endif() if (UNIX) - set(CMAKE_CXX_FLAGS "-std=c++11 -fPIC -Wall ${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "-g ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "-g -O2 ${CMAKE_CXX_FLAGS}") elseif (WIN32) @@ -34,8 +34,12 @@ include_directories(./include) aux_source_directory(./src SRC_LIST) -add_library(extern_interface_static STATIC ${SRC_LIST}) -add_library(extern_interface SHARED ${SRC_LIST}) +add_library(exint_static STATIC ${SRC_LIST}) +add_library(exint SHARED ${SRC_LIST}) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(exint PRIVATE -Wno-nonnull -fvisibility=hidden) +endif() # 设置测试文件和公共源文件 set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests") @@ -60,4 +64,4 @@ enable_testing() add_test(NAME test COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES} -) +) diff --git a/include/comframe.h b/include/comframe.h index ee51943..b3eca1d 100755 --- a/include/comframe.h +++ b/include/comframe.h @@ -7,7 +7,7 @@ #include #include -//#define COM_FRAME_DEBUG +// #define COM_FRAME_DEBUG #define COM_FRAME_MAGIC_NUMBER 0xEB90 #define COM_FRAME_DEFAULT_PAYLOAD_LENGTH 2 diff --git a/include/dataqueue.hpp b/include/dataqueue.hpp index ef61663..af6a4db 100644 --- a/include/dataqueue.hpp +++ b/include/dataqueue.hpp @@ -1,15 +1,21 @@ #ifndef _INCLUDED_QUEUE_ #define _INCLUDED_QUEUE_ -#include +#include #include +#include #include +#include + +class QueueException; template class DataQueue { public: - DataQueue() = default; - DataQueue(DataQueue&) = delete; + DataQueue() : m_CurrEpoch(0) {} + DataQueue(const DataQueue&) = delete; + + ~DataQueue() { Clear(); } void Push(T data) { @@ -21,37 +27,95 @@ public: T Pop() { std::unique_lock lock(m_Mutex); + auto epoch = m_CurrEpoch; while (m_Queue.empty()) { m_Cond.wait(lock); + if (epoch != m_CurrEpoch) { + throw QueueException(this); + } } T data = std::move(m_Queue.front()); m_Queue.pop_front(); return data; } - bool Empty() + template + T Pop(const std::chrono::duration timeout) + { + std::unique_lock lock(m_Mutex); + auto epoch = m_CurrEpoch; + while (m_Queue.empty()) + { + if (m_Cond.wait_for(lock, timeout) == std::cv_status::timeout) { + throw QueueTimeout(this); + } + if (epoch != m_CurrEpoch) { + throw QueueException(this); + } + } + } + + bool Empty() noexcept { std::lock_guard lock(m_Mutex); return m_Queue.empty(); } - size_t Size() + size_t Size() noexcept { std::lock_guard lock(m_Mutex); return m_Queue.size(); } - void Clear() + void Clear() noexcept { std::lock_guard lock(m_Mutex); m_Queue.clear(); + m_CurrEpoch++; + m_Cond.notify_all(); } protected: - std::list m_Queue; + std::deque m_Queue; std::mutex m_Mutex; std::condition_variable m_Cond; + +private: + uint8_t m_CurrEpoch; +}; + +class QueueException : public std::exception +{ +public: + QueueException(void* queue) : queue(queue) {} + + template + DataQueue* GetQueue() const noexcept + { + return static_cast*>(queue); + } + +private: + void* queue; +}; + +class QueueCleared : QueueException +{ +public: + const char* what() const noexcept override + { + return "queue cleared"; + } +}; + +class QueueTimeout : QueueException +{ +public: + const char* what() const noexcept override + { + return "queue timeout"; + } }; #endif \ No newline at end of file diff --git a/include/defines.h b/include/defines.h index 21e446b..159b9ef 100755 --- a/include/defines.h +++ b/include/defines.h @@ -187,7 +187,7 @@ extern char g_strSystemLogPath[500]; extern char g_strPCMSavePath[500]; extern struct tm g_tCurLocalTime; -extern bool g_bKeepEtifRuning; +extern bool g_bKeepExintRuning; extern long g_iSaveInputAudio; extern long g_iSaveTTSAudio; extern long g_iSaveHostAudio; diff --git a/include/exint/detail.h b/include/exint/detail.h index 943269b..4b6b6ba 100644 --- a/include/exint/detail.h +++ b/include/exint/detail.h @@ -10,7 +10,8 @@ extern "C" { #endif -void handle_pack(uint32_t type, size_t len, union PacketData data); +void exint_handle_pack(uint32_t type, size_t len, union PacketData data); +int exint_init_from_tty(int host_com_tty, int telemetry_com_tty, et_callback_t cb); void* telemetry_host_com_thread(void* args); void* upper_host_com_thread(void* arg); @@ -18,7 +19,7 @@ void* upper_host_com_thread(void* arg); extern int g_iHostCom_tty_id; extern int g_iTelemetry_Com_tty_id; extern int g_iEnableAlarmCode; -extern bool g_bKeepEtifRuning; +extern bool g_bKeepExintRuning; extern int g_iExternTimeDifference; extern int g_iUseHostComForTelemetry; extern uint8_t g_iAlarmCode[4]; diff --git a/include/exint/event.h b/include/exint/event.h index 46a125c..864e7c0 100644 --- a/include/exint/event.h +++ b/include/exint/event.h @@ -24,6 +24,7 @@ void exint_event(const char *event_name, size_t args_size, void *args); int exint_event_register(const char *event_name, event_callback callback, void* user_data); int exint_event_unregister(const char *event_name, event_callback callback, void* user_data); void* exint_event_thread(void*); +void exint_event_thread_exit(); #ifdef __cplusplus } diff --git a/include/external_interface.h b/include/external_interface.h index 4026020..2c689cf 100644 --- a/include/external_interface.h +++ b/include/external_interface.h @@ -17,7 +17,7 @@ #if defined(_MSC_VER) #define EXTERN_INTERFACE_PUBLIC __declspec(dllexport) #elif defined(__GNUC__) -#define EXTERN_INTERFACE_PUBLIC __attribute__ ((dllexport)) +#define EXTERN_INTERFACE_PUBLIC __attribute__ ((visibility("default"))) #endif #ifdef __cplusplus @@ -56,7 +56,7 @@ int exint_init(const char* config_path, et_callback_t cb); EXTERN_INTERFACE_PUBLIC void exint_send(uint32_t type, size_t len, union PacketData data); EXTERN_INTERFACE_PUBLIC -void extern_interface_deinit(); +void exint_finialize(); #ifdef __cplusplus } diff --git a/include/logging/logger.hpp b/include/logging/logger.hpp index 6531386..70b4625 100644 --- a/include/logging/logger.hpp +++ b/include/logging/logger.hpp @@ -96,6 +96,8 @@ private: class LoggerStreamBuf : public std::streambuf { public: LoggerStreamBuf(Logger& logger, Logger::Level level); + LoggerStreamBuf(const LoggerStreamBuf&) = delete; + LoggerStreamBuf(LoggerStreamBuf&& loggerStream) = default; protected: int overflow(int c) override; diff --git a/src/comframe.cpp b/src/comframe.cpp index 4d3a186..bfa96ec 100755 --- a/src/comframe.cpp +++ b/src/comframe.cpp @@ -203,8 +203,8 @@ ssize_t ComFrame_Send(int tty_id, const ComFrame* frame, const bool swap_endian) uint32_t length = ComFrame_Length(frame, swap_endian); char* buf = (char*)frame; #ifdef COM_FRAME_DEBUG - PrintFilePos(); printf("send length: %d\n", ComFrame_Length(frame, swap_endian)); - PrintFilePos(); printf("send checksum: %04x\n", ComFrame_Checksum(frame, swap_endian)); + printf("send length: %d\n", ComFrame_Length(frame, swap_endian)); + printf("send checksum: %04x\n", ComFrame_Checksum(frame, swap_endian)); #endif while (length > 0) { ssize_t written = write(tty_id, buf, length); @@ -253,15 +253,18 @@ ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size, if (recv_size <= 0 && cached_size == offset) { usleep(2); continue; + } else if (recv_size < 0) { + perror("com read error"); + recv_size = 0; } #ifdef COM_FRAME_DEBUG - PrintFilePos(); printf( + printf( "receive com data (received=%zd,cached=%zu,number=%04x)\n", recv_size, cached_size, ComFrame_HEADER(buffer)->magic_number ); - PrintFilePos(); printf("buffer: "); + printf("buffer: "); for (size_t i = 0; i < cached_size + recv_size; ++i) { - PrintFilePos(); printf("%02x", ((uint8_t*)buffer)[i]); + printf("%02x", ((uint8_t*)buffer)[i]); } putchar('\n'); #endif @@ -275,7 +278,7 @@ ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size, if (swap_endian) ComFrameHeader_SwapEndian(ComFrame_HEADER(((uint8_t*)buffer) + offset)); #ifdef COM_FRAME_DEBUG - PrintFilePos(); printf("find valid data (length=%u)\n", ComFrame_LENGTH(((uint8_t*)buffer)+offset)); + printf("find valid data (length=%u)\n", ComFrame_LENGTH(((uint8_t*)buffer)+offset)); #endif pred_size = ComFrame_LENGTH(((uint8_t*)buffer) + offset); if (pred_size > buffer_size) { diff --git a/src/event.cpp b/src/event.cpp index cf9df09..77b1bc6 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -3,13 +3,14 @@ #include #include #include +#include #include #include #include "dataqueue.hpp" #include "exint/event.h" #include "exint/detail.h" - +std::atomic_bool _is_event_thread_running { false }; DataQueue, void*>> _event_queue; static std::unordered_map>>& get_event_map() { @@ -22,8 +23,17 @@ void exint_event(const char *event_name, size_t args_size, void *args) { auto it = event_map.find(event_name); if (it != event_map.end()) { for (auto &pair : it->second) { - auto args_copy = new uint8_t[args_size]; - memcpy(args_copy, args, args_size); + if (!_is_event_thread_running) { + pair.first(event_name, args_size, args, pair.second); + continue; + } + uint8_t* args_copy; + if (args_size == 0) { + args_copy = NULL; + } else { + args_copy = new uint8_t[args_size]; + memcpy(args_copy, args, args_size); + } _event_queue.Push(std::make_tuple(event_name, pair.first, args_size, std::unique_ptr(args_copy), pair.second)); } } @@ -60,14 +70,31 @@ int exint_event_unregister(const char *event_name, event_callback callback, void } void* exint_event_thread(void*) { + bool is_running = false; + if (!_is_event_thread_running.compare_exchange_strong(is_running, true)) { + return NULL; + } const char* event_name; event_callback callback; size_t args_size; std::unique_ptr args; void* user_data; - while (g_bKeepEtifRuning) { - std::tie(event_name, callback, args_size, args, user_data) = _event_queue.Pop(); + while (g_bKeepExintRuning) { + try { + std::tie(event_name, callback, args_size, args, user_data) = _event_queue.Pop(); + } catch (const QueueException&) { + break; + } callback(event_name, args_size, args.get(), user_data); } + _is_event_thread_running.store(false); return NULL; } + +void exint_event_thread_exit() { + bool is_running = true; + if (!_is_event_thread_running.compare_exchange_strong(is_running, false)) { + return; + } + _event_queue.Clear(); +} diff --git a/src/external_interface.cpp b/src/external_interface.cpp index 77121eb..9615b62 100644 --- a/src/external_interface.cpp +++ b/src/external_interface.cpp @@ -14,7 +14,7 @@ int g_iHostCom_tty_id; int g_iTelemetry_Com_tty_id; int g_iEnableAlarmCode = true; bool g_bTelemetry_Open = true; -bool g_bKeepEtifRuning = false; +bool g_bKeepExintRuning = false; int g_iExternTimeDifference = 0; int g_iUseHostComForTelemetry = true; uint8_t g_iAlarmCode[4] = {0xAA, 0xAA, 0xAA, 0xAA}; @@ -42,7 +42,18 @@ int exint_init(const char* config_path, et_callback_t cb) { if (read_config(config_path)) return -1; et_callback = cb; - g_bKeepEtifRuning = true; + g_bKeepExintRuning = true; + pthread_create(&event_thread, NULL, exint_event_thread, NULL); + pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL); + pthread_create(&telemetry_thread, NULL, telemetry_host_com_thread, NULL); + return 0; +} + +int exint_init_from_tty(int host_com_tty, int telemetry_com_tty, et_callback_t cb) { + et_callback = cb; + g_iHostCom_tty_id = host_com_tty; + g_iTelemetry_Com_tty_id = telemetry_com_tty; + g_bKeepExintRuning = true; pthread_create(&event_thread, NULL, exint_event_thread, NULL); pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL); pthread_create(&telemetry_thread, NULL, telemetry_host_com_thread, NULL); @@ -65,13 +76,13 @@ void exint_send(uint32_t type, size_t len, union PacketData data) { exint_event(event_name, len, data_pointer); } -void extern_interface_deinit() { - g_bKeepEtifRuning = false; +void exint_finialize() { + g_bKeepExintRuning = false; pthread_cancel(event_thread); pthread_cancel(upperhost_thread); pthread_cancel(telemetry_thread); } -void handle_pack(uint32_t type, size_t len, union PacketData data) { +void exint_handle_pack(uint32_t type, size_t len, union PacketData data) { et_callback(type, len, data); } diff --git a/src/host_com.cpp b/src/host_com.cpp index 0f3f262..f5548bb 100644 --- a/src/host_com.cpp +++ b/src/host_com.cpp @@ -26,7 +26,7 @@ volatile bool g_bNeedReboot = false; volatile int32_t g_iMS2Reboot = 1000; void get_telemetry_data(TelemetryRequestData* data) { - handle_pack(ET_TYPE_TELEMETRY_REQUEST, sizeof(TelemetryRequestData), { .pd_pointer = data }); + exint_handle_pack(ET_TYPE_TELEMETRY_REQUEST, sizeof(TelemetryRequestData), { .pd_pointer = data }); } /* create a msg data for upper host telemetry*/ @@ -189,19 +189,17 @@ void* telemetry_host_com_thread(void* path) {//Integrated Business Unit, telemet const uint16_t address = COM_FRAME_ADDRESS_VOIX; // TODO size_t offset = 0, cached_size = 0; uint8_t* buffer = new uint8_t[buffer_size]; - uint8_t err_data[2]; uint64_t iTelemetryAnswerTimes = 0; - void* pDataBlock; - int iRet; TelemetryCommandInfo TeleCmdInfo2Send; TelemetryData TelemetryData2Send; // gejp 2024.10.03 memset(&TeleCmdInfo2Send, 0, sizeof(TelemetryCommandInfo)); - while (g_bKeepEtifRuning) { + while (g_bKeepExintRuning) { // if ( (iTelemetryAnswerTimes % 3 == 0) && g_bNeedReboot) system("reboot"); - ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepEtifRuning, true); + ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepExintRuning, true); + if (frame == NULL) break; //ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true); if (ComFrame_Verify(frame, false)) { if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_CHECKSUM, true)) @@ -364,28 +362,22 @@ AlarmData* GetAlarmTextByCode(uint8_t cmd_code[], uint8_t iAlarmCode[4]) void* upper_host_com_thread(void* arg) {//hand-control display processing unit 手控显示处理单元 int tty_id = g_iHostCom_tty_id; const uint16_t address = COM_FRAME_ADDRESS_VOIX; - const uint32_t buffer_size = 1024 * 100; // TODO + const uint32_t buffer_size = 1024 * 100; const int64_t iHostAudioBufferSize = 1024 * 1024; uint8_t* buffer = new uint8_t[buffer_size]; - int64_t iEnqueueBytes; - bool bSucc; - char* pStrNotice; size_t offset = 0, cached_size = 0; - uint64_t iTelemetryAnswerTimes; int16_t* ptrProcHostAudio = (int16_t*)malloc(iHostAudioBufferSize); - int16_t* ptrProcHostAudioEnd = ptrProcHostAudio; - int ProcHostAudioLengthMS = 1000; - int iProcHostAudioSampleCnt; timeval tLastTime, tCurTime; TelemetryData4UpperHost UpperHostTeleData; - while (g_bKeepEtifRuning) { + while (g_bKeepExintRuning) { - ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepEtifRuning, true); + ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepExintRuning, true); //ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true); //PrintFilePos(); printf("%04X \n", ComFrame_HEADER(frame)->type); + if (frame == NULL) break; switch (ComFrame_HEADER(frame)->type) { case COM_FRAME_TYPE_COMMAND: @@ -446,7 +438,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit else //-------END 2024.10.23 noted by zgb */ - handle_pack(ET_TYPE_COMMAND, 6, {.pd_pointer = frame->payload}); + exint_handle_pack(ET_TYPE_COMMAND, 6, {.pd_pointer = frame->payload}); break; } case COM_FRAME_TYPE_SPEECH_INJECTED: @@ -462,7 +454,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit COM_FRAME_ADDRESS_VOIX, COM_FRAME_TYPE_SPEECH_INJECTED, payload, 6, true); - handle_pack(ET_TYPE_TEXT, 6, {.pd_pointer = f_data->payload}); + exint_handle_pack(ET_TYPE_TEXT, 6, {.pd_pointer = f_data->payload}); if (ComFrame_Send(tty_id, f_data, true)) { PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno)); } @@ -492,7 +484,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit PrintFilePos(); fprintf(stderr, " com frame interval %d\n", iIntervalTime); tLastTime = tCurTime; - handle_pack(ET_TYPE_AUDIO, ComFrame_PAYLOAD_LENGTH(frame), {.pd_pointer = frame->payload}); + exint_handle_pack(ET_TYPE_AUDIO, ComFrame_PAYLOAD_LENGTH(frame), {.pd_pointer = frame->payload}); break; } @@ -558,7 +550,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit if(!alarm) continue; - handle_pack(ET_TYPE_TEXT, sizeof(alarm), {.pd_pointer = alarm}); + exint_handle_pack(ET_TYPE_TEXT, sizeof(alarm), {.pd_pointer = alarm}); uint8_t payload[6] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}; ComFrame* f_data = ComFrame_New( diff --git a/src/logging.cpp b/src/logging.cpp index c855658..7d46936 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -222,8 +222,7 @@ LoggerOStream::LoggerOStream(Logger& logger, Logger::Level level) LoggerOStream::LoggerOStream(LoggerOStream&& loggerStream) : std::ostream(std::move(loggerStream)), _streamBuf(std::move(loggerStream._streamBuf)) -{ -} +{} LoggerStreamBuf::LoggerStreamBuf(Logger& logger, Logger::Level level) : _logger(logger), _level(level) {} diff --git a/tests/c_testcase.cpp b/tests/c_testcase.cpp index 329c8a4..9a38ee3 100644 --- a/tests/c_testcase.cpp +++ b/tests/c_testcase.cpp @@ -107,7 +107,7 @@ static __inline void print_separator_ex(char lc, const char* str, const char* co static int collect_testcase() { for (int i = 0; i < test_case_total; ++i) { puts(test_cases[i].name); - putchar(' '); + // putchar(' '); } putchar('\n'); return 0; diff --git a/tests/test_event.cpp b/tests/test_event.cpp new file mode 100644 index 0000000..d6fb147 --- /dev/null +++ b/tests/test_event.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include "exint/event.h" +#include "exint/detail.h" +#include "c_testcase.h" + +static std::vector g_vec; + +ON_EVENT(test) { + int* arg = (int*)args; + g_vec.push_back(*arg); +} + +SETUP { + g_vec.clear(); + g_bKeepExintRuning = true; + return 0; +} + +TEARDOWN { + g_bKeepExintRuning = false; + exint_event_thread_exit(); + return 0; +} + +TEST_CASE(test_unknow_event) { + exint_event("unknow_event", 0, NULL); + END_TEST; +} + +TEST_CASE(test_event) { + int i = 1; + exint_event("test", sizeof(int), &i); + assert_eq(g_vec.size(), 1); + assert_eq(g_vec[0], i); + END_TEST; +} + +TEST_CASE(test_event_thread) { + bool started = false; + std::thread t([&]() { + started = true; + exint_event_thread(NULL); + }); + t.detach(); + while (!started) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + int i = 2; + exint_event("test", sizeof(int), &i); + for (int i = 0; i < 10; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (g_vec.size() != 1) { + continue; + } + assert_eq(g_vec[0], 2); + goto end; + } + assert(false); + +end: + END_TEST; +} diff --git a/tests/test_host_com.cpp b/tests/test_host_com.cpp new file mode 100644 index 0000000..9f7a634 --- /dev/null +++ b/tests/test_host_com.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "comframe.h" +#include "telemetry.h" +#include "dataqueue.hpp" +#include "exint/detail.h" +#include "c_testcase.h" + +static int g_telemetry_request_count = 0; +static DataQueue> g_data_queue; +static int host_com_master_id; +static int telemetry_com_master_id; + +void exint_data_callback(uint32_t type, size_t size, PacketData data) { + if (type == ET_TYPE_TELEMETRY_REQUEST) { + g_telemetry_request_count++; + memset(data.pd_pointer, 0, size); + ((TelemetryRequestData*)data.pd_pointer)->app_ver_high = 1; + ((TelemetryRequestData*)data.pd_pointer)->app_ver_low = 2; + } else { + g_data_queue.Push(std::make_tuple(type, size, data)); + } +} + +SETUP { + int host_com_slave_id, telemetry_com_slave_id; + if (openpty(&host_com_master_id, &host_com_slave_id, NULL, NULL, NULL) < 0) { + return 1; + } + if (openpty(&telemetry_com_master_id, &telemetry_com_slave_id, NULL, NULL, NULL) < 0) { + return 1; + } + init_tty(host_com_master_id, 115200); + init_tty(telemetry_com_master_id, 115200); + // init_tty(host_com_slave_id, 115200); + // init_tty(telemetry_com_slave_id, 115200); + exint_init_from_tty(host_com_slave_id, telemetry_com_slave_id, exint_data_callback); + g_telemetry_request_count = 0; + return 0; +} + +TEARDOWN { + exint_finialize(); + close(host_com_master_id); + close(telemetry_com_master_id); + g_data_queue.Clear(); + return 0; +} + +TEST_CASE(test_init) { + assert(host_com_master_id); + assert(telemetry_com_master_id); + END_TEST; +} + +TEST_CASE(test_host_telemetry) { + auto request_msg = NewTelemetryRequestMsg(COM_FRAME_ADDRESS_VOIX, true); + ComFrame_Send(telemetry_com_master_id, request_msg, true); + ComFrame_Del(request_msg); + + bool timeout_flag = true; + std::thread([&]() { + std::this_thread::sleep_for(std::chrono::seconds(1)); + timeout_flag = false; + }).detach(); + + size_t offset = 0; + size_t cached_size = 0; + auto telemetry_reply = ComFrame_ReceiveEx(telemetry_com_master_id, NULL, 100, &offset, &cached_size, &timeout_flag, true); + assert(telemetry_reply); + assert_eq(g_telemetry_request_count, 1); + + TelemetryData* telemetry_data = (TelemetryData*)ComFrame_PAYLOAD(telemetry_reply); + assert_eq(ComFrame_TYPE(telemetry_reply), COM_FRAME_TYPE_TELEMETRY_ANSWER); + assert_eq(ComFrame_PAYLOAD_LENGTH(telemetry_reply), sizeof(TelemetryData)); + assert_eq(telemetry_data->application_version_high, 1); + + END_TEST; +} + +TEST_CASE(test_send_command) { + ComFrame* command_frame = NULL; + bool timeout_flag = true; + std::thread([&]() { + size_t offset = 0; + size_t cached_size = 0; + command_frame = ComFrame_ReceiveEx(host_com_master_id, NULL, 100, &offset, &cached_size, &timeout_flag, true); + }).detach(); + + char command_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; + exint_send(ET_TYPE_COMMAND, 6, { .pd_pointer = command_data }); + + for (int i = 0; i < 100; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (command_frame) { + break; + } + } + timeout_flag = false; + assert(command_frame); + assert_eq(ComFrame_TYPE(command_frame), COM_FRAME_TYPE_REQUEST); + assert_eq(ComFrame_PAYLOAD_LENGTH(command_frame), 6); + assert_eq(ComFrame_PAYLOAD(command_frame)[0], 0x00); + assert_eq(ComFrame_PAYLOAD(command_frame)[5], 0x05); + END_TEST; +} diff --git a/tests/test_logging.cpp b/tests/test_logging.cpp new file mode 100644 index 0000000..8ff19b2 --- /dev/null +++ b/tests/test_logging.cpp @@ -0,0 +1,132 @@ +#include +#include "c_testcase.h" +#include "logging/interface.h" +#include "logging/logger.hpp" + +using namespace logging; + +TEST_CASE(test_init) { + log_info("test_init before"); + log_init(NULL); + assert_eq(log_level(), LOG_LEVEL_INFO); + log_info("test_init after"); + + log_debug("test_init debug"); + log_warn("test_init warn"); + log_error("test_init error"); + log_fatal("test_init fatal"); + + log_init("debug"); + assert_eq(log_level(), LOG_LEVEL_DEBUG); + log_warn_with_source("test_init warn with source"); + log_error_from_errno("TestError"); + END_TEST; +} + +TEST_CASE(test_add_stream) { + std::stringstream ss; + log_init(NULL); + logging::global_logger->add_stream(ss); + + log_info("test_stream"); + auto s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 19), "[INFO] test_stream\n"); + ss.str(""); + + log_debug("test_stream debug"); + s = ss.str(); + assert_eq(s.length(), 0); + ss.str(""); + + log_set_level(LOG_LEVEL_DEBUG); + + log_debug("test_stream debug"); + s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 26), "[DEBUG] test_stream debug\n"); + ss.str(""); + + log_warn("test_stream warn"); + s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 24), "[WARN] test_stream warn\n"); + ss.str(""); + + log_error("test_stream error"); + s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 26), "[ERROR] test_stream error\n"); + ss.str(""); + + log_fatal("test_stream fatal"); + s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 26), "[FATAL] test_stream fatal\n"); + ss.str(""); + + logging::global_logger->log("test_stream debug"); + s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 26), "[DEBUG] test_stream debug\n"); + + END_TEST; +} + +TEST_CASE(test_log_stream) { + log_init(NULL); + auto& logger = *logging::global_logger; + + std::stringstream ss; + logger.add_stream(ss); + + logger[LOG_LEVEL_INFO] << "test_log_stream" << std::endl; + auto s = ss.str(); + assert_str_eq(s.c_str() + (s.length() - 23), "[INFO] test_log_stream\n"); + ss.str(""); + + logger[LOG_LEVEL_DEBUG] << "test_log_stream debug" << std::endl; + s = ss.str(); + assert_eq(s.length(), 0); + + END_TEST; +} + +TEST_CASE(test_sub_logger) { + log_init(NULL); + auto sublogger = get_logger("sublogger"); + assert_eq(sublogger->level(), LogLevel::INFO); + assert_eq(sublogger->name(), "sublogger"); + assert_eq(sublogger->parent(), logging::global_logger.get()); + + auto subsublogger = get_logger("sublogger::subsublogger"); + assert_eq(subsublogger->level(), LogLevel::INFO); + assert_eq(subsublogger->name(), "sublogger::subsublogger"); + assert_eq(subsublogger->parent(), sublogger); + + auto sub1sub1logger = get_logger("sublogger1::subsublogger1"); + assert_eq(sub1sub1logger->level(), LogLevel::INFO); + assert_eq(sub1sub1logger->name(), "sublogger1::subsublogger1"); + auto sub1logger = get_logger("sublogger1"); + assert_eq(sub1logger->level(), LogLevel::INFO); + assert_eq(sub1logger->name(), "sublogger1"); + assert_eq(sub1logger->parent(), logging::global_logger.get()); + assert_eq(sub1sub1logger->parent(), sub1logger); + + auto root_logger = get_logger(""); + assert_eq(root_logger, logging::global_logger.get()); + auto root_logger1 = get_logger("::"); + assert_eq(root_logger1, root_logger); + auto subsublogger1 = get_logger("sublogger::subsublogger"); + assert_eq(subsublogger1, subsublogger); + auto subsublogger2 = get_logger("::sublogger::subsublogger"); + assert_eq(subsublogger2, subsublogger); + auto subsublogger3 = get_logger("sublogger::subsublogger::"); + assert_eq(subsublogger3, subsublogger); + auto subsublogger4 = get_logger("sublogger::::::subsublogger"); + assert_eq(subsublogger4, subsublogger); + + global_logger->set_level(LogLevel::DEBUG); + assert_eq(global_logger->level(), LogLevel::DEBUG); + assert_eq(sublogger->level(), LogLevel::DEBUG); + assert_eq(subsublogger->level(), LogLevel::DEBUG); + sublogger->set_level(LogLevel::WARN); + assert_eq(global_logger->level(), LogLevel::DEBUG); + assert_eq(sublogger->level(), LogLevel::WARN); + assert_eq(subsublogger->level(), LogLevel::WARN); + END_TEST; +} diff --git a/tests/test_queue.cpp b/tests/test_queue.cpp index 1b8748c..3af3023 100644 --- a/tests/test_queue.cpp +++ b/tests/test_queue.cpp @@ -3,14 +3,14 @@ #include "c_testcase.h" #include "dataqueue.hpp" -TEST_CASE(init) { +TEST_CASE(test_init) { DataQueue q; assert(q.Empty()); assert_eq(q.Size(), 0); END_TEST; } -TEST_CASE(push) { +TEST_CASE(test_push) { DataQueue q; q.Push(10); assert_eq(q.Size(), 1); @@ -18,7 +18,7 @@ TEST_CASE(push) { END_TEST; } -TEST_CASE(pop) { +TEST_CASE(test_pop) { DataQueue q; std::thread t([&]() { for (int i = 0; i < 10; i++) { @@ -32,3 +32,23 @@ TEST_CASE(pop) { t.join(); END_TEST; } + +TEST_CASE(test_clear) { + DataQueue q; + q.Push(10); + q.Clear(); + assert(q.Empty()); + + std::thread t([&]() { + try { + q.Pop(); + } catch (const QueueException&) { + return; + } + throw std::runtime_error("QueueException not thrown"); + }); + usleep(100); + q.Clear(); + t.join(); + END_TEST; +}