refactor(project): remove unused DataQueue implementation and CCfgFileParser

- Removed DataQueue and CCfgFileParser classes
- Deleted related source files and Makefile
- Updated .gitignore to exclude new directories
- Modified CMakeLists.txt to add library output path
- Added new memory comparison assertion macros in c_testcase.h
This commit is contained in:
ovizro 2024-12-06 22:08:52 +08:00
parent 5ca1a439f3
commit 610a7e4008
27 changed files with 213 additions and 1642 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ build
################ Executable program ################ ################ Executable program ################
bin/ bin/
lib/
dist/ dist/
################### VSCode config ################## ################### VSCode config ##################

View File

@ -5,6 +5,7 @@ project(external_interface CXX)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
if (NOT CMAKE_CROSSCOMPILING) if (NOT CMAKE_CROSSCOMPILING)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib)
endif() endif()
if (UNIX) if (UNIX)

49
README.md Normal file
View File

@ -0,0 +1,49 @@
# 外部接口模块文档
本文档主要描述Voix中的用于与遥测机及上位机进行通讯及相关附加功能的模块。
这些模块拆分自原host_com.cpp文件。
## 1. 构建及测试
使用cmake进行构建
```bash
cmake . -B build
cmake --build build -j6
```
使用cmake及ctest进行测试
```bash
cmake . -B build
cmake --build build -j6 --target test
```
或在构建完成后使用测试脚本:
```bash
./scripts/unittest.py bin/test_*
```
## 2. 模块公开接口
以下接口由通讯模块公开可以在VOIX主程序中使用。
1. `void exint_init(const char* config_path, et_callback_t cb)`:模块初始化函数,此函数会读取配置文件,开启串口并启动模块所需的线程
- `config_path`:配置文件路径
- `cb`:回调函数,用于进行指令响应和遥测数据请求
2. `void (*et_callback_t)(uint32_t type, size_t len, void* data)`:回调函数类型,内部数据为指针类型的数据包仅保证在回调函数中有效。
- `type`:数据包类型
- `len`:数据包长度,对于字符串类型数据应包含后缀`\0`的长度。
- `data`:数据包数据
4. 数据包类型(宏定义):
- `ET_TYPE_TEXT`:文本,对应`const char*`类型的数据
- `ET_TYPE_AUDIO`:音频,对应`short*`类型的数据
- `ET_TYPE_COMMAND`:指令码,对应`uint8_t[6]`类型的数据
- `ET_TYPE_ALARM`:告警码,对应`AlarmData*`类型的数据
- `ET_TYPE_TELEMETRY_REQUEST`:遥测请求,对应`TelemetryRequestData*`类型的数据,需要主程序在数据包内的指针中写入对应的变量数据
5. `void exint_send(uint32_t type, size_t len, void* data)`:发送数据包,此函数是非阻塞的
- `type`:数据包类型
- `len`:数据包长度,对于字符串类型数据应包含后缀`\0`的长度。
- `data`:数据包数据
6. `void exint_finialize()`:模块销毁函数,调用后模块会终止所有内部线程,释放所有资源。

View File

@ -154,6 +154,36 @@ extern "C"{
test_case_abort(1); \ test_case_abort(1); \
} \ } \
} while (0) } while (0)
#define assert_mem_eq(expr1, expr2, size) do { \
if (memcmp((expr1), (expr2), (size)) != 0) { \
printf("assertion failed: %s == %s\n", #expr1, #expr2); \
printf("\t#0: "); \
for (int i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr1))[i]); \
} \
printf("\n\t#1: "); \
for (int i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr2))[i]); \
} \
printf("\nfile: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
test_case_abort(1); \
} \
} while (0)
#define assert_mem_ne(expr1, expr2, size) do { \
if (memcmp((expr1), (expr2), (size)) == 0) { \
printf("assertion failed: %s != %s\n", #expr1, #expr2); \
printf("\t#0: "); \
for (int i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr1))[i]); \
} \
printf("\n\t#1: "); \
for (int i = 0; i < (size); i++) { \
printf("%02X", ((uint8_t*)(expr2))[i]); \
} \
printf("\nfile: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
test_case_abort(1); \
} \
} while (0)
typedef int (*test_case)(); typedef int (*test_case)();

View File

@ -7,7 +7,45 @@
#include <condition_variable> #include <condition_variable>
#include <stdexcept> #include <stdexcept>
class QueueException; template <typename T>
class DataQueue;
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 : public QueueException
{
public:
QueueCleared(void* queue) : QueueException(queue) {}
const char* what() const noexcept override
{
return "queue cleared";
}
};
class QueueTimeout : public QueueException
{
public:
QueueTimeout(void* queue) : QueueException(queue) {}
const char* what() const noexcept override
{
return "queue timeout";
}
};
template <typename T> template <typename T>
class DataQueue { class DataQueue {
@ -32,7 +70,7 @@ public:
{ {
m_Cond.wait(lock); m_Cond.wait(lock);
if (epoch != m_CurrEpoch) { if (epoch != m_CurrEpoch) {
throw QueueException(this); throw QueueCleared(this);
} }
} }
T data = std::move(m_Queue.front()); T data = std::move(m_Queue.front());
@ -51,9 +89,12 @@ public:
throw QueueTimeout(this); throw QueueTimeout(this);
} }
if (epoch != m_CurrEpoch) { if (epoch != m_CurrEpoch) {
throw QueueException(this); throw QueueCleared(this);
} }
} }
T data = std::move(m_Queue.front());
m_Queue.pop_front();
return data;
} }
bool Empty() noexcept bool Empty() noexcept
@ -85,37 +126,4 @@ private:
uint8_t m_CurrEpoch; 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

@ -10,7 +10,7 @@
extern "C" { extern "C" {
#endif #endif
void exint_handle_pack(uint32_t type, size_t len, union PacketData data); void exint_handle_pack(uint32_t type, size_t len, void* data);
int exint_init_from_tty(int host_com_tty, int telemetry_com_tty, et_callback_t cb); 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);

View File

@ -41,20 +41,12 @@ struct TelemetryRequestData {
int app_ver_low; int app_ver_low;
}; };
union PacketData typedef void (*et_callback_t)(uint32_t, size_t, void*);
{
int64_t pd_integer;
double pd_float;
const char* pd_text;
void* pd_pointer;
};
typedef void (*et_callback_t)(uint32_t, size_t, union PacketData);
EXTERN_INTERFACE_PUBLIC EXTERN_INTERFACE_PUBLIC
int exint_init(const char* config_path, et_callback_t cb); 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, void* data);
EXTERN_INTERFACE_PUBLIC EXTERN_INTERFACE_PUBLIC
void exint_finialize(); void exint_finialize();

View File

@ -1,263 +0,0 @@
//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 &section = (*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;
}

View File

@ -1,78 +0,0 @@
#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_)

View File

@ -1,44 +0,0 @@
INCS = log.h CCfgFileParser.h
SRCS = CCfgFileParser.cpp log.cpp dataqueue.cpp
CXX = g++
AR = ar
EXEC_SO = libqueuelog.so
EXEC_A = libqueuelog.a
EXEC_O = libqueuelog.o
# 输出目录
OUTPUT_LIB_DIR = ../../libs/
OUTPUT_INCLUDE_DIR=../../includes/
ifdef DEBUG_VERSION
CFLAGS := -DMY_DEBUG -fvisibility=hidden -g -Wall -fPIC -shared -std=c++11 -Wl,--as-needed
else
CFLAGS := -fvisibility=hidden -g3 -O2 -Wall -fPIC -shared -std=c++11 -Wl,--as-needed
endif
LFLAGS1 = -lpthread
OBJS = $(SRCS:.cpp=.o)
all: $(EXEC_SO) $(EXEC_A)
$(EXEC_SO): $(OBJS)
$(CXX) -o $(EXEC_SO) $(OBJS) $(CFLAGS) $(LFLAGS1)
$(EXEC_A): $(OBJS)
$(AR) rcs $(EXEC_A) $(OBJS)
mkdir -p $(OUTPUT_LIB_DIR)
mkdir -p $(OUTPUT_INCLUDE_DIR)
mv $(EXEC_A) $(OUTPUT_LIB_DIR)
mv $(EXEC_SO) $(OUTPUT_LIB_DIR)
cp -u *.h $(OUTPUT_INCLUDE_DIR)
find . -name "*.d" -type f -print -exec rm -rf {} \;
@echo "Compile successfully! result-->" $(OUTPUT_LIB_DIR)
%.o: %.cpp
$(CXX) -o $@ -c $< $(CFLAGS)
.PHONY: clean
clean:
rm -f $(EXEC_SO) $(EXEC_A) $(EXEC_O) $(OBJS)

View File

@ -1,11 +0,0 @@
#!/bin/sh
#rm -f *.so *.o
CUR=$(basename `pwd`)
echo $CUR
mkdir -p ../../_backup
tar --exclude=*.so --exclude=*.a --exclude=*.o --exclude=*.d --exclude=./.vs --exclude=*.git* --exclude=*.swp -czvf ../../_backup/${CUR}-`date +"%Y.%m.%d-%H.%M"`.tar.gz ../${CUR}/*
#tar -czvf ../_backup/${CUR}-`date +"%Y.%m.%d-%H.%M"`.tar.gz ../${CUR}
curDate=$(date +"%Y.%m.%d %H:%M:%S")
echo backup done@${curDate}

View File

@ -1,537 +0,0 @@
//#pragma once
#include <time.h>
#include "dataqueue.h"
#include <stdio.h>
#define BLOCK_PADDING_SIZE 64 //bytes
#define HEADER_BYTES 16//remain: block-bytes: 8 bytes int64_t + data bytes: 8bytes int64_t
#define CHECK_QUEUE_ERR 1
#define myMax(x,y) ((x)>(y)?(x):(y))
typedef void* voidPtr;
static char g_strDQCurTime[50] = "";
//----------------------------------------------------------------------------------------
inline char* GetCurTimeStr(char* strBuf, int iBufSize)// g_strDQCurTime
{
time_t tt;
tt = time(NULL);
strftime(strBuf, iBufSize, "%Y.%m.%d %H:%M:%S", localtime(&tt));//gener string with format:"YYYY-MM-DD hh:mm:ss"
return strBuf;
}
#define DATA_QUEUE_RETAIN_BLOCK_CNT 4
//----------------------------------------------------------------------------------------
DataQueue::DataQueue(int64_t iSizeInKB, int64_t iMaxBlockSize, bool bUseMutex, int iReadThreadCnt)
{
m_pDataBuf = NULL;
m_bUseMutex = bUseMutex;
if (m_bUseMutex)
pthread_mutex_init(&m_BufMutex, NULL);
InitQueue(iSizeInKB, iMaxBlockSize, iReadThreadCnt);//KB
}
//----------------------------------------------------------------------------------------
DataQueue::~DataQueue()
{
if (m_pDataBuf != NULL)
free((void*)m_pDataBuf);
if (m_bUseMutex)
pthread_mutex_destroy(&m_BufMutex);
}
//----------------------------------------------------------------------------------------
int DataQueue::InitQueue(int64_t iTotalKB4QueueBuf, int iMaxBlockBytes, int iReadThreadCnt)//KB
{
if (m_pDataBuf != NULL)
free((void*)m_pDataBuf);
m_pDataBuf = NULL;
m_iMaxBlockByte = iMaxBlockBytes;
m_iReservedBlockNum = iReadThreadCnt + DATA_QUEUE_RETAIN_BLOCK_CNT;
m_iReservedBufBytes = m_iMaxBlockByte * m_iReservedBlockNum; //4 times of m_iMaxBlockByte
int64_t iTotalByes = 0;
if (iTotalKB4QueueBuf > 0)
{
iTotalByes = iTotalKB4QueueBuf * 1024 + 2 * HEADER_BYTES + m_iReservedBufBytes; //KB;
m_pDataBuf = (uint8_t*)malloc(iTotalByes); //for safe sake in case of over step the border
if (m_pDataBuf == NULL)
{
fprintf(stderr, "\n----------------------------------------------------------------\n");
GetCurTimeStr(g_strDQCurTime, sizeof(g_strDQCurTime));
fprintf(stderr, "***Error: fail to malloc for data queue, mem:%ld @line:%d %s\n", iTotalKB4QueueBuf, __LINE__, g_strDQCurTime);
fprintf(stderr, "----------------------------------------------------------------\n");
fflush(stderr);
exit(4);
}
}
m_iFreeBytes = m_iQueueBufBytes = iTotalByes;
ResetDataQueue();
return 0;
}
//----------------------------------------------------------------------------------------
void DataQueue::ResetDataQueue()
{
if (m_bUseMutex)
pthread_mutex_lock(&m_BufMutex);
m_iBufOutPos = m_iBufInPos = 0;
m_iRcvBlocks = 0;
m_iRcvBytes = 0;
m_iProcBlocks = 0;
m_iEmptyTimes = 0;
m_iFullTimes = 0;
m_iPaddingBlocks = m_iProcPaddingBlocks = 0;
m_iFreeBytes = m_iQueueBufBytes;
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
}
//----------------------------------------------------------------------------------------
int64_t DataQueue::GetBufBytes()
{//Get buf size
int64_t iBytes;
iBytes = m_iQueueBufBytes - m_iReservedBufBytes;
if (iBytes < 0)
iBytes = 0;
return iBytes;
}
//----------------------------------------------------------------------------------------
int64_t DataQueue::GetQueueFreeBytes()
{
//int64_t iFreeBytes = (m_iBufInPos >= m_iBufOutPos ? (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)) : ((m_iBufOutPos - m_iBufInPos) ) );
int64_t iFreeBytes;
iFreeBytes = (m_iBufInPos >= m_iBufOutPos ? (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)) : ((m_iBufOutPos - m_iBufInPos)));
iFreeBytes -= m_iReservedBufBytes;
if (iFreeBytes < 0)//iFreeBytes never is 0 because of m_iReservedBufBytes, unless the beginning state where m_iBufOutPos and m_iBufInPos are same
iFreeBytes = 0;
return iFreeBytes;
}
//----------------------------------------------------------------------------------------
int64_t DataQueue::GetFreeBytes()
{
return GetQueueFreeBytes();
}
//----------------------------------------------------------------------------------------
inline bool DataQueue::CanRcv(int iNeedBytes)
{
bool bCanRcv;
m_iMaxBlockByte = iNeedBytes > m_iMaxBlockByte ? iNeedBytes : m_iMaxBlockByte;
m_iReservedBufBytes = m_iMaxBlockByte * m_iReservedBlockNum; //4<><34><EFBFBD><EFBFBD>m_iMaxBlockByte
bCanRcv = (GetQueueFreeBytes() >= iNeedBytes);
return bCanRcv;
}
//----------------------------------------------------------------------------------------
bool DataQueue::IsFull()
{
//---- 这种判断方式可能存在错误期间m_iBufOutPos到尾部折回到队列开头变得小于m_iBufInPos
//int iFreeBytes = (m_iBufInPos < m_iBufOutPos ? (m_iBufOutPos - m_iBufInPos) : (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)));//
bool bFull;
int64_t iFreeBytes;
iFreeBytes = (m_iBufInPos >= m_iBufOutPos ? (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)) : ((m_iBufOutPos - m_iBufInPos)));
bFull = (iFreeBytes <= m_iReservedBufBytes);
// if( bFull )
// printf("dataqueue is full, size:%ld free:%ld - %ld < retain:%ld in:%ld out:%ld\n",
// m_iQueueBufBytes,iFreeBytes, GetFreeBytes(),m_iReservedBufBytes,m_iBufInPos,m_iBufOutPos );
return bFull;
}
//----------------------------------------------------------------------------------------
bool DataQueue::IsEmpty()
{
return (m_iBufInPos == m_iBufOutPos);
}
//----------------------------------------------------------------------------------------
int64_t DataQueue::EnQueue(void* e, int64_t iDataBytes, void* extradata, int64_t iExtraDataBytes, void* extradata2, int64_t iExtraDataBytes2)
{ // >=0 for normal & success,
//<0: error
int64_t iBlockBytes;
void* pWritePos = NULL;
int64_t iPadding = 0;
if (iDataBytes < 0 || iExtraDataBytes < 0 || iExtraDataBytes2 < 0)
{
fprintf(stderr, "iDataBytes %ld iExtraDataBytes %ld iExtraDataBytes %ld\n",
iDataBytes, iExtraDataBytes, iExtraDataBytes2);
fflush(stderr);
throw __LINE__;
}
if (m_bUseMutex)
pthread_mutex_lock(&m_BufMutex);
int64_t iTotalDataBytes = iDataBytes + iExtraDataBytes + iExtraDataBytes2;
#if CHECK_QUEUE_ERR
CheckQueue(__LINE__, 0);
#endif
iBlockBytes = (((iTotalDataBytes + 7) >> 3) << 3)//8<>ı<EFBFBD><C4B1><EFBFBD>
+ HEADER_BYTES
+ BLOCK_PADDING_SIZE;// 32
if (!CanRcv(iBlockBytes))
{
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
return QUEUE_IS_FULL;
}
if (m_iBufInPos >= m_iBufOutPos)
{
if (m_iBufInPos + iBlockBytes > m_iQueueBufBytes)
{//create a padding block
*((int64_t*)(m_pDataBuf + m_iBufInPos)) = m_iQueueBufBytes - m_iBufInPos; //m_iQueueBufBytes: the next block is at the begining of the buf
*((int64_t*)(m_pDataBuf + m_iBufInPos + sizeof(int64_t))) = 0;
//m_iRcvBlocks++;
//printf("+iBlockBytes:%d, iDataByte:%d\n", m_iQueueBufBytes - m_iBufInPos, 0);
m_iPaddingBlocks++;
iPadding++;
m_iBufInPos = 0;
}
}
#if CHECK_QUEUE_ERR
CheckQueue(__LINE__, iBlockBytes);
#endif
pWritePos = m_pDataBuf + m_iBufInPos;
*((int64_t*)pWritePos) = iBlockBytes;
*((int64_t*)(pWritePos + sizeof(int64_t))) = iTotalDataBytes;
memcpy(pWritePos + HEADER_BYTES, e, iDataBytes);
if (extradata && iExtraDataBytes > 0)
memcpy(pWritePos + HEADER_BYTES + iDataBytes, extradata, iExtraDataBytes);//iExtraDataBytes
if (extradata2 && iExtraDataBytes2 > 0)
memcpy(pWritePos + HEADER_BYTES + iDataBytes + iExtraDataBytes, extradata2, iExtraDataBytes2);//iExtraDataBytes
m_iRcvBlocks++;
m_iRcvBytes += iTotalDataBytes;
m_iBufInPos = (m_iBufInPos + iBlockBytes) % m_iQueueBufBytes;
//#ifdef MY_DEBUG
// printf("+iBlockBytes:%d, iDataByte:%d\n", iBlockBytes, iDataBytes);
//#endif
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
return iTotalDataBytes;
}
//----------------------------------------------------------------------------------------
#ifdef ARM_VERSION //NO_PORN_FUNC
#define THERE_ARE_CONCURRENT_DEQUEUE_OP 1
#else
#define THERE_ARE_CONCURRENT_DEQUEUE_OP 1
#endif
int64_t DataQueue::DeQueue(void** e)
{//return value: Bytes, >0 if sucess, =0 no data, < 0 error. No data copy, only return the pointer of data area
void* p;
int iBlockBytes, iDataBytes;
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
{
pthread_mutex_lock(&m_BufMutex);
#if CHECK_QUEUE_ERR
CheckQueue(__LINE__, 0);
#endif
}
#endif
if (IsEmpty())
{
//#ifdef MY_DEBUG
// m_iEmptyTimes++;
// if ( m_iEmptyTimes <5 || ( m_iEmptyTimes % 50 == 0) )
// {
// printf("***Block Queue IsEmpty %1dth: m_iBufInPos=%lu, m_iBufOutPos=%lu, m_iQueueBufBytes=%lu, m_iReservedBufBytes=%lu\n",
// m_iEmptyTimes, m_iBufInPos, m_iBufOutPos, m_iQueueBufBytes, m_iReservedBufBytes); //<2F>ճ<EFBFBD>4<EFBFBD><34>
// fflush(stdout);
// }
//#endif
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
return EMPTY_QUEUE_NO_DATA;
}
p = m_pDataBuf + m_iBufOutPos;
iBlockBytes = *((int64_t*)p);
iDataBytes = *((int64_t*)(p + sizeof(int64_t)));
//int iDataBytes = *((int*)(p + sizeof(int)));
m_iBufOutPos = (m_iBufOutPos + iBlockBytes) % m_iQueueBufBytes;
//#ifdef MY_DEBUG
// printf("-iBlockBytes:%d, iDataByte:%d\n", iBlockBytes, iDataBytes);
//#endif
if (iDataBytes > 0)//not pading block
{
m_iProcBlocks++;
*e = (void*)(p + HEADER_BYTES);
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
return iDataBytes;
}
else//padding block
{
m_iProcPaddingBlocks++;
if (IsEmpty())
{
//printf("CSegmentPool IsEmpty\n");
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
return EMPTY_QUEUE_NO_DATA;
}
p = m_pDataBuf + m_iBufOutPos;
iBlockBytes = *((int64_t*)p);
iDataBytes = *((int64_t*)(p + sizeof(int64_t)));
//#ifdef MY_DEBUG
// printf("-iBlockBytes:%d, iDataByte:%d\n", iBlockBytes, iDataBytes);
//#endif
m_iBufOutPos = (m_iBufOutPos + iBlockBytes) % m_iQueueBufBytes;
#if CHECK_QUEUE_ERR
if (m_bUseMutex)
CheckQueue(__LINE__, 0);
#endif
if (iDataBytes > 0)//not pading block
{
m_iProcBlocks++;
*e = (void*)(p + HEADER_BYTES);
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
return iDataBytes;
}
else
{//pading block
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
m_iProcPaddingBlocks++;
char strMsg[200];
GetCurTimeStr(g_strDQCurTime, sizeof(g_strDQCurTime));
sprintf(strMsg, "***Error in DeQueue: 2 successive padding block!@line %d %s\n", __LINE__, g_strDQCurTime);
fprintf(stderr, "\n----------------------------------------------------------------\n");
fprintf(stderr, "%s", strMsg);
fprintf(stderr, "----------------------------------------------------------------\n");
fflush(stderr);
exit(0);
return EMPTY_QUEUE_NO_DATA;
}
}
#if THERE_ARE_CONCURRENT_DEQUEUE_OP
if (m_bUseMutex)
pthread_mutex_unlock(&m_BufMutex);
#endif
char strMsg[200];
GetCurTimeStr(g_strDQCurTime, sizeof(g_strDQCurTime));
sprintf(strMsg, "***Error in DeQueue: @line %d %s\n", __LINE__, g_strDQCurTime);
fprintf(stderr, "\n----------------------------------------------------------------\n");
fprintf(stderr, "%s", strMsg);
fprintf(stderr, "----------------------------------------------------------------\n");
fflush(stderr);
exit(0);
return EMPTY_QUEUE_NO_DATA;
}
//----------------------------------------------------------------------------------------
void DataQueue::OutPutStatus(char* strBuf, int iBufLen)
{
int iLen = iBufLen, iStrLen;
char* p = strBuf;
snprintf(p, iLen, "m_iBufOutPos = % ld, m_iBufInPos = % ld, m_iFreeBytes = % ld, m_iQueueBufBytes = % ld, m_iRcvBlocks = % ld, m_iRcvBytes = % ld\n",
m_iBufOutPos, m_iBufInPos, m_iFreeBytes, m_iQueueBufBytes, m_iRcvBlocks, m_iRcvBytes);
iStrLen = strlen(p);
p += iStrLen;
iLen -= iStrLen;
snprintf(p, iLen, "\m_iProcBlocks=%ld, m_iPaddingBlocks=%ld, m_iProcPaddingBlocks=%ld, m_iMaxBlockByte=%ld, m_iReservedBufBytes=%ld, m_iReservedBlockNum=%ld,m_iEmptyTimes=%ld, m_iFullTimes=%ld\n",
m_iProcBlocks, m_iPaddingBlocks, m_iProcPaddingBlocks, m_iMaxBlockByte, m_iReservedBufBytes, m_iReservedBlockNum, m_iEmptyTimes, m_iFullTimes);
iStrLen = strlen(p);
p += iStrLen;
iLen -= iStrLen;
}
//----------------------------------------------------------------------------------------
bool DataQueue::CheckQueue(int iLineNo, int iNeedBytes)
{
int64_t iFreeBytes;
int iErr = 0;
//int iFreeBytes = (m_iBufInPos < m_iBufOutPos ? (m_iBufOutPos - m_iBufInPos) : (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)) );//
iFreeBytes = (m_iBufInPos >= m_iBufOutPos ? (m_iQueueBufBytes - (m_iBufInPos - m_iBufOutPos)) : (m_iBufOutPos - m_iBufInPos));
if (m_iBufOutPos < 0)
iErr |= 0x1;
if (m_iBufInPos < 0)
iErr |= 0x2;
if (iFreeBytes < (m_iReservedBlockNum - 2) * m_iMaxBlockByte)
iErr |= 0x4;
if (iFreeBytes < iNeedBytes)
iErr |= 0x8;
if (m_bUseMutex && (m_iProcBlocks == m_iRcvBlocks)
&& (m_iPaddingBlocks == m_iProcPaddingBlocks)
&& (m_iBufOutPos != m_iBufInPos))
iErr |= 0x10;
if (iErr)
{
char strMsg[1000];
char strInfo[1000];
OutPutStatus(strMsg, sizeof(strMsg));
snprintf(strInfo, sizeof(strInfo), "******QueueError %d @line %d, iFreeBytes=%ld , iNeedBytes=%d:\n%s \n",
iErr, iLineNo, iFreeBytes, iNeedBytes, strMsg);
FILE* fp = fopen("err.log", "a+");
if (fp)
{
fprintf(fp, "%s\n", strInfo);
fflush(fp);
fclose(fp);
}
fprintf(stderr, "\n----------------------------------------------------------------\n");
fprintf(stderr, "%s\n", strInfo);
fprintf(stderr, "----------------------------------------------------------------\n");
fflush(stderr);
//throw __LINE__;
return false;
}
return true;
}
//----------------------------------------------------------------------------------------
extern "C" voidPtr __attribute__((visibility("default"))) OpenDataQueue(int64_t iTotalKB4QueueBuf, int iMaxBlockBytes, int iReadThreadCnt)
{
//DataQueue* p = new DataQueue(iTotalKB4QueueBuf, iMaxBlockBytes, bConcurrent);//bUseMutex = bConcurrent
DataQueue* p = new DataQueue(iTotalKB4QueueBuf, iMaxBlockBytes, true);//bUseMutex = true
return (void*)p;
}
//----------------------------------------------------------------------------------------
extern "C" bool __attribute__((visibility("default"))) GetDataQueueInfo(void* pQueue, int64_t iSize[5])
{//return the total data blocks, and set the buf with info string
int64_t iFreeBytes, iBufBytes;
DataQueue* p = (DataQueue*)pQueue;
if (!pQueue)
return false;
iSize[0] = p->GetBufBytes();
iSize[1] = p->GetFreeBytes();
iSize[2] = p->GetTotalRcvBlockCnt();
iSize[3] = p->GetProcBlockCnt();
iSize[4] = p->GetBlockCnt();
return true;
}
//----------------------------------------------------------------------------------------
#define LOG_QUEUE_INFO 0
extern "C" int64_t __attribute__((visibility("default"))) EnDataQueue(void* pQueue, void* e, int64_t iDataBytes, void* extradata1, int64_t iExtraDataBytes1, void* extradata2, int64_t iExtraDataBytes2)
{// int DataQueue::EnQueue(void* e, int64_t iDataBytes, void* extradata1, int64_t iExtraDataBytes1, void* extradata2, int64_t iExtraDataBytes2)
int64_t iRet =0;
if (pQueue)
{
#if LOG_QUEUE_INFO
char strBuf[500];
char strBuf2[500];
FILE* fp = NULL;
snprintf(strBuf, sizeof(strBuf), "queue%p.log", pQueue);
fp = fopen(strBuf, "a+");
if (fp)
{
snprintf(strBuf, sizeof(strBuf), "EnQueue1: iDataBytes=%ld, extradata1=%ld, extradata2=%ld\n",
iDataBytes, iExtraDataBytes1, iExtraDataBytes2);
((DataQueue*)pQueue)->OutPutStatus(strBuf2, sizeof(strBuf2));
fprintf(fp, "%s%s", strBuf, strBuf2);
}
#endif
iRet = ((DataQueue*)pQueue)->EnQueue(e, iDataBytes, extradata1, iExtraDataBytes1, extradata2, iExtraDataBytes2);
#if LOG_QUEUE_INFO
if (fp)
{
((DataQueue*)pQueue)->OutPutStatus(strBuf2, sizeof(strBuf2));
fprintf(fp, "EnQueue2: iRet=%ld\n%s\n\n", iRet, strBuf2);
fclose(fp);
}
#endif
}
return iRet;
}
extern "C" int64_t __attribute__((visibility("default"))) DeDataQueue(void* pQueue, void** e)
{
int64_t iRet = 0;
if (pQueue)
{
#if LOG_QUEUE_INFO
char strBuf[500];
char strBuf2[500];
FILE* fp = NULL;
snprintf(strBuf, sizeof(strBuf), "queue%p.log", pQueue);
fp = fopen(strBuf, "a+");
if (fp)
{
((DataQueue*)pQueue)->OutPutStatus(strBuf2, sizeof(strBuf2));
fprintf(fp, "DeQueue1: %s\n", strBuf2);
}
#endif
iRet = ((DataQueue*)pQueue)->DeQueue(e);
#if LOG_QUEUE_INFO
if (fp)
{
((DataQueue*)pQueue)->OutPutStatus(strBuf2, sizeof(strBuf2));
fprintf(fp, "DeQueue2: iRet=%ld\n%s\n\n", iRet, strBuf2);
fclose(fp);
}
#endif
}
return iRet;
}
extern "C" bool __attribute__((visibility("default"))) DataQueueIsFull(void* pQueue)
{
return ((DataQueue*)pQueue)->IsFull();
}
extern "C" void __attribute__((visibility("default"))) ResetDataQueue(void* pQueue)
{//delete all data in the queue, and reset all counters to 0
((DataQueue*)pQueue)->ResetDataQueue();
}
extern "C" void __attribute__((visibility("default"))) CloseDataQueue(void*& pQueue)
{
if (pQueue)
delete (DataQueue*)pQueue;
pQueue = NULL;
}

View File

@ -1,78 +0,0 @@
//#pragma once
#ifndef __HIT_DATAQUEUE_H
#define __HIT_DATAQUEUE_H
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cstring>
#define MAX_BLOCK_BYTES (1024*1024*2)
#define QUEUE_IS_FULL (-1)
#define EMPTY_QUEUE_NO_DATA (0)
class DataQueue
{
public:
DataQueue(int64_t iSizeInKB = 0, int64_t iMaxBlockSize = MAX_BLOCK_BYTES, bool bUseMutex = true, int iReadThreadCnt=1);
~DataQueue();
//private:
void* m_pDataBuf; //[DATA_BUF_LEN]
int64_t m_iBufOutPos;
int64_t m_iBufInPos;
int64_t m_iFreeBytes;
int64_t m_iQueueBufBytes;
int64_t m_iRcvBlocks;//total count
int64_t m_iRcvBytes;//total Bytes
int64_t m_iProcBlocks;
int64_t m_iPaddingBlocks;//padding block cnt in enqueue
int64_t m_iProcPaddingBlocks;//processed padding block cnt in dequeue
int64_t m_iMaxBlockByte;
int64_t m_iReservedBufBytes;
int64_t m_iReservedBlockNum;
int64_t m_iEmptyTimes;
int64_t m_iFullTimes;
bool m_bUseMutex;
pthread_mutex_t m_BufMutex;//pthread_mutex_init(&m_BufMutex, NULL);
bool IsEmpty(); //
bool IsFull();
inline bool CanRcv(int iNeedBytes);
public:
int64_t EnQueue(void* pdata, int64_t iDataBytes = 0, void* extradata = NULL, int64_t iExtraDataBytes = 0, void* extradata2 = NULL, int64_t iExtraDataBytes2 = 0);
int64_t DeQueue(void** pdata);//return value: Bytes, >0 if sucess, =0 no data, < 0 error. No data copy, only return the pointer of data area
uint64_t GetBlockCnt() {
return m_iRcvBlocks - m_iProcBlocks;
};
int64_t GetProcBlockCnt() {
return m_iProcBlocks;
};
int64_t GetTotalRcvBlockCnt() {
return m_iRcvBlocks;
};
int64_t GetFreeBytes();
int64_t GetBufBytes();
inline int64_t GetQueueFreeBytes();
int InitQueue(int64_t iTotalKB4QueueBuf, int iMaxBlockKB = MAX_BLOCK_BYTES, int iReadThreadCnt = 1);//KB
bool CheckQueue(int iLineNo, int iNeedBytes);
void OutPutStatus(char* strBuf, int iLen);
void ResetDataQueue();
};
#define LOG_QUEUE_INFO 0
typedef void* voidPtr;
extern "C" voidPtr __attribute__((visibility("default"))) OpenDataQueue(int64_t iTotalKB4QueueBuf, int iMaxBlockBytes, int iReadThreadCnt);
extern "C" bool __attribute__((visibility("default"))) GetDataQueueInfo(void* pQueue, int64_t iSize[5]);
extern "C" int64_t __attribute__((visibility("default"))) EnDataQueue(void* pQueue, void* e, int64_t iDataBytes, void* extradata1, int64_t iExtraDataBytes1, void* extradata2, int64_t iExtraDataBytes2);
extern "C" int64_t __attribute__((visibility("default"))) DeDataQueue(void* pQueue, void** e);
extern "C" bool __attribute__((visibility("default"))) DataQueueIsFull(void* pQueue);
extern "C" void __attribute__((visibility("default"))) ResetDataQueue(void* pQueue);
extern "C" void __attribute__((visibility("default"))) CloseDataQueue(void*& pQueue);
#endif

View File

@ -1,42 +0,0 @@
#include "log.h"
namespace QUEUE_LOG_COFIG
{
void* WriteLogThread(void* param)
{
CLogFile* pLog = (CLogFile*)(param);
pLog->writeQueue2File();//
}
}
using namespace QUEUE_LOG_COFIG;
typedef void* voidPtr;
//--------------------------------------------------------------------------------------------------------------
extern "C" voidPtr __attribute__((visibility("default"))) OpenLogFile(const char* strPath, const char* strFileName, bool bLogByDay)
{
//CLogFile* p = new CLogFile(strPath, strFileName, bLogByDay, 1);//use queue
CLogFile* p = new CLogFile(strPath, strFileName, false, 1);//use queue 2021.11.09
return (voidPtr)p;
}
//-----------------------------------------------------------------------------------------------------------------
extern "C" int __attribute__((visibility("default"))) WriteLog(void* pLogFile, const char* fmt, ...)
{
if (!pLogFile)
return -1;
char strInfo[INFO_BUF_LEN];
va_list arglist;
va_start(arglist, fmt);
vsprintf(strInfo, fmt, arglist);
va_end(arglist);
((CLogFile*)pLogFile)->append_one_item(0, strInfo);
return 0;
}
//-----------------------------------------------------------------------------------------------------------------
extern "C" void __attribute__((visibility("default"))) CloseLog(void* pLogFile)
{
((CLogFile*)pLogFile)->close_log_file();
return;
}

View File

@ -1,287 +0,0 @@
#ifndef __HIT_LOG_HEADER
#define __HIT_LOG_HEADER
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include "dataqueue.h"
#define INFO_BUF_LEN 4096//2048
typedef void* voidPtr;
extern "C" voidPtr __attribute__((visibility("default"))) OpenLogFile(const char* strPath, const char* strFileName, bool bLogByDay);
//-----------------------------------------------------------------------------------------------------------------
extern "C" int __attribute__((visibility("default"))) WriteLog(void* pLogFile, const char* fmt, ...);
//-----------------------------------------------------------------------------------------------------------------
extern "C" void __attribute__((visibility("default"))) CloseLog(void* pLogFile);
namespace QUEUE_LOG_COFIG
{
static uint64_t g_iLogFileMaxSize = 2L * 1024 * 1024 * 1024;
static uint64_t g_iCheckLogInterval = 20;//20s
inline int checkdir(const char* sPathName)
{
char DirName[256];
strcpy(DirName, sPathName);
int i, len = strlen(DirName);
if (DirName[len - 1] != '/')
strcat(DirName, "/");
len = strlen(DirName);
for (i = 1; i < len; i++)
{
if (DirName[i] == '/')
{
DirName[i] = 0;
if (access(DirName, 0) != 0)
{
if (mkdir(DirName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1)
{
perror(" mkdir error");
return -1;
}
}
DirName[i] = '/';
}
}
return 0;
}
/*
** log class, it is not thread safe.
*/
void* WriteLogThread(void* param);
struct InfoItem
{
struct tm t;
bool bLogTime;
char strInfo[INFO_BUF_LEN];
int GetLen() { return (uint64_t)(&strInfo[0]) - (uint64_t)(this) + strlen(strInfo) + 1; }
};
class CLogFile
{
private:
char* log_filename;
char* log_dirpath;
char* log_fullpath_filename;
int m_bRecordByDay;
int current_day;
FILE* file_handle;
DataQueue m_InfoQueue; //
bool m_bExit;
bool m_bUseQueue;
bool m_bWriteFinish;
pthread_t m_pWriteThreadHandle;
private:
void set_log_fullpath_filename(struct tm* t)
{
if (log_fullpath_filename == NULL)
log_fullpath_filename = (char*)calloc(strlen(log_dirpath) + 1 + 8 + 1 + strlen(log_filename) + 1 + 10, sizeof(char));
if (m_bRecordByDay)
{
current_day = t->tm_mday;
sprintf(log_fullpath_filename, "%s%02d%02d%02d/", log_dirpath, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
}
else
sprintf(log_fullpath_filename, "%s", log_dirpath);
checkdir(log_fullpath_filename);
strcat(log_fullpath_filename, log_filename);
}
void open_log_file()
{
file_handle = fopen(log_fullpath_filename, "a");
if (file_handle == NULL)
{//2019.07.18------------------
fprintf(stderr, "\n----------------------------------------------------------------\n");
fprintf(stderr, "***Fatal error: can't open file: %s", log_fullpath_filename);
fprintf(stderr, "----------------------------------------------------------------\n");
fflush(stderr);
exit(1);
}
}
struct tm* get_time()
{
time_t clock;
time(&clock);
struct tm* t = localtime(&clock);
return t;
}
void print_time()
{
struct tm* t = get_time();
fprintf(file_handle, "%4d-%02d-%02d %02d:%02d:%02d\n",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
}
public:
FILE* GetFileHande() { return file_handle; }
CLogFile(const char* dir, const char* name, int byDay, bool bUseQueue = false)
{
m_bRecordByDay = byDay;
m_bUseQueue = bUseQueue;
file_handle = NULL;
m_bWriteFinish = true;
m_bExit = false;
log_dirpath = (char*)calloc(strlen(dir) + 10, sizeof(char));
log_filename = (char*)calloc(strlen(name) + 10, sizeof(char));
strcpy(log_dirpath, dir);
int i, len = strlen(log_dirpath);
if (log_dirpath[len - 1] != '/')
strcat(log_dirpath, "/");
strcpy(log_filename, name);
log_fullpath_filename = NULL;
struct tm* t = get_time();
set_log_fullpath_filename(t);
open_log_file();
if (bUseQueue)
{
m_InfoQueue.InitQueue(32 * 1024, 8 * 2048);
pthread_create(&m_pWriteThreadHandle, NULL, WriteLogThread, this);
}
}
~CLogFile()
{
m_bExit = true;
pthread_join(m_pWriteThreadHandle, NULL);
close_log_file();
free(log_filename);
free(log_dirpath);
free(log_fullpath_filename);
}
void append_one_item(int print_time_flag, const char* fmt, ...)
{//append the new info into the queue
char fmtbuf[INFO_BUF_LEN];
va_list arglist;
if (m_bExit) return;
InfoItem tmpInfoItem;
va_start(arglist, fmt);
vsprintf(fmtbuf, fmt, arglist);
va_end(arglist);
snprintf(tmpInfoItem.strInfo, sizeof(tmpInfoItem.strInfo), fmtbuf);
tmpInfoItem.t = *get_time();
tmpInfoItem.bLogTime = print_time_flag;
if (m_bUseQueue)
m_InfoQueue.EnQueue((void*)(&tmpInfoItem), tmpInfoItem.GetLen());
else
{
writeItem2File(&tmpInfoItem);
}
}
void checksize(uint64_t iSize)
{
uint64_t iFileBytes = ftell(file_handle);
if (iFileBytes > iSize)
{
char strBackupName[500];
char strCurTime[20];
time_t tt;
tt = time(NULL);
strftime(strCurTime, sizeof(strCurTime), "%Y.%m.%d-%H.%M.%S", localtime(&tt));//产生“YYYY-MM-DD hh:mm:ss”格式的字符串。
sprintf(strBackupName, "%s-bak%s", log_fullpath_filename, strCurTime);
close_log_file();
rename(log_fullpath_filename, strBackupName);//把原文件重命名为新的文件名
open_log_file();
}
};
void writeItem2File(InfoItem* pInfoItem)
{
if (file_handle == NULL)
{//2019.07.18
return;
}
int iBytes;
if ((m_bRecordByDay) && (pInfoItem->t.tm_mday != current_day))
{//change_to_new_day
close_log_file();
current_day = pInfoItem->t.tm_mday;
set_log_fullpath_filename(&(pInfoItem->t));
open_log_file();
char strCmd[300];
sprintf(strCmd, "find %s -type d -mtime +30 -exec rm -rf {} \\;", log_dirpath);
system(strCmd);
}
if (pInfoItem->bLogTime)
{
iBytes = fprintf(file_handle, "%s %4d.%02d.%02d %02d:%02d:%02d\n",
pInfoItem->strInfo,
pInfoItem->t.tm_year + 1900, pInfoItem->t.tm_mon + 1, pInfoItem->t.tm_mday,
pInfoItem->t.tm_hour, pInfoItem->t.tm_min, pInfoItem->t.tm_sec);
}
else
iBytes = fprintf(file_handle, "%s", pInfoItem->strInfo);
if (iBytes < 0)
fprintf(stderr, "***writing \"%s\" to log failed! errno:%d, %s\n", pInfoItem->strInfo, errno, strerror(errno));
else
fflush(file_handle);
}
void writeQueue2File()
{
unsigned int iWiteItems = 0;
InfoItem* pInfoItem;
struct tm* t;
m_bWriteFinish = false;
unsigned n = 0;
int iBytes;
while (!m_bExit)
{
iBytes = m_InfoQueue.DeQueue((void**)(&pInfoItem));
if (iBytes <= 0)
{
sleep(1);//10ms
continue;
}
writeItem2File(pInfoItem);
if ((++n % g_iCheckLogInterval == 0) && (!m_bRecordByDay))
checksize(g_iLogFileMaxSize);// 2L * 1024 * 1024 * 1024);//不超过2GB
}
t = get_time();
fprintf(file_handle, "...finish and exit! @%4d.%02d.%02d %02d:%02d:%02d\n\n",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
fflush(file_handle);
m_bWriteFinish = true;
}
void close_log_file()
{
if (file_handle != NULL)
{
fflush(file_handle);
fclose(file_handle);
file_handle = NULL;
}
}
void clear_expired_logs()
{
}
};
//void * WriteLogThread(void* param)
//{
// CLogFile *pLog = (CLogFile*)(param);
// pLog->writeQueue2File();//
//}
//---------------------------------------------------------------------------------------------------
}
#endif

View File

@ -1,17 +0,0 @@
#!/bin/bash
if echo "$@" | grep -iq r; then
Param1="RELEASE_VERSION=yes"
else
Param1="DEBUG_VERSION=yes"
fi
make clean
clear
if echo "$@" | grep -iq e; then
#------ compile for euler -------------------
make -j 4 $Param1 CXX=arm-ztkp_openeuler-linux-gnueabi-g++ AR=arm-ztkp_openeuler-linux-gnueabi-ar OUTPUT_LIB_DIR=../../libs-euler/
else
#------- compile for arm32 ------------------
make -j 4 $Param1 CXX=arm-linux-gnueabihf-g++ AR=arm-linux-gnueabihf-ar OUTPUT_LIB_DIR=../../libs-arm32/
fi

2
mak
View File

@ -19,5 +19,5 @@ fi
mkdir -p ${BUILD_PREFIX} && cd ${BUILD_PREFIX} mkdir -p ${BUILD_PREFIX} && cd ${BUILD_PREFIX}
rm -f CMakeCache.txt rm -f CMakeCache.txt
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} -DEXECUTABLE_OUTPUT_PATH=../../bin/${BUILD_PREFIX} ../.. cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} -DEXECUTABLE_OUTPUT_PATH=../../bin/${BUILD_PREFIX} -DLIBRARY_OUTPUT_PATH=../../lib/${BUILD_PREFIX} ../..
cmake --build . -j 4 -- cmake --build . -j 4 --

5
scripts/bdist.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
mkdir -p dist
zip -r "dist/exint-build-$(date +%Y%m%d-%H%M%S).zip" bin/ lib/ config/\
scripts/ README.md

5
scripts/sdist.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
mkdir -p dist
tar -czvf "dist/exint-$(date +%Y%m%d-%H%M%S).tar.gz" src/ include/ tests/ config/\
scripts/ toolchains/ tools/ README.md CMakeLists.txt mak .gitignore

View File

@ -389,7 +389,7 @@ if __name__ == "__main__":
for p in namespace.path: for p in namespace.path:
if '*' in p: if '*' in p:
paths.extend(glob(p, recursive=True)) paths.extend(glob(p, recursive=True))
else: elif os.path.isfile(p):
paths.append(p) paths.append(p)
for p in paths: for p in paths:
f = CTestCaseFile(p) f = CTestCaseFile(p)

View File

@ -60,9 +60,8 @@ int exint_init_from_tty(int host_com_tty, int telemetry_com_tty, et_callback_t c
return 0; return 0;
} }
void exint_send(uint32_t type, size_t len, union PacketData data) { void exint_send(uint32_t type, size_t len, void* data) {
const char* event_name; const char* event_name;
void* data_pointer = data.pd_pointer;
switch (type) { switch (type) {
case ET_TYPE_COMMAND: case ET_TYPE_COMMAND:
event_name = "send_command"; event_name = "send_command";
@ -73,7 +72,7 @@ void exint_send(uint32_t type, size_t len, union PacketData data) {
default: default:
break; break;
} }
exint_event(event_name, len, data_pointer); exint_event(event_name, len, data);
} }
void exint_finialize() { void exint_finialize() {
@ -83,6 +82,6 @@ void exint_finialize() {
pthread_cancel(telemetry_thread); pthread_cancel(telemetry_thread);
} }
void exint_handle_pack(uint32_t type, size_t len, union PacketData data) { void exint_handle_pack(uint32_t type, size_t len, void* 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) {
exint_handle_pack(ET_TYPE_TELEMETRY_REQUEST, sizeof(TelemetryRequestData), { .pd_pointer = data }); exint_handle_pack(ET_TYPE_TELEMETRY_REQUEST, sizeof(TelemetryRequestData), data);
} }
/* create a msg data for upper host telemetry*/ /* create a msg data for upper host telemetry*/
@ -438,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
*/ */
exint_handle_pack(ET_TYPE_COMMAND, 6, {.pd_pointer = frame->payload}); exint_handle_pack(ET_TYPE_COMMAND, 6, frame->payload);
break; break;
} }
case COM_FRAME_TYPE_SPEECH_INJECTED: case COM_FRAME_TYPE_SPEECH_INJECTED:
@ -454,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);
exint_handle_pack(ET_TYPE_TEXT, 6, {.pd_pointer = f_data->payload}); exint_handle_pack(ET_TYPE_TEXT, 6, 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));
} }
@ -484,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;
exint_handle_pack(ET_TYPE_AUDIO, ComFrame_PAYLOAD_LENGTH(frame), {.pd_pointer = frame->payload}); exint_handle_pack(ET_TYPE_AUDIO, ComFrame_PAYLOAD_LENGTH(frame), frame->payload);
break; break;
} }
@ -550,7 +550,7 @@ void* upper_host_com_thread(void* arg) {//hand-control display processing unit
if(!alarm) if(!alarm)
continue; continue;
exint_handle_pack(ET_TYPE_TEXT, sizeof(alarm), {.pd_pointer = alarm}); exint_handle_pack(ET_TYPE_TEXT, sizeof(alarm), 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

@ -1,15 +1,19 @@
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <termios.h>
#include <sstream>
#include <atomic>
#include <signal.h> #include <signal.h>
#include <setjmp.h> #include <setjmp.h>
#include <iostream>
#include <string>
#include <sstream>
#include <atomic>
#include <thread>
#include "c_testcase.h" #include "c_testcase.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/ioctl.h>
#include <unistd.h>
#endif
using namespace std; using namespace std;
#define TEST_CASE_STATUS_PASSED 0 #define TEST_CASE_STATUS_PASSED 0
@ -20,6 +24,8 @@ using namespace std;
#define MAX_TESTCASE 64 #define MAX_TESTCASE 64
#define DEFAULT_TTY_COL_SIZE 80
struct TestCase { struct TestCase {
const char* name; const char* name;
test_case func; test_case func;
@ -34,6 +40,7 @@ static context_func teardown = NULL;
static atomic_bool testcase_running; static atomic_bool testcase_running;
static jmp_buf testcase_env; static jmp_buf testcase_env;
static std::thread::id testcase_thread_id;
static int testcase_exit_code = 0; static int testcase_exit_code = 0;
int _add_test_case(const char* name, test_case func) { int _add_test_case(const char* name, test_case func) {
@ -62,18 +69,36 @@ int _set_teardown(context_func func) {
return 0; return 0;
} }
void __attribute__((noreturn)) test_case_abort(int exit_code) { [[noreturn]] void test_case_abort(int exit_code) {
if (!testcase_running.load(std::memory_order_acquire)) { auto tid = std::this_thread::get_id();
if (!testcase_running.load(std::memory_order_acquire) || tid != testcase_thread_id) {
exit(exit_code); exit(exit_code);
} }
testcase_exit_code = exit_code; testcase_exit_code = exit_code;
longjmp(testcase_env, 1); longjmp(testcase_env, 1);
} }
static __inline int get_tty_col(int fd) { static inline int get_tty_col(int fd) {
#ifdef _WIN32
// Windows
HANDLE hConsole = (HANDLE)_get_osfhandle(fd);
if (hConsole == INVALID_HANDLE_VALUE) {
return DEFAULT_TTY_COL_SIZE; // 错误处理
}
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) {
return DEFAULT_TTY_COL_SIZE; // 错误处理
}
return csbi.srWindow.Right - csbi.srWindow.Left + 1; // 计算列数
#else
// POSIX (Linux, macOS, etc.)
struct winsize size; struct winsize size;
ioctl(fd, TIOCGWINSZ,&size); if (ioctl(fd, TIOCGWINSZ, &size) == -1) {
return size.ws_col; return DEFAULT_TTY_COL_SIZE; // 错误处理
}
return size.ws_col; // 返回列数
#endif
} }
static __inline void print_separator(char lc) { static __inline void print_separator(char lc) {
@ -140,6 +165,7 @@ static int run_test_case_func(test_case func) {
if (setjmp(testcase_env)) { if (setjmp(testcase_env)) {
return testcase_exit_code; return testcase_exit_code;
} }
testcase_thread_id = std::this_thread::get_id();
int ret = func(); int ret = func();
running = true; running = true;
if (!testcase_running.compare_exchange_strong(running, false, std::memory_order_acq_rel)) { if (!testcase_running.compare_exchange_strong(running, false, std::memory_order_acq_rel)) {

View File

@ -9,16 +9,16 @@
#include "c_testcase.h" #include "c_testcase.h"
static int g_telemetry_request_count = 0; static int g_telemetry_request_count = 0;
static DataQueue<std::tuple<uint32_t, size_t, PacketData>> g_data_queue; static DataQueue<std::tuple<uint32_t, size_t, void*>> g_data_queue;
static int host_com_master_id; static int host_com_master_id;
static int telemetry_com_master_id; static int telemetry_com_master_id;
void exint_data_callback(uint32_t type, size_t size, PacketData data) { void exint_data_callback(uint32_t type, size_t size, void* data) {
if (type == ET_TYPE_TELEMETRY_REQUEST) { if (type == ET_TYPE_TELEMETRY_REQUEST) {
g_telemetry_request_count++; g_telemetry_request_count++;
memset(data.pd_pointer, 0, size); memset(data, 0, size);
((TelemetryRequestData*)data.pd_pointer)->app_ver_high = 1; ((TelemetryRequestData*)data)->app_ver_high = 1;
((TelemetryRequestData*)data.pd_pointer)->app_ver_low = 2; ((TelemetryRequestData*)data)->app_ver_low = 2;
} else { } else {
g_data_queue.Push(std::make_tuple(type, size, data)); g_data_queue.Push(std::make_tuple(type, size, data));
} }
@ -80,6 +80,21 @@ TEST_CASE(test_host_telemetry) {
END_TEST; END_TEST;
} }
TEST_CASE(test_callback) {
uint8_t command[] = { 0x00, 0x01, 0x02, 0x03, 0xAA, 0xAA};
auto command_msg = ComFrame_New(COM_FRAME_ADDRESS_VOIX, COM_FRAME_TYPE_COMMAND, command, sizeof(command), true);
assert(!ComFrame_Send(host_com_master_id, command_msg, true));
uint32_t tp;
size_t len;
void* pack;
std::tie(tp, len, pack) = g_data_queue.Pop(std::chrono::milliseconds(1000));
assert_eq(tp, ET_TYPE_COMMAND);
assert_eq(len, sizeof(command));
assert_mem_eq(command, pack, len);
END_TEST;
}
TEST_CASE(test_send_command) { TEST_CASE(test_send_command) {
ComFrame* command_frame = NULL; ComFrame* command_frame = NULL;
bool timeout_flag = true; bool timeout_flag = true;
@ -89,8 +104,9 @@ TEST_CASE(test_send_command) {
command_frame = ComFrame_ReceiveEx(host_com_master_id, NULL, 100, &offset, &cached_size, &timeout_flag, true); command_frame = ComFrame_ReceiveEx(host_com_master_id, NULL, 100, &offset, &cached_size, &timeout_flag, true);
}).detach(); }).detach();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
char command_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; char command_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
exint_send(ET_TYPE_COMMAND, 6, { .pd_pointer = command_data }); exint_send(ET_TYPE_COMMAND, 6, command_data );
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -102,7 +118,6 @@ TEST_CASE(test_send_command) {
assert(command_frame); assert(command_frame);
assert_eq(ComFrame_TYPE(command_frame), COM_FRAME_TYPE_REQUEST); assert_eq(ComFrame_TYPE(command_frame), COM_FRAME_TYPE_REQUEST);
assert_eq(ComFrame_PAYLOAD_LENGTH(command_frame), 6); assert_eq(ComFrame_PAYLOAD_LENGTH(command_frame), 6);
assert_eq(ComFrame_PAYLOAD(command_frame)[0], 0x00); assert_mem_eq(ComFrame_PAYLOAD(command_frame), command_data, 6);
assert_eq(ComFrame_PAYLOAD(command_frame)[5], 0x05);
END_TEST; END_TEST;
} }

View File

@ -47,7 +47,7 @@ TEST_CASE(test_clear) {
} }
throw std::runtime_error("QueueException not thrown"); throw std::runtime_error("QueueException not thrown");
}); });
usleep(100); std::this_thread::sleep_for(std::chrono::milliseconds(10));
q.Clear(); q.Clear();
t.join(); t.join();
END_TEST; END_TEST;

View File

@ -1,5 +1,5 @@
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-none-linux-gnueabihf-gcc) set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-none-linux-gnueabihf-g++) set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

View File

@ -1,203 +0,0 @@
cmake_minimum_required(VERSION 2.8)
###################################################################################
project(libgo)
enable_language(C ASM)
if (CMAKE_BUILD_TYPE)
else()
set(CMAKE_BUILD_TYPE RELEASE)
#set(CMAKE_BUILD_TYPE DEBUG)
endif()
message("------------ Options -------------")
message(" CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(" CMAKE_COMMAND: ${CMAKE_COMMAND}")
option(ENABLE_DEBUGGER "enable debugger" OFF)
if (ENABLE_DEBUGGER)
set(ENABLE_DEBUGGER 1)
message (" enable_debugger: yes")
else()
set(ENABLE_DEBUGGER 0)
message (" enable_debugger: no")
endif()
option(DISABLE_HOOK "disable hook" OFF)
if (DISABLE_HOOK)
set(ENABLE_HOOK 0)
message (" enable_hook: no")
else()
set(ENABLE_HOOK 1)
message (" enable_hook: yes")
endif()
if (BUILD_DYNAMIC)
message (" build dynamic lib: yes")
else()
message (" build dynamic lib: no")
endif()
message("-------------- Env ---------------")
message(" CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
message(" CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}")
message("----------------------------------")
configure_file(${PROJECT_SOURCE_DIR}/libgo/common/cmake_config.h.in ${PROJECT_SOURCE_DIR}/libgo/common/cmake_config.h)
message("----------------------------------")
if (UNIX)
set(CMAKE_CXX_FLAGS "-std=c++17 -fPIC -Wall ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-g -O3 -DNDEBUG")
set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS S)
if(CMAKE_CROSSCOMPILING)
message(STATUS "> CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
set(ASM_DIR "${PROJECT_SOURCE_DIR}/third_party/boost.context/libs/context/src/asm/")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
set(jump_asm_file "${ASM_DIR}jump_arm_aapcs_elf_gas.S")
set(make_asm_file "${ASM_DIR}make_arm_aapcs_elf_gas.S")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(jump_asm_file "${ASM_DIR}jump_arm64_aapcs_elf_gas.S")
set(make_asm_file "${ASM_DIR}make_arm64_aapcs_elf_gas.S")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(jump_asm_file "${ASM_DIR}jump_x86_64_sysv_elf_gas.S")
set(make_asm_file "${ASM_DIR}make_x86_64_sysv_elf_gas.S")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") # macOS
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(jump_asm_file "${ASM_DIR}jump_arm64_aapcs_macho_gas.S")
set(make_asm_file "${ASM_DIR}make_arm64_aapcs_macho_gas.S")
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
set(jump_asm_file "${ASM_DIR}jump_i386_ms_pe_gas.asm")
set(make_asm_file "${ASM_DIR}make_i386_ms_pe_gas.asm")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(jump_asm_file "${ASM_DIR}jump_x86_64_ms_pe_gas.asm")
set(make_asm_file "${ASM_DIR}make_x86_64_ms_pe_gas.asm")
endif()
endif()
if (NOT jump_asm_file OR NOT make_asm_file)
message(FATAL_ERROR "--> select asm source file failed")
return()
endif()
file(COPY ${jump_asm_file} DESTINATION ${PROJECT_SOURCE_DIR}/libgo/context)
file(COPY ${make_asm_file} DESTINATION ${PROJECT_SOURCE_DIR}/libgo/context)
else()
message("--> select asm source file, please wait about 5 seconds ...")
execute_process(COMMAND "${PROJECT_SOURCE_DIR}/third_party/select_asm.sh" "${PROJECT_SOURCE_DIR}" "jump" OUTPUT_VARIABLE jump_asm_file)
execute_process(COMMAND "${PROJECT_SOURCE_DIR}/third_party/select_asm.sh" "${PROJECT_SOURCE_DIR}" "make" OUTPUT_VARIABLE make_asm_file)
endif()
#
message(STATUS "Jump ASM File: ${jump_asm_file}")
message(STATUS "Make ASM File: ${make_asm_file}")
elseif (WIN32)
# windows platform
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd /EHsc")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /EHsc")
#set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm)
#file(COPY ${PROJECT_SOURCE_DIR}/third_party/boost.context/libs/context/src/asm/make_x86_64_ms_pe_masm.asm DESTINATION ${PROJECT_SOURCE_DIR}/libgo/context)
#file(COPY ${PROJECT_SOURCE_DIR}/third_party/boost.context/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm DESTINATION ${PROJECT_SOURCE_DIR}/libgo/context)
endif()
message("------------ Cxx flags -------------")
message(" CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}: ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
message("------------------------------------")
include_directories(${PROJECT_SOURCE_DIR})
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/common CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/context CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/task CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/scheduler CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/sync CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/timer CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/cls CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/defer CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/pool CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/debug CO_SRC_LIST)
if (NOT DISABLE_HOOK)
if (UNIX)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/netio/unix CO_SRC_LIST)
elseif (WIN32)
include_directories(${PROJECT_SOURCE_DIR}/libgo/netio/windows)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/netio/windows CO_SRC_LIST)
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/context/fiber CO_SRC_LIST)
list(APPEND CO_SRC_LIST ${PROJECT_SOURCE_DIR}/libgo/netio/windows/xhook/xhook.cpp)
endif()
else()
aux_source_directory(${PROJECT_SOURCE_DIR}/libgo/netio/disable_hook CO_SRC_LIST)
endif()
set(TARGET "libgo")
set(STATIC_T "libgo_static")
set(STATIC_HOOK "static_hook")
list(APPEND CO_SRC_LIST ${jump_asm_file})
list(APPEND CO_SRC_LIST ${make_asm_file})
add_library("${STATIC_T}" STATIC ${CO_SRC_LIST})
set_target_properties("${STATIC_T}" PROPERTIES OUTPUT_NAME "${TARGET}")
if (UNIX)
install(TARGETS ${STATIC_T} LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib")
install(DIRECTORY ${PROJECT_SOURCE_DIR}/libgo/ DESTINATION "include/libgo" FILES_MATCHING PATTERN "*.h")
#PATTERN "windows" EXCLUDE
add_library("${STATIC_HOOK}" STATIC "${PROJECT_SOURCE_DIR}/libgo/netio/unix/static_hook/static_hook.cpp")
if (BUILD_DYNAMIC)
set(SHARED_T "libgo_dynamic")
add_library("${SHARED_T}" SHARED ${CO_SRC_LIST})
set_target_properties("${SHARED_T}" PROPERTIES OUTPUT_NAME "${TARGET}")
target_link_libraries("${SHARED_T}" ${LINK_LIBS} -ldl)
install(TARGETS ${SHARED_T} LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib")
endif()
add_custom_target(debug
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=DEBUG ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Switch CMAKE_BUILD_TYPE to Debug"
)
add_custom_target(release
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=RELEASE ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Switch CMAKE_BUILD_TYPE to Release"
)
set(PROFILE_FLAGS "-pg ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
#message("PROFILE_FLAGS: ${PROFILE_FLAGS}")
add_custom_target(profile
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=PROFILE -DCMAKE_CXX_FLAGS_PROFILE=\\'${PROFILE_FLAGS}\\' ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Switch CMAKE_BUILD_TYPE to PROFILE"
)
add_custom_target(uninstall
COMMAND rm ${CMAKE_INSTALL_PREFIX}/lib/liblibgo.a ${CMAKE_INSTALL_PREFIX}/lib/liblibgo.so ${CMAKE_INSTALL_PREFIX}/lib/liblibgo_main.a -f
COMMAND rm ${CMAKE_INSTALL_PREFIX}/include/libgo -rf
)
elseif (WIN32)
set_target_properties("${STATIC_T}" PROPERTIES COMPILE_FLAGS "/wd4819 /wd4267")
endif()
if (WIN32)
if (BOOST_ROOT)
add_subdirectory(${PROJECT_SOURCE_DIR}/test/gtest_unit)
add_subdirectory(${PROJECT_SOURCE_DIR}/tutorial)
endif()
endif()