Реализация протокола с параметрами в C++

<< Click to Display Table of Contents >>

Navigation:  API MasterSCADA 4D > Функции, ФБ, Протоколы на С++ > API для ФБ и протоколов > Разработка протоколов > Разработка протокола с параметрами >

Реализация протокола с параметрами в C++

Пример реализации подключен к Examples.sln как mplc_protocol_with_params:

realiz_protocola_param_v_C

Для разработки своих собственных протоколов нужно открыть пример и изменить те части проекта, которые отвечают за логику работы. Вспомогательные файлы, служащие для взаимодействия с исполнительной системой, редактировать не требуется.

Порядок разработки

test_protocol_params.h

Общая структура и регистрация класса протокола не отличается от той, что использовалась в примере протокола с модулями. Однако в данном случае дополнительно в класс протокола необходимо добавить два поля типа mplc::api::ScadaParameter и перегрузить отдельный метод Create именно для параметров.

Для этого в примере был создан заголовочный файл test_protocol_params.h:

realiz_protocola_param_v_C_2

Содержимое файла:

Скриншот

Текст

realiz_protocola_param_v_C_1

#pragma once
#include <mplc/api.h>
#include "test_module_params.h"
#include "emulator.h"
class ProtocolWithParameters final : public mplc::api::ScadaProtocol {
    ModuleWithParameters* param_module;
    mplc::api::ScadaParameter InputParameter;
    mplc::api::ScadaParameter OutputParameter;
    Emulator* emulator;
    bool connected{false};
    int input_param_value {0};
    bool Connect();
public:
    MPLC_OBJECT(ProtocolWithParameters);
    ProtocolWithParameters();
    ~ProtocolWithParameters() override;
    void Init() override;
    void Execute() override;
    mplc::api::ScadaModule* Create(const mplc::vm::IOModulemoduleoverride;
    mplc::api::ScadaParameter* Create(const mplc::vm::Variablevaroverride;
};

test_protocol_params.cpp

Создание параметров отличается от создания каналов и модулей тем, что в данном случае необходимо определять параметр по названию, что задается в редакторе. Работа с самими параметрами не сильно отличается от работы с каналами. Тут так же при чтении желательно проверять, изменилось ли значение, и только после этого считывать его. Для записи значения нужно сначала проверить валидность параметра, после чего записать в него не само значение на прямую, а предварительно поместив его в OpcUa_VariantHlp. В остальном отличий от обычного протокола нет.

Для этого в примере был создан файл test_protocol_params.cpp:

realiz_protocola_param_v_C_5

Содержимое файла:

Скриншот

Текст

realiz_protocola_param_v_C_3

realiz_protocola_param_v_C_4

#include "test_protocol_params.h"
ProtocolWithParameters::ProtocolWithParameters() {
    emulator = new Emulator();
}
ProtocolWithParameters::~ProtocolWithParameters() {
    emulator->close();
    delete emulator;
}
bool ProtocolWithParameters::Connect() {
    if (connected) {
        return true;
    }
    if (!emulator->connect()) {
        return false;
    }
    connected = true;
    SetFaultState(false"");
    return true;
}
void ProtocolWithParameters::Init() {
    emulator->init();
}
void ProtocolWithParameters::Execute() {
    if (!isConnect()) {
        return;
    }
    if (!Connect()) {
        SetFaultState(true"Failed to connect");
        return;
    }
    if (!isExecute()) {
        return;
    }
    std::string buff;
    // Чтение значения из параметра
    std::string test_str;
   
    if (InputParameter.Changed()) {
        input_param_value = InputParameter.Get<int>();
    }
    int result = param_module->Execute(emulator, input_param_value);
    // Запись значения в параметр
    if (OutputParameter.Valid()) {
        OpcUa_VariantHlp value;
        value.SetInt(result);
        OutputParameter.Update(value);
    }
    AcknowledgeAllChanges();
}
mplc::api::ScadaModuleProtocolWithParameters::Create(const mplc::vm::IOModulemodule) {
    param_module = new ModuleWithParameters();
    mplc::api::ScadaModule& req = *param_module;
    return &req;
}
mplc::api::ScadaParameterProtocolWithParameters::Create(const mplc::vm::Variablevar) {
    if (var->name.translited() == "input_parameter") {
        InputParameter.Init(var);
        return &InputParameter;
    }
    if (var->name.translited() == "output_parameter") {
        OutputParameter.Init(var);
        return &OutputParameter;
    }
    return nullptr;
}
MPLC_PROTOCOL_TYPE(ProtocolWithParametersProtocolWithParameters);

test_module_params.h

Теперь рассмотрим реализацию модуля. Как и в случае протокола отличий от примера с модулями почти нет. Здесь так же нужно добавить два поля типа mplc::api::ScadaParameter и перегрузить метод Create для параметров. Так же стоит отметить, что метод создания каналов для модулей обязателен к перегрузке, но в этом примере работы с каналами нет, поэтому просто добавим реализацию, что возвращает nullptr.

Для этого в примере был создан файл test_module_params.h:

realiz_protocola_param_v_C_6

Содержимое файла:

Скриншот

Текст

realiz_protocola_param_v_C_7

#pragma once
#include <mplc/api.h>
#include "emulator.h"
class ModuleWithParameters : public mplc::api::ScadaModule {
    mplc::api::ScadaParameter InputStruct;
    mplc::api::ScadaParameter OutputStruct;
public:
    ModuleWithParameters();
    ~ModuleWithParameters() override;
    mplc::api::ScadaParameter* Create(const mplc::vm::VariablevarLuaDataProviderprovideroverride;
    mplc::api::ScadaChannel* Create(const mplc::vm::ChannelchannelLuaDataProviderprovideroverride;
    int Execute(Emulatoremulatorint protocol_value);
};

test_module_params.cpp

Как и в случае протокола, создание параметров в модуле выполняется поименно. Однако, при чтении из параметра структуры нужно обратиться напрямую к хранимому значению OpcUa_VariantHlp Value, у которого потребуется вызвать метод GetJson(), что вернет OpcUa_Json. Его нужно будет разбирать отдельно при помощи набора функций GetSafe...Value. При записи в структуры, необходимо не просто поместить значение в OpcUa_VariantHlp, а предварительно поместить его в rapidjson::Value. При этом наименования ключей в JSON должны полностью совпадать с названиями полей в редакторе.

Для этого в примере был создан файл test_module_params.cpp:

realiz_protocola_param_v_C_8

Содержимое файла:

Скриншот

Текст

realiz_protocola_param_v_C_9

#include "test_module_params.h"
ModuleWithParameters::ModuleWithParameters() {}
ModuleWithParameters::~ModuleWithParameters() {}
mplc::api::ScadaChannelModuleWithParameters::Create(const mplc::vm::ChannelchannelLuaDataProviderprovider) {
    return nullptr;
}
mplc::api::ScadaParameterModuleWithParameters::Create(const mplc::vm::VariablevarLuaDataProviderprovider) {
    if (var->name.translited() == "input_struct") {
        InputStruct.Init(var);
        return &InputStruct;
    }
    if (var->name.translited() == "output_struct") {
        OutputStruct.Init(var);
        return &OutputStruct;
    }
    return nullptr;
}
int ModuleWithParameters::Execute(Emulatoremulatorint protocol_value) {
    std::string buff;
    auto& json_input = InputStruct.Value.GetJson();
    std::string str_string = GetSafeStringValue(json_input.get(), "text_data""");
    int dint_field = GetSafeInt64Value(json_input.get(), "dint_data", 0);
    emulator->write(str_string, protocol_value, dint_field);
    buff = emulator->read();
    if (OutputStruct.Valid()) {
        mplc::OpcUa_Json json;
        rapidjson::Value val(rapidjson::kObjectType);
        val.AddMember("text_data", buff, json.GetAllocator());
        val.AddMember("dint_data", buff.size(), json.GetAllocator());
        OpcUa_VariantHlp value;
        value.SetJson(val);
        OutputStruct.Update(value);
    }
    return buff.size();
}

Далее можно компилировать проект.

Компиляция проекта

ОС Windows

Для компиляции проекта на ОС Windows нужно выполнить команду Build в контекстном меню проекта:

realiz_protocola_param_v_C_11

Скомпилированные файлы появятся в папке проекта: C:\mplc\api\platform\x64\bin\Release (адрес действителен, если название папок, которые делал разработчик, совпадают с названиями, которые давались в этой инструкции).

ОС Linux

Чтобы произвести сборку под Linux платформы, нужно сохранить проект и перенести все файлы из папки C:\mplc\api (адрес действителен, если название папок, которые делал разработчик, совпадают с названиями, которые давались в этой инструкции) в созданный каталог на компьютере с ОС Linux. Подробнее смотрите в разделе Сборка под Linux платформы.

После сборки можно приступать к тестированию созданного ФБ.