Go to file
2022-08-15 11:36:21 +03:00
debug_support Merge branch 'master' of http://server_gorbunov:3000/SmartForce4.0/profinet_io_dev 2022-08-05 15:27:12 +03:00
libs dev(UML-981): Поправил сборку, добавил описание 2022-08-15 11:36:21 +03:00
profinet_stack dev(UML-981): Повторно выкладываю osal 2022-08-08 09:03:44 +03:00
profinet_test dev(UML-981): Переделал для взаимодействия по pipe 2022-08-11 09:10:48 +03:00
src dev(UML-981): Поправил сборку, добавил описание 2022-08-15 11:36:21 +03:00
.gitignore dev(UML-981): Переделал для взаимодействия по pipe 2022-08-11 09:10:48 +03:00
README.md dev(UML-981): Поправил сборку, добавил описание 2022-08-15 11:36:21 +03:00

profinet_io_dev

Драйвер 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

Пример подключения к памяти:

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 - соединение с контроллером разорвано.

Пример ожидания установления соединения или приема новых циклических данных:

uint32_t events = p_profinet_data->Events.wait_flags(EVENT_CONNECTION_ESTABLISHED | EVENT_NEW_CYCLIC_DATA);

wait_flags - блокирует поток до момента установления флага.

Когда флаг установлен, его нужно сбросить:

p_profinet_data->Events.clear_flags(EVENT_NEW_CYCLIC_DATA);

Пример чтения данных параметров подмодуля

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

Пример чтения и записи циклических данных подмодуля

///Читаем данные от ПЛК
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);

pipe каналы

Обмен происходит по двум каналам, по умолчанию это:

  • profinet_io_dev_out
  • profinet_io_dev_inp

Путь к аналам задается в конфигурационном файле program_configure.json.

ПО сначала открывает канал для чтения(inp), затем ожидает подключения клиента, после чего открывает канал для записи(out).

Обмен происходит с помощью json rpc, протокол описан в файле src/interprocess/pipes/json_rpc_protocol.txt.