ProfinetConnector/src/user_data/user_data.cpp

294 lines
8.4 KiB
C++
Raw Normal View History

#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)
{
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];
data_.uint64 = 0;
for (auto bit : bits_)
{
if (!j_bit.contains(bit.Name))
return false;
uint8_t value = j_bit[bit.Name].get<uint8_t>();
data_.uint64 |= static_cast<uint64_t>(value) << 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
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))
{
/// Данные в профинет передаются в формате 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));
}