dev(UML-981): Решение некоторых проблем и документирование кода
1. Выделение разделяемой памяти учитывает количество требуемой памяти 2. Выложил собранные библиотеки pnet и osal 3. Добавил общее описание в readme.md
This commit is contained in:
parent
b992c1c3a6
commit
3c9774a173
177
README.md
177
README.md
@ -1,3 +1,178 @@
|
||||
# profinet_io_dev
|
||||
|
||||
Драйвер profinet io device.
|
||||
Драйвер profinet io device. Предназначен для работы в фоне и взаимодействием с Profinet контроллером с использованием ethernet.
|
||||
|
||||
Реализует следующий функционал:
|
||||
|
||||
1. Читает из json файла структуру данных Profinet,
|
||||
2. Конфигурирует и запускает циклический обмен по Profinet,
|
||||
3. Принимает циклические данные от контроллера Profinet и записывает их в разделяемую память.
|
||||
4. Берет циклические данные из разделяемой памяти и передает их контроллеру Profinet
|
||||
|
||||
Использует следующие библиотеки:
|
||||
1. pnet
|
||||
2. boost (1.74)
|
||||
|
||||
## Структура проекта:
|
||||
* ***debug_support*** - содержит скрипт для запуска отладки с правами суперпользователя и обновления gdb (нужно для Ubuntu 22.04, там есть баг с gdb - он падает при переключении на другой поток в отлажеваемом ПО),
|
||||
* ***libs*** - собранные библиотеки ***pnet*** и используемая ей ***osal***,
|
||||
* ***profinet_stack*** - исходники библиотеки pnet,
|
||||
* ***profinet_test*** - тестовые проекты. Наиболее интересен проект в папке ***sample_app_echo*** реализует функционал тестового модуля ECHO через взаимодействие с profinet_io_dev и подключение к разделяемой памяти.
|
||||
* ***src*** - исходный код приложения profinet_io_dev.
|
||||
|
||||
## Общее описание данных Profinet
|
||||
Терминалогия принятая в Profinet:
|
||||
* Выходные данные - данные от контроллера к устройству,
|
||||
* Входные данные - данные от устройства к контроллеру.
|
||||
|
||||
Профинет предоставляет абстракцию типичной системы управления на базе ПЛК, который имеет универсальные слоты в которые подключаются специализированные модули, например CAN, RS-422, аналоговых входов и т.д. В терминах Profinet все тоже самое: есть контроллер у которого есть слоты в которые он при установлении связи подключает модули устройства.
|
||||
|
||||
На стороне контроллера имеется один или несколько слотов(slots), каждый из которых имеет один или несколько подслотов(subslots).
|
||||
|
||||
На стороне устройства имеется один или несколько модулей(modules), каждый из которых имеет один или несколько подмодулей(submodules).
|
||||
|
||||
К каждому слоту на стороне контроллера может быть поключен модуль со стороны устройства.
|
||||
|
||||
К каждому подслоту на стороне контроллера может быть подключен подмодуль со стороны устройства.
|
||||
|
||||
Каждый подмодуль может включать:
|
||||
* Выходные циклические данные (от контроллера к устройству)
|
||||
* Входные циклические данные (от устройства к контроллеру)
|
||||
* один или больше параметров.
|
||||
|
||||
Могут быть подмодули не содержащие данных вообще.
|
||||
|
||||
Параметры подмодуля отличаются от циклических данных тем, что записываются контроллером при установлении соединения, перед началом циклического обмена и больше не меняются. Их может изменить только пользователь, предварительно разорвав связь (по крайней мере в CodeSys так).
|
||||
|
||||
Параметры могут использоваться устройством для расчета входных данных для контроллера.
|
||||
|
||||
Описание конфигурации данных Profinet определяется специальным ***gsdml*** файлом, который на самом деле является ***xml*** файлом содержимое которого описано в спецификации Profinet. Этот файл нужен для всяких СКАДА систем при конфигурировании контроллера Profinet, загружаешь в СКАДА этот файл и в нем появляются Profinet устройство описанное в этом файле, а так-же все его модули, подмодули и параметры.
|
||||
|
||||
Идентификация модулей и подмодулей осуществляется с помощью 32-х битного идентификатора.
|
||||
Идентификация параметра осуществляется с помощью 32-х битного индекса.
|
||||
|
||||
Установление связи выглядит следующим образом:
|
||||
1. Мастер запрашивает соединение,
|
||||
2. Дает команду устройству: модуль с идентификатором A подключить к слоту с номером B.
|
||||
3. Дает команду устройству: подмодуль с идентификатором A входящий в состав модуля с идентификатором B подключить к подслоту с номером C слота с номером D.
|
||||
4. Записывает параметры подключенного подмодуля.
|
||||
5. Начинается обмен циклическими данными.
|
||||
|
||||
**Все данные в Profinet пишутся в порядке big endian.**
|
||||
|
||||
|
||||
## Циклический обмен
|
||||
|
||||
Циклический обмен инициируется устройством, т.е. устройство должно с каким-либо периодом отправлять данные контроллеру.
|
||||
|
||||
## Файл конфигурации *program_configure.json*
|
||||
|
||||
Описывает общие настройки ПО.
|
||||
|
||||
***ProfinetSettings:***
|
||||
* *ticks_us* - период таймера в мкс который вызывает pnet и реализует логику обмена.
|
||||
* *cyclic_ms* - период обмена циклическими данными.
|
||||
* *eth_dev_name* - наименование устройства ethernet в Linux через которое будет идти обмен по Profinet.
|
||||
* *profinet_device_config* - путь к json файлу конфигурации устройства, который описывает структуру модулей и подмодулей.
|
||||
|
||||
## Файл конфигурации устройства Profinet
|
||||
|
||||
Описывает структуру модулей и подмодулей. В качетсве примера можно рассмотреть описание тестового модуля ECHO: profinet_device_configure.json.
|
||||
|
||||
***ProfinetDeviceSettings***
|
||||
|
||||
Содержить часть параметров структуры ***pnet_cfg*** из ***pnet_api.h***. Это стандартные параметры Profinet которые указаны и описаны в спецификации. Например имя станции или имя устройства.
|
||||
|
||||
***ProfinetDeviceModulesSettings***
|
||||
|
||||
Описание структуры данных устройства.
|
||||
* ***modules***
|
||||
* *id* - идентификатор модуля в шеснадцатиричном или десятичном виде. Шеснадцатиричный вид обозначется как в С через 0х.
|
||||
* *name* - имя модуля, в обмене не используется, нужно для удобства.
|
||||
* ***submodules*** - описание подмодулей:
|
||||
* *id* - идентификатор подмодуля,
|
||||
* *name* - имя подмодуля. В обмене не используется, нужно для удобства.
|
||||
* *cyc_data_dir* - направление циклических данных. Может принимать значения:
|
||||
* PNET_DIR_NO_IO - нет циклических данных,
|
||||
* PNET_DIR_IO - входные и выходные циклические данные,
|
||||
* PNET_DIR_INPUT - только входные циклические данные,
|
||||
* PNET_DIR_OUTPUT - только выходные циклические данные.
|
||||
* *cyc_inp_data_size* - размер входных циклических данных в байтах,
|
||||
* *cyc_out_data_size* - размер выходных циклических данных в байтах,
|
||||
* ***parameters*** - описание параметров:
|
||||
* *index* - индекс параметра,
|
||||
* *name* - наименование параметра. В обмене не используется, нужно для удобства.
|
||||
* *data_size* - размер данных параметра в байтах.
|
||||
|
||||
## Межпроцессное взаимодействие
|
||||
|
||||
При запуске ПО выделяет блок разделяемой памяти с наименованием ***"profinet_shared_data"***.
|
||||
|
||||
Структура описана в ***profinet_data_map.hpp***.
|
||||
|
||||
API для работы с памятью приведено в файле: ***profinet_shared_data_client.hpp***
|
||||
|
||||
### Пример подключения к памяти:
|
||||
|
||||
```C++
|
||||
ProfinetSharedDataClient shared_data;
|
||||
|
||||
ProfinetData_Map * p_profinet_data = shared_data.Connect("profinet_shared_data");
|
||||
|
||||
/// Берем указатель на данные подмодуля в разделяемой памяти
|
||||
auto echo_submod_ptr = shared_data.getSubmodule(ECHO_MODULE_ID, ECHO_SUBMOD_ID);
|
||||
|
||||
/// Берем указатель на данные параметра подмодуля в разделяемолй памяти
|
||||
auto echo_param_gain_ptr = shared_data.getSubmoduleParameter(ECHO_MODULE_ID, ECHO_SUBMOD_ID, ECHO_PARAMETER_GAIN_IDX);
|
||||
|
||||
```
|
||||
### Пример ожидания наступления события
|
||||
В структуре `ProfinetData_Map` есть разделяемые флаги `Events` типа `SharedFlags` которые могут быть использованы для ожидания следующих событий:
|
||||
* `EVENT_CONNECTION_ESTABLISHED` - соединение установлено
|
||||
* `EVENT_NEW_CYCLIC_DATA` - получены новые циклические данные. Не указывает на то, что данные изменились, просто по профинету была получена новая порция цикличесиких данных от контроллера.
|
||||
* `EVENT_NEW_PARAM_DATA` - контроллером была осуществлена запись данных параметров какого-либо подмодуля.
|
||||
* `EVENT_CONNECTION_ABORT` - соединение с контроллером разорвано.
|
||||
|
||||
Пример ожидания установления соединения или приема новых циклических данных:
|
||||
```C++
|
||||
uint32_t events = p_profinet_data->Events.wait_flags(EVENT_CONNECTION_ESTABLISHED | EVENT_NEW_CYCLIC_DATA);
|
||||
|
||||
```
|
||||
`wait_flags` - блокирует поток до момента установления флага.
|
||||
|
||||
Когда флаг установлен, его нужно сбросить:
|
||||
```C++
|
||||
p_profinet_data->Events.clear_flags(EVENT_NEW_CYCLIC_DATA);
|
||||
```
|
||||
|
||||
### Пример чтения данных параметров подмодуля
|
||||
|
||||
```C++
|
||||
uint32_t Echo_Gain = 0;
|
||||
echo_param_gain_ptr->data.Read(0, (uint8_t*)&Echo_Gain, echo_param_gain_ptr->length);
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_Gain);
|
||||
```
|
||||
|
||||
### Пример чтения и записи циклических данных подмодуля
|
||||
```C++
|
||||
///Читаем данные от ПЛК
|
||||
echo_submod_ptr->out_data.Read(0, Echo_outCycData.mem, echo_submod_ptr->cyc_outdata_len);
|
||||
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_f);
|
||||
|
||||
///Подготавливаем данные для ПЛК
|
||||
Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i;
|
||||
Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f;
|
||||
///Конвертируем в биг эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
///Отправляем данные для ПЛК
|
||||
echo_submod_ptr->inp_data.Write(0, Echo_inpCycData.mem, echo_submod_ptr->cyc_indata_len);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
sudo /usr/bin/gdb "$@"
|
||||
sudo /usr/local/bin/gdb "$@"
|
||||
|
131
libs/include/osal.h
Normal file
131
libs/include/osal.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2017 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is licensed under the terms of the BSD 3-clause
|
||||
* license. See the file LICENSE distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef OSAL_H
|
||||
#define OSAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sys/osal_sys.h"
|
||||
#include "sys/osal_cc.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(n) (1U << (n))
|
||||
#endif
|
||||
|
||||
#ifndef NELEMENTS
|
||||
#define NELEMENTS(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef OS_WAIT_FOREVER
|
||||
#define OS_WAIT_FOREVER 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
#ifndef OS_MAIN
|
||||
#define OS_MAIN int main
|
||||
#endif
|
||||
|
||||
#ifndef OS_MUTEX
|
||||
typedef void os_mutex_t;
|
||||
#endif
|
||||
|
||||
#ifndef OS_SEM
|
||||
typedef void os_sem_t;
|
||||
#endif
|
||||
|
||||
#ifndef OS_THREAD
|
||||
typedef void os_thread_t;
|
||||
#endif
|
||||
|
||||
#ifndef OS_EVENT
|
||||
typedef void os_event_t;
|
||||
#endif
|
||||
|
||||
#ifndef OS_MBOX
|
||||
typedef void os_mbox_t;
|
||||
#endif
|
||||
|
||||
#ifndef OS_TIMER
|
||||
typedef void os_timer_t;
|
||||
#endif
|
||||
|
||||
void * os_malloc (size_t size);
|
||||
void os_free (void * ptr);
|
||||
|
||||
void os_usleep (uint32_t us);
|
||||
uint32_t os_get_current_time_us (void);
|
||||
|
||||
os_thread_t * os_thread_create (
|
||||
const char * name,
|
||||
uint32_t priority,
|
||||
size_t stacksize,
|
||||
void (*entry) (void * arg),
|
||||
void * arg);
|
||||
|
||||
os_mutex_t * os_mutex_create (void);
|
||||
void os_mutex_lock (os_mutex_t * mutex);
|
||||
void os_mutex_unlock (os_mutex_t * mutex);
|
||||
void os_mutex_destroy (os_mutex_t * mutex);
|
||||
|
||||
os_sem_t * os_sem_create (size_t count);
|
||||
bool os_sem_wait (os_sem_t * sem, uint32_t time);
|
||||
void os_sem_signal (os_sem_t * sem);
|
||||
void os_sem_destroy (os_sem_t * sem);
|
||||
|
||||
os_event_t * os_event_create (void);
|
||||
bool os_event_wait (
|
||||
os_event_t * event,
|
||||
uint32_t mask,
|
||||
uint32_t * value,
|
||||
uint32_t time);
|
||||
void os_event_set (os_event_t * event, uint32_t value);
|
||||
void os_event_clr (os_event_t * event, uint32_t value);
|
||||
void os_event_destroy (os_event_t * event);
|
||||
|
||||
os_mbox_t * os_mbox_create (size_t size);
|
||||
bool os_mbox_fetch (os_mbox_t * mbox, void ** msg, uint32_t time);
|
||||
bool os_mbox_post (os_mbox_t * mbox, void * msg, uint32_t time);
|
||||
void os_mbox_destroy (os_mbox_t * mbox);
|
||||
|
||||
os_timer_t * os_timer_create (
|
||||
uint32_t us,
|
||||
void (*fn) (os_timer_t * timer, void * arg),
|
||||
void * arg,
|
||||
bool oneshot);
|
||||
void os_timer_set (os_timer_t * timer, uint32_t us);
|
||||
void os_timer_start (os_timer_t * timer);
|
||||
void os_timer_stop (os_timer_t * timer);
|
||||
void os_timer_destroy (os_timer_t * timer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OSAL_H */
|
78
libs/include/osal_log.h
Normal file
78
libs/include/osal_log.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2017 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is licensed under the terms of the BSD 3-clause
|
||||
* license. See the file LICENSE distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef OSAL_LOG_H
|
||||
#define OSAL_LOG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "osal.h"
|
||||
|
||||
/* Log levels */
|
||||
#define LOG_LEVEL_DEBUG 0x00
|
||||
#define LOG_LEVEL_INFO 0x01
|
||||
#define LOG_LEVEL_WARNING 0x02
|
||||
#define LOG_LEVEL_ERROR 0x03
|
||||
#define LOG_LEVEL_FATAL 0x04
|
||||
#define LOG_LEVEL_MASK 0x07
|
||||
#define LOG_LEVEL_GET(t) (t & LOG_LEVEL_MASK)
|
||||
|
||||
/* Log states */
|
||||
#define LOG_STATE_ON 0x80
|
||||
#define LOG_STATE_OFF 0x00
|
||||
|
||||
#define LOG_ENABLED(type) \
|
||||
((LOG_LEVEL_GET (type) >= LOG_LEVEL) && (type & LOG_STATE_ON))
|
||||
|
||||
/** Log a message if it is enabled */
|
||||
#define LOG(type, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (LOG_ENABLED (type)) \
|
||||
{ \
|
||||
os_log (type, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Log debug messages */
|
||||
#define LOG_DEBUG(type, ...) LOG ((LOG_LEVEL_DEBUG | type), __VA_ARGS__)
|
||||
|
||||
/** Log informational messages */
|
||||
#define LOG_INFO(type, ...) LOG ((LOG_LEVEL_INFO | type), __VA_ARGS__)
|
||||
|
||||
/** Log warning messages */
|
||||
#define LOG_WARNING(type, ...) LOG ((LOG_LEVEL_WARNING | type), __VA_ARGS__)
|
||||
|
||||
/** Log error messages */
|
||||
#define LOG_ERROR(type, ...) LOG ((LOG_LEVEL_ERROR | type), __VA_ARGS__)
|
||||
|
||||
/** Log fatal messages */
|
||||
#define LOG_FATAL(type, ...) LOG ((LOG_LEVEL_FATAL | type), __VA_ARGS__)
|
||||
|
||||
#define LOG_DEBUG_ENABLED(type) LOG_ENABLED (LOG_LEVEL_DEBUG | type)
|
||||
#define LOG_INFO_ENABLED(type) LOG_ENABLED (LOG_LEVEL_INFO | type)
|
||||
#define LOG_WARNING_ENABLED(type) LOG_ENABLED (LOG_LEVEL_WARNING | type)
|
||||
#define LOG_ERROR_ENABLED(type) LOG_ENABLED (LOG_LEVEL_ERROR | type)
|
||||
#define LOG_FATAL_ENABLED(type) LOG_ENABLED (LOG_LEVEL_FATAL | type)
|
||||
|
||||
void os_log (uint8_t type, const char * fmt, ...) CC_FORMAT (2, 3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OSAL_LOG_H */
|
54
libs/include/pnal_config.h
Normal file
54
libs/include/pnal_config.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2021 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief PNAL-specific configuration
|
||||
*
|
||||
* This file contains definitions of configuration settings for the
|
||||
* PNAL layer.
|
||||
*/
|
||||
|
||||
#ifndef PNAL_CONFIG_H
|
||||
#define PNAL_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* Thread priority and stack size
|
||||
*/
|
||||
typedef struct pnal_thread_cfg
|
||||
{
|
||||
uint32_t prio;
|
||||
size_t stack_size;
|
||||
} pnal_thread_cfg_t;
|
||||
|
||||
typedef struct pnal_cfg
|
||||
{
|
||||
pnal_thread_cfg_t snmp_thread;
|
||||
pnal_thread_cfg_t eth_recv_thread;
|
||||
pnal_thread_cfg_t bg_worker_thread;
|
||||
} pnal_cfg_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PNAL_CONFIG_H */
|
2257
libs/include/pnet_api.h
Normal file
2257
libs/include/pnet_api.h
Normal file
File diff suppressed because it is too large
Load Diff
42
libs/include/pnet_export.h
Normal file
42
libs/include/pnet_export.h
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef PNET_EXPORT_H
|
||||
#define PNET_EXPORT_H
|
||||
|
||||
#ifdef PNET_STATIC_DEFINE
|
||||
# define PNET_EXPORT
|
||||
# define PNET_NO_EXPORT
|
||||
#else
|
||||
# ifndef PNET_EXPORT
|
||||
# ifdef profinet_EXPORTS
|
||||
/* We are building this library */
|
||||
# define PNET_EXPORT
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define PNET_EXPORT
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef PNET_NO_EXPORT
|
||||
# define PNET_NO_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PNET_DEPRECATED
|
||||
# define PNET_DEPRECATED __attribute__ ((__deprecated__))
|
||||
#endif
|
||||
|
||||
#ifndef PNET_DEPRECATED_EXPORT
|
||||
# define PNET_DEPRECATED_EXPORT PNET_EXPORT PNET_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifndef PNET_DEPRECATED_NO_EXPORT
|
||||
# define PNET_DEPRECATED_NO_EXPORT PNET_NO_EXPORT PNET_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if 0 /* DEFINE_NO_DEPRECATED */
|
||||
# ifndef PNET_NO_DEPRECATED
|
||||
# define PNET_NO_DEPRECATED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* PNET_EXPORT_H */
|
33
libs/include/pnet_options.h
Normal file
33
libs/include/pnet_options.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef PNET_OPTIONS_H
|
||||
#define PNET_OPTIONS_H
|
||||
|
||||
#if !defined (PNET_MAX_PHYSICAL_PORTS)
|
||||
/** Max number of physical ports */
|
||||
#define PNET_MAX_PHYSICAL_PORTS 1
|
||||
#endif
|
||||
|
||||
#if !defined (PNET_MAX_DIRECTORYPATH_SIZE)
|
||||
/** Max directory path size, including termination */
|
||||
#define PNET_MAX_DIRECTORYPATH_SIZE 240
|
||||
#endif
|
||||
|
||||
#if !defined (PNET_OPTION_DRIVER_ENABLE)
|
||||
#define PNET_OPTION_DRIVER_ENABLE 0
|
||||
#endif
|
||||
|
||||
#endif /* PNET_OPTIONS_H */
|
41
libs/include/pnet_version.h
Normal file
41
libs/include/pnet_version.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef PNET_VERSION_H
|
||||
#define PNET_VERSION_H
|
||||
|
||||
/* #undef PROFINET_GIT_REVISION */
|
||||
|
||||
#if !defined(PNET_VERSION_BUILD) && defined(PROFINET_GIT_REVISION)
|
||||
#define PNET_VERSION_BUILD PROFINET_GIT_REVISION
|
||||
#endif
|
||||
|
||||
/* clang-format-off */
|
||||
|
||||
#define PNET_VERSION_MAJOR 0
|
||||
#define PNET_VERSION_MINOR 2
|
||||
#define PNET_VERSION_PATCH 0
|
||||
|
||||
#if defined(PNET_VERSION_BUILD)
|
||||
#define PNET_VERSION \
|
||||
"0.2.0+" PNET_VERSION_BUILD
|
||||
#else
|
||||
#define PNET_VERSION \
|
||||
"0.2.0"
|
||||
#endif
|
||||
|
||||
/* clang-format-on */
|
||||
|
||||
#endif /* PNET_VERSION_H */
|
98
libs/include/sys/osal_cc.h
Normal file
98
libs/include/sys/osal_cc.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2017 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is licensed under the terms of the BSD 3-clause
|
||||
* license. See the file LICENSE distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef CC_H
|
||||
#define CC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__clang__)
|
||||
#if !defined(CLANG_ANALYZER_NORETURN)
|
||||
#if __has_feature(attribute_analyzer_noreturn)
|
||||
#define CLANG_ANALYZER_NORETURN __attribute__ ((analyzer_noreturn))
|
||||
#else
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
#endif
|
||||
|
||||
static inline void cc_assert (int exp) CLANG_ANALYZER_NORETURN
|
||||
{
|
||||
assert (exp); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
#define CC_PACKED_BEGIN
|
||||
#define CC_PACKED_END
|
||||
#define CC_PACKED __attribute__ ((packed))
|
||||
|
||||
#define CC_FORMAT(str, arg) __attribute__ ((format (printf, str, arg)))
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define CC_TO_LE16(x) ((uint16_t)(x))
|
||||
#define CC_TO_LE32(x) ((uint32_t)(x))
|
||||
#define CC_TO_LE64(x) ((uint64_t)(x))
|
||||
#define CC_FROM_LE16(x) ((uint16_t)(x))
|
||||
#define CC_FROM_LE32(x) ((uint32_t)(x))
|
||||
#define CC_FROM_LE64(x) ((uint64_t)(x))
|
||||
#define CC_TO_BE16(x) ((uint16_t)__builtin_bswap16 (x))
|
||||
#define CC_TO_BE32(x) ((uint32_t)__builtin_bswap32 (x))
|
||||
#define CC_TO_BE64(x) ((uint64_t)__builtin_bswap64 (x))
|
||||
#define CC_FROM_BE16(x) ((uint16_t)__builtin_bswap16 (x))
|
||||
#define CC_FROM_BE32(x) ((uint32_t)__builtin_bswap32 (x))
|
||||
#define CC_FROM_BE64(x) ((uint64_t)__builtin_bswap64 (x))
|
||||
#else
|
||||
#define CC_TO_LE16(x) ((uint16_t)__builtin_bswap16 (x))
|
||||
#define CC_TO_LE32(x) ((uint32_t)__builtin_bswap32 (x))
|
||||
#define CC_TO_LE64(x) ((uint64_t)__builtin_bswap64 (x))
|
||||
#define CC_FROM_LE16(x) ((uint16_t)__builtin_bswap16 (x))
|
||||
#define CC_FROM_LE32(x) ((uint32_t)__builtin_bswap32 (x))
|
||||
#define CC_FROM_LE64(x) ((uint64_t)__builtin_bswap64 (x))
|
||||
#define CC_TO_BE16(x) ((uint16_t)(x))
|
||||
#define CC_TO_BE32(x) ((uint32_t)(x))
|
||||
#define CC_TO_BE64(x) ((uint64_t)(x))
|
||||
#define CC_FROM_BE16(x) ((uint16_t)(x))
|
||||
#define CC_FROM_BE32(x) ((uint32_t)(x))
|
||||
#define CC_FROM_BE64(x) ((uint64_t)(x))
|
||||
#endif
|
||||
|
||||
#define CC_ATOMIC_GET8(p) __atomic_load_n ((p), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_GET16(p) __atomic_load_n ((p), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_GET32(p) __atomic_load_n ((p), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_GET64(p) __atomic_load_n ((p), __ATOMIC_SEQ_CST)
|
||||
|
||||
#define CC_ATOMIC_SET8(p, v) __atomic_store_n ((p), (v), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_SET16(p, v) __atomic_store_n ((p), (v), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_SET32(p, v) __atomic_store_n ((p), (v), __ATOMIC_SEQ_CST)
|
||||
#define CC_ATOMIC_SET64(p, v) __atomic_store_n ((p), (v), __ATOMIC_SEQ_CST)
|
||||
|
||||
#define CC_ASSERT(exp) cc_assert (exp)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CC_STATIC_ASSERT(exp) static_assert (exp, "")
|
||||
#else
|
||||
#define CC_STATIC_ASSERT(exp) _Static_assert(exp, "")
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CC_H */
|
77
libs/include/sys/osal_sys.h
Normal file
77
libs/include/sys/osal_sys.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2017 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is licensed under the terms of the BSD 3-clause
|
||||
* license. See the file LICENSE distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef OSAL_SYS_H
|
||||
#define OSAL_SYS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#define OS_THREAD
|
||||
#define OS_MUTEX
|
||||
#define OS_SEM
|
||||
#define OS_EVENT
|
||||
#define OS_MBOX
|
||||
#define OS_TIMER
|
||||
|
||||
typedef pthread_t os_thread_t;
|
||||
typedef pthread_mutex_t os_mutex_t;
|
||||
|
||||
typedef struct os_sem
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
size_t count;
|
||||
} os_sem_t;
|
||||
|
||||
typedef struct os_event
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
uint32_t flags;
|
||||
} os_event_t;
|
||||
|
||||
typedef struct os_mbox
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
size_t r;
|
||||
size_t w;
|
||||
size_t count;
|
||||
size_t size;
|
||||
void * msg[];
|
||||
} os_mbox_t;
|
||||
|
||||
typedef struct os_timer
|
||||
{
|
||||
timer_t timerid;
|
||||
os_thread_t * thread;
|
||||
pid_t thread_id;
|
||||
bool exit;
|
||||
void (*fn) (struct os_timer *, void * arg);
|
||||
void * arg;
|
||||
uint32_t us;
|
||||
bool oneshot;
|
||||
} os_timer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OSAL_SYS_H */
|
BIN
libs/lib/x86_64/libosal.a
Normal file
BIN
libs/lib/x86_64/libosal.a
Normal file
Binary file not shown.
BIN
libs/lib/x86_64/libprofinet.a
Normal file
BIN
libs/lib/x86_64/libprofinet.a
Normal file
Binary file not shown.
@ -1,5 +1,6 @@
|
||||
#include "profinet_shared_data_client.hpp"
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#define ECHO_MODULE_ID 0x00000040 /// Идентификатор тестового модуля
|
||||
#define ECHO_SUBMOD_ID 0x00000140 /// Идентификатор тестового подмодуля
|
||||
@ -45,32 +46,34 @@ uint32_t event_mask = ( ProfinetEvent::EVENT_CONNECTION_ESTABLISHED |
|
||||
ProfinetEvent::EVENT_NEW_PARAM_DATA |
|
||||
ProfinetEvent::EVENT_CONNECTION_ABORT );
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
p_profinet_data = shared_data.Connect("profinet_shared_data");
|
||||
auto& echo_module = p_profinet_data->p_mods[0];
|
||||
if (echo_module.id != ECHO_MODULE_ID)
|
||||
|
||||
if (p_profinet_data == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& echo_submod = echo_module.p_submods[0];
|
||||
/// Берем указатель на данные подмодуля в разделяемой памяти
|
||||
auto echo_submod_ptr = shared_data.getSubmodule(ECHO_MODULE_ID, ECHO_SUBMOD_ID);
|
||||
|
||||
if (echo_submod.id != ECHO_SUBMOD_ID)
|
||||
if (echo_submod_ptr->id != ECHO_SUBMOD_ID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/// Берем указатель на данные параметра подмодуля в разделяемолй памяти
|
||||
auto echo_param_gain_ptr = shared_data.getSubmoduleParameter(ECHO_MODULE_ID, ECHO_SUBMOD_ID, ECHO_PARAMETER_GAIN_IDX);
|
||||
|
||||
if (echo_param_gain_ptr->index != ECHO_PARAMETER_GAIN_IDX)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& echo_param_gain = echo_submod.p_params[0];
|
||||
|
||||
if (echo_param_gain.index != ECHO_PARAMETER_GAIN_IDX)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
std::cout << "Strarting..." << std::endl;
|
||||
|
||||
|
||||
|
||||
for(;;)
|
||||
{
|
||||
uint32_t events = p_profinet_data->Events.wait_flags(event_mask);
|
||||
@ -84,15 +87,31 @@ int main(int argc, char * argv[])
|
||||
|
||||
if (events & ProfinetEvent::EVENT_NEW_CYCLIC_DATA)
|
||||
{
|
||||
std::cout << "New cyc data" << std::endl;
|
||||
static uint32_t value_i = 0;
|
||||
static float value_f = 0.0;
|
||||
|
||||
p_profinet_data->Events.clear_flags(ProfinetEvent::EVENT_NEW_CYCLIC_DATA);
|
||||
|
||||
///Читаем данные от ПЛК
|
||||
echo_submod.out_data.Read(0, Echo_outCycData.mem, echo_submod.cyc_outdata_len);
|
||||
echo_submod_ptr->out_data.Read(0, Echo_outCycData.mem, echo_submod_ptr->cyc_outdata_len);
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_f);
|
||||
|
||||
if (value_i != Echo_outCycData.data.data_i)
|
||||
{
|
||||
value_i = Echo_outCycData.data.data_i;
|
||||
|
||||
std::cout << "New data_i from PLC: " << value_i << std::endl;
|
||||
}
|
||||
|
||||
if (value_f != Echo_outCycData.data.data_f)
|
||||
{
|
||||
value_f = Echo_outCycData.data.data_f;
|
||||
|
||||
std::cout << "New data_f from PLC: " << value_f << std::endl;
|
||||
}
|
||||
|
||||
///Подготавливаем данные для ПЛК
|
||||
Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i;
|
||||
Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f;
|
||||
@ -100,8 +119,7 @@ int main(int argc, char * argv[])
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
///Отправляем данные для ПЛК
|
||||
echo_submod.inp_data.Write(0, Echo_inpCycData.mem, echo_submod.cyc_indata_len);
|
||||
|
||||
echo_submod_ptr->inp_data.Write(0, Echo_inpCycData.mem, echo_submod_ptr->cyc_indata_len);
|
||||
}
|
||||
|
||||
if (events & ProfinetEvent::EVENT_NEW_PARAM_DATA)
|
||||
@ -110,10 +128,16 @@ int main(int argc, char * argv[])
|
||||
|
||||
std::cout << "Event: New parameter data: " << std::endl;
|
||||
//Читаем параметр записанный ПЛК при установлении связи
|
||||
echo_param_gain.data.Read(0, (uint8_t*)&Echo_Gain, echo_param_gain.length);
|
||||
echo_param_gain_ptr->data.Read(0, (uint8_t*)&Echo_Gain, echo_param_gain_ptr->length);
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_Gain);
|
||||
std::cout << "Echo_Gain = " << std::to_string(Echo_Gain) << endl;
|
||||
}
|
||||
|
||||
if (events & ProfinetEvent::EVENT_CONNECTION_ABORT)
|
||||
{
|
||||
p_profinet_data->Events.clear_flags(ProfinetEvent::EVENT_CONNECTION_ABORT);
|
||||
std::cout << "Connection Aborted" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,3 @@
|
||||
#********************************************************************
|
||||
# _ _ _
|
||||
# _ __ | |_ _ | | __ _ | |__ ___
|
||||
# | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
# | | | |_ _ | || (_| || |_) |\__ \
|
||||
# |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
#
|
||||
# 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.0)
|
||||
|
||||
project (PN_DEV_TEST VERSION 0.0.1)
|
||||
@ -16,6 +5,7 @@ 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)
|
||||
set(TARGET_NAME profinet_io_dev)
|
||||
|
||||
include(./utils/utils.cmake)
|
||||
include(./profinet/profinet.cmake)
|
||||
@ -27,10 +17,24 @@ include (./shared_data/shared_data.cmake)
|
||||
|
||||
set(SRC_FILES ${SRC_FILES} ./app.cpp)
|
||||
|
||||
# Копирование заглушки скрипта установки параметров сети.
|
||||
# Если не копировать, то в недрах pnet после fork вызовется exit и
|
||||
# вызовутся деструкторы объектов, что может привести к непредвиденным последствиям.
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/set_network_parameters
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(pn_dev_test ./main.cpp ${SRC_FILES})
|
||||
#Копирование файла конфигурации
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/program_configure.json
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
target_include_directories(pn_dev_test PRIVATE
|
||||
#Копирование тестового файла конфигурации устройства Profinet
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/profinet_device_configure.json
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
|
||||
add_executable(${TARGET_NAME} ./main.cpp ${SRC_FILES})
|
||||
|
||||
target_include_directories(${TARGET_NAME} PRIVATE
|
||||
./
|
||||
${INC_DIRS}
|
||||
${LIBS_INSTALL_PATH}/include
|
||||
@ -40,5 +44,6 @@ target_include_directories(pn_dev_test PRIVATE
|
||||
${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 ${Boost_LIBRARIES})
|
||||
target_link_directories(${TARGET_NAME} PUBLIC ${LIBS_INSTALL_PATH}/lib/x86_64)
|
||||
|
||||
target_link_libraries (${TARGET_NAME} PUBLIC profinet osal ${Boost_LIBRARIES})
|
||||
|
@ -157,12 +157,70 @@ static uint8_t programconf_dataDirConvert(string dir_str)
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Считаем общий размер данных требуемый всеми подмодулями: их циклическими данными и параметрами
|
||||
* Пробегает по файлу конфигурации и считает размер требуемой памяти.
|
||||
* @param j
|
||||
* @param memory_size
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static bool programconf_calc_memory_size(json& j, uint32_t& memory_size)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceModulesSettings"))
|
||||
return false;
|
||||
|
||||
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
|
||||
|
||||
memory_size = sizeof(ProfinetData_Map) + modules_sett.size() * sizeof(ProfinetData_Module);
|
||||
|
||||
for (auto& mod_set : modules_sett)
|
||||
{
|
||||
auto& submodules_sett = mod_set["submodules"];
|
||||
|
||||
memory_size += submodules_sett.size() * sizeof(ProfinetData_Submodule);
|
||||
|
||||
for (auto& submod_sett : submodules_sett)
|
||||
{
|
||||
|
||||
uint16_t in_data_len = static_cast<uint16_t>(submod_sett["cyc_inp_data_size"].get<int>());
|
||||
uint16_t out_data_len = static_cast<uint16_t>(submod_sett["cyc_out_data_size"].get<int>());
|
||||
|
||||
memory_size+= in_data_len + out_data_len;
|
||||
|
||||
///Параметры подмодуля
|
||||
auto& params_sett = submod_sett["parameters"];
|
||||
|
||||
memory_size += params_sett.size() * sizeof(ProfinetData_Parameter);
|
||||
|
||||
/// Записываем параметры в подмодуль
|
||||
for (auto& parm_sett : params_sett)
|
||||
{
|
||||
uint16_t data_size = static_cast<uint16_t>(parm_sett["data_size"].get<int>());
|
||||
memory_size += data_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
|
||||
{
|
||||
if (!j.contains("ProfinetDeviceModulesSettings"))
|
||||
return false;
|
||||
|
||||
|
||||
uint32_t required_mem_size;
|
||||
|
||||
if (!programconf_calc_memory_size(j, required_mem_size))
|
||||
return false;
|
||||
|
||||
/// Проверяем достаточно ли у нас выделено памяти под текущую конфигурацию
|
||||
/// Если недостаточно, то выделяем недостающее.
|
||||
shared_data.checkMemorySize(required_mem_size);
|
||||
|
||||
/// Далее идет выделение
|
||||
|
||||
auto& modules_sett = j["ProfinetDeviceModulesSettings"]["modules"];
|
||||
///Узнаем количество модулей
|
||||
uint32_t mudules_number = modules_sett.size();
|
||||
@ -297,6 +355,8 @@ static bool programconf_getProfinetModulesSettings(json& j, ProfinetData_Map * p
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDeviceSettings& pn_sett,
|
||||
ProfinetData_Map * p_data_map, ProfinetSharedData& shared_data)
|
||||
{
|
||||
@ -320,3 +380,4 @@ bool programconf_getProfinetDeviceSettings(std::string file_path, ProfinetDevice
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ ProfinetData_Map * ProfinetSharedData::Create(std::string mem_name)
|
||||
{
|
||||
/// Если память уже выделена, удаляем
|
||||
shared_memory_object::remove(mem_name.c_str());
|
||||
|
||||
/// Для начала выделяем 65к байт. Потом вызывается функция checkMemorySize и размер моджет быть увеличен
|
||||
shmem_ = managed_shared_memory{create_only, mem_name.c_str(), 65536};
|
||||
mem_name_ = mem_name;
|
||||
///Создаем данные в разделяемой памяти
|
||||
@ -46,3 +46,20 @@ ProfinetData_Map * ProfinetSharedData::Create(std::string mem_name)
|
||||
return p_profinet_data_;
|
||||
}
|
||||
|
||||
void ProfinetSharedData::checkMemorySize(uint32_t required_mem_size)
|
||||
{
|
||||
uint32_t free_size = shmem_.get_size();
|
||||
|
||||
if (required_mem_size < free_size)
|
||||
return;
|
||||
|
||||
/// Увеличиваем память
|
||||
managed_shared_memory::grow(mem_name_.c_str(), required_mem_size - free_size);
|
||||
|
||||
/// Заново открываем память(может измениться указатель)
|
||||
shmem_ = managed_shared_memory{open_only, mem_name_.c_str()};
|
||||
|
||||
/// Заново находим или создаем структуру ProfinetData_Map
|
||||
p_profinet_data_ = shmem_.find_or_construct<ProfinetData_Map>("ProfinetData_Map")();
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,8 @@ class ProfinetSharedData {
|
||||
public:
|
||||
~ProfinetSharedData() {
|
||||
///Удаляем память
|
||||
//boost::interprocess::shared_memory_object::remove(mem_name_.c_str());
|
||||
boost::interprocess::shared_memory_object::remove(mem_name_.c_str());
|
||||
//std::cout << "Destruct: ProfinetSharedData: Shared data deleted" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Выделяыет раздеяемую память под структуру ProfinetData_Map
|
||||
@ -29,6 +30,15 @@ public:
|
||||
return shmem_.construct<T>(boost::interprocess::anonymous_instance)[nbr]();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, что размер свободной памяти не меньше чем значение required_mem_size
|
||||
* Если меньше, то увеличиват память.
|
||||
*
|
||||
* @param required_mem_size
|
||||
* @return uint32_t
|
||||
*/
|
||||
void checkMemorySize(uint32_t required_mem_size);
|
||||
|
||||
ProfinetData_Map * p_profinet_data_;
|
||||
|
||||
private:
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class ProfinetSharedDataClient {
|
||||
public:
|
||||
@ -22,6 +24,8 @@ public:
|
||||
{
|
||||
auto mem = shmem_.find<ProfinetData_Map>("ProfinetData_Map");
|
||||
out = mem.first;
|
||||
///Упорядочиваем память для удобства обращения по индентификатору Profinet
|
||||
collected_data = collect(out);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
@ -34,10 +38,76 @@ public:
|
||||
std::cerr << e.what() << '\n';
|
||||
return out;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* @brief Возвращает указатель на данные подмодуля в разделяемой памяти
|
||||
*
|
||||
* @param module_id идентификатор модуля
|
||||
* @param submodule_id идентификатор подмодуля
|
||||
* @return ProfinetData_Submodule*
|
||||
*/
|
||||
ProfinetData_Submodule * getSubmodule(uint32_t module_id, uint32_t submodule_id)
|
||||
{
|
||||
return (*collected_data)[module_id].submods[submodule_id].p_submod;
|
||||
}
|
||||
/**
|
||||
* @brief Возвращает указатель на данные параметра подмодуля в разделяемой памяти
|
||||
*
|
||||
* @param module_id идентификатор модуля
|
||||
* @param submodule_id идентификатор подмодуля
|
||||
* @param param_index индекс параметра
|
||||
* @return ProfinetData_Parameter*
|
||||
*/
|
||||
ProfinetData_Parameter * getSubmoduleParameter(uint32_t module_id, uint32_t submodule_id, uint32_t param_index)
|
||||
{
|
||||
return (*collected_data)[module_id].submods[submodule_id].params[param_index];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct ProfinetSharedDataSubmodule {
|
||||
ProfinetData_Submodule* p_submod;
|
||||
std::map<uint32_t, ProfinetData_Parameter*> params;
|
||||
};
|
||||
|
||||
struct ProfinetSharedDataModule {
|
||||
ProfinetData_Module* p_mod;
|
||||
std::map<uint32_t, ProfinetSharedDataSubmodule> submods;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Собирает данные в словарь, можно использовать для удобства обращения к данным по идентификатору
|
||||
*
|
||||
* @param p_data_map
|
||||
* @return std::shared_ptr<std::map<uint32_t, ProfinetSharedDataModule>>
|
||||
*/
|
||||
static std::shared_ptr<std::map<uint32_t, ProfinetSharedDataModule>> collect(ProfinetData_Map * p_data_map) {
|
||||
std::shared_ptr<std::map<uint32_t, ProfinetSharedDataModule>> p_map(new std::map<uint32_t, ProfinetSharedDataModule>);
|
||||
|
||||
for (int i = 0; i < p_data_map->mods_nbr; ++i)
|
||||
{
|
||||
auto& mod = (*p_map)[p_data_map->p_mods[i].id];
|
||||
|
||||
mod.p_mod = &p_data_map->p_mods[i];
|
||||
|
||||
for (int j = 0; j < p_data_map->p_mods[i].submods_nbr; ++j)
|
||||
{
|
||||
auto& submod = mod.submods[p_data_map->p_mods[i].p_submods[j].id];
|
||||
|
||||
submod.p_submod = &p_data_map->p_mods[i].p_submods[j];
|
||||
|
||||
for (int k = 0; k < p_data_map->p_mods[i].p_submods[j].params_nbr; ++k)
|
||||
{
|
||||
submod.params[p_data_map->p_mods[i].p_submods[j].p_params[k].index] = &p_data_map->p_mods[i].p_submods[j].p_params[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p_map;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::interprocess::managed_shared_memory shmem_;
|
||||
std::shared_ptr<std::map<uint32_t, ProfinetSharedDataModule>> collected_data; /// Упорядоченная структура указателей на разделяемую память
|
||||
};
|
16
src/set_network_parameters
Executable file
16
src/set_network_parameters
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
############################################
|
||||
# Скрипт для установки параметров сети #
|
||||
############################################
|
||||
#
|
||||
# Данный скрипт запускается стеком pnet при инициализации.
|
||||
# Если файл с именем set_network_parameters будет отсутсвовать,
|
||||
# то в недрах pnet после вызова fork будет вызван exit, что может привести
|
||||
# к нежелательным последствиям, например вызовам деструкторов копий объектов
|
||||
# родительского процесса.
|
||||
#
|
||||
|
||||
echo "set_network_parameters: This is dummy script wich called by pnet stack. As example see pnet/src/ports/linux/set_network_parameters."
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user