dev(UML-981): Создание и уничтожение потока циклических операций
This commit is contained in:
parent
14c8d5a1eb
commit
8f279814df
10
src/main.cpp
10
src/main.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "app_settings.hpp"
|
#include "app_settings.hpp"
|
||||||
#include "../libs/include/pnet_api.h"
|
#include "../libs/include/pnet_api.h"
|
||||||
#include "profinet.hpp"
|
#include "profinet.hpp"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля
|
#define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля
|
||||||
#define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля
|
#define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля
|
||||||
@ -118,11 +119,16 @@ int main(int argc, char * argv[])
|
|||||||
/// Это делает profinet controller.
|
/// Это делает profinet controller.
|
||||||
profinet.addModule(echo_module_ptr);
|
profinet.addModule(echo_module_ptr);
|
||||||
|
|
||||||
/// Циклические данные?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Циклические данные устройства передаются с определенным периодом, сообщения от контроллера при этом не требуются.
|
* Циклические данные устройства передаются с определенным периодом, сообщения от контроллера при этом не требуются.
|
||||||
*/
|
*/
|
||||||
|
/// Запуск потока Profinet
|
||||||
|
profinet.Start();
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -23,6 +23,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -145,9 +148,10 @@ static void pnetConfigure(pnet_cfg_t& cfg, ProfinetSettings& Settings, ProfinetD
|
|||||||
cfg.use_qualified_diagnosis = false;
|
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)
|
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));
|
std::memset(&pnet_cfg, 0, sizeof(pnet_cfg));
|
||||||
|
|
||||||
pnetConfigure(pnet_cfg, Settings, DevSettings);
|
pnetConfigure(pnet_cfg, Settings, DevSettings);
|
||||||
|
|
||||||
|
m_run_period_us = Settings.ticks_us;
|
||||||
|
m_cyclic_io_period_ms = Settings.cyclic_ms;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///TODO Определить что передавать в cb_cfg
|
///TODO Определить что передавать в cb_cfg
|
||||||
pnet_cfg.cb_arg = static_cast<void*>(this);
|
pnet_cfg.cb_arg = static_cast<void*>(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<ProfinetSlot>& 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<ProfinetSubslot>& 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
|
* Callbacks
|
||||||
* =========================================================================================
|
* =========================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||||
{
|
{
|
||||||
uint16_t err_cls = 0; /* Error code 1 */
|
uint16_t err_cls = 0; /* Error code 1 */
|
||||||
|
|||||||
@ -8,6 +8,9 @@
|
|||||||
#include "profinet_slot.hpp"
|
#include "profinet_slot.hpp"
|
||||||
#include "profinet_serv_data.hpp"
|
#include "profinet_serv_data.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
class Profinet {
|
class Profinet {
|
||||||
public:
|
public:
|
||||||
Profinet();
|
Profinet();
|
||||||
@ -121,8 +124,31 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::shared_ptr<ProfinetParameter> getSubmoduleParameter(uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t param_index);
|
std::shared_ptr<ProfinetParameter> getSubmoduleParameter(uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t param_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Таймер для циклического обмена данными
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void PeriodicOperations();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Запуск потока
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
~Profinet();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProfinetServiceData m_pnet_data;
|
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<bool> m_periodic_stop; /// Флаг завершения потока
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ключ - номер слота, Значение - указатель на слот
|
* @brief Ключ - номер слота, Значение - указатель на слот
|
||||||
*
|
*
|
||||||
@ -149,6 +175,8 @@ private:
|
|||||||
|
|
||||||
void initDataAndIoxs();
|
void initDataAndIoxs();
|
||||||
|
|
||||||
|
void cyclicIoData();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
#include "../../libs/include/pnet_api.h"
|
#include "../../libs/include/pnet_api.h"
|
||||||
|
|
||||||
struct ProfinetServiceData {
|
struct ProfinetServiceData {
|
||||||
pnet_t * pnet_ptr;
|
pnet_t * pnet_ptr; /// Указатель на pnet
|
||||||
uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet
|
uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet
|
||||||
uint32_t arep; /// Аналогично
|
uint32_t arep; /// Аналогично
|
||||||
uint32_t arep_for_appl_ready; /// Костыль pnet
|
uint32_t arep_for_appl_ready; /// Костыль для pnet (нужно реализовать как в примере)
|
||||||
};
|
};
|
||||||
@ -83,5 +83,6 @@ struct ProfinetDeviceSettings {
|
|||||||
/// Настройки не зависящие от описания данных Profinet
|
/// Настройки не зависящие от описания данных Profinet
|
||||||
struct ProfinetSettings {
|
struct ProfinetSettings {
|
||||||
uint32_t ticks_us = 1000; /// Устанавливает время в мкс между вызовами pnet_handle_periodic()
|
uint32_t ticks_us = 1000; /// Устанавливает время в мкс между вызовами pnet_handle_periodic()
|
||||||
|
uint32_t cyclic_ms = 100; /// Устанавливает период в мс для циклического обмена данными
|
||||||
std::string EthIface = ""; /// Имя интерфейса ethernet
|
std::string EthIface = ""; /// Имя интерфейса ethernet
|
||||||
};
|
};
|
||||||
@ -9,7 +9,9 @@ ProfinetSubmodule::ProfinetSubmodule(uint16_t submodule_id,
|
|||||||
m_name(submodule_name),
|
m_name(submodule_name),
|
||||||
m_data_cfg(submodule_data_cfg),
|
m_data_cfg(submodule_data_cfg),
|
||||||
m_inp_data_ptr(inp_data_ptr),
|
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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,12 @@ public:
|
|||||||
const std::string m_name; /// Имя подмодуля
|
const std::string m_name; /// Имя подмодуля
|
||||||
const pnet_data_cfg_t m_data_cfg; /// Конфигурация циклических данных подмодуля
|
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_inp_data_ptr; /// Входные циклические данные (DEV->PLC)
|
||||||
void * const m_out_data_ptr; /// Выходные циклические данные (PLC->DEV)
|
void * const m_out_data_ptr; /// Выходные циклические данные (PLC->DEV)
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,6 @@ ProfinetSubslot::ProfinetSubslot(uint16_t subslot_nbr, uint16_t slot_nbr, uint32
|
|||||||
m_subslot_nbr(subslot_nbr),
|
m_subslot_nbr(subslot_nbr),
|
||||||
m_slot_nbr(slot_nbr),
|
m_slot_nbr(slot_nbr),
|
||||||
m_module_id(module_id),
|
m_module_id(module_id),
|
||||||
m_indata_iocs(0),
|
|
||||||
m_outdata_iops(0),
|
|
||||||
m_submodule_ptr(nullptr)
|
m_submodule_ptr(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@ -37,12 +37,6 @@ private:
|
|||||||
/// Идентификатор модуля куда входит подключаемый подмодуль
|
/// Идентификатор модуля куда входит подключаемый подмодуль
|
||||||
uint32_t m_module_id;
|
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<ProfinetSubmodule> m_submodule_ptr;
|
std::shared_ptr<ProfinetSubmodule> m_submodule_ptr;
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user