feat(core): rename and restructure event handling and initialization
- Rename exint_init to exint_initialize - Update event handling to use multiple threads - Add epoch checking to DataQueue - Modify config reading logic - Update build scripts - Refactor test cases
This commit is contained in:
parent
ccaa4908b5
commit
53a5fe6d50
|
@ -31,7 +31,7 @@ if (CMAKE_CROSSCOMPILING)
|
|||
message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories(./include)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/src SRC_LIST)
|
||||
|
||||
add_library(exint SHARED ${SRC_LIST})
|
||||
|
@ -40,8 +40,9 @@ set_target_properties(exint_static PROPERTIES OUTPUT_NAME exint)
|
|||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(exint PRIVATE -Wno-nonnull -fvisibility=hidden)
|
||||
target_compile_options(exint_static PRIVATE -Wno-nonnull -fvisibility=hidden)
|
||||
endif()
|
||||
|
||||
link_libraries(pthread)
|
||||
link_libraries(pthread util)
|
||||
|
||||
subdirs(tests)
|
||||
add_subdirectory(tests)
|
||||
|
|
|
@ -29,7 +29,7 @@ cmake --build build -j6 --target test
|
|||
|
||||
以下接口由通讯模块公开,可以在VOIX主程序中使用。
|
||||
|
||||
1. `void exint_init(const char* config_path, et_callback_t cb)`:模块初始化函数,此函数会读取配置文件,开启串口并启动模块所需的线程
|
||||
1. `void exint_initialize(const char* config_path, et_callback_t cb)`:模块初始化函数,此函数会读取配置文件,开启串口并启动模块所需的线程
|
||||
- `config_path`:配置文件路径
|
||||
- `cb`:回调函数,用于进行指令响应和遥测数据请求
|
||||
2. `void (*et_callback_t)(uint32_t type, size_t len, void* data)`:回调函数类型,内部数据为指针类型的数据包仅保证在回调函数中有效。
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
#if !defined(AFX_CFGFILEPARSERGENERATOR_H__AAF8F913_7694_4A69_A05F_57A1A1887CA1__INCLUDED_)
|
||||
#define AFX_CFGFILEPARSERGENERATOR_H__AAF8F913_7694_4A69_A05F_57A1A1887CA1__INCLUDED_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4786)
|
||||
#pragma warning(disable:4503)
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class __attribute__((visibility("default"))) CCfgFileParser
|
||||
{
|
||||
public:
|
||||
explicit CCfgFileParser(bool base64 = false,
|
||||
char chSectionBMark = '[',
|
||||
char chSectionEMark = ']',
|
||||
char chRecordEMark = ';', //record end-mark
|
||||
char chCommentMark = '#'
|
||||
)
|
||||
:m_base64(base64), m_chSectionBMark(chSectionBMark), m_chSectionEMark(chSectionEMark),
|
||||
m_chRecordEMark(chRecordEMark), m_chCommentMark(chCommentMark), m_bShowError(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CCfgFileParser() {}
|
||||
|
||||
typedef std::map<std::string, std::string> SECTION_CONTENT;
|
||||
typedef std::map<std::string, SECTION_CONTENT > FILE_CONTENT;
|
||||
|
||||
private:
|
||||
bool m_base64;
|
||||
enum{
|
||||
SYNTAX_ERROR = 0x100,
|
||||
};
|
||||
|
||||
public:
|
||||
bool m_bShowError;
|
||||
const char* getErrorString(int err);
|
||||
int parseFile(const char* lpszFilename);
|
||||
int sections() const { return m_content.size(); }
|
||||
|
||||
FILE_CONTENT::const_iterator sectionBegin() const { return m_content.begin(); }
|
||||
FILE_CONTENT::const_iterator sectionEnd() const { return m_content.end(); }
|
||||
|
||||
//return empty-string if no corresponding value presented.
|
||||
bool getValue(const std::string& strSection, const std::string& strKey, const char *&Value) const;
|
||||
bool getValue(const std::string& strKey, const char *&Value) const;
|
||||
bool getIntValue(const std::string& strSection, const std::string& strKey, long &pValue) const;
|
||||
bool getIntValue(const std::string& strKey, long &Value) const;
|
||||
bool getDoubleValue(const std::string& strSection, const std::string& strKey, double &Value) const;
|
||||
bool getDoubleValue(const std::string& strKey, double &Value) const;
|
||||
void printContent();
|
||||
|
||||
protected:
|
||||
bool extractSection(char* line, std::string& strSection);
|
||||
bool extractKeyValue(char* line, std::pair<std::string, std::string>& pairKeyValue);
|
||||
|
||||
private:
|
||||
FILE_CONTENT m_content;
|
||||
|
||||
char m_chSectionBMark;
|
||||
char m_chSectionEMark;
|
||||
char m_chRecordEMark;
|
||||
char m_chCommentMark;
|
||||
int m_error_line;
|
||||
};
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) CCfgFileParser* createParser();
|
||||
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) void deleteParser(CCfgFileParser* parser);
|
||||
|
||||
|
||||
#endif // !defined(AFX_CFGFILEPARSERGENERATOR_H__AAF8F913_7694_4A69_A05F_57A1A1887CA1__INCLUDED_)
|
|
@ -47,6 +47,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
typedef uint8_t queue_epoch_t;
|
||||
|
||||
template <typename T>
|
||||
class DataQueue {
|
||||
public:
|
||||
|
@ -109,6 +111,18 @@ public:
|
|||
return m_Queue.size();
|
||||
}
|
||||
|
||||
queue_epoch_t GetEpoch() noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
return m_CurrEpoch;
|
||||
}
|
||||
|
||||
bool CheckEpoch(queue_epoch_t epoch) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
return m_CurrEpoch == epoch;
|
||||
}
|
||||
|
||||
void Clear() noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
|
@ -123,7 +137,7 @@ protected:
|
|||
std::condition_variable m_Cond;
|
||||
|
||||
private:
|
||||
uint8_t m_CurrEpoch;
|
||||
queue_epoch_t m_CurrEpoch;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _INCLUDE_EVENT_H_
|
||||
#define _INCLUDE_EVENT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define CONCAT_(prefix, suffix) prefix##suffix
|
||||
|
@ -23,8 +24,8 @@ typedef void (*event_callback)(const char*, size_t, void*, void*);
|
|||
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();
|
||||
void exint_event_thread_start(uint8_t num);
|
||||
void exint_event_thread_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _INCLUDE_EXINT_HANDLER_
|
||||
#define _INCLUDE_EXINT_HANDLER_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "comframe.h"
|
||||
|
||||
#define ET_HDL_FLAG_DEFAULT 0
|
||||
#define ET_HDL_FLAG_DISABLED 1
|
||||
#define ET_HDL_FLAG_ASYNC 2
|
||||
#define ET_HDL_FLAG_NOVERIFY 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct EtHandlerDef {
|
||||
uint16_t hd_type;
|
||||
uint16_t hd_flags;
|
||||
void (*hd_handler)(struct EtHandlerDef *handler, ComFrame* frame);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -44,7 +44,7 @@ struct TelemetryRequestData {
|
|||
typedef void (*et_callback_t)(uint32_t, size_t, void*);
|
||||
|
||||
EXTERN_INTERFACE_PUBLIC
|
||||
int exint_init(const char* config_path, et_callback_t cb);
|
||||
int exint_initialize(const char* config_path, et_callback_t cb);
|
||||
EXTERN_INTERFACE_PUBLIC
|
||||
void exint_send(uint32_t type, size_t len, void* data);
|
||||
EXTERN_INTERFACE_PUBLIC
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#!/bin/sh
|
||||
mkdir -p dist
|
||||
|
||||
zip -r "dist/exint-build-$(date +%Y%m%d-%H%M%S).zip" bin/ lib/ config/\
|
||||
NAME="dist/exint-build-$(date +%Y%m%d-%H%M%S).zip"
|
||||
|
||||
zip -r $NAME bin/ lib/ config/\
|
||||
scripts/ README.md include/external_interface.h
|
||||
|
||||
echo "Created $NAME"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#!/bin/sh
|
||||
mkdir -p dist
|
||||
|
||||
tar -czvf "dist/exint-$(date +%Y%m%d-%H%M%S).tar.gz" src/ include/ tests/ config/\
|
||||
NAME="dist/exint-$(date +%Y%m%d-%H%M%S).tar.gz"
|
||||
|
||||
tar -czvf $NAME src/ include/ tests/ config/\
|
||||
scripts/ toolchains/ README.md CMakeLists.txt mak .gitignore
|
||||
|
||||
echo "Created $NAME"
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
SERVER="sunrise@192.168.50.58"
|
||||
SDIST=$(./scripts/sdist.sh | tail -1 | sed "s/Created //")
|
||||
scp -r ${SDIST} $SERVER:/tmp
|
||||
ssh $SERVER << EOF
|
||||
mkdir -p voix_exint && cd voix_exint
|
||||
tar -xzf /tmp/$(basename ${SDIST})
|
||||
./mak $@
|
||||
rm -rf src/ include/ tests/ build/
|
||||
EOF
|
||||
rm -rf ./lib/x3/
|
||||
scp -r $SERVER:voix_exint/lib/ ./lib/x3/
|
|
@ -0,0 +1,263 @@
|
|||
//bb.cpp
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "CCfgFileParser.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static inline bool istab(int c) { return (c == '\t'); }
|
||||
|
||||
static inline char *strltrim(char *str) {
|
||||
while (isspace(*str) || istab(*str)) {
|
||||
++str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline char *strrtrim(char *str) {
|
||||
int len = strlen(str) - 1;
|
||||
while (isspace(str[len]) || istab(str[len])) {
|
||||
str[len--] = '\0';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
int CCfgFileParser::parseFile(const char *lpszFilename) {
|
||||
using std::string;
|
||||
std::ifstream in1(lpszFilename);
|
||||
|
||||
if (!in1.is_open()) return errno;
|
||||
|
||||
char line[2048];
|
||||
char *pline;
|
||||
bool bInSection = false;
|
||||
SECTION_CONTENT *pSC = NULL;
|
||||
string strSection;
|
||||
std::pair<string, string> pairKeyValue;
|
||||
|
||||
m_error_line = 0;
|
||||
m_content.clear();
|
||||
pSC = &m_content["default"];
|
||||
bInSection = true;
|
||||
string base64str("");
|
||||
string mystr("");
|
||||
while (!in1.eof()) {
|
||||
in1.getline(line, sizeof(line));
|
||||
|
||||
if (line[strlen(line)] != '\n')
|
||||
mystr += line + string("\n");
|
||||
else
|
||||
mystr += line;
|
||||
|
||||
}
|
||||
in1.close();
|
||||
|
||||
stringstream in;
|
||||
in.str(mystr);
|
||||
|
||||
while (!in.eof()) { /*if(base64str.size() > sizeof(line))
|
||||
{
|
||||
printf("error in config parser!\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(line, base64str.c_str(), base64str.size());
|
||||
*/
|
||||
in.getline(line, sizeof(line));
|
||||
pline = line;
|
||||
++m_error_line;
|
||||
pline = strltrim(pline);
|
||||
if (pline[0] == '\0') continue; //white line, skip
|
||||
if (pline[0] == m_chCommentMark) continue; //comment line, skip
|
||||
if (bInSection) {
|
||||
//is new-section begin?
|
||||
if (pline[0] == m_chSectionBMark && extractSection(pline, strSection)) {
|
||||
pSC = &m_content[strSection];
|
||||
}
|
||||
else if (extractKeyValue(pline, pairKeyValue)) {
|
||||
//key-value pair
|
||||
pSC->insert(pairKeyValue);
|
||||
}
|
||||
else {
|
||||
//in.close();
|
||||
return SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
else { //NOT in section
|
||||
//is a valid section?
|
||||
if (extractSection(pline, strSection)) {
|
||||
pSC = &m_content[strSection];
|
||||
bInSection = true;
|
||||
}
|
||||
else {
|
||||
//in.close();
|
||||
return SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
// in.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool CCfgFileParser::getValue(const std::string &strSection,
|
||||
const std::string &strKey, const char * &Value) const {
|
||||
FILE_CONTENT::const_iterator it;
|
||||
|
||||
if ((it = m_content.find(strSection)) != m_content.end()) {
|
||||
SECTION_CONTENT::const_iterator p;
|
||||
const SECTION_CONTENT §ion = (*it).second;//m_content[strSection];
|
||||
if ((p = section.find(strKey)) != section.end()) {
|
||||
Value = ((*p).second).c_str();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bShowError)
|
||||
fprintf(stderr, "***Error: fail to read [%s]:%s\n", strSection.c_str(), strKey.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCfgFileParser::getValue(const std::string &strKey, const char * &pValue) const {
|
||||
return getValue("default", strKey, pValue);
|
||||
}
|
||||
|
||||
bool CCfgFileParser::getIntValue(const std::string &strSection,
|
||||
const std::string& strKey, long& Value) const {
|
||||
const char* pstr;
|
||||
if (getValue(strSection, strKey, pstr) && strlen(pstr) > 0)
|
||||
{
|
||||
if (strlen(pstr) > 0)
|
||||
{
|
||||
Value = atol(pstr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (m_bShowError)
|
||||
fprintf(stderr, "***Error: fail to read [%s]:%s\n", strSection.c_str(), strKey.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCfgFileParser::getIntValue(const std::string &strKey, long &Value) const {
|
||||
return getIntValue("default", strKey, Value);
|
||||
}
|
||||
|
||||
bool CCfgFileParser::getDoubleValue(const std::string &strSection,
|
||||
const std::string &strKey, double &Value) const {
|
||||
const char *pstr;
|
||||
if (getValue(strSection, strKey, pstr) && strlen(pstr) > 0)
|
||||
{
|
||||
Value = atof(pstr);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bShowError)
|
||||
fprintf(stderr, "***Error: fail to read [%s]:%s\n", strSection.c_str(), strKey.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCfgFileParser::getDoubleValue(const std::string &strKey, double &Value) const {
|
||||
return getDoubleValue("default", strKey, Value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Description: Extract section name
|
||||
* Parameters: line[IN]---A string line to be parsed
|
||||
* strSection[OUT]---Section name
|
||||
*
|
||||
* Return Value: if section name is in the line return true,or return false
|
||||
*/
|
||||
bool CCfgFileParser::extractSection(char *line, std::string &strSection) {
|
||||
char *tmp;
|
||||
if (line[0] == m_chSectionBMark) {
|
||||
if ((tmp = strchr(++line, m_chSectionEMark)) != NULL) {
|
||||
*tmp = '\0';
|
||||
strSection = line;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Description: Parse a record line into a std:pair as key and value
|
||||
* Parameters: line[IN]---A string to be parsed
|
||||
* pairKeyValue[OUT]---Parsing result
|
||||
*
|
||||
* Return Value: If parse successfully return true,or return false
|
||||
*/
|
||||
|
||||
bool CCfgFileParser::extractKeyValue(char *line,
|
||||
std::pair<std::string, std::string> &pairKeyValue) {
|
||||
char *tmp;
|
||||
if ((tmp = strchr(line, m_chRecordEMark)) != NULL || (tmp = strchr(line, '\r')) != NULL ||
|
||||
(tmp = strchr(line, '='))) {
|
||||
if (*tmp == '=')
|
||||
tmp = line + strlen(line); // tmp++;
|
||||
*tmp = '\0'; //ignore content after ';'(the RecordEMark)
|
||||
if ((tmp = strchr(line, '=')) != NULL) {
|
||||
*tmp++ = '\0';
|
||||
tmp = strltrim(tmp);
|
||||
tmp = strrtrim(tmp);
|
||||
line = strrtrim(line);
|
||||
|
||||
pairKeyValue.first = line;
|
||||
pairKeyValue.second = tmp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *CCfgFileParser::getErrorString(int err) {
|
||||
static char buf[100];
|
||||
if (err == SYNTAX_ERROR) {
|
||||
sprintf(buf, "configuration file format is invalid at line %d", m_error_line);
|
||||
return buf;
|
||||
}
|
||||
else {
|
||||
return strerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCfgFileParser::printContent() {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
FILE_CONTENT::const_iterator pf;
|
||||
SECTION_CONTENT::const_iterator ps;
|
||||
for (pf = m_content.begin(); pf != m_content.end(); ++pf) {
|
||||
cout << "section:" << (*pf).first << endl;
|
||||
const SECTION_CONTENT &sc = (*pf).second;
|
||||
for (ps = sc.begin(); ps != sc.end(); ++ps) {
|
||||
cout << '\t' << (*ps).first << "=" << (*ps).second << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在库中定义一个工厂函数 createParser
|
||||
extern "C" __attribute__((visibility("default"))) CCfgFileParser* createParser() {
|
||||
return new CCfgFileParser(); // 在工厂函数中调用构造函数创建对象并返回指针
|
||||
}
|
||||
|
||||
// 在库中定义一个销毁函数 deleteParser
|
||||
|
||||
extern "C" __attribute__((visibility("default"))) void deleteParser(CCfgFileParser* parser) {
|
||||
// 在销毁函数中调用析构函数销毁对象
|
||||
delete parser;
|
||||
}
|
|
@ -4,15 +4,19 @@
|
|||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "logging/logger.hpp"
|
||||
#include "dataqueue.hpp"
|
||||
#include "exint/event.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;
|
||||
using EventCallbackData = std::tuple<std::string, event_callback, size_t, std::unique_ptr<uint8_t[]>, void*>;
|
||||
std::atomic_size_t _event_thread_count { 0 };
|
||||
DataQueue<EventCallbackData> _event_queue;
|
||||
|
||||
static auto& logger = *logging::get_logger("exint::event");
|
||||
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*>>> _events;
|
||||
return _events;
|
||||
|
@ -23,7 +27,7 @@ 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) {
|
||||
if (!_is_event_thread_running) {
|
||||
if (!_event_thread_count.load()) {
|
||||
pair.first(event_name, args_size, args, pair.second);
|
||||
continue;
|
||||
}
|
||||
|
@ -70,31 +74,46 @@ 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;
|
||||
std::string event_name;
|
||||
event_callback callback;
|
||||
size_t args_size;
|
||||
std::unique_ptr<uint8_t[]> args;
|
||||
void* user_data;
|
||||
while (g_bKeepExintRuning) {
|
||||
queue_epoch_t queue_epoch = _event_queue.GetEpoch();
|
||||
_event_thread_count.fetch_add(1);
|
||||
while (_event_queue.CheckEpoch(queue_epoch)) {
|
||||
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);
|
||||
callback(event_name.c_str(), args_size, args.get(), user_data);
|
||||
}
|
||||
_is_event_thread_running.store(false);
|
||||
_event_thread_count.fetch_sub(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void exint_event_thread_exit() {
|
||||
bool is_running = true;
|
||||
if (!_is_event_thread_running.compare_exchange_strong(is_running, false)) {
|
||||
void exint_event_thread_start(uint8_t num) {
|
||||
if (_event_thread_count.load()) {
|
||||
logger.warn("event thread already started");
|
||||
}
|
||||
for (int i = 0; i < num; i++) {
|
||||
std::thread([] { (void)exint_event_thread(NULL); }).detach();
|
||||
}
|
||||
while (_event_thread_count.load() != num) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
logger.info("started %d event threads", num);
|
||||
}
|
||||
|
||||
void exint_event_thread_stop() {
|
||||
if (!_event_thread_count.load()) {
|
||||
logger.warn("event thread already stopped");
|
||||
return;
|
||||
}
|
||||
_event_queue.Clear();
|
||||
while (_event_thread_count.load()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
logger.info("stopped event threads");
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#include <pthread.h>
|
||||
#include "logging/logger.hpp"
|
||||
#include "comframe.h"
|
||||
#include "CCfgFileParser.h"
|
||||
#include "inicpp.hpp"
|
||||
#include "exint/detail.h"
|
||||
#include "exint/event.h"
|
||||
|
||||
static auto& logger = *logging::get_logger("exint");
|
||||
static et_callback_t et_callback;
|
||||
static pthread_t event_thread;
|
||||
static pthread_t upperhost_thread;
|
||||
static pthread_t telemetry_thread;
|
||||
|
||||
int g_iHostCom_tty_id;
|
||||
int g_iTelemetry_Com_tty_id;
|
||||
int g_iHostCom_tty_id = 0;
|
||||
int g_iTelemetry_Com_tty_id = 0;
|
||||
int g_iEnableAlarmCode = true;
|
||||
bool g_bTelemetry_Open = true;
|
||||
bool g_bKeepExintRuning = false;
|
||||
|
@ -20,30 +21,53 @@ int g_iUseHostComForTelemetry = true;
|
|||
uint8_t g_iAlarmCode[4] = {0xAA, 0xAA, 0xAA, 0xAA};
|
||||
|
||||
static int read_config(const char* config_path) {
|
||||
inicpp::IniManager manager(config_path);
|
||||
if (!manager.isSectionExists("System-Setting")) return -1;
|
||||
auto system_setting = manager["System-Setting"];
|
||||
auto host_com_path = system_setting["HostInfo_COM_Path"];
|
||||
auto host_com_baudrate = system_setting.toInt("HostInfo_COM_Baud_Rate");
|
||||
g_iHostCom_tty_id = get_com_tty_id(host_com_path.c_str(), host_com_baudrate);
|
||||
g_iUseHostComForTelemetry = system_setting.toInt("Use_HostCOM_for_Telemetry");
|
||||
CCfgFileParser config;
|
||||
if (config.parseFile(config_path) < 0) {
|
||||
logger.error("read config file %s failed", config_path);
|
||||
return -1;
|
||||
}
|
||||
const char* host_com_path = NULL;
|
||||
if (!config.getValue("System-Setting", "HostInfo_COM_Path", host_com_path)) {
|
||||
logger.error("fail to read [System-Setting]:HostInfo_ExchangeMode from %s", config_path);
|
||||
}
|
||||
long host_com_baudrate = 115200;
|
||||
if (!config.getIntValue("System-Setting", "HostInfo_COM_Baud_Rate", host_com_baudrate)) {
|
||||
logger.error("fail to read [System-Setting]:HostInfo_COM_Baud_Rate from %s", config_path);
|
||||
}
|
||||
if (host_com_path != NULL)
|
||||
g_iHostCom_tty_id = get_com_tty_id(host_com_path, host_com_baudrate);
|
||||
|
||||
g_bTelemetry_Open = system_setting.toInt("Telemetry_Open") == 1;
|
||||
long use_host_com_for_telemetry = 1;
|
||||
if (!config.getIntValue("System-Setting", "Use_HostCOM_for_Telemetry", use_host_com_for_telemetry)) {
|
||||
logger.error("fail to read [System-Setting]:Use_HostCOM_for_Telemetry from %s", config_path);
|
||||
}
|
||||
g_iUseHostComForTelemetry = use_host_com_for_telemetry == 1;
|
||||
long telemetry_open = 1;
|
||||
if (!config.getIntValue("System-Setting", "Telemetry_Open", telemetry_open)) {
|
||||
logger.error("fail to read [System-Setting]:Telemetry_Open from %s", config_path);
|
||||
}
|
||||
g_bTelemetry_Open = telemetry_open == 1;
|
||||
if (g_bTelemetry_Open) {
|
||||
auto telemetry_com_path = system_setting["Telemetry_COM_Path"];
|
||||
auto telemetry_com_baudrate = system_setting.toInt("Telemetry_COM_Baud_Rate");
|
||||
g_iTelemetry_Com_tty_id = get_com_tty_id(telemetry_com_path.c_str(), telemetry_com_baudrate);
|
||||
|
||||
const char* telemetry_com_path = NULL;
|
||||
if (!config.getValue("System-Setting", "Telemetry_COM_Path", telemetry_com_path)) {
|
||||
logger.error("fail to read [System-Setting]:Telemetry_COM_Path from %s", config_path);
|
||||
}
|
||||
long telemetry_com_baudrate = 115200;
|
||||
if (!config.getIntValue("System-Setting", "Telemetry_COM_Baud_Rate", telemetry_com_baudrate)) {
|
||||
logger.error("fail to read [System-Setting]:Telemetry_COM_Baud_Rate from %s", config_path);
|
||||
}
|
||||
if (telemetry_com_path != NULL)
|
||||
g_iTelemetry_Com_tty_id = get_com_tty_id(telemetry_com_path, telemetry_com_baudrate);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exint_init(const char* config_path, et_callback_t cb) {
|
||||
int exint_initialize(const char* config_path, et_callback_t cb) {
|
||||
if (read_config(config_path)) return -1;
|
||||
et_callback = cb;
|
||||
|
||||
g_bKeepExintRuning = true;
|
||||
pthread_create(&event_thread, NULL, exint_event_thread, NULL);
|
||||
exint_event_thread_start(1);
|
||||
pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL);
|
||||
pthread_create(&telemetry_thread, NULL, telemetry_host_com_thread, NULL);
|
||||
return 0;
|
||||
|
@ -54,7 +78,7 @@ int exint_init_from_tty(int host_com_tty, int telemetry_com_tty, et_callback_t c
|
|||
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);
|
||||
exint_event_thread_start(1);
|
||||
pthread_create(&upperhost_thread, NULL, upper_host_com_thread, NULL);
|
||||
pthread_create(&telemetry_thread, NULL, telemetry_host_com_thread, NULL);
|
||||
return 0;
|
||||
|
@ -77,9 +101,9 @@ void exint_send(uint32_t type, size_t len, void* data) {
|
|||
|
||||
void exint_finialize() {
|
||||
g_bKeepExintRuning = false;
|
||||
pthread_cancel(event_thread);
|
||||
pthread_cancel(upperhost_thread);
|
||||
pthread_cancel(telemetry_thread);
|
||||
exint_event_thread_stop();
|
||||
}
|
||||
|
||||
void exint_handle_pack(uint32_t type, size_t len, void* data) {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "exint/handler.h"
|
|
@ -611,10 +611,10 @@ void send_command_upper_host(int length, void* payload) {
|
|||
payload, length, true);
|
||||
|
||||
struct timeval tCurTime;
|
||||
uint64_t last_send_time;
|
||||
while (need_resend && g_bKeepExintRuning) {
|
||||
gettimeofday(&tCurTime, NULL);
|
||||
uint64_t tCurTimeMs = tCurTime.tv_sec * 1000 + tCurTime.tv_usec / 1000;
|
||||
uint64_t last_send_time;
|
||||
while (need_resend) {
|
||||
if (sendtime == 0) {
|
||||
last_send_time = tCurTimeMs;
|
||||
|
||||
|
@ -678,3 +678,7 @@ void send_audio_upper_host(int length, void* payload) {
|
|||
ON_EVENT(send_command) {
|
||||
send_command_upper_host(args_size, args);
|
||||
}
|
||||
|
||||
ON_EVENT(send_audio) {
|
||||
send_audio_upper_host(args_size, args);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(test)
|
||||
|
||||
set(TESTS_DIR .)
|
||||
set(TEST_COMMON_SOURCE "${TESTS_DIR}/c_testcase.cpp")
|
||||
|
||||
file(GLOB_RECURSE TEST_FILES "${TESTS_DIR}/test_*.cpp")
|
||||
|
||||
foreach(TEST_FILE ${TEST_FILES})
|
||||
|
@ -12,6 +8,9 @@ foreach(TEST_FILE ${TEST_FILES})
|
|||
list(APPEND TEST_EXECUTABLES "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}")
|
||||
endforeach()
|
||||
|
||||
# message(STATUS "Test files: ${TEST_FILES}")
|
||||
# message(STATUS "Test executables: ${TEST_EXECUTABLES}")
|
||||
|
||||
add_custom_target(test
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES}
|
||||
DEPENDS ${TEST_EXECUTABLES}
|
||||
|
|
|
@ -14,13 +14,11 @@ ON_EVENT(test) {
|
|||
|
||||
SETUP {
|
||||
g_vec.clear();
|
||||
g_bKeepExintRuning = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEARDOWN {
|
||||
g_bKeepExintRuning = false;
|
||||
exint_event_thread_exit();
|
||||
exint_event_thread_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,15 +36,7 @@ TEST_CASE(test_event) {
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
exint_event_thread_start(2);
|
||||
int i = 2;
|
||||
exint_event("test", sizeof(int), &i);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
@ -60,5 +50,6 @@ TEST_CASE(test_event_thread) {
|
|||
assert(false);
|
||||
|
||||
end:
|
||||
exint_event_thread_stop();
|
||||
END_TEST;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-9)
|
||||
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-9)
|
||||
set(CMAKE_C_COMPILER arm-none-linux-gnueabihf-gcc)
|
||||
set(CMAKE_CXX_COMPILER arm-none-linux-gnueabihf-g++)
|
||||
|
||||
# set(CMAKE_CXX_FLAGS "-static ${CMAKE_CXX_FLAGS}")
|
||||
|
|
Loading…
Reference in New Issue