2022-07-29 09:25:07 +03:00
|
|
|
|
#include "program_config.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
#include "file_api.hpp"
|
|
|
|
|
|
#include "json.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
#include "../profinet/profinet_data_map.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/interprocess/managed_shared_memory.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using namespace boost::interprocess;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
static uint8_t programconf_dataDirConvert(string dir_str)
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
2022-08-03 17:01:01 +03:00
|
|
|
|
ProfinetSubmoduleDir out = PROFINET_SUBMOD_DIR_NO_IO;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
|
|
|
|
|
if (dir_str == "PNET_DIR_IO")
|
|
|
|
|
|
{
|
2022-08-03 17:01:01 +03:00
|
|
|
|
out = PROFINET_SUBMOD_DIR_IO;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
else if (dir_str == "PNET_DIR_INPUT")
|
|
|
|
|
|
{
|
2022-08-03 17:01:01 +03:00
|
|
|
|
out = PROFINET_SUBMOD_DIR_INPUT;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
else if (dir_str == "PNET_DIR_OUTPUT")
|
|
|
|
|
|
{
|
2022-08-03 17:01:01 +03:00
|
|
|
|
out = PROFINET_SUBMOD_DIR_OUTPUT;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-05 14:58:37 +03:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief Считаем общий размер данных требуемый всеми подмодулями: их циклическими данными и параметрами
|
|
|
|
|
|
* Пробегает по файлу конфигурации и считает размер требуемой памяти.
|
|
|
|
|
|
* @param j
|
|
|
|
|
|
* @param memory_size
|
|
|
|
|
|
* @return true
|
|
|
|
|
|
* @return false
|
|
|
|
|
|
*/
|
|
|
|
|
|
static bool programconf_calc_memory_size(json& j, uint32_t& memory_size)
|
2022-08-03 17:01:01 +03:00
|
|
|
|
{
|
2022-07-29 09:25:07 +03:00
|
|
|
|
if (!j.contains("ProfinetDeviceModulesSettings"))
|
|
|
|
|
|
return false;
|
2022-08-05 14:58:37 +03:00
|
|
|
|
|
|
|
|
|
|
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);
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-05 14:58:37 +03:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-03 17:01:01 +03:00
|
|
|
|
|
2022-08-05 14:58:37 +03:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
/// Далее идет выделение
|
|
|
|
|
|
|
2022-07-29 09:25:07 +03:00
|
|
|
|
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
|
2022-08-03 17:01:01 +03:00
|
|
|
|
///Узнаем количество модулей
|
|
|
|
|
|
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;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
|
|
|
|
|
for (auto& mod_set : modules_sett)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t mod_id = hexstring_to_int(mod_set["id"].get<string>());
|
2022-08-03 17:01:01 +03:00
|
|
|
|
|
|
|
|
|
|
///Модуль
|
|
|
|
|
|
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();
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
if (submudules_number == 0)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
///Выделяем разделяемую память
|
|
|
|
|
|
mod.p_submods = shared_data.allocateData<ProfinetData_Submodule>(submudules_number);
|
|
|
|
|
|
|
|
|
|
|
|
if (mod.p_submods == nullptr)
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
mod.submods_nbr = submudules_number;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t submodules_index = 0;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
|
|
|
|
|
for (auto& submod_sett : submodules_sett)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t submod_id = hexstring_to_int(submod_sett["id"].get<string>());
|
2022-08-03 17:01:01 +03:00
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
submod.inp_data.Init(p_data, submod.cyc_indata_len);
|
|
|
|
|
|
}
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
///Параметры подмодуля
|
|
|
|
|
|
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)
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
submod.params_nbr = params_nbr;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t params_index = 0;
|
|
|
|
|
|
|
2022-07-29 09:25:07 +03:00
|
|
|
|
/// Записываем параметры в подмодуль
|
|
|
|
|
|
for (auto& parm_sett : params_sett)
|
|
|
|
|
|
{
|
2022-08-03 17:01:01 +03:00
|
|
|
|
auto& param = submod.p_params[params_index];
|
|
|
|
|
|
++params_index;
|
2022-07-29 09:25:07 +03:00
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
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)
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2022-08-03 17:01:01 +03:00
|
|
|
|
/// Выделяем память для параметров
|
|
|
|
|
|
uint8_t * p_data = shared_data.allocateData<uint8_t>(param.length);
|
|
|
|
|
|
if (p_data == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
param.data.Init(p_data, param.length);
|
2022-07-29 09:25:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-05 14:58:37 +03:00
|
|
|
|
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
|
|
|
|
|
|
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
json j;
|
|
|
|
|
|
|
|
|
|
|
|
if (!programconf_readfile(j, file_path))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!programconf_getPnetDeviceSettings(j, pn_sett))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-03 17:01:01 +03:00
|
|
|
|
if (!programconf_getProfinetModulesSettings(j, p_data_map, shared_data))
|
2022-07-29 09:25:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-05 14:58:37 +03:00
|
|
|
|
|