init repo
This commit is contained in:
commit
9bf7306aa2
|
@ -0,0 +1,27 @@
|
||||||
|
################### CMake config ###################
|
||||||
|
|
||||||
|
build
|
||||||
|
|
||||||
|
################ Executable program ################
|
||||||
|
|
||||||
|
bin/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
################### VSCode config ##################
|
||||||
|
|
||||||
|
.vscode
|
||||||
|
.VSCodeCounter
|
||||||
|
|
||||||
|
####################### Tools ######################
|
||||||
|
|
||||||
|
tools/*
|
||||||
|
|
||||||
|
#################### Test config ###################
|
||||||
|
|
||||||
|
test.*
|
||||||
|
disabled.*
|
||||||
|
*.disabled
|
||||||
|
|
||||||
|
###################### Misc #######################
|
||||||
|
|
||||||
|
!.gitkeep
|
|
@ -0,0 +1,126 @@
|
||||||
|
# 通讯模块文档
|
||||||
|
|
||||||
|
本文档主要描述Voix中的用于与遥测机及上位机进行通讯及相关附加功能的模块。
|
||||||
|
这些模块拆分自原host_com.cpp文件。
|
||||||
|
|
||||||
|
## 模块公开接口
|
||||||
|
|
||||||
|
以下接口由通讯模块公开,可以在VOIX主程序中使用。
|
||||||
|
|
||||||
|
1. `void extern_interface_init(const char* config_path, et_callback_t cb)`:模块初始化函数
|
||||||
|
- `config_path`:配置文件路径
|
||||||
|
- `cb`:回调函数,用于进行指令响应和遥测数据请求
|
||||||
|
2. `void (*et_callback_t)(uint32_t type, size_t len, union PacketData data)`:回调函数类型,内部数据为指针类型的数据包仅保证在回调函数中有效。
|
||||||
|
- `type`:数据包类型
|
||||||
|
- `len`:数据包长度,对于指针类型数据包,len为指针指向的数据长度,对于字符串类型数据包,len为字符串包含后缀`\0`的长度。
|
||||||
|
- `data`:数据包数据
|
||||||
|
3. `union PacketData`:数据包定义
|
||||||
|
- `pd_integer`:int64_t类型的数据
|
||||||
|
- `pd_float`:double类型的数据
|
||||||
|
- `pd_text`:const char*类型的数据
|
||||||
|
- `pd_pointer`:void*类型的数据,
|
||||||
|
4. 数据包类型(宏定义):
|
||||||
|
- `ET_TYPE_NONE`:无数据
|
||||||
|
- `ET_TYPE_TEXT`:文本,对应const char*类型的数据
|
||||||
|
- `ET_TYPE_AUDIO`:音频,对应short*类型的数据
|
||||||
|
- `ET_TYPE_COMMAND`:指令码,对应uint8_t[6]类型的数据
|
||||||
|
- `ET_TYPE_ALARM`:告警码,对应uint8_t[4]类型的数据
|
||||||
|
- `ET_TYPE_TELEMETRY_REQUEST`:遥测请求,对应void*类型的数据,需要主程序在数据包内的指针中写入对应的变量数据
|
||||||
|
5. `void send_data_packet(uint32_t type, size_t len, union PacketData data)`:发送数据包
|
||||||
|
- `type`:数据包类型
|
||||||
|
- `len`:数据包长度,对于指针类型数据包,len为指针指向的数据长度,对于字符串类型数据包,len为字符串包含后缀`\0`的长度。
|
||||||
|
- `data`:数据包数据
|
||||||
|
|
||||||
|
## 外部依赖
|
||||||
|
|
||||||
|
通讯模块需要一些来自主程序的全局变量,主要用于生成遥测报文。
|
||||||
|
|
||||||
|
- `g_bKeepSysRuning`:系统运行状态标志
|
||||||
|
- `g_bCloseASR`:ASR关闭状态标志
|
||||||
|
- `g_iSysState`:系统状态
|
||||||
|
- `g_bVolumeKeyPressed`:静音按键状态标志
|
||||||
|
- `g_bWakeupKeyPressed`:唤醒按键状态标志
|
||||||
|
- `g_iVolumeGrade`:音量等级
|
||||||
|
- `g_iSysVerHigh`:系统版本号高8位
|
||||||
|
- `g_iSysVerLow`:系统版本号低8位
|
||||||
|
- `g_iAppVerHigh`:应用版本号高8位
|
||||||
|
- `g_iAppVerLow`:应用版本号低8位
|
||||||
|
|
||||||
|
以上全局变量通过回调函数中的遥测请求数据包获取。
|
||||||
|
|
||||||
|
## Transport模块
|
||||||
|
|
||||||
|
用于进行底层通讯的模块,包含comframe库、通讯线程及回调定义接口的封装。
|
||||||
|
|
||||||
|
主程序需要构建回调函数定义数组,并通过线程函数的参数传入。
|
||||||
|
|
||||||
|
### 公开接口
|
||||||
|
|
||||||
|
1. `void* transport_thread(void* arg)`:线程函数
|
||||||
|
- `arg`:需要传入以零项作为结尾的`struct ComFrameTypeDef`结构体数组
|
||||||
|
2. `struct ComFrameTypeDef`:回调函数定义
|
||||||
|
- `tp_id`:数据类型,与数据帧中的type对应
|
||||||
|
- `tp_callback`:回调函数指针
|
||||||
|
- `tp_flag`:类型回调标签,如 是否进行校验
|
||||||
|
3. `void (*tp_callback_t)(struct ComFrameTypeDef*, struct Comframe*)`:回调函数
|
||||||
|
- `struct ComFrameTypeDef*`:回调函数定义结构体指针
|
||||||
|
- `struct Comframe*`:数据帧
|
||||||
|
4. 回调标签(宏定义):
|
||||||
|
- `TP_FLAG_DEFAULT`:默认回调标签
|
||||||
|
- `TP_FLAG_NOVERIFY`:不进行数据校验
|
||||||
|
- `TP_FLAG_THREAD`:在独立线程中执行回调函数
|
||||||
|
- `TP_FLAG_DISABLE`:禁用回调函数
|
||||||
|
|
||||||
|
## Telemetry模块
|
||||||
|
|
||||||
|
遥测模块,用于获取并同步遥测信息,并提供遥测回调函数。
|
||||||
|
|
||||||
|
### 公开接口
|
||||||
|
|
||||||
|
1. `void telemetry_handler(struct ComFrameTypeDef*, struct Comframe*)`:遥测请求回调函数
|
||||||
|
|
||||||
|
### 内部接口
|
||||||
|
|
||||||
|
1. `struct Telemetry`:遥测数据(遥测串口)
|
||||||
|
2. `struct UpperHostTelemetry`:遥测数据(上位机串口)
|
||||||
|
3. `void flush_telemetry_data()`:更新遥测数据(遥测串口)
|
||||||
|
4. `void flush_upper_host_telemetry_data()`:更新遥测数据(上位机串口)
|
||||||
|
|
||||||
|
## Command模块
|
||||||
|
|
||||||
|
用于定义命令回调函数,在transport模块中调用。
|
||||||
|
|
||||||
|
### 公开接口
|
||||||
|
|
||||||
|
1. `void command_handler(struct ComFrameTypeDef*, struct Comframe*)`:命令回调函数
|
||||||
|
|
||||||
|
### 内部接口
|
||||||
|
|
||||||
|
1. `struct CommandDef`:命令定义
|
||||||
|
- `cmd_id`:命令ID
|
||||||
|
- `cmd_callback`:回调函数指针
|
||||||
|
2. `void (*cmd_callback_t)(uint8_t[])`:命令回调函数
|
||||||
|
|
||||||
|
## Alarm模块
|
||||||
|
|
||||||
|
用于定义告警回调函数,在transport模块中调用。
|
||||||
|
|
||||||
|
### 公开接口
|
||||||
|
|
||||||
|
1. `void alarm_handler(struct ComFrameTypeDef*, struct Comframe*)`:告警回调函数
|
||||||
|
|
||||||
|
### 内部接口
|
||||||
|
|
||||||
|
1. `struct AlarmDef`:告警定义
|
||||||
|
- `alarm_id`:告警ID
|
||||||
|
- `alarm_text`:告警文本
|
||||||
|
|
||||||
|
## TypeHandler模块
|
||||||
|
|
||||||
|
用于定义除遥测请求及告警信息外的其他回调函数,在transport模块中调用。
|
||||||
|
|
||||||
|
### 公开接口
|
||||||
|
|
||||||
|
1. `void speech_injected_handler(struct ComFrameTypeDef*, struct Comframe*)`:语音注入回调函数
|
||||||
|
2. `void audio_handler(struct ComFrameTypeDef*, struct Comframe*)`:语音数据回调函数
|
||||||
|
3. `void grant_time_handler(struct ComFrameTypeDef*, struct Comframe*)`:授时回调函数
|
|
@ -0,0 +1,173 @@
|
||||||
|
#ifndef _INCLUDE_C_TESTCASE_
|
||||||
|
#define _INCLUDE_C_TESTCASE_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SKIP_RET_NUMBER (*((const int*)"SKIP"))
|
||||||
|
#define SKIP_TEST do { return SKIP_RET_NUMBER; } while (0)
|
||||||
|
#define END_TEST do { return 0; } while (0)
|
||||||
|
|
||||||
|
#define TEST_CASE(name) \
|
||||||
|
int name (); \
|
||||||
|
int _tc_tmp_ ## name = _add_test_case(# name, name); \
|
||||||
|
int name ()
|
||||||
|
#define INTERACTIVE \
|
||||||
|
int interactive_impl(int argc, const char** argv); \
|
||||||
|
int _tc_s_tmp_interactive = _set_interactive(interactive_impl); \
|
||||||
|
int interactive_impl(int argc, const char** argv)
|
||||||
|
#define SETUP \
|
||||||
|
int setup_impl(const char* test_case_name); \
|
||||||
|
int _tc_s_tmp_setup = _set_setup(setup_impl); \
|
||||||
|
int setup_impl(const char* test_case_name)
|
||||||
|
#define TEARDOWN \
|
||||||
|
int teardown_impl(const char* test_case_name); \
|
||||||
|
int _tc_s_tmp_teardown = _set_teardown(teardown_impl); \
|
||||||
|
int teardown_impl(const char* test_case_name)
|
||||||
|
|
||||||
|
#undef assert
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define assert(expr) do { \
|
||||||
|
if (!(static_cast <bool> (expr))) { \
|
||||||
|
::std::cout << "assert failed: " #expr "\n" << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_eq(expr1, expr2) do { \
|
||||||
|
if ((expr1) != (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " == " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_ne(expr1, expr2) do { \
|
||||||
|
if ((expr1) == (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " != " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_gt(expr1, expr2) do { \
|
||||||
|
if ((expr1) <= (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " > " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_ls(expr1, expr2) do { \
|
||||||
|
if ((expr1) >= (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " < " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_ge(expr1, expr2) do { \
|
||||||
|
if ((expr1) < (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " >= " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_le(expr1, expr2) do { \
|
||||||
|
if ((expr1) > (expr2)) { \
|
||||||
|
::std::cout << "assert failed: " #expr1 " <= " #expr2 "\n" << ::std::endl; \
|
||||||
|
::std::cout << "\t#0: " << (expr1) << ::std::endl; \
|
||||||
|
::std::cout << "\t#1: " << (expr2) << ::std::endl; \
|
||||||
|
::std::cout << "file: \"" __FILE__ "\", line " << __LINE__ << ", in " << __ASSERT_FUNCTION << "\n" << ::std::endl;\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define assert(expr) do { \
|
||||||
|
if (!((bool)(expr))) { \
|
||||||
|
printf("assert failed: " #expr "\n"); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#define assert_i32_eq(expr1, expr2) do { \
|
||||||
|
if ((int32_t)(expr1) != (uint32_t)(expr2)) { \
|
||||||
|
printf("assert failed: " #expr1 " == " #expr2 "\n"); \
|
||||||
|
printf("\t\t%d\t!=\t%d\n", (int32_t)(expr1), (int32_t)(expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_i32_ne(expr1, expr2) do { \
|
||||||
|
if ((int32_t)(expr1) == (int32_t)(expr2)) { \
|
||||||
|
printf("assert failed: " #expr1 " != " #expr2 "\n"); \
|
||||||
|
printf("\t\t%d\t==\t%d\n", (int32_t)(expr1), (int32_t)(expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_i64_eq(expr1, expr2) do { \
|
||||||
|
if ((expr1) != (expr2)) { \
|
||||||
|
printf("assert failed: " #expr1 " == " #expr2 "\n"); \
|
||||||
|
printf("\t\t%lld\t!=\t%lld\n", (int64_t)(expr1), (int64_t)(expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_i64_ne(expr1, expr2) do { \
|
||||||
|
if ((expr1) == (expr2)) { \
|
||||||
|
printf("assert failed: " #expr1 " != " #expr2 "\n"); \
|
||||||
|
printf("\t\t%lld\t==\t%lld\n", (int64_t)(expr1), (int64_t)(expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_str_eq(expr1, expr2) do { \
|
||||||
|
if (strcmp((expr1), (expr2)) != 0) { \
|
||||||
|
printf("assert failed: " #expr1 " == " #expr2 "\n"); \
|
||||||
|
printf("\t#0: %s\n", (expr1)); \
|
||||||
|
printf("\t#1: %s\n", (expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define assert_str_ne(expr1, expr2) do { \
|
||||||
|
if (strcmp((expr1), (expr2)) == 0) { \
|
||||||
|
printf("assert failed: " #expr1 " != " #expr2 "\n"); \
|
||||||
|
printf("\t#0: %s\n", (expr1)); \
|
||||||
|
printf("\t#1: %s\n", (expr2)); \
|
||||||
|
printf("file: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\
|
||||||
|
test_case_abort(1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (*test_case)();
|
||||||
|
typedef int (*interactive_func)(int argc, const char** argv);
|
||||||
|
typedef int (*context_func)(const char* name);
|
||||||
|
|
||||||
|
int _add_test_case(const char* name, test_case func);
|
||||||
|
int _set_interactive(interactive_func func);
|
||||||
|
int _set_setup(context_func func);
|
||||||
|
int _set_teardown(context_func func);
|
||||||
|
void __attribute__((noreturn)) test_case_abort(int exit_code);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,240 @@
|
||||||
|
#ifndef _INCLUDE_FRAME_
|
||||||
|
#define _INCLUDE_FRAME_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "defines.h"
|
||||||
|
//#define COM_FRAME_DEBUG
|
||||||
|
|
||||||
|
#define byteswapl(x) (0xff000000 & x << 24) \
|
||||||
|
|(0x00ff0000 & x << 8) \
|
||||||
|
|(0x0000ff00 & x >> 8) \
|
||||||
|
|(0x000000ff & x >> 24)
|
||||||
|
#define byteswaps(x) (0xff00 & x << 8) \
|
||||||
|
|(0x00ff & x >> 8)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ComFrameHeader {
|
||||||
|
uint16_t magic_number;
|
||||||
|
uint16_t address;
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
typedef struct _ComFrame {
|
||||||
|
struct ComFrameHeader header;
|
||||||
|
uint8_t payload[COM_FRAME_DEFAULT_PAYLOAD_LENGTH];
|
||||||
|
} ComFrame;
|
||||||
|
|
||||||
|
#define ComFrame_HEADER(frame) ((struct ComFrameHeader*)(frame))
|
||||||
|
#define ComFrame_ADDRESS(frame) (ComFrame_HEADER(frame)->address)
|
||||||
|
#define ComFrame_TYPE(frame) (ComFrame_HEADER(frame)->type)
|
||||||
|
#define ComFrame_PAYLOAD(frame) (frame->payload)
|
||||||
|
#define ComFrame_PAYLOAD_LENGTH(frame) (ComFrame_HEADER(frame)->length - 1)
|
||||||
|
#define ComFrame_PAYLOAD_ALIGNED_LENGTH(frame) (ComFrame_HEADER(frame)->length & (~1))
|
||||||
|
#define ComFrame_CHECKSUM(frame) (((uint16_t*)&(frame)->payload)[ComFrame_HEADER(frame)->length >> 1])
|
||||||
|
#define ComFrame_LENGTH(frame) (sizeof(ComFrame) + ComFrame_PAYLOAD_ALIGNED_LENGTH(frame) - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t))
|
||||||
|
|
||||||
|
/// @brief init frame header struct
|
||||||
|
/// @param header header struct
|
||||||
|
/// @param address device address
|
||||||
|
/// @param type frame type
|
||||||
|
/// @param length frame payload length + 1
|
||||||
|
static __inline void ComFrameHeader_Init(struct ComFrameHeader* header, uint16_t address, uint16_t type, uint16_t length) {
|
||||||
|
header->magic_number = COM_FRAME_MAGIC_NUMBER;
|
||||||
|
header->address = address;
|
||||||
|
header->type = type;
|
||||||
|
header->length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief swap haeder structure endianness
|
||||||
|
/// @param header header struct
|
||||||
|
static __inline void ComFrameHeader_SwapEndian(struct ComFrameHeader* header) {
|
||||||
|
header->magic_number = byteswaps(header->magic_number);
|
||||||
|
header->address = byteswaps(header->address);
|
||||||
|
header->type = byteswaps(header->type);
|
||||||
|
header->length = byteswaps(header->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief check magic number of header struct
|
||||||
|
/// @param header header struct
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return structure validity, true means invalid
|
||||||
|
static __inline bool ComFrameHeader_Check(const struct ComFrameHeader* header, const bool swap_endian) {
|
||||||
|
uint16_t number = header->magic_number;
|
||||||
|
if (swap_endian) {
|
||||||
|
number = byteswaps(number);
|
||||||
|
}
|
||||||
|
if (number != COM_FRAME_MAGIC_NUMBER) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
number = header->address;
|
||||||
|
if (swap_endian) {
|
||||||
|
number = byteswaps(number);
|
||||||
|
}
|
||||||
|
if (number != COM_FRAME_ADDRESS_VOIX) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ComFrame_LENGTH(header) < 12) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
number = header->type;
|
||||||
|
if (swap_endian) {
|
||||||
|
number = byteswaps(number);
|
||||||
|
}
|
||||||
|
// if ( // commented by gejp 20201007
|
||||||
|
// number != COM_FRAME_TYPE_COMMAND &&
|
||||||
|
// number != COM_FRAME_TYPE_SPEECH_INJECTED &&
|
||||||
|
// number != COM_FRAME_TYPE_SPEECH_TEXT &&
|
||||||
|
// number != COM_FRAME_TYPE_SPEECH_PCM &&
|
||||||
|
// number != COM_FRAME_TYPE_AUDIO &&
|
||||||
|
// number != COM_FRAME_TYPE_REQUEST &&
|
||||||
|
// number != COM_FRAME_TYPE_TELEMETRY_REQUEST
|
||||||
|
// ) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief create new com frame uninitialized
|
||||||
|
/// @param payload_length length of payload
|
||||||
|
/// @return new uinitialized frame
|
||||||
|
static __inline ComFrame* ComFrame_NewUninited(uint16_t payload_length) {
|
||||||
|
if (payload_length & 1) {
|
||||||
|
payload_length += 1;
|
||||||
|
}
|
||||||
|
return (ComFrame*)malloc(sizeof(ComFrame) + payload_length - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief get frame checksum
|
||||||
|
/// @param frame com frame struct
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return checksum
|
||||||
|
static __inline uint16_t ComFrame_Checksum(const ComFrame* frame, const bool swap_endian) {
|
||||||
|
const uint16_t* buffer = (const uint16_t*)&frame->payload;
|
||||||
|
uint16_t length = ComFrame_HEADER(frame)->length;
|
||||||
|
if (swap_endian) {
|
||||||
|
length = byteswaps(length);
|
||||||
|
}
|
||||||
|
return buffer[length >> 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief get frame length
|
||||||
|
/// @param frame com frame struct
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return length of the frame
|
||||||
|
static __inline uint32_t ComFrame_Length(const ComFrame* frame, const bool swap_endian) {
|
||||||
|
uint16_t length = ComFrame_HEADER(frame)->length;
|
||||||
|
if (swap_endian) {
|
||||||
|
length = byteswaps(length);
|
||||||
|
}
|
||||||
|
length &= (~1);
|
||||||
|
return sizeof(ComFrame) + length - COM_FRAME_DEFAULT_PAYLOAD_LENGTH + sizeof(uint16_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief destroy the frame
|
||||||
|
/// @param frame the frame to destroy
|
||||||
|
static __inline void ComFrame_Del(ComFrame* frame) {
|
||||||
|
if (frame) free(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief flush receive buffer
|
||||||
|
/// @param offset the size used, usually the length of the data frame
|
||||||
|
/// @param buffer receive buffer
|
||||||
|
/// @param p_cached_size cache size to reset, not null
|
||||||
|
/// @note please set the offset to 0 after calling the function if used with ComFrame_ReceiveEx
|
||||||
|
static __inline void ComFrame_ReceiveFlushBuffer(size_t offset, uint8_t* buffer, size_t* p_cached_size) {
|
||||||
|
*p_cached_size -= offset;
|
||||||
|
memmove(buffer, buffer + offset, *p_cached_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief calculate the checksum of the specified payload
|
||||||
|
/// @param header header struct (must be little endian)
|
||||||
|
/// @param payload payload data
|
||||||
|
/// @return checksum
|
||||||
|
uint16_t ComFramePayload_EvalChecksum(const struct ComFrameHeader* header, const void* payload);
|
||||||
|
|
||||||
|
/// @brief verify the checksum of the specified payload
|
||||||
|
/// @param header header struct (must be little endian)
|
||||||
|
/// @param payload payload data
|
||||||
|
/// @param checksum checksum to verify
|
||||||
|
/// @param swap_checksum_endian whether to switch checksum endianness
|
||||||
|
/// @return payload validity, true means invalid
|
||||||
|
bool ComFramePayload_VerifyChecksum(const struct ComFrameHeader* header, const void* payload, uint16_t checksum);
|
||||||
|
|
||||||
|
/// @brief create new com frame from header and known checksum
|
||||||
|
/// @param header header struct (must be little endian)
|
||||||
|
/// @param payload payload data
|
||||||
|
/// @param checksum payload checksum
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return new frame
|
||||||
|
ComFrame* ComFrame_FromHeaderEx(const struct ComFrameHeader* header, const void* payload, uint16_t checksum, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief create new com frame from header
|
||||||
|
/// @param header header struct (must be little endian)
|
||||||
|
/// @param payload payload data
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return new frame
|
||||||
|
ComFrame* ComFrame_FromHeader(const struct ComFrameHeader* header, const void* payload, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief create new com frame
|
||||||
|
/// @param address device address
|
||||||
|
/// @param type frame type
|
||||||
|
/// @param payload payload data
|
||||||
|
/// @param payload_length payload data real length
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return new frame
|
||||||
|
ComFrame* ComFrame_New(uint16_t address, uint16_t type, const void* payload, uint16_t payload_length, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief update frame payload and checksum
|
||||||
|
/// @param frame com frame struct
|
||||||
|
/// @param payload payload data or NULL, if set to NULL, the payload will not be updated.
|
||||||
|
/// @param payload_length payload data real length
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
void ComFrame_UpdatePayload(ComFrame* frame, const void* payload, const uint16_t payload_length, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief verify frame checksum
|
||||||
|
/// @param frame con frame struct
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return structure validity, true means invalid
|
||||||
|
bool ComFrame_Verify(const ComFrame* frame, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief send a frame to com
|
||||||
|
/// @param tty_id com tty id
|
||||||
|
/// @param frame con frame struct
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return error number, 0 means ok
|
||||||
|
ssize_t ComFrame_Send(int tty_id, const ComFrame* frame, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief receive a frame from com
|
||||||
|
/// @param tty_id com tty id
|
||||||
|
/// @param buffer_size receive buffer size
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return new frame (little endian) or NULL
|
||||||
|
ComFrame* ComFrame_Receive(int tty_id, const size_t buffer_size, const bool swap_endian);
|
||||||
|
|
||||||
|
/// @brief receive a frame from com
|
||||||
|
/// @param tty_id com tty id
|
||||||
|
/// @param buffer buffer pointer, create a new one when it is NULL
|
||||||
|
/// @param buffer_size receive buffer size
|
||||||
|
/// @param p_offset offset will be set if not null
|
||||||
|
/// @param p_cached_size cached size will be set if not null
|
||||||
|
/// @param p_run_flag run flag pointer, if the inner date is set to false, the function will stop and return NULL
|
||||||
|
/// @param swap_endian whether to switch endianness
|
||||||
|
/// @return frame (little endian) in buffer or NULL
|
||||||
|
ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size, size_t* p_offset, size_t* p_cached_size, bool* p_run_flag, const bool swap_endian);
|
||||||
|
|
||||||
|
//int get_com_tty_id(const char* path, unsigned int baudRate);
|
||||||
|
//void init_tty(int tty_id, unsigned int baudRate);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef SYS_COMMAND_H_
|
||||||
|
#define SYS_COMMAND_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
bool is_command(uint8_t* array, uint8_t* value, int size);
|
||||||
|
|
||||||
|
//--
|
||||||
|
uint8_t command_open_asr[] = { 0x00, 0xf0, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
uint8_t command_close_asr[] = { 0x00, 0xf2, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
uint8_t command_open_call[] = { 0x00, 0xf4, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
uint8_t command_close_call[] = { 0x00, 0xf6, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
|
||||||
|
uint8_t command_wakeup[] = { 0x00, 0x01, 0x02, 0x27, 0x02, 0x27 };
|
||||||
|
uint8_t command_sleep[] = { 0x00, 0x01, 0x02, 0x28, 0x02, 0x28 };
|
||||||
|
uint8_t command_volume[] = { 0x00, 0x01, 0x02, 0x29, 0x02, 0x29};//2024.10.22{0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
uint8_t command_reset[] = { 0x00, 0x01, 0x02, 0x2A, 0x02, 0x2A};//2024.10.22 { 0x00, 0xfa, 0xaa, 0xaa, 0xaa, 0xaa };
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef _INCLUDED_QUEUE_
|
||||||
|
#define _INCLUDED_QUEUE_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class DataQueue {
|
||||||
|
public:
|
||||||
|
DataQueue(size_t init_size = 0) : m_Queue(init_size)
|
||||||
|
{}
|
||||||
|
DataQueue(DataQueue&) = delete;
|
||||||
|
|
||||||
|
void Push(T data)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
m_Queue.push_back(data);
|
||||||
|
m_Cond.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
T Pop()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_Mutex);
|
||||||
|
while (m_Queue.empty())
|
||||||
|
{
|
||||||
|
m_Cond.wait(lock);
|
||||||
|
}
|
||||||
|
T data = m_Queue.front();
|
||||||
|
m_Queue.pop_front();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Empty()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
return m_Queue.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Size()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
return m_Queue.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
m_Queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<T> m_Queue;
|
||||||
|
std::mutex m_Mutex;
|
||||||
|
std::condition_variable m_Cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,255 @@
|
||||||
|
#ifndef VOIX_DEFINES_H
|
||||||
|
#define VOIX_DEFINES_H
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <map>
|
||||||
|
#include "CCfgFileParser.h"
|
||||||
|
#include "dataqueue.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
#define PrintFilePos() //printf("\nfile:%s, line:%2d---",__FILE__,__LINE__);
|
||||||
|
#define CHUNK_SIZE 512 // 512 samples per frame
|
||||||
|
#define SAMPLE_RATE 16000 // ReSpeaker Mic Array V2.0 support SampleRate from 16kHz to 48kHz
|
||||||
|
#define RECORD_SECONDS 200000
|
||||||
|
#define ASR_RESULT_LEN 1024
|
||||||
|
#define WAKE_CHUNK_SIZE 512
|
||||||
|
#define ASR_CHUNCK_SIZE 8000
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 512 // 512 samples per frame
|
||||||
|
#define SAMPLE_RATE 16000 // ReSpeaker Mic Array V2.0 support g_iSampleRate from 16kHz to 48kHz
|
||||||
|
#define RECORD_SECONDS 200000
|
||||||
|
#define ASR_RESULT_LEN 1024
|
||||||
|
#define ASR_CHUNCK_SIZE 8000
|
||||||
|
#define LAST_FRAME_ENERGY_ARRAY_SIZE 15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------host telemetry defines start --------------------------
|
||||||
|
#define COM_FRAME_MAGIC_NUMBER 0xEB90
|
||||||
|
#define COM_FRAME_DEFAULT_PAYLOAD_LENGTH 2
|
||||||
|
#define COM_FRAME_PADDING_DATA 0xAA
|
||||||
|
|
||||||
|
#define COM_FRAME_TYPE_COMMAND 0x00C0
|
||||||
|
#define COM_FRAME_TYPE_SPEECH_INJECTED 0x00D0
|
||||||
|
#define COM_FRAME_TYPE_SPEECH_TEXT 0x00D0
|
||||||
|
#define COM_FRAME_TYPE_SPEECH_PCM 0x00D1
|
||||||
|
#define COM_FRAME_TYPE_AUDIO 0x00D1
|
||||||
|
#define COM_FRAME_TYPE_REQUEST 0x0090
|
||||||
|
#define COM_FRAME_TYPE_TELEMETRY_REQUEST 0x00B0
|
||||||
|
#define COM_FRAME_TYPE_TELEMETRY_ANSWER 0x0070
|
||||||
|
#define COM_FRAME_TYPE_TELEMETRY_ERROR 0x0071
|
||||||
|
|
||||||
|
#define COM_FRAME_ADDRESS_VOIX 0x011A
|
||||||
|
|
||||||
|
// added by gejp start 2024.10.03
|
||||||
|
#define COM_FRAME_TYPE_GRANT_TIME 0x0085
|
||||||
|
#define COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_REQUEST 0x0083
|
||||||
|
#define COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_RESPONSE 0x0083
|
||||||
|
|
||||||
|
|
||||||
|
#define CMD_CODE_TELEMETRY_LOW_CABIN_TEMPERATURE 0x2F01
|
||||||
|
#define CMD_TEXT_TELEMETRY_LOW_CABIN_TEMPERATURE "设置低舱温"
|
||||||
|
#define CMD_CODE_TELEMETRY_MODERATE_CABIN_TEMPERATURE 0x2F02
|
||||||
|
#define CMD_TEXT_TELEMETRY_MODERATE_CABIN_TEMPERATURE "设置舱温适中"
|
||||||
|
#define CMD_CODE_TELEMETRY_HIGH_CABIN_TEMPERATURE 0x2F04
|
||||||
|
#define CMD_TEXT_TELEMETRY_HIGH_CABIN_TEMPERATURE "设置高舱温"
|
||||||
|
#define CMD_CODE_TURN_OFF_AMBIENT_LIGHT 0x2F07
|
||||||
|
#define CMD_TEXT_TURN_OFF_AMBIENT_LIGHT "关氛围灯"
|
||||||
|
#define CMD_CODE_TURN_ON_AMBIENT_LIGHT 0x2F08
|
||||||
|
#define CMD_TEXT_TURN_ON_AMBIENT_LIGHT "开氛围灯"
|
||||||
|
#define CMD_CODE_CONTROL_TOP_LIGHT 0x2F0B
|
||||||
|
#define CMD_TEXT_CONTROL_TOP_LIGHT "控制顶部照明灯"
|
||||||
|
#define CMD_CODE_CONTROL_SHOULDER_LIGHT 0x2F0D
|
||||||
|
#define CMD_TEXT_CONTROL_SHOULDER_LIGHT "控制肩部照明灯"
|
||||||
|
#define CMD_CODE_USE_RESTROOM 0x2F0E
|
||||||
|
#define CMD_TEXT_USE_RESTROOM "使用卫生间"
|
||||||
|
#define CMD_CODE_RESTROOM_USE_FINISHED 0x2F10
|
||||||
|
#define CMD_TEXT_RESTROOM_USE_FINISHED "卫生间使用结束"
|
||||||
|
extern std::map<std::string, uint16_t> g_telemetryText2Code;
|
||||||
|
|
||||||
|
//==============Queue============================================
|
||||||
|
typedef void* voidPtr;
|
||||||
|
extern void* g_pStatusLog, * g_pProcessLog, * g_pResultLog, * g_pDebugLog;
|
||||||
|
|
||||||
|
//==========================================================
|
||||||
|
extern void** g_pDataQueue;
|
||||||
|
extern void* g_pRecordQueue;
|
||||||
|
extern volatile bool g_bCloseASR;
|
||||||
|
extern volatile bool g_bCall;
|
||||||
|
extern volatile uint32_t g_iPlayedCallFrameCnt, g_iPlayedCallSampleCnt;
|
||||||
|
extern volatile uint32_t g_iCallRcvFrameCnt;//本次通话接收的帧数量
|
||||||
|
extern volatile uint32_t g_iInsertSlientSegCnt;
|
||||||
|
extern uint8_t g_iAlarmCode[4]; // 报警码 gejp 2024.10.03
|
||||||
|
extern uint8_t g_i5cmdNum[5]; // 5 info of cmd in history added by gejp 2024.10.03
|
||||||
|
extern uint16_t g_i5cmdCode[5];
|
||||||
|
extern uint8_t g_i5cmdOutcodes[5][6];
|
||||||
|
extern uint8_t g_i5cmdSendAbsTime[5][5];
|
||||||
|
extern uint32_t g_iCmdCount;
|
||||||
|
|
||||||
|
// gejp 2024.10.09
|
||||||
|
extern uint8_t g_iSysVerHigh;
|
||||||
|
extern uint8_t g_iSysVerLow;
|
||||||
|
extern uint8_t g_iAppVerHigh;
|
||||||
|
extern uint8_t g_iAppVerLow;
|
||||||
|
|
||||||
|
// gejp 2024.10.10
|
||||||
|
extern uint8_t g_iEnableAlarmCode;
|
||||||
|
// tangyc 2024.10.25
|
||||||
|
extern long g_iExternTimeDifference;
|
||||||
|
|
||||||
|
#define getCodeInfo() getCodeLine(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
|
||||||
|
extern bool g_bPrintResultLog;
|
||||||
|
extern int32_t g_outputBaseNum;
|
||||||
|
//int LoadLogQueueModule(char* strModulePath);
|
||||||
|
int32_t openLogAndQueues(char *config_file_path);
|
||||||
|
void ProcQueueFull(int i, bool bClear = true);
|
||||||
|
|
||||||
|
extern int g_iQueueCnt;
|
||||||
|
extern long g_iRcvNackedPCM;
|
||||||
|
|
||||||
|
extern bool g_bGPIO_Open;
|
||||||
|
extern int g_iGPIOWakeNum;
|
||||||
|
extern int g_iGPIOVolumeNum;
|
||||||
|
extern int g_iGPIOWakePressTime;
|
||||||
|
|
||||||
|
extern bool g_bTelemetry_Open;
|
||||||
|
extern bool g_bHostInfoTrans_Open;
|
||||||
|
extern int g_iUseTeleComForTelemetry;
|
||||||
|
extern int g_iUseHostComForTelemetry;
|
||||||
|
|
||||||
|
|
||||||
|
extern double g_fSilEnergy;
|
||||||
|
extern long g_iMicDataQueueMB;
|
||||||
|
extern void* g_pLogQueueModuleHandle;
|
||||||
|
|
||||||
|
extern long g_iPcmBlockBytes;
|
||||||
|
extern long g_iCallBytesPerBlockMS;
|
||||||
|
extern long g_iCallSampleRateMS;
|
||||||
|
|
||||||
|
extern char g_strPCM_ComPath[128];
|
||||||
|
extern int g_iPcmCom_tty_id;
|
||||||
|
extern long g_iPCMCom_BaudRate;
|
||||||
|
|
||||||
|
extern char g_strHostInfo_ComPath[128];
|
||||||
|
extern int g_iHostCom_tty_id;
|
||||||
|
extern long g_iHostInfoCom_BaudRate;
|
||||||
|
|
||||||
|
extern char g_strTelemetry_ComPath[128];
|
||||||
|
extern int g_iTelemetry_Com_tty_id;
|
||||||
|
extern long g_iTelemetryCom_BaudRate;
|
||||||
|
|
||||||
|
enum QueueIndex { // 数据类型
|
||||||
|
RECORD_DATA_QUEUE = 0,
|
||||||
|
PCM_QUEUE_FOR_KWS,
|
||||||
|
PCM_QUEUE_FOR_ASR,//
|
||||||
|
TEXT_QUEUE_FOR_TTS,//
|
||||||
|
TEXT_QUEUE_FOR_TTS_URGENT,
|
||||||
|
AUDIO_QUEUE_FOR_PLAY,//
|
||||||
|
AUDIO_QUEUE_FOR_PLAY_URGENT,
|
||||||
|
ORDER_INFO_QUEUE,// to upper host
|
||||||
|
ASSISTANT_INFO_QUEUE,// to upper host
|
||||||
|
HOST_INFO_QUEUE, //from upper host
|
||||||
|
|
||||||
|
AUDIO_FOR_HOST, // to upper host
|
||||||
|
|
||||||
|
DATA_QUEUE_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
//extern void* SystemTimer_old(void* p);
|
||||||
|
extern void* SystemTimer(void* p);
|
||||||
|
extern char g_strCurTime[50], g_strStartTime[50];
|
||||||
|
|
||||||
|
//------------ input audio parameters -----------------------
|
||||||
|
extern long g_iInputType;// 0--com 1--mic 2--udp
|
||||||
|
extern char g_strRcvPCM_UDP_IP[64];
|
||||||
|
extern long g_iUdpPort4RcvPCM;
|
||||||
|
extern char g_strPCM_ComPath[128];
|
||||||
|
extern long g_iPCMCom_BaudRate;
|
||||||
|
extern long g_iPCMCom_Proto;
|
||||||
|
extern int g_iPcmCom_tty_id;
|
||||||
|
|
||||||
|
//------------ upper host parameters -----------------------
|
||||||
|
extern long g_iHostInfoTransMode; //0--com, 1--udp, 2--unix socket
|
||||||
|
extern char g_strHostInfo_ComPath[128];
|
||||||
|
extern long g_iHostInfoCom_BaudRate;
|
||||||
|
extern int g_iHostCom_tty_id;
|
||||||
|
|
||||||
|
extern char g_strSndUnixSocket[500];
|
||||||
|
extern char g_strRcvUnixSocket[500];
|
||||||
|
extern char g_strUpperHostIP[64];
|
||||||
|
extern long g_iSndUdpPort4HostInfo; //port of upper host to receive
|
||||||
|
extern long g_iRcvUdpPort4HostInfo; //port to receive upper host info
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
extern long g_iWakeWhenStart;
|
||||||
|
extern long g_iStatusLogInterval;
|
||||||
|
//extern volatile long g_iConfirmRemainSeconds;//remain time to finish confirm, seconds
|
||||||
|
//extern volatile long g_iNoEffectiveResultSeconds;// record total time lenght there is no effective result
|
||||||
|
extern volatile uint64_t g_iLastWakeTime;
|
||||||
|
extern volatile uint64_t g_iLastResultTime;
|
||||||
|
extern volatile uint64_t g_iEndPlayTime;
|
||||||
|
//extern volatile uint64_t g_iToSleepTime;
|
||||||
|
extern volatile int g_iWaitType;
|
||||||
|
extern volatile uint64_t g_iWaitTimeMS[5];
|
||||||
|
extern volatile long g_iSilentSampleCnt, g_iSoundSampleCnt;
|
||||||
|
extern volatile long g_iSilentSampleCnt2FetchResul;
|
||||||
|
|
||||||
|
extern char g_strSystemLogPath[500];
|
||||||
|
|
||||||
|
extern char g_strPCMSavePath[500];
|
||||||
|
extern struct tm g_tCurLocalTime;
|
||||||
|
|
||||||
|
extern bool g_bKeepSysRuning;
|
||||||
|
extern long g_iSaveInputAudio;
|
||||||
|
extern long g_iSaveTTSAudio;
|
||||||
|
extern long g_iSaveHostAudio;
|
||||||
|
extern long g_iSavePlaySound;
|
||||||
|
|
||||||
|
extern long g_iPlaySound;
|
||||||
|
extern uint32_t g_iQueueFullTimes[DATA_QUEUE_COUNT];
|
||||||
|
extern volatile uint64_t g_iComRcvBytes[2];
|
||||||
|
extern long g_iUseASR2Wake;
|
||||||
|
extern void set_signal_handler(int n);
|
||||||
|
void setSysSleep(char* pSrc);//pSrc: by whom, kws,asr, button or start
|
||||||
|
void setSysWake(char *pSrc);//pSrc: by whom, kws,asr, button or start
|
||||||
|
void SayHello(char* pNoticeStr);
|
||||||
|
|
||||||
|
extern std::atomic<int> g_iSysState;
|
||||||
|
extern bool g_bKeepSysRunning;
|
||||||
|
|
||||||
|
extern unsigned int g_iOrderCnt;
|
||||||
|
extern unsigned int g_iOrderExeSuccCnt;
|
||||||
|
extern unsigned int g_iOrderExeFailCnt;
|
||||||
|
|
||||||
|
extern unsigned int g_iOrderSndSuccCnt;
|
||||||
|
extern unsigned int g_iOrderSndFailCnt;
|
||||||
|
extern unsigned int g_iOrderResultCnt;
|
||||||
|
|
||||||
|
extern unsigned int g_iAssistantCnt;
|
||||||
|
|
||||||
|
extern unsigned int g_iQuerySndSuccCnt;
|
||||||
|
extern unsigned int g_iQuerySndFailCnt;
|
||||||
|
extern unsigned int g_iQueryResultCnt;
|
||||||
|
|
||||||
|
extern unsigned int g_iRcvResultErr[2];
|
||||||
|
extern uint16_t volatile g_iTelemetryOrderSndSuccCnt;
|
||||||
|
extern uint8_t volatile g_last_send_command[6];
|
||||||
|
//extern int64_t g_iPreWakeTime;
|
||||||
|
extern std::atomic<int> g_iOrdinaryPlayStop;
|
||||||
|
|
||||||
|
extern bool g_bVolumeKeyState;
|
||||||
|
extern bool g_bWakeupKeyState;
|
||||||
|
extern bool g_bVolumeKeyPressed;
|
||||||
|
extern bool g_bWakeupKeyPressed;
|
||||||
|
|
||||||
|
#endif //AUDIOSERVER_AUDIODATAUNIT_H
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef _INCLUDE_EVENT_H_
|
||||||
|
#define _INCLUDE_EVENT_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*event_callback)(const char*, void*, void*);
|
||||||
|
|
||||||
|
void sys_event(const char *event_name, void *args);
|
||||||
|
int sys_event_register(const char *event_name, event_callback callback, void* user_data);
|
||||||
|
int sys_event_unregister(const char *event_name, event_callback callback);
|
||||||
|
void* sys_event_thread(void*);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef _INCLUDE_EXTERN_INTERFACE_H_
|
||||||
|
#define _INCLUDE_EXTERN_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define ET_TYPE_NONE 0
|
||||||
|
#define ET_TYPE_TEXT 1
|
||||||
|
#define ET_TYPE_AUDIO 2
|
||||||
|
#define ET_TYPE_COMMAND 3
|
||||||
|
#define ET_TYPE_ALARM 4
|
||||||
|
#define ET_TYPE_TELEMETRY_REQUEST 5
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct TelemetryRequestData {
|
||||||
|
bool keep_sys_running;
|
||||||
|
bool close_asr;
|
||||||
|
int sys_state;
|
||||||
|
bool volume_key_pressed;
|
||||||
|
bool wakeup_key_pressed;
|
||||||
|
int volume_grade;
|
||||||
|
int sys_ver_high;
|
||||||
|
int sys_ver_low;
|
||||||
|
int app_ver_high;
|
||||||
|
int app_ver_low;
|
||||||
|
};
|
||||||
|
|
||||||
|
union PacketData
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
void extern_interface_init(const char* config_path, et_callback_t cb);
|
||||||
|
void extern_interface_send(uint32_t type, size_t len, union PacketData data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,196 @@
|
||||||
|
#ifndef _INCLUDE_TELEMETRY_
|
||||||
|
#define _INCLUDE_TELEMETRY_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "comframe.h"
|
||||||
|
|
||||||
|
#define TELEMETRY_REQUEST_PAYLOAD 0xFF11
|
||||||
|
|
||||||
|
#define TELEMETRY_STATUS_OK 0xAA
|
||||||
|
#define TELEMETRY_STATUS_ERROR 0x55
|
||||||
|
|
||||||
|
#define TELEMETRY_ERROR_TYPE 0x00E1
|
||||||
|
#define TELEMETRY_ERROR_CHECKSUM 0x00E2
|
||||||
|
|
||||||
|
#define TELEMETRY_SEND_COMMAND_INFO_LENGTH 5
|
||||||
|
|
||||||
|
#define TELEMETRY_ALARM_TC_A_PRESS 0x00610061
|
||||||
|
#define TELEMETRY_ALARM_TC_B_PRESS 0x00620062
|
||||||
|
#define TELEMETRY_ALARM_SUBSYS_PARAM_ERR 0x00630063
|
||||||
|
#define TELEMETRY_ALARM_WATER_TANK_FULL 0x00640064
|
||||||
|
#define TELEMETRY_ALARM_N2_PRESS_LOW 0x00650065
|
||||||
|
#define TELEMETRY_ALARM_O2_PRESS_LOW 0x00660066
|
||||||
|
#define TELEMETRY_ALARM_RETURN_CAB_FIRE 0x00670067
|
||||||
|
#define TELEMETRY_ALARM_RETURN_CAB_TOTAL_PRESS 0x00680068
|
||||||
|
#define TELEMETRY_ALARM_RETURN_CAB_O2_PART_PRESS 0x00690069
|
||||||
|
#define TELEMETRY_ALARM_RETURN_CAB_CO2_PART_PRESS 0x00700070
|
||||||
|
#define TELEMETRY_ALARM_INT_PUMP_B_SPEED 0x00710071
|
||||||
|
#define TELEMETRY_ALARM_CIRC_FAN_SPEED 0x00720072
|
||||||
|
#define TELEMETRY_ALARM_LND_SEAL_CAB_TOTAL_PRESS 0x00730073
|
||||||
|
#define TELEMETRY_ALARM_LND_SEAL_CAB_O2_PART_PRESS 0x00740074
|
||||||
|
#define TELEMETRY_ALARM_LND_SEAL_CAB_CO2_PART_PRESS 0x00750075
|
||||||
|
#define TELEMETRY_ALARM_LND_SEAL_CAB_FIRE 0x00760076
|
||||||
|
#define TELEMETRY_ALARM_LND_RAD_LEAK 0x00770077
|
||||||
|
#define TELEMETRY_ALARM_TAKEOFF 0x00010001
|
||||||
|
#define TELEMETRY_ALARM_SEP 0x00020002
|
||||||
|
#define TELEMETRY_ALARM_COMP_DOCK 0x00030003
|
||||||
|
#define TELEMETRY_ALARM_COMP_SEP 0x00040004
|
||||||
|
#define TELEMETRY_ALARM_RET_SEP 0x00050005
|
||||||
|
#define TELEMETRY_ALARM_REC_START 0x00060006
|
||||||
|
#define TELEMETRY_ALARM_LND 0x00070007
|
||||||
|
#define TELEMETRY_ALARM_ESC_TOWER_ESC 0x00080008
|
||||||
|
#define TELEMETRY_ALARM_RESERVED_1 0x00090009
|
||||||
|
#define TELEMETRY_ALARM_ESC_TOWER_SEP 0x000A000A
|
||||||
|
#define TELEMETRY_ALARM_VESSEL_ESC 0x00110011
|
||||||
|
#define TELEMETRY_ALARM_PREP_5_MIN 0x17711771
|
||||||
|
#define TELEMETRY_ALARM_PREP_1_MIN 0x17721772
|
||||||
|
#define TELEMETRY_ALARM_DOCK_PREP 0x17731773
|
||||||
|
#define TELEMETRY_ALARM_DOCK_RING_CONTACT 0x17741774
|
||||||
|
#define TELEMETRY_ALARM_SEP_COMPLETE 0x17751775
|
||||||
|
#define TELEMETRY_ALARM_PAYLOAD_SEP 0x17761776
|
||||||
|
#define TELEMETRY_ALARM_SAILS_DEPLOY 0x17771777
|
||||||
|
#define TELEMETRY_ALARM_SEP_PREP 0x17781778
|
||||||
|
#define TELEMETRY_ALARM_SAILS_DEPLOY_PREP 0x17791779
|
||||||
|
#define TELEMETRY_ALARM_RESERVED_2 0x177A177A
|
||||||
|
#define TELEMETRY_ALARM_ORBIT_CHG_30_MIN 0x177B177B
|
||||||
|
#define TELEMETRY_ALARM_ORBIT_CHG_10_MIN 0x177C177C
|
||||||
|
#define TELEMETRY_ALARM_ORBIT_CHG_5_MIN 0x177D177D
|
||||||
|
#define TELEMETRY_ALARM_ENGINE_START_CMD 0x177E177E
|
||||||
|
#define TELEMETRY_ALARM_ENGINE_STOP_CMD 0x177F177F
|
||||||
|
#define TELEMETRY_ALARM_ORBIT_CHG_END 0x17801780
|
||||||
|
#define TELEMETRY_ALARM_GNC_SELF_CTRL_MODE 0x17811781
|
||||||
|
#define TELEMETRY_ALARM_APPROACH_FLIGHT_START 0x17821782
|
||||||
|
#define TELEMETRY_ALARM_YAW_ADJ_START 0x17831783
|
||||||
|
#define TELEMETRY_ALARM_YAW_ADJ_COMPLETE 0x17841784
|
||||||
|
#define TELEMETRY_ALARM_TRANSLATION_PHASE 0x17851785
|
||||||
|
#define TELEMETRY_ALARM_DOCK_POINT_ENTRY 0x17861786
|
||||||
|
#define TELEMETRY_ALARM_APPROACH_FLIGHT_CONTINUE 0x17871787
|
||||||
|
#define TELEMETRY_ALARM_PITCH_ADJ_START 0x17881788
|
||||||
|
#define TELEMETRY_ALARM_PITCH_ADJ_COMPLETE 0x17891789
|
||||||
|
#define TELEMETRY_ALARM_FINAL_APPROACH_FLIGHT 0x178A178A
|
||||||
|
|
||||||
|
#define ComFrameTelemetry_STATUS_OK(status) ((status) == TELEMETRY_STATUS_OK)
|
||||||
|
#define ComFrameTelemetry_STATUS_ERR(status) ((status) == TELEMETRY_STATUS_ERROR)
|
||||||
|
#define ComFrameTelemetry_STATUS_STR(status) ( \
|
||||||
|
ComFrameTelemetry_STATUS_OK(status) ? "ok" : \
|
||||||
|
(ComFrameTelemetry_STATUS_ERR(status) ? "error" : "unknown") \
|
||||||
|
)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct TelemetryCommandInfo {
|
||||||
|
uint32_t time;
|
||||||
|
uint8_t code[2];
|
||||||
|
uint16_t seqid;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct TelemetrySendCommandInfo {
|
||||||
|
uint8_t seqid;
|
||||||
|
uint8_t flag;
|
||||||
|
uint32_t time;
|
||||||
|
uint8_t code[2];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
|
struct TelemetryData4UpperHost { // upper
|
||||||
|
uint8_t work_status;
|
||||||
|
uint8_t com_status;
|
||||||
|
uint8_t coprocessor1_status;
|
||||||
|
uint8_t coprocessor2_status;
|
||||||
|
uint8_t voice_circuit_status;
|
||||||
|
//uint8_t work_status_backup;
|
||||||
|
uint8_t telemetry_count;
|
||||||
|
uint8_t voice_mode;
|
||||||
|
uint8_t recognition_status;
|
||||||
|
uint8_t recognition_info[8];
|
||||||
|
uint8_t particle_detection1;
|
||||||
|
uint8_t particle_detection2;
|
||||||
|
uint8_t particle_detection3;
|
||||||
|
// 2024.10.25
|
||||||
|
struct TelemetryCommandInfo receive_command;
|
||||||
|
struct TelemetryCommandInfo send_command;
|
||||||
|
|
||||||
|
uint8_t volume_key_status;
|
||||||
|
uint8_t wake_key_status;
|
||||||
|
uint8_t key_status_backup;
|
||||||
|
uint8_t current_volume;
|
||||||
|
uint8_t system_version_high;
|
||||||
|
uint8_t system_version_low;
|
||||||
|
uint8_t application_version_high;
|
||||||
|
uint8_t application_version_low;
|
||||||
|
uint8_t alarm_code[4];
|
||||||
|
uint8_t telemetry_backup[5];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct TelemetryData { // telemetry
|
||||||
|
uint8_t work_status;
|
||||||
|
uint8_t com_status;
|
||||||
|
uint8_t coprocessor1_status;
|
||||||
|
uint8_t coprocessor2_status;
|
||||||
|
uint8_t voice_circuit_status;
|
||||||
|
//uint8_t work_status_backup;
|
||||||
|
uint8_t telemetry_count;
|
||||||
|
uint8_t voice_mode;
|
||||||
|
uint8_t recognition_status;
|
||||||
|
uint8_t recognition_info[8];
|
||||||
|
uint8_t particle_detection1;
|
||||||
|
uint8_t particle_detection2;
|
||||||
|
uint8_t particle_detection3;
|
||||||
|
|
||||||
|
// 2024.10.25
|
||||||
|
struct TelemetryCommandInfo receive_command;
|
||||||
|
struct TelemetrySendCommandInfo send_command[TELEMETRY_SEND_COMMAND_INFO_LENGTH];
|
||||||
|
|
||||||
|
uint8_t volume_key_status;
|
||||||
|
uint8_t wake_key_status;
|
||||||
|
uint8_t key_status_backup;
|
||||||
|
uint8_t current_volume;
|
||||||
|
uint8_t system_version_high;
|
||||||
|
uint8_t system_version_low;
|
||||||
|
uint8_t application_version_high;
|
||||||
|
uint8_t application_version_low;
|
||||||
|
uint8_t send_count;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static __inline void UpperHostTelemetryData_SwapEndian(struct TelemetryData4UpperHost* tele_data) {
|
||||||
|
tele_data->receive_command.seqid = byteswaps(tele_data->receive_command.seqid);
|
||||||
|
tele_data->receive_command.time = byteswapl(tele_data->receive_command.time);
|
||||||
|
tele_data->send_command.seqid = byteswaps(tele_data->send_command.seqid);
|
||||||
|
tele_data->send_command.time = byteswapl(tele_data->send_command.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void TelemetryData_SwapEndian(struct TelemetryData* tele_data) {
|
||||||
|
tele_data->receive_command.seqid = byteswaps(tele_data->receive_command.seqid);
|
||||||
|
tele_data->receive_command.time = byteswapl(tele_data->receive_command.time);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < TELEMETRY_SEND_COMMAND_INFO_LENGTH; i++) {
|
||||||
|
tele_data->send_command[i].time = byteswapl(tele_data->send_command[i].time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ComFrame* NewTelemetryRequestMsg(uint16_t address, const bool swap_endian) {
|
||||||
|
uint16_t tele_request_payload = (swap_endian) ? byteswaps(TELEMETRY_REQUEST_PAYLOAD) : TELEMETRY_REQUEST_PAYLOAD;
|
||||||
|
return ComFrame_New(address, COM_FRAME_TYPE_TELEMETRY_REQUEST, &tele_request_payload, sizeof(uint16_t), swap_endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ComFrame* NewTelemetryAnswerData(uint16_t address, const struct TelemetryData4UpperHost* tele_data, const bool swap_endian) {
|
||||||
|
ComFrame* frame = ComFrame_New(address, COM_FRAME_TYPE_TELEMETRY_ANSWER, tele_data, sizeof(struct TelemetryData4UpperHost), swap_endian);
|
||||||
|
if (swap_endian)
|
||||||
|
UpperHostTelemetryData_SwapEndian((struct TelemetryData4UpperHost*)(frame->payload));
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ComFrame* NewTelemetryErrorMsg(uint16_t address, uint16_t code, const bool swap_endian) {
|
||||||
|
uint16_t tele_error_payload = (swap_endian) ? byteswaps(code) : code;
|
||||||
|
return ComFrame_New(address, COM_FRAME_TYPE_TELEMETRY_REQUEST, &tele_error_payload, sizeof(uint16_t), swap_endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SendTelemetryErrorMsg(int tty_id, uint16_t address, uint16_t code, const bool swap_endian);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_)
|
|
@ -0,0 +1,44 @@
|
||||||
|
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)
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/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}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,537 @@
|
||||||
|
//#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
//#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
|
|
@ -0,0 +1,42 @@
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -0,0 +1,287 @@
|
||||||
|
#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
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/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
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/bash
|
||||||
|
mkdir -p build && cd $(dirname $0)/build
|
||||||
|
|
||||||
|
if echo "$@" | grep -iq r; then
|
||||||
|
BUILD_TYPE=RELEASE
|
||||||
|
else
|
||||||
|
BUILD_TYPE=DEBUG
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$@" | grep -iq e; then
|
||||||
|
#------ compile for euler -------------------
|
||||||
|
TOOLCHAIN=../../toolchains/armv7l_openeuler_setup.cmake
|
||||||
|
BUILD_PREFIX=armv7l-openeular
|
||||||
|
else
|
||||||
|
#------- compile for arm32 ------------------
|
||||||
|
TOOLCHAIN=../../toolchains/armv7l_linux_setup.cmake
|
||||||
|
BUILD_PREFIX=armv7l-linux
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p ${BUILD_PREFIX} && cd ${BUILD_PREFIX}
|
||||||
|
rm -f CMakeCache.txt
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} -DEXECUTABLE_OUTPUT_PATH=../../bin/${BUILD_PREFIX} ../..
|
||||||
|
cmake --build . -j 4 --
|
|
@ -0,0 +1,415 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from enum import IntEnum
|
||||||
|
from glob import glob
|
||||||
|
from subprocess import run
|
||||||
|
from time import time
|
||||||
|
from traceback import print_exception
|
||||||
|
from typing import List, NoReturn, Optional
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = "0.1.2"
|
||||||
|
|
||||||
|
|
||||||
|
if sys.stdout.isatty():
|
||||||
|
TTY_COLOR_RED = "\033[31m"
|
||||||
|
TTY_COLOR_RED_BOLD = "\033[1;31m"
|
||||||
|
TTY_COLOR_GREEN = "\033[32m"
|
||||||
|
TTY_COLOR_GREEN_BOLD = "\033[1;32m"
|
||||||
|
TTY_COLOR_YELLOW = "\033[33m"
|
||||||
|
TTY_COLOR_YELLOW_BOLD = "\033[1;33m"
|
||||||
|
TTY_COLOR_CYAN_BOLD = "\033[1;36m"
|
||||||
|
TTY_COLOR_CLEAR = "\033[0m"
|
||||||
|
|
||||||
|
TTY_COLUMNS_SIZE = os.get_terminal_size().columns
|
||||||
|
else:
|
||||||
|
TTY_COLOR_RED = ""
|
||||||
|
TTY_COLOR_RED_BOLD = ""
|
||||||
|
TTY_COLOR_GREEN = ""
|
||||||
|
TTY_COLOR_GREEN_BOLD = ""
|
||||||
|
TTY_COLOR_YELLOW = ""
|
||||||
|
TTY_COLOR_YELLOW_BOLD = ""
|
||||||
|
TTY_COLOR_CYAN_BOLD = ""
|
||||||
|
TTY_COLOR_CLEAR = ""
|
||||||
|
|
||||||
|
TTY_COLUMNS_SIZE = 80
|
||||||
|
|
||||||
|
|
||||||
|
def print_separator_ex(lc: str, title: str, color: str) -> None:
|
||||||
|
len_str = len(title)
|
||||||
|
|
||||||
|
print(f"{TTY_COLOR_CLEAR}{color}", end='') # 设置颜色样式
|
||||||
|
if len_str + 2 > TTY_COLUMNS_SIZE:
|
||||||
|
print(title)
|
||||||
|
else:
|
||||||
|
print(f" {title} ".center(TTY_COLUMNS_SIZE, lc))
|
||||||
|
print(TTY_COLOR_CLEAR, end='') # 重置颜色为默认
|
||||||
|
|
||||||
|
|
||||||
|
class CTestCaseStatus(IntEnum):
|
||||||
|
NOT_RUN = -1
|
||||||
|
PASSED = 0
|
||||||
|
ERROR = 1
|
||||||
|
FAILED = 16
|
||||||
|
SKIPPED = 32
|
||||||
|
SETUP_FAILED = 17
|
||||||
|
TEARDOWN_FAILED = 18
|
||||||
|
|
||||||
|
|
||||||
|
class CTestCaseCounter:
|
||||||
|
__slots__ = ["total_count", "passed", "error", "failed", "skipped"]
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.total_count = 0
|
||||||
|
self.passed: 'set[CTestCase]' = set()
|
||||||
|
self.error: 'set[CTestCase]' = set()
|
||||||
|
self.failed: 'set[CTestCase]' = set()
|
||||||
|
self.skipped: 'set[CTestCase]' = set()
|
||||||
|
|
||||||
|
def update(self, test_case: "CTestCase") -> None:
|
||||||
|
self.total_count += 1
|
||||||
|
if test_case.status == CTestCaseStatus.PASSED:
|
||||||
|
self.passed.add(test_case)
|
||||||
|
elif test_case.status == CTestCaseStatus.ERROR:
|
||||||
|
self.error.add(test_case)
|
||||||
|
elif test_case.status == CTestCaseStatus.SKIPPED:
|
||||||
|
self.skipped.add(test_case)
|
||||||
|
elif test_case.status in [CTestCaseStatus.FAILED, CTestCaseStatus.SETUP_FAILED, CTestCaseStatus.TEARDOWN_FAILED]:
|
||||||
|
self.failed.add(test_case)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"{test_case.status} is not a valid status for counter")
|
||||||
|
|
||||||
|
def clone(self) -> "CTestCaseCounter":
|
||||||
|
counter = CTestCaseCounter()
|
||||||
|
counter.total_count = self.total_count
|
||||||
|
counter.passed = self.passed
|
||||||
|
counter.error = self.error
|
||||||
|
counter.failed = self.failed
|
||||||
|
counter.skipped = self.skipped
|
||||||
|
return counter
|
||||||
|
|
||||||
|
def __add__(self, other: "CTestCaseCounter") -> "CTestCaseCounter":
|
||||||
|
counter = self.clone()
|
||||||
|
counter += other
|
||||||
|
return counter
|
||||||
|
|
||||||
|
def __iadd__(self, other: "CTestCaseCounter") -> "CTestCaseCounter":
|
||||||
|
self.total_count += other.total_count
|
||||||
|
self.passed.update(other.passed)
|
||||||
|
self.error.update(other.error)
|
||||||
|
self.failed.update(other.failed)
|
||||||
|
self.skipped.update(other.skipped)
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> CTestCaseStatus:
|
||||||
|
if self.error:
|
||||||
|
return CTestCaseStatus.ERROR
|
||||||
|
elif self.failed:
|
||||||
|
return CTestCaseStatus.FAILED
|
||||||
|
elif self.skipped:
|
||||||
|
return CTestCaseStatus.SKIPPED
|
||||||
|
elif self.passed:
|
||||||
|
return CTestCaseStatus.PASSED
|
||||||
|
else:
|
||||||
|
return CTestCaseStatus.NOT_RUN
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<counter total: {self.total_count}, passed: {len(self.passed)}, error: {len(self.error)}, failed: {len(self.failed)}, skipped: {len(self.skipped)}>"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
ss = StringIO()
|
||||||
|
ss.write(f"total: {self.total_count}")
|
||||||
|
if self.passed:
|
||||||
|
ss.write(f", passed: {len(self.passed)}")
|
||||||
|
elif self.skipped:
|
||||||
|
ss.write(f", skipped: {len(self.skipped)}")
|
||||||
|
elif self.failed:
|
||||||
|
ss.write(f", failed: {len(self.failed)}")
|
||||||
|
elif self.error:
|
||||||
|
ss.write(f", error: {len(self.error)}")
|
||||||
|
return ss.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
class CTestCase:
|
||||||
|
__slots__ = ["id", "name", "status", "file", "result", "error_info"]
|
||||||
|
|
||||||
|
def __init__(self, id: int, name: str, file: "CTestCaseFile") -> None:
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
self.file = file
|
||||||
|
self.status = CTestCaseStatus.NOT_RUN
|
||||||
|
self.result = None
|
||||||
|
self.error_info = None
|
||||||
|
|
||||||
|
def run(self, *, verbose: bool = False, capture: bool = True) -> CTestCaseStatus:
|
||||||
|
try:
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
self.result = run([self.file.path, "--unittest", str(self.id)], capture_output=capture)
|
||||||
|
except Exception:
|
||||||
|
self.status = CTestCaseStatus.ERROR
|
||||||
|
self.error_info = sys.exc_info()
|
||||||
|
if not capture:
|
||||||
|
print(TTY_COLOR_RED)
|
||||||
|
print_exception(*self.error_info)
|
||||||
|
print(TTY_COLOR_CLEAR)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.status = CTestCaseStatus.ERROR
|
||||||
|
self.error_info = sys.exc_info()
|
||||||
|
else:
|
||||||
|
code = self.result.returncode
|
||||||
|
if code in CTestCaseStatus.__members__.values():
|
||||||
|
self.status = CTestCaseStatus(code)
|
||||||
|
else:
|
||||||
|
self.status = CTestCaseStatus.ERROR
|
||||||
|
if verbose:
|
||||||
|
self.print_status_verbose()
|
||||||
|
else:
|
||||||
|
self.print_status()
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
def print_status(self) -> None:
|
||||||
|
if self.status == CTestCaseStatus.PASSED:
|
||||||
|
print(f"{TTY_COLOR_GREEN}.{TTY_COLOR_CLEAR}", end='')
|
||||||
|
elif self.status in [CTestCaseStatus.FAILED, CTestCaseStatus.SETUP_FAILED, CTestCaseStatus.TEARDOWN_FAILED]:
|
||||||
|
print(f"{TTY_COLOR_RED}F{TTY_COLOR_CLEAR}", end='')
|
||||||
|
elif self.status == CTestCaseStatus.ERROR:
|
||||||
|
print(f"{TTY_COLOR_RED}E{TTY_COLOR_CLEAR}", end='')
|
||||||
|
elif self.status == CTestCaseStatus.SKIPPED:
|
||||||
|
print(f"{TTY_COLOR_YELLOW}s{TTY_COLOR_CLEAR}", end='')
|
||||||
|
else:
|
||||||
|
raise ValueError(f"invalid test case status: {self.status}")
|
||||||
|
|
||||||
|
def print_status_verbose(self) -> None:
|
||||||
|
if self.status == CTestCaseStatus.PASSED:
|
||||||
|
print(f"{self.name} {TTY_COLOR_GREEN}PASSED{TTY_COLOR_CLEAR}")
|
||||||
|
elif self.status == CTestCaseStatus.FAILED:
|
||||||
|
print(f"{self.name} {TTY_COLOR_RED}FAILED{TTY_COLOR_CLEAR}")
|
||||||
|
elif self.status == CTestCaseStatus.ERROR:
|
||||||
|
print(f"{self.name} {TTY_COLOR_RED}ERROR{TTY_COLOR_CLEAR}")
|
||||||
|
elif self.status == CTestCaseStatus.SETUP_FAILED:
|
||||||
|
print(f"{self.name} {TTY_COLOR_RED}SETUP FAILED{TTY_COLOR_CLEAR}")
|
||||||
|
elif self.status == CTestCaseStatus.TEARDOWN_FAILED:
|
||||||
|
print(f"{self.name} {TTY_COLOR_RED}TEARDOWN FAILED{TTY_COLOR_CLEAR}")
|
||||||
|
elif self.status == CTestCaseStatus.SKIPPED:
|
||||||
|
print(f"{self.name} {TTY_COLOR_YELLOW}SKIPPED{TTY_COLOR_CLEAR}")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"invalid test case status: {self.status}")
|
||||||
|
|
||||||
|
def report(self) -> Optional[str]:
|
||||||
|
if self.status == CTestCaseStatus.PASSED:
|
||||||
|
return
|
||||||
|
elif self.status == CTestCaseStatus.SKIPPED:
|
||||||
|
return f"{TTY_COLOR_YELLOW}SKIPPED{TTY_COLOR_CLEAR} {self.name}"
|
||||||
|
elif self.status == CTestCaseStatus.ERROR:
|
||||||
|
if self.error_info:
|
||||||
|
print_separator_ex('_', self.name, TTY_COLOR_RED)
|
||||||
|
print(TTY_COLOR_RED, end='')
|
||||||
|
print_exception(*self.error_info)
|
||||||
|
print(TTY_COLOR_CLEAR, end='')
|
||||||
|
assert self.error_info[0]
|
||||||
|
if str(self.error_info[1]):
|
||||||
|
error = f"{self.error_info[0].__name__}: {self.error_info[1]}"
|
||||||
|
else:
|
||||||
|
error = f"{self.error_info[0].__name__}"
|
||||||
|
return f"{TTY_COLOR_RED}ERROR{TTY_COLOR_CLEAR} {self.name} - {error}"
|
||||||
|
else:
|
||||||
|
assert self.result
|
||||||
|
if self.result.stderr:
|
||||||
|
print_separator_ex('_', self.name, TTY_COLOR_RED)
|
||||||
|
print(TTY_COLOR_RED, end='')
|
||||||
|
print(self.result.stderr.decode("utf-8"), end='')
|
||||||
|
print(TTY_COLOR_CLEAR, end='')
|
||||||
|
if self.result.stdout:
|
||||||
|
print_separator_ex('-', "Captured stdout", '')
|
||||||
|
print(self.result.stdout.decode("utf-8"), end='')
|
||||||
|
return f"{TTY_COLOR_RED}ERROR{TTY_COLOR_CLEAR} {self.name} - RuntimeError ({self.result.returncode})"
|
||||||
|
elif self.status in [CTestCaseStatus.FAILED, CTestCaseStatus.SETUP_FAILED, CTestCaseStatus.TEARDOWN_FAILED]:
|
||||||
|
assert self.result
|
||||||
|
if self.result.stderr:
|
||||||
|
print_separator_ex('_', self.name, TTY_COLOR_RED)
|
||||||
|
print(TTY_COLOR_RED, end='')
|
||||||
|
print(self.result.stderr.decode("utf-8"), end='')
|
||||||
|
print(TTY_COLOR_CLEAR, end='')
|
||||||
|
if self.result.stdout:
|
||||||
|
if self.result.stderr:
|
||||||
|
print_separator_ex('-', "Captured stdout", '')
|
||||||
|
else:
|
||||||
|
print_separator_ex('_', self.name, '')
|
||||||
|
print(self.result.stdout.decode("utf-8", "replace"), end='')
|
||||||
|
if self.status == CTestCaseStatus.FAILED:
|
||||||
|
return f"{TTY_COLOR_RED}FAILED{TTY_COLOR_CLEAR} {self.name}"
|
||||||
|
elif self.status == CTestCaseStatus.SETUP_FAILED:
|
||||||
|
return f"{TTY_COLOR_RED}FAILED{TTY_COLOR_CLEAR} {self.name} - SetupError"
|
||||||
|
else:
|
||||||
|
return f"{TTY_COLOR_RED}FAILED{TTY_COLOR_CLEAR} {self.name} - TeardownError"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"invalid test case status: {self.status}")
|
||||||
|
|
||||||
|
|
||||||
|
class CTestCaseFile:
|
||||||
|
__slots__ = ["path", "test_cases", "collect_result", "collect_error_info", "counter"]
|
||||||
|
|
||||||
|
def __init__(self, path: str) -> None:
|
||||||
|
self.path = path
|
||||||
|
self.test_cases: List[CTestCase] = []
|
||||||
|
self.collect_result = None
|
||||||
|
self.collect_error_info = None
|
||||||
|
|
||||||
|
def collect(self) -> int:
|
||||||
|
try:
|
||||||
|
result = run([self.path, "--collect"], capture_output=True)
|
||||||
|
except Exception:
|
||||||
|
self.collect_error_info = sys.exc_info()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
self.collect_result = result
|
||||||
|
return 0
|
||||||
|
for id, name in enumerate(result.stdout.decode("ascii").split()):
|
||||||
|
self.test_cases.append(CTestCase(id, name, self))
|
||||||
|
return len(self.test_cases)
|
||||||
|
|
||||||
|
def run(self, verbose: bool = False, capture: bool = True) -> CTestCaseCounter:
|
||||||
|
counter = CTestCaseCounter()
|
||||||
|
if not verbose:
|
||||||
|
print(self.path, end=' ')
|
||||||
|
for i in self.test_cases:
|
||||||
|
if verbose:
|
||||||
|
print(self.path, end='::')
|
||||||
|
i.run(verbose=verbose, capture=capture)
|
||||||
|
counter.update(i)
|
||||||
|
if not verbose:
|
||||||
|
print()
|
||||||
|
return counter
|
||||||
|
|
||||||
|
def report(self) -> List[str]:
|
||||||
|
if self.collect_result is not None:
|
||||||
|
print_separator_ex('_', f"ERROR collecting {self.path}", TTY_COLOR_RED_BOLD)
|
||||||
|
print(TTY_COLOR_RED, end='')
|
||||||
|
print(self.collect_result.stderr.decode())
|
||||||
|
print(TTY_COLOR_CLEAR, end='')
|
||||||
|
if self.collect_result.stdout:
|
||||||
|
print_separator_ex('-', "Captured stdout", '')
|
||||||
|
print(self.collect_result.stdout.decode())
|
||||||
|
return [f"ERROR {self.path} - CollectError ({self.collect_result.returncode})"]
|
||||||
|
elif self.collect_error_info is not None:
|
||||||
|
assert self.collect_error_info[0]
|
||||||
|
print_separator_ex('_', f"ERROR collecting {self.path}", TTY_COLOR_RED_BOLD)
|
||||||
|
print(TTY_COLOR_RED, end='')
|
||||||
|
print_exception(*self.collect_error_info)
|
||||||
|
print(TTY_COLOR_CLEAR, end='')
|
||||||
|
return [f"ERROR{TTY_COLOR_CLEAR} {self.path} - {self.collect_error_info[0].__name__}: {self.collect_error_info[1]}"]
|
||||||
|
return list(filter(None, (i.report() for i in self.test_cases)))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def error(self) -> bool:
|
||||||
|
return self.collect_result is not None or self.collect_error_info is not None
|
||||||
|
|
||||||
|
|
||||||
|
def report_collect_error(start_time: float, *error_files: CTestCaseFile) -> NoReturn:
|
||||||
|
print_separator_ex('=', "ERRORS", '')
|
||||||
|
summary = []
|
||||||
|
for i in error_files:
|
||||||
|
summary.extend(i.report())
|
||||||
|
|
||||||
|
print_separator_ex('=', "short test summary info", TTY_COLOR_CYAN_BOLD)
|
||||||
|
for i in summary:
|
||||||
|
print(i)
|
||||||
|
print_separator_ex('!', f"Interrupted: {len(error_files)} error during collection", '')
|
||||||
|
cur_time = time()
|
||||||
|
print_separator_ex('=', f"{len(summary)} error in {cur_time - start_time:.2f}s", TTY_COLOR_RED_BOLD)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def report_no_ran(start_time: float) -> NoReturn:
|
||||||
|
cur_time = time()
|
||||||
|
print_separator_ex('=', f"no tests ran in {cur_time - start_time:.2f}s", TTY_COLOR_YELLOW)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
def report(start_time: float, counter: CTestCaseCounter, *, show_capture: bool = True) -> NoReturn:
|
||||||
|
cur_time = time()
|
||||||
|
summary = []
|
||||||
|
if counter.error:
|
||||||
|
if show_capture:
|
||||||
|
print_separator_ex('=', "ERRORS", '')
|
||||||
|
for i in counter.error:
|
||||||
|
summary.append(i.report())
|
||||||
|
if counter.failed:
|
||||||
|
if show_capture:
|
||||||
|
print_separator_ex('=', "FAILURES", TTY_COLOR_RED)
|
||||||
|
for i in counter.failed:
|
||||||
|
summary.append(i.report())
|
||||||
|
if counter.skipped:
|
||||||
|
for i in counter.skipped:
|
||||||
|
summary.append(i.report())
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
print_separator_ex('=', "short test summary info", TTY_COLOR_CYAN_BOLD)
|
||||||
|
for i in summary:
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
if counter.status in [CTestCaseStatus.FAILED, CTestCaseStatus.ERROR]:
|
||||||
|
color = TTY_COLOR_RED_BOLD
|
||||||
|
elif counter.status == CTestCaseStatus.SKIPPED:
|
||||||
|
color = TTY_COLOR_YELLOW_BOLD
|
||||||
|
else:
|
||||||
|
color = TTY_COLOR_GREEN_BOLD
|
||||||
|
|
||||||
|
print_separator_ex('=', f"{counter} in {cur_time - start_time:.2f}s", color)
|
||||||
|
if counter.status in [CTestCaseStatus.FAILED, CTestCaseStatus.ERROR]:
|
||||||
|
sys.exit(1)
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = ArgumentParser("unittest", description="Run unit tests")
|
||||||
|
parser.add_argument("path", nargs='+', help="path to the test directory or file", default="./test_*")
|
||||||
|
parser.add_argument("-V", "--version", action="version", version=__version__)
|
||||||
|
parser.add_argument("-v", "--verbose", action="store_true", help="verbose output")
|
||||||
|
parser.add_argument("-s", "--no-capture", action="store_false", help="capture stdout and stderr")
|
||||||
|
|
||||||
|
namespace = parser.parse_args()
|
||||||
|
|
||||||
|
print_separator_ex("=", "test session starts", "")
|
||||||
|
print(f"platform: {sys.platform} -- Python {sys.version.split(' ')[0]}, c_unittest {__version__}")
|
||||||
|
print(f"rootdir: {os.getcwd()}")
|
||||||
|
|
||||||
|
files: List[CTestCaseFile] = []
|
||||||
|
total = 0
|
||||||
|
error_files = []
|
||||||
|
start_time = time()
|
||||||
|
|
||||||
|
paths = []
|
||||||
|
for p in namespace.path:
|
||||||
|
if '*' in p:
|
||||||
|
paths.extend(glob(p, recursive=True))
|
||||||
|
else:
|
||||||
|
paths.append(p)
|
||||||
|
for p in paths:
|
||||||
|
f = CTestCaseFile(p)
|
||||||
|
total += f.collect()
|
||||||
|
if f.error:
|
||||||
|
error_files.append(f)
|
||||||
|
else:
|
||||||
|
files.append(f)
|
||||||
|
|
||||||
|
if error_files:
|
||||||
|
print(f"collected {total} items / {len(error_files)} error\n")
|
||||||
|
report_collect_error(start_time, *error_files)
|
||||||
|
else:
|
||||||
|
print(f"collected {total} items\n")
|
||||||
|
|
||||||
|
if total == 0:
|
||||||
|
report_no_ran(start_time)
|
||||||
|
|
||||||
|
counter = CTestCaseCounter()
|
||||||
|
for f in files:
|
||||||
|
counter += f.run(verbose=namespace.verbose, capture=namespace.no_capture)
|
||||||
|
|
||||||
|
report(start_time, counter, show_capture=namespace.no_capture)
|
|
@ -0,0 +1,16 @@
|
||||||
|
width=$(stty size | awk '{print $2}')
|
||||||
|
# run add test_* in bin/*
|
||||||
|
for i in `ls bin/test_*`
|
||||||
|
do
|
||||||
|
echo
|
||||||
|
printf '%*s\n' "$width" '' | tr ' ' '*'
|
||||||
|
|
||||||
|
echo run test file: $i
|
||||||
|
$i $@
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "\033[0m\033[1;31mtest $i failed\033[0m"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
# printf '%*s\n' "$width" '' | tr ' ' '*'
|
|
@ -0,0 +1,327 @@
|
||||||
|
// #define COM_FRAME_DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "comframe.h"
|
||||||
|
#include "telemetry.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//int get_com_tty_id(const char* path, unsigned int baudRate) {
|
||||||
|
// int tty_id = open((const char*)path, O_RDWR | O_NOCTTY);
|
||||||
|
// if (tty_id < 0)
|
||||||
|
// {
|
||||||
|
// PrintFilePos(); fprintf(stderr, "...error open tty failed: %s @%s:%d\n", strerror(errno), __FILE__, __LINE__);
|
||||||
|
// exit(__LINE__);
|
||||||
|
// }
|
||||||
|
// init_tty(tty_id, baudRate);
|
||||||
|
// PrintFilePos(); printf("COM '%s' is ready!\n", path);
|
||||||
|
// return tty_id;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void init_tty(int tty_id, unsigned int baudRate) {
|
||||||
|
// struct termios options, old;
|
||||||
|
// // deploy usart par
|
||||||
|
// memset(&options, 0, sizeof(options));
|
||||||
|
// int ret = tcgetattr(tty_id, &old);
|
||||||
|
// if (ret != 0)
|
||||||
|
// {
|
||||||
|
// PrintFilePos(); fprintf(stderr, "...error tcgetattr() failed: %s\n @%s:%d", strerror(errno), __FILE__, __LINE__);
|
||||||
|
// exit(__LINE__);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// tcflush(tty_id, TCIOFLUSH);
|
||||||
|
//
|
||||||
|
// switch (baudRate) {
|
||||||
|
// case 9600:
|
||||||
|
// cfsetispeed(&options, B9600);
|
||||||
|
// cfsetospeed(&options, B9600);
|
||||||
|
// break;
|
||||||
|
// case 19200:
|
||||||
|
// cfsetispeed(&options, B19200);
|
||||||
|
// cfsetospeed(&options, B19200);
|
||||||
|
// break;
|
||||||
|
// case 38400:
|
||||||
|
// cfsetispeed(&options, B38400);
|
||||||
|
// cfsetospeed(&options, B38400);
|
||||||
|
// break;
|
||||||
|
// case 57600:
|
||||||
|
// cfsetispeed(&options, B57600);
|
||||||
|
// cfsetospeed(&options, B57600);
|
||||||
|
// break;
|
||||||
|
// case 115200:
|
||||||
|
// cfsetispeed(&options, B115200);
|
||||||
|
// cfsetospeed(&options, B115200);
|
||||||
|
// break;
|
||||||
|
// case 576000:
|
||||||
|
// cfsetispeed(&options, B576000);
|
||||||
|
// cfsetospeed(&options, B576000);
|
||||||
|
// break;
|
||||||
|
// case 921600:
|
||||||
|
// cfsetispeed(&options, B921600);
|
||||||
|
// cfsetospeed(&options, B921600);
|
||||||
|
// break;
|
||||||
|
// case 2000000:
|
||||||
|
// cfsetispeed(&options, B2000000);
|
||||||
|
// cfsetospeed(&options, B2000000);
|
||||||
|
// break;
|
||||||
|
// case 3000000:
|
||||||
|
// cfsetispeed(&options, B3000000);
|
||||||
|
// cfsetospeed(&options, B3000000);
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// PrintFilePos(); printf("****Error: baud rate %u too low!\n", baudRate);
|
||||||
|
// exit(__LINE__);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// switch (1)
|
||||||
|
// {
|
||||||
|
// case 0:
|
||||||
|
// options.c_cflag &= ~PARENB;
|
||||||
|
// options.c_cflag &= ~INPCK;
|
||||||
|
// break;
|
||||||
|
// case 1:
|
||||||
|
// options.c_cflag |= (PARODD //使用奇校验代替偶校验
|
||||||
|
// | PARENB);//校验位有效
|
||||||
|
// options.c_iflag |= INPCK; //校验有效
|
||||||
|
// break;
|
||||||
|
// case 2:
|
||||||
|
// options.c_cflag |= PARENB;
|
||||||
|
// options.c_cflag &= ~PARODD;
|
||||||
|
// options.c_iflag |= INPCK;
|
||||||
|
// break;
|
||||||
|
// case 3:
|
||||||
|
// options.c_cflag &= ~PARENB;
|
||||||
|
// options.c_cflag &= ~CSTOPB;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// options.c_cflag &= ~PARENB;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// options.c_cflag |= (CLOCAL | CREAD);
|
||||||
|
// options.c_cflag &= ~CSIZE;
|
||||||
|
// options.c_cflag &= ~CRTSCTS;
|
||||||
|
// options.c_cflag |= CS8;
|
||||||
|
// options.c_cflag &= ~CSTOPB;
|
||||||
|
// options.c_oflag = 0;
|
||||||
|
// options.c_lflag = 0;
|
||||||
|
// options.c_cc[VTIME] = 0;
|
||||||
|
// options.c_cc[VMIN] = 0;
|
||||||
|
// // 启用输出的XON/XOFF控制字符
|
||||||
|
// // Enable software flow control (XON/XOFF) for both input and output
|
||||||
|
// options.c_iflag |= (IXON | IXOFF); // Enable input and output XON/XOFF control characters
|
||||||
|
// options.c_oflag |= (IXON | IXOFF); // Enable input and output XON/XOFF control characters
|
||||||
|
// tcflush(tty_id, TCIFLUSH);
|
||||||
|
//
|
||||||
|
// if ((tcsetattr(tty_id, TCSANOW, &options)) != 0)
|
||||||
|
// {
|
||||||
|
// PrintFilePos(); fprintf(stderr, "...error tcsetattr failed:%s\n", strerror(errno));
|
||||||
|
// exit(__LINE__);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
uint16_t ComFramePayload_EvalChecksum(const struct ComFrameHeader* header, const void* payload) {
|
||||||
|
size_t length = ComFrame_PAYLOAD_LENGTH(header);
|
||||||
|
const uint16_t* buf = (const uint16_t*)payload;
|
||||||
|
uint16_t sum = 0;
|
||||||
|
while (length > 1)
|
||||||
|
{
|
||||||
|
sum ^= *(buf++);
|
||||||
|
length -= 2;
|
||||||
|
}
|
||||||
|
if (length == 1) {
|
||||||
|
sum ^= (COM_FRAME_PADDING_DATA << 8) + *((uint8_t*)buf);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComFramePayload_VerifyChecksum(const struct ComFrameHeader* header, const void* payload, uint16_t checksum) {
|
||||||
|
return ComFramePayload_EvalChecksum(header, (uint8_t*)payload) != checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComFrame* ComFrame_FromHeaderEx(const struct ComFrameHeader* header, const void* payload, uint16_t checksum, const bool swap_endian) {
|
||||||
|
uint16_t length = ComFrame_PAYLOAD_LENGTH(header);
|
||||||
|
ComFrame* frame = ComFrame_NewUninited(length);
|
||||||
|
if (frame == NULL)
|
||||||
|
return NULL;
|
||||||
|
memcpy(&frame->header, header, sizeof(struct ComFrameHeader));
|
||||||
|
if (swap_endian) {
|
||||||
|
ComFrameHeader_SwapEndian(ComFrame_HEADER(frame));
|
||||||
|
}
|
||||||
|
ComFrame_UpdatePayload(frame, payload, length, swap_endian);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComFrame* ComFrame_FromHeader(const struct ComFrameHeader* header, const void* payload, const bool swap_endian) {
|
||||||
|
uint16_t checksum = ComFramePayload_EvalChecksum(header, payload);
|
||||||
|
ComFrame* frame = ComFrame_FromHeaderEx(header, payload, checksum, swap_endian);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComFrame* ComFrame_New(uint16_t address, uint16_t type, const void* payload, uint16_t payload_length, const bool swap_endian) {
|
||||||
|
ComFrame* frame = ComFrame_NewUninited(payload_length);
|
||||||
|
ComFrameHeader_Init(ComFrame_HEADER(frame), address, type, 0);
|
||||||
|
if (swap_endian) {
|
||||||
|
ComFrameHeader_SwapEndian(ComFrame_HEADER(frame));
|
||||||
|
}
|
||||||
|
ComFrame_UpdatePayload(frame, payload, payload_length, swap_endian);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComFrame_UpdatePayload(ComFrame* frame, const void* payload, const uint16_t payload_length, const bool swap_endian) {
|
||||||
|
if (payload)
|
||||||
|
memcpy(&frame->payload, payload, payload_length);
|
||||||
|
if (payload_length & 1) {
|
||||||
|
frame->payload[payload_length] = COM_FRAME_PADDING_DATA;
|
||||||
|
}
|
||||||
|
ComFrame_HEADER(frame)->length = payload_length + 1;
|
||||||
|
uint16_t checksum = ComFramePayload_EvalChecksum(ComFrame_HEADER(frame), &frame->payload);
|
||||||
|
memcpy((uint8_t*)(&frame->payload) + ComFrame_PAYLOAD_ALIGNED_LENGTH(frame), &checksum, sizeof(uint16_t));
|
||||||
|
if (swap_endian) {
|
||||||
|
ComFrame_HEADER(frame)->length = byteswaps(ComFrame_HEADER(frame)->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComFrame_Verify(const ComFrame* frame, const bool swap_endian) {
|
||||||
|
struct ComFrameHeader header;
|
||||||
|
if (swap_endian) {
|
||||||
|
memcpy(&header, frame, sizeof(ComFrameHeader));
|
||||||
|
ComFrameHeader_SwapEndian(&header);
|
||||||
|
}
|
||||||
|
uint16_t checksum = ComFrame_Checksum(frame, swap_endian);
|
||||||
|
return ComFramePayload_VerifyChecksum((swap_endian) ? &header : ComFrame_HEADER(frame), frame->payload, checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ComFrame_Send(int tty_id, const ComFrame* frame, const bool swap_endian) {
|
||||||
|
uint32_t length = ComFrame_Length(frame, swap_endian);
|
||||||
|
char* buf = (char*)frame;
|
||||||
|
#ifdef COM_FRAME_DEBUG
|
||||||
|
PrintFilePos(); printf("send length: %d\n", ComFrame_Length(frame, swap_endian));
|
||||||
|
PrintFilePos(); printf("send checksum: %04x\n", ComFrame_Checksum(frame, swap_endian));
|
||||||
|
#endif
|
||||||
|
while (length > 0) {
|
||||||
|
ssize_t written = write(tty_id, buf, length);
|
||||||
|
if (written < 0) return written;
|
||||||
|
length -= written;
|
||||||
|
buf += written;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SendTelemetryErrorMsg(int tty_id, uint16_t address, uint16_t code, const bool swap_endian) {
|
||||||
|
ComFrame* f_error = NewTelemetryErrorMsg(address, code, true);
|
||||||
|
ssize_t wr = ComFrame_Send(tty_id, f_error, swap_endian);
|
||||||
|
ComFrame_Del(f_error);
|
||||||
|
return wr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COM_FRAME_RECEIVE_PRED_SIZE (2 * sizeof(ComFrameHeader))
|
||||||
|
|
||||||
|
ComFrame* ComFrame_ReceiveEx(int tty_id, void* buffer, const size_t buffer_size, size_t* p_offset, size_t* p_cached_size, bool* p_run_flag, const bool swap_endian) {
|
||||||
|
bool find_head = false;
|
||||||
|
ComFrame* frame = NULL;
|
||||||
|
ssize_t recv_size;
|
||||||
|
size_t pred_size = COM_FRAME_RECEIVE_PRED_SIZE; // min buffer size to keep,
|
||||||
|
size_t offset = (p_offset) ? *p_offset : 0; // scanned data size
|
||||||
|
size_t cached_size = (p_cached_size) ? *p_cached_size : 0; // read data size
|
||||||
|
assert(buffer_size >= pred_size);
|
||||||
|
|
||||||
|
if (buffer == NULL) {
|
||||||
|
buffer = (uint8_t*)malloc(buffer_size);
|
||||||
|
}
|
||||||
|
bool _keep_run = true;
|
||||||
|
if (p_run_flag == NULL) {
|
||||||
|
p_run_flag = &_keep_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the cache when the remaining length of the cache is less than 2 times the frame length or find the header
|
||||||
|
if (offset && buffer_size - cached_size < pred_size) {
|
||||||
|
cached_size -= offset;
|
||||||
|
memmove(buffer, ((uint8_t*)buffer)+offset, cached_size);
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*p_run_flag) {
|
||||||
|
recv_size = read(tty_id, ((uint8_t*)buffer) + cached_size, buffer_size - cached_size);
|
||||||
|
if (recv_size <= 0 && cached_size == offset) {
|
||||||
|
usleep(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef COM_FRAME_DEBUG
|
||||||
|
PrintFilePos(); printf(
|
||||||
|
"receive com data (received=%zd,cached=%zu,number=%04x)\n",
|
||||||
|
recv_size, cached_size, ComFrame_HEADER(buffer)->magic_number
|
||||||
|
);
|
||||||
|
PrintFilePos(); printf("buffer: ");
|
||||||
|
for (size_t i = 0; i < cached_size + recv_size; ++i) {
|
||||||
|
PrintFilePos(); printf("%02x", ((uint8_t*)buffer)[i]);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
#endif
|
||||||
|
cached_size += recv_size;
|
||||||
|
|
||||||
|
if (!find_head) {
|
||||||
|
// update offset to scan the header
|
||||||
|
for (; offset + sizeof(ComFrameHeader) < cached_size; ++offset) {
|
||||||
|
find_head = !ComFrameHeader_Check(ComFrame_HEADER(((uint8_t*)buffer) + offset), swap_endian);
|
||||||
|
if (find_head) {
|
||||||
|
if (swap_endian)
|
||||||
|
ComFrameHeader_SwapEndian(ComFrame_HEADER(((uint8_t*)buffer) + offset));
|
||||||
|
#ifdef COM_FRAME_DEBUG
|
||||||
|
PrintFilePos(); printf("find valid data (length=%u)\n", ComFrame_LENGTH(((uint8_t*)buffer)+offset));
|
||||||
|
#endif
|
||||||
|
pred_size = ComFrame_LENGTH(((uint8_t*)buffer) + offset);
|
||||||
|
if (pred_size > buffer_size) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "data size is too large (%zu)\n", pred_size);
|
||||||
|
find_head = false;
|
||||||
|
pred_size = COM_FRAME_RECEIVE_PRED_SIZE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the cache when the remaining length of the cache is less than 2 times the frame length or find the header
|
||||||
|
if (offset && buffer_size - cached_size < pred_size) {
|
||||||
|
cached_size -= offset;
|
||||||
|
memmove(buffer, ((uint8_t*)buffer)+offset, cached_size);
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_head && cached_size >= pred_size + offset) {
|
||||||
|
// all data received
|
||||||
|
frame = (ComFrame*)((uint8_t*)buffer + offset);
|
||||||
|
offset += pred_size; // update offset for next run
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (p_offset)
|
||||||
|
*p_offset = offset;
|
||||||
|
if (p_cached_size)
|
||||||
|
*p_cached_size = cached_size;
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComFrame* ComFrame_Receive(int tty_id, const size_t buffer_size, const bool swap_endian) {
|
||||||
|
size_t offset = 0;
|
||||||
|
auto raw_frame = ComFrame_ReceiveEx(tty_id, NULL, buffer_size, &offset, NULL, NULL, swap_endian);
|
||||||
|
// correct the offset
|
||||||
|
offset -= ComFrame_LENGTH(raw_frame);
|
||||||
|
auto frame = (ComFrame*)(((char*)raw_frame) - offset);
|
||||||
|
// move the data to the buffer head, so that the data can be free safely
|
||||||
|
if (offset) {
|
||||||
|
memmove(frame, raw_frame, ComFrame_LENGTH(raw_frame));
|
||||||
|
}
|
||||||
|
return frame;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
#include "event.h"
|
||||||
|
#include "dataqueue.hpp"
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<event_callback, void*>>> _events;
|
||||||
|
bool _event_thread_running = false;
|
||||||
|
DataQueue<std::tuple<const char*, event_callback, void*, void*>> _event_queue;
|
||||||
|
|
||||||
|
void sys_event(const char *event_name, void *args) {
|
||||||
|
auto it = _events.find(event_name);
|
||||||
|
if (it != _events.end()) {
|
||||||
|
for (auto &pair : it->second) {
|
||||||
|
pair.first(event_name, args, pair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_event_register(const char *event_name, event_callback callback, void* user_data) {
|
||||||
|
_events[event_name].push_back(std::make_pair(callback, user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_event_unregister(const char *event_name, event_callback callback) {
|
||||||
|
auto it = _events.find(event_name);
|
||||||
|
if (it != _events.end()) {
|
||||||
|
for (auto it2 = it->second.begin(); it2 != it->second.end(); it2++) {
|
||||||
|
if (it2->first == callback) {
|
||||||
|
it->second.erase(it2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* sys_event_thread(void*) {
|
||||||
|
_event_thread_running = true;
|
||||||
|
while (_event_thread_running) {
|
||||||
|
auto [event_name, callback, args, user_data] = _event_queue.Pop();
|
||||||
|
callback(event_name, args, user_data);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "extern_interface.h"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,807 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <list>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include "telemetry.h"
|
||||||
|
#include "dataqueue.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
extern bool g_bKeepSysRuning;
|
||||||
|
void play_text(char* pTextStr, int iRepeat_times);
|
||||||
|
|
||||||
|
// int32_t g_iExternTimeDifference = 0;
|
||||||
|
static TelemetryCommandInfo g_receiveCommandInfo;
|
||||||
|
static std::list<TelemetryCommandInfo> g_sendCommandList;
|
||||||
|
static void* g_pRcvCmdQueue = NULL;
|
||||||
|
|
||||||
|
volatile static uint8_t g_iUpperHostTelemetryCount = 0;
|
||||||
|
volatile static uint8_t g_iTelemetryCount = 0;
|
||||||
|
// volatile static uint8_t telemetry_3package_loop_count[2] = {0, 0}; // added by gejp
|
||||||
|
// volatile static uint8_t telemetry_3package_count[2] = {0, 0}; // added by gejp
|
||||||
|
volatile bool need_resend = false;
|
||||||
|
volatile bool g_bNeedReboot = false;
|
||||||
|
volatile int32_t g_iMS2Reboot = 1000;
|
||||||
|
|
||||||
|
/* create a msg data for upper host telemetry*/
|
||||||
|
void set_telemetry_host_data(TelemetryData4UpperHost* pTelemetryData) {
|
||||||
|
pTelemetryData->work_status = 0xAA;
|
||||||
|
pTelemetryData->com_status = 0xAA;
|
||||||
|
pTelemetryData->coprocessor1_status = 0xAA;
|
||||||
|
pTelemetryData->coprocessor2_status = 0xAA;
|
||||||
|
pTelemetryData->voice_circuit_status = 0xAA;
|
||||||
|
pTelemetryData->telemetry_count = g_iUpperHostTelemetryCount++;
|
||||||
|
if (g_bCloseASR) {
|
||||||
|
pTelemetryData->voice_mode = 0xAA;
|
||||||
|
}
|
||||||
|
else if (g_iSysState == SYS_STATUS_WAKE) {
|
||||||
|
pTelemetryData->voice_mode = 0x55;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pTelemetryData->voice_mode = 0xA5;
|
||||||
|
}
|
||||||
|
if (g_iSysState == SYS_STATUS_WAKE) {
|
||||||
|
pTelemetryData->recognition_status = 0x55;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pTelemetryData->recognition_status = 0xAA;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
pTelemetryData->recognition_info[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTelemetryData->particle_detection1 = 0xAA;
|
||||||
|
pTelemetryData->particle_detection2 = 0xAA;
|
||||||
|
pTelemetryData->particle_detection3 = 0xAA;
|
||||||
|
|
||||||
|
memcpy(&pTelemetryData->receive_command, &g_receiveCommandInfo, sizeof(TelemetryCommandInfo));
|
||||||
|
|
||||||
|
if (g_sendCommandList.empty()) {
|
||||||
|
memset(&pTelemetryData->send_command, 0x00, sizeof(TelemetryCommandInfo));
|
||||||
|
} else {
|
||||||
|
memcpy(&pTelemetryData->send_command, &g_sendCommandList.front(), sizeof(TelemetrySendCommandInfo));
|
||||||
|
}
|
||||||
|
//if (g_bVolumeKeyState) {
|
||||||
|
// pTelemetryData->volume_key_status = 0xAA;
|
||||||
|
//}
|
||||||
|
//else {
|
||||||
|
// pTelemetryData->volume_key_status = 0x55;
|
||||||
|
//}
|
||||||
|
//if (g_bWakeupKeyState) {
|
||||||
|
// pTelemetryData->wake_key_status = 0xAA;
|
||||||
|
//}
|
||||||
|
//else {
|
||||||
|
// pTelemetryData->wake_key_status = 0x55;
|
||||||
|
//}
|
||||||
|
//pTelemetryData->volume_key_status = g_bVolumeKeyState ? 0xAA : 0x55;
|
||||||
|
//pTelemetryData->wake_key_status = g_bWakeupKeyState ? 0xAA : 0x55;
|
||||||
|
pTelemetryData->volume_key_status = g_bVolumeKeyPressed ? 0xAA : 0x55;
|
||||||
|
pTelemetryData->wake_key_status = g_bWakeupKeyPressed ? 0xAA : 0x55;
|
||||||
|
g_bVolumeKeyPressed = false;
|
||||||
|
g_bWakeupKeyPressed = false;
|
||||||
|
|
||||||
|
pTelemetryData->key_status_backup = 0x55;
|
||||||
|
if ( g_iCurVolumeGrade == g_iVolumeGradeCnt-1 ) {//large
|
||||||
|
pTelemetryData->current_volume = 0x3;
|
||||||
|
}
|
||||||
|
else if ( g_iCurVolumeGrade == 0 ) {//small
|
||||||
|
pTelemetryData->current_volume = 0x1;
|
||||||
|
}
|
||||||
|
else {//midium
|
||||||
|
pTelemetryData->current_volume = 0x2;
|
||||||
|
}
|
||||||
|
pTelemetryData->system_version_high = g_iSysVerHigh;
|
||||||
|
pTelemetryData->system_version_low = g_iSysVerLow;
|
||||||
|
pTelemetryData->application_version_high = g_iAppVerHigh;
|
||||||
|
pTelemetryData->application_version_low = g_iAppVerLow;
|
||||||
|
// 2024.10.10
|
||||||
|
if (g_iEnableAlarmCode == 0) {
|
||||||
|
pTelemetryData->alarm_code[0] = 0xAA;
|
||||||
|
pTelemetryData->alarm_code[1] = 0xAA;
|
||||||
|
pTelemetryData->alarm_code[2] = 0xAA;
|
||||||
|
pTelemetryData->alarm_code[3] = 0xAA;
|
||||||
|
} else {
|
||||||
|
pTelemetryData->alarm_code[0] = g_iAlarmCode[0];
|
||||||
|
pTelemetryData->alarm_code[1] = g_iAlarmCode[1];
|
||||||
|
pTelemetryData->alarm_code[2] = g_iAlarmCode[2];
|
||||||
|
pTelemetryData->alarm_code[3] = g_iAlarmCode[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
pTelemetryData->telemetry_backup[i] = 0xAA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a telemetry msg data for telemetry, by gejp 2024.10.03 */
|
||||||
|
void set_telemetry_data(TelemetryData* pTelemetryHostData, TelemetryCommandInfo *pReceiveCommandInfo) {
|
||||||
|
pTelemetryHostData->work_status = 0xAA;
|
||||||
|
pTelemetryHostData->com_status = 0xAA;
|
||||||
|
pTelemetryHostData->coprocessor1_status = 0xAA;
|
||||||
|
pTelemetryHostData->coprocessor2_status = 0xAA;
|
||||||
|
pTelemetryHostData->voice_circuit_status = 0xAA;
|
||||||
|
pTelemetryHostData->telemetry_count = g_iTelemetryCount++;
|
||||||
|
|
||||||
|
if (g_bCloseASR) {
|
||||||
|
pTelemetryHostData->voice_mode = 0xAA;
|
||||||
|
}
|
||||||
|
else if (g_iSysState == SYS_STATUS_WAKE) {
|
||||||
|
pTelemetryHostData->voice_mode = 0x55;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pTelemetryHostData->voice_mode = 0xA5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_iSysState == SYS_STATUS_WAKE) {
|
||||||
|
pTelemetryHostData->recognition_status = 0x55;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pTelemetryHostData->recognition_status = 0xAA;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTelemetryHostData->particle_detection1 = 0xAA;
|
||||||
|
pTelemetryHostData->particle_detection2 = 0xAA;
|
||||||
|
pTelemetryHostData->particle_detection3 = 0xAA;
|
||||||
|
|
||||||
|
memcpy(&(pTelemetryHostData->receive_command), (void*)pReceiveCommandInfo, sizeof(TelemetryCommandInfo));
|
||||||
|
|
||||||
|
// above same as set_telemetry_host_data
|
||||||
|
|
||||||
|
// 5 cmd info in history
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto& send_cmd : g_sendCommandList) {
|
||||||
|
pTelemetryHostData->send_command[i].seqid = send_cmd.seqid & 0xFF;
|
||||||
|
pTelemetryHostData->send_command[i].flag = 0x66;
|
||||||
|
pTelemetryHostData->send_command[i].time = send_cmd.time;
|
||||||
|
memcpy(pTelemetryHostData->send_command[i].code, send_cmd.code, 2);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (; i < 5; i++) {
|
||||||
|
memset(pTelemetryHostData->send_command + i, 0x00, sizeof(TelemetrySendCommandInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following same as set_telemetry_host_data
|
||||||
|
pTelemetryHostData->volume_key_status = g_bVolumeKeyPressed ? 0xAA : 0x55;
|
||||||
|
pTelemetryHostData->wake_key_status = g_bWakeupKeyPressed ? 0xAA : 0x55;
|
||||||
|
g_bVolumeKeyPressed = false;
|
||||||
|
g_bWakeupKeyPressed = false;
|
||||||
|
|
||||||
|
pTelemetryHostData->key_status_backup = 0x55;
|
||||||
|
|
||||||
|
if (g_iCurVolumeGrade == g_iVolumeGradeCnt-1) {//Large
|
||||||
|
pTelemetryHostData->current_volume = 0x3;
|
||||||
|
}
|
||||||
|
else if (g_iCurVolumeGrade == 0) {//Small
|
||||||
|
pTelemetryHostData->current_volume = 0x1;
|
||||||
|
}
|
||||||
|
else {//Medium
|
||||||
|
pTelemetryHostData->current_volume = 0x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTelemetryHostData->system_version_high = g_iSysVerHigh;
|
||||||
|
pTelemetryHostData->system_version_low = g_iSysVerLow;
|
||||||
|
|
||||||
|
pTelemetryHostData->application_version_high = g_iAppVerHigh;
|
||||||
|
pTelemetryHostData->application_version_low = g_iAppVerLow;
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline bool is_command(uint8_t* array, uint8_t* value, int size) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (array[i] != value[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* telemetry_host_com_thread(void* path) {//Integrated Business Unit, telemetry_com综合业务单元,遥测口
|
||||||
|
int tty_id = g_iTelemetry_Com_tty_id; // TODO
|
||||||
|
const uint32_t buffer_size = 1024 * 100; // TODO
|
||||||
|
const uint16_t address = COM_FRAME_ADDRESS_VOIX; // TODO
|
||||||
|
size_t offset = 0, cached_size = 0;
|
||||||
|
uint8_t* buffer = new uint8_t[buffer_size];
|
||||||
|
uint8_t err_data[2];
|
||||||
|
uint64_t iTelemetryAnswerTimes = 0;
|
||||||
|
void* pDataBlock;
|
||||||
|
int iRet;
|
||||||
|
TelemetryCommandInfo TeleCmdInfo2Send;
|
||||||
|
TelemetryData TelemetryData2Send; // gejp 2024.10.03
|
||||||
|
|
||||||
|
memset(&TeleCmdInfo2Send, 0, sizeof(TelemetryCommandInfo));
|
||||||
|
|
||||||
|
while (g_bKeepSysRuning) {
|
||||||
|
|
||||||
|
// if ( (iTelemetryAnswerTimes % 3 == 0) && g_bNeedReboot) system("reboot");
|
||||||
|
ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepSysRuning, true);
|
||||||
|
//ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true);
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_CHECKSUM, true))
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry exception frame error: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ComFrame_HEADER(frame)->type != COM_FRAME_TYPE_TELEMETRY_REQUEST ||
|
||||||
|
ComFrame_PAYLOAD_LENGTH(frame) != 2 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (frame->payload[0] != 0xFF || frame->payload[1] != 0x11) {
|
||||||
|
if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_TYPE, true))
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry exception frame error: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iTelemetryAnswerTimes % 3 == 0 && g_pRcvCmdQueue != NULL) {
|
||||||
|
iRet = DeDataQueue(g_pRcvCmdQueue, &pDataBlock);
|
||||||
|
if (iRet < sizeof(TelemetryCommandInfo))
|
||||||
|
{//empty
|
||||||
|
if (0)//2024.11.04 g_bNeedReboot)
|
||||||
|
{
|
||||||
|
system("reboot");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
TeleCmdInfo2Send = *((TelemetryCommandInfo*)pDataBlock);
|
||||||
|
PrintFilePos(); printf("telemetry receive command (%d)\n", TeleCmdInfo2Send.seqid);
|
||||||
|
}
|
||||||
|
set_telemetry_data(&TelemetryData2Send, &TeleCmdInfo2Send);
|
||||||
|
}
|
||||||
|
|
||||||
|
//keep same every 3 answers, count from 0, 1, ...
|
||||||
|
TelemetryData2Send.send_count = iTelemetryAnswerTimes; //count from 0, 1, ..
|
||||||
|
iTelemetryAnswerTimes++;
|
||||||
|
|
||||||
|
ComFrame* pTeleAnswerMsg = ComFrame_New(address, COM_FRAME_TYPE_TELEMETRY_ANSWER, &TelemetryData2Send, sizeof(struct TelemetryData), true);
|
||||||
|
TelemetryData_SwapEndian((struct TelemetryData*)(pTeleAnswerMsg->payload));
|
||||||
|
|
||||||
|
if (ComFrame_Send(tty_id, pTeleAnswerMsg, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
// added by gejp start
|
||||||
|
// if (telemetry_3package_loop_count[0] == 0) {
|
||||||
|
// telemetry_3package_count[0] += 1;
|
||||||
|
// }
|
||||||
|
// telemetry_3package_loop_count[0] += 1;
|
||||||
|
// if (telemetry_3package_loop_count[0] == 3) {
|
||||||
|
// telemetry_3package_loop_count[0] = 0;
|
||||||
|
// }
|
||||||
|
// added by gejp end
|
||||||
|
ComFrame_Del(pTeleAnswerMsg);
|
||||||
|
//ComFrame_Del(frame);
|
||||||
|
//ComFrame_ReceiveFlushBuffer(ComFrame_LENGTH(frame), buffer, &cached_size);
|
||||||
|
}
|
||||||
|
delete [] buffer;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCallMode(bool bCall)
|
||||||
|
{
|
||||||
|
if (bCall)
|
||||||
|
{
|
||||||
|
PrintFilePos(); printf("Open call with upper host\n");
|
||||||
|
g_bCallMode = true;
|
||||||
|
g_iCallRcvFrameCnt = 0;
|
||||||
|
g_iPlayedCallFrameCnt = 0;
|
||||||
|
g_iOrdinaryPlayStop = 1;
|
||||||
|
g_bCloseASR = true;
|
||||||
|
g_iInsertSlientSegCnt=0;
|
||||||
|
|
||||||
|
g_iPcmBlockBytes = g_iCallBytesPerBlockMS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintFilePos(); printf("Close call with upper host\n");
|
||||||
|
g_bCallMode = false;
|
||||||
|
g_iPcmBlockBytes = 512 * g_iChannelCnt * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//获取指令文本与报警码
|
||||||
|
struct AlarmNotice {
|
||||||
|
uint32_t iAlarmCode; //指令编码,小端序
|
||||||
|
const char* pAlarmText;
|
||||||
|
};
|
||||||
|
AlarmNotice g_AlarmTable[] = {
|
||||||
|
{0x61006100, "热控,A回路,压力报警"},
|
||||||
|
{0x62006200, "热控,B回路,压力报警"},
|
||||||
|
{0x63006300, "热控分系统,参数异常"},
|
||||||
|
{0x64006400, "环控水箱满提醒"},
|
||||||
|
{0x65006500, "氮瓶压力过低报警"},
|
||||||
|
{0x66006600, "氧瓶压力过低报警"},
|
||||||
|
{0x67006700, "返回舱,火灾报警"},
|
||||||
|
{0x68006800, "返回舱,总压告警"},
|
||||||
|
{0x69006900, "返回舱,氧分压告警"},
|
||||||
|
{0x70007000, "返回舱,二氧化碳,分压告警"},
|
||||||
|
{0x71007100, "内回路泵,壁,转速报警"},
|
||||||
|
{0x72007200, "循环副风机转速报警"},
|
||||||
|
{0x73007300, "着陆器密封舱,总压报警"},
|
||||||
|
{0x74007400, "着陆器密封舱,氧分压报警"},
|
||||||
|
{0x75007500, "着陆器密封舱,二氧化碳分压报警"},
|
||||||
|
{0x76007600, "着陆器密封舱,火灾报警"},
|
||||||
|
{0x77007700, "着陆器辐射器,泄漏报警"},
|
||||||
|
{0x01000100, "起飞"},
|
||||||
|
{0x02000200, "船箭分离"},
|
||||||
|
{0x03000300, "组合体停靠"},
|
||||||
|
{0x04000400, "组合体分离"},
|
||||||
|
{0x05000500, "服返分离"},
|
||||||
|
{0x06000600, "回收开始"},
|
||||||
|
{0x07000700, "着陆"},
|
||||||
|
{0x08000800, "逃逸塔逃逸"},
|
||||||
|
{0x09000900, "预留"},
|
||||||
|
{0x0A000A00, "逃逸塔分离"},
|
||||||
|
{0x11001100, "整船逃逸"},
|
||||||
|
{0x71177117, "五分钟准备"},
|
||||||
|
{0x72177217, "一分钟准备"},
|
||||||
|
{0x73177317, "对接准备"},
|
||||||
|
{0x74177417, "对接环接触"},
|
||||||
|
{0x75177517, "分离完成"},
|
||||||
|
{0x76177617, "整流罩分离"},
|
||||||
|
{0x77177717, "帆板展开"},
|
||||||
|
{0x78177817, "船箭分离准备"},
|
||||||
|
{0x79177917, "帆板展开准备"},
|
||||||
|
{0x7A177A17, NULL}, // 预留
|
||||||
|
{0x7B177B17, "三十分钟后变轨"},
|
||||||
|
{0x7C177C17, "十分钟后变轨"},
|
||||||
|
{0x7D177D17, "五分钟后变轨"},
|
||||||
|
{0x7E177E17, "轨控发动机,开机指令发出"},
|
||||||
|
{0x7F177F17, "轨控发动机,关机指令发出"},
|
||||||
|
{0x80178017, "变轨结束"},
|
||||||
|
{0x81178117, "GNC转入自主控制模式"},
|
||||||
|
{0x82178217, "开始接近飞行"},
|
||||||
|
{0x83178317, "开始偏航调姿"},
|
||||||
|
{0x84178417, "偏航调姿完成"},
|
||||||
|
{0x85178517, "转平移,靠拢段"},
|
||||||
|
{0x86178617, "进入停泊点"},
|
||||||
|
{0x87178717, "开始接近飞行"},
|
||||||
|
{0x88178817, "开始俯仰调姿"},
|
||||||
|
{0x89178917, "俯仰调姿完成"},
|
||||||
|
{0x8A178A17, "最后靠拢飞行"},
|
||||||
|
{0x8B178B17, NULL}, //预留
|
||||||
|
{0x8C178C17, NULL}, //预留
|
||||||
|
{0x8D178D17, "转芬离,撤离段"},
|
||||||
|
{0x8E178E17, NULL}, // 预留
|
||||||
|
{0x8F178F17, "开始撤退飞行"},
|
||||||
|
{0x90179017, "转返回准备段"},
|
||||||
|
{0x91179117, "开始调姿"},
|
||||||
|
{0x92179217, NULL}, //预留
|
||||||
|
{0x93179317, NULL}, //预留
|
||||||
|
{0x94179417, NULL}, //预留
|
||||||
|
{0x95179517, "2分钟后服返分离"},
|
||||||
|
{0x96179617, NULL}, //预留
|
||||||
|
{0x97179717, NULL}, //预留
|
||||||
|
{0x98179817, NULL}, //预留
|
||||||
|
{0x99179917, "2分钟后回收启动"},
|
||||||
|
{0x9A179A17, "回收开关接通"},
|
||||||
|
{0x9B179B17, NULL}, //预留
|
||||||
|
{0x9C179C17, "着陆准备"},
|
||||||
|
{0x9D179D17, NULL}, //预留
|
||||||
|
{0x9E179E17, "三十分钟准备"},
|
||||||
|
{0x9F179F17, "制动发动机开机,指令发出"},
|
||||||
|
{0xA017A017, "制动发动机关机,指令发出"},
|
||||||
|
{0xA117A117, "逃逸转入值班"}
|
||||||
|
};
|
||||||
|
|
||||||
|
//获取指令文本与报警码
|
||||||
|
const char* GetAlarmTextByCode(uint8_t cmd_code[], uint8_t iAlarmCode[4])
|
||||||
|
{
|
||||||
|
uint32_t iCode = *(uint32_t*)cmd_code ;
|
||||||
|
uint32_t* pAlarmCode = (uint32_t*)iAlarmCode;
|
||||||
|
int n = sizeof(g_AlarmTable) / sizeof(struct AlarmNotice);
|
||||||
|
|
||||||
|
for (int i = 0; i<n; ++i) {
|
||||||
|
if (g_AlarmTable[i].iAlarmCode == iCode) {
|
||||||
|
*pAlarmCode = iCode;
|
||||||
|
return g_AlarmTable[i].pAlarmText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pAlarmCode = 0;
|
||||||
|
printf("0083: no fit code ");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----*/
|
||||||
|
void* upper_host_com_thread(void* arg) {//hand-control display processing unit 手控显示处理单元
|
||||||
|
int tty_id = g_iHostCom_tty_id;
|
||||||
|
const uint16_t address = COM_FRAME_ADDRESS_VOIX;
|
||||||
|
const uint32_t buffer_size = 1024 * 100; // TODO
|
||||||
|
const int64_t iHostAudioBufferSize = 1024 * 1024;
|
||||||
|
|
||||||
|
g_pRcvCmdQueue = OpenDataQueue(128, sizeof(struct TelemetryCommandInfo), true);
|
||||||
|
|
||||||
|
struct TTSInfo ttsInfo;
|
||||||
|
uint8_t* buffer = new uint8_t[buffer_size];
|
||||||
|
int64_t iEnqueueBytes;
|
||||||
|
bool bSucc;
|
||||||
|
char* pStrNotice;
|
||||||
|
AudioPlayInfo PlayInfo;
|
||||||
|
PlayInfo.m_iUrgent = 2;
|
||||||
|
//PlayInfo.m_iDataBytes = retLen;
|
||||||
|
PlayInfo.m_iSource = 0;
|
||||||
|
PlayInfo.m_iTimerValue = -1;
|
||||||
|
PlayInfo.m_iTimerID2Set = 0;
|
||||||
|
size_t offset = 0, cached_size = 0;
|
||||||
|
uint64_t iTelemetryAnswerTimes;
|
||||||
|
int16_t* ptrProcHostAudio = (int16_t*)malloc(iHostAudioBufferSize);
|
||||||
|
int16_t* ptrProcHostAudioEnd = ptrProcHostAudio;
|
||||||
|
int ProcHostAudioLengthMS = 1000;
|
||||||
|
int iProcHostAudioSampleCnt;
|
||||||
|
timeval tLastTime, tCurTime;
|
||||||
|
|
||||||
|
TelemetryData4UpperHost UpperHostTeleData;
|
||||||
|
|
||||||
|
while (g_bKeepSysRuning) {
|
||||||
|
|
||||||
|
ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, &offset, &cached_size, &g_bKeepSysRuning, true);
|
||||||
|
//ComFrame* frame = ComFrame_ReceiveEx(tty_id, buffer, buffer_size, true);
|
||||||
|
//PrintFilePos(); printf("%04X \n", ComFrame_HEADER(frame)->type);
|
||||||
|
switch (ComFrame_HEADER(frame)->type)
|
||||||
|
{
|
||||||
|
case COM_FRAME_TYPE_COMMAND:
|
||||||
|
{
|
||||||
|
//PrintFilePos(); printf("123\n");
|
||||||
|
|
||||||
|
// 2024.10.25 disable command frame verify
|
||||||
|
#ifdef USE_TELE_CTRL_CHECK_SUM
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
// //ComFrame_Del(frame);
|
||||||
|
// //ComFrame_ReceiveFlushBuffer(ComFrame_LENGTH(frame), buffer, &cached_size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ComFrame_PAYLOAD_LENGTH(frame) != 6) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
struct sysinfo info;
|
||||||
|
|
||||||
|
if (sysinfo(&info)) {
|
||||||
|
fprintf(stderr, "Failed to get sysinfo, errno:%u, reason:%s\n",errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t telemetryTimeSeconds = info.uptime + g_iExternTimeDifference;
|
||||||
|
|
||||||
|
g_receiveCommandInfo.seqid++;
|
||||||
|
g_receiveCommandInfo.code[0] = ComFrame_PAYLOAD(frame)[4];
|
||||||
|
g_receiveCommandInfo.code[1] = ComFrame_PAYLOAD(frame)[5];
|
||||||
|
g_receiveCommandInfo.time = telemetryTimeSeconds;
|
||||||
|
|
||||||
|
if (!g_bNeedReboot) {
|
||||||
|
int iRet = EnDataQueue(g_pRcvCmdQueue, &g_receiveCommandInfo, sizeof(TelemetryCommandInfo), NULL, 0, NULL, 0);
|
||||||
|
if (iRet < sizeof(TelemetryCommandInfo)) {
|
||||||
|
PrintFilePos(); printf("EnDataQueue failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-------START 2024.10.23 noted by zgb start
|
||||||
|
if (is_command(frame->payload, command_open_call, 6)) {
|
||||||
|
// ProcHostAudioLengthMS = 500;//first audio block at least 200ms
|
||||||
|
// gettimeofday(&tLastTime, 0);
|
||||||
|
// SetCallMode(true);
|
||||||
|
}
|
||||||
|
else if (is_command(frame->payload, command_close_call, 6)) {
|
||||||
|
// SetCallMode(false);
|
||||||
|
}
|
||||||
|
else if (is_command(frame->payload, command_open_asr, 6)) {
|
||||||
|
PrintFilePos(); printf("Open Asr\n");
|
||||||
|
setSysWake("host");
|
||||||
|
PrintFilePos(); printf("...wakeup by host\n");
|
||||||
|
g_bCloseASR = false;
|
||||||
|
SetCallMode(false); //g_bCall = false;
|
||||||
|
}
|
||||||
|
else if (is_command(frame->payload, command_close_asr, 6)) {
|
||||||
|
PrintFilePos(); printf("Close Asr\n");
|
||||||
|
setSysSleep("by host");
|
||||||
|
PrintFilePos(); printf("...sleep by host\n");
|
||||||
|
g_bCloseASR = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
//-------END 2024.10.23 noted by zgb
|
||||||
|
*/
|
||||||
|
if (is_command(frame->payload, command_wakeup, 6)) {
|
||||||
|
setSysWake("telemetry");
|
||||||
|
}
|
||||||
|
else if(is_command(frame->payload, command_sleep, 6)) {
|
||||||
|
setSysSleep("telemetry");
|
||||||
|
}
|
||||||
|
else if (is_command(frame->payload, command_volume, 6)) {
|
||||||
|
VolumeUpCycleFunc();
|
||||||
|
announce_state(0);
|
||||||
|
}
|
||||||
|
else if (is_command(frame->payload, command_reset, 6)) {
|
||||||
|
PrintFilePos(); printf("reboot flag set!\n");
|
||||||
|
#ifdef USE_TELEMETRY_REBOOT_CMD
|
||||||
|
g_bNeedReboot = true;// system("reboot");
|
||||||
|
if(strlen(g_strNoticeCmdText) > 1)
|
||||||
|
play_text(g_strNoticeCmdText, g_strNoticeCmdTextPlayTimes); // 播报相应内容
|
||||||
|
#else
|
||||||
|
if (strlen(g_strNoticeCmdText) > 1)
|
||||||
|
play_text(g_strNoticeCmdText, g_strNoticeCmdTextPlayTimes); // 播报相应内容
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_SPEECH_INJECTED:
|
||||||
|
{
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
//ComFrame_Del(frame);
|
||||||
|
//ComFrame_ReceiveFlushBuffer(ComFrame_LENGTH(frame), buffer, &cached_size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint8_t payload[6] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
|
||||||
|
ComFrame* f_data = ComFrame_New(
|
||||||
|
COM_FRAME_ADDRESS_VOIX,
|
||||||
|
COM_FRAME_TYPE_SPEECH_INJECTED,
|
||||||
|
payload, 6, true);
|
||||||
|
ttsInfo.m_iSource = 0;
|
||||||
|
ttsInfo.m_iDataBytes = ComFrame_PAYLOAD_LENGTH(frame);
|
||||||
|
ttsInfo.m_iTimerValue = -1;
|
||||||
|
g_iOrdinaryPlayStop = 1;
|
||||||
|
ttsInfo.m_iUrgent = 1;
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[TEXT_QUEUE_FOR_TTS_URGENT], (void*)(&ttsInfo), sizeof(ttsInfo),
|
||||||
|
(void*)(frame->payload), ComFrame_PAYLOAD_LENGTH(frame), NULL, 0);
|
||||||
|
if (iEnqueueBytes <= 0)
|
||||||
|
{
|
||||||
|
ProcQueueFull(TEXT_QUEUE_FOR_TTS_URGENT, true);
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[TEXT_QUEUE_FOR_TTS_URGENT], (void*)(&ttsInfo), sizeof(ttsInfo),
|
||||||
|
(void*)(frame->payload), ComFrame_PAYLOAD_LENGTH(frame), NULL, 0);
|
||||||
|
bSucc = false;
|
||||||
|
}
|
||||||
|
if (bSucc)
|
||||||
|
pStrNotice = "proc info-msg";
|
||||||
|
else
|
||||||
|
pStrNotice = "***Error: unknow info-msg ";
|
||||||
|
PrintFilePos(); WriteLog(g_pProcessLog, "%s from %s %s", pStrNotice, "upper-host", g_strCurTime);
|
||||||
|
|
||||||
|
if (ComFrame_Send(tty_id, f_data, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
ComFrame_Del(f_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_REQUEST:
|
||||||
|
{
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
need_resend = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_AUDIO:
|
||||||
|
{
|
||||||
|
//if (ComFrame_Verify(frame, false)) {
|
||||||
|
// PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
// //ComFrame_Del(frame);
|
||||||
|
// ComFrame_ReceiveFlushBuffer(ComFrame_LENGTH(frame), buffer, &cached_size);
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
|
gettimeofday(&tCurTime, 0);
|
||||||
|
int iIntervalTime = (tCurTime.tv_sec - tLastTime.tv_sec) * 1000 + (tCurTime.tv_usec - tLastTime.tv_usec) / 1000;
|
||||||
|
if( iIntervalTime > 15 )
|
||||||
|
PrintFilePos(); WriteLog(g_pProcessLog, " com frame interval %d ms %s\n", iIntervalTime, g_strCurTime);
|
||||||
|
tLastTime = tCurTime;
|
||||||
|
|
||||||
|
if (g_bCallMode) {
|
||||||
|
iProcHostAudioSampleCnt = proc_audio_upper_host((uint16_t*)(frame->payload), (uint16_t*)ptrProcHostAudioEnd, ComFrame_PAYLOAD_LENGTH(frame) / 2, false);
|
||||||
|
ptrProcHostAudioEnd += iProcHostAudioSampleCnt;
|
||||||
|
if (ptrProcHostAudioEnd - ptrProcHostAudio >= 16 * ProcHostAudioLengthMS) {
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[AUDIO_QUEUE_FOR_PLAY_URGENT], (void*)(&PlayInfo), sizeof(PlayInfo),
|
||||||
|
(void*)(ptrProcHostAudio), (ptrProcHostAudioEnd - ptrProcHostAudio) * 2, NULL, 0);// 16 * ProcHostAudioLengthMS * 2, NULL, 0);
|
||||||
|
if (iEnqueueBytes <= 0) {
|
||||||
|
ProcQueueFull(AUDIO_QUEUE_FOR_PLAY_URGENT, true);
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[AUDIO_QUEUE_FOR_PLAY_URGENT], (void*)(&PlayInfo), sizeof(PlayInfo),
|
||||||
|
(void*)(ptrProcHostAudio), (ptrProcHostAudioEnd - ptrProcHostAudio) * 2, NULL, 0);// 16 * ProcHostAudioLengthMS * 2, NULL, 0);
|
||||||
|
}
|
||||||
|
//memcpy(ptrProcHostAudio, ptrProcHostAudio + 16 * ProcHostAudioLengthMS, (ptrProcHostAudioEnd - ptrProcHostAudio - 16 * ProcHostAudioLengthMS) * 2);
|
||||||
|
ptrProcHostAudioEnd = ptrProcHostAudio;// ptrProcHostAudioEnd -= ptrProcHostAudio;
|
||||||
|
ProcHostAudioLengthMS = 500;//restore to 100ms
|
||||||
|
}
|
||||||
|
|
||||||
|
//iEnqueueBytes = EnDataQueue(g_pDataQueue[AUDIO_QUEUE_FOR_PLAY_URGENT], (void*)(&PlayInfo), sizeof(PlayInfo),
|
||||||
|
// (void*)(frame->payload), ComFrame_PAYLOAD_LENGTH(frame), NULL, 0);
|
||||||
|
//if (iEnqueueBytes <= 0) {
|
||||||
|
// ProcQueueFull(AUDIO_QUEUE_FOR_PLAY_URGENT, true);
|
||||||
|
// iEnqueueBytes = EnDataQueue(g_pDataQueue[AUDIO_QUEUE_FOR_PLAY_URGENT], (void*)(&PlayInfo), sizeof(PlayInfo),
|
||||||
|
// (void*)(frame->payload), ComFrame_PAYLOAD_LENGTH(frame), NULL, 0);
|
||||||
|
//}
|
||||||
|
//PrintFilePos(); printf("iProcHostAudioSampleCnt %d\n", iProcHostAudioSampleCnt);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_TELEMETRY_REQUEST:
|
||||||
|
{
|
||||||
|
if (g_iUseHostComForTelemetry != 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_CHECKSUM, true))
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry exception frame error: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (frame->payload[0] != 0xFF || frame->payload[1] != 0x11) {
|
||||||
|
if (SendTelemetryErrorMsg(tty_id, address, TELEMETRY_ERROR_TYPE, true))
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry exception frame error: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ComFrame_HEADER(frame)->type != COM_FRAME_TYPE_TELEMETRY_REQUEST ||
|
||||||
|
ComFrame_PAYLOAD_LENGTH(frame) != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_telemetry_host_data(&UpperHostTeleData); // count from 0, 1, ..
|
||||||
|
|
||||||
|
ComFrame* pUpperHostTeleAnswerMsg = NewTelemetryAnswerData(address, &UpperHostTeleData, true);
|
||||||
|
|
||||||
|
if (ComFrame_Send(tty_id, pUpperHostTeleAnswerMsg, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
// added by gejp start
|
||||||
|
// if (telemetry_3package_loop_count[1] == 0) {
|
||||||
|
// telemetry_3package_count[1] += 1;
|
||||||
|
// }
|
||||||
|
// telemetry_3package_loop_count[1] += 1;
|
||||||
|
// if (telemetry_3package_loop_count[1] == 3) {
|
||||||
|
// telemetry_3package_loop_count[1] = 0;
|
||||||
|
// }
|
||||||
|
// added by gejp end
|
||||||
|
ComFrame_Del(pUpperHostTeleAnswerMsg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_REQUEST: // gejp 2024.10.03
|
||||||
|
{
|
||||||
|
if (g_iEnableAlarmCode == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (frame->payload[0] != 0xAA || frame->payload[1] != 0x55) { // data error
|
||||||
|
// printf("alarm code: data error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int64_t iEnqueueBytes;
|
||||||
|
int iTextBytes;
|
||||||
|
const char *pNoticeStr;
|
||||||
|
|
||||||
|
ttsInfo.m_iSource = 0;
|
||||||
|
ttsInfo.m_iTimerValue = -1;
|
||||||
|
g_iOrdinaryPlayStop = 1;
|
||||||
|
ttsInfo.m_iUrgent = 1;
|
||||||
|
|
||||||
|
//语音通报与报警码
|
||||||
|
pNoticeStr = GetAlarmTextByCode(frame->payload+2, g_iAlarmCode);
|
||||||
|
if(!pNoticeStr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
iTextBytes = strlen(pNoticeStr) + 1;
|
||||||
|
ttsInfo.m_iDataBytes = iTextBytes;
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[TEXT_QUEUE_FOR_TTS_URGENT], (void*)(&ttsInfo), sizeof(ttsInfo),
|
||||||
|
(void*)pNoticeStr, iTextBytes, NULL, 0);
|
||||||
|
if (iEnqueueBytes <= 0) {//队列满,入队失败
|
||||||
|
ProcQueueFull(TEXT_QUEUE_FOR_TTS_URGENT, true);
|
||||||
|
iEnqueueBytes = EnDataQueue(g_pDataQueue[TEXT_QUEUE_FOR_TTS_URGENT], (void*)(&ttsInfo), sizeof(ttsInfo),
|
||||||
|
(void*)pNoticeStr, iTextBytes, NULL, 0);
|
||||||
|
}
|
||||||
|
uint8_t payload[6] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
|
||||||
|
ComFrame* f_data = ComFrame_New(
|
||||||
|
COM_FRAME_ADDRESS_VOIX,
|
||||||
|
COM_FRAME_TYPE_VOICE_ANNOUNCEMENT_AND_ALARM_CODE_RESPONSE,
|
||||||
|
payload, 6, true);
|
||||||
|
if (ComFrame_Send(tty_id, f_data, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
ComFrame_Del(f_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COM_FRAME_TYPE_GRANT_TIME: { // gejp 2024.10.03
|
||||||
|
if (ComFrame_Verify(frame, false)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "com frame checksum error\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->payload[0] != 0x66) { // data error
|
||||||
|
printf("grant time: data error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secondsAbs = *((int*)(frame->payload+1));
|
||||||
|
secondsAbs = byteswapl(secondsAbs);
|
||||||
|
|
||||||
|
struct sysinfo info;
|
||||||
|
|
||||||
|
if (sysinfo(&info)) {
|
||||||
|
fprintf(stderr, "Failed to get sysinfo, errno:%u, reason:%s\n",errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintFilePos(); printf("---> uptime changed\n");
|
||||||
|
PrintFilePos(); printf("old uptime: %d\n", info.uptime + g_iExternTimeDifference);
|
||||||
|
g_iExternTimeDifference = secondsAbs - info.uptime;
|
||||||
|
PrintFilePos(); printf("new uptime: %d\n", info.uptime + g_iExternTimeDifference);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
free(ptrProcHostAudio);
|
||||||
|
if (g_pRcvCmdQueue)
|
||||||
|
{
|
||||||
|
CloseDataQueue(g_pRcvCmdQueue);
|
||||||
|
g_pRcvCmdQueue = NULL;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_command_upper_host(int length, void* payload) {
|
||||||
|
int tty_id = g_iHostCom_tty_id;
|
||||||
|
need_resend = true;
|
||||||
|
int sendtime = 0;
|
||||||
|
ComFrame* f_data = ComFrame_New(
|
||||||
|
COM_FRAME_ADDRESS_VOIX,
|
||||||
|
COM_FRAME_TYPE_REQUEST,
|
||||||
|
payload, length, true);
|
||||||
|
uint64_t last_send_time;
|
||||||
|
while (need_resend) {
|
||||||
|
if (sendtime == 0) {
|
||||||
|
last_send_time = g_iSysTimerMilliSeconds;
|
||||||
|
|
||||||
|
if (ComFrame_Send(tty_id, f_data, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
sendtime += 1;
|
||||||
|
}
|
||||||
|
else if (sendtime == 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (g_iSysTimerMilliSeconds > last_send_time + 250) {
|
||||||
|
last_send_time = g_iSysTimerMilliSeconds;
|
||||||
|
|
||||||
|
if (ComFrame_Send(tty_id, f_data, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
sendtime += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
usleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComFrame_Del(f_data);
|
||||||
|
|
||||||
|
if (length != 6) return;
|
||||||
|
|
||||||
|
uint16_t send_seq = (g_sendCommandList.empty()) ? 0 : g_sendCommandList.front().seqid;
|
||||||
|
|
||||||
|
struct sysinfo info;
|
||||||
|
|
||||||
|
if (sysinfo(&info)) {
|
||||||
|
fprintf(stderr, "Failed to get sysinfo, errno:%u, reason:%s\n",errno, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t telemetryTimeSeconds = info.uptime + g_iExternTimeDifference;
|
||||||
|
|
||||||
|
TelemetryCommandInfo telemetryCommandInfo = {telemetryTimeSeconds, {((uint8_t*)payload)[3], ((uint8_t*)payload)[4]}, send_seq + 1};
|
||||||
|
g_sendCommandList.push_front(telemetryCommandInfo);
|
||||||
|
if (g_sendCommandList.size() > TELEMETRY_SEND_COMMAND_INFO_LENGTH) {
|
||||||
|
g_sendCommandList.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_audio_upper_host(int length, void* payload) {
|
||||||
|
int tty_id = g_iHostCom_tty_id;
|
||||||
|
ComFrame* f_data = ComFrame_New(
|
||||||
|
COM_FRAME_ADDRESS_VOIX,
|
||||||
|
COM_FRAME_TYPE_AUDIO,
|
||||||
|
payload, length, true);
|
||||||
|
if (ComFrame_Send(tty_id, f_data, true)) {
|
||||||
|
PrintFilePos(); fprintf(stderr, "send telemetry data frame error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
ComFrame_Del(f_data);
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
#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 <setjmp.h>
|
||||||
|
#include "c_testcase.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define TEST_CASE_STATUS_PASSED 0
|
||||||
|
#define TEST_CASE_STATUS_SKIPPED 32
|
||||||
|
#define TEST_CASE_STATUS_FAILED 16
|
||||||
|
#define TEST_CASE_STATUS_SETUP_FAILED 17
|
||||||
|
#define TEST_CASE_STATUS_TEARDOWN_FAILED 18
|
||||||
|
|
||||||
|
#define MAX_TESTCASE 64
|
||||||
|
|
||||||
|
struct TestCase {
|
||||||
|
const char* name;
|
||||||
|
test_case func;
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestCase test_cases[MAX_TESTCASE];
|
||||||
|
static int test_case_total = 0;
|
||||||
|
|
||||||
|
static interactive_func interactive = NULL;
|
||||||
|
static context_func setup = NULL;
|
||||||
|
static context_func teardown = NULL;
|
||||||
|
|
||||||
|
static atomic_bool testcase_running = false;
|
||||||
|
static jmp_buf testcase_env;
|
||||||
|
static int testcase_exit_code = 0;
|
||||||
|
|
||||||
|
int _add_test_case(const char* name, test_case func) {
|
||||||
|
if (test_case_total == MAX_TESTCASE) {
|
||||||
|
fprintf(stderr, "too many test case\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
TestCase* tc = &(test_cases[test_case_total++]);
|
||||||
|
tc->name = name;
|
||||||
|
tc->func = func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _set_interactive(interactive_func func) {
|
||||||
|
interactive = func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _set_setup(context_func func) {
|
||||||
|
setup = func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _set_teardown(context_func func) {
|
||||||
|
teardown = func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) test_case_abort(int exit_code) {
|
||||||
|
if (!testcase_running.load(std::memory_order_acquire)) {
|
||||||
|
exit(exit_code);
|
||||||
|
}
|
||||||
|
testcase_exit_code = exit_code;
|
||||||
|
longjmp(testcase_env, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline int get_tty_col(int fd) {
|
||||||
|
struct winsize size;
|
||||||
|
ioctl(fd, TIOCGWINSZ,&size);
|
||||||
|
return size.ws_col;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void print_separator(char lc) {
|
||||||
|
int size = get_tty_col(STDOUT_FILENO);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
putchar(lc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void print_separator_ex(char lc, const char* str, const char* color) {
|
||||||
|
int size = get_tty_col(STDOUT_FILENO);
|
||||||
|
int len = strlen(str);
|
||||||
|
printf("\033[0m%s", color); // 设置颜色
|
||||||
|
if(len > size) {
|
||||||
|
printf("%s\n", str);
|
||||||
|
} else {
|
||||||
|
int pad = (size - len - 2) / 2;
|
||||||
|
for(int i = 0; i < pad; i++) {
|
||||||
|
putchar(lc);
|
||||||
|
}
|
||||||
|
printf(" %s ", str);
|
||||||
|
for(int i = 0; i < pad; i++) {
|
||||||
|
putchar(lc);
|
||||||
|
}
|
||||||
|
if((size - len) % 2) putchar(lc);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
printf("\033[0m"); // 重置颜色
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_testcase() {
|
||||||
|
for (int i = 0; i < test_case_total; ++i) {
|
||||||
|
puts(test_cases[i].name);
|
||||||
|
putchar(' ');
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestCase* get_test_case(const char* name) {
|
||||||
|
TestCase* tc = NULL;
|
||||||
|
if (*name >= '0' && *name <= '9') {
|
||||||
|
int id = atoi(name);
|
||||||
|
if (id >= 0 && id < test_case_total) {
|
||||||
|
tc = &(test_cases[id]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < test_case_total; ++i) {
|
||||||
|
if (strcmp(test_cases[i].name, name) == 0) {
|
||||||
|
tc = &(test_cases[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run_test_case_func(test_case func) {
|
||||||
|
bool running = false;
|
||||||
|
if (!testcase_running.compare_exchange_strong(running, true, std::memory_order_acq_rel)) {
|
||||||
|
cerr << "test case is running" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (setjmp(testcase_env)) {
|
||||||
|
return testcase_exit_code;
|
||||||
|
}
|
||||||
|
int ret = func();
|
||||||
|
running = true;
|
||||||
|
if (!testcase_running.compare_exchange_strong(running, false, std::memory_order_acq_rel)) {
|
||||||
|
cerr << "test case is not running" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unittest_testcase(TestCase* tc) {
|
||||||
|
assert(tc != NULL);
|
||||||
|
if (setup && setup(tc->name)) {
|
||||||
|
return TEST_CASE_STATUS_SETUP_FAILED;
|
||||||
|
}
|
||||||
|
int ret = run_test_case_func(tc->func);
|
||||||
|
if (teardown && teardown(tc->name)) {
|
||||||
|
return TEST_CASE_STATUS_TEARDOWN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == SKIP_RET_NUMBER) {
|
||||||
|
return TEST_CASE_STATUS_SKIPPED;
|
||||||
|
} else if (ret != 0) {
|
||||||
|
return TEST_CASE_STATUS_FAILED;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char** argv) {
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
const char* arg = argv[i];
|
||||||
|
if (strcmp(arg, "-i") == 0 || strcmp(arg, "--interactive") == 0) {
|
||||||
|
if (interactive)
|
||||||
|
return interactive(argc, argv);
|
||||||
|
else {
|
||||||
|
cout << "interactive mode is not supported" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(arg, "-c") == 0 || strcmp(arg, "--collect") == 0) {
|
||||||
|
return collect_testcase();
|
||||||
|
}
|
||||||
|
else if (strcmp(arg, "-u") == 0 || strcmp(arg, "--unittest") == 0) {
|
||||||
|
const char* name = NULL;
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
name = argv[++i];
|
||||||
|
} else {
|
||||||
|
cout << "--unittest require an argument" << endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
TestCase* tc = get_test_case(name);
|
||||||
|
if (tc == NULL) {
|
||||||
|
cout << "test case " << name << " not found" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return unittest_testcase(tc);
|
||||||
|
} else {
|
||||||
|
if (interactive)
|
||||||
|
return interactive(argc, argv);
|
||||||
|
else {
|
||||||
|
cout << "unknown argument '" << arg << "'" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = test_case_total;
|
||||||
|
int passed = 0;
|
||||||
|
int failed = 0;
|
||||||
|
int skipped = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < total; ++i) {
|
||||||
|
print_separator('-');
|
||||||
|
TestCase* tc = &test_cases[i];
|
||||||
|
cout << "running " << tc->name << endl;
|
||||||
|
switch (unittest_testcase(tc)) {
|
||||||
|
case 0:
|
||||||
|
cout << "\033[0m\033[1;32mtest case \"" << tc->name << "\" passed\033[0m" << endl;
|
||||||
|
passed++;
|
||||||
|
break;
|
||||||
|
case TEST_CASE_STATUS_SKIPPED:
|
||||||
|
cout << "\033[0m\033[1;33mtest case \"" << tc->name << "\" skipped\033[0m" << endl;
|
||||||
|
skipped++;
|
||||||
|
break;
|
||||||
|
case TEST_CASE_STATUS_SETUP_FAILED:
|
||||||
|
cout << "\033[0m\033[1;31msetup \"" << tc->name << "\" failed\033[0m" << endl;
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
case TEST_CASE_STATUS_TEARDOWN_FAILED:
|
||||||
|
cout << "\033[0m\033[1;31mteardown \"" << tc->name << "\" failed\033[0m" << endl;
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cout << "\033[0m\033[1;31mtest case \"" << tc->name << "\" failed\033[0m" << endl;
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringstream ss;
|
||||||
|
ss << "total: " << total << ", passed: " << passed << ", failed: " << failed << ", skipped: " << skipped;
|
||||||
|
string sum = ss.str();
|
||||||
|
|
||||||
|
const char* color;
|
||||||
|
if (failed)
|
||||||
|
color = "\033[1;31m";
|
||||||
|
else if (skipped)
|
||||||
|
color = "\033[1;33m";
|
||||||
|
else
|
||||||
|
color = "\033[1;32m";
|
||||||
|
|
||||||
|
print_separator_ex('=', sum.c_str(), color);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue