Merge branch 'master' of http://server_gorbunov:3000/SmartForce4.0/profinet_io_dev
This commit is contained in:
commit
b68e6e2a86
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# игнорирование папок build
|
||||
/src/build
|
||||
/profinet_test/sample_app/build
|
||||
*.bin
|
||||
37
debug_support/gdb_update.sh
Executable file
37
debug_support/gdb_update.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Motivation: build gdb 12.1 from source because of this issue: https://github.com/Gallopsled/pwntools/issues/1783
|
||||
|
||||
# Optional: remove existing gdb
|
||||
echo ">>>> remove existing gdb:"
|
||||
echo ">>>> sudo apt remove gdb gdbserver"
|
||||
#sudo apt remove gdb gdbserver
|
||||
|
||||
# Get latest source from https://ftp.gnu.org/gnu/gdb/
|
||||
echo ">>>> Get latest source from https://ftp.gnu.org/gnu/gdb/:"
|
||||
echo ">>>> wget https://ftp.gnu.org/gnu/gdb/gdb-12.1.tar.xz"
|
||||
wget https://ftp.gnu.org/gnu/gdb/gdb-12.1.tar.xz
|
||||
|
||||
echo ">>>> tar xf gdb-12.1.tar.xz"
|
||||
tar xf gdb-12.1.tar.xz
|
||||
|
||||
# Install necessary build tools
|
||||
echo ">>>> Install necessary build tools:"
|
||||
echo ">>>> sudo apt install -y build-essential texinfo bison flex"
|
||||
sudo apt install -y build-essential texinfo bison flex python3-dev libgmp-dev
|
||||
echo ">>>> cd gdb-12.1"
|
||||
cd gdb-12.1
|
||||
echo ">>>> Configure with python3 support"
|
||||
echo ">>>> ./configure --with-python=/usr/bin/python3"
|
||||
# Configure with python3 support
|
||||
./configure --with-python=/usr/bin/python3
|
||||
|
||||
# Build (this takes a while)
|
||||
echo ">>>> Build (this takes a while)"
|
||||
echo ">>>> make -j8"
|
||||
make -j8
|
||||
|
||||
# Install binary
|
||||
echo ">>>> Install binary:"
|
||||
echo ">>>> sudo make install"
|
||||
sudo make install
|
||||
@ -13,3 +13,8 @@ sudo chmod -x debug_support/gdb
|
||||
-i - eth-интерфейс к которому подключен Profinet мастер
|
||||
-v - уровень логов, чтобы был Debug нужно указать 4 раза
|
||||
-p - папка для хранения настроечных файлов
|
||||
|
||||
|
||||
Если версия Ubuntu 22.04, то там есть баг с gdb - он падает при переключении на другой поток в отлажеваемом ПО
|
||||
Для исправления нужно либо установить Ubuntu 22.10, либо собрать gdb 12.1.
|
||||
Для сборки запустить скрипт gdb_update.sh
|
||||
|
||||
40
src/CMakeLists.txt
Normal file
40
src/CMakeLists.txt
Normal file
@ -0,0 +1,40 @@
|
||||
#********************************************************************
|
||||
# _ _ _
|
||||
# _ __ | |_ _ | | __ _ | |__ ___
|
||||
# | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
# | | | |_ _ | || (_| || |_) |\__ \
|
||||
# |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
#
|
||||
# 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(CMAKE_CXX_STANDARD 20)
|
||||
set(LIBS_INSTALL_PATH ../libs)
|
||||
set(PNET_PATH ../profinet_stack/p-net)
|
||||
|
||||
include(./utils/utils.cmake)
|
||||
include(./profinet/profinet.cmake)
|
||||
include(./nlohmann_json/nlohmann_json.cmake)
|
||||
include(./file_api/file_api.cmake)
|
||||
include(./configuration/configuration.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)
|
||||
8
src/app_settings.hpp
Normal file
8
src/app_settings.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
struct AppSettings
|
||||
{
|
||||
std::string EthDevName; /// Имя адаптера
|
||||
};
|
||||
5
src/configuration/configuration.cmake
Normal file
5
src/configuration/configuration.cmake
Normal file
@ -0,0 +1,5 @@
|
||||
set(SRC_FILES ${SRC_FILES}
|
||||
./configuration/program_config.cpp
|
||||
)
|
||||
|
||||
set(INC_DIRS ${INC_DIRS} ./configuration)
|
||||
241
src/configuration/program_config.cpp
Normal file
241
src/configuration/program_config.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include "program_config.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include "file_api.hpp"
|
||||
#include "json.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using string = std::string;
|
||||
|
||||
static bool programconf_readfile(json& j, std::string& file_path)
|
||||
{
|
||||
///string config_str;
|
||||
|
||||
try
|
||||
{
|
||||
///config_str = fileapi_read_full_stream( fileapi_read_file(file_path) );
|
||||
j = json::parse(fileapi_read_file(file_path));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool programconf_getProfinetSettings(std::string file_path, ProfinetSettings& pn_sett)
|
||||
{
|
||||
json j;
|
||||
|
||||
if (!programconf_readfile(j, file_path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pn_sett.ticks_us = j["ProfinetSettings"]["ticks_us"].get<int>();
|
||||
pn_sett.cyclic_ms = j["ProfinetSettings"]["cyclic_ms"].get<int>();
|
||||
pn_sett.eth_dev_name = j["ProfinetSettings"]["eth_dev_name"].get<string>();
|
||||
pn_sett.profinet_device_config = j["ProfinetSettings"]["profinet_device_config"].get<string>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t hexstring_to_int(string s)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
if (s.find("0x") != string::npos)
|
||||
{
|
||||
s = s.substr(2); //Игнорируем 0x
|
||||
std::istringstream(s) >> std::hex >> n;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::istringstream(s) >> std::dec >> n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool programconf_getPnetDeviceSettings(json& j, ProfinetDeviceSettings& pnet_sett)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceSettings"))
|
||||
return false;
|
||||
|
||||
auto& sett = j["ProfinetDeviceSettings"];
|
||||
pnet_sett.product_name = sett["product_name"].get<string>();
|
||||
pnet_sett.station_name = sett["station_name"].get<string>();
|
||||
pnet_sett.station_name = sett["station_name"].get<string>();
|
||||
|
||||
|
||||
if (!sett.contains("im_0"))
|
||||
return false;
|
||||
|
||||
auto& im_0 = sett["im_0"];
|
||||
|
||||
pnet_sett.im_0.vendor_id = hexstring_to_int( im_0["vendor_id"].get<string>() );
|
||||
pnet_sett.im_0.hw_revision = im_0["hw_revision"].get<int>();
|
||||
|
||||
|
||||
if (!im_0.contains("sw_revision"))
|
||||
return false;
|
||||
|
||||
auto& sw_revision = im_0["sw_revision"];
|
||||
|
||||
string prefix = sw_revision["prefix"].get<string>();
|
||||
if (prefix.length())
|
||||
{
|
||||
pnet_sett.im_0.sw_revision.prefix = prefix.c_str()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
pnet_sett.im_0.sw_revision.prefix = ' ';
|
||||
}
|
||||
|
||||
pnet_sett.im_0.sw_revision.functional_enhancement = sw_revision["functional_enhancement"].get<int>();
|
||||
pnet_sett.im_0.sw_revision.bug_fix = sw_revision["bug_fix"].get<int>();
|
||||
pnet_sett.im_0.sw_revision.internal_change = sw_revision["internal_change"].get<int>();
|
||||
|
||||
|
||||
pnet_sett.im_0.revision_counter = im_0["revision_counter"].get<int>();
|
||||
pnet_sett.im_0.profile_id = hexstring_to_int(im_0["profile_id"].get<string>());
|
||||
pnet_sett.im_0.profile_specific_type = hexstring_to_int(im_0["profile_specific_type"].get<string>());
|
||||
pnet_sett.im_0.supported = hexstring_to_int(im_0["supported"].get<string>());
|
||||
pnet_sett.im_0.order_id = im_0["order_id"].get<string>();
|
||||
pnet_sett.im_0.serial_number = im_0["serial_number"].get<string>();
|
||||
|
||||
|
||||
if (!sett.contains("im_1"))
|
||||
return false;
|
||||
|
||||
auto& im_1 = sett["im_1"];
|
||||
pnet_sett.im_1.tag_function = im_1["tag_function"].get<string>();
|
||||
pnet_sett.im_1.tag_location = im_1["tag_location"].get<string>();
|
||||
|
||||
|
||||
pnet_sett.im_2.date = sett["im_2"]["date"].get<string>();
|
||||
pnet_sett.im_3.descriptor = sett["im_3"]["descriptor"].get<string>();
|
||||
pnet_sett.im_4.signature = sett["im_4"]["signature"].get<string>();
|
||||
|
||||
pnet_sett.device_id = hexstring_to_int(sett["device_id"].get<string>());
|
||||
pnet_sett.oem_vendor_id = hexstring_to_int(sett["oem_vendor_id"].get<string>());
|
||||
pnet_sett.oem_device_id = hexstring_to_int(sett["oem_device_id"].get<string>());
|
||||
pnet_sett.send_hello = sett["send_hello"].get<bool>();
|
||||
pnet_sett.min_device_interval = sett["min_device_interval"].get<int>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static pnet_submodule_dir_t programconf_dataDirConvert(string dir_str)
|
||||
{
|
||||
pnet_submodule_dir_t out = PNET_DIR_NO_IO;
|
||||
|
||||
if (dir_str == "PNET_DIR_IO")
|
||||
{
|
||||
out = PNET_DIR_IO;
|
||||
}
|
||||
else if (dir_str == "PNET_DIR_INPUT")
|
||||
{
|
||||
out = PNET_DIR_INPUT;
|
||||
}
|
||||
else if (dir_str == "PNET_DIR_OUTPUT")
|
||||
{
|
||||
out = PNET_DIR_OUTPUT;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool programconf_getProfinetModulesSettings(json& j, std::vector<std::shared_ptr<ProfinetModule>>& modules_vect)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceModulesSettings"))
|
||||
return false;
|
||||
|
||||
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
|
||||
|
||||
for (auto& mod_set : modules_sett)
|
||||
{
|
||||
uint32_t mod_id = hexstring_to_int(mod_set["id"].get<string>());
|
||||
string mod_name = mod_set["name"].get<string>();
|
||||
|
||||
auto module_ptr = ProfinetModule::Create(mod_id, mod_name);
|
||||
if (module_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& submodules_sett = mod_set["submodules"];
|
||||
|
||||
for (auto& submod_sett : submodules_sett)
|
||||
{
|
||||
uint32_t submod_id = hexstring_to_int(submod_sett["id"].get<string>());
|
||||
string submod_name = submod_sett["name"].get<string>();
|
||||
|
||||
pnet_data_cfg_t data_cfg;
|
||||
|
||||
data_cfg.data_dir = programconf_dataDirConvert(submod_sett["cyc_data_dir"].get<string>());
|
||||
data_cfg.insize = submod_sett["cyc_inp_data_size"].get<int>();
|
||||
data_cfg.outsize = submod_sett["cyc_out_data_size"].get<int>();
|
||||
|
||||
auto submodule_ptr = ProfinetSubmodule::Create(submod_id, submod_name, data_cfg);
|
||||
|
||||
if (submodule_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& params_sett = submod_sett["parameters"];
|
||||
|
||||
/// Записываем параметры в подмодуль
|
||||
for (auto& parm_sett : params_sett)
|
||||
{
|
||||
uint32_t index = parm_sett["index"].get<int>();
|
||||
string parm_name = parm_sett["name"].get<string>();
|
||||
uint16_t length = parm_sett["data_size"].get<int>();
|
||||
|
||||
auto submod_param_ptr = ProfinetParameter::Create(index, parm_name, length);
|
||||
|
||||
if (submod_param_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
submodule_ptr->addParameter(submod_param_ptr);
|
||||
}
|
||||
|
||||
module_ptr->addSubmodule(submodule_ptr);
|
||||
}
|
||||
|
||||
modules_vect.push_back(module_ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett, std::vector<std::shared_ptr<ProfinetModule>>& modules_vect)
|
||||
{
|
||||
json j;
|
||||
|
||||
if (!programconf_readfile(j, file_path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!programconf_getPnetDeviceSettings(j, pn_sett))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!programconf_getProfinetModulesSettings(j, modules_vect))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
13
src/configuration/program_config.hpp
Normal file
13
src/configuration/program_config.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "json.hpp"
|
||||
#include "profinet_settings.hpp"
|
||||
#include "profinet_module.hpp"
|
||||
|
||||
bool programconf_getProfinetSettings(std::string file_path, ProfinetSettings& pn_sett);
|
||||
|
||||
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
|
||||
std::vector<std::shared_ptr<ProfinetModule>>& modules_vect);
|
||||
|
||||
5
src/file_api/file_api.cmake
Normal file
5
src/file_api/file_api.cmake
Normal file
@ -0,0 +1,5 @@
|
||||
set(SRC_FILES ${SRC_FILES}
|
||||
./file_api/file_api.cpp
|
||||
)
|
||||
|
||||
set(INC_DIRS ${INC_DIRS} ./file_api)
|
||||
26
src/file_api/file_api.cpp
Normal file
26
src/file_api/file_api.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "file_api.hpp"
|
||||
|
||||
std::ifstream fileapi_read_file( std::filesystem::path filepath, std::ostream & info)
|
||||
{
|
||||
|
||||
if( not std::filesystem::exists( filepath ) )
|
||||
throw std::invalid_argument{ "File: " + filepath.string() + " does not exist." };
|
||||
|
||||
if( not std::filesystem::is_regular_file( filepath ) )
|
||||
throw std::invalid_argument{"File: " + filepath.string() + " is not a file."};
|
||||
|
||||
info << "File: " + filepath.string() + " is valid." << std::endl;
|
||||
|
||||
return { filepath };
|
||||
}
|
||||
|
||||
std::string fileapi_read_full_stream( std::ifstream _is )
|
||||
{
|
||||
std::string file_;
|
||||
while( _is ){
|
||||
std::string file_str;
|
||||
_is >> file_str;
|
||||
file_ += file_str;
|
||||
}
|
||||
return file_;
|
||||
}
|
||||
10
src/file_api/file_api.hpp
Normal file
10
src/file_api/file_api.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
std::ifstream fileapi_read_file( std::filesystem::path filepath, std::ostream & info = std::cout );
|
||||
|
||||
std::string fileapi_read_full_stream( std::ifstream _is );
|
||||
34
src/flags/flags.hpp
Normal file
34
src/flags/flags.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <cstdint>
|
||||
|
||||
class Flags {
|
||||
public:
|
||||
Flags() : flags_{0} {}
|
||||
|
||||
void set_flag(uint32_t mask) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
flags_ |= mask;
|
||||
}
|
||||
|
||||
uint32_t get_flag(uint32_t mask) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return flags_ & mask;
|
||||
}
|
||||
|
||||
uint32_t get_flags() {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void clear_flags(uint32_t mask)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
flags_ &= ~mask;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t flags_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
17
src/log/log.hpp
Normal file
17
src/log/log.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
class Log {
|
||||
public:
|
||||
Log(int log_level) : log_level_(log_level) {}
|
||||
|
||||
void put(std::string info) {
|
||||
if (log_level_ > 0)
|
||||
std::cout << "log: " << info << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
const int log_level_;
|
||||
};
|
||||
99
src/main.cpp
Normal file
99
src/main.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "app_settings.hpp"
|
||||
#include "../libs/include/pnet_api.h"
|
||||
#include "profinet.hpp"
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
|
||||
#include "program_config.hpp"
|
||||
|
||||
#define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля
|
||||
#define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля
|
||||
#define ECHO_INPUT_DATA_SIZE 8
|
||||
#define ECHO_OUTPUT_DATA_SIZE 8
|
||||
#define ECHO_PARAMETER_GAIN_IDX 125 /// Индекс параметра Gain для подмодуля ECHO
|
||||
|
||||
using namespace std;
|
||||
|
||||
uint32_t Echo_Gain = 0;
|
||||
|
||||
struct EchoData {
|
||||
float data_f;
|
||||
uint32_t data_i;
|
||||
};
|
||||
|
||||
union EchoDataMem
|
||||
{
|
||||
EchoData data;
|
||||
uint8_t mem[sizeof(EchoData)];
|
||||
};
|
||||
|
||||
EchoDataMem Echo_inpCycData;
|
||||
EchoDataMem Echo_outCycData;
|
||||
|
||||
uint8_t be_data_inp[sizeof(EchoData)];
|
||||
|
||||
void endian_convert_32(uint8_t * p_data)
|
||||
{
|
||||
uint8_t tmp = p_data[1];
|
||||
p_data[1] = p_data[2];
|
||||
p_data[2] = tmp;
|
||||
tmp = p_data[0];
|
||||
p_data[0] = p_data[3];
|
||||
p_data[3] = tmp;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
Echo_inpCycData.data.data_f = 54321.9f; /// Преобразовать в big endian
|
||||
Echo_inpCycData.data.data_i = 876; /// Преобразовать в big endian
|
||||
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i);
|
||||
|
||||
Echo_outCycData.data.data_f = 0.0f;
|
||||
Echo_outCycData.data.data_i = 0;
|
||||
|
||||
ProfinetSettings profinet_settings;
|
||||
ProfinetDeviceSettings profinet_dev_settings;
|
||||
|
||||
/// Читаем настройки из файла
|
||||
if (!programconf_getProfinetSettings("program_configure.json", profinet_settings))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ProfinetModule>> Modules;
|
||||
|
||||
/// Читаем настройки из файла
|
||||
if (!programconf_getProfinetDeviceSettings(profinet_settings.profinet_device_config, profinet_dev_settings, Modules))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Profinet profinet;
|
||||
/// Настройка Profinet: Инициализация pnet, добавление DAP слотов и подслотов и подключение к ним модулей и подмодулей,
|
||||
if (!profinet.Config(profinet_settings, profinet_dev_settings, Modules))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Циклические данные устройства передаются с определенным периодом, сообщения от контроллера при этом не требуются.
|
||||
*/
|
||||
/// Запуск потока Profinet
|
||||
profinet.Start();
|
||||
|
||||
auto echo_mod = profinet.getModule(ECHO_MODULE_ID);
|
||||
auto echo_submod = echo_mod->getSubmodulePtr(ECHO_SUBMOD_ID);
|
||||
echo_submod->putDataToPlc(Echo_inpCycData.mem);
|
||||
|
||||
uint32_t ix = 0;
|
||||
while(1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
++ix;
|
||||
std::cout << "tick: " << ix << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
24188
src/nlohmann_json/json.hpp
Normal file
24188
src/nlohmann_json/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1
src/nlohmann_json/nlohmann_json.cmake
Normal file
1
src/nlohmann_json/nlohmann_json.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(INC_DIRS ${INC_DIRS} ./nlohmann_json)
|
||||
26
src/profinet/profinet.cmake
Normal file
26
src/profinet/profinet.cmake
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
set(SRC_FILES ${SRC_FILES}
|
||||
./profinet/profinet.cpp
|
||||
./profinet/profinet_slot.cpp
|
||||
./profinet/profinet_subslot.cpp
|
||||
./profinet/profinet_module.cpp
|
||||
./profinet/profinet_submodule.cpp
|
||||
./profinet/profinet_parameter.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
|
||||
)
|
||||
|
||||
set(INC_DIRS ${INC_DIRS} ./profinet)
|
||||
941
src/profinet/profinet.cpp
Normal file
941
src/profinet/profinet.cpp
Normal file
@ -0,0 +1,941 @@
|
||||
#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 <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
#define FLAGS_AREP_APP_READY 0x00000001
|
||||
|
||||
//#define RELEASE
|
||||
|
||||
#ifndef RELEASE
|
||||
#define LOG(STR) log_.put(STR)
|
||||
#else
|
||||
#define LOG(STR)
|
||||
#endif
|
||||
|
||||
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() : m_pnet_data({nullptr, 0, UINT32_MAX, 0}),
|
||||
m_cyclic_io_cnt{0},
|
||||
m_periodic_stop{false},
|
||||
log_{1}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Profinet::Config(ProfinetSettings& Settings,
|
||||
ProfinetDeviceSettings& DevSettings,
|
||||
std::vector<std::shared_ptr<ProfinetModule>>& Modules)
|
||||
{
|
||||
bool ret = true;
|
||||
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);
|
||||
|
||||
m_run_period_us = Settings.ticks_us;
|
||||
m_cyclic_io_period_ms = Settings.cyclic_ms;
|
||||
|
||||
///В колбэки pnet передается этот объект
|
||||
pnet_cfg.cb_arg = static_cast<void*>(this);
|
||||
|
||||
utils_pnet_cfg_init_netifs(Settings.eth_dev_name.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;
|
||||
|
||||
///
|
||||
pnet_data_cfg_t dap_data_cfg = { PNET_DIR_NO_IO, 0, 0 };
|
||||
/// Создаем обязательный модуль DAP
|
||||
auto dap_module = ProfinetModule::Create(PNET_MOD_DAP_IDENT, "DAP 1");
|
||||
/// Создаем обязательный подмодуль DAP Identity 1
|
||||
auto dap_submodule_indent_1 = ProfinetSubmodule::Create(PNET_SUBMOD_DAP_IDENT, "DAP Identity 1", dap_data_cfg);
|
||||
/// Создаем обязательный подмодуль DAP IFACE1 IDENT
|
||||
auto dap_submodule_iface_1_indent_1 = ProfinetSubmodule::Create(PNET_SUBMOD_DAP_INTERFACE_1_IDENT, "DAP IFACE1 IDENT", dap_data_cfg);
|
||||
/// Создаем обязательный подмодуль DAP Port 1
|
||||
auto dap_subslot_iface_1_port1_ident = ProfinetSubmodule::Create(PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, "DAP Port 1", dap_data_cfg);
|
||||
/// Добавляем подмодули к модулю
|
||||
ret&= dap_module->addSubmodule(dap_submodule_indent_1);
|
||||
ret&= dap_module->addSubmodule(dap_submodule_iface_1_indent_1);
|
||||
ret&= dap_module->addSubmodule(dap_subslot_iface_1_port1_ident);
|
||||
|
||||
/// Создаем слот для модуля DAP и доключаем к нему модуль dap_module
|
||||
ret&= addSlotAndPlugModule(PNET_SLOT_DAP_IDENT, dap_module);
|
||||
/// Добавляем подслоты к слоту PNET_SLOT_DAP_IDENT и подключаем к подслотам подмодули
|
||||
/// 1. Подмодуль "DAP Identity 1"
|
||||
ret&= addSubslotAndPlugSubmodule(PNET_SLOT_DAP_IDENT, PNET_SUBSLOT_DAP_IDENT, dap_submodule_indent_1);
|
||||
/// 2. Подмодуль "DAP IFACE1 IDENT"
|
||||
ret&= addSubslotAndPlugSubmodule(PNET_SLOT_DAP_IDENT, PNET_SUBSLOT_DAP_INTERFACE_1_IDENT, dap_submodule_iface_1_indent_1);
|
||||
/// 3. Подмодуль "DAP Port 1"
|
||||
ret&= addSubslotAndPlugSubmodule(PNET_SLOT_DAP_IDENT, PNET_SUBSLOT_DAP_INTERFACE_1_PORT_1_IDENT, dap_subslot_iface_1_port1_ident);
|
||||
|
||||
///Копируем конфигурацию модулей
|
||||
for (auto module_ptr : Modules)
|
||||
{
|
||||
if (module_ptr == nullptr)
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!addModule(module_ptr))
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetSlot> Profinet::addSlot(uint16_t slot_nbr)
|
||||
{
|
||||
std::shared_ptr<ProfinetSlot> slot_ptr(nullptr);
|
||||
|
||||
if (m_slots.count(slot_nbr))
|
||||
{
|
||||
slot_ptr = m_slots[slot_nbr];
|
||||
}
|
||||
else
|
||||
{
|
||||
slot_ptr = make_shared<ProfinetSlot>(slot_nbr);
|
||||
}
|
||||
|
||||
if (slot_ptr != nullptr)
|
||||
{
|
||||
m_slots[slot_nbr] = slot_ptr;
|
||||
}
|
||||
|
||||
return slot_ptr;
|
||||
}
|
||||
|
||||
bool Profinet::addModule(std::shared_ptr<ProfinetModule>& module_ptr)
|
||||
{
|
||||
if (module_ptr == nullptr)
|
||||
return false;
|
||||
|
||||
m_modules[module_ptr->m_id] = module_ptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetModule> Profinet::getModule(uint32_t module_id)
|
||||
{
|
||||
if (!m_modules.count(module_id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_modules[module_id];
|
||||
}
|
||||
|
||||
|
||||
bool Profinet::addSlotAndPlugModule(uint16_t slot_nbr, std::shared_ptr<ProfinetModule>& module_ptr)
|
||||
{
|
||||
auto slot = addSlot(slot_nbr);
|
||||
|
||||
if (slot == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return slot->plugModule(m_pnet_data, module_ptr);
|
||||
}
|
||||
|
||||
bool Profinet::addSlotAndPlugModule(uint16_t slot_nbr, uint32_t module_id)
|
||||
{
|
||||
/// 1. Проверяем, что module_id поддерживается
|
||||
auto module_ptr = getModule(module_id);
|
||||
|
||||
if (module_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
///2. Добавляет слот
|
||||
auto slot = addSlot(slot_nbr);
|
||||
|
||||
if (slot == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// 3. Подключаем модуль к слоту
|
||||
return slot->plugModule(m_pnet_data, module_ptr);
|
||||
}
|
||||
|
||||
|
||||
bool Profinet::addSubslotAndPlugSubmodule(uint16_t slot_nbr, uint16_t subslot_nbr, std::shared_ptr<ProfinetSubmodule>& submodule_ptr)
|
||||
{
|
||||
auto slot_ptr = getSlotPtr(slot_nbr);
|
||||
|
||||
if (slot_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto subslot_ptr = slot_ptr->addSubslot(subslot_nbr);
|
||||
|
||||
if (subslot_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return subslot_ptr->plugSubmodule(m_pnet_data, submodule_ptr);
|
||||
}
|
||||
|
||||
bool Profinet::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)
|
||||
{
|
||||
///1. Проверяем наличие слота
|
||||
auto slot_ptr = getSlotPtr(slot_nbr);
|
||||
|
||||
if (slot_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
///2. Проверяем, что к слоту подключен модуль с идентификатором module_id
|
||||
auto module_ptr = slot_ptr->getModulePtr();
|
||||
if (module_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (module_ptr->m_id != module_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
///3. Проверяем, что в модуль входит подмодуль с идентфикатором submodule_id
|
||||
auto submodule_ptr = module_ptr->getSubmodulePtr(submodule_id);
|
||||
if (submodule_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (submodule_ptr->m_id != submodule_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
///4. Проверяем, что конфигурация данных подмодуля совпадает
|
||||
if ((submodule_ptr->m_data_cfg.data_dir != p_exp_data->data_dir) ||
|
||||
(submodule_ptr->m_data_cfg.insize != p_exp_data->insize) ||
|
||||
(submodule_ptr->m_data_cfg.outsize != p_exp_data->outsize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return addSubslotAndPlugSubmodule(slot_nbr, subslot_nbr, submodule_ptr);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ProfinetSlot> Profinet::getSlotPtr(uint16_t slot_nbr)
|
||||
{
|
||||
/// 1. Проверить, что слот slot добавлен в конфигурацию
|
||||
if (!m_slots.count(slot_nbr))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_slots[slot_nbr];
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> Profinet::getSubslotPtr(uint16_t slot_nbr, uint16_t subslot_nbr)
|
||||
{
|
||||
auto slot_ptr = getSlotPtr(slot_nbr);
|
||||
|
||||
if (slot_ptr == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return slot_ptr->getSubslotPtr(subslot_nbr);
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetParameter> Profinet::getSubmoduleParameter(uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t param_index)
|
||||
{
|
||||
///1. Проверяем что существует подслот \a subslot_nbr входящий к \a slot_nbr
|
||||
auto subslot_ptr = getSubslotPtr(slot_nbr, subslot_nbr);
|
||||
|
||||
if (subslot_ptr == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///2. Проверяем что к подслоту \a subslot_nbr подключен подмодуль
|
||||
auto submodule_ptr = subslot_ptr->getSubmodulePtr();
|
||||
|
||||
if (submodule_ptr == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
///3. Проверяем, что у подмодуля есть параметр с индексом idx
|
||||
auto param_ptr = submodule_ptr->getParameterPtr(param_index);
|
||||
|
||||
if (param_ptr == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return param_ptr;
|
||||
}
|
||||
|
||||
void Profinet::initDataAndIoxs()
|
||||
{
|
||||
uint8_t indata_iops;
|
||||
/**
|
||||
* Итерируемся по всем слотам.
|
||||
* Если слоты есть, то и модули к ним уже подключены, т.к. это делает контроллер.
|
||||
*/
|
||||
for (auto slot : m_slots)
|
||||
{
|
||||
shared_ptr<ProfinetSlot>& slot_ptr = slot.second;
|
||||
|
||||
auto& subslots = slot_ptr->getSubslotsPtr();
|
||||
/// Итерируемся по всем подслотам
|
||||
for (auto subslot : subslots)
|
||||
{
|
||||
shared_ptr<ProfinetSubslot>& subslot_ptr = subslot.second;
|
||||
|
||||
auto submodule_ptr = subslot_ptr->getSubmodulePtr();
|
||||
|
||||
/// На всякий случай. Вообще если подслоты есть, то и подмодули уже к ним подключены.
|
||||
if (submodule_ptr == nullptr)
|
||||
continue;
|
||||
|
||||
indata_iops = PNET_IOXS_BAD;
|
||||
/**
|
||||
* @brief Если для подмодуля существуют входные данные (данные от устройства к контроллеру) или
|
||||
* циклических данных нет(DAP), то нужно установить статус IOPS.
|
||||
* submodule_ptr->m_data_cfg.data_dir == PNET_DIR_NO_IO - вот это условие нужно для установки статуса для DAP
|
||||
*/
|
||||
if ( submodule_ptr->m_data_cfg.insize > 0 ||
|
||||
submodule_ptr->m_data_cfg.data_dir == PNET_DIR_NO_IO )
|
||||
{
|
||||
/// Для данных DAP статус всегда ОК
|
||||
if (slot_ptr->m_slot_nbr == PNET_SLOT_DAP_IDENT)
|
||||
{
|
||||
/// Для данных DAP статус ОК
|
||||
indata_iops = PNET_IOXS_GOOD;
|
||||
}
|
||||
else if (submodule_ptr->m_data_cfg.insize > 0)
|
||||
{
|
||||
|
||||
}
|
||||
submodule_ptr->inputSetData( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
indata_iops);
|
||||
|
||||
/*
|
||||
* If a submodule is still plugged but not used in current AR,
|
||||
* setting the data and IOPS will fail.
|
||||
* This is not a problem.
|
||||
* Log message below will only be printed for active submodules.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Если данные подмодуля включаются в себя выходные данные(данные от контроллера к устройству)
|
||||
* То нужно установить для них статус IOCS в PNET_IOXS_GOOD.
|
||||
*
|
||||
*/
|
||||
if (submodule_ptr->m_data_cfg.outsize > 0)
|
||||
{
|
||||
int ret = pnet_output_set_iocs ( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
PNET_IOXS_GOOD);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
/// Успешно
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Profinet::PeriodicOperations()
|
||||
{
|
||||
while(!m_periodic_stop.load(std::memory_order_relaxed))
|
||||
{
|
||||
/// Ждем время в мкс: ticks_period_us, по умолчанию 1мс
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(m_run_period_us));
|
||||
|
||||
if (flags_.get_flag(FLAGS_AREP_APP_READY))
|
||||
{
|
||||
pnet_application_ready (m_pnet_data.pnet_ptr, m_pnet_data.arep_for_appl_ready);
|
||||
flags_.clear_flags(FLAGS_AREP_APP_READY);
|
||||
LOG("FLAGS_AREP_APP_READY");
|
||||
}
|
||||
|
||||
/// Вызов cyclic io
|
||||
if (++m_cyclic_io_cnt >= m_cyclic_io_period_ms)
|
||||
{
|
||||
m_cyclic_io_cnt = 0;
|
||||
cyclicIoData();
|
||||
}
|
||||
|
||||
/// запускаем pnet
|
||||
pnet_handle_periodic (m_pnet_data.pnet_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Profinet::cyclicIoData()
|
||||
{
|
||||
for (auto slot : m_slots)
|
||||
{
|
||||
shared_ptr<ProfinetSlot>& slot_ptr = slot.second;
|
||||
|
||||
/// DAP слот игнорируем при циклическом обмене
|
||||
if (slot_ptr->m_slot_nbr == PNET_SLOT_DAP_IDENT)
|
||||
continue;
|
||||
|
||||
auto& subslots = slot_ptr->getSubslotsPtr();
|
||||
/// Итерируемся по всем подслотам
|
||||
for (auto subslot : subslots)
|
||||
{
|
||||
shared_ptr<ProfinetSubslot>& subslot_ptr = subslot.second;
|
||||
|
||||
auto submodule_ptr = subslot_ptr->getSubmodulePtr();
|
||||
|
||||
/// На всякий случай. Вообще если подслоты есть, то и подмодули уже к ним подключены.
|
||||
if (submodule_ptr == nullptr)
|
||||
continue;
|
||||
|
||||
if (submodule_ptr->m_data_cfg.outsize > 0)
|
||||
{
|
||||
bool outdata_updated;
|
||||
uint16_t outdata_length = submodule_ptr->m_data_cfg.outsize;
|
||||
uint8_t outdata_iops;
|
||||
|
||||
/// Копируем данные от контроллера в m_out_data_ptr
|
||||
submodule_ptr->outputGetData( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr);
|
||||
}
|
||||
|
||||
if (submodule_ptr->m_data_cfg.insize > 0)
|
||||
{
|
||||
uint8_t indata_iocs;
|
||||
uint8_t indata_iops = PNET_IOXS_GOOD;
|
||||
|
||||
/**
|
||||
* @brief Отправляем данные подмодуля в ПЛК
|
||||
*
|
||||
*/
|
||||
submodule_ptr->inputSetData(
|
||||
m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
indata_iops
|
||||
);
|
||||
|
||||
(void)pnet_input_get_iocs (
|
||||
m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr,
|
||||
&indata_iocs);
|
||||
|
||||
submodule_ptr->m_indata_iocs = indata_iocs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Profinet::Start()
|
||||
{
|
||||
LOG("Waiting PLC connection...");
|
||||
m_periodic_thread = std::move(std::thread(&Profinet::PeriodicOperations, this));
|
||||
}
|
||||
|
||||
Profinet::~Profinet()
|
||||
{
|
||||
///Остановка потока
|
||||
m_periodic_stop.store(true, std::memory_order_relaxed);
|
||||
|
||||
if (m_periodic_thread.joinable())
|
||||
{
|
||||
m_periodic_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**\
|
||||
* =========================================================================================
|
||||
* Callbacks
|
||||
* =========================================================================================
|
||||
*/
|
||||
int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||
{
|
||||
LOG("callbackStateInd: event = " + std::to_string(event));
|
||||
|
||||
uint16_t err_cls = 0; /* Error code 1 */
|
||||
uint16_t err_code = 0; /* Error code 2 */
|
||||
const char * error_class_description = "";
|
||||
const char * error_code_description = "";
|
||||
|
||||
if (event == PNET_EVENT_ABORT)
|
||||
{
|
||||
LOG("callbackStateInd:PNET_EVENT_ABORT");
|
||||
if (pnet_get_ar_error_codes (m_pnet_data.pnet_ptr, arep, &err_cls, &err_code) == 0)
|
||||
{
|
||||
/**
|
||||
* @brief Коды ошибок в err_cls и err_code
|
||||
* TODO: Нужно передавать в управляющее приложение
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Ошибок нет
|
||||
}
|
||||
|
||||
/* Only abort AR with correct session key */
|
||||
///os_event_set (app->main_events, APP_EVENT_ABORT);
|
||||
}
|
||||
else if (event == PNET_EVENT_PRMEND)
|
||||
{
|
||||
LOG("callbackStateInd:PNET_EVENT_PRMEND");
|
||||
if (isConnectedToController())
|
||||
{
|
||||
/// Если уже были подключены и пришел запрос на еще одно подключение
|
||||
}
|
||||
|
||||
m_pnet_data.arep = arep;
|
||||
|
||||
initDataAndIoxs();
|
||||
|
||||
(void)pnet_set_provider_state (m_pnet_data.pnet_ptr, true);
|
||||
/**
|
||||
* @brief Костыль библиотеки pnet:
|
||||
* По правилам Profinet нужно ответить Application ready.
|
||||
* Однако тут нельзя вызвать pnet_application_ready, т.к. это испортит
|
||||
* внутреннее состояние стэка pnet.
|
||||
* Это нужно делать на следующем "тике".
|
||||
* См. описание pnet_application_ready:
|
||||
* This function must be called after the application has received the pnet_state_ind()
|
||||
* user callback with PNET_EVENT_PRMEND, in order for a connection to be established.
|
||||
*
|
||||
*/
|
||||
/* Send application ready at next tick
|
||||
Do not call pnet_application_ready() here as it will affect
|
||||
the internal stack states */
|
||||
m_pnet_data.arep_for_appl_ready = arep;
|
||||
flags_.set_flag(FLAGS_AREP_APP_READY);
|
||||
|
||||
///os_event_set (app->main_events, APP_EVENT_READY_FOR_DATA); ///
|
||||
}
|
||||
else if (event == PNET_EVENT_DATA)
|
||||
{
|
||||
LOG("callbackStateInd:PNET_EVENT_DATA");
|
||||
/// Стартовал обмен cyclic io
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackConnectInd ( uint32_t arep, pnet_result_t * p_result)
|
||||
{
|
||||
LOG("callbackConnectInd");
|
||||
/**
|
||||
* @brief
|
||||
* Если будет возвращено 0, то соединение будет установлено.
|
||||
* Если будет возвращено значение отличное от 0, то не будет, в этом случае нужно указать p_result.
|
||||
*/
|
||||
|
||||
/// Сообщить приложению об установлении связи с контроллером.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackReleaseInd ( uint32_t arep, pnet_result_t * p_result)
|
||||
{
|
||||
LOG("callbackReleaseInd");
|
||||
/**
|
||||
* @brief
|
||||
* Cоединение будет разорвано при любом возвращаемом значении
|
||||
*/
|
||||
|
||||
/// Сообщить приложению об разрыве связи с контроллером.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackDcontrolInd ( uint32_t arep,
|
||||
pnet_control_command_t control_command,
|
||||
pnet_result_t * p_result)
|
||||
{
|
||||
LOG("callbackDcontrolInd: command= " + to_string(control_command));
|
||||
/**
|
||||
* @brief
|
||||
* Можно оставить пустым
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackCcontrolInd ( uint32_t arep, pnet_result_t * p_result)
|
||||
{
|
||||
LOG("callbackCcontrolInd");
|
||||
/**
|
||||
* @brief
|
||||
* Можно оставить пустым
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::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)
|
||||
{
|
||||
LOG("callbackReadInd");
|
||||
///1. Проверяем, что у подмодуля есть параметр с индексом idx
|
||||
auto param_ptr = getSubmoduleParameter(slot_nbr, subslot_nbr, idx);
|
||||
|
||||
if (param_ptr == nullptr)
|
||||
{
|
||||
p_result->pnio_status.error_code = PNET_ERROR_CODE_READ;
|
||||
p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW;
|
||||
p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_APP_READ_ERROR;
|
||||
p_result->pnio_status.error_code_2 = 0; /* User specific */
|
||||
return -1;
|
||||
}
|
||||
|
||||
///2. Проверяем корректность длины данных (меньше быть не должно, если больше - это норм)
|
||||
if (*p_read_length < param_ptr->length)
|
||||
{
|
||||
p_result->pnio_status.error_code = PNET_ERROR_CODE_READ;
|
||||
p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW;
|
||||
p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_APP_READ_ERROR;
|
||||
p_result->pnio_status.error_code_2 = 0; /* User specific */
|
||||
return -1;
|
||||
}
|
||||
|
||||
///3. Передаем данные параметра
|
||||
/**
|
||||
* По идее тут нужно утановить мьютекс lock, а unlock сделать потом, когда данные будет причитаны стеком pnet
|
||||
* Проблема в том, что нет ни одного события которое бы сообщало об окончании процесса чтения данных стеком pnet.
|
||||
* Нужно поисследовать.
|
||||
*/
|
||||
*pp_read_data = param_ptr->getDataPointer();
|
||||
*p_read_length = param_ptr->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::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)
|
||||
{
|
||||
LOG("callbackWriteInd");
|
||||
///1. Проверяем, что у подмодуля есть параметр с индексом idx
|
||||
auto param_ptr = getSubmoduleParameter(slot_nbr, subslot_nbr, idx);
|
||||
|
||||
if (param_ptr == nullptr)
|
||||
{
|
||||
p_result->pnio_status.error_code = PNET_ERROR_CODE_WRITE;
|
||||
p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW;
|
||||
p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_APP_WRITE_ERROR;
|
||||
p_result->pnio_status.error_code_2 = 0; /* User specific */
|
||||
LOG("callbackWriteInd: No such parameter with index " + std::to_string(idx));
|
||||
return -1;
|
||||
}
|
||||
///2. Проверяем корректность длины данных
|
||||
if (write_length != param_ptr->length)
|
||||
{
|
||||
p_result->pnio_status.error_code = PNET_ERROR_CODE_WRITE;
|
||||
p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW;
|
||||
p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_APP_WRITE_ERROR;
|
||||
p_result->pnio_status.error_code_2 = 0; /* User specific */
|
||||
LOG("callbackWriteInd: Wrong data length " + std::to_string(write_length) + ", will be " + std::to_string(param_ptr->length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
///3. Копируем данные
|
||||
param_ptr->writeParameter(p_write_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackExpModuleInd ( uint16_t slot, uint32_t module_ident)
|
||||
{
|
||||
LOG("callbackExpModuleInd: plug module id=" + std::to_string(module_ident) + " -> slot num=" + std::to_string(slot));
|
||||
|
||||
bool ret = addSlotAndPlugModule(slot, module_ident);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
return -1;
|
||||
LOG("Error!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackExpSubmoduleInd ( uint16_t slot,
|
||||
uint16_t subslot,
|
||||
uint32_t module_id,
|
||||
uint32_t submodule_id,
|
||||
const pnet_data_cfg_t * p_exp_data)
|
||||
{
|
||||
LOG("callbackExpSubmoduleInd: plug submodule " + std::to_string(submodule_id) + " -> subslot " + std::to_string(subslot));
|
||||
|
||||
bool ret = addSubslotAndPlugSubmodule(slot, subslot, module_id, submodule_id, p_exp_data);
|
||||
|
||||
if (ret == false)
|
||||
{
|
||||
LOG("Error!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackNewDataStatusInd ( uint32_t arep,
|
||||
uint32_t crep,
|
||||
uint8_t changes,
|
||||
uint8_t data_status)
|
||||
{
|
||||
LOG("callbackNewDataStatusInd");
|
||||
/// Пока ничего не делаем
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::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)
|
||||
{
|
||||
LOG("callbackAlarmInd");
|
||||
/**
|
||||
* @brief Должен быть ответ pnet_alarm_send_ack
|
||||
* Пока заглушка
|
||||
*
|
||||
*/
|
||||
pnet_pnio_status_t pnio_status = {0, 0, 0, 0};
|
||||
|
||||
pnet_alarm_send_ack (m_pnet_data.pnet_ptr, arep, p_alarm_arg, &pnio_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackAlarmCnf ( uint32_t arep, const pnet_pnio_status_t * p_pnio_status)
|
||||
{
|
||||
LOG("callbackAlarmCnf");
|
||||
/// Пока ничего не делаем
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackAlarmAckCnf ( uint32_t arep, int res)
|
||||
{
|
||||
LOG("callbackAlarmAckCnf");
|
||||
/// Пока ничего не делаем
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackResetInd ( bool should_reset_application, uint16_t reset_mode)
|
||||
{
|
||||
LOG("callbackResetInd");
|
||||
/// Пока ничего не делаем
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackSignalLedInd (bool led_state)
|
||||
{
|
||||
LOG("callbackSignalLedInd");
|
||||
/// Пока ничего не делаем
|
||||
return 0;
|
||||
}
|
||||
427
src/profinet/profinet.hpp
Normal file
427
src/profinet/profinet.hpp
Normal file
@ -0,0 +1,427 @@
|
||||
#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:
|
||||
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();
|
||||
|
||||
~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_;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Проверяет наличие слота slot_nbr в конфигурации
|
||||
*
|
||||
* @param slot_nbr номер слота
|
||||
* @return ProfinetSlot* - указатель на слот, при успехе или nullptr есои слот в конфигурации отсутсвует
|
||||
*/
|
||||
std::shared_ptr<ProfinetSlot> getSlotPtr(uint16_t slot_nbr);
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> getSubslotPtr(uint16_t slot_nbr, uint16_t subslot_nbr);
|
||||
|
||||
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);
|
||||
};
|
||||
13
src/profinet/profinet_cb_alarm_ack_cnf.cpp
Normal file
13
src/profinet/profinet_cb_alarm_ack_cnf.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#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<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackAlarmAckCnf(arep, res);
|
||||
}
|
||||
33
src/profinet/profinet_cb_alarm_ack_cnf.hpp
Normal file
33
src/profinet/profinet_cb_alarm_ack_cnf.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* The controller acknowledges the alarm ACK sent previously.
|
||||
*
|
||||
* This functionality is used for alarms triggered by the IO-controller.
|
||||
*
|
||||
* It is optional to implement this callback.
|
||||
* The return value from this call-back function is ignored by the Profinet
|
||||
* stack.
|
||||
*
|
||||
* Контроллер подтверждает отправленный ранее ACK аварийного сигнала.
|
||||
*
|
||||
* Эта функциональность используется для аварийных сигналов, запускаемых IO-контроллером.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно. Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* @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 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 profinet_cb_alarm_ack_cnf (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
int res);
|
||||
13
src/profinet/profinet_cb_alarm_cnf.cpp
Normal file
13
src/profinet/profinet_cb_alarm_cnf.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "./profinet/profinet_cb_alarm_cnf.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_alarm_cnf (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
const pnet_pnio_status_t * p_pnio_status)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackAlarmCnf(arep, p_pnio_status);
|
||||
}
|
||||
31
src/profinet/profinet_cb_alarm_cnf.hpp
Normal file
31
src/profinet/profinet_cb_alarm_cnf.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* The controller acknowledges the alarm sent previously.
|
||||
* It is now possible to send another alarm.
|
||||
*
|
||||
* This functionality is used for alarms triggered by the IO-device.
|
||||
*
|
||||
* It is optional to implement this callback.
|
||||
* The return value from this call-back function is ignored by the Profinet
|
||||
* stack.
|
||||
*
|
||||
* Контроллер подтверждает отправленный ранее аварийный сигнал. Теперь можно отправить еще один сигнал тревоги.
|
||||
*
|
||||
* Эта функция используется для аварийных сигналов, инициируемых IO-устройством.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно. Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* @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 p_pnio_status In: Detailed ACK information.
|
||||
* @return 0 on success. Other values are ignored.
|
||||
*/
|
||||
int profinet_cb_alarm_cnf (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
const pnet_pnio_status_t * p_pnio_status);
|
||||
16
src/profinet/profinet_cb_alarm_ind.cpp
Normal file
16
src/profinet/profinet_cb_alarm_ind.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "./profinet/profinet_cb_alarm_ind.hpp"
|
||||
#include "./profinet/profinet.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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackAlarmInd(arep, p_alarm_arg, data_len, data_usi, p_data);
|
||||
}
|
||||
38
src/profinet/profinet_cb_alarm_ind.hpp
Normal file
38
src/profinet/profinet_cb_alarm_ind.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* The IO-controller has sent an alarm to the device.
|
||||
*
|
||||
* This functionality is used for alarms triggered by the IO-controller.
|
||||
*
|
||||
* When receiving this indication, the application shall
|
||||
* respond with \a pnet_alarm_send_ack(), which
|
||||
* may be called in the context of this callback.
|
||||
*
|
||||
* IO-контроллер отправил сигнал тревоги на устройство.
|
||||
*
|
||||
* Эта функциональность используется для аварийных сигналов, запускаемых IO-контроллером.
|
||||
* При получении этого указания приложение должно ответить \a pnet_alarm_send_ack(), которое
|
||||
* может быть вызвано в контексте этого обратного вызова.
|
||||
*
|
||||
* @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 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 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);
|
||||
13
src/profinet/profinet_cb_ccontrol_ind.cpp
Normal file
13
src/profinet/profinet_cb_ccontrol_ind.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "./profinet/profinet_cb_ccontrol_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_ccontrol_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackCcontrolInd(arep, p_result);
|
||||
}
|
||||
42
src/profinet/profinet_cb_ccontrol_ind.hpp
Normal file
42
src/profinet/profinet_cb_ccontrol_ind.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
|
||||
/**
|
||||
* Indication to the application that a CControl confirmation was received from
|
||||
* the controller. Typically this means that the controller has received our
|
||||
* "Application ready" message.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on every
|
||||
* CControl confirmation from the Profinet controller.
|
||||
*
|
||||
* The application is not required to take any action.
|
||||
* The return value from this call-back function is ignored by the Profinet
|
||||
* stack. In case of error the application should provide error information in
|
||||
* \a p_result.
|
||||
*
|
||||
* It is optional to implement this callback (assumes success?).
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получено подтверждение CControl. Обычно это означает,
|
||||
* что контроллер получил наше сообщение «Приложение готово».
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом подтверждении CControl от контроллера Profinet.
|
||||
*
|
||||
* Приложение не требует никаких действий. Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* В случае ошибки приложение должно предоставить информацию об ошибке в \a p_result.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (предполагается успех?).
|
||||
*
|
||||
* @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 p_result Out: Detailed error information.
|
||||
* @return 0 on success. Other values are ignored.
|
||||
*/
|
||||
int profinet_cb_ccontrol_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result);
|
||||
12
src/profinet/profinet_cb_connect_ind.cpp
Normal file
12
src/profinet/profinet_cb_connect_ind.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "./profinet/profinet_cb_connect_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_connect_ind( pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackConnectInd(arep, p_result);
|
||||
}
|
||||
39
src/profinet/profinet_cb_connect_ind.hpp
Normal file
39
src/profinet/profinet_cb_connect_ind.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that a Connect request was received from the
|
||||
* controller.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on every
|
||||
* Connect request from the Profinet controller.
|
||||
*
|
||||
* The connection will be opened if this function returns 0 (zero) and the stack
|
||||
* is otherwise able to establish a connection.
|
||||
*
|
||||
* If this function returns something other than 0 (zero) then the Connect
|
||||
* request is refused by the device. In case of error the application should
|
||||
* provide error information in \a p_result.
|
||||
*
|
||||
* It is optional to implement this callback (assumes success if not
|
||||
* implemented).
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получен запрос на подключение.
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе Connect от контроллера Profinet.
|
||||
* Соединение будет открыто, если эта функция вернет 0 (ноль) и стек в противном случае сможет установить соединение.
|
||||
* Если эта функция возвращает значение, отличное от 0 (нуля), то запрос на подключение отклоняется устройством.
|
||||
* В случае ошибки приложение должно предоставить информацию об ошибке в p_result.
|
||||
* Реализовать этот обратный вызов необязательно (предполагается успех, если он не реализован).
|
||||
*
|
||||
* @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 p_result Out: Detailed error information if return != 0.
|
||||
* @return 0 on success.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
int profinet_cb_connect_ind( pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result);
|
||||
14
src/profinet/profinet_cb_dcontrol_ind.cpp
Normal file
14
src/profinet/profinet_cb_dcontrol_ind.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "./profinet/profinet_cb_dcontrol_ind.hpp"
|
||||
#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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackDcontrolInd(arep, control_command, p_result);
|
||||
}
|
||||
46
src/profinet/profinet_cb_dcontrol_ind.hpp
Normal file
46
src/profinet/profinet_cb_dcontrol_ind.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that a DControl request was received from the
|
||||
* controller. Typically this means that the controller is done writing
|
||||
* parameters.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on every
|
||||
* DControl request from the Profinet controller.
|
||||
*
|
||||
* The application is not required to take any action but the function must
|
||||
* return 0 (zero) for proper function of the stack. If this function returns
|
||||
* something other than 0 (zero) then the DControl request is refused by the
|
||||
* device. In case of error the application should provide error information in
|
||||
* \a p_result.
|
||||
*
|
||||
* It is optional to implement this callback (assumes success if not
|
||||
* implemented).
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получен запрос DControl. Обычно это означает, что контроллер закончил запись параметров.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе DControl от контроллера Profinet.
|
||||
*
|
||||
* От приложения не требуется никаких действий, но функция должна возвращать 0 (ноль) для правильной работы стека.
|
||||
* Если эта функция возвращает значение, отличное от 0 (нуля), то запрос DControl отклоняется устройством.
|
||||
* В случае ошибки приложение должно предоставить информацию об ошибке в \a p_result.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (предполагается успех, если он не реализован).
|
||||
*
|
||||
*
|
||||
* @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 profinet_cb_dcontrol_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_control_command_t control_command,
|
||||
pnet_result_t * p_result);
|
||||
14
src/profinet/profinet_cb_exp_module_ind.cpp
Normal file
14
src/profinet/profinet_cb_exp_module_ind.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "./profinet/profinet_cb_exp_module_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_exp_module_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t api,
|
||||
uint16_t slot,
|
||||
uint32_t module_ident)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackExpModuleInd(slot, module_ident);
|
||||
}
|
||||
50
src/profinet/profinet_cb_exp_module_ind.hpp
Normal file
50
src/profinet/profinet_cb_exp_module_ind.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Индикация приложению о том, что модуль запрошен контроллером в определенном слоте.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet, чтобы указать, что
|
||||
* контроллер запросил наличие определенного модуля с идентификационным номером \a module_ident в слоте с номером \a slot.
|
||||
*
|
||||
* Приложение должно отреагировать на это, соответствующим образом сконфигурировав себя (если это возможно) и вызвать
|
||||
* функцию pnet_plug_module() для настройки стека для этого модуля.
|
||||
*
|
||||
* Если установлен неправильный идентификационный номер модуля, стек примет это, но сигнализирует контроллеру, что установлен
|
||||
* заменяющий модуль.
|
||||
*
|
||||
* Эта функция должна возвращать 0 (ноль), если был подключен допустимый модуль.
|
||||
* Или верните -1, если приложение не может обработать этот запрос.
|
||||
*
|
||||
* @param net InOut: The p-net stack instance
|
||||
* @param arg InOut: User-defined data (not used by p-net)
|
||||
* @param api In: The AP identifier.
|
||||
* @param slot In: The slot number.
|
||||
* @param module_ident In: The module ident number.
|
||||
* @return 0 on success.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
int profinet_cb_exp_module_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t api,
|
||||
uint16_t slot,
|
||||
uint32_t module_ident);
|
||||
17
src/profinet/profinet_cb_exp_submodule_ind.cpp
Normal file
17
src/profinet/profinet_cb_exp_submodule_ind.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "./profinet/profinet_cb_exp_submodule_ind.hpp"
|
||||
#include "./profinet/profinet.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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackExpSubmoduleInd(slot, subslot, module_id, submodule_id, p_exp_data);
|
||||
}
|
||||
64
src/profinet/profinet_cb_exp_submodule_ind.hpp
Normal file
64
src/profinet/profinet_cb_exp_submodule_ind.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that a sub-module is requested by the
|
||||
* controller in a specific sub-slot.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* If a module has not been plugged in the slot \a slot then an automatic plug
|
||||
* request is issued internally by the stack.
|
||||
*
|
||||
* The application must react to this by configuring itself accordingly (if
|
||||
* possible) and call function \a pnet_plug_submodule() to configure the stack
|
||||
* with the correct input/output data sizes.
|
||||
*
|
||||
* If the wrong sub-module ident number is plugged then the stack will accept
|
||||
* this, but signal to the controller that a substitute sub-module is fitted.
|
||||
*
|
||||
* This function should return 0 (zero) if a valid sub-module was plugged,
|
||||
* or return -1 if the application cannot handle this request.
|
||||
*
|
||||
* Индикация приложению о том, что субмодуль запрошен контроллером в определенном субслоте.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet, чтобы указать, что контроллер
|
||||
* запросил наличие определенного подмодуля с идентификационным номером \a идентификатор_подмодуля,
|
||||
* в подслоте с номером подслота \a, с идентификационным номером модуля \a module_ident в слоте \a slot.
|
||||
*
|
||||
* Если модуль не был вставлен в слот \a slot, то внутри стека выдается автоматический запрос на вставку.
|
||||
*
|
||||
* Приложение должно отреагировать на это, настроив себя соответствующим образом (если это возможно) и
|
||||
* вызвать функцию \a pnet_plug_submodule() для настройки стека с правильными размерами входных/выходных данных.
|
||||
*
|
||||
* Если установлен неправильный идентификационный номер субмодуля, стек примет это, но сигнализирует контроллеру,
|
||||
* что установлен замещающий субмодуль.
|
||||
*
|
||||
* Эта функция должна возвращать 0 (ноль), если был подключен допустимый подмодуль, или возвращать -1,
|
||||
* если приложение не может обработать этот запрос.
|
||||
*
|
||||
* @param net InOut: The p-net stack instance
|
||||
* @param arg InOut: User-defined data (not used by p-net)
|
||||
* @param api In: The AP identifier.
|
||||
* @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 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);
|
||||
16
src/profinet/profinet_cb_new_data_status_ind.cpp
Normal file
16
src/profinet/profinet_cb_new_data_status_ind.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "./profinet/profinet_cb_new_data_status_ind.hpp"
|
||||
#include "./profinet/profinet.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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackNewDataStatusInd(arep, crep, changes, data_status);
|
||||
}
|
||||
39
src/profinet/profinet_cb_new_data_status_ind.hpp
Normal file
39
src/profinet/profinet_cb_new_data_status_ind.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that the data status received from the
|
||||
* controller has changed.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack to
|
||||
* indicate that the received data status has changed.
|
||||
*
|
||||
* The application is not required by the Profinet stack to take any action. It
|
||||
* may use this information as it wishes. The return value from this call-back
|
||||
* function is ignored by the Profinet stack.
|
||||
*
|
||||
* Индикация приложению, что статус данных, полученных от контроллера, изменился.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet, чтобы указать, что статус полученных данных изменился.
|
||||
*
|
||||
* Стек Profinet не требует от приложения каких-либо действий. Он может использовать эту информацию по своему усмотрению.
|
||||
* Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* @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 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 profinet_cb_new_data_status_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
uint32_t crep,
|
||||
uint8_t changes,
|
||||
uint8_t data_status);
|
||||
27
src/profinet/profinet_cb_read_ind.cpp
Normal file
27
src/profinet/profinet_cb_read_ind.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "./profinet/profinet_cb_read_ind.hpp"
|
||||
#include "./profinet/profinet.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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackReadInd( arep,
|
||||
slot_nbr,
|
||||
subslot_nbr,
|
||||
idx,
|
||||
sequence_number,
|
||||
pp_read_data,
|
||||
p_read_length,
|
||||
p_result);
|
||||
}
|
||||
65
src/profinet/profinet_cb_read_ind.hpp
Normal file
65
src/profinet/profinet_cb_read_ind.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that an IODRead request was received from the
|
||||
* controller.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The application must verify the value of \a idx, and that \a p_read_length is
|
||||
* large enough. Further, the application must provide a
|
||||
* pointer to the binary value in \a pp_read_data and the size, in bytes, of the
|
||||
* binary value in \a p_read_length.
|
||||
*
|
||||
* The Profinet stack does not perform any endianness conversion on the binary
|
||||
* value.
|
||||
*
|
||||
* In case of error the application should provide error information in \a
|
||||
* p_result.
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получен запрос IODRead.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе IODRead от контроллера Profinet,
|
||||
* в котором указывается специфичное для приложения значение \a idx (0x0000 - 0x7fff). Все остальные значения \a idx
|
||||
* обрабатываются внутри стека Profinet.
|
||||
*
|
||||
* Приложение должно проверить значение \a idx и достаточно ли велико значение \a p_read_length.
|
||||
* Кроме того, приложение должно предоставить указатель на двоичное значение в \a pp_read_data и размер в байтах
|
||||
* двоичного значения в \a p_read_length.
|
||||
*
|
||||
* Стек Profinet не выполняет никакого преобразования порядка байтов в двоичном значении.
|
||||
*
|
||||
* В случае ошибки приложение должно предоставить информацию об ошибке в \a p_result.
|
||||
*
|
||||
* @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 api In: The AP identifier.
|
||||
* @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 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);
|
||||
15
src/profinet/profinet_cb_release_ind.cpp
Normal file
15
src/profinet/profinet_cb_release_ind.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "./profinet/profinet_cb_release_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int profinet_cb_release_ind( pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackReleaseInd(arep, p_result);
|
||||
}
|
||||
37
src/profinet/profinet_cb_release_ind.hpp
Normal file
37
src/profinet/profinet_cb_release_ind.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
/**
|
||||
* Indication to the application that a Release request was received from the
|
||||
* controller.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on every
|
||||
* Release request from the Profinet controller.
|
||||
*
|
||||
* The connection will be closed regardless of the return value from this
|
||||
* function. In case of error the application should provide error information
|
||||
* in \a p_result.
|
||||
*
|
||||
* It is optional to implement this callback (assumes success if not
|
||||
* implemented).
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получен запрос Release.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе Release от контроллера Profinet.
|
||||
*
|
||||
* Соединение будет закрыто независимо от возвращаемого значения этой функцией. В случае ошибки приложение должно предоставить
|
||||
* информацию об ошибке в \a p_result.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (предполагается успех, если он не реализован).
|
||||
*
|
||||
* @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 p_result Out: Detailed error information if return != 0.
|
||||
* @return 0 on success.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
int profinet_cb_release_ind( pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_result_t * p_result);
|
||||
13
src/profinet/profinet_cb_reset_ind.cpp
Normal file
13
src/profinet/profinet_cb_reset_ind.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "./profinet/profinet_cb_reset_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_reset_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
bool should_reset_application,
|
||||
uint16_t reset_mode)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackResetInd(should_reset_application, reset_mode);
|
||||
}
|
||||
81
src/profinet/profinet_cb_reset_ind.hpp
Normal file
81
src/profinet/profinet_cb_reset_ind.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that a reset request was received from the
|
||||
* IO-controller.
|
||||
*
|
||||
* The IO-controller can ask for communication parameters or application
|
||||
* data to be reset, or to do a factory reset.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on every
|
||||
* reset request (via the DCP "Set" command) from the Profinet controller.
|
||||
*
|
||||
* The application should reset the application data if
|
||||
* \a should_reset_application is true. For other cases this callback is
|
||||
* triggered for diagnostic reasons.
|
||||
*
|
||||
* The return value from this call-back function is ignored by the Profinet
|
||||
* stack.
|
||||
*
|
||||
* It is optional to implement this callback (if you do not have any application
|
||||
* data that could be reset).
|
||||
*
|
||||
* Reset modes:
|
||||
* * 0: (Power-on reset, not from IO-controller. Will not trigger this.)
|
||||
* * 1: Reset application data
|
||||
* * 2: Reset communication parameters (done by the stack)
|
||||
* * 99: Reset all (factory reset).
|
||||
*
|
||||
* The reset modes 1-9 (out of which 1 and 2 are supported here) are defined
|
||||
* by the Profinet standard. Value 99 is used here to indicate that the
|
||||
* IO-controller has requested a factory reset via another mechanism.
|
||||
*
|
||||
* In order to remain responsive to DCP communication and Ethernet switching,
|
||||
* the device should not do a hard or soft reset for reset mode 1 or 2. It is
|
||||
* allowed for the factory reset case (but not mandatory).
|
||||
*
|
||||
* No \a arep information is available, as this callback typically is triggered
|
||||
* when there is no active connection.
|
||||
*
|
||||
* Индикация приложению о том, что от IO-контроллера получен запрос на сброс.
|
||||
*
|
||||
* Контроллер ввода-вывода может запросить сброс параметров связи или данных приложения или выполнить сброс к заводским настройкам.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе на сброс (через команду «Set» DCP)
|
||||
* от контроллера Profinet.
|
||||
*
|
||||
* Приложение должно сбросить данные приложения, если \a should_reset_application имеет значение true. В других случаях этот
|
||||
* обратный вызов запускается по диагностическим причинам.
|
||||
*
|
||||
* Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (если у вас нет данных приложения, которые можно было бы сбросить).
|
||||
*
|
||||
* Режимы сброса:
|
||||
* 0: (Сброс при включении питания, а не от IO-контроллера. Это не срабатывает.)
|
||||
* 1: Сбросить данные приложения
|
||||
* 2: Сброс параметров связи (выполняется стеком)
|
||||
* 99: Сбросить все (сброс настроек).
|
||||
*
|
||||
* Режимы сброса 1-9 (из которых здесь поддерживаются 1 и 2) определены стандартом Profinet. Здесь используется значение 99,
|
||||
* чтобы указать, что контроллер ввода-вывода запросил сброс к заводским настройкам с помощью другого механизма.
|
||||
*
|
||||
* Чтобы оставаться чувствительным к связи DCP и коммутации Ethernet, устройство не должно выполнять аппаратный
|
||||
* или программный сброс для режима сброса 1 или 2. Это разрешено для случая сброса к заводским настройкам (но не обязательно).
|
||||
*
|
||||
* Информация \a arep недоступна, так как этот обратный вызов обычно запускается при отсутствии активного соединения.
|
||||
*
|
||||
* @param net InOut: The p-net stack instance
|
||||
* @param arg InOut: User-defined data (not used by p-net)
|
||||
* @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 profinet_cb_reset_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
bool should_reset_application,
|
||||
uint16_t reset_mode);
|
||||
9
src/profinet/profinet_cb_signal_led_ind.cpp
Normal file
9
src/profinet/profinet_cb_signal_led_ind.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "./profinet/profinet_cb_signal_led_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_signal_led_ind (pnet_t * net, void * arg, bool led_state)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackSignalLedInd(led_state);
|
||||
}
|
||||
31
src/profinet/profinet_cb_signal_led_ind.hpp
Normal file
31
src/profinet/profinet_cb_signal_led_ind.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that the Profinet signal LED should change
|
||||
* state.
|
||||
*
|
||||
* Use this callback to implement control of the LED.
|
||||
*
|
||||
* It is optional to implement this callback (but a compliant Profinet device
|
||||
* must have a signal LED)
|
||||
*
|
||||
* No \a arep information is available, as this callback typically is triggered
|
||||
* when there is no active connection.
|
||||
*
|
||||
* Индикация приложению о том, что сигнальный светодиод Profinet должен изменить состояние.
|
||||
*
|
||||
* Используйте этот обратный вызов для реализации управления светодиодом.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (но совместимое с Profinet устройство должно иметь сигнальный светодиод).
|
||||
*
|
||||
* Информация \a arep недоступна, так как этот обратный вызов обычно запускается при отсутствии активного соединения.
|
||||
*
|
||||
* @param net InOut: The p-net stack instance
|
||||
* @param arg InOut: User-defined data (not used by p-net)
|
||||
* @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 profinet_cb_signal_led_ind (pnet_t * net, void * arg, bool led_state);
|
||||
13
src/profinet/profinet_cb_state_ind.cpp
Normal file
13
src/profinet/profinet_cb_state_ind.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "./profinet/profinet_cb_state_ind.hpp"
|
||||
#include "./profinet/profinet.hpp"
|
||||
|
||||
int profinet_cb_state_ind (
|
||||
pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_event_values_t event)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackStateInd(arep, event);
|
||||
}
|
||||
43
src/profinet/profinet_cb_state_ind.hpp
Normal file
43
src/profinet/profinet_cb_state_ind.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
/**
|
||||
* Indication to the application that a state transition has occurred within the
|
||||
* Profinet stack.
|
||||
*
|
||||
* This application call-back function is called by the Profinet stack on
|
||||
* specific state transitions within the Profinet stack.
|
||||
*
|
||||
* At the very least the application must react to the PNET_EVENT_PRMEND state
|
||||
* transition. After this event the application must call \a
|
||||
* pnet_application_ready(), when it has finished its setup and it is ready to
|
||||
* exchange data.
|
||||
*
|
||||
* The return value from this call-back function is ignored by the Profinet
|
||||
* stack.
|
||||
*
|
||||
* It is optional to implement this callback (but then it would be difficult
|
||||
* to know when to call the \a pnet_application_ready() function).
|
||||
*
|
||||
* Указание приложению о том, что в стеке Profinet произошел переход состояния.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при определенных переходах состояний в стеке Profinet.
|
||||
*
|
||||
* По крайней мере, приложение должно реагировать на переход состояния PNET_EVENT_PRMEND. После этого события приложение
|
||||
* должно вызвать \a pnet_application_ready(), когда оно закончит настройку и будет готово к обмену данными.
|
||||
*
|
||||
* Возвращаемое значение этой функции обратного вызова игнорируется стеком Profinet.
|
||||
*
|
||||
* Реализовать этот обратный вызов необязательно (но тогда будет трудно понять, когда вызывать функцию \a pnet_application_ready()).
|
||||
*
|
||||
* @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 state In: The state transition event. See
|
||||
* pnet_event_values_t.
|
||||
* @return 0 on success. Other values are ignored.
|
||||
*/
|
||||
int profinet_cb_state_ind( pnet_t * net,
|
||||
void * arg,
|
||||
uint32_t arep,
|
||||
pnet_event_values_t event);
|
||||
27
src/profinet/profinet_cb_write_ind.cpp
Normal file
27
src/profinet/profinet_cb_write_ind.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "./profinet/profinet_cb_write_ind.hpp"
|
||||
#include "./profinet/profinet.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)
|
||||
{
|
||||
Profinet * const profinet_ptr = static_cast<Profinet*>(arg);
|
||||
|
||||
return profinet_ptr->callbackWriteInd( arep,
|
||||
slot_nbr,
|
||||
subslot_nbr,
|
||||
idx,
|
||||
sequence_number,
|
||||
write_length,
|
||||
p_write_data,
|
||||
p_result);
|
||||
}
|
||||
62
src/profinet/profinet_cb_write_ind.hpp
Normal file
62
src/profinet/profinet_cb_write_ind.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
/**
|
||||
* Indication to the application that an IODWrite request was received from the
|
||||
* controller.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The application must verify the values of \a idx and \a write_length and save
|
||||
* (copy) the binary value in \a p_write_data. A future IODRead must return the
|
||||
* latest written value.
|
||||
*
|
||||
* The Profinet stack does not perform any endianness conversion on the binary
|
||||
* value.
|
||||
*
|
||||
* In case of error the application should provide error information in \a
|
||||
* p_result.
|
||||
*
|
||||
* Индикация приложению о том, что от контроллера получен запрос IODWrite.
|
||||
*
|
||||
* Эта функция обратного вызова приложения вызывается стеком Profinet при каждом запросе IODWrite от контроллера Profinet,
|
||||
* в котором указывается специфичное для приложения значение \a idx (0x0000 - 0x7fff). Все остальные значения \a idx
|
||||
* обрабатываются внутри стека Profinet.
|
||||
*
|
||||
* Приложение должно проверить значения \a idx и \a write_length и сохранить (скопировать) двоичное значение в \a p_write_data.
|
||||
* Будущий IODRead должен возвращать самое последнее записанное значение.
|
||||
*
|
||||
* Стек Profinet не выполняет никакого преобразования порядка байтов в двоичном значении.
|
||||
*
|
||||
* В случае ошибки приложение должно предоставить информацию об ошибке в \a p_result.
|
||||
*
|
||||
* @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 api In: The API identifier.
|
||||
* @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 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);
|
||||
7
src/profinet/profinet_definitions_and_abbreviations.txt
Normal file
7
src/profinet/profinet_definitions_and_abbreviations.txt
Normal file
@ -0,0 +1,7 @@
|
||||
AREP - Application Relationship End Point (uint32) - конечная точка отношения приложений (uint32),
|
||||
в значительной степени индекс в массиве AR.
|
||||
|
||||
AR - Application Relation. Отношения приложений. Состоит из нескольких коммуникативных отношений (CR).
|
||||
Обычно это AR IO, который представляет собой соединение с ПЛК, но также может быть AR супервизора.
|
||||
|
||||
DAP - Device Access Point
|
||||
25
src/profinet/profinet_module.cpp
Normal file
25
src/profinet/profinet_module.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "profinet_module.hpp"
|
||||
|
||||
ProfinetModule::ProfinetModule(uint32_t module_id, std::string module_name) :
|
||||
m_id(module_id),
|
||||
m_name(module_name)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
bool ProfinetModule::addSubmodule(std::shared_ptr<ProfinetSubmodule>& submodule_ptr)
|
||||
{
|
||||
auto ret = m_submodules.emplace(submodule_ptr->m_id, submodule_ptr);
|
||||
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetSubmodule> ProfinetModule::getSubmodulePtr(uint32_t submodule_id)
|
||||
{
|
||||
if (!m_submodules.count(submodule_id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_submodules[submodule_id];
|
||||
}
|
||||
30
src/profinet/profinet_module.hpp
Normal file
30
src/profinet/profinet_module.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "profinet_submodule.hpp"
|
||||
|
||||
|
||||
class ProfinetModule {
|
||||
public:
|
||||
static std::shared_ptr<ProfinetModule> Create(uint32_t module_id, std::string module_name) {
|
||||
return std::shared_ptr<ProfinetModule>(new ProfinetModule(module_id, module_name));
|
||||
}
|
||||
|
||||
ProfinetModule(uint32_t module_id, std::string module_name);
|
||||
|
||||
bool addSubmodule(std::shared_ptr<ProfinetSubmodule>& submodule_ptr);
|
||||
|
||||
std::shared_ptr<ProfinetSubmodule> getSubmodulePtr(uint32_t submodule_id);
|
||||
|
||||
public:
|
||||
const uint32_t m_id; /// module id
|
||||
const std::string m_name; /// module name
|
||||
|
||||
private:
|
||||
/// Набор поддерживаемых подмодулей
|
||||
std::map<uint32_t, std::shared_ptr<ProfinetSubmodule>> m_submodules;
|
||||
};
|
||||
50
src/profinet/profinet_parameter.cpp
Normal file
50
src/profinet/profinet_parameter.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "profinet_parameter.hpp"
|
||||
#include <cstring>
|
||||
|
||||
ProfinetParameter::ProfinetParameter(uint32_t Index, std::string Name, uint16_t Length) :
|
||||
index(Index),
|
||||
name(Name),
|
||||
length(Length),
|
||||
data_ptr_(new uint8_t[Length])
|
||||
{
|
||||
};
|
||||
|
||||
bool ProfinetParameter::readParameter(uint8_t * const data_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(data_mutex_); /// Синхронизация чтения и записи
|
||||
|
||||
if (data_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data_ptr, data_ptr_.get(), length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfinetParameter::writeParameter(const uint8_t * data_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(data_mutex_); /// Синхронизация чтения и записи
|
||||
|
||||
if (data_ptr == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data_ptr_.get(), data_ptr, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t * ProfinetParameter::getDataPointer()
|
||||
{
|
||||
/**
|
||||
* @brief Слабое утешение от ситуации когда приложение записывает данные в параметр, а контроллер хочет этот параметр
|
||||
* прочитать и вызвался коллбэк profinet_cb_read. В этом случае будем тут висеть пока приложение не запишет параметр.
|
||||
*
|
||||
*/
|
||||
std::lock_guard<std::mutex> guard(data_mutex_);
|
||||
|
||||
return data_ptr_.get();
|
||||
}
|
||||
55
src/profinet/profinet_parameter.hpp
Normal file
55
src/profinet/profinet_parameter.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class ProfinetParameter
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<ProfinetParameter> Create(uint32_t Index, std::string Name, uint16_t Length)
|
||||
{
|
||||
return std::shared_ptr<ProfinetParameter>(new ProfinetParameter(Index, Name, Length));
|
||||
}
|
||||
|
||||
ProfinetParameter(uint32_t Index, std::string Name, uint16_t Length);
|
||||
|
||||
/**
|
||||
* @brief Защищенная запись данных параметра
|
||||
*
|
||||
* @param data_ptr
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool writeParameter(const uint8_t * data_ptr);
|
||||
|
||||
/**
|
||||
* @brief Защищенное чтение данных параметра
|
||||
*
|
||||
* @param data_ptr
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool readParameter(uint8_t * const data_ptr);
|
||||
|
||||
/**
|
||||
* @brief Стек pnet сам копирует данные параметра внутрь себя.
|
||||
* Для этого ему в колбэке нужно предоставить указатель на данные параметра и длину данных.
|
||||
* Подразумевается, что эта функция будет использоваться только внутри колбэка стека pnet.
|
||||
* см. profinet_cb_read.cpp
|
||||
* Не использовать эту функцию в приложении!!!
|
||||
* @return uint8_t*
|
||||
*/
|
||||
uint8_t * getDataPointer();
|
||||
|
||||
|
||||
const std::string name; /// Имя параметра
|
||||
const uint32_t index; /// Идентфикатор параметра
|
||||
const uint16_t length; /// длина параметра в байтах
|
||||
|
||||
private:
|
||||
std::shared_ptr<uint8_t[]> data_ptr_; /// указатель на данные параметра
|
||||
mutable std::mutex data_mutex_; /// Доступ к данным
|
||||
};
|
||||
10
src/profinet/profinet_serv_data.hpp
Normal file
10
src/profinet/profinet_serv_data.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
struct ProfinetServiceData {
|
||||
pnet_t * pnet_ptr; /// Указатель на pnet
|
||||
uint32_t api; /// Непонятно что это, обязательно посмотреть в коде либы pnet
|
||||
uint32_t arep; /// Аналогично
|
||||
uint32_t arep_for_appl_ready; /// Костыль для pnet (нужно реализовать как в примере)
|
||||
};
|
||||
89
src/profinet/profinet_settings.hpp
Normal file
89
src/profinet/profinet_settings.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
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()
|
||||
uint32_t cyclic_ms = 100; /// Устанавливает период в мс для циклического обмена данными
|
||||
std::string eth_dev_name = ""; /// Имя интерфейса ethernet
|
||||
std::string profinet_device_config = ""; ///Файл конфигурации profinet device
|
||||
};
|
||||
88
src/profinet/profinet_slot.cpp
Normal file
88
src/profinet/profinet_slot.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "profinet_slot.hpp"
|
||||
|
||||
ProfinetSlot::ProfinetSlot ( uint16_t slot_nbr ) :
|
||||
m_slot_nbr(slot_nbr),
|
||||
m_module_ptr(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool ProfinetSlot::pullModule(ProfinetServiceData& pnet_data)
|
||||
{
|
||||
int result = pnet_pull_module (pnet_data.pnet_ptr, pnet_data.api, m_slot_nbr);
|
||||
|
||||
m_module_ptr = nullptr;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
bool ProfinetSlot::plugModule(ProfinetServiceData& pnet_data, std::shared_ptr<ProfinetModule>& module_ptr)
|
||||
{
|
||||
/// Сначала отключаем модуль
|
||||
pullModule(pnet_data);
|
||||
|
||||
/// Затем подключаем модуль
|
||||
int result = pnet_plug_module (pnet_data.pnet_ptr, pnet_data.api, m_slot_nbr, module_ptr->m_id);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
m_module_ptr = module_ptr;
|
||||
}
|
||||
|
||||
return (m_module_ptr != nullptr);
|
||||
}
|
||||
|
||||
bool ProfinetSlot::addSubslot(std::shared_ptr<ProfinetSubslot>& subslot_ptr)
|
||||
{
|
||||
if (subslot_ptr == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_module_ptr == nullptr)
|
||||
return false;
|
||||
|
||||
subslot_ptr->setSlotNumber(m_slot_nbr);
|
||||
subslot_ptr->setModuleId(m_module_ptr->m_id);
|
||||
|
||||
m_subslots[subslot_ptr->m_subslot_nbr] = subslot_ptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> ProfinetSlot::addSubslot(uint16_t subslot_nbr)
|
||||
{
|
||||
std::shared_ptr<ProfinetSubslot> subslot_ptr(nullptr);
|
||||
|
||||
if (m_subslots.count(subslot_nbr))
|
||||
{
|
||||
subslot_ptr = m_subslots[subslot_nbr];
|
||||
}
|
||||
else
|
||||
{
|
||||
subslot_ptr = std::make_shared<ProfinetSubslot>(subslot_nbr, m_slot_nbr, m_module_ptr->m_id);
|
||||
}
|
||||
|
||||
if (subslot_ptr != nullptr)
|
||||
{
|
||||
m_subslots[subslot_nbr] = subslot_ptr;
|
||||
}
|
||||
|
||||
return subslot_ptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> ProfinetSlot::getSubslotPtr(uint16_t subslot_nbr)
|
||||
{
|
||||
/// Проверка наличия подслота в конфигурации
|
||||
if (!m_subslots.count(subslot_nbr))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_subslots[subslot_nbr];
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetModule> ProfinetSlot::getModulePtr()
|
||||
{
|
||||
return m_module_ptr;
|
||||
}
|
||||
|
||||
70
src/profinet/profinet_slot.hpp
Normal file
70
src/profinet/profinet_slot.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "profinet_serv_data.hpp"
|
||||
#include "profinet_subslot.hpp"
|
||||
#include "profinet_module.hpp"
|
||||
|
||||
class ProfinetSlot
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Profinet Slot object
|
||||
*
|
||||
* @param slot_nbr номер слота
|
||||
*/
|
||||
ProfinetSlot(uint16_t slot_nbr);
|
||||
/**
|
||||
* @brief Подключает модуль к слоту
|
||||
*
|
||||
* @param pnet_data Данные pnet
|
||||
* @return true модуль подключен
|
||||
* @return false модуль не подключен
|
||||
*/
|
||||
bool plugModule(ProfinetServiceData& pnet_data, std::shared_ptr<ProfinetModule>& module_ptr);
|
||||
/**
|
||||
* @brief Отключает модуль от слота
|
||||
*
|
||||
* @param pnet_data Данные pnet
|
||||
* @return true модуль был поключен и теперь отключен
|
||||
* @return false модуль не был подключен
|
||||
*/
|
||||
bool pullModule(ProfinetServiceData& pnet_data);
|
||||
|
||||
/**
|
||||
* @brief Добавляет ранее созданный подслот subslot_ptr
|
||||
*
|
||||
* @param subslot_ptr подслот
|
||||
* @return true подслот добавлен
|
||||
* @return false подслот был добавлен ранее
|
||||
*/
|
||||
bool addSubslot(std::shared_ptr<ProfinetSubslot>& subslot_ptr);
|
||||
|
||||
/**
|
||||
* @brief Если подслот с номером subslot_nbr еще не добавлен, то создает подслот и добавляет его
|
||||
*
|
||||
* @param subslot_nbr номер подслота
|
||||
* @return std::shared_ptr<ProfinetSubslot> указатель на подслот
|
||||
*/
|
||||
std::shared_ptr<ProfinetSubslot> addSubslot(uint16_t subslot_nbr);
|
||||
|
||||
std::shared_ptr<ProfinetSubslot> getSubslotPtr(uint16_t subslot_nbr);
|
||||
|
||||
std::shared_ptr<ProfinetModule> getModulePtr();
|
||||
|
||||
std::map<uint16_t, std::shared_ptr<ProfinetSubslot>>& getSubslotsPtr() { return m_subslots; };
|
||||
|
||||
public:
|
||||
/// Номер слота
|
||||
const uint16_t m_slot_nbr;
|
||||
|
||||
private:
|
||||
/// Модуль вставленный в этот слот
|
||||
std::shared_ptr<ProfinetModule> m_module_ptr;
|
||||
|
||||
/// множество подслотов
|
||||
std::map<uint16_t, std::shared_ptr<ProfinetSubslot>> m_subslots;
|
||||
};
|
||||
136
src/profinet/profinet_submodule.cpp
Normal file
136
src/profinet/profinet_submodule.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "profinet_submodule.hpp"
|
||||
#include <cstring>
|
||||
|
||||
ProfinetSubmodule::ProfinetSubmodule(uint32_t submodule_id,
|
||||
std::string submodule_name,
|
||||
pnet_data_cfg_t& submodule_data_cfg) :
|
||||
m_id(submodule_id),
|
||||
m_name(submodule_name),
|
||||
m_data_cfg(submodule_data_cfg),
|
||||
inp_data_ptr_(nullptr),
|
||||
out_data_ptr_(nullptr),
|
||||
m_indata_iocs(0),
|
||||
m_outdata_iops(0)
|
||||
{
|
||||
/// Могут быть подмодули без данных, например DAP
|
||||
if (m_data_cfg.insize > 0)
|
||||
{
|
||||
inp_data_ptr_ = std::shared_ptr<uint8_t[]>(new uint8_t[m_data_cfg.insize]);
|
||||
}
|
||||
|
||||
if (m_data_cfg.outsize > 0)
|
||||
{
|
||||
out_data_ptr_ = std::shared_ptr<uint8_t[]>(new uint8_t[m_data_cfg.outsize]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::addParameter(std::shared_ptr<ProfinetParameter>& param)
|
||||
{
|
||||
auto ret = m_params.emplace(param->index, param);
|
||||
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
std::shared_ptr<ProfinetParameter> ProfinetSubmodule::getParameterPtr(uint32_t index)
|
||||
{
|
||||
if (!m_params.count(index))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_params[index];
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::inputSetData( pnet_t * pnet_ptr,
|
||||
uint32_t api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint8_t iops)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(inp_data_mutex_);
|
||||
|
||||
if ((pnet_ptr == nullptr) || (inp_data_ptr_ == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// Копируем данные для передачи в ПЛК
|
||||
pnet_input_set_data_and_iops( pnet_ptr,
|
||||
api,
|
||||
slot_nbr,
|
||||
subslot_nbr,
|
||||
inp_data_ptr_.get(),
|
||||
m_data_cfg.insize,
|
||||
iops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
|
||||
uint32_t api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr )
|
||||
{
|
||||
/// Существуют подмодули без данных, например DAP
|
||||
if ((pnet_ptr == nullptr) || (out_data_ptr_ == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(out_data_mutex_);
|
||||
|
||||
uint16_t outdata_length = m_data_cfg.outsize;
|
||||
uint8_t outdata_iops;
|
||||
bool updated;
|
||||
|
||||
/// Копируем данные от полученные от контроллера
|
||||
pnet_output_get_data_and_iops (pnet_ptr,
|
||||
api,
|
||||
slot_nbr,
|
||||
subslot_nbr,
|
||||
&updated,
|
||||
out_data_ptr_.get(),
|
||||
&outdata_length,
|
||||
&outdata_iops);
|
||||
|
||||
m_outdata_iops = outdata_iops;
|
||||
data_updated_ = updated;
|
||||
|
||||
if (m_data_cfg.outsize != outdata_length)
|
||||
{
|
||||
/// Неправильная длина данных
|
||||
}
|
||||
else if (outdata_iops == PNET_IOXS_BAD)
|
||||
{
|
||||
/// Что-то не так с данными от контроллера
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::getDataFromPlc(uint8_t * data_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(out_data_mutex_);
|
||||
|
||||
if ((data_ptr == nullptr) || (out_data_ptr_ == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data_ptr, out_data_ptr_.get(), m_data_cfg.outsize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::putDataToPlc(uint8_t * data_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(inp_data_mutex_);
|
||||
|
||||
if ((data_ptr == nullptr) || (inp_data_ptr_ == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(inp_data_ptr_.get(), data_ptr, m_data_cfg.insize);
|
||||
|
||||
return true;
|
||||
}
|
||||
73
src/profinet/profinet_submodule.hpp
Normal file
73
src/profinet/profinet_submodule.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "profinet_parameter.hpp"
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
|
||||
class ProfinetSubmodule {
|
||||
public:
|
||||
static std::shared_ptr<ProfinetSubmodule> Create(uint32_t submodule_id,
|
||||
std::string submodule_name,
|
||||
pnet_data_cfg_t& submodule_data_cfg)
|
||||
{
|
||||
return std::shared_ptr<ProfinetSubmodule>(new ProfinetSubmodule(submodule_id,
|
||||
submodule_name,
|
||||
submodule_data_cfg));
|
||||
}
|
||||
|
||||
ProfinetSubmodule(uint32_t submodule_id,
|
||||
std::string submodule_name,
|
||||
pnet_data_cfg_t& submodule_data_cfg);
|
||||
|
||||
bool addParameter(std::shared_ptr<ProfinetParameter>& param);
|
||||
|
||||
std::shared_ptr<ProfinetParameter> getParameterPtr(uint32_t index);
|
||||
|
||||
bool inputSetData( pnet_t * pnet_ptr,
|
||||
uint32_t api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint8_t iops);
|
||||
|
||||
bool outputGetData(pnet_t * pnet_ptr,
|
||||
uint32_t api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr);
|
||||
|
||||
bool getDataFromPlc(uint8_t * data_ptr);
|
||||
|
||||
bool putDataToPlc (uint8_t * data_ptr);
|
||||
|
||||
bool isDataUpdated() { return data_updated_; };
|
||||
|
||||
public:
|
||||
const uint32_t m_id; /// Идентификатор подмодуля
|
||||
const std::string m_name; /// Имя подмодуля
|
||||
const pnet_data_cfg_t m_data_cfg; /// Конфигурация циклических данных подмодуля
|
||||
|
||||
/// iocs = I/O consumer status data (формат данных из pnet_ioxs_values_t)
|
||||
uint8_t m_indata_iocs;
|
||||
|
||||
/// iops = I/O provider status data (формат данных из pnet_ioxs_values_t)
|
||||
uint8_t m_outdata_iops;
|
||||
|
||||
|
||||
private:
|
||||
/// Набор параметров подмодуля
|
||||
std::map<uint32_t, std::shared_ptr<ProfinetParameter>> m_params;
|
||||
|
||||
std::shared_ptr<uint8_t[]> inp_data_ptr_; /// Входные циклические данные (DEV->PLC)
|
||||
std::mutex inp_data_mutex_;
|
||||
|
||||
std::shared_ptr<uint8_t[]> out_data_ptr_; /// Выходные циклические данные (PLC->DEV)
|
||||
std::mutex out_data_mutex_;
|
||||
|
||||
bool data_updated_;
|
||||
};
|
||||
45
src/profinet/profinet_subslot.cpp
Normal file
45
src/profinet/profinet_subslot.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "profinet_subslot.hpp"
|
||||
|
||||
ProfinetSubslot::ProfinetSubslot(uint16_t subslot_nbr, uint16_t slot_nbr, uint32_t module_id) :
|
||||
m_subslot_nbr(subslot_nbr),
|
||||
m_slot_nbr(slot_nbr),
|
||||
m_module_id(module_id),
|
||||
m_submodule_ptr(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_ptr = nullptr;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
bool ProfinetSubslot::plugSubmodule(ProfinetServiceData& pnet_data, std::shared_ptr<ProfinetSubmodule>& submodule_ptr)
|
||||
{
|
||||
/// Сначала отключаем подмодуль
|
||||
pullSubmodule(pnet_data);
|
||||
|
||||
/// Подключаем подмодуль
|
||||
int result = pnet_plug_submodule (
|
||||
pnet_data.pnet_ptr,
|
||||
pnet_data.api,
|
||||
m_slot_nbr,
|
||||
m_subslot_nbr,
|
||||
m_module_id,
|
||||
submodule_ptr->m_id,
|
||||
submodule_ptr->m_data_cfg.data_dir,
|
||||
submodule_ptr->m_data_cfg.insize,
|
||||
submodule_ptr->m_data_cfg.outsize);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
m_submodule_ptr = submodule_ptr;
|
||||
}
|
||||
|
||||
return (m_submodule_ptr != nullptr);
|
||||
}
|
||||
42
src/profinet/profinet_subslot.hpp
Normal file
42
src/profinet/profinet_subslot.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "../../libs/include/pnet_api.h"
|
||||
|
||||
#include "profinet_serv_data.hpp"
|
||||
#include "profinet_submodule.hpp"
|
||||
|
||||
class ProfinetSubslot
|
||||
{
|
||||
public:
|
||||
//ProfinetSubslot(uint16_t subslot_nbr) : m_subslot_nbr(subslot_nbr) {};
|
||||
|
||||
ProfinetSubslot(uint16_t subslot_nbr, uint16_t slot_nbr, uint32_t module_id);
|
||||
|
||||
bool plugSubmodule(ProfinetServiceData& pnet_data, std::shared_ptr<ProfinetSubmodule>& submodule_ptr);
|
||||
|
||||
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; };
|
||||
|
||||
std::shared_ptr<ProfinetSubmodule> getSubmodulePtr() { return m_submodule_ptr; };
|
||||
|
||||
public:
|
||||
/// Номер подслота
|
||||
const uint16_t m_subslot_nbr;
|
||||
|
||||
private:
|
||||
/// Номер слота куда входит данный подслот
|
||||
uint16_t m_slot_nbr;
|
||||
|
||||
/// Идентификатор модуля куда входит подключаемый подмодуль
|
||||
uint32_t m_module_id;
|
||||
|
||||
/// Подмодуль вставленный в этот подслот
|
||||
std::shared_ptr<ProfinetSubmodule> m_submodule_ptr;
|
||||
};
|
||||
74
src/profinet_device_configure.json
Normal file
74
src/profinet_device_configure.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"ProfinetDeviceSettings":
|
||||
{
|
||||
"product_name": "P-Net Sample Application",
|
||||
"station_name": "rt-labs-dev",
|
||||
"im_0":
|
||||
{
|
||||
"vendor_id": "0x0493",
|
||||
"hw_revision": 3,
|
||||
"sw_revision":
|
||||
{
|
||||
"prefix": "V",
|
||||
"functional_enhancement": 0,
|
||||
"bug_fix": 2,
|
||||
"internal_change": 0
|
||||
},
|
||||
"revision_counter": 0,
|
||||
"profile_id": "0x1234",
|
||||
"profile_specific_type": "0x5678",
|
||||
"supported": "0x000E",
|
||||
"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",
|
||||
"send_hello": true,
|
||||
"min_device_interval": 32
|
||||
},
|
||||
"ProfinetDeviceModulesSettings":
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"id": "0x00000040",
|
||||
"name": "Echo module",
|
||||
"submodules": [
|
||||
{
|
||||
"id": "0x00000140",
|
||||
"name": "Echo submodule",
|
||||
"cyc_data_dir": "PNET_DIR_IO",
|
||||
"cyc_inp_data_size": 8,
|
||||
"cyc_out_data_size": 8,
|
||||
"parameters": [
|
||||
{
|
||||
"index": 125,
|
||||
"name": "Echo gain setting",
|
||||
"data_size": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
9
src/program_configure.json
Normal file
9
src/program_configure.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ProfinetSettings":
|
||||
{
|
||||
"ticks_us": 1000,
|
||||
"cyclic_ms": 100,
|
||||
"eth_dev_name": "enp6s1",
|
||||
"profinet_device_config": "profinet_device_configure.json"
|
||||
}
|
||||
}
|
||||
153
src/utils/utils.c
Normal file
153
src/utils/utils.c
Normal file
@ -0,0 +1,153 @@
|
||||
#include "utils.h"
|
||||
#include "string.h"
|
||||
#include "pnal.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 = 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;
|
||||
}
|
||||
3
src/utils/utils.cmake
Normal file
3
src/utils/utils.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
set(SRC_FILES ${SRC_FILES} ./utils/utils.c)
|
||||
set(INC_DIRS ${INC_DIRS} ./utils)
|
||||
46
src/utils/utils.h
Normal file
46
src/utils/utils.h
Normal file
@ -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
|
||||
Loading…
Reference in New Issue
Block a user