#include "program_config.hpp" #include #include #include "file_api.hpp" #include "json.hpp" #include #include "../profinet/profinet_data_map.hpp" #include 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(); pn_sett.cyclic_ms = j["ProfinetSettings"]["cyclic_ms"].get(); pn_sett.eth_dev_name = j["ProfinetSettings"]["eth_dev_name"].get(); pn_sett.profinet_device_config = j["ProfinetSettings"]["profinet_device_config"].get(); 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(); pnet_sett.station_name = sett["station_name"].get(); pnet_sett.station_name = sett["station_name"].get(); 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() ); pnet_sett.im_0.hw_revision = im_0["hw_revision"].get(); if (!im_0.contains("sw_revision")) return false; auto& sw_revision = im_0["sw_revision"]; string prefix = sw_revision["prefix"].get(); 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(); pnet_sett.im_0.sw_revision.bug_fix = sw_revision["bug_fix"].get(); pnet_sett.im_0.sw_revision.internal_change = sw_revision["internal_change"].get(); pnet_sett.im_0.revision_counter = im_0["revision_counter"].get(); pnet_sett.im_0.profile_id = hexstring_to_int(im_0["profile_id"].get()); pnet_sett.im_0.profile_specific_type = hexstring_to_int(im_0["profile_specific_type"].get()); pnet_sett.im_0.supported = hexstring_to_int(im_0["supported"].get()); pnet_sett.im_0.order_id = im_0["order_id"].get(); pnet_sett.im_0.serial_number = im_0["serial_number"].get(); if (!sett.contains("im_1")) return false; auto& im_1 = sett["im_1"]; pnet_sett.im_1.tag_function = im_1["tag_function"].get(); pnet_sett.im_1.tag_location = im_1["tag_location"].get(); pnet_sett.im_2.date = sett["im_2"]["date"].get(); pnet_sett.im_3.descriptor = sett["im_3"]["descriptor"].get(); pnet_sett.im_4.signature = sett["im_4"]["signature"].get(); pnet_sett.device_id = hexstring_to_int(sett["device_id"].get()); pnet_sett.oem_vendor_id = hexstring_to_int(sett["oem_vendor_id"].get()); pnet_sett.oem_device_id = hexstring_to_int(sett["oem_device_id"].get()); pnet_sett.send_hello = sett["send_hello"].get(); pnet_sett.min_device_interval = sett["min_device_interval"].get(); 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(submod_sett["cyc_inp_data_size"].get()); uint16_t out_data_len = static_cast(submod_sett["cyc_out_data_size"].get()); 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(parm_sett["data_size"].get()); 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(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()); ///Модуль auto& mod = p_data_map->p_mods[module_index]; ++module_index; /// Копируем параметры модуля mod.id = mod_id; mod.name = mod_set["name"].get(); auto& submodules_sett = mod_set["submodules"]; uint32_t submudules_number = submodules_sett.size(); if (submudules_number == 0) continue; ///Выделяем разделяемую память mod.p_submods = shared_data.allocateData(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()); auto& submod = mod.p_submods[submodules_index]; ++submodules_index; /// Копируем данные подмодуля submod.id = submod_id; submod.name = submod_sett["name"].get(); submod.cyc_data_dir = programconf_dataDirConvert(submod_sett["cyc_data_dir"].get()); submod.cyc_indata_len = static_cast(submod_sett["cyc_inp_data_size"].get()); submod.cyc_outdata_len = static_cast(submod_sett["cyc_out_data_size"].get()); /// Выделяем память под циклические данные if (submod.cyc_indata_len) { uint8_t * p_data = shared_data.allocateData(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(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(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(parm_sett["index"].get()); param.name = parm_sett["name"].get(); param.length = static_cast(parm_sett["data_size"].get()); if (param.length == 0) { return false; } /// Выделяем память для параметров uint8_t * p_data = shared_data.allocateData(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; }