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 "../libs/include/pnet_api.h"
|
||||
#include "profinet.hpp"
|
||||
#include <thread>
|
||||
|
||||
#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;
|
||||
}
|
@ -23,6 +23,9 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
|
||||
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<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
|
||||
* =========================================================================================
|
||||
*/
|
||||
|
||||
int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||
{
|
||||
uint16_t err_cls = 0; /* Error code 1 */
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include "profinet_slot.hpp"
|
||||
#include "profinet_serv_data.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
class Profinet {
|
||||
public:
|
||||
Profinet();
|
||||
@ -121,8 +124,31 @@ public:
|
||||
*/
|
||||
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:
|
||||
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 Ключ - номер слота, Значение - указатель на слот
|
||||
*
|
||||
@ -149,6 +175,8 @@ private:
|
||||
|
||||
void initDataAndIoxs();
|
||||
|
||||
void cyclicIoData();
|
||||
|
||||
public:
|
||||
/**
|
||||
*
|
||||
|
@ -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 (нужно реализовать как в примере)
|
||||
};
|
@ -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
|
||||
};
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
|
@ -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<ProfinetSubmodule> m_submodule_ptr;
|
||||
};
|
Loading…
Reference in New Issue
Block a user