261 lines
9.4 KiB
C++
261 lines
9.4 KiB
C++
#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); \
|
||
}
|