修改DDSInterface实现,修复ModelObject的问题
This commit is contained in:
parent
efcc6597cb
commit
a6818f35bc
99
Release/include/XNCore/XNByteArray.h
Normal file
99
Release/include/XNCore/XNByteArray.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
/**
|
||||
* @brief 自定义字节数组容器类
|
||||
* @details 提供类似QByteArray的功能,用于处理二进制数据
|
||||
*/
|
||||
class XNByteArray
|
||||
{
|
||||
public:
|
||||
XNByteArray() = default;
|
||||
explicit XNByteArray(size_t size) : data_(size) {}
|
||||
|
||||
/**
|
||||
* @brief 从原始数据构造
|
||||
* @param buffer 原始数据缓冲区
|
||||
* @param size 数据大小
|
||||
*/
|
||||
XNByteArray(const uint8_t *buffer, size_t size) : data_(buffer, buffer + size) {}
|
||||
|
||||
/**
|
||||
* @brief 获取数据指针
|
||||
* @return 数据指针
|
||||
*/
|
||||
uint8_t *data() { return data_.data(); }
|
||||
|
||||
/**
|
||||
* @brief 获取常量数据指针
|
||||
* @return 常量数据指针
|
||||
*/
|
||||
const uint8_t *data() const { return data_.data(); }
|
||||
|
||||
/**
|
||||
* @brief 获取数据大小
|
||||
* @return 数据大小
|
||||
*/
|
||||
size_t size() const { return data_.size(); }
|
||||
|
||||
/**
|
||||
* @brief 调整大小
|
||||
* @param size 新大小
|
||||
*/
|
||||
void resize(size_t size) { data_.resize(size); }
|
||||
|
||||
/**
|
||||
* @brief 清空数据
|
||||
*/
|
||||
void clear() { data_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 追加数据
|
||||
* @param buffer 要追加的数据
|
||||
* @param size 数据大小
|
||||
*/
|
||||
void append(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t oldSize = data_.size();
|
||||
data_.resize(oldSize + size);
|
||||
std::memcpy(data_.data() + oldSize, buffer, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 追加另一个XNByteArray
|
||||
* @param other 要追加的XNByteArray
|
||||
*/
|
||||
void append(const XNByteArray &other) { append(other.data(), other.size()); }
|
||||
|
||||
/**
|
||||
* @brief 获取指定位置的字节
|
||||
* @param index 索引
|
||||
* @return 字节值
|
||||
*/
|
||||
uint8_t &operator[](size_t index) { return data_[index]; }
|
||||
|
||||
/**
|
||||
* @brief 获取指定位置的字节(常量版本)
|
||||
* @param index 索引
|
||||
* @return 字节值
|
||||
*/
|
||||
const uint8_t &operator[](size_t index) const { return data_[index]; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否为空
|
||||
* @return 是否为空
|
||||
*/
|
||||
bool isEmpty() const { return data_.empty(); }
|
||||
|
||||
/**
|
||||
* @brief 预分配空间
|
||||
* @param size 要预分配的大小
|
||||
*/
|
||||
void reserve(size_t size) { data_.reserve(size); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
};
|
@ -37,6 +37,9 @@
|
||||
# include <sstream>
|
||||
# include <dlfcn.h>
|
||||
# include <filesystem>
|
||||
# include <array>
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include <fastdds/dds/domain/DomainParticipant.hpp>
|
||||
@ -47,6 +50,7 @@
|
||||
#include <fastdds/dds/subscriber/Subscriber.hpp>
|
||||
#include <fastdds/dds/topic/TypeSupport.hpp>
|
||||
#include <fastdds/dds/subscriber/DataReaderListener.hpp>
|
||||
#include <fastcdr/xcdr/optional.hpp>
|
||||
#define FAST_DDS_MACRO eprosima::fastdds::dds
|
||||
|
||||
/**
|
||||
|
@ -1,191 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fastcdr/xcdr/optional.hpp>
|
||||
#include "XNObject.h"
|
||||
#include "XNByteArray.h"
|
||||
#include "XNTypeTraits.h"
|
||||
#include <stdexcept>
|
||||
|
||||
// 定义UDP包的最大大小
|
||||
constexpr size_t MAX_UDP_PACKET_SIZE = 40000;
|
||||
|
||||
template <typename T>
|
||||
struct is_std_array : std::false_type {
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_std_array<std::array<T, N>> : std::true_type {
|
||||
};
|
||||
|
||||
// 变量模板简化使用
|
||||
template <typename T>
|
||||
inline constexpr bool is_std_array_v = is_std_array<T>::value;
|
||||
|
||||
// 获取类型大小的辅助函数
|
||||
template <typename T>
|
||||
constexpr size_t getTypeSize()
|
||||
{
|
||||
if constexpr (is_std_array_v<T>) {
|
||||
// 对于std::array,计算所有元素的总大小
|
||||
return getTypeSize<typename T::value_type>() * std::tuple_size<T>::value;
|
||||
} else {
|
||||
return sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
class XNDDSInterface
|
||||
{
|
||||
public:
|
||||
XNDDSInterface() = default;
|
||||
virtual ~XNDDSInterface() = default;
|
||||
|
||||
void getUDPPackage(uint8_t *buffer, size_t bufferSize)
|
||||
{
|
||||
if (bufferSize < MAX_UDP_PACKET_SIZE)
|
||||
return;
|
||||
public:
|
||||
/**
|
||||
* @brief 初始化
|
||||
* @param framework: 框架
|
||||
*/
|
||||
virtual void Initialize(XNFrameworkPtr framework) = 0;
|
||||
|
||||
size_t currentPos = 0;
|
||||
/**
|
||||
* @brief 获取该接口的UDP包
|
||||
* @return 字节数组
|
||||
*/
|
||||
XNByteArray getUDPPackage();
|
||||
|
||||
// 复制头部
|
||||
if (headerSize >= 5) {
|
||||
std::memcpy(buffer, header, 5);
|
||||
currentPos = 5;
|
||||
}
|
||||
|
||||
// 复制数据
|
||||
for (auto func : getByteArrayFunction) {
|
||||
if (currentPos + func.size <= MAX_UDP_PACKET_SIZE) {
|
||||
func.func(buffer + currentPos, func.size);
|
||||
currentPos += func.size;
|
||||
} else {
|
||||
break; // 超出最大包大小
|
||||
}
|
||||
}
|
||||
|
||||
// 更新包大小
|
||||
if (currentPos >= 5) {
|
||||
buffer[4] = static_cast<uint8_t>(currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
std::string getData(const std::string &varName)
|
||||
{
|
||||
int index1 = -1;
|
||||
int index2 = -1;
|
||||
std::string trueVarName = varName;
|
||||
|
||||
size_t startPos = varName.find('[');
|
||||
if (startPos != std::string::npos) {
|
||||
size_t midPos = varName.find("][", startPos);
|
||||
size_t endPos = varName.find_last_of(']');
|
||||
|
||||
if (midPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, midPos - startPos - 1));
|
||||
index2 = std::stoi(varName.substr(midPos + 2, endPos - midPos - 2));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
index2 = 0;
|
||||
}
|
||||
} else if (endPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, endPos - startPos - 1));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
}
|
||||
}
|
||||
trueVarName = varName.substr(0, startPos);
|
||||
}
|
||||
|
||||
auto it = getDataFunction.find(trueVarName);
|
||||
if (it == getDataFunction.end()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::string result = it->second();
|
||||
|
||||
if (index1 < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> list;
|
||||
std::stringstream ss(result);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
list.push_back(item);
|
||||
}
|
||||
|
||||
if (index1 >= static_cast<int>(list.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (index2 < 0) {
|
||||
return list[index1];
|
||||
}
|
||||
|
||||
std::vector<std::string> list2;
|
||||
std::stringstream ss2(list[index1]);
|
||||
while (std::getline(ss2, item, ' ')) {
|
||||
list2.push_back(item);
|
||||
}
|
||||
|
||||
if (index2 >= static_cast<int>(list2.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return list2[index2];
|
||||
}
|
||||
/**
|
||||
* @brief JSON前端获取指定变量的数据
|
||||
* @param varName: 变量名
|
||||
* @param nameSize: 变量名大小
|
||||
* @param varData: 数据
|
||||
* @param dataSize: 数据大小
|
||||
*/
|
||||
void getData(const char *varName, const size_t nameSize, char *varData, size_t dataSize);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 获取指定变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @return 字节数组
|
||||
*/
|
||||
template <typename T>
|
||||
void getByteArray(eprosima::fastcdr::optional<T> data, uint8_t *buffer, size_t bufferSize)
|
||||
XNByteArray getByteArray(eprosima::fastcdr::optional<T> data)
|
||||
{
|
||||
if (bufferSize < getTypeSize<T>())
|
||||
return;
|
||||
XNByteArray result(getTypeSize<T>());
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
if (data) {
|
||||
std::memcpy(buffer, &data.value(), sizeof(T));
|
||||
std::memcpy(result.data(), &data.value(), sizeof(T));
|
||||
} else {
|
||||
T zero = 0;
|
||||
std::memcpy(buffer, &zero, sizeof(T));
|
||||
std::memcpy(result.data(), &zero, sizeof(T));
|
||||
}
|
||||
} else if constexpr (is_std_array_v<T>) {
|
||||
if (data) {
|
||||
getByteArrayFromStdArray(data.value(), buffer, bufferSize);
|
||||
return getByteArrayFromStdArray(data.value());
|
||||
} else {
|
||||
T zero = {};
|
||||
getByteArrayFromStdArray(zero, buffer, bufferSize);
|
||||
return getByteArrayFromStdArray(zero);
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||
"Type must be arithmetic or std::array");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @param byteArray: 字节数组
|
||||
*/
|
||||
template <typename T>
|
||||
void setByteArray(eprosima::fastcdr::optional<T> &data, const XNByteArray &byteArray)
|
||||
{
|
||||
if (byteArray.size() < getTypeSize<T>())
|
||||
return;
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
T temp;
|
||||
std::memcpy(&temp, byteArray.data(), sizeof(T));
|
||||
data = temp;
|
||||
} else if constexpr (is_std_array_v<T>) {
|
||||
if (!data) {
|
||||
data = T{};
|
||||
}
|
||||
setByteArrayFromStdArray(data.value(), byteArray);
|
||||
} else {
|
||||
static_assert(std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||
"Type must be arithmetic or std::array");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定数组变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @return 字节数组
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
void getByteArrayFromStdArray(std::array<T, N> data, uint8_t *buffer, size_t bufferSize)
|
||||
XNByteArray getByteArrayFromStdArray(const std::array<T, N> &data)
|
||||
{
|
||||
if (bufferSize < getTypeSize<T>() * N)
|
||||
XNByteArray result(getTypeSize<T>() * N);
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
std::memcpy(result.data() + i * getTypeSize<T>(), &data[i], getTypeSize<T>());
|
||||
} else {
|
||||
XNByteArray subArray = getByteArrayFromStdArray(data[i]);
|
||||
std::memcpy(result.data() + i * getTypeSize<T>(), subArray.data(),
|
||||
getTypeSize<T>());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定数组变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @param byteArray: 字节数组
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
void setByteArrayFromStdArray(std::array<T, N> &data, const XNByteArray &byteArray)
|
||||
{
|
||||
if (byteArray.size() < getTypeSize<T>() * N)
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
std::memcpy(buffer + i * getTypeSize<T>(), &data[i], getTypeSize<T>());
|
||||
std::memcpy(&data[i], byteArray.data() + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
} else {
|
||||
getByteArrayFromStdArray(data[i], buffer + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
XNByteArray subArray(byteArray.data() + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
setByteArrayFromStdArray(data[i], subArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定变量的字符串数据,用于JSON前端
|
||||
* @param data: 数据
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
template <typename T>
|
||||
std::string getString(eprosima::fastcdr::optional<T> data)
|
||||
{
|
||||
@ -206,6 +164,11 @@ protected:
|
||||
return std::string();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定数组变量的字符串数据,用于JSON前端
|
||||
* @param data: 数据
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
std::string getStringFromStdArray(std::array<T, N> data)
|
||||
{
|
||||
@ -222,24 +185,35 @@ protected:
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 通过变量名获取指定的数据
|
||||
* @param varName: 变量名
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
std::string getData(const std::string &varName);
|
||||
|
||||
protected:
|
||||
struct ByteArrayFunc {
|
||||
std::function<void(uint8_t *, size_t)> func;
|
||||
std::function<XNByteArray(void)> func;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::function<std::string()>> getDataFunction;
|
||||
std::vector<ByteArrayFunc> getByteArrayFunction;
|
||||
std::unordered_map<std::string, std::function<void(XNByteArray)>> setByteArrayFunction;
|
||||
std::mutex mutex;
|
||||
uint8_t header[5]{}; // 固定大小的头部
|
||||
size_t headerSize = 0;
|
||||
};
|
||||
|
||||
#define MAP_GET_DATA_FUNC(NAME) \
|
||||
#define MAP_DATA_FUNC(NAME) \
|
||||
getDataFunction[#NAME] = [this]() { return getString(data.NAME()); }; \
|
||||
getByteArrayFunction.push_back( \
|
||||
{[this](uint8_t *buffer, size_t size) { getByteArray(data.NAME(), buffer, size); }, \
|
||||
getTypeSize<decltype(data.NAME())>()})
|
||||
{[this]() { return getByteArray(data.NAME()); }, getTypeSize<decltype(data.NAME())>()}); \
|
||||
setByteArrayFunction[#NAME] = [this](XNByteArray byteArray) { \
|
||||
setByteArray(data.NAME(), byteArray); \
|
||||
}
|
||||
|
||||
#define ASSIGN_VALUE_GET(NAME) \
|
||||
if (data.NAME()) { \
|
||||
|
@ -121,6 +121,54 @@ public:
|
||||
*/
|
||||
void SetVersion(const std::string &sVersion);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行频率组
|
||||
* @return uint32_t: 模型运行频率组
|
||||
*/
|
||||
uint32_t GetRunFreq() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行频率组
|
||||
* @param runFreq: uint32_t类型,模型运行频率组
|
||||
*/
|
||||
void SetRunFreq(uint32_t runFreq);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行节点
|
||||
* @return uint32_t: 模型运行节点
|
||||
*/
|
||||
uint32_t GetRunNode() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行节点
|
||||
* @param runNode: uint32_t类型,模型运行节点
|
||||
*/
|
||||
void SetRunNode(uint32_t runNode);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行优先级
|
||||
* @return uint32_t: 模型运行优先级
|
||||
*/
|
||||
uint32_t GetRunPriority() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行优先级
|
||||
* @param runPriority: uint32_t类型,模型运行优先级
|
||||
*/
|
||||
void SetRunPriority(uint32_t runPriority);
|
||||
|
||||
/**
|
||||
* @brief 获取模型设置频率
|
||||
* @return double: 模型设置频率
|
||||
*/
|
||||
double GetSetFreq() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型设置频率
|
||||
* @param setFreq: double类型,模型设置频率
|
||||
*/
|
||||
void SetSetFreq(double setFreq);
|
||||
|
||||
/**
|
||||
* @brief 单步执行函数
|
||||
* @details 模型默认的周期性执行函数
|
||||
@ -169,12 +217,18 @@ public:
|
||||
TriggerEvent(eventName, eventData, true, XNEvent::Priority::RealTime);
|
||||
}
|
||||
|
||||
void SetInitializeType(uint32_t initialType);
|
||||
|
||||
void SetThreadID(uint32_t threadID);
|
||||
|
||||
uint32_t GetThreadID() const;
|
||||
|
||||
/**
|
||||
* @brief 初始化函数
|
||||
* @details
|
||||
* 模型的初始化函数接口,子类继承时要调用父类初始化接口,或在此函数中使用AddMyFunction方法注册需要被线程调用的函数
|
||||
*/
|
||||
virtual void Initialize(uint32_t initialType, uint32_t threadID);
|
||||
virtual void Initialize();
|
||||
|
||||
/**
|
||||
* @brief 仿真系统运行前做最后处理
|
||||
|
@ -84,6 +84,11 @@ struct XNModelObjectPrivate : public XNObjectPrivate {
|
||||
*/
|
||||
double _setFreq;
|
||||
|
||||
/**
|
||||
* @brief 模型初始化类型
|
||||
*/
|
||||
uint32_t _initialType;
|
||||
|
||||
/**
|
||||
* @brief 模型线程ID
|
||||
*/
|
||||
|
@ -81,6 +81,22 @@ public:
|
||||
*/
|
||||
virtual bool PrepareForExecute() override;
|
||||
|
||||
/**
|
||||
* @brief 设置线程频率
|
||||
* @param threadID: UINT32类型,线程ID
|
||||
* @param freq: double类型,线程频率
|
||||
* @details 设置线程频率接口
|
||||
*/
|
||||
void SetThreadFreqByID(uint32_t threadID, double freq);
|
||||
|
||||
/**
|
||||
* @brief 获取线程频率
|
||||
* @param threadID: UINT32类型,线程ID
|
||||
* @return double: 线程频率
|
||||
* @details 获取线程频率接口
|
||||
*/
|
||||
double GetThreadFreqByID(uint32_t threadID);
|
||||
|
||||
/**
|
||||
* @brief 仿真控制
|
||||
* @param objectId: 对象ID
|
||||
|
28
Release/include/XNCore/XNTypeTraits.h
Normal file
28
Release/include/XNCore/XNTypeTraits.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
template <typename T>
|
||||
struct is_std_array : std::false_type {
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_std_array<std::array<T, N>> : std::true_type {
|
||||
};
|
||||
|
||||
// 变量模板简化使用
|
||||
template <typename T>
|
||||
inline constexpr bool is_std_array_v = is_std_array<T>::value;
|
||||
|
||||
// 获取类型大小的辅助函数
|
||||
template <typename T>
|
||||
constexpr size_t getTypeSize()
|
||||
{
|
||||
if constexpr (is_std_array_v<T>) {
|
||||
// 对于std::array,计算所有元素的总大小
|
||||
return getTypeSize<typename T::value_type>() * std::tuple_size<T>::value;
|
||||
} else {
|
||||
return sizeof(T);
|
||||
}
|
||||
}
|
4
XNCore/.vscode/settings.json
vendored
4
XNCore/.vscode/settings.json
vendored
@ -79,6 +79,8 @@
|
||||
"csignal": "cpp",
|
||||
"any": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"fstream": "cpp"
|
||||
"fstream": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"valarray": "cpp"
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ find_package(OpenSSL REQUIRED)
|
||||
add_library(XNCore SHARED
|
||||
XNCore_global.h
|
||||
XNCore_Function.cpp
|
||||
XNTypeTraits.h
|
||||
XNByteArray.h
|
||||
XNObject.h
|
||||
XNObject.cpp
|
||||
XNObject_p.h
|
||||
|
99
XNCore/XNByteArray.h
Normal file
99
XNCore/XNByteArray.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
/**
|
||||
* @brief 自定义字节数组容器类
|
||||
* @details 提供类似QByteArray的功能,用于处理二进制数据
|
||||
*/
|
||||
class XNByteArray
|
||||
{
|
||||
public:
|
||||
XNByteArray() = default;
|
||||
explicit XNByteArray(size_t size) : data_(size) {}
|
||||
|
||||
/**
|
||||
* @brief 从原始数据构造
|
||||
* @param buffer 原始数据缓冲区
|
||||
* @param size 数据大小
|
||||
*/
|
||||
XNByteArray(const uint8_t *buffer, size_t size) : data_(buffer, buffer + size) {}
|
||||
|
||||
/**
|
||||
* @brief 获取数据指针
|
||||
* @return 数据指针
|
||||
*/
|
||||
uint8_t *data() { return data_.data(); }
|
||||
|
||||
/**
|
||||
* @brief 获取常量数据指针
|
||||
* @return 常量数据指针
|
||||
*/
|
||||
const uint8_t *data() const { return data_.data(); }
|
||||
|
||||
/**
|
||||
* @brief 获取数据大小
|
||||
* @return 数据大小
|
||||
*/
|
||||
size_t size() const { return data_.size(); }
|
||||
|
||||
/**
|
||||
* @brief 调整大小
|
||||
* @param size 新大小
|
||||
*/
|
||||
void resize(size_t size) { data_.resize(size); }
|
||||
|
||||
/**
|
||||
* @brief 清空数据
|
||||
*/
|
||||
void clear() { data_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 追加数据
|
||||
* @param buffer 要追加的数据
|
||||
* @param size 数据大小
|
||||
*/
|
||||
void append(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t oldSize = data_.size();
|
||||
data_.resize(oldSize + size);
|
||||
std::memcpy(data_.data() + oldSize, buffer, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 追加另一个XNByteArray
|
||||
* @param other 要追加的XNByteArray
|
||||
*/
|
||||
void append(const XNByteArray &other) { append(other.data(), other.size()); }
|
||||
|
||||
/**
|
||||
* @brief 获取指定位置的字节
|
||||
* @param index 索引
|
||||
* @return 字节值
|
||||
*/
|
||||
uint8_t &operator[](size_t index) { return data_[index]; }
|
||||
|
||||
/**
|
||||
* @brief 获取指定位置的字节(常量版本)
|
||||
* @param index 索引
|
||||
* @return 字节值
|
||||
*/
|
||||
const uint8_t &operator[](size_t index) const { return data_[index]; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否为空
|
||||
* @return 是否为空
|
||||
*/
|
||||
bool isEmpty() const { return data_.empty(); }
|
||||
|
||||
/**
|
||||
* @brief 预分配空间
|
||||
* @param size 要预分配的大小
|
||||
*/
|
||||
void reserve(size_t size) { data_.reserve(size); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
};
|
@ -37,6 +37,9 @@
|
||||
# include <sstream>
|
||||
# include <dlfcn.h>
|
||||
# include <filesystem>
|
||||
# include <array>
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include <fastdds/dds/domain/DomainParticipant.hpp>
|
||||
@ -47,6 +50,7 @@
|
||||
#include <fastdds/dds/subscriber/Subscriber.hpp>
|
||||
#include <fastdds/dds/topic/TypeSupport.hpp>
|
||||
#include <fastdds/dds/subscriber/DataReaderListener.hpp>
|
||||
#include <fastcdr/xcdr/optional.hpp>
|
||||
#define FAST_DDS_MACRO eprosima::fastdds::dds
|
||||
|
||||
/**
|
||||
|
107
XNCore/XNDDSInterface.cpp
Normal file
107
XNCore/XNDDSInterface.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include "XNDDSInterface.h"
|
||||
#include "XNObject_p.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void XNDDSInterface::getUDPPackage(uint8_t *buffer, size_t bufferSize)
|
||||
{
|
||||
if (bufferSize < MAX_UDP_PACKET_SIZE)
|
||||
return;
|
||||
|
||||
size_t currentPos = 0;
|
||||
|
||||
// 复制头部
|
||||
if (headerSize >= 5) {
|
||||
std::memcpy(buffer, header, 5);
|
||||
currentPos = 5;
|
||||
}
|
||||
|
||||
// 复制数据
|
||||
for (auto func : getByteArrayFunction) {
|
||||
if (currentPos + func.size <= MAX_UDP_PACKET_SIZE) {
|
||||
func.func(buffer + currentPos, func.size);
|
||||
currentPos += func.size;
|
||||
} else {
|
||||
break; // 超出最大包大小
|
||||
}
|
||||
}
|
||||
|
||||
// 更新包大小
|
||||
if (currentPos >= 5) {
|
||||
buffer[4] = static_cast<uint8_t>(currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
std::string XNDDSInterface::getData(const std::string &varName)
|
||||
{
|
||||
int index1 = -1;
|
||||
int index2 = -1;
|
||||
std::string trueVarName = varName;
|
||||
|
||||
size_t startPos = varName.find('[');
|
||||
if (startPos != std::string::npos) {
|
||||
size_t midPos = varName.find("][", startPos);
|
||||
size_t endPos = varName.find_last_of(']');
|
||||
|
||||
if (midPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, midPos - startPos - 1));
|
||||
index2 = std::stoi(varName.substr(midPos + 2, endPos - midPos - 2));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
index2 = 0;
|
||||
}
|
||||
} else if (endPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, endPos - startPos - 1));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
}
|
||||
}
|
||||
trueVarName = varName.substr(0, startPos);
|
||||
}
|
||||
|
||||
auto it = getDataFunction.find(trueVarName);
|
||||
if (it == getDataFunction.end()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::string result = it->second();
|
||||
|
||||
if (index1 < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> list;
|
||||
std::stringstream ss(result);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
list.push_back(item);
|
||||
}
|
||||
|
||||
if (index1 >= static_cast<int>(list.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (index2 < 0) {
|
||||
return list[index1];
|
||||
}
|
||||
|
||||
std::vector<std::string> list2;
|
||||
std::stringstream ss2(list[index1]);
|
||||
while (std::getline(ss2, item, ' ')) {
|
||||
list2.push_back(item);
|
||||
}
|
||||
|
||||
if (index2 >= static_cast<int>(list2.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return list2[index2];
|
||||
}
|
@ -1,191 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fastcdr/xcdr/optional.hpp>
|
||||
#include "XNObject.h"
|
||||
#include "XNByteArray.h"
|
||||
#include "XNTypeTraits.h"
|
||||
#include <stdexcept>
|
||||
|
||||
// 定义UDP包的最大大小
|
||||
constexpr size_t MAX_UDP_PACKET_SIZE = 40000;
|
||||
|
||||
template <typename T>
|
||||
struct is_std_array : std::false_type {
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_std_array<std::array<T, N>> : std::true_type {
|
||||
};
|
||||
|
||||
// 变量模板简化使用
|
||||
template <typename T>
|
||||
inline constexpr bool is_std_array_v = is_std_array<T>::value;
|
||||
|
||||
// 获取类型大小的辅助函数
|
||||
template <typename T>
|
||||
constexpr size_t getTypeSize()
|
||||
{
|
||||
if constexpr (is_std_array_v<T>) {
|
||||
// 对于std::array,计算所有元素的总大小
|
||||
return getTypeSize<typename T::value_type>() * std::tuple_size<T>::value;
|
||||
} else {
|
||||
return sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
class XNDDSInterface
|
||||
{
|
||||
public:
|
||||
XNDDSInterface() = default;
|
||||
virtual ~XNDDSInterface() = default;
|
||||
|
||||
void getUDPPackage(uint8_t *buffer, size_t bufferSize)
|
||||
{
|
||||
if (bufferSize < MAX_UDP_PACKET_SIZE)
|
||||
return;
|
||||
public:
|
||||
/**
|
||||
* @brief 初始化
|
||||
* @param framework: 框架
|
||||
*/
|
||||
virtual void Initialize(XNFrameworkPtr framework) = 0;
|
||||
|
||||
size_t currentPos = 0;
|
||||
/**
|
||||
* @brief 获取该接口的UDP包
|
||||
* @return 字节数组
|
||||
*/
|
||||
XNByteArray getUDPPackage();
|
||||
|
||||
// 复制头部
|
||||
if (headerSize >= 5) {
|
||||
std::memcpy(buffer, header, 5);
|
||||
currentPos = 5;
|
||||
}
|
||||
|
||||
// 复制数据
|
||||
for (auto func : getByteArrayFunction) {
|
||||
if (currentPos + func.size <= MAX_UDP_PACKET_SIZE) {
|
||||
func.func(buffer + currentPos, func.size);
|
||||
currentPos += func.size;
|
||||
} else {
|
||||
break; // 超出最大包大小
|
||||
}
|
||||
}
|
||||
|
||||
// 更新包大小
|
||||
if (currentPos >= 5) {
|
||||
buffer[4] = static_cast<uint8_t>(currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
std::string getData(const std::string &varName)
|
||||
{
|
||||
int index1 = -1;
|
||||
int index2 = -1;
|
||||
std::string trueVarName = varName;
|
||||
|
||||
size_t startPos = varName.find('[');
|
||||
if (startPos != std::string::npos) {
|
||||
size_t midPos = varName.find("][", startPos);
|
||||
size_t endPos = varName.find_last_of(']');
|
||||
|
||||
if (midPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, midPos - startPos - 1));
|
||||
index2 = std::stoi(varName.substr(midPos + 2, endPos - midPos - 2));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
index2 = 0;
|
||||
}
|
||||
} else if (endPos != std::string::npos) {
|
||||
try {
|
||||
index1 = std::stoi(varName.substr(startPos + 1, endPos - startPos - 1));
|
||||
} catch (...) {
|
||||
std::cerr << "无法解析数组索引: " << varName << std::endl;
|
||||
index1 = 0;
|
||||
}
|
||||
}
|
||||
trueVarName = varName.substr(0, startPos);
|
||||
}
|
||||
|
||||
auto it = getDataFunction.find(trueVarName);
|
||||
if (it == getDataFunction.end()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::string result = it->second();
|
||||
|
||||
if (index1 < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> list;
|
||||
std::stringstream ss(result);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
list.push_back(item);
|
||||
}
|
||||
|
||||
if (index1 >= static_cast<int>(list.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
if (index2 < 0) {
|
||||
return list[index1];
|
||||
}
|
||||
|
||||
std::vector<std::string> list2;
|
||||
std::stringstream ss2(list[index1]);
|
||||
while (std::getline(ss2, item, ' ')) {
|
||||
list2.push_back(item);
|
||||
}
|
||||
|
||||
if (index2 >= static_cast<int>(list2.size())) {
|
||||
std::cerr << "数组索引超出范围: " << varName << std::endl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return list2[index2];
|
||||
}
|
||||
/**
|
||||
* @brief JSON前端获取指定变量的数据
|
||||
* @param varName: 变量名
|
||||
* @param nameSize: 变量名大小
|
||||
* @param varData: 数据
|
||||
* @param dataSize: 数据大小
|
||||
*/
|
||||
void getData(const char *varName, const size_t nameSize, char *varData, size_t dataSize);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 获取指定变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @return 字节数组
|
||||
*/
|
||||
template <typename T>
|
||||
void getByteArray(eprosima::fastcdr::optional<T> data, uint8_t *buffer, size_t bufferSize)
|
||||
XNByteArray getByteArray(eprosima::fastcdr::optional<T> data)
|
||||
{
|
||||
if (bufferSize < getTypeSize<T>())
|
||||
return;
|
||||
XNByteArray result(getTypeSize<T>());
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
if (data) {
|
||||
std::memcpy(buffer, &data.value(), sizeof(T));
|
||||
std::memcpy(result.data(), &data.value(), sizeof(T));
|
||||
} else {
|
||||
T zero = 0;
|
||||
std::memcpy(buffer, &zero, sizeof(T));
|
||||
std::memcpy(result.data(), &zero, sizeof(T));
|
||||
}
|
||||
} else if constexpr (is_std_array_v<T>) {
|
||||
if (data) {
|
||||
getByteArrayFromStdArray(data.value(), buffer, bufferSize);
|
||||
return getByteArrayFromStdArray(data.value());
|
||||
} else {
|
||||
T zero = {};
|
||||
getByteArrayFromStdArray(zero, buffer, bufferSize);
|
||||
return getByteArrayFromStdArray(zero);
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||
"Type must be arithmetic or std::array");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @param byteArray: 字节数组
|
||||
*/
|
||||
template <typename T>
|
||||
void setByteArray(eprosima::fastcdr::optional<T> &data, const XNByteArray &byteArray)
|
||||
{
|
||||
if (byteArray.size() < getTypeSize<T>())
|
||||
return;
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
T temp;
|
||||
std::memcpy(&temp, byteArray.data(), sizeof(T));
|
||||
data = temp;
|
||||
} else if constexpr (is_std_array_v<T>) {
|
||||
if (!data) {
|
||||
data = T{};
|
||||
}
|
||||
setByteArrayFromStdArray(data.value(), byteArray);
|
||||
} else {
|
||||
static_assert(std::is_arithmetic_v<T> || is_std_array_v<T>,
|
||||
"Type must be arithmetic or std::array");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定数组变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @return 字节数组
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
void getByteArrayFromStdArray(std::array<T, N> data, uint8_t *buffer, size_t bufferSize)
|
||||
XNByteArray getByteArrayFromStdArray(const std::array<T, N> &data)
|
||||
{
|
||||
if (bufferSize < getTypeSize<T>() * N)
|
||||
XNByteArray result(getTypeSize<T>() * N);
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
std::memcpy(result.data() + i * getTypeSize<T>(), &data[i], getTypeSize<T>());
|
||||
} else {
|
||||
XNByteArray subArray = getByteArrayFromStdArray(data[i]);
|
||||
std::memcpy(result.data() + i * getTypeSize<T>(), subArray.data(),
|
||||
getTypeSize<T>());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置指定数组变量的字节数据,用于网络通信
|
||||
* @param data: 数据
|
||||
* @param byteArray: 字节数组
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
void setByteArrayFromStdArray(std::array<T, N> &data, const XNByteArray &byteArray)
|
||||
{
|
||||
if (byteArray.size() < getTypeSize<T>() * N)
|
||||
return;
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
std::memcpy(buffer + i * getTypeSize<T>(), &data[i], getTypeSize<T>());
|
||||
std::memcpy(&data[i], byteArray.data() + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
} else {
|
||||
getByteArrayFromStdArray(data[i], buffer + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
XNByteArray subArray(byteArray.data() + i * getTypeSize<T>(), getTypeSize<T>());
|
||||
setByteArrayFromStdArray(data[i], subArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定变量的字符串数据,用于JSON前端
|
||||
* @param data: 数据
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
template <typename T>
|
||||
std::string getString(eprosima::fastcdr::optional<T> data)
|
||||
{
|
||||
@ -206,6 +164,11 @@ protected:
|
||||
return std::string();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定数组变量的字符串数据,用于JSON前端
|
||||
* @param data: 数据
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
template <typename T, std::size_t N>
|
||||
std::string getStringFromStdArray(std::array<T, N> data)
|
||||
{
|
||||
@ -222,24 +185,35 @@ protected:
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 通过变量名获取指定的数据
|
||||
* @param varName: 变量名
|
||||
* @return: 数据(字符串格式)
|
||||
*/
|
||||
std::string getData(const std::string &varName);
|
||||
|
||||
protected:
|
||||
struct ByteArrayFunc {
|
||||
std::function<void(uint8_t *, size_t)> func;
|
||||
std::function<XNByteArray(void)> func;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::function<std::string()>> getDataFunction;
|
||||
std::vector<ByteArrayFunc> getByteArrayFunction;
|
||||
std::unordered_map<std::string, std::function<void(XNByteArray)>> setByteArrayFunction;
|
||||
std::mutex mutex;
|
||||
uint8_t header[5]{}; // 固定大小的头部
|
||||
size_t headerSize = 0;
|
||||
};
|
||||
|
||||
#define MAP_GET_DATA_FUNC(NAME) \
|
||||
#define MAP_DATA_FUNC(NAME) \
|
||||
getDataFunction[#NAME] = [this]() { return getString(data.NAME()); }; \
|
||||
getByteArrayFunction.push_back( \
|
||||
{[this](uint8_t *buffer, size_t size) { getByteArray(data.NAME(), buffer, size); }, \
|
||||
getTypeSize<decltype(data.NAME())>()})
|
||||
{[this]() { return getByteArray(data.NAME()); }, getTypeSize<decltype(data.NAME())>()}); \
|
||||
setByteArrayFunction[#NAME] = [this](XNByteArray byteArray) { \
|
||||
setByteArray(data.NAME(), byteArray); \
|
||||
}
|
||||
|
||||
#define ASSIGN_VALUE_GET(NAME) \
|
||||
if (data.NAME()) { \
|
||||
|
@ -38,6 +38,9 @@ XNModelManager::XNModelManager(PrivateType *p) : XNBaseFrameObject(p)
|
||||
bool XNModelManager::PrepareForExecute()
|
||||
{
|
||||
T_D();
|
||||
for (auto &model : d->ModelMap) {
|
||||
model.second->PrepareForExecute();
|
||||
}
|
||||
d->_status = XNFrameObjectStatus::Ready;
|
||||
LOG_INFO("XNModelManager is prepared!");
|
||||
return true;
|
||||
@ -72,7 +75,8 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string &
|
||||
model->SetUniqueId(modelID);
|
||||
model->SetObjectName(className);
|
||||
model->SetFramework(GetFramework());
|
||||
|
||||
model->SetInitializeType(initialType);
|
||||
model->SetThreadID(threadID);
|
||||
// 使用std::filesystem处理路径
|
||||
std::filesystem::path configPath =
|
||||
std::filesystem::path(modelPath).parent_path() / (className + ".mcfg");
|
||||
@ -82,7 +86,7 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string &
|
||||
d->ModelMap[modelID] = model;
|
||||
|
||||
// 初始化模型
|
||||
model->Initialize(initialType, threadID);
|
||||
model->Initialize();
|
||||
|
||||
// 注册到线程管理器
|
||||
if (threadID != 0) {
|
||||
@ -90,7 +94,12 @@ void XNModelManager::LoadModel(const std::string &modelPath, const std::string &
|
||||
if (framework) {
|
||||
framework->GetThreadManager()->RegisterFunction(
|
||||
modelID, std::bind(&XNModelObject::StepUpdate, model.get()), threadID,
|
||||
0, 0, 0);
|
||||
model->GetRunFreq(), model->GetRunNode(), model->GetRunPriority());
|
||||
// 设置模型设置频率
|
||||
double threadFreq =
|
||||
framework->GetThreadManager()->GetThreadFreqByID(threadID);
|
||||
double modelSetFreq = threadFreq / (double)(1 << model->GetRunFreq());
|
||||
model->SetSetFreq(modelSetFreq);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -126,12 +126,78 @@ void XNModelObject::SetVersion(const std::string &sVersion)
|
||||
d->_sVersion = sVersion;
|
||||
}
|
||||
|
||||
void XNModelObject::SetInitializeType(uint32_t initialType)
|
||||
{
|
||||
T_D();
|
||||
d->_initialType = initialType;
|
||||
}
|
||||
|
||||
void XNModelObject::SetThreadID(uint32_t threadID)
|
||||
{
|
||||
T_D();
|
||||
d->_threadID = threadID;
|
||||
}
|
||||
|
||||
uint32_t XNModelObject::GetThreadID() const
|
||||
{
|
||||
T_D();
|
||||
return d->_threadID;
|
||||
}
|
||||
|
||||
uint32_t XNModelObject::GetRunFreq() const
|
||||
{
|
||||
T_D();
|
||||
return d->_runFreq;
|
||||
}
|
||||
|
||||
void XNModelObject::SetRunFreq(uint32_t runFreq)
|
||||
{
|
||||
T_D();
|
||||
d->_runFreq = runFreq;
|
||||
}
|
||||
|
||||
uint32_t XNModelObject::GetRunNode() const
|
||||
{
|
||||
T_D();
|
||||
return d->_runNode;
|
||||
}
|
||||
|
||||
void XNModelObject::SetRunNode(uint32_t runNode)
|
||||
{
|
||||
T_D();
|
||||
d->_runNode = runNode;
|
||||
}
|
||||
|
||||
uint32_t XNModelObject::GetRunPriority() const
|
||||
{
|
||||
T_D();
|
||||
return d->_runPriority;
|
||||
}
|
||||
|
||||
void XNModelObject::SetRunPriority(uint32_t runPriority)
|
||||
{
|
||||
T_D();
|
||||
d->_runPriority = runPriority;
|
||||
}
|
||||
|
||||
double XNModelObject::GetSetFreq() const
|
||||
{
|
||||
T_D();
|
||||
return d->_setFreq;
|
||||
}
|
||||
|
||||
void XNModelObject::SetSetFreq(double setFreq)
|
||||
{
|
||||
T_D();
|
||||
d->_setFreq = setFreq;
|
||||
}
|
||||
|
||||
// 初始化函数
|
||||
void XNModelObject::Initialize(uint32_t initialType, uint32_t threadID)
|
||||
void XNModelObject::Initialize()
|
||||
{
|
||||
// 先尝试调取动态库
|
||||
T_D();
|
||||
if (initialType == 0) {
|
||||
if (d->_initialType == 0) {
|
||||
// 读取配置文件,设置循环执行函数
|
||||
std::ifstream file(GetXmlPath());
|
||||
if (!file.is_open()) {
|
||||
@ -179,7 +245,6 @@ void XNModelObject::Initialize(uint32_t initialType, uint32_t threadID)
|
||||
|
||||
// 使用标准C++字符串处理
|
||||
d->_runFreq = std::stoi(funcNode.substr(0, tmp));
|
||||
d->_setFreq = d->_setFreq / std::pow(2.0, d->_runFreq);
|
||||
d->_runNode = std::stoi(funcNode.substr(tmp + 1));
|
||||
|
||||
// 注册周期性函数
|
||||
@ -188,7 +253,7 @@ void XNModelObject::Initialize(uint32_t initialType, uint32_t threadID)
|
||||
auto threadManager = framework->GetThreadManager();
|
||||
if (threadManager) {
|
||||
threadManager->RegisterFunction(
|
||||
GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), threadID,
|
||||
GetUniqueId(), std::bind(&XNModelObject::StepUpdate, this), d->_threadID,
|
||||
d->_runFreq, d->_runNode, d->_runPriority);
|
||||
}
|
||||
}
|
||||
@ -284,9 +349,8 @@ void XNModelObject::RegisterDDSParticipant()
|
||||
XN_PUBLISHTOPIC(XNSim::XNSimStatus::XNModelStatus);
|
||||
}
|
||||
|
||||
int XNModelObject::RegisterEventHandler(const std::string &eventName,
|
||||
std::function<void(const std::any &)> callback, bool async,
|
||||
XNEvent::Priority priority)
|
||||
int XNModelObject::RegisterEventHandler(const std::string &eventName, XNEventCallback callback,
|
||||
bool async, XNEvent::Priority priority)
|
||||
{
|
||||
// 获取事件管理器
|
||||
auto framework = GetFramework();
|
||||
|
@ -121,6 +121,54 @@ public:
|
||||
*/
|
||||
void SetVersion(const std::string &sVersion);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行频率组
|
||||
* @return uint32_t: 模型运行频率组
|
||||
*/
|
||||
uint32_t GetRunFreq() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行频率组
|
||||
* @param runFreq: uint32_t类型,模型运行频率组
|
||||
*/
|
||||
void SetRunFreq(uint32_t runFreq);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行节点
|
||||
* @return uint32_t: 模型运行节点
|
||||
*/
|
||||
uint32_t GetRunNode() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行节点
|
||||
* @param runNode: uint32_t类型,模型运行节点
|
||||
*/
|
||||
void SetRunNode(uint32_t runNode);
|
||||
|
||||
/**
|
||||
* @brief 获取模型运行优先级
|
||||
* @return uint32_t: 模型运行优先级
|
||||
*/
|
||||
uint32_t GetRunPriority() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型运行优先级
|
||||
* @param runPriority: uint32_t类型,模型运行优先级
|
||||
*/
|
||||
void SetRunPriority(uint32_t runPriority);
|
||||
|
||||
/**
|
||||
* @brief 获取模型设置频率
|
||||
* @return double: 模型设置频率
|
||||
*/
|
||||
double GetSetFreq() const;
|
||||
|
||||
/**
|
||||
* @brief 设置模型设置频率
|
||||
* @param setFreq: double类型,模型设置频率
|
||||
*/
|
||||
void SetSetFreq(double setFreq);
|
||||
|
||||
/**
|
||||
* @brief 单步执行函数
|
||||
* @details 模型默认的周期性执行函数
|
||||
@ -169,12 +217,18 @@ public:
|
||||
TriggerEvent(eventName, eventData, true, XNEvent::Priority::RealTime);
|
||||
}
|
||||
|
||||
void SetInitializeType(uint32_t initialType);
|
||||
|
||||
void SetThreadID(uint32_t threadID);
|
||||
|
||||
uint32_t GetThreadID() const;
|
||||
|
||||
/**
|
||||
* @brief 初始化函数
|
||||
* @details
|
||||
* 模型的初始化函数接口,子类继承时要调用父类初始化接口,或在此函数中使用AddMyFunction方法注册需要被线程调用的函数
|
||||
*/
|
||||
virtual void Initialize(uint32_t initialType, uint32_t threadID);
|
||||
virtual void Initialize();
|
||||
|
||||
/**
|
||||
* @brief 仿真系统运行前做最后处理
|
||||
|
@ -84,6 +84,11 @@ struct XNModelObjectPrivate : public XNObjectPrivate {
|
||||
*/
|
||||
double _setFreq;
|
||||
|
||||
/**
|
||||
* @brief 模型初始化类型
|
||||
*/
|
||||
uint32_t _initialType;
|
||||
|
||||
/**
|
||||
* @brief 模型线程ID
|
||||
*/
|
||||
|
@ -29,6 +29,9 @@ bool XNServiceManager::Initialize()
|
||||
bool XNServiceManager::PrepareForExecute()
|
||||
{
|
||||
T_D();
|
||||
for (auto &service : d->ServiceList) {
|
||||
service.second->PrepareForExecute();
|
||||
}
|
||||
d->_status = XNFrameObjectStatus::Ready;
|
||||
LOG_INFO("XNServiceManager is prepared!");
|
||||
return true;
|
||||
|
@ -272,6 +272,7 @@ void XNThread::SetRunFrequecy(const double &dRunFrequecy)
|
||||
{
|
||||
T_D();
|
||||
d->_setFreq = dRunFrequecy;
|
||||
d->pinfo.period_ns = 1.0E9 / dRunFrequecy;
|
||||
}
|
||||
|
||||
// 获取线程运行优先级
|
||||
|
@ -225,3 +225,15 @@ uint32_t XNThreadManager::AllocateThreadID()
|
||||
d->threadList[threadID] = nullptr;
|
||||
return threadID;
|
||||
}
|
||||
|
||||
void XNThreadManager::SetThreadFreqByID(uint32_t threadID, double freq)
|
||||
{
|
||||
T_D();
|
||||
d->threadList[threadID]->SetRunFrequecy(freq);
|
||||
}
|
||||
|
||||
double XNThreadManager::GetThreadFreqByID(uint32_t threadID)
|
||||
{
|
||||
T_D();
|
||||
return d->threadList[threadID]->GetRunFrequecy();
|
||||
}
|
||||
|
@ -81,6 +81,22 @@ public:
|
||||
*/
|
||||
virtual bool PrepareForExecute() override;
|
||||
|
||||
/**
|
||||
* @brief 设置线程频率
|
||||
* @param threadID: UINT32类型,线程ID
|
||||
* @param freq: double类型,线程频率
|
||||
* @details 设置线程频率接口
|
||||
*/
|
||||
void SetThreadFreqByID(uint32_t threadID, double freq);
|
||||
|
||||
/**
|
||||
* @brief 获取线程频率
|
||||
* @param threadID: UINT32类型,线程ID
|
||||
* @return double: 线程频率
|
||||
* @details 获取线程频率接口
|
||||
*/
|
||||
double GetThreadFreqByID(uint32_t threadID);
|
||||
|
||||
/**
|
||||
* @brief 仿真控制
|
||||
* @param objectId: 对象ID
|
||||
|
28
XNCore/XNTypeTraits.h
Normal file
28
XNCore/XNTypeTraits.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
template <typename T>
|
||||
struct is_std_array : std::false_type {
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_std_array<std::array<T, N>> : std::true_type {
|
||||
};
|
||||
|
||||
// 变量模板简化使用
|
||||
template <typename T>
|
||||
inline constexpr bool is_std_array_v = is_std_array<T>::value;
|
||||
|
||||
// 获取类型大小的辅助函数
|
||||
template <typename T>
|
||||
constexpr size_t getTypeSize()
|
||||
{
|
||||
if constexpr (is_std_array_v<T>) {
|
||||
// 对于std::array,计算所有元素的总大小
|
||||
return getTypeSize<typename T::value_type>() * std::tuple_size<T>::value;
|
||||
} else {
|
||||
return sizeof(T);
|
||||
}
|
||||
}
|
69
XNModels/XNAerodynamics/.vscode/settings.json
vendored
69
XNModels/XNAerodynamics/.vscode/settings.json
vendored
@ -7,6 +7,73 @@
|
||||
"*.ipp": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"optional": "cpp",
|
||||
"type_traits": "cpp"
|
||||
"type_traits": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"chrono": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"complex": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"regex": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ protected:
|
||||
XNAerodynamics(PrivateType *p);
|
||||
|
||||
public:
|
||||
virtual void Initialize(uint32_t initialType, uint32_t threadID) override;
|
||||
virtual void Initialize() override;
|
||||
virtual void PrepareForExecute() override;
|
||||
|
||||
public:
|
||||
|
@ -3,13 +3,12 @@
|
||||
#include <XNCore/XNModelObject.h>
|
||||
#include "../XNGroundHandlingInterface/XNGroundHandlingInterface.hpp"
|
||||
|
||||
class XNGroundHandlingPrivate;
|
||||
struct XNGroundHandlingPrivate;
|
||||
|
||||
class XNGROUNDHANDLING_EXPORT XNGroundHandling : public XNModelObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(XNGroundHandling)
|
||||
Q_DECLARE_PRIVATE(XNGroundHandling)
|
||||
XN_METATYPE(XNGroundHandling, XNModelObject)
|
||||
XN_DECLARE_PRIVATE(XNGroundHandling)
|
||||
XN_DECLARE_DDS()
|
||||
public:
|
||||
explicit XNGroundHandling(QObject *parent = nullptr);
|
||||
@ -18,9 +17,9 @@ public:
|
||||
protected:
|
||||
XNGroundHandling(XNGroundHandlingPrivate &dd, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
virtual void OnInitialize() override;
|
||||
virtual void OnPrepareForExecute() override;
|
||||
public:
|
||||
virtual void Initialize() override;
|
||||
virtual void PrepareForExecute() override;
|
||||
|
||||
public:
|
||||
virtual void StepUpdate() override;
|
||||
|
@ -1,20 +1,15 @@
|
||||
#pragma once
|
||||
#include <XNCore/XNModelObject_p.h>
|
||||
#include <DataModels/libSACSCGroundHandling_V2.0.27.1H/std_04_dll.h>
|
||||
#include <QMutex>
|
||||
|
||||
typedef void (*FunctionType)(ComacDataStructure_S *);
|
||||
|
||||
class XNGroundHandlingPrivate : public XNModelObjectPrivate
|
||||
{
|
||||
public:
|
||||
Q_DECLARE_PUBLIC(XNGroundHandling)
|
||||
|
||||
XNGroundHandlingPrivate(XNGroundHandling *q) : XNModelObjectPrivate(q) {}
|
||||
|
||||
struct XNGroundHandlingPrivate : public XNModelObjectPrivate {
|
||||
FunctionType _fun = nullptr;
|
||||
|
||||
ComacDataStructure_S _data;
|
||||
|
||||
QMutex _mutex;
|
||||
std::string _entryPointName = "_Z29SACSCGroundHandlingEntryPointP20ComacDataStructure_S";
|
||||
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user