307 lines
8.8 KiB
C++
307 lines
8.8 KiB
C++
#include "user_data.hpp"
|
||
#include <bit>
|
||
#include "../endian/endian.hpp"
|
||
#include <iostream>
|
||
|
||
using json = nlohmann::json;
|
||
|
||
const std::map<UserData::UserDataTypes, uint32_t> UserData::data_size{
|
||
{UserDataTypes::BOOL, 1},
|
||
{UserDataTypes::UINT8, 1},
|
||
{UserDataTypes::UINT16, 2},
|
||
{UserDataTypes::UINT32, 4},
|
||
{UserDataTypes::UINT64, 8},
|
||
{UserDataTypes::INT64, 8},
|
||
{UserDataTypes::INT32, 4},
|
||
{UserDataTypes::INT16, 2},
|
||
{UserDataTypes::INT8, 1},
|
||
{UserDataTypes::FLOAT32, 4},
|
||
{UserDataTypes::FLOAT64, 8}
|
||
};
|
||
|
||
const std::map<std::string, UserData::UserDataTypes> UserData::data_corr {
|
||
{"Boolean", UserDataTypes::BOOL},
|
||
{"Unsigned8", UserDataTypes::UINT8},
|
||
{"Unsigned16", UserDataTypes::UINT16},
|
||
{"Unsigned32", UserDataTypes::UINT32},
|
||
{"Unsigned64", UserDataTypes::UINT64},
|
||
{"Integer64", UserDataTypes::INT64},
|
||
{"Integer32", UserDataTypes::INT32},
|
||
{"Integer16", UserDataTypes::INT16},
|
||
{"Integer8", UserDataTypes::INT8},
|
||
{"Float32", UserDataTypes::FLOAT32},
|
||
{"Float64", UserDataTypes::FLOAT64}
|
||
};
|
||
|
||
bool UserData::putBit(std::string& bit_name, uint32_t bit_pos)
|
||
{
|
||
if (bits_.size() >= size * 8)
|
||
return false; /// Все биты уже заняты
|
||
|
||
bits_.push_back(UserDataBit{bit_name, bit_pos});
|
||
|
||
return true;
|
||
}
|
||
|
||
bool UserData::toRpcJson(nlohmann::json& j) const
|
||
{
|
||
if (bits_.empty())
|
||
{
|
||
switch(type)
|
||
{
|
||
case UserDataTypes::UINT8:
|
||
{
|
||
j[name] = data_.uint8[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT16:
|
||
{
|
||
j[name] = data_.uint16[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT32:
|
||
{
|
||
j[name] = data_.uint32[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT64:
|
||
{
|
||
j[name] = data_.uint64;
|
||
}
|
||
break;
|
||
case UserDataTypes::INT8:
|
||
{
|
||
j[name] = data_.int8[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::INT16:
|
||
{
|
||
j[name] = data_.int16[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::INT32:
|
||
{
|
||
j[name] = data_.int32[0];
|
||
}
|
||
break;
|
||
case UserDataTypes::INT64:
|
||
{
|
||
j[name] = data_.int64;
|
||
}
|
||
break;
|
||
case UserDataTypes::FLOAT32:
|
||
{
|
||
j[name] = data_.float32;
|
||
}
|
||
break;
|
||
case UserDataTypes::FLOAT64:
|
||
{
|
||
j[name] = data_.float64;
|
||
}
|
||
break;
|
||
case UserDataTypes::BOOL:
|
||
{
|
||
j[name] = data_.boolean;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/// Только беззнаковые типы могут быть битовыми
|
||
if ((type < UserDataTypes::UINT8) || (type > UserDataTypes::UINT64))
|
||
return false;
|
||
|
||
json& j_bit = j[name];
|
||
for (auto& bit : bits_)
|
||
{
|
||
j_bit[bit.Name] = ( data_.uint64 & (1 << bit.Pos) ) ? (1) : (0);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool UserData::fromRpcJson(const nlohmann::json& j)
|
||
{
|
||
if (!j.contains(name))
|
||
return false;
|
||
|
||
if (!bits_.size()) /// Данные
|
||
{
|
||
switch(type)
|
||
{
|
||
case UserDataTypes::UINT8:
|
||
{
|
||
data_.uint8[0] = j[name].get<uint8_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT16:
|
||
{
|
||
data_.uint16[0] = j[name].get<uint16_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT32:
|
||
{
|
||
data_.uint32[0] = j[name].get<uint32_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::UINT64:
|
||
{
|
||
data_.uint64 = j[name].get<uint64_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::INT8:
|
||
{
|
||
data_.int8[0] = j[name].get<int8_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::INT16:
|
||
{
|
||
data_.int16[0] = j[name].get<int16_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::INT32:
|
||
{
|
||
data_.int32[0] = j[name].get<int32_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::INT64:
|
||
{
|
||
data_.int64 = j[name].get<int64_t>();
|
||
}
|
||
break;
|
||
case UserDataTypes::FLOAT32:
|
||
{
|
||
data_.float32 = j[name].get<float>();
|
||
}
|
||
break;
|
||
case UserDataTypes::FLOAT64:
|
||
{
|
||
data_.float64 = j[name].get<double>();
|
||
}
|
||
break;
|
||
case UserDataTypes::BOOL:
|
||
{
|
||
data_.boolean = j[name].get<bool>();
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
else /// Биты
|
||
{
|
||
/// Только беззнаковые типы могут быть битовыми
|
||
if ((type < UserDataTypes::UINT8) || (type > UserDataTypes::UINT64))
|
||
return false;
|
||
|
||
const json& j_bit = j[name];
|
||
|
||
for (auto bit : bits_)
|
||
{
|
||
/// Проверяем есть ли в принятой датаграмме бит
|
||
if (!j_bit.contains(bit.Name))
|
||
continue;
|
||
|
||
uint8_t value = j_bit[bit.Name].get<uint8_t>();
|
||
|
||
if (value == 0)
|
||
{
|
||
/// Очистка бита
|
||
data_.uint64&= ~(static_cast<uint64_t>(1) << bit.Pos);
|
||
}
|
||
else if (value == 1)
|
||
{
|
||
/// Установка бита
|
||
data_.uint64 |= (static_cast<uint64_t>(1) << bit.Pos);
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool UserData::convertBinaryToJson(const std::vector<uint8_t>& vect_inp, nlohmann::json& j_out)
|
||
{
|
||
/// Вектор должен иметь подходящий размер
|
||
if (vect_inp.size() < (size + data_offset_))
|
||
return false;
|
||
|
||
/// Копируем бинарные данные из вектора с учетом офсета и эндиана
|
||
insertData(vect_inp);
|
||
/// Преобразовываем бинарные данные в json
|
||
toRpcJson(j_out);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool UserData::convertJsonToBinary(const nlohmann::json& j_inp, std::vector<uint8_t>& vect_out)
|
||
{
|
||
/// Вектор должен иметь подходящий размер
|
||
if (vect_out.size() < (size + data_offset_))
|
||
return false;
|
||
|
||
/// Берем данные из json и преобразуем их в бинарный вид
|
||
fromRpcJson(j_inp);
|
||
/// Вставляем бинарные данные с учетом офсета в вектор
|
||
extractData(vect_out);
|
||
|
||
return true;
|
||
}
|
||
|
||
void UserData::extractData(std::vector<uint8_t>& vect)
|
||
{
|
||
/// Копируем данные в vect
|
||
uint8_t buf[size];
|
||
std::copy(&data_.uint8[0], &data_.uint8[size], buf);
|
||
/// Данные в профинет передаются в формате BigEndian
|
||
/// преобразуем из Little в Big
|
||
if (swap_)
|
||
{
|
||
endian_swapbytes(&buf[0], size);
|
||
}
|
||
/// Вставляем данные в вектор по офсету
|
||
std::copy(buf, &buf[size], vect.begin() + data_offset_);
|
||
}
|
||
|
||
void UserData::insertData(const std::vector<uint8_t>& vect)
|
||
{
|
||
/// Копируем данные из вектора
|
||
std::copy(&vect[data_offset_], &vect[data_offset_ + size], data_.uint8);
|
||
/// Конвертим
|
||
if ((type >= UserDataTypes::UINT16) &&
|
||
(type <= UserDataTypes::FLOAT64) && swap_)
|
||
{
|
||
/// Данные в профинет передаются в формате BigEndian
|
||
/// преобразуем из Big в Little
|
||
endian_swapbytes(data_.uint8, size);
|
||
}
|
||
}
|
||
|
||
/*void UserData::init(std::string& Name, std::string& DataType, uint16_t offset)
|
||
{
|
||
name = Name;
|
||
type = data_corr.at(DataType);
|
||
size = data_size.at(type);
|
||
data_offset_ = offset;
|
||
};*/
|
||
|
||
SubmoduleUserData& UserData_addNewSubmod(uint32_t mod_id, uint32_t submod_id, UserDataMap& user_data_map)
|
||
{
|
||
uint64_t key = (static_cast<uint64_t>(mod_id) << 32) + submod_id;
|
||
return user_data_map[key];
|
||
}
|
||
|
||
SubmoduleUserData& UserData_getSubmod(uint32_t mod_id, uint32_t submod_id, UserDataMap& user_data_map)
|
||
{
|
||
uint64_t key = (static_cast<uint64_t>(mod_id) << 32) + submod_id;
|
||
return user_data_map.at(key);
|
||
}
|
||
|
||
int UserData::getDataSize(const std::string& type_name)
|
||
{
|
||
if (!data_corr.contains(type_name))
|
||
return 0;
|
||
|
||
return data_size.at(data_corr.at(type_name));
|
||
}
|