#pragma once #include "XNObject.h" #include "XNByteArray.h" #include "XNTypeTraits.h" #include // 定义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 XNByteArray getByteArray(eprosima::fastcdr::optional data) { XNByteArray result(getTypeSize()); if constexpr (std::is_arithmetic_v) { 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) { if (data) { return getByteArrayFromStdArray(data.value()); } else { T zero = {}; return getByteArrayFromStdArray(zero); } } else { static_assert(std::is_arithmetic_v || is_std_array_v, "Type must be arithmetic or std::array"); } return result; } /** * @brief 设置指定变量的字节数据,用于网络通信 * @param data: 数据 * @param byteArray: 字节数组 */ template void setByteArray(eprosima::fastcdr::optional &data, const XNByteArray &byteArray) { if (byteArray.size() < getTypeSize()) return; if constexpr (std::is_arithmetic_v) { T temp; std::memcpy(&temp, byteArray.data(), sizeof(T)); data = temp; } else if constexpr (is_std_array_v) { if (!data) { data = T{}; } setByteArrayFromStdArray(data.value(), byteArray); } else { static_assert(std::is_arithmetic_v || is_std_array_v, "Type must be arithmetic or std::array"); } } /** * @brief 获取指定数组变量的字节数据,用于网络通信 * @param data: 数据 * @return 字节数组 */ template XNByteArray getByteArrayFromStdArray(const std::array &data) { XNByteArray result(getTypeSize() * N); for (std::size_t i = 0; i < N; ++i) { if constexpr (std::is_arithmetic_v) { std::memcpy(result.data() + i * getTypeSize(), &data[i], getTypeSize()); } else { XNByteArray subArray = getByteArrayFromStdArray(data[i]); std::memcpy(result.data() + i * getTypeSize(), subArray.data(), getTypeSize()); } } return result; } /** * @brief 设置指定数组变量的字节数据,用于网络通信 * @param data: 数据 * @param byteArray: 字节数组 */ template void setByteArrayFromStdArray(std::array &data, const XNByteArray &byteArray) { if (byteArray.size() < getTypeSize() * N) return; for (std::size_t i = 0; i < N; ++i) { if constexpr (std::is_arithmetic_v) { std::memcpy(&data[i], byteArray.data() + i * getTypeSize(), getTypeSize()); } else { XNByteArray subArray(byteArray.data() + i * getTypeSize(), getTypeSize()); setByteArrayFromStdArray(data[i], subArray); } } } /** * @brief 获取指定变量的字符串数据,用于JSON前端 * @param data: 数据 * @return: 数据(字符串格式) */ template std::string getString(eprosima::fastcdr::optional data) { if constexpr (std::is_arithmetic_v) { if (data) { return std::to_string(data.value()); } else { return std::to_string(0); } } else if constexpr (std::is_same_v) { if (data) { return getStringFromStdArray(data.value()); } else { T zero = {}; return getStringFromStdArray(zero); } } return std::string(); } /** * @brief 获取指定数组变量的字符串数据,用于JSON前端 * @param data: 数据 * @return: 数据(字符串格式) */ template std::string getStringFromStdArray(std::array data) { std::stringstream ss; for (std::size_t i = 0; i < N; ++i) { if (i > 0) ss << ","; if constexpr (std::is_arithmetic_v) { 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 func; size_t size; }; std::unordered_map> getDataFunction; std::vector getByteArrayFunction; std::unordered_map> setByteArrayFunction; std::mutex mutex; uint8_t header[5]{}; // 固定大小的头部 size_t headerSize = 5; }; #define MAP_DATA_FUNC(NAME) \ getDataFunction[#NAME] = [this]() { return getString(data.NAME()); }; \ getByteArrayFunction.push_back( \ {[this]() { return getByteArray(data.NAME()); }, getTypeSize()}); \ 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) { \ model_data->NAME = temp; \ } else if constexpr (std::is_std_array_v) { \ size_t arraySize = std::tuple_size::value; \ for (size_t i = 0; i < arraySize; ++i) { \ if constexpr (std::is_arithmetic_v) { \ model_data->NAME[i] = temp[i]; \ } else if constexpr (std::is_std_array_v) { \ size_t arraySize2 = std::tuple_size::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) { \ data.NAME(model_data->NAME); \ } else if constexpr (std::is_std_array_v) { \ using thisType = typename decltype(data.NAME())::type; \ thisType temp; \ size_t arraySize1 = std::tuple_size::value; \ using subType = thisType::value_type; \ if constexpr (std::is_arithmetic_v) { \ for (size_t i = 0; i < arraySize1; ++i) { \ temp[i] = model_data->NAME[i]; \ } \ } else if constexpr (std::is_std_array_v) { \ size_t arraySize2 = std::tuple_size::value; \ std::array 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); \ }