diff --git a/src/main.cpp b/src/main.cpp index 52be0b6..48e5248 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "app_settings.hpp" #include "../libs/include/pnet_api.h" #include "profinet.hpp" +#include #define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля #define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля @@ -118,11 +119,16 @@ int main(int argc, char * argv[]) /// Это делает profinet controller. profinet.addModule(echo_module_ptr); - /// Циклические данные? - /** * Циклические данные устройства передаются с определенным периодом, сообщения от контроллера при этом не требуются. */ + /// Запуск потока Profinet + profinet.Start(); + + while(1) + { + } + return 0; } \ No newline at end of file diff --git a/src/profinet/profinet.cpp b/src/profinet/profinet.cpp index 2798489..043c409 100644 --- a/src/profinet/profinet.cpp +++ b/src/profinet/profinet.cpp @@ -23,6 +23,9 @@ #include #include +#include +#include + using namespace std; @@ -145,9 +148,10 @@ static void pnetConfigure(pnet_cfg_t& cfg, ProfinetSettings& Settings, ProfinetD cfg.use_qualified_diagnosis = false; } -Profinet::Profinet(void) : m_pnet_data({nullptr, 0, UINT32_MAX}) +Profinet::Profinet() : m_pnet_data({nullptr, 0, UINT32_MAX, 0}), + m_cyclic_io_cnt{0}, + m_periodic_stop{false} { - } bool Profinet::Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSettings) @@ -161,6 +165,12 @@ bool Profinet::Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSet std::memset(&pnet_cfg, 0, sizeof(pnet_cfg)); pnetConfigure(pnet_cfg, Settings, DevSettings); + + m_run_period_us = Settings.ticks_us; + m_cyclic_io_period_ms = Settings.cyclic_ms; + + + ///TODO Определить что передавать в cb_cfg pnet_cfg.cb_arg = static_cast(this); @@ -504,12 +514,125 @@ void Profinet::initDataAndIoxs() } } +void Profinet::PeriodicOperations() +{ + while(!m_periodic_stop.load(std::memory_order_relaxed)) + { + /// Ждем время в мкс: ticks_period_us, по умолчанию 1мс + std::this_thread::sleep_for(std::chrono::microseconds(m_run_period_us)); + + /// Вызов cyclic io + if (++m_cyclic_io_cnt >= m_cyclic_io_period_ms) + { + m_cyclic_io_cnt = 0; + cyclicIoData(); + } + + /// запускаем pnet + pnet_handle_periodic (m_pnet_data.pnet_ptr); + } +} + +void Profinet::cyclicIoData() +{ + for (auto slot : m_slots) + { + shared_ptr& slot_ptr = slot.second; + + /// DAP слот игнорируем при циклическом обмене + if (slot_ptr->m_slot_nbr == PNET_SLOT_DAP_IDENT) + continue; + + auto& subslots = slot_ptr->getSubslotsPtr(); + /// Итерируемся по всем подслотам + for (auto subslot : subslots) + { + shared_ptr& subslot_ptr = subslot.second; + + auto submodule_ptr = subslot_ptr->getSubmodulePtr(); + + /// На всякий случай. Вообще если подслоты есть, то и подмодули уже к ним подключены. + if (submodule_ptr == nullptr) + continue; + + if (submodule_ptr->m_data_cfg.outsize > 0) + { + bool outdata_updated; + uint16_t outdata_length = submodule_ptr->m_data_cfg.outsize; + uint8_t outdata_iops; + + /// Копируем данные от контроллера в m_out_data_ptr + (void)pnet_output_get_data_and_iops ( + m_pnet_data.pnet_ptr, + m_pnet_data.api, + slot_ptr->m_slot_nbr, + subslot_ptr->m_subslot_nbr, + &outdata_updated, + (uint8_t*)submodule_ptr->m_out_data_ptr, + &outdata_length, + &outdata_iops); + + submodule_ptr->m_outdata_iops = outdata_iops; + + if (submodule_ptr->m_data_cfg.outsize != outdata_length) + { + /// Неправильная длина данных + } + else if (outdata_iops == PNET_IOXS_BAD) + { + /// Что-то не так с данными от контроллера + } + } + + if (submodule_ptr->m_data_cfg.insize > 0) + { + uint8_t indata_iocs; + uint8_t indata_iops = PNET_IOXS_GOOD; + /* Send input data to the PLC */ + (void)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); + + (void)pnet_input_get_iocs ( + m_pnet_data.pnet_ptr, + m_pnet_data.api, + slot_ptr->m_slot_nbr, + subslot_ptr->m_subslot_nbr, + &indata_iocs); + + submodule_ptr->m_indata_iocs = indata_iocs; + } + } + } +} + +void Profinet::Start() +{ + m_periodic_thread = std::move(std::thread(&Profinet::PeriodicOperations, this)); +} + +Profinet::~Profinet() +{ + ///Остановка потока + m_periodic_stop.store(true, std::memory_order_relaxed); + + if (m_periodic_thread.joinable()) + { + m_periodic_thread.join(); + } +} + + /**\ * ========================================================================================= * Callbacks * ========================================================================================= */ - int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event) { uint16_t err_cls = 0; /* Error code 1 */ diff --git a/src/profinet/profinet.hpp b/src/profinet/profinet.hpp index a1fe468..5125745 100644 --- a/src/profinet/profinet.hpp +++ b/src/profinet/profinet.hpp @@ -8,6 +8,9 @@ #include "profinet_slot.hpp" #include "profinet_serv_data.hpp" +#include +#include + class Profinet { public: Profinet(); @@ -121,8 +124,31 @@ public: */ std::shared_ptr getSubmoduleParameter(uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t param_index); + /** + * @brief Таймер для циклического обмена данными + * + */ + void PeriodicOperations(); + + /** + * @brief Запуск потока + * + */ + void Start(); + + ~Profinet(); + private: ProfinetServiceData m_pnet_data; + + uint32_t m_run_period_us; /// Период одного тика (цикла) выполнения + + uint32_t m_cyclic_io_period_ms; /// Период циклического обмена + uint32_t m_cyclic_io_cnt; /// Счетчик циклического обмена + + std::thread m_periodic_thread; /// Поток в котором исполняется PeriodicOperations + std::atomic m_periodic_stop; /// Флаг завершения потока + /** * @brief Ключ - номер слота, Значение - указатель на слот * @@ -149,6 +175,8 @@ private: void initDataAndIoxs(); + void cyclicIoData(); + public: /** * diff --git a/src/profinet/profinet_serv_data.hpp b/src/profinet/profinet_serv_data.hpp index 3ad48d5..0c6074e 100644 --- a/src/profinet/profinet_serv_data.hpp +++ b/src/profinet/profinet_serv_data.hpp @@ -3,8 +3,8 @@ #include "../../libs/include/pnet_api.h" struct ProfinetServiceData { - pnet_t * pnet_ptr; - uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet - uint32_t arep; /// Аналогично - uint32_t arep_for_appl_ready; /// Костыль pnet + pnet_t * pnet_ptr; /// Указатель на pnet + uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet + uint32_t arep; /// Аналогично + uint32_t arep_for_appl_ready; /// Костыль для pnet (нужно реализовать как в примере) }; \ No newline at end of file diff --git a/src/profinet/profinet_settings.hpp b/src/profinet/profinet_settings.hpp index d4b3e7d..ade861b 100644 --- a/src/profinet/profinet_settings.hpp +++ b/src/profinet/profinet_settings.hpp @@ -83,5 +83,6 @@ struct ProfinetDeviceSettings { /// Настройки не зависящие от описания данных Profinet struct ProfinetSettings { uint32_t ticks_us = 1000; /// Устанавливает время в мкс между вызовами pnet_handle_periodic() + uint32_t cyclic_ms = 100; /// Устанавливает период в мс для циклического обмена данными std::string EthIface = ""; /// Имя интерфейса ethernet }; \ No newline at end of file diff --git a/src/profinet/profinet_submodule.cpp b/src/profinet/profinet_submodule.cpp index e6c99d4..4f30843 100644 --- a/src/profinet/profinet_submodule.cpp +++ b/src/profinet/profinet_submodule.cpp @@ -9,7 +9,9 @@ ProfinetSubmodule::ProfinetSubmodule(uint16_t submodule_id, m_name(submodule_name), m_data_cfg(submodule_data_cfg), m_inp_data_ptr(inp_data_ptr), - m_out_data_ptr(out_data_ptr) + m_out_data_ptr(out_data_ptr), + m_indata_iocs(0), + m_outdata_iops(0) { } diff --git a/src/profinet/profinet_submodule.hpp b/src/profinet/profinet_submodule.hpp index 3ccd898..47fa998 100644 --- a/src/profinet/profinet_submodule.hpp +++ b/src/profinet/profinet_submodule.hpp @@ -28,6 +28,12 @@ public: const std::string m_name; /// Имя подмодуля const pnet_data_cfg_t m_data_cfg; /// Конфигурация циклических данных подмодуля + /// iocs = I/O consumer status data (формат данных из pnet_ioxs_values_t) + uint8_t m_indata_iocs; + + /// iops = I/O provider status data (формат данных из pnet_ioxs_values_t) + uint8_t m_outdata_iops; + void * const m_inp_data_ptr; /// Входные циклические данные (DEV->PLC) void * const m_out_data_ptr; /// Выходные циклические данные (PLC->DEV) diff --git a/src/profinet/profinet_subslot.cpp b/src/profinet/profinet_subslot.cpp index 3d83764..b45666f 100644 --- a/src/profinet/profinet_subslot.cpp +++ b/src/profinet/profinet_subslot.cpp @@ -4,8 +4,6 @@ ProfinetSubslot::ProfinetSubslot(uint16_t subslot_nbr, uint16_t slot_nbr, uint32 m_subslot_nbr(subslot_nbr), m_slot_nbr(slot_nbr), m_module_id(module_id), - m_indata_iocs(0), - m_outdata_iops(0), m_submodule_ptr(nullptr) { diff --git a/src/profinet/profinet_subslot.hpp b/src/profinet/profinet_subslot.hpp index c78d220..3c81e3d 100644 --- a/src/profinet/profinet_subslot.hpp +++ b/src/profinet/profinet_subslot.hpp @@ -37,12 +37,6 @@ private: /// Идентификатор модуля куда входит подключаемый подмодуль uint32_t m_module_id; - /// iocs = I/O consumer status data (формат данных из pnet_ioxs_values_t) - uint8_t m_indata_iocs; - - /// iops = I/O provider status data (формат данных из pnet_ioxs_values_t) - uint8_t m_outdata_iops; - /// Подмодуль вставленный в этот подслот std::shared_ptr m_submodule_ptr; }; \ No newline at end of file