XNSim/XNCore/XNDDSInterface.h

261 lines
9.4 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 "XNObject.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) = 0;
/**
* @brief 获取该接口的UDP包
* @return 字节数组
*/
XNByteArray getUDPPackage();
/**
* @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>
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 (std::is_same_v<T, std::string>) {
if (data) {
return getStringFromStdArray(data.value());
} else {
T zero = {};
return getStringFromStdArray(zero);
}
}
return std::string();
}
/**
* @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();
}
private:
/**
* @brief 通过变量名获取指定的数据
* @param varName: 变量名
* @return: 数据(字符串格式)
*/
std::string getData(const std::string &varName);
protected:
struct ByteArrayFunc {
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_DATA_FUNC(NAME) \
getDataFunction[#NAME] = [this]() { return getString(data.NAME()); }; \
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 (std::is_std_array_v<decltype(temp)>) { \
size_t arraySize = std::tuple_size<decltype(temp)>::value; \
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 (std::is_std_array_v<decltype(temp[i])>) { \
size_t arraySize2 = std::tuple_size<decltype(temp[i])>::value; \
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(data.NAME())::type>) { \
data.NAME(model_data->NAME); \
} else if constexpr (std::is_std_array_v<decltype(data.NAME())::type>) { \
using thisType = typename decltype(data.NAME())::type; \
thisType temp; \
size_t arraySize1 = std::tuple_size<thisType>::value; \
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 (std::is_std_array_v<subType>) { \
size_t arraySize2 = std::tuple_size<subType>::value; \
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]; \
} \
} \
} \
data.NAME(temp); \
}