ProfinetConnector/src/configuration/program_config.cpp
Vadim Sychev 3c9774a173 dev(UML-981): Решение некоторых проблем и документирование кода
1. Выделение разделяемой памяти учитывает количество требуемой памяти
2. Выложил собранные библиотеки pnet и osal
3. Добавил общее описание в readme.md
2022-08-05 14:58:37 +03:00

384 lines
12 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.

#include "program_config.hpp"
#include <filesystem>
#include <iostream>
#include "file_api.hpp"
#include "json.hpp"
#include <cstdint>
#include "../profinet/profinet_data_map.hpp"
#include <boost/interprocess/managed_shared_memory.hpp>
using namespace boost::interprocess;
using json = nlohmann::json;
using string = std::string;
static bool programconf_readfile(json& j, std::string& file_path)
{
///string config_str;
try
{
///config_str = fileapi_read_full_stream( fileapi_read_file(file_path) );
j = json::parse(fileapi_read_file(file_path));
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
return false;
}
return true;
}
bool programconf_getProfinetSettings(std::string file_path, ProfinetSettings& pn_sett)
{
json j;
if (!programconf_readfile(j, file_path))
{
return false;
}
pn_sett.ticks_us = j["ProfinetSettings"]["ticks_us"].get<int>();
pn_sett.cyclic_ms = j["ProfinetSettings"]["cyclic_ms"].get<int>();
pn_sett.eth_dev_name = j["ProfinetSettings"]["eth_dev_name"].get<string>();
pn_sett.profinet_device_config = j["ProfinetSettings"]["profinet_device_config"].get<string>();
return true;
}
static uint32_t hexstring_to_int(string s)
{
uint32_t n;
if (s.find("0x") != string::npos)
{
s = s.substr(2); //Игнорируем 0x
std::istringstream(s) >> std::hex >> n;
}
else
{
std::istringstream(s) >> std::dec >> n;
}
return n;
}
static bool programconf_getPnetDeviceSettings(json& j, ProfinetDeviceSettings& pnet_sett)
{
if (!j.contains("ProfinetDeviceSettings"))
return false;
auto& sett = j["ProfinetDeviceSettings"];
pnet_sett.product_name = sett["product_name"].get<string>();
pnet_sett.station_name = sett["station_name"].get<string>();
pnet_sett.station_name = sett["station_name"].get<string>();
if (!sett.contains("im_0"))
return false;
auto& im_0 = sett["im_0"];
pnet_sett.im_0.vendor_id = hexstring_to_int( im_0["vendor_id"].get<string>() );
pnet_sett.im_0.hw_revision = im_0["hw_revision"].get<int>();
if (!im_0.contains("sw_revision"))
return false;
auto& sw_revision = im_0["sw_revision"];
string prefix = sw_revision["prefix"].get<string>();
if (prefix.length())
{
pnet_sett.im_0.sw_revision.prefix = prefix.c_str()[0];
}
else
{
pnet_sett.im_0.sw_revision.prefix = ' ';
}
pnet_sett.im_0.sw_revision.functional_enhancement = sw_revision["functional_enhancement"].get<int>();
pnet_sett.im_0.sw_revision.bug_fix = sw_revision["bug_fix"].get<int>();
pnet_sett.im_0.sw_revision.internal_change = sw_revision["internal_change"].get<int>();
pnet_sett.im_0.revision_counter = im_0["revision_counter"].get<int>();
pnet_sett.im_0.profile_id = hexstring_to_int(im_0["profile_id"].get<string>());
pnet_sett.im_0.profile_specific_type = hexstring_to_int(im_0["profile_specific_type"].get<string>());
pnet_sett.im_0.supported = hexstring_to_int(im_0["supported"].get<string>());
pnet_sett.im_0.order_id = im_0["order_id"].get<string>();
pnet_sett.im_0.serial_number = im_0["serial_number"].get<string>();
if (!sett.contains("im_1"))
return false;
auto& im_1 = sett["im_1"];
pnet_sett.im_1.tag_function = im_1["tag_function"].get<string>();
pnet_sett.im_1.tag_location = im_1["tag_location"].get<string>();
pnet_sett.im_2.date = sett["im_2"]["date"].get<string>();
pnet_sett.im_3.descriptor = sett["im_3"]["descriptor"].get<string>();
pnet_sett.im_4.signature = sett["im_4"]["signature"].get<string>();
pnet_sett.device_id = hexstring_to_int(sett["device_id"].get<string>());
pnet_sett.oem_vendor_id = hexstring_to_int(sett["oem_vendor_id"].get<string>());
pnet_sett.oem_device_id = hexstring_to_int(sett["oem_device_id"].get<string>());
pnet_sett.send_hello = sett["send_hello"].get<bool>();
pnet_sett.min_device_interval = sett["min_device_interval"].get<int>();
return true;
}
static uint8_t programconf_dataDirConvert(string dir_str)
{
ProfinetSubmoduleDir out = PROFINET_SUBMOD_DIR_NO_IO;
if (dir_str == "PNET_DIR_IO")
{
out = PROFINET_SUBMOD_DIR_IO;
}
else if (dir_str == "PNET_DIR_INPUT")
{
out = PROFINET_SUBMOD_DIR_INPUT;
}
else if (dir_str == "PNET_DIR_OUTPUT")
{
out = PROFINET_SUBMOD_DIR_OUTPUT;
}
return out;
}
/**
* @brief Считаем общий размер данных требуемый всеми подмодулями: их циклическими данными и параметрами
* Пробегает по файлу конфигурации и считает размер требуемой памяти.
* @param j
* @param memory_size
* @return true
* @return false
*/
static bool programconf_calc_memory_size(json& j, uint32_t& memory_size)
{
if (!j.contains("ProfinetDeviceModulesSettings"))
return false;
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
memory_size = sizeof(ProfinetData_Map) + modules_sett.size() * sizeof(ProfinetData_Module);
for (auto& mod_set : modules_sett)
{
auto& submodules_sett = mod_set["submodules"];
memory_size += submodules_sett.size() * sizeof(ProfinetData_Submodule);
for (auto& submod_sett : submodules_sett)
{
uint16_t in_data_len = static_cast<uint16_t>(submod_sett["cyc_inp_data_size"].get<int>());
uint16_t out_data_len = static_cast<uint16_t>(submod_sett["cyc_out_data_size"].get<int>());
memory_size+= in_data_len + out_data_len;
///Параметры подмодуля
auto& params_sett = submod_sett["parameters"];
memory_size += params_sett.size() * sizeof(ProfinetData_Parameter);
/// Записываем параметры в подмодуль
for (auto& parm_sett : params_sett)
{
uint16_t data_size = static_cast<uint16_t>(parm_sett["data_size"].get<int>());
memory_size += data_size;
}
}
}
return true;
}
static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
{
if (!j.contains("ProfinetDeviceModulesSettings"))
return false;
uint32_t required_mem_size;
if (!programconf_calc_memory_size(j, required_mem_size))
return false;
/// Проверяем достаточно ли у нас выделено памяти под текущую конфигурацию
/// Если недостаточно, то выделяем недостающее.
shared_data.checkMemorySize(required_mem_size);
/// Далее идет выделение
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
///Узнаем количество модулей
uint32_t mudules_number = modules_sett.size();
if (mudules_number == 0)
{
return false;
}
///Выделяем разделяемую память
p_data_map->p_mods = shared_data.allocateData<ProfinetData_Module>(mudules_number);
if (p_data_map->p_mods == nullptr)
{
return false;
}
p_data_map->mods_nbr = mudules_number;
uint32_t module_index = 0;
for (auto& mod_set : modules_sett)
{
uint32_t mod_id = hexstring_to_int(mod_set["id"].get<string>());
///Модуль
auto& mod = p_data_map->p_mods[module_index];
++module_index;
/// Копируем параметры модуля
mod.id = mod_id;
mod.name = mod_set["name"].get<string>();
auto& submodules_sett = mod_set["submodules"];
uint32_t submudules_number = submodules_sett.size();
if (submudules_number == 0)
continue;
///Выделяем разделяемую память
mod.p_submods = shared_data.allocateData<ProfinetData_Submodule>(submudules_number);
if (mod.p_submods == nullptr)
{
return false;
}
mod.submods_nbr = submudules_number;
uint32_t submodules_index = 0;
for (auto& submod_sett : submodules_sett)
{
uint32_t submod_id = hexstring_to_int(submod_sett["id"].get<string>());
auto& submod = mod.p_submods[submodules_index];
++submodules_index;
/// Копируем данные подмодуля
submod.id = submod_id;
submod.name = submod_sett["name"].get<string>();
submod.cyc_data_dir = programconf_dataDirConvert(submod_sett["cyc_data_dir"].get<string>());
submod.cyc_indata_len = static_cast<uint16_t>(submod_sett["cyc_inp_data_size"].get<int>());
submod.cyc_outdata_len = static_cast<uint16_t>(submod_sett["cyc_out_data_size"].get<int>());
/// Выделяем память под циклические данные
if (submod.cyc_indata_len)
{
uint8_t * p_data = shared_data.allocateData<uint8_t>(submod.cyc_indata_len);
if (p_data == nullptr)
{
return false;
}
submod.inp_data.Init(p_data, submod.cyc_indata_len);
}
if (submod.cyc_outdata_len)
{
uint8_t * p_data = shared_data.allocateData<uint8_t>(submod.cyc_outdata_len);
if (p_data == nullptr)
{
return false;
}
submod.out_data.Init(p_data, submod.cyc_outdata_len);
}
///Параметры подмодуля
auto& params_sett = submod_sett["parameters"];
uint32_t params_nbr = params_sett.size();
///Выделяем разделяемую память
submod.p_params = shared_data.allocateData<ProfinetData_Parameter>(params_nbr);
if (submod.p_params == nullptr)
{
return false;
}
submod.params_nbr = params_nbr;
uint32_t params_index = 0;
/// Записываем параметры в подмодуль
for (auto& parm_sett : params_sett)
{
auto& param = submod.p_params[params_index];
++params_index;
param.index = static_cast<uint32_t>(parm_sett["index"].get<int>());
param.name = parm_sett["name"].get<string>();
param.length = static_cast<uint16_t>(parm_sett["data_size"].get<int>());
if (param.length == 0)
{
return false;
}
/// Выделяем память для параметров
uint8_t * p_data = shared_data.allocateData<uint8_t>(param.length);
if (p_data == nullptr)
{
return false;
}
param.data.Init(p_data, param.length);
}
}
}
return true;
}
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
{
json j;
if (!programconf_readfile(j, file_path))
{
return false;
}
if (!programconf_getPnetDeviceSettings(j, pn_sett))
{
return false;
}
if (!programconf_getProfinetModulesSettings(j, p_data_map, shared_data))
{
return false;
}
return true;
}