XNSim/XNCore/XNDDSInterface.h
2025-05-22 08:53:29 +08:00

355 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include "XNFramework.h"
#include "XNDDSManager.h"
#include "XNByteArray.h"
#include "XNTypeTraits.h"
#include <stdexcept>
// 定义UDP包的最大大小
constexpr size_t MAX_UDP_PACKET_SIZE = 40000;
class XNDDSInterface
{
public:
XNDDSInterface() = default;
virtual ~XNDDSInterface() = default;
public:
/**
* @brief 初始化
* @param framework: 框架
*/
virtual void Initialize(XNFrameworkPtr framework, uint32_t modelID) = 0;
/**
* @brief 获取该接口的UDP包
* @return 字节数组
*/
XNByteArray getUDPPackage();
/**
* @brief 批量获取指定变量的数据
* @param varNames: 变量名列表
* @return: 变量名到数据的映射
*/
std::unordered_map<std::string, std::string> getStringData(std::vector<std::string> varNames);
/**
* @brief 批量设置指定变量的数据
* @param data: 变量名到数据的映射
*/
void setDataByString(std::unordered_map<std::string, std::string> data);
protected:
/**
* @brief 获取指定变量的字节数据,用于网络通信
* @param data: 数据
* @return 字节数组
*/
template <typename T>
XNByteArray getByteArray(eprosima::fastcdr::optional<T> data)
{
XNByteArray result(getTypeSize<T>());
if constexpr (std::is_arithmetic_v<T>) {
if (data) {
std::memcpy(result.data(), &data.value(), sizeof(T));
} else {
T zero = 0;
std::memcpy(result.data(), &zero, sizeof(T));
}
} else if constexpr (is_std_array_v<T>) {
if (data) {
return getByteArrayFromStdArray(data.value());
} else {
T zero = {};
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>
XNByteArray getByteArrayFromStdArray(const std::array<T, N> &data)
{
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(&data[i], byteArray.data() + i * getTypeSize<T>(), getTypeSize<T>());
} else {
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)
{
if constexpr (std::is_arithmetic_v<T>) {
if (data) {
return std::to_string(data.value());
} else {
return std::to_string(0);
}
} else if constexpr (is_std_array_v<T>) {
if (data) {
return getStringFromStdArray(data.value());
} else {
T zero = {};
return getStringFromStdArray(zero);
}
}
return std::string();
}
/**
* @brief 通过字符串数据设置指定变量用于JSON前端
* @param data: 数据
* @param value: 字符串数据
*/
template <typename T>
void setDataFromString(eprosima::fastcdr::optional<T> &data, const std::string &value)
{
if constexpr (std::is_arithmetic_v<T>) {
if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) {
data = std::stod(value);
} else {
data = std::stoll(value);
}
} else if constexpr (is_std_array_v<T>) {
// 解析输入字符串
std::stringstream ss(value);
std::string item;
std::vector<std::string> items;
while (std::getline(ss, item, ',')) {
items.push_back(item);
}
T temp;
setStdArrayFromString(temp, items, 0);
data = temp;
}
}
/**
* @brief 获取指定数组变量的字符串数据用于JSON前端
* @param data: 数据
* @return: 数据(字符串格式)
*/
template <typename T, std::size_t N>
std::string getStringFromStdArray(std::array<T, N> data)
{
std::stringstream ss;
for (std::size_t i = 0; i < N; ++i) {
if (i > 0)
ss << ",";
if constexpr (std::is_arithmetic_v<T>) {
ss << data[i];
} else {
ss << getStringFromStdArray(data[i]);
}
}
return ss.str();
}
/**
* @brief 通过字符串数据设置指定数组变量用于JSON前端
* @param data: 数据
* @param value: 字符串数据,格式为"数字,数字,..."
* @param start_pos: 当前数组在输入字符串中的起始位置
* @return 处理完当前数组后,下一个数组的起始位置
* @throw std::runtime_error: 当输入数据格式不正确时抛出异常
*/
template <typename T, std::size_t N>
size_t setStdArrayFromString(std::array<T, N> &data, const std::vector<std::string> &value,
size_t start_pos = 0)
{
// 递归处理每个元素
for (std::size_t i = 0; i < N; ++i) {
try {
if constexpr (std::is_arithmetic_v<T>) {
// 对于基本类型,直接转换
if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) {
data[i] = static_cast<T>(std::stod(value[start_pos + i]));
} else {
data[i] = static_cast<T>(std::stoll(value[start_pos + i]));
}
} else if constexpr (is_std_array_v<T>) {
// 对于嵌套数组,递归处理
start_pos = setStdArrayFromString(data[i], value, start_pos + i);
} else {
static_assert(std::is_arithmetic_v<T> || is_std_array_v<T>,
"Type must be arithmetic or std::array");
}
} catch (const std::exception &e) {
throw std::runtime_error("Error parsing element " + std::to_string(i) + ": "
+ e.what());
}
}
return start_pos + N;
}
template <typename T1, typename T2>
void assign_value_get(eprosima::fastcdr::optional<T1> &data, T2 &model_data)
{
if (data) {
auto temp = data.value();
if constexpr (std::is_arithmetic_v<T1>) {
model_data = temp;
} else if constexpr (is_std_array_v<T1>) {
size_t arraySize = array_size_v<T1>;
for (size_t i = 0; i < arraySize; ++i) {
auto temp2 = temp[i];
if constexpr (std::is_arithmetic_v<T2>) {
model_data[i] = temp2;
} else if constexpr (is_std_array_v<T2>) {
size_t arraySize2 = array_size_v<T2>;
for (size_t j = 0; j < arraySize2; ++j) {
model_data[i][j] = temp2[j];
}
}
}
}
}
}
virtual void clearOutData() {}
virtual void sendOutData() {}
protected:
struct ByteArrayFunc {
std::function<XNByteArray(void)> func;
size_t size;
};
std::unordered_map<std::string, std::function<std::string()>> getDataFunction;
std::unordered_map<std::string, std::function<void(std::string)>> setDataFunction;
std::vector<ByteArrayFunc> getByteArrayFunction;
std::unordered_map<std::string, std::function<void(XNByteArray)>> setByteArrayFunction;
std::mutex mutex;
uint8_t header[5]{}; // 固定大小的头部
size_t headerSize = 5;
FAST_DDS_MACRO::DataWriter *dataWriter;
};
#define MAP_DATA_FUNC(NAME) \
getDataFunction[#NAME] = [this]() { return getString(data.NAME()); }; \
setDataFunction[#NAME] = [this](std::string value) { \
setDataFromString(out_data.NAME(), value); \
}; \
getByteArrayFunction.push_back( \
{[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()) { \
auto temp = data.NAME().value(); \
if constexpr (std::is_arithmetic_v<decltype(temp)>) { \
model_data->NAME = temp; \
} else if constexpr (is_std_array_v<decltype(temp)>) { \
size_t arraySize = array_size_v<decltype(temp)>; \
for (size_t i = 0; i < arraySize; ++i) { \
if constexpr (std::is_arithmetic_v<decltype(temp[i])>) { \
model_data->NAME[i] = temp[i]; \
} else if constexpr (is_std_array_v<decltype(temp[i])>) { \
size_t arraySize2 = array_size_v<decltype(temp[i])>; \
for (size_t j = 0; j < arraySize2; ++j) { \
model_data->NAME[i][j] = temp[i][j]; \
} \
} \
} \
} \
}
#define ASSIGN_VALUE_SET(NAME) \
if constexpr (std::is_arithmetic_v<decltype(out_data.NAME())::type>) { \
out_data.NAME(model_data->NAME); \
} else if constexpr (is_std_array_v<decltype(out_data.NAME())::type>) { \
using thisType = typename decltype(out_data.NAME())::type; \
thisType temp; \
size_t arraySize1 = array_size_v<thisType>; \
using subType = thisType::value_type; \
if constexpr (std::is_arithmetic_v<subType>) { \
for (size_t i = 0; i < arraySize1; ++i) { \
temp[i] = model_data->NAME[i]; \
} \
} else if constexpr (is_std_array_v<subType>) { \
size_t arraySize2 = array_size_v<subType>; \
std::array<subType, arraySize1> temp; \
for (size_t i = 0; i < arraySize1; ++i) { \
for (size_t j = 0; j < arraySize2; ++j) { \
temp[i][j] = model_data->NAME[i][j]; \
} \
} \
} \
out_data.NAME(temp); \
}