From d5c127d91157df3988a23ada648a29d9c582ec80 Mon Sep 17 00:00:00 2001 From: Vadim Sychev Date: Fri, 29 Jul 2022 14:15:25 +0300 Subject: [PATCH] =?UTF-8?q?dev(UML-981):=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=BC=D0=B5=D1=85=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=20=D0=B5=D0=B2=D0=B5=D0=BD=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BE=D1=82=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BD=D0=B5?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B4=D0=BE=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/flags/flags.hpp | 11 ++++++ src/main.cpp | 55 ++++++++++++++++++++--------- src/profinet/profinet.cpp | 37 ++++++++++++------- src/profinet/profinet.hpp | 38 ++++++++++++++++---- src/profinet/profinet_submodule.cpp | 12 +++++-- 5 files changed, 115 insertions(+), 38 deletions(-) diff --git a/src/flags/flags.hpp b/src/flags/flags.hpp index 61e0570..d28a327 100644 --- a/src/flags/flags.hpp +++ b/src/flags/flags.hpp @@ -2,6 +2,7 @@ #include #include +#include class Flags { public: @@ -10,6 +11,7 @@ public: void set_flag(uint32_t mask) { std::lock_guard guard(mutex_); flags_ |= mask; + flag_cond_.notify_one(); } uint32_t get_flag(uint32_t mask) { @@ -28,7 +30,16 @@ public: flags_ &= ~mask; } + uint32_t wait_flags(uint32_t mask) + { + std::unique_lock lk(mutex_); + flag_cond_.wait(lk, [&]{return flags_ & mask;}); + lk.unlock(); + return flags_; + } + private: uint32_t flags_; mutable std::mutex mutex_; + std::condition_variable flag_cond_; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 898171e..f174f7b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,11 +44,8 @@ void endian_convert_32(uint8_t * p_data) int main(int argc, char * argv[]) { - Echo_inpCycData.data.data_f = 54321.9f; /// Преобразовать в big endian - Echo_inpCycData.data.data_i = 876; /// Преобразовать в big endian - - endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f); - endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i); + Echo_inpCycData.data.data_f = 0.0f; /// Преобразовать в big endian + Echo_inpCycData.data.data_i = 0; /// Преобразовать в big endian Echo_outCycData.data.data_f = 0.0f; Echo_outCycData.data.data_i = 0; @@ -83,6 +80,11 @@ int main(int argc, char * argv[]) /// Запуск потока Profinet profinet.Start(); + + /** + * @brief Ниже тестовый функционал + * + */ auto echo_mod = profinet.getModule(ECHO_MODULE_ID); auto echo_submod = echo_mod->getSubmodulePtr(ECHO_SUBMOD_ID); echo_submod->putDataToPlc(Echo_inpCycData.mem); @@ -90,24 +92,31 @@ int main(int argc, char * argv[]) auto param = echo_submod->getParameterPtr(ECHO_PARAMETER_GAIN_IDX); - uint32_t ix = 0; - while(1) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - ++ix; - std::cout << "tick: " << ix << endl; - if (echo_submod->isDataUpdated()) + uint32_t event_mask = (Profinet::EVENT_CONNECTION_ESTABLISHED | + Profinet::EVENT_NEW_CYCLIC_DATA | + Profinet::EVENT_NEW_PARAM_DATA ); + for (;;) + { + uint32_t events = profinet.EventWait(event_mask); + //std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + //++ix; + //std::cout << "tick: " << ix << endl; + + if (events & Profinet::EVENT_CONNECTION_ESTABLISHED) { - std::cout << "New data from Plc" << endl; + profinet.EventClear(Profinet::EVENT_CONNECTION_ESTABLISHED); + + std::cout << "Event: PLC connection established" << endl; + } + else if (events & Profinet::EVENT_NEW_CYCLIC_DATA) + { + profinet.EventClear(Profinet::EVENT_NEW_CYCLIC_DATA); + ///Читаем данные от ПЛК echo_submod->getDataFromPlc(Echo_outCycData.mem); - //Читаем параметр записанный ПЛК при установлении связи - param->readParameter((uint8_t*)&Echo_Gain); /// Конвертируем в литл эндиан - endian_convert_32((uint8_t*)&Echo_Gain); endian_convert_32((uint8_t*)&Echo_outCycData.data.data_i); endian_convert_32((uint8_t*)&Echo_outCycData.data.data_f); - ///Подготавливаем данные для ПЛК Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i; Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f; @@ -116,6 +125,18 @@ int main(int argc, char * argv[]) endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f); ///Отправляем данные для ПЛК echo_submod->putDataToPlc(Echo_inpCycData.mem); + + } + else if (events & Profinet::EVENT_NEW_PARAM_DATA) + { + profinet.EventClear(Profinet::EVENT_NEW_PARAM_DATA); + + std::cout << "Event: New parameter data: "; + //Читаем параметр записанный ПЛК при установлении связи + param->readParameter((uint8_t*)&Echo_Gain); + /// Конвертируем в литл эндиан + endian_convert_32((uint8_t*)&Echo_Gain); + std::cout << "Echo_Gain = " << std::to_string(Echo_Gain) << endl; } } diff --git a/src/profinet/profinet.cpp b/src/profinet/profinet.cpp index 1d3c0d5..b4a4bf7 100644 --- a/src/profinet/profinet.cpp +++ b/src/profinet/profinet.cpp @@ -33,7 +33,6 @@ using namespace std; #define GET_HIGH_BYTE(id) ((id >> 8) & 0xFF) #define GET_LOW_BYTE(id) (id & 0xFF) -#define APP_MAIN_SLEEPTIME_US 5000 * 1000 #define APP_SNMP_THREAD_PRIORITY 1 #define APP_SNMP_THREAD_STACKSIZE 256 * 1024 /* bytes */ #define APP_ETH_THREAD_PRIORITY 10 @@ -43,9 +42,9 @@ using namespace std; #define FLAGS_AREP_APP_READY 0x00000001 -//#define RELEASE +#define LOG_ENABLE -#ifndef RELEASE +#ifdef LOG_ENABLE #define LOG(STR) log_.put(STR) #else #define LOG(STR) @@ -588,15 +587,16 @@ void Profinet::cyclicIoData() 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 submodule_ptr->outputGetData( m_pnet_data.pnet_ptr, m_pnet_data.api, slot_ptr->m_slot_nbr, - subslot_ptr->m_subslot_nbr); + subslot_ptr->m_subslot_nbr); + + if (submodule_ptr->isDataUpdated()) + { + events_.set_flag(EVENT_NEW_CYCLIC_DATA); + } } if (submodule_ptr->m_data_cfg.insize > 0) @@ -672,12 +672,17 @@ int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event) * @brief Коды ошибок в err_cls и err_code * TODO: Нужно передавать в управляющее приложение */ + } else { /// Ошибок нет } + events_.clear_flags(EVENT_CONNECTION_ESTABLISHED); + + m_pnet_data.arep = UINT32_MAX; + /* Only abort AR with correct session key */ ///os_event_set (app->main_events, APP_EVENT_ABORT); } @@ -719,6 +724,7 @@ int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event) else if (event == PNET_EVENT_STARTUP) { LOG("callbackStateInd: PNET_EVENT_STARTUP: A connection has been initiated."); + events_.set_flag(EVENT_CONNECTION_ESTABLISHED); } else if (event == PNET_EVENT_APPLRDY) { @@ -769,10 +775,7 @@ int Profinet::callbackDcontrolInd ( uint32_t arep, int Profinet::callbackCcontrolInd ( uint32_t arep, pnet_result_t * p_result) { LOG("callbackCcontrolInd"); - /** - * @brief - * Можно оставить пустым - */ + return 0; } @@ -854,7 +857,15 @@ int Profinet::callbackWriteInd ( uint32_t arep, } ///3. Копируем данные - return param_ptr->writeParameter(p_write_data); + if (!param_ptr->writeParameter(p_write_data)) + { + return -1; + } + + /// Устанавливаем событие + events_.set_flag(EVENT_NEW_PARAM_DATA); + + return 0; } int Profinet::callbackExpModuleInd ( uint16_t slot, uint32_t module_ident) diff --git a/src/profinet/profinet.hpp b/src/profinet/profinet.hpp index b4399dd..4986d18 100644 --- a/src/profinet/profinet.hpp +++ b/src/profinet/profinet.hpp @@ -18,6 +18,13 @@ class Profinet { public: + enum Events + { + EVENT_CONNECTION_ESTABLISHED = 0x00000001, /// Установлено соединение с ПЛК + EVENT_NEW_CYCLIC_DATA = 0x00000002, /// Получение новых циклических данных от ПЛК + EVENT_NEW_PARAM_DATA = 0x00000004, /// Новая запись параметра от ПЛК + }; + Profinet(); bool Config(ProfinetSettings& Settings, @@ -143,6 +150,11 @@ public: */ void Start(); + uint32_t EventWait(uint32_t mask) { return events_.wait_flags(mask); } + + void EventClear(uint32_t mask) { events_.clear_flags(mask); } + + ~Profinet(); private: @@ -168,22 +180,36 @@ private: std::map> m_modules; Log log_; - - Flags flags_; - + Flags flags_; /// Внутренние флаги: взаимодействиe между потоком Profinet и потоком стека Pnet + + Flags events_; /// Флаги для внешних событий. Это более общие флаги, например флаг получения данных от ПЛК, а в каком подмодуле, уже не уточняется. private: /** - * @brief Проверяет наличие слота slot_nbr в конфигурации + * @brief Проверяет наличие слота slot_nbr в конфигурации и возвращает указатель на него * * @param slot_nbr номер слота - * @return ProfinetSlot* - указатель на слот, при успехе или nullptr есои слот в конфигурации отсутсвует + * @return std::shared_ptr указатель на слот, при успехе или nullptr если слот в конфигурации отсутсвует */ std::shared_ptr getSlotPtr(uint16_t slot_nbr); - + /** + * @brief Проверяет наличие подслота в слоте и возвращает указатель на него + * + * @param slot_nbr номер слота + * @param subslot_nbr номер подслота + * @return std::shared_ptr указатель на подслот, при успехе или nullptr если подслот в конфигурации отсутсвует + */ std::shared_ptr getSubslotPtr(uint16_t slot_nbr, uint16_t subslot_nbr); + /** + * @brief Флаг подключение к контроллеру(ПЛК). + * Реализация взята с примера стека pnet. На самом деле не понятна роль AREP. + * Открытой информации недостаточно, нужно покупать и смотреть спецификацию. * + * + * @return true подключение есть + * @return false + */ bool isConnectedToController() { return m_pnet_data.arep != UINT32_MAX; }; void initDataAndIoxs(); diff --git a/src/profinet/profinet_submodule.cpp b/src/profinet/profinet_submodule.cpp index 9bea6db..4f7c084 100644 --- a/src/profinet/profinet_submodule.cpp +++ b/src/profinet/profinet_submodule.cpp @@ -78,6 +78,8 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr, uint16_t slot_nbr, uint16_t subslot_nbr ) { + bool out = true; + /// Существуют подмодули без данных, например DAP if ((pnet_ptr == nullptr) || (out_data_ptr_ == nullptr)) { @@ -104,19 +106,25 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr, if ((!data_updated_) && (updated == true)) { - data_updated_ = updated; /// Сбрасывается после прочтения данных устройством + /** + * @brief Устанавливаем флаг новых данных (данные смогут быть такие-же, но флаг все равно установится) + * Флаг сбрасывается в функции getDataFromPlc после прочтения данных устройством + */ + data_updated_ = updated; } if (m_data_cfg.outsize != outdata_length) { /// Неправильная длина данных + out = false; } else if (outdata_iops == PNET_IOXS_BAD) { /// Что-то не так с данными от контроллера + out = false; } - return true; + return out; } bool ProfinetSubmodule::getDataFromPlc(uint8_t * data_ptr)