453 lines
20 KiB
C++
453 lines
20 KiB
C++
#pragma once
|
||
|
||
#include "../../libs/include/pnet_api.h"
|
||
#include "profinet_settings.hpp"
|
||
#include <string>
|
||
#include <map>
|
||
#include <memory>
|
||
#include "profinet_slot.hpp"
|
||
#include "profinet_serv_data.hpp"
|
||
|
||
#include <atomic>
|
||
#include <thread>
|
||
#include <vector>
|
||
|
||
#include "../log/log.hpp"
|
||
#include "../flags/flags.hpp"
|
||
|
||
|
||
class Profinet {
|
||
public:
|
||
enum Events
|
||
{
|
||
EVENT_CONNECTION_ESTABLISHED = 0x00000001, /// Установлено соединение с ПЛК
|
||
EVENT_NEW_CYCLIC_DATA = 0x00000002, /// Получение новых циклических данных от ПЛК
|
||
EVENT_NEW_PARAM_DATA = 0x00000004, /// Новая запись параметра от ПЛК
|
||
};
|
||
|
||
Profinet();
|
||
|
||
bool Config(ProfinetSettings& Settings,
|
||
ProfinetDeviceSettings& DevSettings,
|
||
std::vector<std::shared_ptr<ProfinetModule>>& Modules);
|
||
|
||
/**
|
||
* @brief Добавляет ранее созданный слот slot_ptr
|
||
*
|
||
* @param slot_ptr слот
|
||
* @return true слот добавлен
|
||
* @return false слот не был добавлен
|
||
*/
|
||
bool addSlot(std::shared_ptr<ProfinetSlot>& slot_ptr);
|
||
|
||
/**
|
||
* @brief Если слот с номером slot_nbr еще не добавлен, то создает слот и добавляет его
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @return указатель на слот
|
||
*/
|
||
std::shared_ptr<ProfinetSlot> addSlot(uint16_t slot_nbr);
|
||
|
||
/**
|
||
* @brief Добавляет слот с номером slot_nbr и подключает к нему модуль module_ptr.
|
||
* Если слота с номером slot_nbr еще не добавлено, то он будет создан и добавлен.
|
||
* Если слот с номером slot_nbr был добавлен ранее, то это штатная работа данной функции.
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param module_ptr указатель на модуль
|
||
* @return true модуль успешно подключен
|
||
* @return false модуль не подключен
|
||
*/
|
||
bool addSlotAndPlugModule(uint16_t slot_nbr, std::shared_ptr<ProfinetModule>& module_ptr);
|
||
|
||
/**
|
||
* @brief Добавляет слот с номером slot_nbr и подключает к нему модуль из словаря \a m_modules чей
|
||
* идентификатор равен module_id.
|
||
* Если слота с номером slot_nbr еще не добавлено, то он будет создан и добавлен.
|
||
* Если слот с номером slot_nbr был добавлен ранее, то это штатная работа данной функции.
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param module_id идентификатор модуля
|
||
* @return true модуль успешно подключен
|
||
* @return false модуль не подключен
|
||
*/
|
||
bool addSlotAndPlugModule(uint16_t slot_nbr, uint32_t module_id);
|
||
|
||
/**
|
||
* @brief Добавляет к слоту с номером \a slot_nbr подслот с номером \a subslot_nbr и подключает к нему подмодуль \a submodule_ptr.
|
||
* Если слота с номером \a slot_nbr еще не добавлено, то выполнене функции завершиться со значением \a false.
|
||
* Если подслота с номером \a subslot_nbr еще не добавлено в слот \a slot_nbr то он будет создан и добавлен.
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param subslot_nbr номер подслота
|
||
* @param submodule_ptr указатель на подмодуль
|
||
* @return true подмодуль успешно подключен
|
||
* @return false подмодуль не подключен
|
||
*/
|
||
bool addSubslotAndPlugSubmodule(uint16_t slot_nbr, uint16_t subslot_nbr, std::shared_ptr<ProfinetSubmodule>& submodule_ptr);
|
||
|
||
/**
|
||
* @brief Добавляет к слоту с номером \a slot_nbr, к которому подключен модуль с идентификатором \a module_id, подслот
|
||
* с номером \a subslot_nbr и подключает к нему подмодуль с идентификатором \a submodule_id.
|
||
* Выполнение функции прекратиться с возвратом false, если:
|
||
* - слот \a slot_nbr не был добавлен ранее,
|
||
* - слот \a slot_nbr был добавлен ранее, но к нему подключен модуль с идентфикатором не равным \a module_id,
|
||
* - в модуль с идентификатором \a module_id не входит подмодуль с идентификатором \a submodule_id
|
||
* - описание данных подмодуля \a submodule_id не совпарадет с описанием данным в \a p_exp_data
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param subslot_nbr номер подслота
|
||
* @param module_id идентификатор модуля
|
||
* @param submodule_id идентификатор подмодуля
|
||
* @param p_exp_data описание данныз подмодуля
|
||
* @return true подмодуль подключен
|
||
* @return false подмодуль не подключен
|
||
*/
|
||
bool addSubslotAndPlugSubmodule(uint16_t slot_nbr,
|
||
uint16_t subslot_nbr,
|
||
uint32_t module_id,
|
||
uint32_t submodule_id,
|
||
const pnet_data_cfg_t * p_exp_data);
|
||
|
||
|
||
/**
|
||
* @brief Добавляет модуль в конфигурацию
|
||
*
|
||
* @param module_ptr
|
||
* @return true
|
||
* @return false
|
||
*/
|
||
bool addModule(std::shared_ptr<ProfinetModule>& module_ptr);
|
||
|
||
/**
|
||
* @brief геттер модуля
|
||
*
|
||
* @param module_id идентификатор модуля
|
||
* @return std::shared_ptr<ProfinetModule> возвращает указатель на модуль или nullptr если такого модуля нет в \a m_modules
|
||
*/
|
||
std::shared_ptr<ProfinetModule> getModule(uint32_t module_id);
|
||
|
||
/**
|
||
* @brief геттер указателя на структуру данных параметра подмодуля с идексом \a param_index подключенного к подслоту
|
||
* \a subslot_nbr входящего в состав \a slot_nbr.
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param subslot_nbr номер подслота
|
||
* @param param_index индекс параметра
|
||
* @return std::shared_ptr<ProfinetParameter> указатель на параметр или nullptr
|
||
*/
|
||
std::shared_ptr<ProfinetParameter> getSubmoduleParameter(uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t param_index);
|
||
|
||
/**
|
||
* @brief Таймер для циклического обмена данными
|
||
*
|
||
*/
|
||
void PeriodicOperations();
|
||
|
||
/**
|
||
* @brief Запуск потока
|
||
*
|
||
*/
|
||
void Start();
|
||
|
||
uint32_t EventWait(uint32_t mask) { return events_.wait_flags(mask); }
|
||
|
||
void EventClear(uint32_t mask) { events_.clear_flags(mask); }
|
||
|
||
|
||
~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 Ключ - номер слота, Значение - указатель на слот
|
||
*
|
||
*/
|
||
std::map<uint16_t, std::shared_ptr<ProfinetSlot>> m_slots;
|
||
/**
|
||
* @brief Ключ - идентиикатор модуля, Значение - указатель на модуль
|
||
*
|
||
*/
|
||
std::map<uint32_t, std::shared_ptr<ProfinetModule>> m_modules;
|
||
|
||
Log log_;
|
||
|
||
Flags flags_; /// Внутренние флаги: взаимодействиe между потоком Profinet и потоком стека Pnet
|
||
|
||
Flags events_; /// Флаги для внешних событий. Это более общие флаги, например флаг получения данных от ПЛК, а в каком подмодуле, уже не уточняется.
|
||
|
||
private:
|
||
/**
|
||
* @brief Проверяет наличие слота slot_nbr в конфигурации и возвращает указатель на него
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @return std::shared_ptr<ProfinetSlot> указатель на слот, при успехе или nullptr если слот в конфигурации отсутсвует
|
||
*/
|
||
std::shared_ptr<ProfinetSlot> getSlotPtr(uint16_t slot_nbr);
|
||
/**
|
||
* @brief Проверяет наличие подслота в слоте и возвращает указатель на него
|
||
*
|
||
* @param slot_nbr номер слота
|
||
* @param subslot_nbr номер подслота
|
||
* @return std::shared_ptr<ProfinetSubslot> указатель на подслот, при успехе или nullptr если подслот в конфигурации отсутсвует
|
||
*/
|
||
std::shared_ptr<ProfinetSubslot> 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();
|
||
|
||
void cyclicIoData();
|
||
|
||
public:
|
||
/**
|
||
*
|
||
* Indication to the application that a module is requested by the controller in
|
||
* a specific slot.
|
||
*
|
||
* This application call-back function is called by the Profinet stack to
|
||
* indicate that the controller has requested the presence of a specific module,
|
||
* ident number \a module_ident, in the slot number \a slot.
|
||
*
|
||
* The application must react to this by configuring itself accordingly (if
|
||
* possible) and call function pnet_plug_module() to configure the stack for
|
||
* this module.
|
||
*
|
||
* If the wrong module ident number is plugged then the stack will accept this,
|
||
* but signal to the controller that a substitute module is fitted.
|
||
*
|
||
* This function should return 0 (zero) if a valid module was plugged. Or return
|
||
* -1 if the application cannot handle this request.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param event In: The state transition event. See pnet_event_values_t
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackStateInd ( uint32_t arep, pnet_event_values_t event);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* Connect request from the Profinet controller.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param p_result Out: Detailed error information if return != 0.
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackConnectInd ( uint32_t arep, pnet_result_t * p_result);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* Release request from the Profinet controller.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param p_result Out: Detailed error information if return != 0.
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackReleaseInd ( uint32_t arep, pnet_result_t * p_result);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* DControl request from the Profinet controller.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param control_command In: The DControl command code.
|
||
* @param p_result Out: Detailed error information if return != 0.
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackDcontrolInd ( uint32_t arep,
|
||
pnet_control_command_t control_command,
|
||
pnet_result_t * p_result);
|
||
|
||
/**
|
||
* @brief * This application call-back function is called by the Profinet stack on every
|
||
* CControl confirmation from the Profinet controller.
|
||
* @param arep In: The AREP.
|
||
* @param p_result Out: Detailed error information.
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackCcontrolInd ( uint32_t arep, pnet_result_t * p_result);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* IODRead request from the Profinet controller which specify an
|
||
* application-specific value of \a idx (0x0000 - 0x7fff). All other values of
|
||
* \a idx are handled internally by the Profinet stack.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param slot In: The slot number.
|
||
* @param subslot In: The sub-slot number.
|
||
* @param idx In: The data record index.
|
||
* @param sequence_number In: The sequence number.
|
||
* @param pp_read_data Out: A pointer to the binary value.
|
||
* @param p_read_length InOut: The maximum (in) and actual (out) length in
|
||
* bytes of the binary value.
|
||
* @param p_result Out: Detailed error information if returning != 0
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackReadInd (
|
||
uint32_t arep,
|
||
uint16_t slot_nbr,
|
||
uint16_t subslot_nbr,
|
||
uint16_t idx,
|
||
uint16_t sequence_number,
|
||
uint8_t ** pp_read_data,
|
||
uint16_t * p_read_length,
|
||
pnet_result_t * p_result);
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* IODWrite request from the Profinet controller which specify an
|
||
* application-specific value of \a idx (0x0000 - 0x7fff). All other values of
|
||
* \a idx are handled internally by the Profinet stack.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param slot In: The slot number.
|
||
* @param subslot In: The sub-slot number.
|
||
* @param idx In: The data record index.
|
||
* @param sequence_number In: The sequence number.
|
||
* @param write_length In: The length in bytes of the binary value.
|
||
* @param p_write_data In: A pointer to the binary value.
|
||
* @param p_result Out: Detailed error information if returning != 0
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackWriteInd (
|
||
uint32_t arep,
|
||
uint16_t slot_nbr,
|
||
uint16_t subslot_nbr,
|
||
uint16_t idx,
|
||
uint16_t sequence_number,
|
||
uint16_t write_length,
|
||
const uint8_t * p_write_data,
|
||
pnet_result_t * p_result);
|
||
|
||
/**
|
||
* @brief * This application call-back function is called by the Profinet stack to
|
||
* indicate that the controller has requested the presence of a specific module,
|
||
* ident number \a module_ident, in the slot number \a slot.
|
||
*
|
||
* @param slot
|
||
* @param module_ident
|
||
* @return int
|
||
*/
|
||
int callbackExpModuleInd ( uint16_t slot, uint32_t module_ident);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack to
|
||
* indicate that the controller has requested the presence of a specific
|
||
* sub-module with ident number \a submodule_ident, in the sub-slot number
|
||
* \a subslot, with module ident number \a module_ident in slot \a slot.
|
||
*
|
||
* @param slot In: The slot number.
|
||
* @param subslot In: The sub-slot number.
|
||
* @param module_ident In: The module ident number.
|
||
* @param submodule_ident In: The sub-module ident number.
|
||
* @param p_exp_data In: The expected data configuration (sizes and
|
||
* direction)
|
||
* @return 0 on success.
|
||
* -1 if an error occurred.
|
||
*/
|
||
int callbackExpSubmoduleInd (
|
||
uint16_t slot,
|
||
uint16_t subslot,
|
||
uint32_t module_id,
|
||
uint32_t submodule_id,
|
||
const pnet_data_cfg_t * p_exp_data);
|
||
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack to
|
||
* indicate that the received data status has changed.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param crep In: The CREP.
|
||
* @param changes In: The changed bits in the received data status.
|
||
* See pnet_data_status_bits_t
|
||
* @param data_status In: Current received data status (after changes).
|
||
* See pnet_data_status_bits_t
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackNewDataStatusInd (
|
||
uint32_t arep,
|
||
uint32_t crep,
|
||
uint8_t changes,
|
||
uint8_t data_status);
|
||
|
||
/**
|
||
* @brief This functionality is used for alarms triggered by the IO-controller.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param p_alarm_argument In: The alarm argument (with slot, subslot,
|
||
* alarm_type etc)
|
||
* @param data_len In: Data length
|
||
* @param data_usi In: Alarm USI
|
||
* @param p_data In: Alarm data
|
||
* @return 0 on success.
|
||
* Other values are ignored.
|
||
*/
|
||
int callbackAlarmInd (
|
||
uint32_t arep,
|
||
const pnet_alarm_argument_t * p_alarm_arg,
|
||
uint16_t data_len,
|
||
uint16_t data_usi,
|
||
const uint8_t * p_data);
|
||
|
||
/**
|
||
* @brief This functionality is used for alarms triggered by the IO-device.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param p_pnio_status In: Detailed ACK information.
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackAlarmCnf ( uint32_t arep, const pnet_pnio_status_t * p_pnio_status);
|
||
|
||
/**
|
||
* @brief This functionality is used for alarms triggered by the IO-controller.
|
||
*
|
||
* @param arep In: The AREP.
|
||
* @param res In: 0 if ACK was received by the remote side.
|
||
* This is cnf(+).
|
||
* -1 if ACK was not received by the remote
|
||
* side. This is cnf(-).
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackAlarmAckCnf ( uint32_t arep, int res);
|
||
/**
|
||
* @brief This application call-back function is called by the Profinet stack on every
|
||
* reset request (via the DCP "Set" command) from the Profinet controller.
|
||
*
|
||
* @param should_reset_application In: True if the user should reset the
|
||
* application data.
|
||
* @param reset_mode In: Detailed reset information.
|
||
* @return 0 on success. Other values are ignored.
|
||
*/
|
||
int callbackResetInd ( bool should_reset_application, uint16_t reset_mode);
|
||
|
||
/**
|
||
* @brief Use this callback to implement control of the LED.
|
||
*
|
||
* @param led_state In: True if the signal LED should be on.
|
||
* @return 0 on success.
|
||
* -1 if an error occurred. Will trigger a log message.
|
||
*/
|
||
int callbackSignalLedInd (bool led_state);
|
||
}; |