Реализация протокола с группой каналов в C++

<< Click to Display Table of Contents >>

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

Реализация протокола с группой каналов в C++

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

realiz_protocola_grup_canal_v_C

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

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

test_protocol_ch_groups.h

Для начала по аналогии с простым протоколом создается класс, унаследованный от ScadaProtocol, реализующий требуемый функционал. Необходимы макросы регистрации класса MPLC_OBJECT(ProtocolChannelGroups) в секции public. Также переопределению подлежат чисто виртуальные методы Execute() и метод Create() для модулей.

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

realiz_protocola_grup_canal_v_C_1

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

Скриншот

Текст

realiz_protocola_grup_canal_v_C_2

#pragma once

#include <mplc/api.h>

 

#include "emulator.h"

#include "module_with_ch_groups.h"

 

 

 

class ProtocolChannelGroups final : public mplc::api::ScadaProtocol {

private:

    Emulator *emulator;

    std::vector<ModuleWithChannelGroups*> modules;

    bool connected{false};

    bool Connect();

 

public:

    MPLC_OBJECT(ProtocolChannelGroups);

    ProtocolChannelGroups();

    ~ProtocolChannelGroups();

    void Execute() override;

    mplc::api::ScadaModule* Create(const mplc::vm::IOModule* moduleoverride;

    void Init() override;

};

test_protocol_ch_groups.cpp

Протокол и его свойства надо зарегистрировать в файлах исходных кодов макроса MPLC_PROTOCOL_TYPE.

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

realiz_protocola_grup_canal_v_C_3

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

Скриншот

Текст

realiz_protocola_grup_canal_v_C_4

#include "test_protocol_ch_groups.h"

 

ProtocolChannelGroups::ProtocolChannelGroups() {

    emulator = new Emulator();

}

 

ProtocolChannelGroups::~ProtocolChannelGroups() {

    emulator->close();

    delete emulator;

}

 

bool ProtocolChannelGroups::Connect() {

    if (connected) {

        return true;

    }

    if (!emulator->connect()) {

        return false;

    }

    connected = true;

    SetFaultState(false"");

    return true;

}

 

 

void ProtocolChannelGroups::Init() {

    emulator->init();

}

 

void ProtocolChannelGroups::Execute() {

    if (!isConnect()) {

        return;

    }

    if (!Connect()) {

        SetFaultState(true"Failed to connect");

        return;

    }

    if (!isExecute()) {

        return;

    }

 

    std::string buff;

    for (auto module: modules) {

        module->Execute(emulator);

    }

    AcknowledgeAllChanges();

}

 

mplc::api::ScadaModuleProtocolChannelGroups::Create(const mplc::vm::IOModulemodule) {

    auto mod = new ModuleWithChannelGroups(modules.size());

    modules.push_back(mod);

    mplc::api::ScadaModule& req = *mod;

    return &req;

}

 

MPLC_PROTOCOL_TYPE(ProtocolChannelGroupsProtocolChannelGroups);

 

Если при создании модулей необходимо отличать их, то в методе протокола Create() для модулей имеется поле SubType класса vm::IOModule, в котором и содержится значение Подтипа модуля, которое указывалось в редакторе.

module_with_ch_groups.h

Далее идёт создание класса модуля, унаследованного от ScadaModule. Далее создаётся отдельный класс ChannelGroup, что и будет выполнять работу группы каналов. Для создания группы каналов в классе ScadaModule есть перегружаемый метод InitChannelGroup, в котором дополнительно происходит инициализация каналов. Так как работу по созданию каналов выполняет метод InitChannelGroup, а метод Create() чисто виртуальный, необходимо переопределить его кодом с возвращением nullptr.

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

realiz_protocola_grup_canal_v_C_5

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

Скриншот

Текст

realiz_protocola_grup_canal_v_C_6

#pragma once

#include <mplc/api.h>

#include "emulator.h"

 

struct ChannelGroup {

    int module_id;

    int group_id;

    mplc::api::ScadaChannel TestInput;

    mplc::api::ScadaChannel TestIncrement;

    mplc::api::ScadaChannel TestOutput;

 

    ChannelGroup(int nod_numint group_num): module_id(nod_num), group_id(group_num) {}

    void Execute(Emulatoremulator);

};

 

class ModuleWithChannelGroups : public mplc::api::ScadaModule {

    int module_id;

    std::vector<ChannelGroup*> groups;

 

public:

    ModuleWithChannelGroups(int num): module_id(num) {}

    void InitChannelGroup(const mplc::vm::ChannelGroupgroupLuaDataProviderprovideroverride;

    virtual mplc::api::ScadaChannel* Create(const mplc::vm::ChannelchannelLuaDataProviderprovideroverride;

    void Execute(Emulatoremulator);

};

module_with_ch_groups.cpp

В файле исходных кодов работа с макросами регистрации не отличается от обычного протокола.

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

realiz_protocola_grup_canal_v_C_7

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

Скриншот

Текст

realiz_protocola_grup_canal_v_C_8

#include "module_with_ch_groups.h"

 

 

void ChannelGroup::Execute(Emulatoremulator) {

    std::string buff;

    if (TestIncrement.OutVar.Changed()) {

        emulator->set_increment(module_id, group_id, TestIncrement.OutVar.Get<int>());

    }

    if (TestInput.OutVar.Changed()) {

        emulator->write(module_id, group_id, TestInput.OutVar.Get<std::string>());

    }

    buff = emulator->read(module_id, group_id);

    TestOutput.InVar.Update(buff);

}

 

void ModuleWithChannelGroups::InitChannelGroup(const mplc::vm::ChannelGroupgroupLuaDataProviderprovider) {

    int group_id = 0;

    if (auto it = group->settings.find("id"); it != group->settings.end()) {

        group_id = it->second.Get<int>(0);

    }

 

    auto ch_group = new ChannelGroup(module_id, group_id);

 

    for (auto channel: group->childs<mplc::vm::Channel>()) {

        mplc::api::ScadaChannel* ch;

        if (channel->name.utf8() == "test_input") {

            ch = &ch_group->TestInput;

        } else if (channel->name.utf8() == "test_output") {

            ch = &ch_group->TestOutput;

        } else if (channel->name.utf8() == "test_increment") {

            ch = &ch_group->TestIncrement;

        } else {

            ch = nullptr;

        }

        if (ch) {

            ch->BaseInit(channel);

            Register(ch);

        }

    }

    groups.push_back(ch_group);

}

 

mplc::api::ScadaChannelModuleWithChannelGroups::Create(const mplc::vm::ChannelchannelLuaDataProviderprovider) {

    return nullptr;

}

 

void ModuleWithChannelGroups::Execute(Emulatoremulator) {

    for (auto group: groups) {

        group->Execute(emulator);

    }

}

 

 

 

Ввод и вывод данных из каналов модулей происходит методами Read() и Write() класса ScadaChannel. ch - это указатель на класс ScadaChannel.

Важно! Метод Read выдаёт ошибку и не возвращает значение, пока заменяется на комбинацию методов.

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

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

ОС Windows

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

realiz_protocola_grup_canal_v_C_9

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

ОС Linux

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

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