V0.21.18.250613_alpha:数据监控的CSV文件注入功能完备
This commit is contained in:
parent
5b9bb35775
commit
e1b4139d04
Binary file not shown.
@ -273,7 +273,7 @@ protected:
|
|||||||
}
|
}
|
||||||
} else if constexpr (is_std_array_v<T>) {
|
} else if constexpr (is_std_array_v<T>) {
|
||||||
// 对于嵌套数组,递归处理
|
// 对于嵌套数组,递归处理
|
||||||
start_pos = setStdArrayFromString(data[i], value, start_pos + i);
|
start_pos = setStdArrayFromString(data[i], value, start_pos);
|
||||||
} else {
|
} else {
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_arithmetic_v<T> || is_std_array_v<T>,
|
std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||||
|
@ -273,7 +273,7 @@ protected:
|
|||||||
}
|
}
|
||||||
} else if constexpr (is_std_array_v<T>) {
|
} else if constexpr (is_std_array_v<T>) {
|
||||||
// 对于嵌套数组,递归处理
|
// 对于嵌套数组,递归处理
|
||||||
start_pos = setStdArrayFromString(data[i], value, start_pos + i);
|
start_pos = setStdArrayFromString(data[i], value, start_pos);
|
||||||
} else {
|
} else {
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_arithmetic_v<T> || is_std_array_v<T>,
|
std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||||
|
@ -11,49 +11,96 @@ CSVDataInjectThread::~CSVDataInjectThread()
|
|||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVDataInjectThread::Initialize(std::vector<std::string> structNames)
|
bool CSVDataInjectThread::Initialize(std::vector<InjectDataInfo> injectDataInfos)
|
||||||
{
|
{
|
||||||
m_csvFile.open(m_csvFilePath);
|
m_csvFile.open(m_csvFilePath);
|
||||||
if (!m_csvFile.is_open()) {
|
if (!m_csvFile.is_open()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_injectDataInfos = injectDataInfos;
|
||||||
|
|
||||||
std::string headerLine;
|
std::string headerLine;
|
||||||
if (!std::getline(m_csvFile, headerLine)) {
|
if (!std::getline(m_csvFile, headerLine)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> interfaceNames;
|
// 修改CSV头解析逻辑
|
||||||
std::stringstream ss(headerLine);
|
std::stringstream ss(headerLine);
|
||||||
std::string field;
|
std::string field;
|
||||||
std::getline(ss, field, ',');
|
std::getline(ss, field, ','); // 跳过第一列时间戳
|
||||||
|
|
||||||
|
// 使用getline读取所有字段,包括最后一个
|
||||||
while (std::getline(ss, field, ',')) {
|
while (std::getline(ss, field, ',')) {
|
||||||
interfaceNames.push_back(field);
|
// 去除字段前后的空白字符
|
||||||
|
field.erase(0, field.find_first_not_of(" \t\r\n"));
|
||||||
|
field.erase(field.find_last_not_of(" \t\r\n") + 1);
|
||||||
|
|
||||||
|
if (!field.empty()) {
|
||||||
|
parseHeaderField(field);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将结构体和接口名称一一对应
|
for (const auto &injectDataInfo : m_injectDataInfos) {
|
||||||
if (structNames.size() != interfaceNames.size()) {
|
auto dataMonitor = DataMonitorFactory::GetInstance(injectDataInfo.structName);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < structNames.size(); i++) {
|
|
||||||
m_structInterfaceMap[structNames[i]].push_back(interfaceNames[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &[structName, interfaceNames] : m_structInterfaceMap) {
|
|
||||||
auto dataMonitor = DataMonitorFactory::GetInstance(structName);
|
|
||||||
if (dataMonitor == nullptr) {
|
if (dataMonitor == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (dataMonitor->isInitialized()) {
|
if (dataMonitor->isInitialized()) {
|
||||||
m_alreadyStartedMonitors[structName] = dataMonitor;
|
m_alreadyStartedMonitors[injectDataInfo.structName] = dataMonitor;
|
||||||
} else {
|
} else {
|
||||||
m_notStartedMonitors[structName] = dataMonitor;
|
m_notStartedMonitors[injectDataInfo.structName] = dataMonitor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVDataInjectThread::parseHeaderField(const std::string &headerField)
|
||||||
|
{
|
||||||
|
CSVHeaderField csvHeaderField;
|
||||||
|
csvHeaderField.fieldName = headerField.substr(0, headerField.find('['));
|
||||||
|
csvHeaderField.arrayDim = 0;
|
||||||
|
csvHeaderField.arrayIndex1 = 0;
|
||||||
|
csvHeaderField.arrayIndex2 = 0;
|
||||||
|
|
||||||
|
if (headerField.find('[') != std::string::npos) {
|
||||||
|
// 处理一维数组
|
||||||
|
size_t firstBracketPos = headerField.find('[');
|
||||||
|
size_t firstBracketEndPos = headerField.find(']');
|
||||||
|
csvHeaderField.arrayIndex1 = std::stoi(
|
||||||
|
headerField.substr(firstBracketPos + 1, firstBracketEndPos - firstBracketPos - 1));
|
||||||
|
csvHeaderField.arrayDim = 1;
|
||||||
|
|
||||||
|
// 检查是否有第二个方括号,判断是否为二维数组
|
||||||
|
if (headerField.find('[', firstBracketEndPos) != std::string::npos) {
|
||||||
|
size_t secondBracketPos = headerField.find('[', firstBracketEndPos);
|
||||||
|
size_t secondBracketEndPos = headerField.find(']', secondBracketPos);
|
||||||
|
csvHeaderField.arrayIndex2 = std::stoi(headerField.substr(
|
||||||
|
secondBracketPos + 1, secondBracketEndPos - secondBracketPos - 1));
|
||||||
|
csvHeaderField.arrayDim = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &injectDataInfo : m_injectDataInfos) {
|
||||||
|
for (int i = 0; i < injectDataInfo.interfaceNames.size(); i++) {
|
||||||
|
if (injectDataInfo.interfaceNames[i] == csvHeaderField.fieldName) {
|
||||||
|
csvHeaderField.structName = injectDataInfo.structName;
|
||||||
|
if (injectDataInfo.arraySizes[i].second > 1) {
|
||||||
|
csvHeaderField.arraySize1 = injectDataInfo.arraySizes[i].first;
|
||||||
|
} else {
|
||||||
|
csvHeaderField.arraySize1 = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (csvHeaderField.structName.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_headerFields.push_back(csvHeaderField);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVDataInjectThread::start()
|
void CSVDataInjectThread::start()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
@ -107,14 +154,62 @@ void CSVDataInjectThread::updateData()
|
|||||||
double timeStamp = std::stod(field);
|
double timeStamp = std::stod(field);
|
||||||
m_nextExecuteTime = static_cast<int64_t>(timeStamp * 1000); // 转换为毫秒
|
m_nextExecuteTime = static_cast<int64_t>(timeStamp * 1000); // 转换为毫秒
|
||||||
|
|
||||||
// 解析每个结构体的数据
|
// 为每个结构体初始化数据
|
||||||
for (const auto &[structName, interfaceNames] : m_structInterfaceMap) {
|
std::unordered_map<std::string, std::unordered_map<std::string, std::vector<std::string>>>
|
||||||
std::unordered_map<std::string, std::string> dataMap;
|
tempDataMap;
|
||||||
for (const auto &interfaceName : interfaceNames) {
|
for (const auto &injectDataInfo : m_injectDataInfos) {
|
||||||
std::getline(ss, field, ',');
|
std::unordered_map<std::string, std::vector<std::string>> dataMap;
|
||||||
dataMap[interfaceName] = field;
|
for (int i = 0; i < injectDataInfo.interfaceNames.size(); i++) {
|
||||||
|
if (injectDataInfo.arraySizes[i].first > 1) {
|
||||||
|
for (int j = 0; j < injectDataInfo.arraySizes[i].first; j++) {
|
||||||
|
if (injectDataInfo.arraySizes[i].second > 1) {
|
||||||
|
for (int k = 0; k < injectDataInfo.arraySizes[i].second; k++) {
|
||||||
|
dataMap[injectDataInfo.interfaceNames[i]].push_back("0");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataMap[injectDataInfo.interfaceNames[i]].push_back("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataMap[injectDataInfo.interfaceNames[i]].push_back("0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_data[structName] = dataMap;
|
tempDataMap[injectDataInfo.structName] = dataMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取下一行数据
|
||||||
|
for (int i = 0; i < m_headerFields.size(); i++) {
|
||||||
|
std::getline(ss, field, ',');
|
||||||
|
if (m_headerFields[i].arrayDim == 0) {
|
||||||
|
tempDataMap[m_headerFields[i].structName][m_headerFields[i].fieldName][0] = field;
|
||||||
|
} else if (m_headerFields[i].arrayDim == 1) {
|
||||||
|
tempDataMap[m_headerFields[i].structName][m_headerFields[i].fieldName]
|
||||||
|
[m_headerFields[i].arrayIndex1] = field;
|
||||||
|
} else if (m_headerFields[i].arrayDim == 2) {
|
||||||
|
tempDataMap[m_headerFields[i].structName][m_headerFields[i].fieldName]
|
||||||
|
[m_headerFields[i].arrayIndex1 * m_headerFields[i].arraySize1
|
||||||
|
+ m_headerFields[i].arrayIndex2] = field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将tempDataMap转换为m_data格式
|
||||||
|
for (const auto &[structName, dataMap] : tempDataMap) {
|
||||||
|
std::unordered_map<std::string, std::string> structData;
|
||||||
|
for (const auto &[interfaceName, values] : dataMap) {
|
||||||
|
if (values.empty()) {
|
||||||
|
structData[interfaceName] = "0";
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
for (size_t i = 0; i < values.size(); ++i) {
|
||||||
|
ss << values[i];
|
||||||
|
if (i < values.size() - 1) {
|
||||||
|
ss << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
structData[interfaceName] = ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_data[structName] = structData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
~CSVDataInjectThread();
|
~CSVDataInjectThread();
|
||||||
|
|
||||||
bool Initialize(std::vector<std::string> structNames);
|
bool Initialize(std::vector<InjectDataInfo> injectDataInfos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 启动数据注入线程
|
* @brief 启动数据注入线程
|
||||||
@ -50,10 +50,13 @@ private:
|
|||||||
*/
|
*/
|
||||||
void threadFunc();
|
void threadFunc();
|
||||||
|
|
||||||
|
void parseHeaderField(const std::string &headerField);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_csvFilePath;
|
std::string m_csvFilePath;
|
||||||
std::ifstream m_csvFile;
|
std::ifstream m_csvFile;
|
||||||
std::unordered_map<std::string, std::vector<std::string>> m_structInterfaceMap;
|
std::vector<InjectDataInfo> m_injectDataInfos;
|
||||||
|
std::vector<CSVHeaderField> m_headerFields;
|
||||||
std::thread m_thread; ///< 数据注入线程
|
std::thread m_thread; ///< 数据注入线程
|
||||||
std::atomic<bool> m_running; ///< 线程运行标志
|
std::atomic<bool> m_running; ///< 线程运行标志
|
||||||
std::mutex m_mutex; ///< 互斥锁
|
std::mutex m_mutex; ///< 互斥锁
|
||||||
@ -65,6 +68,4 @@ private:
|
|||||||
std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
|
std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
|
||||||
m_data; ///< 要注入的数据
|
m_data; ///< 要注入的数据
|
||||||
std::atomic<int64_t> m_nextExecuteTime; ///< 下一次执行的时间点
|
std::atomic<int64_t> m_nextExecuteTime; ///< 下一次执行的时间点
|
||||||
};
|
};
|
||||||
|
|
||||||
using CSVDataInjectThreadPtr = std::shared_ptr<CSVDataInjectThread>;
|
|
@ -209,3 +209,51 @@ struct ModelDefinition {
|
|||||||
*/
|
*/
|
||||||
std::vector<std::shared_ptr<NamespaceDefinition>> namespaceDefinitions;
|
std::vector<std::shared_ptr<NamespaceDefinition>> namespaceDefinitions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct InjectDataInfo {
|
||||||
|
/**
|
||||||
|
* @brief 结构体名称
|
||||||
|
*/
|
||||||
|
std::string structName;
|
||||||
|
/**
|
||||||
|
* @brief 接口名称
|
||||||
|
*/
|
||||||
|
std::vector<std::string> interfaceNames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数组大小
|
||||||
|
*/
|
||||||
|
std::vector<std::pair<int, int>> arraySizes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CSVHeaderField {
|
||||||
|
/**
|
||||||
|
* @brief 字段名
|
||||||
|
*/
|
||||||
|
std::string fieldName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 结构体名称
|
||||||
|
*/
|
||||||
|
std::string structName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数组维度
|
||||||
|
*/
|
||||||
|
int arrayDim;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数组索引1
|
||||||
|
*/
|
||||||
|
int arrayIndex1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数组索引2
|
||||||
|
*/
|
||||||
|
int arrayIndex2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 一维数组大小
|
||||||
|
*/
|
||||||
|
int arraySize1;
|
||||||
|
};
|
@ -20,7 +20,7 @@ bool g_modelInfoMonitorStarted = false;
|
|||||||
SystemControl *systemControl = nullptr;
|
SystemControl *systemControl = nullptr;
|
||||||
bool g_systemControlStarted = false;
|
bool g_systemControlStarted = false;
|
||||||
|
|
||||||
CSVDataInjectThreadPtr g_csvDataInjectThread;
|
CSVDataInjectThread *g_csvDataInjectThread = nullptr;
|
||||||
|
|
||||||
// 初始化函数实现
|
// 初始化函数实现
|
||||||
int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int errorMsgSize)
|
int XN_Initialize(const char *domainId, int domainIdLen, char *errorMsg, int errorMsgSize)
|
||||||
@ -584,26 +584,40 @@ int XN_StopInjectContinuous(const char *structName, const int structNameLen, cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 从csv文件中注入数据接口
|
// 从csv文件中注入数据接口
|
||||||
int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *structName,
|
int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *injectDataInfo,
|
||||||
const int structNameLen,
|
const int injectDataInfoLen,
|
||||||
const char *csvFilePath,
|
const char *csvFilePath,
|
||||||
const int csvFilePathLen, char *infoMsg,
|
const int csvFilePathLen, char *infoMsg,
|
||||||
int infoMsgSize)
|
int infoMsgSize)
|
||||||
{
|
{
|
||||||
std::vector<std::string> structNames;
|
if (!g_initialized) {
|
||||||
std::string structNameStr(structName, structNameLen);
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
try {
|
strncpy(infoMsg, "DDSMonitor Not Initialized", infoMsgSize - 1);
|
||||||
nlohmann::json structNamesJson = nlohmann::json::parse(structNameStr);
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
if (!structNamesJson.is_array()) {
|
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
|
||||||
strncpy(infoMsg, "Invalid struct name format - expected JSON array",
|
|
||||||
infoMsgSize - 1);
|
|
||||||
infoMsg[infoMsgSize - 1] = '\0';
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
for (const auto &structNameJson : structNamesJson) {
|
return -1;
|
||||||
structNames.push_back(structNameJson.get<std::string>());
|
}
|
||||||
|
if (g_csvDataInjectThread != nullptr) {
|
||||||
|
g_csvDataInjectThread->stop();
|
||||||
|
delete g_csvDataInjectThread;
|
||||||
|
g_csvDataInjectThread = nullptr;
|
||||||
|
}
|
||||||
|
std::vector<InjectDataInfo> injectDataInfos;
|
||||||
|
std::string injectDataInfoStr(injectDataInfo, injectDataInfoLen);
|
||||||
|
try {
|
||||||
|
nlohmann::json injectDataInfoJson = nlohmann::json::parse(injectDataInfoStr);
|
||||||
|
for (const auto &[structName, interfaceInfo] : injectDataInfoJson.items()) {
|
||||||
|
InjectDataInfo info;
|
||||||
|
info.structName = structName;
|
||||||
|
for (const auto &[interfaceName, size] : interfaceInfo.items()) {
|
||||||
|
info.interfaceNames.push_back(interfaceName);
|
||||||
|
if (size.is_array()) {
|
||||||
|
info.arraySizes.push_back({size[0].get<int>(), size[1].get<int>()});
|
||||||
|
} else {
|
||||||
|
info.arraySizes.push_back({0, 0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
injectDataInfos.push_back(info);
|
||||||
}
|
}
|
||||||
} catch (const nlohmann::json::parse_error &e) {
|
} catch (const nlohmann::json::parse_error &e) {
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
@ -628,31 +642,42 @@ int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *structName,
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (g_csvDataInjectThread == nullptr) {
|
try {
|
||||||
g_csvDataInjectThread = std::make_shared<CSVDataInjectThread>(csvFilePathStr);
|
g_csvDataInjectThread = new CSVDataInjectThread(csvFilePathStr);
|
||||||
bool ret = g_csvDataInjectThread->Initialize(structNames);
|
if (!g_csvDataInjectThread->Initialize(injectDataInfos)) {
|
||||||
if (ret) {
|
delete g_csvDataInjectThread;
|
||||||
g_csvDataInjectThread->start();
|
g_csvDataInjectThread = nullptr;
|
||||||
} else {
|
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
strncpy(infoMsg, "CSV 注入线程初始化失败", infoMsgSize - 1);
|
strncpy(infoMsg, "CSV 注入线程初始化失败", infoMsgSize - 1);
|
||||||
infoMsg[infoMsgSize - 1] = '\0';
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
g_csvDataInjectThread->start();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
if (g_csvDataInjectThread) {
|
||||||
|
delete g_csvDataInjectThread;
|
||||||
|
g_csvDataInjectThread = nullptr;
|
||||||
|
}
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
strncpy(infoMsg, "CSV 注入线程已在运行", infoMsgSize - 1);
|
strncpy(infoMsg, e.what(), infoMsgSize - 1);
|
||||||
infoMsg[infoMsgSize - 1] = '\0';
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
std::cout << "CSV注入线程已启动" << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XN_GetCsvDataInjectStatus(char *infoMsg, int infoMsgSize)
|
int XN_GetCsvDataInjectStatus(char *infoMsg, int infoMsgSize)
|
||||||
{
|
{
|
||||||
|
if (!g_initialized) {
|
||||||
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
|
strncpy(infoMsg, "DDSMonitor Not Initialized", infoMsgSize - 1);
|
||||||
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_csvDataInjectThread == nullptr) {
|
if (g_csvDataInjectThread == nullptr) {
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
strncpy(infoMsg, "CSV 注入线程已不存在", infoMsgSize - 1);
|
strncpy(infoMsg, "CSV 注入线程已不存在", infoMsgSize - 1);
|
||||||
@ -660,14 +685,20 @@ int XN_GetCsvDataInjectStatus(char *infoMsg, int infoMsgSize)
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (g_csvDataInjectThread->isRunning()) {
|
|
||||||
return 1;
|
return g_csvDataInjectThread->isRunning() ? 1 : 0;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int XN_StopCsvDataInject(char *infoMsg, int infoMsgSize)
|
int XN_StopCsvDataInject(char *infoMsg, int infoMsgSize)
|
||||||
{
|
{
|
||||||
|
if (!g_initialized) {
|
||||||
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
|
strncpy(infoMsg, "DDSMonitor Not Initialized", infoMsgSize - 1);
|
||||||
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_csvDataInjectThread == nullptr) {
|
if (g_csvDataInjectThread == nullptr) {
|
||||||
if (infoMsg && infoMsgSize > 0) {
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
strncpy(infoMsg, "CSV 注入线程已不存在", infoMsgSize - 1);
|
strncpy(infoMsg, "CSV 注入线程已不存在", infoMsgSize - 1);
|
||||||
@ -676,9 +707,18 @@ int XN_StopCsvDataInject(char *infoMsg, int infoMsgSize)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_csvDataInjectThread->stop();
|
try {
|
||||||
g_csvDataInjectThread.reset(); // 释放智能指针
|
g_csvDataInjectThread->stop();
|
||||||
std::cout << "CSV注入线程已停止" << std::endl;
|
delete g_csvDataInjectThread;
|
||||||
|
g_csvDataInjectThread = nullptr;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
if (infoMsg && infoMsgSize > 0) {
|
||||||
|
strncpy(infoMsg, e.what(), infoMsgSize - 1);
|
||||||
|
infoMsg[infoMsgSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,8 +214,8 @@ extern "C"
|
|||||||
* @param infoMsgSize 错误信息大小
|
* @param infoMsgSize 错误信息大小
|
||||||
* @return 0: 成功, -1: 失败
|
* @return 0: 成功, -1: 失败
|
||||||
*/
|
*/
|
||||||
int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *structName,
|
int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *InjectDataInfo,
|
||||||
const int structNameLen,
|
const int InjectDataInfoLen,
|
||||||
const char *csvFilePath,
|
const char *csvFilePath,
|
||||||
const int csvFilePathLen,
|
const int csvFilePathLen,
|
||||||
char *infoMsg, int infoMsgSize);
|
char *infoMsg, int infoMsgSize);
|
||||||
|
@ -21,6 +21,7 @@ class DataMonitor extends HTMLElement {
|
|||||||
isInjecting: false,
|
isInjecting: false,
|
||||||
fileName: '',
|
fileName: '',
|
||||||
structNames: [],
|
structNames: [],
|
||||||
|
structData: {}, // 用于存储结构体数据
|
||||||
filePath: '' // 添加文件路径
|
filePath: '' // 添加文件路径
|
||||||
};
|
};
|
||||||
this.monitorStatus = 0; // 监控状态:0-未监控,1-监控中,2-错误
|
this.monitorStatus = 0; // 监控状态:0-未监控,1-监控中,2-错误
|
||||||
@ -419,7 +420,6 @@ class DataMonitor extends HTMLElement {
|
|||||||
throw new Error(`获取CSV注入状态失败: ${csvStatusResponse.status} ${csvStatusResponse.statusText}`);
|
throw new Error(`获取CSV注入状态失败: ${csvStatusResponse.status} ${csvStatusResponse.statusText}`);
|
||||||
}
|
}
|
||||||
const csvStatusData = await csvStatusResponse.json();
|
const csvStatusData = await csvStatusResponse.json();
|
||||||
console.log('CSV注入状态:', csvStatusData.data);
|
|
||||||
// 如果状态为0,触发停止注入
|
// 如果状态为0,触发停止注入
|
||||||
if (csvStatusData.data === 0) {
|
if (csvStatusData.data === 0) {
|
||||||
// 模拟点击停止CSV注入按钮
|
// 模拟点击停止CSV注入按钮
|
||||||
@ -1916,7 +1916,7 @@ class DataMonitor extends HTMLElement {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
structName: JSON.stringify(this.csvState.structNames),
|
structName: JSON.stringify(this.csvState.structData),
|
||||||
csvFilePath: this.csvState.filePath
|
csvFilePath: this.csvState.filePath
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -2127,7 +2127,7 @@ class DataMonitor extends HTMLElement {
|
|||||||
// 检查每个头部是否在接口表中
|
// 检查每个头部是否在接口表中
|
||||||
const missingInterfaces = [];
|
const missingInterfaces = [];
|
||||||
const invalidInterfaces = [];
|
const invalidInterfaces = [];
|
||||||
const structNames = []; // 用于按顺序收集结构体名称
|
const structData = {}; // 用于存储结构体数据
|
||||||
|
|
||||||
// 检查第一个接口(时间)是否在接口表中
|
// 检查第一个接口(时间)是否在接口表中
|
||||||
const firstHeader = validateResult.headers[0];
|
const firstHeader = validateResult.headers[0];
|
||||||
@ -2141,14 +2141,49 @@ class DataMonitor extends HTMLElement {
|
|||||||
// 检查其他接口是否在接口表中
|
// 检查其他接口是否在接口表中
|
||||||
for (let i = 1; i < validateResult.headers.length; i++) {
|
for (let i = 1; i < validateResult.headers.length; i++) {
|
||||||
const header = validateResult.headers[i];
|
const header = validateResult.headers[i];
|
||||||
|
// 提取接口名称和数组索引
|
||||||
|
const match = header.match(/^(.+?)(?:\[(\d+)\](?:\[(\d+)\])?)?$/);
|
||||||
|
if (!match) continue;
|
||||||
|
|
||||||
|
const baseInterfaceName = match[1];
|
||||||
|
const index1 = match[2] ? parseInt(match[2]) : null;
|
||||||
|
const index2 = match[3] ? parseInt(match[3]) : null;
|
||||||
|
|
||||||
const interfaceInfo = this.interfaces.find(interfaceItem =>
|
const interfaceInfo = this.interfaces.find(interfaceItem =>
|
||||||
interfaceItem.InterfaceName === header
|
interfaceItem.InterfaceName === baseInterfaceName
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!interfaceInfo) {
|
if (!interfaceInfo) {
|
||||||
missingInterfaces.push(header);
|
missingInterfaces.push(header);
|
||||||
} else {
|
} else {
|
||||||
// 按顺序收集结构体名称
|
// 构造结构体数据
|
||||||
structNames.push(interfaceInfo.ModelStructName);
|
if (!structData[interfaceInfo.ModelStructName]) {
|
||||||
|
structData[interfaceInfo.ModelStructName] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!structData[interfaceInfo.ModelStructName][baseInterfaceName]) {
|
||||||
|
const size1 = interfaceInfo.InterfaceArraySize_1 || 0;
|
||||||
|
const size2 = interfaceInfo.InterfaceArraySize_2 || 0;
|
||||||
|
|
||||||
|
structData[interfaceInfo.ModelStructName][baseInterfaceName] = [size1, size2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数组索引是否越界
|
||||||
|
if (index1 !== null) {
|
||||||
|
if (index2 !== null) {
|
||||||
|
// 二维数组
|
||||||
|
if (index1 >= interfaceInfo.InterfaceArraySize_1 || index2 >= interfaceInfo.InterfaceArraySize_2) {
|
||||||
|
console.warn(`接口 ${baseInterfaceName} 的数组索引 [${index1}][${index2}] 超出范围`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 一维数组
|
||||||
|
if (index1 >= interfaceInfo.InterfaceArraySize_1) {
|
||||||
|
console.warn(`接口 ${baseInterfaceName} 的数组索引 [${index1}] 超出范围`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2183,7 +2218,7 @@ class DataMonitor extends HTMLElement {
|
|||||||
|
|
||||||
// 更新CSV状态
|
// 更新CSV状态
|
||||||
this.csvState.fileName = result.file.name;
|
this.csvState.fileName = result.file.name;
|
||||||
this.csvState.structNames = structNames;
|
this.csvState.structData = structData; // 保存结构体数据
|
||||||
this.csvState.filePath = result.file.path;
|
this.csvState.filePath = result.file.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ router.post('/stop-all-continuous', async (req, res) => {
|
|||||||
/**
|
/**
|
||||||
* @brief 从CSV文件注入数据
|
* @brief 从CSV文件注入数据
|
||||||
* @route POST /api/data-monitor/inject-csv
|
* @route POST /api/data-monitor/inject-csv
|
||||||
* @param {string} structName - 结构体名称
|
* @param {string} structName - 结构体数据JSON字符串,格式为 {structName1: {interfaceName1: [size1, size2], ...}, structName2: ...}
|
||||||
* @param {string} csvFilePath - CSV文件路径
|
* @param {string} csvFilePath - CSV文件路径
|
||||||
* @returns {Object} 返回注入结果
|
* @returns {Object} 返回注入结果
|
||||||
*/
|
*/
|
||||||
@ -340,6 +340,43 @@ router.post('/inject-csv', async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析并验证 structName JSON 字符串
|
||||||
|
let structData;
|
||||||
|
try {
|
||||||
|
structData = JSON.parse(structName);
|
||||||
|
// 验证数据结构
|
||||||
|
if (typeof structData !== 'object' || structData === null) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '结构体数据格式错误:必须是有效的对象'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 验证每个结构体的接口数据
|
||||||
|
for (const [structName, interfaces] of Object.entries(structData)) {
|
||||||
|
if (typeof interfaces !== 'object' || interfaces === null) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: `结构体 ${structName} 的接口数据格式错误:必须是有效的对象`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const [interfaceName, sizes] of Object.entries(interfaces)) {
|
||||||
|
if (!Array.isArray(sizes) || sizes.length !== 2 ||
|
||||||
|
typeof sizes[0] !== 'number' || typeof sizes[1] !== 'number' ||
|
||||||
|
sizes[0] < 0 || sizes[1] < 0) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: `接口 ${interfaceName} 的数据格式错误:必须是包含两个非负数字的数组 [size1, size2]`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: `结构体数据解析失败: ${error.message}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const result = systemMonitor.injectDataInterfaceFromCsv(structName, csvFilePath);
|
const result = systemMonitor.injectDataInterfaceFromCsv(structName, csvFilePath);
|
||||||
if (result.includes('失败')) {
|
if (result.includes('失败')) {
|
||||||
return res.status(500).json({ success: false, message: result });
|
return res.status(500).json({ success: false, message: result });
|
||||||
|
Loading…
x
Reference in New Issue
Block a user