refactor(exint): improve queue implementation and rename project

- Rename project from extern_interface to external_interface
- Update CMakeLists.txt to use new project name and add compiler flags
- Implement QueueException and related classes in dataqueue.hpp
- Update event handling and thread management in event.cpp
- Modify external_interface initialization and naming conventions
- Update logging and test cases to reflect changes
This commit is contained in:
ovizro 2024-12-06 16:07:06 +08:00
parent 6653710be9
commit 5ca1a439f3
18 changed files with 488 additions and 60 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
project(extern_interface CXX) project(external_interface CXX)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
if (NOT CMAKE_CROSSCOMPILING) if (NOT CMAKE_CROSSCOMPILING)
@ -8,7 +8,7 @@ if (NOT CMAKE_CROSSCOMPILING)
endif() endif()
if (UNIX) 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_DEBUG "-g ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "-g -O2 ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "-g -O2 ${CMAKE_CXX_FLAGS}")
elseif (WIN32) elseif (WIN32)
@ -34,8 +34,12 @@ include_directories(./include)
aux_source_directory(./src SRC_LIST) aux_source_directory(./src SRC_LIST)
add_library(extern_interface_static STATIC ${SRC_LIST}) add_library(exint_static STATIC ${SRC_LIST})
add_library(extern_interface SHARED ${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") set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests")

View File

@ -1,15 +1,21 @@
#ifndef _INCLUDED_QUEUE_ #ifndef _INCLUDED_QUEUE_
#define _INCLUDED_QUEUE_ #define _INCLUDED_QUEUE_
#include <list> #include <deque>
#include <mutex> #include <mutex>
#include <chrono>
#include <condition_variable> #include <condition_variable>
#include <stdexcept>
class QueueException;
template <typename T> template <typename T>
class DataQueue { class DataQueue {
public: public:
DataQueue() = default; DataQueue() : m_CurrEpoch(0) {}
DataQueue(DataQueue&) = delete; DataQueue(const DataQueue&) = delete;
~DataQueue() { Clear(); }
void Push(T data) void Push(T data)
{ {
@ -21,37 +27,95 @@ public:
T Pop() T Pop()
{ {
std::unique_lock<std::mutex> lock(m_Mutex); std::unique_lock<std::mutex> lock(m_Mutex);
auto epoch = m_CurrEpoch;
while (m_Queue.empty()) while (m_Queue.empty())
{ {
m_Cond.wait(lock); m_Cond.wait(lock);
if (epoch != m_CurrEpoch) {
throw QueueException(this);
}
} }
T data = std::move(m_Queue.front()); T data = std::move(m_Queue.front());
m_Queue.pop_front(); m_Queue.pop_front();
return data; return data;
} }
bool Empty() template <typename Rep = uint64_t, typename Period = std::milli>
T Pop(const std::chrono::duration<Rep, Period> timeout)
{
std::unique_lock<std::mutex> 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<std::mutex> lock(m_Mutex); std::lock_guard<std::mutex> lock(m_Mutex);
return m_Queue.empty(); return m_Queue.empty();
} }
size_t Size() size_t Size() noexcept
{ {
std::lock_guard<std::mutex> lock(m_Mutex); std::lock_guard<std::mutex> lock(m_Mutex);
return m_Queue.size(); return m_Queue.size();
} }
void Clear() void Clear() noexcept
{ {
std::lock_guard<std::mutex> lock(m_Mutex); std::lock_guard<std::mutex> lock(m_Mutex);
m_Queue.clear(); m_Queue.clear();
m_CurrEpoch++;
m_Cond.notify_all();
} }
protected: protected:
std::list<T> m_Queue; std::deque<T> m_Queue;
std::mutex m_Mutex; std::mutex m_Mutex;
std::condition_variable m_Cond; std::condition_variable m_Cond;
private:
uint8_t m_CurrEpoch;
};
class QueueException : public std::exception
{
public:
QueueException(void* queue) : queue(queue) {}
template <typename T>
DataQueue<T>* GetQueue() const noexcept
{
return static_cast<DataQueue<T>*>(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 #endif

View File

@ -187,7 +187,7 @@ extern char g_strSystemLogPath[500];
extern char g_strPCMSavePath[500]; extern char g_strPCMSavePath[500];
extern struct tm g_tCurLocalTime; extern struct tm g_tCurLocalTime;
extern bool g_bKeepEtifRuning; extern bool g_bKeepExintRuning;
extern long g_iSaveInputAudio; extern long g_iSaveInputAudio;
extern long g_iSaveTTSAudio; extern long g_iSaveTTSAudio;
extern long g_iSaveHostAudio; extern long g_iSaveHostAudio;

View File

@ -10,7 +10,8 @@
extern "C" { extern "C" {
#endif #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* telemetry_host_com_thread(void* args);
void* upper_host_com_thread(void* arg); 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_iHostCom_tty_id;
extern int g_iTelemetry_Com_tty_id; extern int g_iTelemetry_Com_tty_id;
extern int g_iEnableAlarmCode; extern int g_iEnableAlarmCode;
extern bool g_bKeepEtifRuning; extern bool g_bKeepExintRuning;
extern int g_iExternTimeDifference; extern int g_iExternTimeDifference;
extern int g_iUseHostComForTelemetry; extern int g_iUseHostComForTelemetry;
extern uint8_t g_iAlarmCode[4]; extern uint8_t g_iAlarmCode[4];

View File

@ -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_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); int exint_event_unregister(const char *event_name, event_callback callback, void* user_data);
void* exint_event_thread(void*); void* exint_event_thread(void*);
void exint_event_thread_exit();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -17,7 +17,7 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define EXTERN_INTERFACE_PUBLIC __declspec(dllexport) #define EXTERN_INTERFACE_PUBLIC __declspec(dllexport)
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define EXTERN_INTERFACE_PUBLIC __attribute__ ((dllexport)) #define EXTERN_INTERFACE_PUBLIC __attribute__ ((visibility("default")))
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -56,7 +56,7 @@ int exint_init(const char* config_path, et_callback_t cb);
EXTERN_INTERFACE_PUBLIC EXTERN_INTERFACE_PUBLIC
void exint_send(uint32_t type, size_t len, union PacketData data); void exint_send(uint32_t type, size_t len, union PacketData data);
EXTERN_INTERFACE_PUBLIC EXTERN_INTERFACE_PUBLIC
void extern_interface_deinit(); void exint_finialize();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -96,6 +96,8 @@ private:
class LoggerStreamBuf : public std::streambuf { class LoggerStreamBuf : public std::streambuf {
public: public:
LoggerStreamBuf(Logger& logger, Logger::Level level); LoggerStreamBuf(Logger& logger, Logger::Level level);
LoggerStreamBuf(const LoggerStreamBuf&) = delete;
LoggerStreamBuf(LoggerStreamBuf&& loggerStream) = default;
protected: protected:
int overflow(int c) override; int overflow(int c) override;

View File

@ -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); uint32_t length = ComFrame_Length(frame, swap_endian);
char* buf = (char*)frame; char* buf = (char*)frame;
#ifdef COM_FRAME_DEBUG #ifdef COM_FRAME_DEBUG
PrintFilePos(); printf("send length: %d\n", ComFrame_Length(frame, swap_endian)); printf("send length: %d\n", ComFrame_Length(frame, swap_endian));
PrintFilePos(); printf("send checksum: %04x\n", ComFrame_Checksum(frame, swap_endian)); printf("send checksum: %04x\n", ComFrame_Checksum(frame, swap_endian));
#endif #endif
while (length > 0) { while (length > 0) {
ssize_t written = write(tty_id, buf, length); 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) { if (recv_size <= 0 && cached_size == offset) {
usleep(2); usleep(2);
continue; continue;
} else if (recv_size < 0) {
perror("com read error");
recv_size = 0;
} }
#ifdef COM_FRAME_DEBUG #ifdef COM_FRAME_DEBUG
PrintFilePos(); printf( printf(
"receive com data (received=%zd,cached=%zu,number=%04x)\n", "receive com data (received=%zd,cached=%zu,number=%04x)\n",
recv_size, cached_size, ComFrame_HEADER(buffer)->magic_number 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) { 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'); putchar('\n');
#endif #endif
@ -275,7 +278,7 @@ ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size,
if (swap_endian) if (swap_endian)
ComFrameHeader_SwapEndian(ComFrame_HEADER(((uint8_t*)buffer) + offset)); ComFrameHeader_SwapEndian(ComFrame_HEADER(((uint8_t*)buffer) + offset));
#ifdef COM_FRAME_DEBUG #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 #endif
pred_size = ComFrame_LENGTH(((uint8_t*)buffer) + offset); pred_size = ComFrame_LENGTH(((uint8_t*)buffer) + offset);
if (pred_size > buffer_size) { if (pred_size > buffer_size) {

View File

@ -3,13 +3,14 @@
#include <vector> #include <vector>
#include <tuple> #include <tuple>
#include <memory> #include <memory>
#include <atomic>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "dataqueue.hpp" #include "dataqueue.hpp"
#include "exint/event.h" #include "exint/event.h"
#include "exint/detail.h" #include "exint/detail.h"
std::atomic_bool _is_event_thread_running { false };
DataQueue<std::tuple<const char*, event_callback, size_t, std::unique_ptr<uint8_t[]>, void*>> _event_queue; DataQueue<std::tuple<const char*, event_callback, size_t, std::unique_ptr<uint8_t[]>, void*>> _event_queue;
static std::unordered_map<std::string, std::vector<std::pair<event_callback, void*>>>& get_event_map() { static std::unordered_map<std::string, std::vector<std::pair<event_callback, void*>>>& 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); auto it = event_map.find(event_name);
if (it != event_map.end()) { if (it != event_map.end()) {
for (auto &pair : it->second) { for (auto &pair : it->second) {
auto args_copy = new uint8_t[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); memcpy(args_copy, args, args_size);
}
_event_queue.Push(std::make_tuple(event_name, pair.first, args_size, std::unique_ptr<uint8_t[]>(args_copy), pair.second)); _event_queue.Push(std::make_tuple(event_name, pair.first, args_size, std::unique_ptr<uint8_t[]>(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*) { 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; const char* event_name;
event_callback callback; event_callback callback;
size_t args_size; size_t args_size;
std::unique_ptr<uint8_t[]> args; std::unique_ptr<uint8_t[]> args;
void* user_data; void* user_data;
while (g_bKeepEtifRuning) { while (g_bKeepExintRuning) {
try {
std::tie(event_name, callback, args_size, args, user_data) = _event_queue.Pop(); 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); callback(event_name, args_size, args.get(), user_data);
} }
_is_event_thread_running.store(false);
return NULL; 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();
}

View File

@ -14,7 +14,7 @@ int g_iHostCom_tty_id;
int g_iTelemetry_Com_tty_id; int g_iTelemetry_Com_tty_id;
int g_iEnableAlarmCode = true; int g_iEnableAlarmCode = true;
bool g_bTelemetry_Open = true; bool g_bTelemetry_Open = true;
bool g_bKeepEtifRuning = false; bool g_bKeepExintRuning = false;
int g_iExternTimeDifference = 0; int g_iExternTimeDifference = 0;
int g_iUseHostComForTelemetry = true; int g_iUseHostComForTelemetry = true;
uint8_t g_iAlarmCode[4] = {0xAA, 0xAA, 0xAA, 0xAA}; 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; if (read_config(config_path)) return -1;
et_callback = cb; 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(&event_thread, NULL, exint_event_thread, NULL);
pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL); pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL);
pthread_create(&telemetry_thread, NULL, telemetry_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); exint_event(event_name, len, data_pointer);
} }
void extern_interface_deinit() { void exint_finialize() {
g_bKeepEtifRuning = false; g_bKeepExintRuning = false;
pthread_cancel(event_thread); pthread_cancel(event_thread);
pthread_cancel(upperhost_thread); pthread_cancel(upperhost_thread);
pthread_cancel(telemetry_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); et_callback(type, len, data);
} }

View File

@ -26,7 +26,7 @@ volatile bool g_bNeedReboot = false;
volatile int32_t g_iMS2Reboot = 1000; volatile int32_t g_iMS2Reboot = 1000;
void get_telemetry_data(TelemetryRequestData* data) { 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*/ /* 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 const uint16_t address = COM_FRAME_ADDRESS_VOIX; // TODO
size_t offset = 0, cached_size = 0; size_t offset = 0, cached_size = 0;
uint8_t* buffer = new uint8_t[buffer_size]; uint8_t* buffer = new uint8_t[buffer_size];
uint8_t err_data[2];
uint64_t iTelemetryAnswerTimes = 0; uint64_t iTelemetryAnswerTimes = 0;
void* pDataBlock;
int iRet;
TelemetryCommandInfo TeleCmdInfo2Send; TelemetryCommandInfo TeleCmdInfo2Send;
TelemetryData TelemetryData2Send; // gejp 2024.10.03 TelemetryData TelemetryData2Send; // gejp 2024.10.03
memset(&TeleCmdInfo2Send, 0, sizeof(TelemetryCommandInfo)); memset(&TeleCmdInfo2Send, 0, sizeof(TelemetryCommandInfo));
while (g_bKeepEtifRuning) { while (g_bKeepExintRuning) {
// if ( (iTelemetryAnswerTimes % 3 == 0) && g_bNeedReboot) system("reboot"); // 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); //ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true);
if (ComFrame_Verify(frame, false)) { if (ComFrame_Verify(frame, false)) {
if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_CHECKSUM, true)) 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 手控显示处理单元 void* upper_host_com_thread(void* arg) {//hand-control display processing unit 手控显示处理单元
int tty_id = g_iHostCom_tty_id; int tty_id = g_iHostCom_tty_id;
const uint16_t address = COM_FRAME_ADDRESS_VOIX; 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; const int64_t iHostAudioBufferSize = 1024 * 1024;
uint8_t* buffer = new uint8_t[buffer_size]; uint8_t* buffer = new uint8_t[buffer_size];
int64_t iEnqueueBytes;
bool bSucc;
char* pStrNotice;
size_t offset = 0, cached_size = 0; size_t offset = 0, cached_size = 0;
uint64_t iTelemetryAnswerTimes;
int16_t* ptrProcHostAudio = (int16_t*)malloc(iHostAudioBufferSize); int16_t* ptrProcHostAudio = (int16_t*)malloc(iHostAudioBufferSize);
int16_t* ptrProcHostAudioEnd = ptrProcHostAudio;
int ProcHostAudioLengthMS = 1000;
int iProcHostAudioSampleCnt;
timeval tLastTime, tCurTime; timeval tLastTime, tCurTime;
TelemetryData4UpperHost UpperHostTeleData; 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); //ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true);
//PrintFilePos(); printf("%04X \n", ComFrame_HEADER(frame)->type); //PrintFilePos(); printf("%04X \n", ComFrame_HEADER(frame)->type);
if (frame == NULL) break;
switch (ComFrame_HEADER(frame)->type) switch (ComFrame_HEADER(frame)->type)
{ {
case COM_FRAME_TYPE_COMMAND: case COM_FRAME_TYPE_COMMAND:
@ -446,7 +438,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit
else else
//-------END 2024.10.23 noted by zgb //-------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; break;
} }
case COM_FRAME_TYPE_SPEECH_INJECTED: 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_ADDRESS_VOIX,
COM_FRAME_TYPE_SPEECH_INJECTED, COM_FRAME_TYPE_SPEECH_INJECTED,
payload, 6, true); 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)) { if (ComFrame_Send(tty_id, f_data, true)) {
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno)); 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); PrintFilePos(); fprintf(stderr, " com frame interval %d\n", iIntervalTime);
tLastTime = tCurTime; 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; break;
} }
@ -558,7 +550,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit
if(!alarm) if(!alarm)
continue; 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}; uint8_t payload[6] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
ComFrame* f_data = ComFrame_New( ComFrame* f_data = ComFrame_New(

View File

@ -222,8 +222,7 @@ LoggerOStream::LoggerOStream(Logger& logger, Logger::Level level)
LoggerOStream::LoggerOStream(LoggerOStream&& loggerStream) LoggerOStream::LoggerOStream(LoggerOStream&& loggerStream)
: std::ostream(std::move(loggerStream)), _streamBuf(std::move(loggerStream._streamBuf)) : std::ostream(std::move(loggerStream)), _streamBuf(std::move(loggerStream._streamBuf))
{ {}
}
LoggerStreamBuf::LoggerStreamBuf(Logger& logger, Logger::Level level) LoggerStreamBuf::LoggerStreamBuf(Logger& logger, Logger::Level level)
: _logger(logger), _level(level) {} : _logger(logger), _level(level) {}

View File

@ -107,7 +107,7 @@ static __inline void print_separator_ex(char lc, const char* str, const char* co
static int collect_testcase() { static int collect_testcase() {
for (int i = 0; i < test_case_total; ++i) { for (int i = 0; i < test_case_total; ++i) {
puts(test_cases[i].name); puts(test_cases[i].name);
putchar(' '); // putchar(' ');
} }
putchar('\n'); putchar('\n');
return 0; return 0;

64
tests/test_event.cpp Normal file
View File

@ -0,0 +1,64 @@
#include <vector>
#include <thread>
#include <unistd.h>
#include "exint/event.h"
#include "exint/detail.h"
#include "c_testcase.h"
static std::vector<int> 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;
}

108
tests/test_host_com.cpp Normal file
View File

@ -0,0 +1,108 @@
#include <thread>
#include <pty.h>
#include <fcntl.h>
#include <unistd.h>
#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<std::tuple<uint32_t, size_t, PacketData>> 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;
}

132
tests/test_logging.cpp Normal file
View File

@ -0,0 +1,132 @@
#include <sstream>
#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<logging::Logger::Level::DEBUG>("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;
}

View File

@ -3,14 +3,14 @@
#include "c_testcase.h" #include "c_testcase.h"
#include "dataqueue.hpp" #include "dataqueue.hpp"
TEST_CASE(init) { TEST_CASE(test_init) {
DataQueue<int> q; DataQueue<int> q;
assert(q.Empty()); assert(q.Empty());
assert_eq(q.Size(), 0); assert_eq(q.Size(), 0);
END_TEST; END_TEST;
} }
TEST_CASE(push) { TEST_CASE(test_push) {
DataQueue<int> q; DataQueue<int> q;
q.Push(10); q.Push(10);
assert_eq(q.Size(), 1); assert_eq(q.Size(), 1);
@ -18,7 +18,7 @@ TEST_CASE(push) {
END_TEST; END_TEST;
} }
TEST_CASE(pop) { TEST_CASE(test_pop) {
DataQueue<int> q; DataQueue<int> q;
std::thread t([&]() { std::thread t([&]() {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
@ -32,3 +32,23 @@ TEST_CASE(pop) {
t.join(); t.join();
END_TEST; END_TEST;
} }
TEST_CASE(test_clear) {
DataQueue<int> 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;
}