259 lines
10 KiB
C++
259 lines
10 KiB
C++
|
|
#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 <cstring>
|
|||
|
|
|
|||
|
|
#include <cstdio>
|
|||
|
|
#include <iostream>
|
|||
|
|
|
|||
|
|
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<void*>(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<ProfinetSlot>(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<ProfinetSubslot>( 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<ProfinetSubslot>( 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<ProfinetSubslot>( 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<ProfinetSlot>& 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<ProfinetSlot>& slot_ptr)
|
|||
|
|
{
|
|||
|
|
if (!addSlot(slot_ptr))
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
if (!slot_ptr->plugModule(m_pnet_data))
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|