dev(UML-981): Промежуточный коммит
1.Реализован коллбэк callbackStateInd 2.Добавлены данные для циклического обмена
This commit is contained in:
parent
85eff4f7cd
commit
14c8d5a1eb
71
src/main.cpp
71
src/main.cpp
@ -2,15 +2,42 @@
|
||||
#include "../libs/include/pnet_api.h"
|
||||
#include "profinet.hpp"
|
||||
|
||||
#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
|
||||
|
||||
using namespace std;
|
||||
|
||||
uint32_t Echo_Gain = 0;
|
||||
|
||||
struct EchoData
|
||||
{
|
||||
uint32_t data_i;
|
||||
float data_f;
|
||||
};
|
||||
|
||||
union EchoDataMem {
|
||||
EchoData data;
|
||||
uint8_t mem[sizeof(EchoData)];
|
||||
};
|
||||
|
||||
EchoDataMem Echo_inpCycData;
|
||||
EchoDataMem Echo_outCycData;
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
|
||||
AppSettings app_settings = {
|
||||
.EthDevName = "enp6s1",
|
||||
};
|
||||
|
||||
ProfinetSettings settings = {
|
||||
.ticks_us = 1000,
|
||||
.EthIface = "enp6s1",
|
||||
.ticks_us = 1000, /// Период таймера в мкс
|
||||
.EthIface = "enp6s1", /// Имя интерфейса Ethernet к которому будет подключаться
|
||||
};
|
||||
|
||||
ProfinetDeviceSettings profinet_settings = {
|
||||
@ -56,8 +83,46 @@ int main(int argc, char * argv[])
|
||||
/// Настройка Profinet: Инициализация pnet, добавление DAP слотов и подслотов и подключение к ним модулей и подмодулей
|
||||
if (!profinet.Config(settings, profinet_settings))
|
||||
return 0;
|
||||
/**
|
||||
* @brief Создание тестового модуля ECHO
|
||||
* От контроллера принимает данные в составе 1 значения uint32_t и 1 значения float
|
||||
* Умножает их на определенное число Gain и передает получившиеся значения обратно в контроллер.
|
||||
*
|
||||
*/
|
||||
/// 1. Создаем тестовый модуль ECHO: module_id = 0x40
|
||||
auto echo_module_ptr = make_shared<ProfinetModule>(ECHO_MODULE_ID, "Echo module");
|
||||
|
||||
/// Тестовый слот и модуль ECHO: module_id = 0x40
|
||||
/// 2. Создаем конфигурацию циклических данных подмодуля
|
||||
pnet_data_cfg_t echo_data_cfg = { PNET_DIR_NO_IO, ECHO_INPUT_DATA_SIZE, ECHO_OUTPUT_DATA_SIZE };
|
||||
|
||||
/// 3. Создаем тестовый подмодуль для модуля ECHO
|
||||
auto echo_submodule_ptr = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_IDENT,
|
||||
"DAP Identity 1",
|
||||
echo_data_cfg,
|
||||
static_cast<void*>(Echo_inpCycData.mem),
|
||||
static_cast<void*>(Echo_outCycData.mem));
|
||||
|
||||
/// 4. Создаем конфигурационные данные подмодуля (не имеет отношения к echo_data_cfg). Это кастомные настройки подмодуля.
|
||||
auto echo_parameter = make_shared<ProfinetParameter>(ECHO_PARAMETER_GAIN_IDX,
|
||||
"Echo gain setting",
|
||||
(uint8_t *)&Echo_Gain,
|
||||
sizeof(Echo_Gain));
|
||||
|
||||
/// 5. Добавляем параметр к подмодулю
|
||||
echo_submodule_ptr->addParameter(echo_parameter);
|
||||
|
||||
/// 6. Добавляем подмодуль к модулю
|
||||
echo_module_ptr->addSubmodule(echo_submodule_ptr);
|
||||
|
||||
/// 7. Добавляем модуль к конфигурации. В этом месте модуль еще не активен, т.к. он не вставлен в слот.
|
||||
/// Это делает profinet controller.
|
||||
profinet.addModule(echo_module_ptr);
|
||||
|
||||
/// Циклические данные?
|
||||
|
||||
/**
|
||||
* Циклические данные устройства передаются с определенным периодом, сообщения от контроллера при этом не требуются.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
@ -145,7 +145,7 @@ static void pnetConfigure(pnet_cfg_t& cfg, ProfinetSettings& Settings, ProfinetD
|
||||
cfg.use_qualified_diagnosis = false;
|
||||
}
|
||||
|
||||
Profinet::Profinet(void) : m_pnet_data({nullptr, 0})
|
||||
Profinet::Profinet(void) : m_pnet_data({nullptr, 0, UINT32_MAX})
|
||||
{
|
||||
|
||||
}
|
||||
@ -192,11 +192,11 @@ bool Profinet::Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSet
|
||||
/// Создаем обязательный модуль DAP
|
||||
auto dap_module = make_shared<ProfinetModule>(PNET_MOD_DAP_IDENT, "DAP 1");
|
||||
/// Создаем обязательный подмодуль DAP Identity 1
|
||||
auto dap_submodule_indent_1 = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_IDENT, "DAP Identity 1", dap_data_cfg);
|
||||
auto dap_submodule_indent_1 = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_IDENT, "DAP Identity 1", dap_data_cfg, nullptr, nullptr);
|
||||
/// Создаем обязательный подмодуль DAP IFACE1 IDENT
|
||||
auto dap_submodule_iface_1_indent_1 = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_INTERFACE_1_IDENT, "DAP IFACE1 IDENT", dap_data_cfg);
|
||||
auto dap_submodule_iface_1_indent_1 = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_INTERFACE_1_IDENT, "DAP IFACE1 IDENT", dap_data_cfg, nullptr, nullptr);
|
||||
/// Создаем обязательный подмодуль DAP Port 1
|
||||
auto dap_subslot_iface_1_port1_ident = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, "DAP Port 1", dap_data_cfg);
|
||||
auto dap_subslot_iface_1_port1_ident = make_shared<ProfinetSubmodule>(PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, "DAP Port 1", dap_data_cfg, nullptr, nullptr);
|
||||
/// Добавляем подмодули к модулю
|
||||
ret&= dap_module->addSubmodule(dap_submodule_indent_1);
|
||||
ret&= dap_module->addSubmodule(dap_submodule_iface_1_indent_1);
|
||||
@ -204,7 +204,7 @@ bool Profinet::Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSet
|
||||
|
||||
/// Создаем слот для модуля DAP и доключаем к нему модуль dap_module
|
||||
ret&= addSlotAndPlugModule(PNET_SLOT_DAP_IDENT, dap_module);
|
||||
/// Добавляем подслоты к слоту и подключаем к подслоту подмодуль
|
||||
/// Добавляем подслоты к слоту PNET_SLOT_DAP_IDENT и подключаем к подслотам подмодули
|
||||
/// 1. Подмодуль "DAP Identity 1"
|
||||
ret&= addSubslotAndPlugSubmodule(PNET_SLOT_DAP_IDENT, PNET_SUBSLOT_DAP_IDENT, dap_submodule_indent_1);
|
||||
/// 2. Подмодуль "DAP IFACE1 IDENT"
|
||||
@ -415,6 +415,95 @@ std::shared_ptr<ProfinetParameter> Profinet::getSubmoduleParameter(uint16_t slot
|
||||
return param_ptr;
|
||||
}
|
||||
|
||||
void Profinet::initDataAndIoxs()
|
||||
{
|
||||
uint8_t indata_iops;
|
||||
/**
|
||||
* Итерируемся по всем слотам.
|
||||
* Если слоты есть, то и модули к ним уже подключены, т.к. это делает контроллер.
|
||||
*/
|
||||
for (auto slot : m_slots)
|
||||
{
|
||||
shared_ptr<ProfinetSlot>& slot_ptr = slot.second;
|
||||
|
||||
auto& subslots = slot_ptr->getSubslotsPtr();
|
||||
/// Итерируемся по всем подслотам
|
||||
for (auto subslot : subslots)
|
||||
{
|
||||
shared_ptr<ProfinetSubslot>& subslot_ptr = subslot.second;
|
||||
|
||||
auto submodule_ptr = subslot_ptr->getSubmodulePtr();
|
||||
|
||||
/// На всякий случай. Вообще если подслоты есть, то и подмодули уже к ним подключены.
|
||||
if (submodule_ptr == nullptr)
|
||||
continue;
|
||||
|
||||
indata_iops = PNET_IOXS_BAD;
|
||||
/**
|
||||
* @brief Если для подмодуля существуют входные данные (данные от устройства к контроллеру) или
|
||||
* циклических данных нет(DAP), то нужно установить статус IOPS.
|
||||
* submodule_ptr->m_data_cfg.data_dir == PNET_DIR_NO_IO - вот это условие нужно для установки статуса для DAP
|
||||
*/
|
||||
if ( submodule_ptr->m_data_cfg.insize > 0 ||
|
||||
submodule_ptr->m_data_cfg.data_dir == PNET_DIR_NO_IO )
|
||||
{
|
||||
/// Для данных DAP статус всегда ОК
|
||||
if (slot_ptr->m_slot_nbr == PNET_SLOT_DAP_IDENT)
|
||||
{
|
||||
/// Для данных DAP статус ОК
|
||||
indata_iops = PNET_IOXS_GOOD;
|
||||
}
|
||||
else if (submodule_ptr->m_data_cfg.insize > 0)
|
||||
{
|
||||
/// Проверка, что данные есть
|
||||
if (submodule_ptr->m_inp_data_ptr != nullptr)
|
||||
{
|
||||
indata_iops = PNET_IOXS_GOOD;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = pnet_input_set_data_and_iops ( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
(uint8_t*)submodule_ptr->m_inp_data_ptr, /// Указатель на данные
|
||||
submodule_ptr->m_data_cfg.insize, /// Размер данных
|
||||
indata_iops);
|
||||
|
||||
/*
|
||||
* If a submodule is still plugged but not used in current AR,
|
||||
* setting the data and IOPS will fail.
|
||||
* This is not a problem.
|
||||
* Log message below will only be printed for active submodules.
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
/// Успешно
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Если данные подмодуля включаются в себя выходные данные(данные от контроллера к устройству)
|
||||
* То нужно установить для них статус IOCS в PNET_IOXS_GOOD.
|
||||
*
|
||||
*/
|
||||
if (submodule_ptr->m_data_cfg.outsize > 0)
|
||||
{
|
||||
int ret = pnet_output_set_iocs ( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
PNET_IOXS_GOOD);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
/// Успешно
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**\
|
||||
* =========================================================================================
|
||||
* Callbacks
|
||||
@ -423,6 +512,63 @@ std::shared_ptr<ProfinetParameter> Profinet::getSubmoduleParameter(uint16_t slot
|
||||
|
||||
int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||
{
|
||||
uint16_t err_cls = 0; /* Error code 1 */
|
||||
uint16_t err_code = 0; /* Error code 2 */
|
||||
const char * error_class_description = "";
|
||||
const char * error_code_description = "";
|
||||
|
||||
if (event == PNET_EVENT_ABORT)
|
||||
{
|
||||
if (pnet_get_ar_error_codes (m_pnet_data.pnet_ptr, arep, &err_cls, &err_code) == 0)
|
||||
{
|
||||
/**
|
||||
* @brief Коды ошибок в err_cls и err_code
|
||||
* TODO: Нужно передавать в управляющее приложение
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Ошибок нет
|
||||
}
|
||||
|
||||
|
||||
/* Only abort AR with correct session key */
|
||||
///os_event_set (app->main_events, APP_EVENT_ABORT);
|
||||
}
|
||||
else if (event == PNET_EVENT_PRMEND)
|
||||
{
|
||||
if (isConnectedToController())
|
||||
{
|
||||
/// Если уже были подключены и пришел запрос на еще одно подключение
|
||||
}
|
||||
|
||||
m_pnet_data.arep = arep;
|
||||
|
||||
initDataAndIoxs();
|
||||
|
||||
(void)pnet_set_provider_state (m_pnet_data.pnet_ptr, true);
|
||||
/**
|
||||
* @brief Костыль библиотеки pnet:
|
||||
* По правилам Profinet нужно ответить Application ready.
|
||||
* Однако тут нельзя вызвать pnet_application_ready, т.к. это испортит
|
||||
* внутреннее состояние стэка pnet.
|
||||
* Это нужно делать на следующем "тике".
|
||||
* См. описание pnet_application_ready:
|
||||
* This function must be called after the application has received the pnet_state_ind()
|
||||
* user callback with PNET_EVENT_PRMEND, in order for a connection to be established.
|
||||
*
|
||||
*/
|
||||
/* Send application ready at next tick
|
||||
Do not call pnet_application_ready() here as it will affect
|
||||
the internal stack states */
|
||||
m_pnet_data.arep_for_appl_ready = arep;
|
||||
|
||||
///os_event_set (app->main_events, APP_EVENT_READY_FOR_DATA); ///
|
||||
}
|
||||
else if (event == PNET_EVENT_DATA)
|
||||
{
|
||||
/// Стартовал обмен cyclic io
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,10 @@ private:
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> getSubslotPtr(uint16_t slot_nbr, uint16_t subslot_nbr);
|
||||
|
||||
bool isConnectedToController() { return m_pnet_data.arep != UINT32_MAX; };
|
||||
|
||||
void initDataAndIoxs();
|
||||
|
||||
public:
|
||||
/**
|
||||
*
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
struct ProfinetParameter
|
||||
{
|
||||
ProfinetParameter(std::string Name, uint32_t Index, uint8_t * pData, uint16_t Length) :
|
||||
name(Name),
|
||||
ProfinetParameter(uint32_t Index, std::string Name, uint8_t * pData, uint16_t Length) :
|
||||
index(Index),
|
||||
name(Name),
|
||||
data_ptr(pData),
|
||||
length(Length) {};
|
||||
|
||||
|
@ -5,4 +5,6 @@
|
||||
struct ProfinetServiceData {
|
||||
pnet_t * pnet_ptr;
|
||||
uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet
|
||||
uint32_t arep; /// Аналогично
|
||||
uint32_t arep_for_appl_ready; /// Костыль pnet
|
||||
};
|
@ -55,6 +55,8 @@ public:
|
||||
|
||||
std::shared_ptr<ProfinetModule> getModulePtr();
|
||||
|
||||
std::map<uint16_t, std::shared_ptr<ProfinetSubslot>>& getSubslotsPtr() { return m_subslots; };
|
||||
|
||||
public:
|
||||
/// Номер слота
|
||||
const uint16_t m_slot_nbr;
|
||||
|
@ -2,10 +2,14 @@
|
||||
|
||||
ProfinetSubmodule::ProfinetSubmodule(uint16_t submodule_id,
|
||||
std::string submodule_name,
|
||||
pnet_data_cfg_t& submodule_data_cfg) :
|
||||
pnet_data_cfg_t& submodule_data_cfg,
|
||||
void * const inp_data_ptr,
|
||||
void * const out_data_ptr) :
|
||||
m_id(submodule_id),
|
||||
m_name(submodule_name),
|
||||
m_data_cfg(submodule_data_cfg)
|
||||
m_data_cfg(submodule_data_cfg),
|
||||
m_inp_data_ptr(inp_data_ptr),
|
||||
m_out_data_ptr(out_data_ptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -13,19 +13,25 @@ class ProfinetSubmodule {
|
||||
public:
|
||||
ProfinetSubmodule(uint16_t submodule_id,
|
||||
std::string submodule_name,
|
||||
pnet_data_cfg_t& submodule_data_cfg);
|
||||
pnet_data_cfg_t& submodule_data_cfg,
|
||||
void * const inp_data_ptr,
|
||||
void * const out_data_ptr);
|
||||
|
||||
bool addParameter(std::shared_ptr<ProfinetParameter>& param);
|
||||
|
||||
std::shared_ptr<ProfinetParameter> getParameterPtr(uint32_t index);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
const uint16_t m_id; /// Идентификатор подмодуля
|
||||
const std::string m_name; /// Имя подмодуля
|
||||
const pnet_data_cfg_t m_data_cfg; /// Конфигурация циклических данных подмодуля
|
||||
|
||||
void * const m_inp_data_ptr; /// Входные циклические данные (DEV->PLC)
|
||||
void * const m_out_data_ptr; /// Выходные циклические данные (PLC->DEV)
|
||||
|
||||
private:
|
||||
/// Набор параметров подмодуля
|
||||
std::map<uint32_t, std::shared_ptr<ProfinetParameter>> m_params;
|
||||
|
||||
};
|
@ -9,7 +9,6 @@
|
||||
#include "profinet_serv_data.hpp"
|
||||
#include "profinet_submodule.hpp"
|
||||
|
||||
|
||||
class ProfinetSubslot
|
||||
{
|
||||
public:
|
||||
@ -47,6 +46,3 @@ private:
|
||||
/// Подмодуль вставленный в этот подслот
|
||||
std::shared_ptr<ProfinetSubmodule> m_submodule_ptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user