dev(UML-981): Добавил новые rpc json запросы
Эти запросы позволяют получать именованные данные датаграммы profinet
This commit is contained in:
parent
1f86ae7b2a
commit
fe46a8b03f
@ -8,14 +8,26 @@
|
||||
|
||||
#define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля
|
||||
#define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля
|
||||
|
||||
#define ECHO_INPUT_DATA_SIZE 8
|
||||
#define ECHO_OUTPUT_DATA_SIZE 8
|
||||
#define ECHO_PARAMETER_GAIN_IDX 125 /// Индекс параметра Gain для подмодуля ECHO
|
||||
|
||||
#define BIT_MODULE_ID 0x00000032
|
||||
#define BIT_SUBMOD_ID 0x00000132
|
||||
#define BIT_INPUT_DATA_SIZE 1
|
||||
#define BIT_OUTPUT_DATA_SIZE 1
|
||||
#define BIT_PARAMETER_1_IDX 123
|
||||
#define BIT_PARAMETER_2_IDX 124
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
uint32_t Echo_Gain = 0;
|
||||
|
||||
uint32_t bit_param_1 = 0;
|
||||
uint32_t bit_param_2 = 0;
|
||||
|
||||
|
||||
struct EchoData {
|
||||
float data_f;
|
||||
uint32_t data_i;
|
||||
@ -50,6 +62,53 @@ std::shared_ptr< std::ostream > p_output_stream_;
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void getParameter(json& jx, std::vector<uint8_t>& in_vect, uint8_t * pParam, uint16_t param_size)
|
||||
{
|
||||
in_vect.clear();
|
||||
in_vect = jx["data"]["bytes"].get<std::vector<uint8_t>>();
|
||||
|
||||
if (in_vect.size() == param_size)
|
||||
{
|
||||
std::copy(in_vect.begin(), in_vect.end(), pParam);
|
||||
|
||||
if (param_size == 4)
|
||||
{
|
||||
endian_convert_32(pParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void requestParam(json& j_request, uint32_t mod_id, uint32_t submod_id, uint32_t param_idx)
|
||||
{
|
||||
json j_data;
|
||||
j_data["module_id"] = mod_id;
|
||||
j_data["submodule_id"] = submod_id;
|
||||
j_data["param_index"] = param_idx;
|
||||
j_request["params"].push_back(j_data);
|
||||
}
|
||||
|
||||
void requestCyclic(json& j_request, uint32_t mod_id, uint32_t submod_id)
|
||||
{
|
||||
json j_data;
|
||||
j_data["module_id"] = mod_id;
|
||||
j_data["submodule_id"] = submod_id;
|
||||
j_request["params"].push_back(j_data);
|
||||
}
|
||||
|
||||
void putCyclicData(json& j_cyc_data, uint32_t mod_id, uint32_t submod_id, uint8_t * pdata, uint16_t data_size)
|
||||
{
|
||||
json j_set_data;
|
||||
|
||||
std::vector<uint8_t> in_data;
|
||||
in_data.insert(in_data.end(), &pdata[0], &pdata[data_size]);
|
||||
|
||||
j_set_data["module_id"] = mod_id;
|
||||
j_set_data["submodule_id"] = submod_id;
|
||||
j_set_data["data"] = json::binary(in_data);
|
||||
|
||||
j_cyc_data["params"].push_back(j_set_data);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
json j_cfg = json::parse(fileapi_read_file("sample_app_echo_config.json"));
|
||||
@ -70,29 +129,28 @@ int main(int argc, char * argv[])
|
||||
|
||||
json j_get_echo_param_gain;
|
||||
j_get_echo_param_gain["jsonrpc"] = "2.0";
|
||||
j_get_echo_param_gain["method"] = "readSubmoduleParameter";
|
||||
j_get_echo_param_gain["method"] = "readSubmoduleParameterNamed";
|
||||
j_get_echo_param_gain["params"] = json::array();
|
||||
json j_data;
|
||||
j_data["module_id"] = ECHO_MODULE_ID;
|
||||
j_data["submodule_id"] = ECHO_SUBMOD_ID;
|
||||
j_data["param_index"] = ECHO_PARAMETER_GAIN_IDX;
|
||||
j_get_echo_param_gain["params"].push_back(j_data);
|
||||
|
||||
requestParam(j_get_echo_param_gain, ECHO_MODULE_ID, ECHO_SUBMOD_ID, ECHO_PARAMETER_GAIN_IDX);
|
||||
requestParam(j_get_echo_param_gain, BIT_MODULE_ID, BIT_SUBMOD_ID, BIT_PARAMETER_1_IDX);
|
||||
requestParam(j_get_echo_param_gain, BIT_MODULE_ID, BIT_SUBMOD_ID, BIT_PARAMETER_2_IDX);
|
||||
j_get_echo_param_gain["id"] = 0;
|
||||
|
||||
|
||||
json j_data;
|
||||
json j_get_echo_data;
|
||||
j_get_echo_data["jsonrpc"] = "2.0";
|
||||
j_get_echo_data["method"] = "readCyclicIoData";
|
||||
j_get_echo_data["method"] = "readCyclicIoDataNamed";
|
||||
j_get_echo_data["params"] = json::array();
|
||||
j_data.clear();
|
||||
j_data["module_id"] = ECHO_MODULE_ID;
|
||||
j_data["submodule_id"] = ECHO_SUBMOD_ID;
|
||||
j_get_echo_data["params"].push_back(j_data);
|
||||
requestCyclic(j_get_echo_data, ECHO_MODULE_ID, ECHO_SUBMOD_ID);
|
||||
requestCyclic(j_get_echo_data, BIT_MODULE_ID, BIT_SUBMOD_ID);
|
||||
j_get_echo_data["id"] = 0;
|
||||
|
||||
json j_set_echo_data;
|
||||
|
||||
j_set_echo_data["jsonrpc"] = "2.0";
|
||||
j_set_echo_data["method"] = "writeCyclicIoData";
|
||||
j_set_echo_data["method"] = "writeCyclicIoDataNamed";
|
||||
j_set_echo_data["params"] = json::array();
|
||||
j_set_echo_data["id"] = 0;
|
||||
|
||||
@ -103,7 +161,6 @@ int main(int argc, char * argv[])
|
||||
answer_str.clear();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
std::string request{j_get_flags.dump()};
|
||||
///Запрос:
|
||||
*p_output_stream_ << request << std::endl;
|
||||
@ -141,12 +198,14 @@ int main(int argc, char * argv[])
|
||||
if (j_res["EVENT_NEW_PARAM_DATA"].get<bool>() == true)
|
||||
{
|
||||
answer_str.clear();
|
||||
std::cout << "EVENT_NEW_PARAM_DATA: true" << std::endl;
|
||||
std::cout << "EVENT_NEW_PARAM_DATA: true" << std::endl;
|
||||
*p_output_stream_ << j_get_echo_param_gain.dump() << std::endl;
|
||||
std::getline( *p_input_stream_.get( ), answer_str);
|
||||
json j_answ_par = json::parse(answer_str);
|
||||
std::vector<uint8_t> in;
|
||||
|
||||
//std::cout << "EVENT_NEW_PARAM_DATA: " << answer_str << std::endl;
|
||||
|
||||
for (auto& jx : j_answ_par["result"])
|
||||
{
|
||||
uint32_t module_id;
|
||||
@ -156,28 +215,81 @@ int main(int argc, char * argv[])
|
||||
module_id = jx["module_id"].get<int>();
|
||||
submodule_id = jx["submodule_id"].get<int>();
|
||||
param_idx = jx["param_index"].get<int>();
|
||||
|
||||
if ((module_id != ECHO_MODULE_ID) || (submodule_id != ECHO_SUBMOD_ID))
|
||||
|
||||
switch(module_id)
|
||||
{
|
||||
std::cout << "Error id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
case ECHO_MODULE_ID:
|
||||
{
|
||||
switch(submodule_id)
|
||||
{
|
||||
case ECHO_SUBMOD_ID:
|
||||
{
|
||||
if (param_idx != ECHO_PARAMETER_GAIN_IDX)
|
||||
{
|
||||
std::cout << "Error param idx" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param_idx != ECHO_PARAMETER_GAIN_IDX)
|
||||
{
|
||||
std::cout << "Error param idx" << std::endl;
|
||||
continue;
|
||||
}
|
||||
in.clear();
|
||||
in = jx["data"]["bytes"].get<std::vector<uint8_t>>();
|
||||
Echo_Gain = jx.at("data").at("EchoGain").get<uint32_t>();
|
||||
|
||||
if (in.size() == 4)
|
||||
{
|
||||
std::copy(in.begin(), in.end(), (uint8_t*)&Echo_Gain);
|
||||
}
|
||||
endian_convert_32((uint8_t*)&Echo_Gain);
|
||||
std::cout << "Echo_Gain = " << Echo_Gain << std::endl;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error submodule id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIT_MODULE_ID:
|
||||
{
|
||||
switch(submodule_id)
|
||||
{
|
||||
case BIT_SUBMOD_ID:
|
||||
{
|
||||
switch(param_idx)
|
||||
{
|
||||
case BIT_PARAMETER_1_IDX:
|
||||
{
|
||||
bit_param_1 = jx.at("data").at("I8O8Param1").get<uint32_t>();
|
||||
std::cout << "bit_param_1 = " << bit_param_1 << std::endl;
|
||||
}
|
||||
break;
|
||||
case BIT_PARAMETER_2_IDX:
|
||||
{
|
||||
bit_param_2 = jx.at("data").at("I8O8Param2").get<uint32_t>();
|
||||
|
||||
std::cout << "Echo_Gain = " << Echo_Gain << std::endl;
|
||||
std::cout << "bit_param_2 = " << bit_param_2 << std::endl;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error param idx" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error submodule id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error module id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +298,8 @@ int main(int argc, char * argv[])
|
||||
static uint32_t value_i = 0;
|
||||
static float value_f = 0.0;
|
||||
|
||||
static uint32_t value_bit = 0;
|
||||
|
||||
answer_str.clear();
|
||||
*p_output_stream_ << j_get_echo_data.dump() << std::endl;
|
||||
std::getline( *p_input_stream_.get( ), answer_str);
|
||||
@ -200,61 +314,105 @@ int main(int argc, char * argv[])
|
||||
module_id = jx["module_id"].get<int>();
|
||||
submodule_id = jx["submodule_id"].get<int>();
|
||||
|
||||
if ((module_id != ECHO_MODULE_ID) || (submodule_id != ECHO_SUBMOD_ID))
|
||||
switch(module_id)
|
||||
{
|
||||
std::cout << "Error id" << std::endl;
|
||||
continue;
|
||||
case ECHO_MODULE_ID:
|
||||
{
|
||||
switch(submodule_id)
|
||||
{
|
||||
case ECHO_SUBMOD_ID:
|
||||
{
|
||||
Echo_outCycData.data.data_f = jx.at("data").at("EchoModuleOutFloat").get<float>();
|
||||
Echo_outCycData.data.data_i = jx.at("data").at("EchoModuleOutInt").get<uint32_t>();
|
||||
|
||||
if (value_i != Echo_outCycData.data.data_i)
|
||||
{
|
||||
value_i = Echo_outCycData.data.data_i;
|
||||
|
||||
std::cout << "New data_i from PLC: " << value_i << std::endl;
|
||||
}
|
||||
|
||||
if (value_f != Echo_outCycData.data.data_f)
|
||||
{
|
||||
value_f = Echo_outCycData.data.data_f;
|
||||
|
||||
std::cout << "New data_f from PLC: " << value_f << std::endl;
|
||||
}
|
||||
|
||||
///Подготавливаем данные для ПЛК
|
||||
Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i;
|
||||
Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f;
|
||||
|
||||
json j_set_data;
|
||||
|
||||
j_set_data["module_id"] = module_id;
|
||||
j_set_data["submodule_id"] = submodule_id;
|
||||
j_set_data["data"]["EchoModuleInpFloat"] = Echo_inpCycData.data.data_f;
|
||||
j_set_data["data"]["EchoModuleInpInt"] = Echo_inpCycData.data.data_i;
|
||||
|
||||
j_set_echo_data["params"].push_back(j_set_data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error submodule id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIT_MODULE_ID:
|
||||
{
|
||||
switch(submodule_id)
|
||||
{
|
||||
case BIT_SUBMOD_ID:
|
||||
{
|
||||
uint8_t bits = 0;
|
||||
|
||||
|
||||
/*in = jx["data"]["bytes"].get<std::vector<uint8_t>>();
|
||||
if (in.size() == 1)
|
||||
{
|
||||
std::copy(in.begin(), in.end(), &bits);
|
||||
}
|
||||
|
||||
if (bits != value_bit)
|
||||
{
|
||||
value_bit = bits;
|
||||
|
||||
std::cout << "New bit data from PLC: " << value_bit << std::endl;
|
||||
}
|
||||
|
||||
bits = ~bits;
|
||||
putCyclicData(j_set_echo_data, module_id, submodule_id, &bits, 1);*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error submodule id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
std::cout << "Error module id" << std::endl;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
in = jx["data"]["bytes"].get<std::vector<uint8_t>>();
|
||||
|
||||
if (in.size() == 8)
|
||||
{
|
||||
std::copy(in.begin(), in.end(), Echo_outCycData.mem);
|
||||
}
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_f);
|
||||
|
||||
if (value_i != Echo_outCycData.data.data_i)
|
||||
{
|
||||
value_i = Echo_outCycData.data.data_i;
|
||||
|
||||
std::cout << "New data_i from PLC: " << value_i << std::endl;
|
||||
}
|
||||
|
||||
if (value_f != Echo_outCycData.data.data_f)
|
||||
{
|
||||
value_f = Echo_outCycData.data.data_f;
|
||||
|
||||
std::cout << "New data_f from PLC: " << value_f << std::endl;
|
||||
}
|
||||
|
||||
///Подготавливаем данные для ПЛК
|
||||
Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i;
|
||||
Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f;
|
||||
///Конвертируем в биг эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
json j_set_data;
|
||||
|
||||
std::vector<uint8_t> in_data;
|
||||
in_data.insert(in_data.end(), &Echo_inpCycData.mem[0], &Echo_inpCycData.mem[8]);
|
||||
|
||||
j_set_data["module_id"] = module_id;
|
||||
j_set_data["submodule_id"] = submodule_id;
|
||||
j_set_data["data"] = json::binary(in_data);
|
||||
|
||||
j_set_echo_data["params"].push_back(j_set_data);
|
||||
///Записываем данные
|
||||
*p_output_stream_ << j_set_echo_data.dump() << std::endl;
|
||||
|
||||
answer_str.clear();
|
||||
///Ждем ответ
|
||||
std::getline( *p_input_stream_.get( ), answer_str);
|
||||
}
|
||||
|
||||
j_set_echo_data["params"].clear();
|
||||
///Записываем данные
|
||||
*p_output_stream_ << j_set_echo_data.dump() << std::endl;
|
||||
std::cout << "OUT: " << j_set_echo_data.dump() << std::endl;
|
||||
j_set_echo_data["params"].array().clear();
|
||||
answer_str.clear();
|
||||
///Ждем ответ
|
||||
std::getline( *p_input_stream_.get( ), answer_str);
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -14,6 +14,8 @@ include(./file_api/file_api.cmake)
|
||||
include(./configuration/configuration.cmake)
|
||||
include (./interprocess/interprocess.cmake)
|
||||
include (./shared_data/shared_data.cmake)
|
||||
include (./endian/endian.cmake)
|
||||
include (./user_data/user_data.cmake)
|
||||
|
||||
set(SRC_FILES ${SRC_FILES} ./app.cpp)
|
||||
|
||||
@ -48,5 +50,5 @@ target_link_directories(${TARGET_NAME} PUBLIC ${LIBS_INSTALL_PATH}/lib/x86_64)
|
||||
|
||||
#Если не собирается с ошибкой линкера undefined reference pthread, то после ${Boost_LIBRARIES} добавить pthread или -lpthread:
|
||||
#target_link_libraries (${TARGET_NAME} PUBLIC profinet osal ${Boost_LIBRARIES} pthread)
|
||||
target_link_libraries (${TARGET_NAME} PUBLIC profinet osal ${Boost_LIBRARIES})
|
||||
target_link_libraries (${TARGET_NAME} PUBLIC profinetd osald ${Boost_LIBRARIES})
|
||||
|
||||
|
@ -17,7 +17,11 @@ bool App::Init(std::string profinet_config_file)
|
||||
ProfinetData_Map * p_profinetMap = shared_data_.Create("profinet_shared_data");
|
||||
|
||||
/// Читаем настройки из файла, выделяем память под структуру модулей и подмодулей
|
||||
if (!programconf_getProfinetDeviceSettings(profinet_settings.profinet_device_config, profinet_dev_settings, p_profinetMap, shared_data_))
|
||||
if (!programconf_getProfinetDeviceSettings(profinet_settings.profinet_device_config,
|
||||
profinet_dev_settings,
|
||||
p_profinetMap,
|
||||
shared_data_,
|
||||
user_data_map_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -37,7 +41,7 @@ bool App::Init(std::string profinet_config_file)
|
||||
/// Запуск потока Profinet
|
||||
profinet_.Start();
|
||||
/// Запуск потока чтения запросов по pipe
|
||||
pipes_.Start(&profinet_);
|
||||
pipes_.Start(&profinet_, &user_data_map_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "./interprocess/shared_memory/profinet_shared_data.hpp"
|
||||
#include "./interprocess/pipes/profinet_pipes.hpp"
|
||||
#include <string>
|
||||
#include "user_data.hpp"
|
||||
|
||||
class App {
|
||||
public:
|
||||
@ -13,4 +14,6 @@ private:
|
||||
ProfinetPipes pipes_;
|
||||
ProfinetSharedData shared_data_;
|
||||
Profinet profinet_;
|
||||
|
||||
UserDataMap user_data_map_; /// Для конвертации данных из rpc json и обратно
|
||||
};
|
@ -163,6 +163,24 @@ static uint8_t programconf_dataDirConvert(string dir_str)
|
||||
return out;
|
||||
}
|
||||
|
||||
static int programconf_getDataSize(const json& j_in)
|
||||
{
|
||||
if (!j_in.is_array())
|
||||
return 0;
|
||||
|
||||
int size = 0;
|
||||
|
||||
for (auto& j : j_in)
|
||||
{
|
||||
if (!j.contains("DataType"))
|
||||
return 0;
|
||||
|
||||
size+= UserData::getDataSize(j.at("DataType").get<std::string>());
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Считаем общий размер данных требуемый всеми подмодулями: их циклическими данными и параметрами
|
||||
* Пробегает по файлу конфигурации и считает размер требуемой памяти.
|
||||
@ -171,47 +189,159 @@ static uint8_t programconf_dataDirConvert(string dir_str)
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static bool programconf_calc_memory_size(json& j, uint32_t& memory_size)
|
||||
static bool programconf_calc_memory_size(const json& j, uint32_t& memory_size)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceModulesSettings"))
|
||||
return false;
|
||||
|
||||
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
|
||||
auto& modules_sett = j.at("ProfinetDeviceModulesSettings").at("modules");
|
||||
|
||||
memory_size = sizeof(ProfinetData_Map) + modules_sett.size() * sizeof(ProfinetData_Module);
|
||||
|
||||
for (auto& mod_set : modules_sett)
|
||||
{
|
||||
auto& submodules_sett = mod_set["submodules"];
|
||||
auto& submodules_sett = mod_set.at("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>());
|
||||
|
||||
auto& cyclic_data = submod_sett.at("cyclic_data");
|
||||
uint16_t in_data_len = programconf_getDataSize(cyclic_data.at("Inputs"));
|
||||
uint16_t out_data_len = programconf_getDataSize(cyclic_data.at("Outputs"));
|
||||
|
||||
memory_size+= in_data_len + out_data_len;
|
||||
|
||||
///Параметры подмодуля
|
||||
auto& params_sett = submod_sett["parameters"];
|
||||
|
||||
memory_size += params_sett.size() * sizeof(ProfinetData_Parameter);
|
||||
///Параметры подмодуля
|
||||
memory_size += submod_sett.at("parameters").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;
|
||||
}
|
||||
memory_size += programconf_getDataSize(submod_sett.at("parameters"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
|
||||
static bool programconf_getCyclycDataDir(json& j_cyclic_data, uint8_t& dir)
|
||||
{
|
||||
if (!j_cyclic_data.contains("dir"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dir = programconf_dataDirConvert(j_cyclic_data["dir"].get<string>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool programconf_getCyclicDataSettings(const json& j_cyc_data, std::map<std::string, UserData>& user_data, uint16_t& cyc_data_len)
|
||||
{
|
||||
uint16_t data_lengh = 0;
|
||||
|
||||
if (!j_cyc_data.is_array())
|
||||
return false;
|
||||
|
||||
for (auto& j : j_cyc_data)
|
||||
{
|
||||
if (!j.contains("name"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!j.contains("DataType"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto name = j.at("name").get<std::string>();
|
||||
auto Type = j.at("DataType").get<std::string>();
|
||||
|
||||
user_data.emplace(std::make_pair(std::string(name), UserData{name, Type, data_lengh}));
|
||||
|
||||
data_lengh+= user_data.at(name).size;
|
||||
|
||||
if (j.contains("bits"))
|
||||
{
|
||||
auto& j_bits = j.at("bits");
|
||||
auto& usr_data = user_data.at(name);
|
||||
for (auto& j_bit : j_bits)
|
||||
{
|
||||
if (!j_bit.contains("name") || !j.contains("BitOffset"))
|
||||
continue;
|
||||
|
||||
auto name = j_bit.at("name").get<std::string>();
|
||||
auto Type = j_bit.at("BitOffset").get<uint32_t>();
|
||||
|
||||
usr_data.putBit(name, Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cyc_data_len = data_lengh;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool programconf_getParamsSettings(const json& j_sett,
|
||||
ProfinetData_Submodule& submod,
|
||||
ProfinetSharedData& shared_data,
|
||||
std::map<std::uint32_t, UserData>& user_data)
|
||||
{
|
||||
if (!j_sett.contains("parameters"))
|
||||
return false;
|
||||
|
||||
if (!j_sett.at("parameters").is_array())
|
||||
return false;
|
||||
|
||||
///Параметры подмодуля
|
||||
auto& params_sett = j_sett.at("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;
|
||||
|
||||
std::string data_type = parm_sett.at("DataType").get<std::string>();
|
||||
param.index = static_cast<uint32_t>(parm_sett.at("index").get<int>());
|
||||
param.name = parm_sett.at("name").get<string>();
|
||||
|
||||
user_data.emplace(std::make_pair(param.index, UserData{param.name, data_type, 0}));
|
||||
|
||||
param.length = static_cast<uint16_t>(user_data.at(param.index).size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p_data_map,
|
||||
ProfinetSharedData& shared_data,
|
||||
UserDataMap& user_data_map)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceModulesSettings"))
|
||||
return false;
|
||||
@ -291,10 +421,43 @@ static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p
|
||||
/// Копируем данные подмодуля
|
||||
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>());
|
||||
|
||||
auto& j_cycdata_sett = submod_sett["cyclic_data"];
|
||||
|
||||
if (!programconf_getCyclycDataDir(j_cycdata_sett, submod.cyc_data_dir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& submod_user_data = UserData_addNewSubmod(mod_id, submod_id, user_data_map);
|
||||
|
||||
/// Если есть секция Inputs
|
||||
if (j_cycdata_sett.contains("Inputs"))
|
||||
{
|
||||
/// Конструируем поля пользовательских данных в датаграмме циклических данных
|
||||
if (!programconf_getCyclicDataSettings(j_cycdata_sett.at("Inputs"), submod_user_data.inp_data_map, submod.cyc_indata_len))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((submod.cyc_data_dir == PROFINET_SUBMOD_DIR_IO) || (submod.cyc_data_dir == PROFINET_SUBMOD_DIR_INPUT))
|
||||
{
|
||||
/// Данные должны быть
|
||||
return false;
|
||||
}
|
||||
|
||||
if (j_cycdata_sett.contains("Outputs"))
|
||||
{
|
||||
if (!programconf_getCyclicDataSettings(j_cycdata_sett.at("Outputs"), submod_user_data.out_data_map, submod.cyc_outdata_len))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((submod.cyc_data_dir == PROFINET_SUBMOD_DIR_IO) || (submod.cyc_data_dir == PROFINET_SUBMOD_DIR_OUTPUT))
|
||||
{
|
||||
/// Данные должны быть
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Выделяем память под циклические данные
|
||||
if (submod.cyc_indata_len)
|
||||
{
|
||||
@ -317,44 +480,8 @@ static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p
|
||||
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);
|
||||
}
|
||||
/// Читаем конфигурацию параметров
|
||||
programconf_getParamsSettings(submod_sett, submod, shared_data, submod_user_data.params_map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +491,8 @@ static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p
|
||||
|
||||
|
||||
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
|
||||
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
|
||||
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data,
|
||||
UserDataMap& user_data_map)
|
||||
{
|
||||
json j;
|
||||
|
||||
@ -378,7 +506,7 @@ bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDevice
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!programconf_getProfinetModulesSettings(j, p_data_map, shared_data))
|
||||
if (!programconf_getProfinetModulesSettings(j, p_data_map, shared_data, user_data_map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -8,8 +8,10 @@
|
||||
#include "profinet_data_map.hpp"
|
||||
#include "profinet_shared_data.hpp"
|
||||
#include "profinet_pipes.hpp"
|
||||
#include "user_data.hpp"
|
||||
|
||||
bool programconf_getProfinetSettings(std::string file_path, ProfinetSettings& pn_sett, ProfinetPipesSettings& pn_pipes_sett);
|
||||
|
||||
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
|
||||
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data);
|
||||
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data,
|
||||
UserDataMap& user_data_map);
|
||||
|
2
src/endian/endian.cmake
Normal file
2
src/endian/endian.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(SRC_FILES ${SRC_FILES} ./endian/endian.cpp)
|
||||
set(INC_DIRS ${INC_DIRS} ./endian)
|
22
src/endian/endian.cpp
Normal file
22
src/endian/endian.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "endian.hpp"
|
||||
|
||||
bool endian_swapbytes(void * p_data, uint32_t size)
|
||||
{
|
||||
uint8_t * p_data_ = static_cast<uint8_t*>(p_data);
|
||||
|
||||
if ((size % 2) || (size < 2))
|
||||
return false; /// Только четные длины можно свапить
|
||||
|
||||
uint32_t size_half = size >> 1;
|
||||
|
||||
for (int i = 0; i < size_half; ++i)
|
||||
{
|
||||
uint32_t j = size - i - 1;
|
||||
uint8_t tmp = p_data_[i];
|
||||
|
||||
p_data_[i] = p_data_[j];
|
||||
p_data_[j] = tmp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
5
src/endian/endian.hpp
Normal file
5
src/endian/endian.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
bool endian_swapbytes(void * p_data, uint32_t size);
|
@ -2,6 +2,7 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include "../../nlohmann_json/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
using string = std::string;
|
||||
@ -163,7 +164,164 @@ static bool json_readSubmoduleParameter(json& j_in, json& j_out, ProfinetIface *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool json_rpc_handler(std::string& input, std::string& output, ProfinetIface * p_profinet)
|
||||
static bool json_writeCyclicIoDataNamed(json& j_in, json& j_out, ProfinetIface * p_profinet,
|
||||
UserDataMap& user_data_map)
|
||||
{
|
||||
if (!j_in.contains("params"))
|
||||
return false;
|
||||
|
||||
/// Запись
|
||||
j_out["result"] = json::array();
|
||||
|
||||
for (auto& param : j_in["params"])
|
||||
{
|
||||
if (!param.contains("module_id") || !param.contains("submodule_id") ||
|
||||
!param.contains("data"))
|
||||
return false;
|
||||
|
||||
json j_arr;
|
||||
uint32_t module_id = param.at("module_id").get<int>();
|
||||
uint32_t submodule_id = param.at("submodule_id").get<int>();
|
||||
|
||||
int data_len = p_profinet->getSubmoduleCyclicInpDataLen(module_id, submodule_id);
|
||||
|
||||
if (data_len < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> pn_data(data_len);
|
||||
|
||||
auto& j_data = param.at("data");
|
||||
|
||||
auto& submod_data_map = UserData_getSubmod(module_id, submodule_id, user_data_map);
|
||||
|
||||
/// Берем данные из rpc json и преобразовываем в бинарный вид в user_data
|
||||
for (auto& m : submod_data_map.inp_data_map)
|
||||
{
|
||||
auto& user_data = m.second;
|
||||
user_data.convertJsonToBinary(j_data, pn_data);
|
||||
}
|
||||
|
||||
/// Копируем данные в профинет
|
||||
auto result = p_profinet->putInputCyclicData(module_id, submodule_id, pn_data);
|
||||
|
||||
///
|
||||
j_arr["module_id"] = module_id;
|
||||
j_arr["submodule_id"] = submodule_id;
|
||||
string status;
|
||||
|
||||
json_rpc_set_status(static_cast<ProfinetIface::ErrorCode>(result), status);
|
||||
|
||||
j_arr["status"] = status;
|
||||
|
||||
j_out["result"].push_back(j_arr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_readCyclicIoDataNamed(const json& j_in, json& j_out, ProfinetIface * p_profinet,
|
||||
UserDataMap& user_data_map)
|
||||
{
|
||||
if (!j_in.contains("params"))
|
||||
return false;
|
||||
|
||||
/// Запись
|
||||
j_out["result"] = json::array();
|
||||
|
||||
for (auto& param : j_in.at("params"))
|
||||
{
|
||||
json j_arr;
|
||||
uint32_t module_id = param.at("module_id").get<int>();
|
||||
uint32_t submodule_id = param.at("submodule_id").get<int>();
|
||||
std::vector<uint8_t> pn_data;
|
||||
|
||||
/// Извлекаем данные из профинета
|
||||
auto result = p_profinet->getOutputCyclicData(module_id, submodule_id, pn_data);
|
||||
|
||||
|
||||
///
|
||||
j_arr["module_id"] = module_id;
|
||||
j_arr["submodule_id"] = submodule_id;
|
||||
|
||||
string status;
|
||||
json_rpc_set_status(static_cast<ProfinetIface::ErrorCode>(result), status);
|
||||
j_arr["status"] = status;
|
||||
|
||||
if (result == ProfinetIface::ERR_SUCCESS)
|
||||
{
|
||||
auto& submod_data_map = UserData_getSubmod(module_id, submodule_id, user_data_map);
|
||||
/// Преобразовываем бинарные данные в rpc json
|
||||
for (auto& m : submod_data_map.out_data_map)
|
||||
{
|
||||
auto& user_data = m.second;
|
||||
user_data.convertBinaryToJson(pn_data, j_arr["data"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
j_arr["data"];
|
||||
}
|
||||
|
||||
j_out["result"].push_back(j_arr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_readSubmoduleParameterNamed(json& j_in, json& j_out, ProfinetIface * p_profinet,
|
||||
UserDataMap& user_data_map)
|
||||
{
|
||||
if (!j_in.contains("params"))
|
||||
return false;
|
||||
|
||||
/// Запись
|
||||
j_out["result"] = json::array();
|
||||
|
||||
for (auto& param : j_in["params"])
|
||||
{
|
||||
json j_arr;
|
||||
uint32_t module_id = param["module_id"].get<int>();
|
||||
uint32_t submodule_id = param["submodule_id"].get<int>();
|
||||
uint32_t param_idx = param["param_index"].get<int>();
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
auto result = p_profinet->getSubmoduleParam(module_id, submodule_id, param_idx, data);
|
||||
|
||||
///
|
||||
j_arr["module_id"] = module_id;
|
||||
j_arr["submodule_id"] = submodule_id;
|
||||
j_arr["param_index"] = param_idx;
|
||||
|
||||
string status;
|
||||
json_rpc_set_status(static_cast<ProfinetIface::ErrorCode>(result), status);
|
||||
j_arr["status"] = status;
|
||||
|
||||
|
||||
|
||||
if (result == ProfinetIface::ERR_SUCCESS)
|
||||
{
|
||||
auto& submod_data_map = UserData_getSubmod(module_id, submodule_id, user_data_map);
|
||||
|
||||
auto& param_user_data = submod_data_map.params_map.at(param_idx);
|
||||
|
||||
param_user_data.convertBinaryToJson(data, j_arr["data"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
j_arr["data"];
|
||||
}
|
||||
|
||||
j_out["result"].push_back(j_arr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool json_rpc_handler(std::string& input, std::string& output,
|
||||
ProfinetIface * p_profinet,
|
||||
UserDataMap * p_UserDataMap)
|
||||
{
|
||||
json j_in;
|
||||
|
||||
@ -215,6 +373,18 @@ bool json_rpc_handler(std::string& input, std::string& output, ProfinetIface * p
|
||||
{
|
||||
json_readSubmoduleParameter(j_in, j_out, p_profinet);
|
||||
}
|
||||
else if (method == "writeCyclicIoDataNamed")
|
||||
{
|
||||
json_writeCyclicIoDataNamed(j_in, j_out, p_profinet, *p_UserDataMap);
|
||||
}
|
||||
else if (method == "readCyclicIoDataNamed")
|
||||
{
|
||||
json_readCyclicIoDataNamed(j_in, j_out, p_profinet, *p_UserDataMap);
|
||||
}
|
||||
else if (method == "readSubmoduleParameterNamed")
|
||||
{
|
||||
json_readSubmoduleParameterNamed(j_in, j_out, p_profinet, *p_UserDataMap);
|
||||
}
|
||||
|
||||
j_out["method"] = method;
|
||||
j_out["id"] = rpc_id;
|
||||
|
@ -1,11 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../nlohmann_json/json.hpp"
|
||||
#include "../../profinet/profinet_iface.hpp"
|
||||
#include "../../user_data/user_data.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
bool json_rpc_handler(std::string& input, std::string& output, ProfinetIface * p_profinet);
|
||||
bool json_rpc_handler(std::string& input,
|
||||
std::string& output,
|
||||
ProfinetIface * p_profinet,
|
||||
UserDataMap * p_UserDataMap );
|
||||
|
||||
|
||||
|
||||
|
@ -217,3 +217,233 @@
|
||||
0-й бит -
|
||||
"id": 0
|
||||
}
|
||||
|
||||
5. Метод записи именованых входных циклических данных(данные к ПЛК):
|
||||
-->
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "writeCyclicIoDataNamed",
|
||||
"params":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"data":
|
||||
{
|
||||
"Имя поля данных 1": значение 1,
|
||||
"Имя поля данных 1": значение 2,
|
||||
:
|
||||
"Имя поля данных N": значение N,
|
||||
Биты представляются следующим образом:
|
||||
"Битовое поле данных ":
|
||||
{
|
||||
"Имя бита 0": значение 0 или 1,
|
||||
"Имя бита 1": значение 0 или 1,
|
||||
:
|
||||
"Имя бита N": значение 0 или 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
}
|
||||
},ProfinetIface::
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
}
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
||||
<--
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "writeCyclicIoDataNamed"
|
||||
"result":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_DATA_LENGTH"
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_DATA_LENGTH"
|
||||
},
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_DATA_LENGTH"
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
||||
|
||||
6. Метод чтения именованых выходных циклических данных(данные от ПЛК):
|
||||
-->
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "readCyclicIoDataNamed",
|
||||
"params":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
},
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
||||
<--
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "readCyclicIoDataNamed"
|
||||
"result":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID"
|
||||
"data":
|
||||
{
|
||||
"Имя поля данных 1": значение 1,
|
||||
"Имя поля данных 1": значение 2,
|
||||
:
|
||||
"Имя поля данных N": значение N,
|
||||
Биты представляются следующим образом:
|
||||
"Битовое поле данных ":
|
||||
{
|
||||
"Имя бита 0": значение 0 или 1,
|
||||
"Имя бита 1": значение 0 или 1,
|
||||
:
|
||||
"Имя бита N": значение 0 или 1
|
||||
}
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID"
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID"
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
||||
|
||||
3. Метод чтения именованых параметров подмодуля:
|
||||
Устройство может только читать параметры. Записывает параметры только Profinet контроллер(ПЛК)
|
||||
после установления связи и перед началом циклического обмена.
|
||||
-->
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "readSubmoduleParameterNamed",
|
||||
"params":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
},
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
||||
<--
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "readSubmoduleParameterNamed",
|
||||
"result":
|
||||
[
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_PARAM_INDEX"
|
||||
"data":
|
||||
{
|
||||
"Имя поля данных 1": значение 1,
|
||||
"Имя поля данных 1": значение 2,
|
||||
:
|
||||
"Имя поля данных N": значение N,
|
||||
Биты представляются следующим образом:
|
||||
"Битовое поле данных ":
|
||||
{
|
||||
"Имя бита 0": значение 0 или 1,
|
||||
"Имя бита 1": значение 0 или 1,
|
||||
:
|
||||
"Имя бита N": значение 0 или 1
|
||||
}
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_PARAM_INDEX"
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
:
|
||||
:
|
||||
{
|
||||
"module_id": Идентификатор модуля
|
||||
"submodule_id": Идентификатор подмодуля
|
||||
"param_index": Индекс парамтера
|
||||
"status": "OK", "WRONG_MODULE_ID", "WRONG_SUBMODULE_ID", "WRONG_PARAM_INDEX"
|
||||
"data":
|
||||
{
|
||||
данные (см. выше)
|
||||
} или null в, если status!=ОК
|
||||
},
|
||||
]
|
||||
"id": 0
|
||||
}
|
@ -36,7 +36,7 @@ void ProfinetPipes::Init( ProfinetPipesSettings& sett )
|
||||
p_output_stream_ = std::move( std::get<1>( streams ) );
|
||||
}
|
||||
|
||||
void ProfinetPipes::listen_pipe(ProfinetIface * p_profinet)
|
||||
void ProfinetPipes::listen_pipe(ProfinetIface * p_profinet, UserDataMap * p_UserDataMap)
|
||||
{
|
||||
std::string request_str;
|
||||
|
||||
@ -46,7 +46,7 @@ void ProfinetPipes::listen_pipe(ProfinetIface * p_profinet)
|
||||
std::string answer_str;
|
||||
std::getline( *p_input_stream_.get(), request_str);
|
||||
//std::cout << "Request: " << request_str << std::endl;
|
||||
if (json_rpc_handler(request_str, answer_str, p_profinet))
|
||||
if (json_rpc_handler(request_str, answer_str, p_profinet, p_UserDataMap))
|
||||
{
|
||||
//std::cout << "Answer: " << answer_str << std::endl;
|
||||
*p_output_stream_ << answer_str << std::endl;
|
||||
@ -79,10 +79,10 @@ void ProfinetPipes::listen_pipe(ProfinetIface * p_profinet)
|
||||
}
|
||||
}
|
||||
|
||||
void ProfinetPipes::Start(ProfinetIface * p_profinet)
|
||||
void ProfinetPipes::Start(ProfinetIface * p_profinet, UserDataMap * p_UserDataMap)
|
||||
{
|
||||
if (!enable_)
|
||||
return;
|
||||
|
||||
listen_thread_ = std::move(std::thread(&ProfinetPipes::listen_pipe, this, p_profinet));
|
||||
listen_thread_ = std::move(std::thread(&ProfinetPipes::listen_pipe, this, p_profinet, p_UserDataMap));
|
||||
}
|
@ -5,8 +5,10 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "../../profinet/profinet_iface.hpp"
|
||||
#include "../../user_data/user_data.hpp"
|
||||
|
||||
struct ProfinetPipesSettings {
|
||||
bool enable;
|
||||
@ -22,9 +24,9 @@ public:
|
||||
|
||||
void Init( ProfinetPipesSettings& sett );
|
||||
|
||||
void listen_pipe(ProfinetIface * p_profinet);
|
||||
void listen_pipe(ProfinetIface * p_profinet, UserDataMap * p_UserDataMap);
|
||||
|
||||
void Start(ProfinetIface * p_profinet);
|
||||
void Start(ProfinetIface * p_profinet, UserDataMap * p_UserDataMap);
|
||||
|
||||
private:
|
||||
/** Поток обработки входящих данных от именнованого канала. */
|
||||
|
@ -689,7 +689,9 @@ int Profinet::putInputCyclicData(uint32_t module_id,
|
||||
return ErrorCode::ERR_SUBMODULE_DOES_NOT_EXIST;
|
||||
|
||||
if (data.size() != submodule->m_data_cfg.insize)
|
||||
{
|
||||
return ErrorCode::ERR_WRONG_DATA_LENGTH;
|
||||
}
|
||||
|
||||
submodule->writeInputData(data);
|
||||
|
||||
@ -734,6 +736,31 @@ Profinet::~Profinet()
|
||||
}
|
||||
}
|
||||
|
||||
int Profinet::getSubmoduleCyclicInpDataLen(uint32_t module_id, uint32_t submodule_id) const
|
||||
{
|
||||
if (!m_modules.contains(module_id))
|
||||
return ErrorCode::ERR_MODULE_DOES_NOT_EXIST;
|
||||
|
||||
auto submodule = m_modules.at(module_id)->getSubmodulePtr(submodule_id);
|
||||
|
||||
if (submodule == nullptr)
|
||||
return ErrorCode::ERR_SUBMODULE_DOES_NOT_EXIST;
|
||||
|
||||
return submodule->m_data_cfg.insize;
|
||||
}
|
||||
|
||||
int Profinet::getSubmoduleCyclicOutDataLen(uint32_t module_id, uint32_t submodule_id) const
|
||||
{
|
||||
if (!m_modules.contains(module_id))
|
||||
return ErrorCode::ERR_MODULE_DOES_NOT_EXIST;
|
||||
|
||||
auto submodule = m_modules.at(module_id)->getSubmodulePtr(submodule_id);
|
||||
|
||||
if (submodule == nullptr)
|
||||
return ErrorCode::ERR_SUBMODULE_DOES_NOT_EXIST;
|
||||
|
||||
return submodule->m_data_cfg.outsize;
|
||||
}
|
||||
|
||||
/**\
|
||||
* =========================================================================================
|
||||
|
@ -168,6 +168,10 @@ public:
|
||||
uint32_t submodule_id,
|
||||
uint32_t param_id,
|
||||
std::vector<uint8_t>& data) override;
|
||||
|
||||
virtual int getSubmoduleCyclicInpDataLen(uint32_t module_id, uint32_t submodule_id) const override;
|
||||
|
||||
virtual int getSubmoduleCyclicOutDataLen(uint32_t module_id, uint32_t submodule_id) const override;
|
||||
|
||||
private:
|
||||
ProfinetServiceData m_pnet_data;
|
||||
|
@ -70,4 +70,8 @@ public:
|
||||
* @return uint32_t
|
||||
*/
|
||||
virtual void clearEvents(uint32_t mask) = 0;
|
||||
|
||||
virtual int getSubmoduleCyclicInpDataLen(uint32_t module_id, uint32_t submodule_id) const = 0;
|
||||
|
||||
virtual int getSubmoduleCyclicOutDataLen(uint32_t module_id, uint32_t submodule_id) const = 0;
|
||||
};
|
@ -54,14 +54,142 @@
|
||||
{
|
||||
"id": "0x00000140",
|
||||
"name": "Echo submodule",
|
||||
"cyc_data_dir": "PNET_DIR_IO",
|
||||
"cyc_inp_data_size": 8,
|
||||
"cyc_out_data_size": 8,
|
||||
"cyclic_data":
|
||||
{
|
||||
"dir": "PNET_DIR_IO",
|
||||
"Inputs": [
|
||||
{
|
||||
"name": "EchoModuleInpFloat",
|
||||
"DataType": "Float32"
|
||||
},
|
||||
{
|
||||
"name": "EchoModuleInpInt",
|
||||
"DataType": "Unsigned32"
|
||||
}
|
||||
],
|
||||
"Outputs": [
|
||||
{
|
||||
"name": "EchoModuleOutFloat",
|
||||
"DataType": "Float32"
|
||||
},
|
||||
{
|
||||
"name": "EchoModuleOutInt",
|
||||
"DataType": "Unsigned32"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"index": 125,
|
||||
"name": "Echo gain setting",
|
||||
"data_size": 4
|
||||
"name": "EchoGain",
|
||||
"DataType": "Unsigned32"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "0x00000032",
|
||||
"name": "I8O8 module",
|
||||
"submodules": [
|
||||
{
|
||||
"id": "0x00000132",
|
||||
"name": "I8O8 submodule",
|
||||
"cyclic_data":
|
||||
{
|
||||
"dir": "PNET_DIR_IO",
|
||||
"Inputs": [
|
||||
{
|
||||
"name": "I808InpBits",
|
||||
"DataType": "Unsigned8",
|
||||
"bits": [
|
||||
{
|
||||
"name": "in_bit_0",
|
||||
"BitOffset": 0
|
||||
},
|
||||
{
|
||||
"name": "in_bit_1",
|
||||
"BitOffset": 1
|
||||
},
|
||||
{
|
||||
"name": "in_bit_2",
|
||||
"BitOffset": 2
|
||||
},
|
||||
{
|
||||
"name": "in_bit_3",
|
||||
"BitOffset": 3
|
||||
},
|
||||
{
|
||||
"name": "in_bit_4",
|
||||
"BitOffset": 4
|
||||
},
|
||||
{
|
||||
"name": "in_bit_5",
|
||||
"BitOffset": 5
|
||||
},
|
||||
{
|
||||
"name": "in_bit_6",
|
||||
"BitOffset": 6
|
||||
},
|
||||
{
|
||||
"name": "in_bit_7",
|
||||
"BitOffset": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Outputs": [
|
||||
{
|
||||
"name": "I808OutBits",
|
||||
"DataType": "Unsigned8",
|
||||
"bits": [
|
||||
{
|
||||
"name": "out_bit_0",
|
||||
"BitOffset": 0
|
||||
},
|
||||
{
|
||||
"name": "out_bit_1",
|
||||
"BitOffset": 1
|
||||
},
|
||||
{
|
||||
"name": "out_bit_2",
|
||||
"BitOffset": 2
|
||||
},
|
||||
{
|
||||
"name": "out_bit_3",
|
||||
"BitOffset": 3
|
||||
},
|
||||
{
|
||||
"name": "out_bit_4",
|
||||
"BitOffset": 4
|
||||
},
|
||||
{
|
||||
"name": "out_bit_5",
|
||||
"BitOffset": 5
|
||||
},
|
||||
{
|
||||
"name": "out_bit_6",
|
||||
"BitOffset": 6
|
||||
},
|
||||
{
|
||||
"name": "out_bit_7",
|
||||
"BitOffset": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"index": 123,
|
||||
"name": "I8O8Param1",
|
||||
"DataType": "Unsigned32"
|
||||
},
|
||||
{
|
||||
"index": 124,
|
||||
"name": "I8O8Param2",
|
||||
"DataType": "Unsigned32"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
2
src/user_data/user_data.cmake
Normal file
2
src/user_data/user_data.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(SRC_FILES ${SRC_FILES} ./user_data/user_data.cpp)
|
||||
set(INC_DIRS ${INC_DIRS} ./user_data)
|
292
src/user_data/user_data.cpp
Normal file
292
src/user_data/user_data.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
#include "user_data.hpp"
|
||||
#include <bit>
|
||||
#include "../endian/endian.hpp"
|
||||
|
||||
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)
|
||||
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] = static_cast<bool>(data_.uint64 & (1 << bit.Pos));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
137
src/user_data/user_data.hpp
Normal file
137
src/user_data/user_data.hpp
Normal file
@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "../nlohmann_json/json.hpp"
|
||||
|
||||
struct UserDataBit {
|
||||
const std::string Name;
|
||||
const uint32_t Pos;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Класс представления данных внутри датаграммы циклического обмена профинет в виде
|
||||
* пользовательского набора стандартных типов. Нужен для выполнения RpcJson запросов оканчивающихся на
|
||||
* Named.
|
||||
*
|
||||
*/
|
||||
class UserData {
|
||||
public:
|
||||
enum class UserDataTypes
|
||||
{
|
||||
BOOL,
|
||||
UINT8,
|
||||
UINT16,
|
||||
UINT32,
|
||||
UINT64,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
INT64,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
};
|
||||
|
||||
UserData(std::string& Name, std::string& DataType, uint16_t offset) :
|
||||
name{Name},
|
||||
type{data_corr.at(DataType)},
|
||||
size{data_size.at(type)},
|
||||
data_offset_{offset}
|
||||
{
|
||||
};
|
||||
|
||||
union AnyData {
|
||||
bool boolean;
|
||||
uint8_t uint8[8];
|
||||
uint16_t uint16[4];
|
||||
uint32_t uint32[2];
|
||||
uint64_t uint64;
|
||||
uint8_t int8[8];
|
||||
uint16_t int16[4];
|
||||
uint32_t int32[2];
|
||||
uint64_t int64;
|
||||
float float32;
|
||||
double float64;
|
||||
};
|
||||
|
||||
//void init(std::string& Name, std::string& DataType, uint16_t offset);
|
||||
|
||||
bool convertBinaryToJson(const std::vector<uint8_t>& vect_inp, nlohmann::json& j_out);
|
||||
|
||||
bool convertJsonToBinary(const nlohmann::json& j_inp, std::vector<uint8_t>& vect_out);
|
||||
|
||||
bool putBit(std::string& bit_name, uint32_t bit_pos);
|
||||
|
||||
static int getDataSize(const std::string& type_name);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Извлекает данные в вектор с учетом оффсета и эндиана
|
||||
*
|
||||
* @param vect
|
||||
*/
|
||||
void extractData(std::vector<uint8_t>& vect);
|
||||
|
||||
/**
|
||||
* @brief Берет данные из вектора с учетом оффсета и эндиана
|
||||
*
|
||||
* @param vect
|
||||
*/
|
||||
void insertData(const std::vector<uint8_t>& vect);
|
||||
|
||||
/**
|
||||
* @brief Кладет внутренние бинарные данные в rpc json
|
||||
*
|
||||
* @param j
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool toRpcJson(nlohmann::json& j);
|
||||
|
||||
/**
|
||||
* @brief Преобразовывает данные их rpc json в бинарные данные
|
||||
*
|
||||
* @param j
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool fromRpcJson(const nlohmann::json& j);
|
||||
|
||||
private:
|
||||
static const std::map<UserDataTypes, uint32_t> data_size;
|
||||
static const std::map<std::string, UserDataTypes> data_corr;
|
||||
|
||||
public:
|
||||
const std::string name; /// Имя данных
|
||||
const UserDataTypes type; /// Тип данных
|
||||
const uint32_t size; /// Размер данных
|
||||
|
||||
private:
|
||||
AnyData data_; /// Данные
|
||||
std::vector<UserDataBit> bits_;
|
||||
const uint16_t data_offset_; /// Офсет от начала датаграммы откуда начинаются данные
|
||||
};
|
||||
|
||||
struct SubmoduleUserData
|
||||
{
|
||||
std::map<std::string, UserData> inp_data_map; /// Ключ - имя данных внутри даташраммы
|
||||
std::map<std::string, UserData> out_data_map; /// Ключ - имя данных внутри даташраммы
|
||||
std::map<uint32_t, UserData> params_map;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
USER_DATA_ID_SUBMOD,
|
||||
USER_DATA_ID_MOD,
|
||||
USER_DATA_ID_TOTAL
|
||||
};
|
||||
|
||||
using UserDataMap = std::map<uint64_t, SubmoduleUserData>;
|
||||
|
||||
SubmoduleUserData& UserData_addNewSubmod(uint32_t mod_id, uint32_t submod_id, UserDataMap& user_data_map);
|
||||
|
||||
SubmoduleUserData& UserData_getSubmod(uint32_t mod_id, uint32_t submod_id, UserDataMap& user_data_map);
|
Loading…
Reference in New Issue
Block a user