dev(UML-981): Небольшой рефакторинг

1. разработаны абстрактные классы флагов и разделяемых даннных. Модуль
profinet их использует.
2. Разделяемые данныне переделаны на использование мьютексов буста
This commit is contained in:
Vadim Sychev 2022-08-04 14:21:05 +03:00
parent 3fdd61b35c
commit b992c1c3a6
19 changed files with 166 additions and 169 deletions

View File

@ -38,45 +38,8 @@ bool App::Init(std::string profinet_config_file)
void App::Run()
{
//пауза
std::this_thread::sleep_for(std::chrono::milliseconds(100));
uint32_t event_mask = (Profinet::EVENT_CONNECTION_ESTABLISHED |
Profinet::EVENT_NEW_CYCLIC_DATA |
Profinet::EVENT_NEW_PARAM_DATA |
Profinet::EVENT_CONNECTION_ABORT);
for (;;)
{
//std::cout << "App: Waiting event flag" << std::endl;
uint32_t events = profinet_.EventWait(event_mask);
//std::cout << "App: New flag = " << std::to_string(events) << std::endl;
if (events & Profinet::EVENT_CONNECTION_ESTABLISHED)
{
std::cout << "App: EVENT_CONNECTION_ESTABLISHED" << std::endl;
profinet_.EventClear(Profinet::EVENT_CONNECTION_ESTABLISHED);
shared_data_.p_profinet_data_->Events.set_flag(ProfinetEvent::EVENT_CONNECTION_ESTABLISHED);
}
if (events & Profinet::EVENT_NEW_CYCLIC_DATA)
{
//std::cout << "App: EVENT_NEW_CYCLIC_DATA" << std::endl;
profinet_.EventClear(Profinet::EVENT_NEW_CYCLIC_DATA);
shared_data_.p_profinet_data_->Events.set_flag(ProfinetEvent::EVENT_NEW_CYCLIC_DATA);
}
if (events & Profinet::EVENT_NEW_PARAM_DATA)
{
std::cout << "App: Clear: EVENT_NEW_PARAM_DATA" << std::endl;
profinet_.EventClear(Profinet::EVENT_NEW_PARAM_DATA);
shared_data_.p_profinet_data_->Events.set_flag(ProfinetEvent::EVENT_NEW_PARAM_DATA);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}

View File

@ -9,6 +9,6 @@ public:
bool Init(std::string profinet_config_file);
void Run();
private:
Profinet profinet_;
ProfinetSharedData shared_data_;
Profinet profinet_;
};

View File

@ -6,24 +6,23 @@
#include <iostream>
class Flags {
#include "flags_iface.hpp"
class Flags : public FlagsIface {
public:
Flags() : flags_{0} {
///Блокируем мьютекс ожидания
mutex_wait_.lock();
}
void set_flag(uint32_t mask) {
virtual void set_flag(uint32_t mask) override
{
{
std::lock_guard<std::mutex> guard(mutex_);
flags_ |= mask;
}
/// Разблокируем мьютекс ожидания
mutex_wait_.unlock();
//flag_cond_.notify_all();
flag_cond_.notify_all();
}
uint32_t get_flag(uint32_t mask) {
virtual uint32_t get_flag(uint32_t mask) override {
uint32_t out;
{
std::lock_guard<std::mutex> guard(mutex_);
@ -32,7 +31,7 @@ public:
return out;
}
uint32_t get_flags() {
virtual uint32_t get_flags() override {
uint32_t out;
{
std::lock_guard<std::mutex> guard(mutex_);
@ -42,29 +41,18 @@ public:
return out;
}
void clear_flags(uint32_t mask)
virtual void clear_flags(uint32_t mask) override
{
std::lock_guard<std::mutex> guard(mutex_);
flags_ &= ~mask;
}
uint32_t wait_flags(uint32_t mask)
{
mutex_wait_.lock(); //Ожидаем изменения данных
uint32_t out;
{
std::lock_guard<std::mutex> guard(mutex_);
out = flags_ & mask;
}
return out;
}
/**
* @brief Блочит потоки pnet. Нужно разбираться.
* @brief Данная реализация блочит потоки pnet.
* Нужно разбираться.
*
*/
/*uint32_t wait_condition(uint32_t mask)
virtual uint32_t wait_flags(uint32_t mask) override
{
uint32_t out;
std::unique_lock<std::mutex> lk(mutex_);
@ -72,10 +60,9 @@ public:
out = flags_ & mask;
lk.unlock();
return out;
}*/
}
private:
uint32_t flags_;
std::mutex mutex_;
std::mutex mutex_wait_;
//std::condition_variable flag_cond_;
std::condition_variable flag_cond_;
};

19
src/flags/flags_iface.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
class FlagsIface {
public:
virtual void set_flag(uint32_t mask) = 0;
virtual uint32_t get_flag(uint32_t mask) = 0;
virtual uint32_t get_flags() = 0;
virtual void clear_flags(uint32_t mask) = 0;
virtual uint32_t wait_flags(uint32_t mask) = 0;
virtual ~FlagsIface() {}
};

View File

@ -3,25 +3,26 @@
#include <cstdint>
#include <mutex>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
class SharedFlags {
#include "flags_iface.hpp"
class SharedFlags : public FlagsIface {
public:
SharedFlags() : flags_{0} {
///Блокируем мьютекс ожидания
mutex_wait_.lock();
}
void set_flag(uint32_t mask) {
virtual void set_flag(uint32_t mask) override {
{
std::lock_guard guard(mutex_);
flags_ |= mask;
}
/// Разблокируем мьютекс ожидания
mutex_wait_.unlock();
//flag_cond_.notify_all();
/// Уведомляем об изменении флага
flag_cond_.notify_all();
}
uint32_t get_flag(uint32_t mask) {
virtual uint32_t get_flag(uint32_t mask) override {
uint32_t out;
{
std::lock_guard guard(mutex_);
@ -30,7 +31,7 @@ public:
return out;
}
uint32_t get_flags() {
virtual uint32_t get_flags() override{
uint32_t out;
{
std::lock_guard guard(mutex_);
@ -40,39 +41,27 @@ public:
return out;
}
void clear_flags(uint32_t mask)
virtual void clear_flags(uint32_t mask) override
{
std::lock_guard guard(mutex_);
flags_ &= ~mask;
}
uint32_t wait_flags(uint32_t mask)
virtual uint32_t wait_flags(uint32_t mask) override
{
mutex_wait_.lock(); //Ожидаем изменения данных
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> lock(mutex_wait_);
flag_cond_.wait(lock); //Ожидаем изменения данных
/// Данные изменились
uint32_t out;
{
std::lock_guard guard(mutex_);
out = flags_ & mask;
}
return out;
}
/**
* @brief Блочит потоки pnet. Нужно разбираться.
*
*/
/*uint32_t wait_condition(uint32_t mask)
{
uint32_t out;
std::unique_lock<std::mutex> lk(mutex_);
flag_cond_.wait(lk, [this, mask]{return static_cast<bool>(flags_ & mask);});
out = flags_ & mask;
lk.unlock();
return out;
}*/
private:
uint32_t flags_;
boost::interprocess::interprocess_mutex mutex_;
boost::interprocess::interprocess_mutex mutex_wait_;
boost::interprocess::interprocess_condition flag_cond_;
};

View File

@ -36,11 +36,11 @@ static uint32_t calc_mem_size(ProfinetData_Map& data_settings)
ProfinetData_Map * ProfinetSharedData::Create(std::string mem_name)
{
/// Удаляем существубющий кусок памяти
/// Если память уже выделена, удаляем
shared_memory_object::remove(mem_name.c_str());
shmem_ = managed_shared_memory{create_only, mem_name.c_str(), 65536};
shmem_ = managed_shared_memory{create_only, mem_name.c_str(), 65536};
mem_name_ = mem_name;
///Создаем данные в разделяемой памяти
p_profinet_data_ = shmem_.construct<ProfinetData_Map>("ProfinetData_Map")();
return p_profinet_data_;

View File

@ -7,8 +7,14 @@
#include "../profinet/profinet_data_map.hpp"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
class ProfinetSharedData {
public:
~ProfinetSharedData() {
///Удаляем память
//boost::interprocess::shared_memory_object::remove(mem_name_.c_str());
}
/**
* @brief Выделяыет раздеяемую память под структуру ProfinetData_Map
*
@ -27,5 +33,5 @@ public:
private:
boost::interprocess::managed_shared_memory shmem_;
std::string mem_name_;
};

View File

@ -3,6 +3,8 @@
#include "../profinet/profinet_data_map.hpp"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>
class ProfinetSharedDataClient {
public:
/**
@ -11,9 +13,29 @@ public:
* @param mem_name
*/
ProfinetData_Map * Connect(std::string mem_name) {
shmem_ = boost::interprocess::managed_shared_memory{boost::interprocess::open_only, mem_name.c_str()};
auto mem = shmem_.find<ProfinetData_Map>("ProfinetData_Map");
return mem.first;
ProfinetData_Map * out{nullptr};
try
{
shmem_ = boost::interprocess::managed_shared_memory{boost::interprocess::open_only, mem_name.c_str()};
try
{
auto mem = shmem_.find<ProfinetData_Map>("ProfinetData_Map");
out = mem.first;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
return nullptr;
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
return out;
}
return out;
}
private:

View File

@ -1,3 +1,7 @@
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
message("log enable")
add_definitions(-DLOG_ENABLE)
endif()
set(SRC_FILES ${SRC_FILES}
./profinet/profinet.cpp

View File

@ -42,8 +42,6 @@ using namespace std;
#define FLAGS_AREP_APP_READY 0x00000001
#define LOG_ENABLE
#ifdef LOG_ENABLE
#define LOG(STR) log_.put(STR)
#else
@ -234,6 +232,8 @@ bool Profinet::Config(ProfinetSettings& Settings,
/// Инициализация библиотеки pnet
m_pnet_data.pnet_ptr = pnet_init (&pnet_cfg);
p_events_ = &p_data_map->Events;
if (m_pnet_data.pnet_ptr == nullptr)
return false;
@ -611,15 +611,16 @@ void Profinet::cyclicIoData()
if (submodule_ptr->m_data_cfg.outsize > 0)
{
bool data_updated;
/// Копируем данные от контроллера в 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, data_updated);
if (submodule_ptr->isDataUpdated())
if (data_updated)
{
events_.set_flag(EVENT_NEW_CYCLIC_DATA);
p_events_->set_flag(EVENT_NEW_CYCLIC_DATA);
}
}
@ -627,7 +628,6 @@ void Profinet::cyclicIoData()
{
uint8_t indata_iocs;
uint8_t indata_iops = PNET_IOXS_GOOD;
//LOG("CYC: Put data to PLC");
/**
* @brief Отправляем данные подмодуля в ПЛК
*
@ -703,7 +703,7 @@ int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
/// Ошибок нет
}
events_.set_flag(EVENT_CONNECTION_ABORT);
p_events_->set_flag(EVENT_CONNECTION_ABORT);
m_pnet_data.arep = UINT32_MAX;
@ -748,7 +748,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);
p_events_->set_flag(EVENT_CONNECTION_ESTABLISHED);
}
else if (event == PNET_EVENT_APPLRDY)
{
@ -887,7 +887,7 @@ int Profinet::callbackWriteInd ( uint32_t arep,
}
/// Устанавливаем событие
events_.set_flag(EVENT_NEW_PARAM_DATA);
p_events_->set_flag(EVENT_NEW_PARAM_DATA);
return 0;
}

View File

@ -15,8 +15,9 @@
#include "../log/log.hpp"
#include "../flags/flags.hpp"
#include "profinet_data_map.hpp"
#include "../flags/flags_iface.hpp"
#include "profinet_data_map.hpp"
class Profinet {
public:
@ -30,6 +31,8 @@ public:
Profinet();
~Profinet();
bool Config(ProfinetSettings& Settings,
ProfinetDeviceSettings& DevSettings,
ProfinetData_Map * const p_data_map);
@ -153,12 +156,10 @@ public:
*/
void Start();
uint32_t EventWait(uint32_t mask) { return events_.wait_flags(mask); }
uint32_t EventWait(uint32_t mask) { return p_events_->wait_flags(mask); }
void EventClear(uint32_t mask) { events_.clear_flags(mask); }
void EventClear(uint32_t mask) { p_events_->clear_flags(mask); }
~Profinet();
private:
ProfinetServiceData m_pnet_data;
@ -185,8 +186,7 @@ private:
Flags flags_; /// Внутренние флаги: взаимодействиe между потоком Profinet и потоком стека Pnet
Flags events_; /// Флаги для внешних событий. Это более общие флаги, например флаг получения данных от ПЛК, а в каком подмодуле, уже не уточняется.
FlagsIface * p_events_; /// Флаги для внешних событий. Это более общие флаги, например флаг получения данных от ПЛК, а в каком подмодуле, уже не уточняется.
private:
/**
* @brief Проверяет наличие слота slot_nbr в конфигурации и возвращает указатель на него

View File

@ -2,8 +2,6 @@
#include <cstdint>
#include <string>
#include <map>
#include <vector>
#include "../flags/shared_flags.hpp"
#include "../shared_data/shared_data.hpp"
@ -22,7 +20,7 @@ enum ProfinetEvent
EVENT_CONNECTION_ESTABLISHED = 0x00000001, /// Установлено соединение с ПЛК
EVENT_NEW_CYCLIC_DATA = 0x00000002, /// Получение новых циклических данных от ПЛК
EVENT_NEW_PARAM_DATA = 0x00000004, /// Новая запись параметра от ПЛК
EVENT_CONNECTION_ABORT = 0x00000008; /// Разрыв соединения
EVENT_CONNECTION_ABORT = 0x00000008 /// Разрыв соединения
};
struct ProfinetData_Parameter {
@ -53,7 +51,7 @@ struct ProfinetData_Module {
};
struct ProfinetData_Map {
SharedFlags Events; /// События profinet
SharedFlags Events; /// События profinet
ProfinetData_Module * p_mods; /// Модули
uint32_t mods_nbr; /// Количество модулей
};

View File

@ -1,9 +1,9 @@
#include "profinet_parameter.hpp"
ProfinetParameter::ProfinetParameter(uint32_t Index, std::string Name, SharedData * p_data) :
ProfinetParameter::ProfinetParameter(uint32_t Index, std::string Name, SharedDataIface * p_data) :
index(Index),
name(Name),
length(p_data->getSize()),
length(p_data->Size()),
p_data_(p_data),
read_buf_(nullptr)
{

View File

@ -4,13 +4,13 @@
#include <cstdint>
#include <string>
#include "../shared_data/shared_data.hpp"
#include "../shared_data/shared_data_iface.hpp"
class ProfinetParameter
{
public:
static std::shared_ptr<ProfinetParameter> Create(uint32_t Index, std::string Name, SharedData * p_data)
static std::shared_ptr<ProfinetParameter> Create(uint32_t Index, std::string Name, SharedDataIface * p_data)
{
if (p_data == nullptr)
{
@ -20,7 +20,7 @@ public:
return std::shared_ptr<ProfinetParameter>(new ProfinetParameter(Index, Name, p_data));
}
ProfinetParameter(uint32_t Index, std::string Name, SharedData * p_data);
ProfinetParameter(uint32_t Index, std::string Name, SharedDataIface * p_data);
/**
* @brief Защищенная запись данных параметра
@ -58,5 +58,5 @@ public:
private:
std::shared_ptr<uint8_t[]> read_buf_; ///Буфер данных для передачи его в стек pnet для операции чтения
SharedData * const p_data_; ///Указатель на данные параметра(в разделяемой области)
SharedDataIface * const p_data_; ///Указатель на данные параметра(в разделяемой области)
};

View File

@ -4,8 +4,8 @@
ProfinetSubmodule::ProfinetSubmodule(uint32_t submodule_id,
std::string submodule_name,
pnet_data_cfg_t& submodule_data_cfg,
SharedData * inp_data_ptr,
SharedData * out_data_ptr) :
SharedDataIface * inp_data_ptr,
SharedDataIface * out_data_ptr) :
m_id(submodule_id),
m_name(submodule_name),
m_data_cfg(submodule_data_cfg),
@ -19,7 +19,7 @@ ProfinetSubmodule::ProfinetSubmodule(uint32_t submodule_id,
{
if (m_data_cfg.outsize && (out_data_ptr_!=nullptr))
{
if (m_data_cfg.outsize == out_data_ptr_->getSize())
if (m_data_cfg.outsize == out_data_ptr_->Size())
{
out_data_buf_ = std::shared_ptr<uint8_t[]>(new uint8_t[m_data_cfg.outsize]);
}
@ -27,7 +27,7 @@ ProfinetSubmodule::ProfinetSubmodule(uint32_t submodule_id,
if (m_data_cfg.insize && (inp_data_ptr_ != nullptr))
{
if (m_data_cfg.insize == inp_data_ptr_->getSize())
if (m_data_cfg.insize == inp_data_ptr_->Size())
{
inp_data_buf_ = std::shared_ptr<uint8_t[]>(new uint8_t[m_data_cfg.insize]);
}
@ -90,7 +90,7 @@ bool ProfinetSubmodule::inputSetData( pnet_t * pnet_ptr,
bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
uint32_t api,
uint16_t slot_nbr,
uint16_t subslot_nbr )
uint16_t subslot_nbr, bool& data_update )
{
bool out = true;
@ -102,15 +102,16 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
uint16_t outdata_length = m_data_cfg.outsize;
uint8_t outdata_iops;
bool updated{false};
/**
* @brief Флаг data_updated_ устанавливается внутри pnet_output_get_data_and_iops почему-то с задержкой 1 сек.
* Поэтому условием новых данных является не равность нулю outdata_length.
*/
/// Копируем данные полученные от контроллера
pnet_output_get_data_and_iops (pnet_ptr,
api,
slot_nbr,
subslot_nbr,
&updated,
&data_updated_,
out_data_buf_.get(),
&outdata_length,
&outdata_iops);
@ -120,19 +121,15 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
if ((out_data_ptr_ != nullptr) && (outdata_length == m_data_cfg.outsize))
{
out_data_ptr_->Write(0, out_data_buf_.get(), m_data_cfg.outsize);
data_update = true;
}
else
{
data_update = false;
}
m_outdata_iops = outdata_iops;
if ((!data_updated_) && (updated == true))
{
/**
* @brief Устанавливаем флаг новых данных (данные смогут быть такие-же, но флаг все равно установится)
* Флаг сбрасывается в функции getDataFromPlc после прочтения данных устройством
*/
data_updated_ = updated;
}
if (m_data_cfg.outsize != outdata_length)
{
/// Неправильная длина данных

View File

@ -7,7 +7,7 @@
#include <mutex>
#include "profinet_parameter.hpp"
#include "../shared_data/shared_data.hpp"
#include "../shared_data/shared_data_iface.hpp"
#include "../../libs/include/pnet_api.h"
@ -17,8 +17,8 @@ public:
static std::shared_ptr<ProfinetSubmodule> Create(uint32_t submodule_id,
std::string submodule_name,
pnet_data_cfg_t& submodule_data_cfg,
SharedData * inp_data_ptr,
SharedData * out_data_ptr)
SharedDataIface * inp_data_ptr,
SharedDataIface * out_data_ptr)
{
return std::shared_ptr<ProfinetSubmodule>(new ProfinetSubmodule(submodule_id,
submodule_name,
@ -30,8 +30,8 @@ public:
ProfinetSubmodule(uint32_t submodule_id,
std::string submodule_name,
pnet_data_cfg_t& submodule_data_cfg,
SharedData * inp_data_ptr,
SharedData * out_data_ptr);
SharedDataIface * inp_data_ptr,
SharedDataIface * out_data_ptr);
bool addParameter(std::shared_ptr<ProfinetParameter>& param);
@ -46,14 +46,10 @@ public:
bool outputGetData(pnet_t * pnet_ptr,
uint32_t api,
uint16_t slot_nbr,
uint16_t subslot_nbr);
uint16_t subslot_nbr, bool& data_update);
bool isDataUpdated() {
bool out{data_updated_};
data_updated_ = false;
return out;
bool isDataUpdated() {
return data_updated_;
};
public:
@ -76,8 +72,8 @@ private:
std::shared_ptr<uint8_t[]> out_data_buf_;
std::shared_ptr<uint8_t[]> inp_data_buf_;
SharedData * const inp_data_ptr_; /// Входные циклические данные (DEV->PLC)
SharedData * const out_data_ptr_; /// Выходные циклические данные (PLC->DEV)
SharedDataIface * const inp_data_ptr_; /// Входные циклические данные (DEV->PLC)
SharedDataIface * const out_data_ptr_; /// Выходные циклические данные (PLC->DEV)
bool data_updated_;
};

View File

@ -13,7 +13,7 @@ bool SharedData::Init(uint8_t * p_data, uint32_t size)
p_data_ = p_data;
size_ = size;
std::lock_guard<std::mutex> guard(mutex_);
std::lock_guard guard(mutex_);
std::memset(p_data_, 0, size);
return true;
@ -26,7 +26,7 @@ bool SharedData::Write(uint32_t offset_bytes, void * p_data, uint32_t length)
return false;
}
std::lock_guard<std::mutex> guard(mutex_);
std::lock_guard guard(mutex_);
std::memcpy(p_data_ + offset_bytes, p_data, length);
return true;
@ -39,7 +39,7 @@ bool SharedData::Read(uint32_t offset_bytes, void * p_data, uint32_t length)
return false;
}
std::lock_guard<std::mutex> guard(mutex_);
std::lock_guard guard(mutex_);
std::memcpy(p_data, p_data_ + offset_bytes, length);
return true;

View File

@ -1,23 +1,23 @@
#pragma once
#include <mutex>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include "shared_data_iface.hpp"
class SharedData {
class SharedData : public SharedDataIface {
public:
SharedData() : p_data_{nullptr}, size_{0} {};
bool Init(uint8_t * p_data, uint32_t size);
virtual bool Init(uint8_t * p_data, uint32_t size) override;
bool Write(uint32_t offset_bytes, void * p_data, uint32_t length);
virtual bool Write(uint32_t offset_bytes, void * p_data, uint32_t length) override;
bool Read(uint32_t offset_bytes, void * p_data, uint32_t length);
virtual bool Read(uint32_t offset_bytes, void * p_data, uint32_t length) override;
uint8_t * get() { return p_data_; }
uint32_t getSize() {return size_; };
virtual uint32_t Size() const override { return size_; }
private:
std::mutex mutex_;
boost::interprocess::interprocess_mutex mutex_;
uint8_t * p_data_;
uint32_t size_;
};

View File

@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
class SharedDataIface {
public:
virtual bool Init(uint8_t * p_data, uint32_t size) = 0;
virtual bool Write(uint32_t offset_bytes, void * p_data, uint32_t length) = 0;
virtual bool Read(uint32_t offset_bytes, void * p_data, uint32_t length) = 0;
virtual uint32_t Size() const = 0;
virtual ~SharedDataIface() {}
};