diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d4fb60f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,37 @@ +#******************************************************************** +# _ _ _ +# _ __ | |_ _ | | __ _ | |__ ___ +# | '__|| __|(_)| | / _` || '_ \ / __| +# | | | |_ _ | || (_| || |_) |\__ \ +# |_| \__|(_)|_| \__,_||_.__/ |___/ +# +# http://www.rt-labs.com +# Copyright 2017 rt-labs AB, Sweden. +# See LICENSE file in the project root for full license information. +#*******************************************************************/ +cmake_minimum_required (VERSION 3.14) + +project (PN_DEV_TEST VERSION 0.0.1) + +set(LIBS_INSTALL_PATH ../libs) +set(PNET_PATH ../profinet_stack/p-net) + +include(./utils/utils.cmake) +include(./profinet/profinet.cmake) + +add_executable(pn_dev_test +./main.cpp ${SRC_FILES}) + +target_include_directories(pn_dev_test PRIVATE + ./ + ${INC_DIRS} + ${LIBS_INSTALL_PATH}/include + ${LIBS_INSTALL_PATH}/include/sys + ${PNET_PATH}/build/src + ${PNET_PATH}/src + ${PNET_PATH}/src/ports/linux +) + +target_link_directories(pn_dev_test PUBLIC ${LIBS_INSTALL_PATH}/lib) + +target_link_libraries (pn_dev_test PUBLIC profinet osal) \ No newline at end of file diff --git a/src/app_settings.hpp b/src/app_settings.hpp new file mode 100644 index 0000000..540b005 --- /dev/null +++ b/src/app_settings.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct AppSettings +{ + std::string EthDevName; /// Имя адаптера +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..f688dfa --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,61 @@ +#include "app_settings.hpp" +#include "../libs/include/pnet_api.h" +#include "profinet.hpp" + +int main(int argc, char * argv[]) +{ + AppSettings app_settings = { + .EthDevName = "enp6s1", + }; + + ProfinetSettings settings = { + .EthIface = "enp6s1", + .ticks_us = 1000 + }; + + ProfinetDeviceSettings profinet_settings = { + .im_0 = { + .vendor_id = 0x0493, + .hw_revision = 3, + .sw_revision = { + .prefix = 'V', + .functional_enhancement = 0, + .internal_change = 0, + .bug_fix = 2 + }, + .revision_counter = 0, + .profile_id = 0x1234, + .profile_specific_type = 0x5678, + .supported = (PNET_SUPPORTED_IM1 | PNET_SUPPORTED_IM2 | PNET_SUPPORTED_IM3), + .order_id = "12345 Abcdefghijk", + .serial_number = "007", + }, + .im_1 = { + .tag_function = "my function", + .tag_location = "my location" + }, + .im_2 = { + .date = "2022-03-01 10:03" + }, + .im_3 = { + .descriptor = "my descriptor" + }, + .im_4 = { + .signature = "" + }, + .device_id = 0x0002, + .oem_vendor_id = 0xcafe, + .oem_device_id = 0xee02, + .product_name = "P-Net Sample Application", + .station_name = "rt-labs-dev", + .send_hello = true, + .min_device_interval = 32 //1ms ?? + }; + + Profinet profinet; + /// Настройка Profinet: Инициализация pnet, добавление DAP слотов и подслотов и подключение к ним модулей и подмодулей + if (!profinet.Config(settings, profinet_settings)) + return 0; + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet.cmake b/src/profinet/profinet.cmake new file mode 100644 index 0000000..bd95bc4 --- /dev/null +++ b/src/profinet/profinet.cmake @@ -0,0 +1,23 @@ + +set(SRC_FILES ${SRC_FILES} + ./profinet/profinet.cpp + ./profinet/profinet_cb_alarm_ack_cnf.cpp + ./profinet/profinet_cb_alarm_cnf.cpp + ./profinet/profinet_cb_alarm_ind.cpp + ./profinet/profinet_cb_ccontrol_ind.cpp + ./profinet/profinet_cb_connect_ind.cpp + ./profinet/profinet_cb_dcontrol_ind.cpp + ./profinet/profinet_cb_exp_module_ind.cpp + ./profinet/profinet_cb_exp_submodule_ind.cpp + ./profinet/profinet_cb_new_data_status_ind.cpp + ./profinet/profinet_cb_read_ind.cpp + ./profinet/profinet_cb_release_ind.cpp + ./profinet/profinet_cb_reset_ind.cpp + ./profinet/profinet_cb_signal_led_ind.cpp + ./profinet/profinet_cb_state_ind.cpp + ./profinet/profinet_cb_write_ind.cpp + ./profinet/profinet.cpp + ./profinet/profinet_slot.cpp + ./profinet/profinet_subslot.cpp) + +set(INC_DIRS ${INC_DIRS} ./profinet) \ No newline at end of file diff --git a/src/profinet/profinet.cpp b/src/profinet/profinet.cpp new file mode 100644 index 0000000..1448d67 --- /dev/null +++ b/src/profinet/profinet.cpp @@ -0,0 +1,259 @@ +#include "profinet.hpp" + +#include "profinet_cb_state_ind.hpp" +#include "profinet_cb_connect_ind.hpp" +#include "profinet_cb_release_ind.hpp" +#include "profinet_cb_dcontrol_ind.hpp" +#include "profinet_cb_ccontrol_ind.hpp" +#include "profinet_cb_read_ind.hpp" +#include "profinet_cb_write_ind.hpp" +#include "profinet_cb_exp_module_ind.hpp" +#include "profinet_cb_exp_submodule_ind.hpp" +#include "profinet_cb_new_data_status_ind.hpp" +#include "profinet_cb_alarm_ind.hpp" +#include "profinet_cb_alarm_cnf.hpp" +#include "profinet_cb_alarm_ack_cnf.hpp" +#include "profinet_cb_reset_ind.hpp" +#include "profinet_cb_signal_led_ind.hpp" + +#include "utils.h" +#include + +#include + #include + +using namespace std; + + +#define GET_HIGH_BYTE(id) ((id >> 8) & 0xFF) +#define GET_LOW_BYTE(id) (id & 0xFF) + +#define APP_MAIN_SLEEPTIME_US 5000 * 1000 +#define APP_SNMP_THREAD_PRIORITY 1 +#define APP_SNMP_THREAD_STACKSIZE 256 * 1024 /* bytes */ +#define APP_ETH_THREAD_PRIORITY 10 +#define APP_ETH_THREAD_STACKSIZE 4096 /* bytes */ +#define APP_BG_WORKER_THREAD_PRIORITY 5 +#define APP_BG_WORKER_THREAD_STACKSIZE 4096 /* bytes */ + +static void pnetConfigure(pnet_cfg_t& cfg, ProfinetSettings& Settings, ProfinetDeviceSettings& DevSettings) +{ + cfg.tick_us = Settings.ticks_us; + cfg.im_0_data.im_vendor_id_hi = GET_HIGH_BYTE(DevSettings.im_0.vendor_id); + cfg.im_0_data.im_vendor_id_lo = GET_LOW_BYTE (DevSettings.im_0.vendor_id); + cfg.im_0_data.im_hardware_revision = DevSettings.im_0.hw_revision; + cfg.im_0_data.im_sw_revision_prefix = DevSettings.im_0.sw_revision.prefix; + cfg.im_0_data.im_sw_revision_functional_enhancement = DevSettings.im_0.sw_revision.functional_enhancement; + cfg.im_0_data.im_sw_revision_bug_fix = DevSettings.im_0.sw_revision.bug_fix; + cfg.im_0_data.im_sw_revision_internal_change = DevSettings.im_0.sw_revision.internal_change; + cfg.im_0_data.im_revision_counter = DevSettings.im_0.revision_counter; + cfg.im_0_data.im_profile_id = DevSettings.im_0.profile_id; + cfg.im_0_data.im_profile_specific_type = DevSettings.im_0.profile_specific_type; + cfg.im_0_data.im_version_major = 1; + cfg.im_0_data.im_version_minor = 1; + cfg.im_0_data.im_supported = DevSettings.im_0.supported; + + std::snprintf ( + cfg.im_0_data.im_order_id, + sizeof (cfg.im_0_data.im_order_id), + "%s", + DevSettings.im_0.order_id.c_str()); + std::snprintf ( + cfg.im_0_data.im_serial_number, + sizeof (cfg.im_0_data.im_serial_number), + "%s", + DevSettings.im_0.serial_number.c_str()); + std::snprintf ( + cfg.im_1_data.im_tag_function, + sizeof (cfg.im_1_data.im_tag_function), + "%s", + DevSettings.im_1.tag_function.c_str()); + std::snprintf ( + cfg.im_1_data.im_tag_location, + sizeof (cfg.im_1_data.im_tag_location), + "%s", + DevSettings.im_1.tag_location.c_str()); + std::snprintf ( + cfg.im_2_data.im_date, + sizeof (cfg.im_2_data.im_date), + "%s", + DevSettings.im_2.date.c_str()); + std::snprintf ( + cfg.im_3_data.im_descriptor, + sizeof (cfg.im_3_data.im_descriptor), + "%s", + DevSettings.im_3.descriptor.c_str()); + std::snprintf ( + cfg.im_4_data.im_signature, + sizeof (cfg.im_4_data.im_signature), + "%s", + DevSettings.im_4.signature.c_str()); + + cfg.state_cb = profinet_cb_state_ind; + cfg.connect_cb = profinet_cb_connect_ind; + cfg.release_cb = profinet_cb_release_ind; + cfg.dcontrol_cb = profinet_cb_dcontrol_ind; + cfg.ccontrol_cb = profinet_cb_ccontrol_ind; + cfg.read_cb = profinet_cb_read_ind; + cfg.write_cb = profinet_cb_write_ind; + cfg.exp_module_cb = profinet_cb_exp_module_ind; + cfg.exp_submodule_cb = profinet_cb_exp_submodule_ind; + cfg.new_data_status_cb = profinet_cb_new_data_status_ind; + cfg.alarm_ind_cb = profinet_cb_alarm_ind; + cfg.alarm_cnf_cb = profinet_cb_alarm_cnf; + cfg.alarm_ack_cnf_cb = profinet_cb_alarm_ack_cnf; + cfg.reset_cb = profinet_cb_reset_ind; + cfg.signal_led_cb = profinet_cb_signal_led_ind; + + cfg.device_id.vendor_id_hi = GET_HIGH_BYTE (DevSettings.im_0.vendor_id); + cfg.device_id.vendor_id_lo = GET_LOW_BYTE (DevSettings.im_0.vendor_id); + cfg.device_id.device_id_hi = GET_HIGH_BYTE (DevSettings.device_id); + cfg.device_id.device_id_lo = GET_LOW_BYTE (DevSettings.device_id); + cfg.oem_device_id.vendor_id_hi = GET_HIGH_BYTE (DevSettings.oem_vendor_id); + cfg.oem_device_id.vendor_id_lo = GET_LOW_BYTE (DevSettings.oem_vendor_id); + cfg.oem_device_id.device_id_hi = GET_HIGH_BYTE (DevSettings.oem_device_id); + cfg.oem_device_id.device_id_lo = GET_LOW_BYTE (DevSettings.oem_device_id); + + + snprintf ( + cfg.product_name, + sizeof (cfg.product_name), + "%s", + DevSettings.product_name.c_str()); + + cfg.send_hello = true; + + /* Timing */ + cfg.min_device_interval = DevSettings.min_device_interval; + + /* Should be set by application as part of network configuration. */ + cfg.num_physical_ports = 1; + + snprintf ( + cfg.station_name, + sizeof (cfg.station_name), + "%s", + DevSettings.station_name.c_str()); + + /* Diagnosis mechanism */ + /* We prefer using "Extended channel diagnosis" instead of + * "Qualified channel diagnosis" format on the wire, + * as this is better supported by Wireshark. + */ + cfg.use_qualified_diagnosis = false; +} + +Profinet::Profinet(void) : m_pnet_data({nullptr, 0}) +{ + +} + +bool Profinet::Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSettings) +{ + pnet_cfg_t pnet_cfg = {0}; + utils_netif_namelist_t netif_name_list; + uint16_t number_of_ports = 1; + pnet_if_cfg_t netif_cfg = {0}; + + std::memset(&pnet_cfg, 0, sizeof(pnet_cfg)); + + pnetConfigure(pnet_cfg, Settings, DevSettings); + ///TODO Определить что передавать в cb_cfg + pnet_cfg.cb_arg = static_cast(this); + + utils_pnet_cfg_init_netifs(Settings.EthIface.c_str(), + &netif_name_list, + &number_of_ports, + &netif_cfg, + 0x10 /* Copper 100 Mbit/s Full duplex */ + ); + + pnet_cfg.if_cfg = netif_cfg; + pnet_cfg.num_physical_ports = number_of_ports; + + pnet_cfg.pnal_cfg.snmp_thread.prio = APP_SNMP_THREAD_PRIORITY; + pnet_cfg.pnal_cfg.snmp_thread.stack_size = APP_SNMP_THREAD_STACKSIZE; + pnet_cfg.pnal_cfg.eth_recv_thread.prio = APP_ETH_THREAD_PRIORITY; + pnet_cfg.pnal_cfg.eth_recv_thread.stack_size = APP_ETH_THREAD_STACKSIZE; + pnet_cfg.pnal_cfg.bg_worker_thread.prio = APP_BG_WORKER_THREAD_PRIORITY; + pnet_cfg.pnal_cfg.bg_worker_thread.stack_size = APP_BG_WORKER_THREAD_STACKSIZE; + + /// Инициализация библиотеки pnet + m_pnet_data.pnet_ptr = pnet_init (&pnet_cfg); + + if (m_pnet_data.pnet_ptr == nullptr) + return false; + /** + * @brief Создаем стандартный слот для модуля DAP 1 (Device Access Point) + * Это обязательный модуль для profinet device + */ + auto dap_slot = make_shared(PNET_SLOT_DAP_IDENT, PNET_MOD_DAP_IDENT, "DAP 1"); + /** + * @brief Добавляем слот и подключаем модуль + * + */ + if (!addSlotAndPlugModule(dap_slot)) + return false; + + pnet_data_cfg_t dap_data_cfg = { PNET_DIR_NO_IO, 0, 0 }; + + /** + * @brief Создаем стандартный подслот для подмодуля identity 1 который входит в модуль DAP 1 + * Это обязательный подслот для profinet device + */ + auto dap_subslot_identity_1 = make_shared( PNET_SUBSLOT_DAP_IDENT, + PNET_SUBMOD_DAP_IDENT, + "DAP Identity 1", + dap_data_cfg ); + /** + * @brief Создаем стандартный подслот для подмодуля iface 1 ident который входит в модуль DAP 1 + * Это обязательный подслот для profinet device + */ + auto dap_subslot_iface_1_ident = make_shared( PNET_SUBSLOT_DAP_INTERFACE_1_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_IDENT, + "DAP IFACE1 IDENT", + dap_data_cfg ); + /** + * @brief Создаем стандартный подслот для подмодуля iface 1.port 1 ident который входит в модуль DAP 1 + * Это обязательный подслот для profinet device + */ + auto dap_subslot_iface_1_port1_ident = make_shared( PNET_SUBSLOT_DAP_INTERFACE_1_PORT_1_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, + "DAP Port 1", + dap_data_cfg ); + /** + * @brief Добавляем подслоты в слот и поключаем подмодули в подслоты + * + */ + if (!dap_slot->addSubslotAndPlugSubmodule(m_pnet_data, dap_subslot_identity_1)) + return false; + + if (!dap_slot->addSubslotAndPlugSubmodule(m_pnet_data, dap_subslot_iface_1_ident)) + return false; + + if (!dap_slot->addSubslotAndPlugSubmodule(m_pnet_data, dap_subslot_iface_1_port1_ident)) + return false; + + return true; +} + +bool Profinet::addSlot(std::shared_ptr& slot_ptr) +{ + if (slot_ptr == nullptr) + return false; + + m_slots[slot_ptr->m_slot_nbr] = slot_ptr; + + return true; +} + +bool Profinet::addSlotAndPlugModule(std::shared_ptr& slot_ptr) +{ + if (!addSlot(slot_ptr)) + return false; + + if (!slot_ptr->plugModule(m_pnet_data)) + return false; + + return true; +} \ No newline at end of file diff --git a/src/profinet/profinet.hpp b/src/profinet/profinet.hpp new file mode 100644 index 0000000..e5a8a67 --- /dev/null +++ b/src/profinet/profinet.hpp @@ -0,0 +1,275 @@ +#pragma once + +#include "../libs/include/pnet_api.h" +#include "profinet_settings.hpp" +#include +#include +#include +#include "profinet_slot.hpp" +#include "profinet_serv_data.hpp" + +class Profinet { +public: + Profinet(); + + bool Config(ProfinetSettings& Settings, ProfinetDeviceSettings& DevSettings); + + bool addSlot(std::shared_ptr& slot_ptr); + + bool addSlotAndPlugModule(std::shared_ptr& slot_ptr); + +private: + ProfinetServiceData m_pnet_data; + /** + * @brief Ключ - идентификатор модуля, Значение - структура слота + * + */ + std::map> m_slots; + +private: + + +public: + /// AREP Application Relationship End Point + /** + * @brief This application call-back function is called by the Profinet stack on + * specific state transitions within the Profinet stack. + * + * @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 net InOut: The p-net stack instance + * @param arg InOut: User-defined data (not used by p-net) + * @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 arg InOut: User-defined data (not used by p-net) + * @param arep In: The AREP. + * @param p_result Out: Detailed error information. + * @return 0 on success. Other values are ignored. + */ + int callbackCcontrolCnf ( + 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 ( + pnet_t * net, + void * arg, + uint32_t api, + 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 ( + pnet_t * net, + void * arg, + 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); +}; \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_ack_cnf.cpp b/src/profinet/profinet_cb_alarm_ack_cnf.cpp new file mode 100644 index 0000000..77ecde1 --- /dev/null +++ b/src/profinet/profinet_cb_alarm_ack_cnf.cpp @@ -0,0 +1,15 @@ +#include "./profinet/profinet_cb_alarm_ack_cnf.hpp" +#include "./profinet/profinet.hpp" + +int profinet_cb_alarm_ack_cnf ( + pnet_t * net, + void * arg, + uint32_t arep, + int res) +{ + Profinet * profinet_ptr = static_cast(arg); + + profinet_ptr->callbackAlarmAckCnf(arep, res); + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_ack_cnf.hpp b/src/profinet/profinet_cb_alarm_ack_cnf.hpp new file mode 100644 index 0000000..afd7c1d --- /dev/null +++ b/src/profinet/profinet_cb_alarm_ack_cnf.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_alarm_ack_cnf ( + pnet_t * net, + void * arg, + uint32_t arep, + int res); \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_cnf.cpp b/src/profinet/profinet_cb_alarm_cnf.cpp new file mode 100644 index 0000000..b3c595e --- /dev/null +++ b/src/profinet/profinet_cb_alarm_cnf.cpp @@ -0,0 +1,10 @@ +#include "./profinet/profinet_cb_alarm_cnf.hpp" + +int profinet_cb_alarm_cnf ( + pnet_t * net, + void * arg, + uint32_t arep, + const pnet_pnio_status_t * p_pnio_status) +{ + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_cnf.hpp b/src/profinet/profinet_cb_alarm_cnf.hpp new file mode 100644 index 0000000..c4167b9 --- /dev/null +++ b/src/profinet/profinet_cb_alarm_cnf.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_alarm_cnf ( + pnet_t * net, + void * arg, + uint32_t arep, + const pnet_pnio_status_t * p_pnio_status); \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_ind.cpp b/src/profinet/profinet_cb_alarm_ind.cpp new file mode 100644 index 0000000..26e90ff --- /dev/null +++ b/src/profinet/profinet_cb_alarm_ind.cpp @@ -0,0 +1,14 @@ +#include "./profinet/profinet_cb_alarm_ind.hpp" + +int profinet_cb_alarm_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + const pnet_alarm_argument_t * p_alarm_arg, + uint16_t data_len, + uint16_t data_usi, + const uint8_t * p_data) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_alarm_ind.hpp b/src/profinet/profinet_cb_alarm_ind.hpp new file mode 100644 index 0000000..d86552e --- /dev/null +++ b/src/profinet/profinet_cb_alarm_ind.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_alarm_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + const pnet_alarm_argument_t * p_alarm_arg, + uint16_t data_len, + uint16_t data_usi, + const uint8_t * p_data); \ No newline at end of file diff --git a/src/profinet/profinet_cb_ccontrol_ind.cpp b/src/profinet/profinet_cb_ccontrol_ind.cpp new file mode 100644 index 0000000..2c8e72c --- /dev/null +++ b/src/profinet/profinet_cb_ccontrol_ind.cpp @@ -0,0 +1,11 @@ +#include "./profinet/profinet_cb_ccontrol_ind.hpp" + +int profinet_cb_ccontrol_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_ccontrol_ind.hpp b/src/profinet/profinet_cb_ccontrol_ind.hpp new file mode 100644 index 0000000..f0a925c --- /dev/null +++ b/src/profinet/profinet_cb_ccontrol_ind.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_ccontrol_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result); \ No newline at end of file diff --git a/src/profinet/profinet_cb_connect_ind.cpp b/src/profinet/profinet_cb_connect_ind.cpp new file mode 100644 index 0000000..348e59a --- /dev/null +++ b/src/profinet/profinet_cb_connect_ind.cpp @@ -0,0 +1,19 @@ +#include "./profinet/profinet_cb_connect_ind.hpp" + +#include + +using namespace std; + +int profinet_cb_connect_ind( pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result) +{ + cout << "profinet_cb_connect_ind: PLC connect indication. AREP:" << arep << endl; + /* + * Handle the request on an application level. + * This is a very simple application which does not need to handle anything. + * All the needed information is in the AR data structure. + */ + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_connect_ind.hpp b/src/profinet/profinet_cb_connect_ind.hpp new file mode 100644 index 0000000..646f645 --- /dev/null +++ b/src/profinet/profinet_cb_connect_ind.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_connect_ind( pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result); \ No newline at end of file diff --git a/src/profinet/profinet_cb_dcontrol_ind.cpp b/src/profinet/profinet_cb_dcontrol_ind.cpp new file mode 100644 index 0000000..a0554de --- /dev/null +++ b/src/profinet/profinet_cb_dcontrol_ind.cpp @@ -0,0 +1,12 @@ +#include "./profinet/profinet.hpp" + +int profinet_cb_dcontrol_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + pnet_control_command_t control_command, + pnet_result_t * p_result) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_dcontrol_ind.hpp b/src/profinet/profinet_cb_dcontrol_ind.hpp new file mode 100644 index 0000000..4e5cfa6 --- /dev/null +++ b/src/profinet/profinet_cb_dcontrol_ind.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_dcontrol_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + pnet_control_command_t control_command, + pnet_result_t * p_result); \ No newline at end of file diff --git a/src/profinet/profinet_cb_exp_module_ind.cpp b/src/profinet/profinet_cb_exp_module_ind.cpp new file mode 100644 index 0000000..ba63779 --- /dev/null +++ b/src/profinet/profinet_cb_exp_module_ind.cpp @@ -0,0 +1,11 @@ +#include "./profinet/profinet_cb_exp_module_ind.hpp" + +int profinet_cb_exp_module_ind ( + pnet_t * net, + void * arg, + uint32_t api, + uint16_t slot, + uint32_t module_ident) +{ + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_exp_module_ind.hpp b/src/profinet/profinet_cb_exp_module_ind.hpp new file mode 100644 index 0000000..a957586 --- /dev/null +++ b/src/profinet/profinet_cb_exp_module_ind.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_exp_module_ind ( + pnet_t * net, + void * arg, + uint32_t api, + uint16_t slot, + uint32_t module_ident); \ No newline at end of file diff --git a/src/profinet/profinet_cb_exp_submodule_ind.cpp b/src/profinet/profinet_cb_exp_submodule_ind.cpp new file mode 100644 index 0000000..6416c55 --- /dev/null +++ b/src/profinet/profinet_cb_exp_submodule_ind.cpp @@ -0,0 +1,15 @@ +#include "./profinet/profinet_cb_exp_submodule_ind.hpp" + +int profinet_cb_exp_submodule_ind ( + pnet_t * net, + void * arg, + uint32_t api, + uint16_t slot, + uint16_t subslot, + uint32_t module_id, + uint32_t submodule_id, + const pnet_data_cfg_t * p_exp_data) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_exp_submodule_ind.hpp b/src/profinet/profinet_cb_exp_submodule_ind.hpp new file mode 100644 index 0000000..3904a3a --- /dev/null +++ b/src/profinet/profinet_cb_exp_submodule_ind.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_exp_submodule_ind ( + pnet_t * net, + void * arg, + uint32_t api, + uint16_t slot, + uint16_t subslot, + uint32_t module_id, + uint32_t submodule_id, + const pnet_data_cfg_t * p_exp_data); \ No newline at end of file diff --git a/src/profinet/profinet_cb_new_data_status_ind.cpp b/src/profinet/profinet_cb_new_data_status_ind.cpp new file mode 100644 index 0000000..560fc56 --- /dev/null +++ b/src/profinet/profinet_cb_new_data_status_ind.cpp @@ -0,0 +1,13 @@ +#include "./profinet/profinet_cb_new_data_status_ind.hpp" + +int profinet_cb_new_data_status_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t crep, + uint8_t changes, + uint8_t data_status) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_new_data_status_ind.hpp b/src/profinet/profinet_cb_new_data_status_ind.hpp new file mode 100644 index 0000000..67ff16b --- /dev/null +++ b/src/profinet/profinet_cb_new_data_status_ind.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_new_data_status_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t crep, + uint8_t changes, + uint8_t data_status); \ No newline at end of file diff --git a/src/profinet/profinet_cb_read_ind.cpp b/src/profinet/profinet_cb_read_ind.cpp new file mode 100644 index 0000000..b841093 --- /dev/null +++ b/src/profinet/profinet_cb_read_ind.cpp @@ -0,0 +1,19 @@ +#include "./profinet/profinet_cb_read_ind.hpp" + + +int profinet_cb_read_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t api, + 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) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_read_ind.hpp b/src/profinet/profinet_cb_read_ind.hpp new file mode 100644 index 0000000..babe3b7 --- /dev/null +++ b/src/profinet/profinet_cb_read_ind.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_read_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t api, + 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); \ No newline at end of file diff --git a/src/profinet/profinet_cb_release_ind.cpp b/src/profinet/profinet_cb_release_ind.cpp new file mode 100644 index 0000000..7f8bf98 --- /dev/null +++ b/src/profinet/profinet_cb_release_ind.cpp @@ -0,0 +1,15 @@ +#include "./profinet/profinet_cb_release_ind.hpp" + +#include + +using namespace std; + +int profinet_cb_release_ind( pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result) +{ + cout << "profinet_cb_release_ind: PLC release (disconnect) indication. AREP: " << arep << endl; + /// По идее погасить светодиод наличия связи + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_release_ind.hpp b/src/profinet/profinet_cb_release_ind.hpp new file mode 100644 index 0000000..1da5f00 --- /dev/null +++ b/src/profinet/profinet_cb_release_ind.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_release_ind( pnet_t * net, + void * arg, + uint32_t arep, + pnet_result_t * p_result); \ No newline at end of file diff --git a/src/profinet/profinet_cb_reset_ind.cpp b/src/profinet/profinet_cb_reset_ind.cpp new file mode 100644 index 0000000..0ad4e28 --- /dev/null +++ b/src/profinet/profinet_cb_reset_ind.cpp @@ -0,0 +1,11 @@ +#include "./profinet/profinet_cb_reset_ind.hpp" + +int profinet_cb_reset_ind ( + pnet_t * net, + void * arg, + bool should_reset_application, + uint16_t reset_mode) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_reset_ind.hpp b/src/profinet/profinet_cb_reset_ind.hpp new file mode 100644 index 0000000..0688b75 --- /dev/null +++ b/src/profinet/profinet_cb_reset_ind.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_reset_ind ( + pnet_t * net, + void * arg, + bool should_reset_application, + uint16_t reset_mode); \ No newline at end of file diff --git a/src/profinet/profinet_cb_signal_led_ind.cpp b/src/profinet/profinet_cb_signal_led_ind.cpp new file mode 100644 index 0000000..9467a20 --- /dev/null +++ b/src/profinet/profinet_cb_signal_led_ind.cpp @@ -0,0 +1,7 @@ +#include "./profinet/profinet_cb_signal_led_ind.hpp" + +int profinet_cb_signal_led_ind (pnet_t * net, void * arg, bool led_state) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_signal_led_ind.hpp b/src/profinet/profinet_cb_signal_led_ind.hpp new file mode 100644 index 0000000..1dcf0b5 --- /dev/null +++ b/src/profinet/profinet_cb_signal_led_ind.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_signal_led_ind (pnet_t * net, void * arg, bool led_state); \ No newline at end of file diff --git a/src/profinet/profinet_cb_state_ind.cpp b/src/profinet/profinet_cb_state_ind.cpp new file mode 100644 index 0000000..bf34849 --- /dev/null +++ b/src/profinet/profinet_cb_state_ind.cpp @@ -0,0 +1,11 @@ +#include "./profinet/profinet_cb_state_ind.hpp" + +int profinet_cb_state_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + pnet_event_values_t event) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_state_ind.hpp b/src/profinet/profinet_cb_state_ind.hpp new file mode 100644 index 0000000..18e50dd --- /dev/null +++ b/src/profinet/profinet_cb_state_ind.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_state_ind( pnet_t * net, + void * arg, + uint32_t arep, + pnet_event_values_t event); \ No newline at end of file diff --git a/src/profinet/profinet_cb_write_ind.cpp b/src/profinet/profinet_cb_write_ind.cpp new file mode 100644 index 0000000..8ea3aea --- /dev/null +++ b/src/profinet/profinet_cb_write_ind.cpp @@ -0,0 +1,18 @@ +#include "./profinet/profinet_cb_write_ind.hpp" + +int profinet_cb_write_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t api, + 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) +{ + + return 0; +} \ No newline at end of file diff --git a/src/profinet/profinet_cb_write_ind.hpp b/src/profinet/profinet_cb_write_ind.hpp new file mode 100644 index 0000000..ac32635 --- /dev/null +++ b/src/profinet/profinet_cb_write_ind.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +int profinet_cb_write_ind ( + pnet_t * net, + void * arg, + uint32_t arep, + uint32_t api, + 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); \ No newline at end of file diff --git a/src/profinet/profinet_serv_data.hpp b/src/profinet/profinet_serv_data.hpp new file mode 100644 index 0000000..fd61089 --- /dev/null +++ b/src/profinet/profinet_serv_data.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../libs/include/pnet_api.h" + +struct ProfinetServiceData { + pnet_t * pnet_ptr; + uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet +}; \ No newline at end of file diff --git a/src/profinet/profinet_settings.hpp b/src/profinet/profinet_settings.hpp new file mode 100644 index 0000000..d4b3e7d --- /dev/null +++ b/src/profinet/profinet_settings.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include +#include + +struct ProfinetSettingsSwRevision +{ + /* Allowed: 'V', 'R', 'P', 'U', 'T' */ + char prefix; + uint8_t functional_enhancement; + uint8_t bug_fix; + uint8_t internal_change; +}; + +struct ProfinetSettingsIm0 +{ + uint16_t vendor_id; + + uint16_t hw_revision; + ProfinetSettingsSwRevision sw_revision; + + uint16_t revision_counter; + uint16_t profile_id; + uint16_t profile_specific_type; + /** One bit for each supported I&M1..15. I&M0 is always supported. + Use pnet_im_supported_values_t. */ + uint16_t supported; + + std::string order_id; + std::string serial_number; +}; + +struct ProfinetSettingsIm1 +{ + std::string tag_function; + std::string tag_location; +}; + +struct ProfinetSettingsIm2 +{ + std::string date; +}; + +struct ProfinetSettingsIm3 +{ + std::string descriptor; +}; + +struct ProfinetSettingsIm4 +{ + std::string signature; +}; + +struct ProfinetDeviceSettings { + /** + * Product name + * + * This is known as DeviceVendorValue and DeviceType in the Profinet + * specification. It constitutes the first part of SystemIdentification + * (sysDescr in SNMP). It may also be used to construct the Chassis ID. + * See IEC CDV 61158-6-10 ch. 4.10.3.3.1. + * + * Terminated string. + */ + std::string product_name; + /** Default station name.*/ + std::string station_name; + + ProfinetSettingsIm0 im_0; + ProfinetSettingsIm1 im_1; + ProfinetSettingsIm2 im_2; + ProfinetSettingsIm3 im_3; + ProfinetSettingsIm4 im_4; + + uint16_t device_id; + uint16_t oem_vendor_id; + uint16_t oem_device_id; + + bool send_hello; + uint16_t min_device_interval; +}; + +/// Настройки не зависящие от описания данных Profinet +struct ProfinetSettings { + uint32_t ticks_us = 1000; /// Устанавливает время в мкс между вызовами pnet_handle_periodic() + std::string EthIface = ""; /// Имя интерфейса ethernet +}; \ No newline at end of file diff --git a/src/profinet/profinet_slot.cpp b/src/profinet/profinet_slot.cpp new file mode 100644 index 0000000..aee6435 --- /dev/null +++ b/src/profinet/profinet_slot.cpp @@ -0,0 +1,59 @@ +#include "profinet_slot.hpp" + +ProfinetSlot::ProfinetSlot ( uint16_t slot_nbr, + uint32_t module_id, + std::string module_name) : m_slot_nbr(slot_nbr), + m_module_id(module_id), + m_module_name(module_name) + +{ + +} + + +bool ProfinetSlot::pullModule(ProfinetServiceData& pnet_data) +{ + int result = pnet_pull_module (pnet_data.pnet_ptr, pnet_data.api, m_slot_nbr); + + m_module_plugged = false; + + return (result == 0); +} + +bool ProfinetSlot::plugModule(ProfinetServiceData& pnet_data) +{ + /// Сначала отключаем модуль + pullModule(pnet_data); + /// Затем подключаем модуль + int result = pnet_plug_module (pnet_data.pnet_ptr, pnet_data.api, m_slot_nbr, m_module_id); + + m_module_plugged = (result == 0); + + return m_module_plugged; +} + +bool ProfinetSlot::addSubslot(std::shared_ptr& subslot_ptr) +{ + if (subslot_ptr == nullptr) + return false; + + subslot_ptr->setSlotNumber(m_slot_nbr); + subslot_ptr->setModuleId(m_module_id); + + m_subslots[subslot_ptr->m_submodule_id] = subslot_ptr; + + return true; +} + + +bool ProfinetSlot::addSubslotAndPlugSubmodule(ProfinetServiceData& pnet_data, std::shared_ptr& subslot_ptr) +{ + if (!addSubslot(subslot_ptr)) + return false; + + if (!subslot_ptr->plugSubmodule(pnet_data)) + return false; + + return true; +} + diff --git a/src/profinet/profinet_slot.hpp b/src/profinet/profinet_slot.hpp new file mode 100644 index 0000000..3cd151d --- /dev/null +++ b/src/profinet/profinet_slot.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "profinet_serv_data.hpp" +#include "profinet_subslot.hpp" + +#include +#include +#include +#include + +class ProfinetSlot +{ +public: + /** + * @brief Construct a new Profinet Slot object + * + * @param slot_nbr номер слота + * @param module_id идентификатор модуля который может поключиться к этому слоту + * @param module_name имя модуля + */ + ProfinetSlot ( + uint16_t slot_nbr, + uint32_t module_id, + std::string module_name + ); + /** + * @brief Подключает модуль к слоту + * + * @param pnet_data Данные pnet + * @return true модуль подключен + * @return false модуль не подключен + */ + bool plugModule(ProfinetServiceData& pnet_data); + /** + * @brief Отключает модуль от слота + * + * @param pnet_data Данные pnet + * @return true модуль был поключен и теперь отключен + * @return false модуль не был подключен + */ + bool pullModule(ProfinetServiceData& pnet_data); + + bool addSubslot(std::shared_ptr& subslot_ptr); + + bool addSubslotAndPlugSubmodule(ProfinetServiceData& pnet_data, std::shared_ptr& subslot_ptr); + +public: + /// Номер слота + const uint16_t m_slot_nbr; + + /// Идентификатор модуля который может быть подключен к данному слоту + const uint32_t m_module_id; + + /// Имя подключаемого модуля + const std::string m_module_name; + +private: + /// Флаг подключения модуля к слоту + bool m_module_plugged; + /// множество подслотов + std::map> m_subslots; +}; diff --git a/src/profinet/profinet_subslot.cpp b/src/profinet/profinet_subslot.cpp new file mode 100644 index 0000000..112307e --- /dev/null +++ b/src/profinet/profinet_subslot.cpp @@ -0,0 +1,44 @@ +#include "profinet_subslot.hpp" + +ProfinetSubslot::ProfinetSubslot(uint16_t subslot_nbr, + uint32_t submodule_id, + std::string submodule_name, + pnet_data_cfg_t data_cfg) : + m_subslot_nbr(subslot_nbr), + m_submodule_id(submodule_id), + m_submodule_name(submodule_name), + m_data_cfg(data_cfg), + m_submodule_plugged(false) +{ + +} + +bool ProfinetSubslot::pullSubmodule(ProfinetServiceData& pnet_data) +{ + int result = pnet_pull_submodule (pnet_data.pnet_ptr, pnet_data.api, m_slot_nbr, m_subslot_nbr); + + m_submodule_plugged = false; + + return (result == 0); +} + +bool ProfinetSubslot::plugSubmodule(ProfinetServiceData& pnet_data) +{ + /// Сначала отключаем подмодуль + pullSubmodule(pnet_data); + /// Подключаем подмодуль + int result = pnet_plug_submodule ( + pnet_data.pnet_ptr, + pnet_data.api, + m_slot_nbr, + m_subslot_nbr, + m_module_id, + m_submodule_id, + m_data_cfg.data_dir, + m_data_cfg.insize, + m_data_cfg.outsize); + + m_submodule_plugged = (result == 0); + + return m_submodule_plugged; +} \ No newline at end of file diff --git a/src/profinet/profinet_subslot.hpp b/src/profinet/profinet_subslot.hpp new file mode 100644 index 0000000..3869101 --- /dev/null +++ b/src/profinet/profinet_subslot.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#include "profinet_serv_data.hpp" +#include "../../libs/include/pnet_api.h" + +/** + * Callback for updated cyclic data + * + * @param subslot InOut: Subslot structure + * @param tag InOut: Typically a handle to a submodule + */ +typedef void (*ProfinetSubslotCallback) (ProfinetSubslot * subslot, void * tag); + +class ProfinetSubslot +{ +public: + ProfinetSubslot(uint16_t subslot_nbr, + uint32_t submodule_id, + std::string submodule_name, + pnet_data_cfg_t data_cfg); + + bool plugSubmodule(ProfinetServiceData& pnet_data); + + bool pullSubmodule(ProfinetServiceData& pnet_data); + + void setSlotNumber(uint16_t slot_nbr) { m_slot_nbr = slot_nbr; }; + + void setModuleId(uint16_t module_id) { m_module_id = module_id; }; + +public: + /// Номер подслота + const uint16_t m_subslot_nbr; + + /// Идентификатор подмодуля который вставлен в данный подслот + const uint32_t m_submodule_id; + + /// Имя этого подмодуля + const std::string m_submodule_name; + + /// Конфигурация данных подмодуля (направление данных, размер данных) + const pnet_data_cfg_t m_data_cfg; + +private: + + /// Флаг подключения подмодуля к подслоту + bool m_submodule_plugged; + + /// Номер слота куда входит данный подслот + uint16_t m_slot_nbr; + + /// Идентификатор модуля куда входит подключаемый подмодуль + uint16_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; + + /** Callback for cyclic input- or output data, or NULL if not implemented */ + ProfinetSubslotCallback m_cyclic_callback; + + /// данные передающиеся в cyclic_callback вторым параметром. + void * m_tag; +}; + + + diff --git a/src/utils/utils.c b/src/utils/utils.c new file mode 100644 index 0000000..6902485 --- /dev/null +++ b/src/utils/utils.c @@ -0,0 +1,151 @@ +#include "utils.h" + +static void utils_copy_ip_to_struct ( + pnet_cfg_ip_addr_t * destination_struct, + uint32_t ip) +{ + destination_struct->a = ((ip >> 24) & 0xFF); + destination_struct->b = ((ip >> 16) & 0xFF); + destination_struct->c = ((ip >> 8) & 0xFF); + destination_struct->d = (ip & 0xFF); +} + +static int utils_get_netif_namelist ( + const char * arg_str, + uint16_t max_port, + utils_netif_namelist_t * p_if_list, + uint16_t * p_num_ports) +{ + int ret = 0; + uint16_t i = 0; + uint16_t j = 0; + uint16_t if_index = 0; + uint16_t number_of_given_names = 1; + uint16_t if_list_size = max_port + 1; + char c; + + if (max_port == 0) + { + printf ("Error: max_port is 0.\n"); + return -1; + } + + memset (p_if_list, 0, sizeof (*p_if_list)); + c = arg_str[i++]; + while (c != '\0') + { + if (c != ',') + { + if (if_index < if_list_size) + { + p_if_list->netif[if_index].name[j++] = c; + } + } + else + { + if (if_index < if_list_size) + { + p_if_list->netif[if_index].name[j++] = '\0'; + j = 0; + if_index++; + } + number_of_given_names++; + } + + c = arg_str[i++]; + } + + if (max_port == 1 && number_of_given_names > 1) + { + printf ("Error: Only 1 network interface expected as max_port is 1.\n"); + return -1; + } + if (number_of_given_names == 2) + { + printf ("Error: It is illegal to give 2 interface names. Use 1, or one " + "more than the number of physical interfaces.\n"); + return -1; + } + if (number_of_given_names > max_port + 1) + { + printf ( + "Error: You have given %u interface names, but max is %u as " + "PNET_MAX_PHYSICAL_PORTS is %u.\n", + number_of_given_names, + max_port + 1, + max_port); + return -1; + } + + if (number_of_given_names == 1) + { + if (strlen (p_if_list->netif[0].name) == 0) + { + printf ("Error: Zero length network interface name.\n"); + return -1; + } + else + { + p_if_list->netif[1] = p_if_list->netif[0]; + *p_num_ports = 1; + } + } + else + { + for (i = 0; i < number_of_given_names; i++) + { + if (strlen (p_if_list->netif[i].name) == 0) + { + printf ("Error: Zero length network interface name (%d).\n", i); + return -1; + } + } + + *p_num_ports = number_of_given_names - 1; + } + + return ret; +} + +int utils_pnet_cfg_init_netifs ( + const char * netif_list_str, + utils_netif_namelist_t * if_list, + uint16_t * number_of_ports, + pnet_if_cfg_t * if_cfg, + uint16_t default_mau_type) +{ + int ret = 0; + int i = 0; + uint32_t ip; + uint32_t netmask; + uint32_t gateway; + + ret = app_utils_get_netif_namelist ( + netif_list_str, + PNET_MAX_PHYSICAL_PORTS, + if_list, + number_of_ports); + + if (ret != 0) + { + return ret; + } + if_cfg->main_netif_name = if_list->netif[0].name; + + for (i = 1; i <= *number_of_ports; i++) + { + if_cfg->physical_ports[i - 1].netif_name = if_list->netif[i].name; + if_cfg->physical_ports[i - 1].default_mau_type = default_mau_type; + } + + /* Read IP, netmask, gateway from operating system */ + ip = pnal_get_ip_address (if_cfg->main_netif_name); + netmask = pnal_get_netmask (if_cfg->main_netif_name); + gateway = pnal_get_gateway (if_cfg->main_netif_name); + + utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_addr, ip); + utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_gateway, gateway); + utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_mask, netmask); + + return ret; +} \ No newline at end of file diff --git a/src/utils/utils.cmake b/src/utils/utils.cmake new file mode 100644 index 0000000..9b55b14 --- /dev/null +++ b/src/utils/utils.cmake @@ -0,0 +1,3 @@ + +set(SRC_FILES ${SRC_FILES} ./utils/utils.c) +set(INC_DIRS ${INC_DIRS} ./utils) \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..db7cf08 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,46 @@ +#ifndef UTILS_H +#define UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pnet_api.h" +#include "osal.h" + +typedef struct utils_netif_name +{ + char name[PNET_INTERFACE_NAME_MAX_SIZE]; +} utils_netif_name_t; + +typedef struct utils_netif_namelist +{ + utils_netif_name_t netif[PNET_MAX_PHYSICAL_PORTS + 1]; +} utils_netif_namelist_t; + +/** + * Update network configuration from a string + * defining a list of network interfaces examples: + * "eth0" or "br0,eth0,eth1" + * + * Read IP, netmask etc from operating system. + * + * @param netif_list_str In: Comma separated string of network ifs + * @param if_list Out: Array of network ifs + * @param number_of_ports Out: Number of ports + * @param if_cfg Out: P-Net network configuration to be updated + * @param default_mau_type + * @return 0 on success, -1 on error + */ +int utils_pnet_cfg_init_netifs ( + const char * netif_list_str, + utils_netif_namelist_t * if_list, + uint16_t * number_of_ports, + pnet_if_cfg_t * if_cfg, + uint16_t default_mau_type); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file