ProfinetConnector/src/profinet/profinet.hpp

453 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
};