From OpenSCADAWiki
Jump to: navigation, search
Line 16: Line 16:
 
Але оскільки транспортні інтерфейси, реалізовані модулями, дозволяють зв'язуватися із різними пристроями на них, то цей документ розширено [[#Internal|короткою інструкцією]] з посиланнями щодо створення внутрішніх Функцій, DAQ-Шаблонів, UI-Віджетів, а також оформлення Бібліотек із ними для розташування і публікації у [[Special:MyLanguage/Libs/Main|офіційній колекції бібліотек OpenSCADA]].
 
Але оскільки транспортні інтерфейси, реалізовані модулями, дозволяють зв'язуватися із різними пристроями на них, то цей документ розширено [[#Internal|короткою інструкцією]] з посиланнями щодо створення внутрішніх Функцій, DAQ-Шаблонів, UI-Віджетів, а також оформлення Бібліотек із ними для розташування і публікації у [[Special:MyLanguage/Libs/Main|офіційній колекції бібліотек OpenSCADA]].
  
Для подальшого розміщення розробленого модуля до [http://oscada.org/websvn/listing.php?repname=OpenSCADA репозиторію дерева вихідних текстів OpenSCADA] ви маєте виконати наступне та дотримуватися наступних вимог:
+
Для подальшого розміщення розробленого модуля до [http://oscada.org/websvn/listing.php?repname=OpenSCADA репозиторію дерева вихідних текстів OpenSCADA], маєте виконати наступне і дотримуватися вимог:
* бути правовласником або автором коду цього модуля та розповсюджувати його за вільною ліцензією, віддаючи перевагу GPL;
+
* бути правовласником або автором коду і розповсюджувати його за вільною ліцензією, віддаючи перевагу GPL;
* приготувати та зберігати код модуля як архів окремої теки модуля будь якої з підсистем OpenSCADA із вимогам до вмісту:
+
* приготувати і зберігати код модуля як архів окремої теки модуля будь якої з підсистем OpenSCADA із вимогами до вмісту:
 
** вихідні тексти модуля на початку кожного файлу мають включати коректну інформацію прав копіювання, бути написаними та відформатованими згідно до якоїсь системи де перевагу треба надавати [[Special:MyLanguage/Documents/API#CodeDesign|стилю форматуванню основних модулів OpenSCADA]];
 
** вихідні тексти модуля на початку кожного файлу мають включати коректну інформацію прав копіювання, бути написаними та відформатованими згідно до якоїсь системи де перевагу треба надавати [[Special:MyLanguage/Documents/API#CodeDesign|стилю форматуванню основних модулів OpenSCADA]];
 
** файли локалізації модулів також мають бути коректними, актуальними та відповідно відформатованими.
 
** файли локалізації модулів також мають бути коректними, актуальними та відповідно відформатованими.
 
* написати коротку інформаційну сторінку модуля для розташування її на [[Special:MyLanguage/Modules|OpenSCADA Wiki]] таким-же чином, як і інші модулів поряд;
 
* написати коротку інформаційну сторінку модуля для розташування її на [[Special:MyLanguage/Modules|OpenSCADA Wiki]] таким-же чином, як і інші модулів поряд;
* для розташування цього модуля написати прямий запит у темі форуму "[http://oscada.org/ua/forum/topics/rozrobka_openscada/ Розробка OpenSCADA]", включаючи доказ працездатності від розробника OpenSCADA або коротке демонстраційним відео.
+
* для розташування цього модуля написати прямий запит у темі форуму "[http://oscada.org/ua/forum/topics/rozrobka_openscada/ Розробка OpenSCADA]", включаючи доказ працездатності від розробника OpenSCADA або коротке демонстраційне відео.
  
 
== Створення Нового Модуля ==
 
== Створення Нового Модуля ==

Revision as of 11:38, 13 April 2025

Other languages:
English • ‎mRussian • ‎Українська

Цей посібник первинно покликано допомогти у створені модулів для OpenSCADA. Створення модуля може знадобитися за бажання додати підтримку нового джерела даних або іншого розширення до OpenSCADA. Оскільки OpenSCADA є гранично модульною, то всі інтерфейси взаємодії із зовнішнім середовищем здійснюється за посередництвом розширення модулями типів:

  • бази даних;
  • комунікаційні інтерфейси, транспорти;
  • протоколи комунікаційних інтерфейсів;
  • джерела даних та збір даних;
  • архіви-історія (повідомлень та значень);
  • інтерфейси користувача (GUI, TUI, WebGUI, speach, signal ...);
  • додаткові модулі, спеціальні.

Але оскільки транспортні інтерфейси, реалізовані модулями, дозволяють зв'язуватися із різними пристроями на них, то цей документ розширено короткою інструкцією з посиланнями щодо створення внутрішніх Функцій, DAQ-Шаблонів, UI-Віджетів, а також оформлення Бібліотек із ними для розташування і публікації у офіційній колекції бібліотек OpenSCADA.

Для подальшого розміщення розробленого модуля до репозиторію дерева вихідних текстів OpenSCADA, маєте виконати наступне і дотримуватися вимог:

  • бути правовласником або автором коду і розповсюджувати його за вільною ліцензією, віддаючи перевагу GPL;
  • приготувати і зберігати код модуля як архів окремої теки модуля будь якої з підсистем OpenSCADA із вимогами до вмісту:
    • вихідні тексти модуля на початку кожного файлу мають включати коректну інформацію прав копіювання, бути написаними та відформатованими згідно до якоїсь системи де перевагу треба надавати стилю форматуванню основних модулів OpenSCADA;
    • файли локалізації модулів також мають бути коректними, актуальними та відповідно відформатованими.
  • написати коротку інформаційну сторінку модуля для розташування її на OpenSCADA Wiki таким-же чином, як і інші модулів поряд;
  • для розташування цього модуля написати прямий запит у темі форуму "Розробка OpenSCADA", включаючи доказ працездатності від розробника OpenSCADA або коротке демонстраційне відео.

1 Створення Нового Модуля

Модулі в OpenSCADA представляють із себе поділювані бібліотеки, які підключаються до ядра OpenSCADA динамічно при запуску або під час функціювання програми. Багато модулів у процесі функціювання можуть бути відключені, підключені та оновлені із менеджера модулів. Модулі також можуть бути вбудовані-включені до ядра OpenSCADA під час складання за посередництвом аргументу --enable-{ModName}=incl до скрипту конфігурації configure, про що можна дізнатися із посібника по збірці. Модулі OpenSCADA можуть бути семи типів згідно присутнім модульним підсистемам. Наразі модулі до OpenSCADA пишуться на мові програмування "C++", хоча у подальшому можлива поява біндінгів на інші мови.

At.png Для створення модулів до OpenSCADA необхідні знання програмування на мові C/C++, складальної системи AutoTools, а також базові знання ОС Linux та використовуваного дистрибутиву Linux.

У дереві вихідних текстів, у гілці кожної підсистеми, для спрощення створення нових модулів передбачено теку "=Tmpl=" із шаблоном модуля відповідної підсистеми. Розробник нового модуля може взяти цю теку та скопіювати її з ім'ям свого нового модуля, хоча він також завжди може використати у якості зразка будь який реальний функціонуючий модуль якщо його новий близький за структурою. Передбачено можливість створення модулів у дереві вихідних текстів проєкту OpenSCADA або як незалежного проєкту зовнішнього модуля до OpenSCADA.

1.1 Створення у дереві вихідних текстів проєкту OpenSCADA

Створювати нові модулі у дереві вихідних текстів проєкту OpenSCADA має сенс у випадку подальших планів передачі нового модуля проєкту OpenSCADA. Оскільки модуль не має суперечити духу відкритого проєкту та ліцензії на основі якої розробляється та розповсюджується OpenSCADA то ліцензією нового модуля вочевидь має бути одна із вільних ліцензій.

Процедура створення нового модуля з включенням до дерева вихідних текстів на основі шаблону в цілому є простішою за процедуру для зовнішнього модуля та включає в себе кроки:

1. Отримати дерево вихідних текстів проєкту OpenSCADA для:
  • Робочої (Work) гілки:
svn co svn://oscada.org/trunk/OpenSCADA
  • гілки стабільного релізу — НЕБАЖАНО, оскільки до стабільних LTS релізів приймаються лише виправлення та ця інструкція потребує версії 0.9 або вище:
svn co svn://oscada.org/tags/openscada_0.9
2. Скопіювати теку шаблону з назвою нового модуля "NewMod", наприклад, для підсистеми "БД":
cd OpenSCADA/src/moduls/bd; cp -r =Tmpl= NewMod; cd NewMod; rm -f configure.ac
для підсистеми "Збір Даних" шлях наступний — "OpenSCADA/src/moduls/daq"
для підсистеми "Архіви-Історія" шлях наступний — "OpenSCADA/src/moduls/arhiv"
для підсистеми "Транспорти" шлях наступний — "OpenSCADA/src/moduls/transport"
для підсистеми "Транспортні Протоколи" шлях наступний — "OpenSCADA/src/moduls/protocol"
для підсистеми "Користувацькі Інтерфейси" шлях наступний — "OpenSCADA/src/moduls/ui"
для підсистеми "Спеціальні" шлях наступний — "OpenSCADA/src/moduls/special"
3. Редагувати файл "module.cpp" щодо:
також може здійснюватися автоматично за допомогою: sed -i "s/Tmpl/NewMod/g" *.{cpp,h}
  • зміни назви функцій вбудування-включення модуля згідно назви нового модуля:
"TModule::SAt bd_Tmpl_module( int n_mod )" —> "TModule::SAt bd_NewMod_module( int n_mod )"
"TModule *bd_Tmpl_attach( const TModule::SAt &AtMod, const string &source )" —> "TModule *bd_NewMod_attach( const TModule::SAt &AtMod, const string &source )"
  • інформації про модуль у файлі "module.cpp", а саме ділянка:
//************************************************
//* Modul info!                                  *
#define MOD_ID          "NewMod"
#define MOD_NAME        _("DB NewMod")
#define MOD_TYPE        SDB_ID
#define VER_TYPE        SDB_VER
#define MOD_VER         "0.0.1"
#define AUTHORS         _("MyName MyFamily")
#define DESCRIPTION     _("BD NewMod description.")
#define MOD_LICENSE     "GPL2"
4. Відредагувати конфігурацію складання модуля у файлі "Makefile.am" щодо:
також може здійснюватися автоматично за допомогою: sed -i "s/Tmpl/NewMod/g" Makefile.am
EXTRA_DIST = *.h po/*

if NewModIncl
noinst_LTLIBRARIES = db_NewMod.la
db_NewMod_la_CXXFLAGS = -DMOD_INCL -fpic
db_NewMod_la_LIBTOOLFLAGS = --tag=disable-shared
db_NewMod_la_LDFLAGS = -module
else
oscd_modul_LTLIBRARIES = db_NewMod.la
db_NewMod_la_CXXFLAGS =
db_NewMod_la_LIBTOOLFLAGS = --tag=disable-static
db_NewMod_la_LDFLAGS = -module -avoid-version $(top_builddir)/src/liboscada.la
endif

db_NewMod_la_CXXFLAGS += $(NewMod_CFLAGS)
db_NewMod_la_LDFLAGS += $(NewMod_LDLAGS)
db_NewMod_la_SOURCES = module.cpp

I18N_mod = $(oscd_modulpref)NewMod
include ../../../../I18N.mk
5. Додати запис нового модуля в кінець секції підсистеми конфігураційного файлу "OpenSCADA/configure.ac" складальної системи OpenSCADA:
  • в кінець секції "DB modules" для підсистеми "БД":
AX_MOD_DB_EN(NewMod, [disable or enable[=incl] compilation module DB.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "DAQ modules" для підсистеми "Збір Даних":
AX_MOD_DAQ_EN(NewMod, [disable or enable[=incl] compilation module DAQ.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "Archive modules" для підсистеми "Архіви-Історія":
AX_MOD_Archive_EN(NewMod, [disable or enable[=incl] compilation module Archive.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "Transport modules" для підсистеми "Транспорти":
AX_MOD_Transport_EN(NewMod, [disable or enable[=incl] compilation module Transport.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "Transport protocol modules" для підсистеми "Транспортні Протоколи":
AX_MOD_TrProt_EN(NewMod, [disable or enable[=incl] compilation module Protocol.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "UI modules" для підсистеми "Користувацькі Інтерфейси":
AX_MOD_UI_EN(NewMod, [disable or enable[=incl] compilation module UI.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
  • в кінець секції "Special modules" для підсистеми "Спеціальні":
AX_MOD_Special_EN(NewMod, [disable or enable[=incl] compilation module Special.NewMod], disable, incl, [
    # Код перевірки зовнішніх бібліотек модуля
])
6. Тепер новий модуль можна скласти у складі OpenSCADA після переформування складальної системи:
autoreconf -if; ./configure --enable-NewMod; make
7. Опублікувати — сформувати латку із вашим модулем та надіслати її розробникам OpenSCADA:
cd OpenSCADA; make distclean; rm -rf src/moduls/bd/NewMod/{Makefile.in,.deps}
svn add src/moduls/bd/NewMod; svn diff > NewMod.patch

1.2 Створення зовнішнього модуля до OpenSCADA

Створення зовнішнього модуля до OpenSCADA може мати сенс у випадку розробки інтерфейсу інтеграції з комерційними системами, які вимагають закриття коду взаємодії, а також у випадку інших реалізацій комерційних інтерфейсів при яких модуль до OpenSCADA отримує статус окремого проєкту, розповсюджується та підтримується незалежно, часто у вигляді бінарних збірок під конкретну платформу та версію OpenSCADA. Ліцензія таких модулів відповідно може бути будь якою.

Процедура створення нового зовнішнього модуля на основі шаблону багато в чому схожа на попередню процедуру та включає в себе кроки:

1. Отримати вихідні текстів проєкту OpenSCADA — для зовнішнього модуля у якості джерела шаблону можна використати будь які файли OpenSCADA версії більш 0.9, оскільки із них потрібно скопіювати лише теку "=Tmpl=" та декілька файлів для збірки.
2. Скопіювати теку шаблону з ім'ям нового модуля "NewMod", наприклад, для підсистеми "БД"; та вже в ній створити та скопіювати потрібні файли зовнішнього модуля. В подальшому інформаційні файли проєкту "COPYING", "NEWS", "README", "AUTHORS" та "ChangeLog" потрібно заповнити згідно сутності нового модуля:
cp -r OpenSCADA/src/moduls/bd/=Tmpl= NewMod; touch NewMod/{NEWS,README,AUTHORS,ChangeLog}; cp OpenSCADA/I18N.mk NewMod/
для підсистеми "Збір Даних" шлях наступний — "OpenSCADA/src/moduls/daq/=Tmpl="
для підсистеми "Архіви-Історія" шлях наступний — "OpenSCADA/src/moduls/arhiv/=Tmpl="
для підсистеми "Транспорти" шлях наступний — "OpenSCADA/src/moduls/transport/=Tmpl="
для підсистеми "Транспортні Протоколи" шлях наступний — "OpenSCADA/src/moduls/protocol/=Tmpl="
для підсистеми "Користувацькі Інтерфейси" шлях наступний — "OpenSCADA/src/moduls/ui/=Tmpl="
для підсистеми "Спеціальні" шлях наступний — "OpenSCADA/src/moduls/special/=Tmpl="
3. Відредагувати інформацію модуля у файлі "module.cpp" аналогічно цьому пункту попереднього розділу.
4. Відредагувати конфігурацію збірки модуля у файлі "Makefile.am" аналогічно цьому пункту попереднього розділу, окрім:
  • замість "db_NewMod_la_LDFLAGS = -module -avoid-version $(top_builddir)/src/liboscada.la" записати "db_NewMod_la_LDFLAGS = -module -avoid-version", тобто видалити "$(top_builddir)/src/liboscada.la"
  • замість "include ../../../../I18N.mk" записати "include I18N.mk", тобто видалити шлях "../../../../"
5. Відредагувати файл конфігурації складальної системи "configure.ac" щодо:
також може здійснюватися автоматично за допомогою: sed -i "s/Tmpl/NewMod/g" configure.ac
  • "AC_INIT([Tmpl],[0.0.1],[my@email.org])" — інформація про модуль: ім'я, версія та Ел.Пошта проєкту
  • "AM_CONDITIONAL([TmplIncl],[test])" — "AM_CONDITIONAL([NewModIncl],[test])"
6. Встановити пакет розробки OpenSCADA "openscada-dev" або "openscada-devel" — у зв'язку з тим, що модуль зовнішній та вихідні файли OpenSCADA потрібні лише на першому етапі його створення, то необхідно встановлювати пакет розробки OpenSCADA, який містить заголовні файли та бібліотеки.
7. Тепер новий модуль можна скласти, після формування складальної системи:
autoreconf -if; ./configure; make

1.3 API of the module

OpenSCADA API for the developer of OpenSCADA and modules to it is described in the document "OpenSCADA API", which should always be on hand at development for OpenSCADA. This document focuses on the detailed explanation of the main points of the modular API.

Modules in OpenSCADA are implemented as shared libraries and one such library can contain many modules of the OpenSCADA subsystems, actually acting as a container. Those containers also can be included-builtin in the OpenSCADA Core Library if you build very tightly solutions.

The first step in connecting the shared libraries (SO — Shared Object) is the connection of the initialization functions. These functions should be defined as usual "C" functions to avoid distortion of them names. Usually this is done as follows:

//================== CUT =========================
extern "C"
{
#ifdef MOD_INCL
    TModule::SAt bd_Tmpl_module( int n_mod )
#else
    TModule::SAt module( int n_mod )
#endif
    {
        if(n_mod == 0) return TModule::SAt(MOD_ID, MOD_TYPE, VER_TYPE);
        return TModule::SAt("");
    }

<!--T:348-->
#ifdef MOD_INCL
    TModule *bd_Tmpl_attach( const TModule::SAt &AtMod, const string &source )
#else
    TModule *attach( const TModule::SAt &AtMod, const string &source )
#endif
    {
        if(AtMod == TModule::SAt(MOD_ID,MOD_TYPE,VER_TYPE)) return new BDTmpl::BDMod(source);
        return NULL;
    }
}
//================== CUT =========================

The entry point of any module are the following functions:

  • TModule::SAt module( int n_mod ), TModule::SAt {modTp}_{modNm}_module( int n_mod ) — are used to scan the list and information about all modules in the library. The first function is used during the implementation of modules in an external shared library, and the second during their including-embedding in the OpenSCADA core, where modTp corresponds to the type of the module, and modNm is its ID.
  • TModule *attach( const TModule::SAt &AtMod, const string &source ), TModule *{modTp}_{modNm}_attach( const TModule::SAt &AtMod, const string &source ) — is used to directly connect-open the selected module by creating a root object of the module inherited from TModule. The first function is used during the implementation of modules in an external shared library, and the second during the including-embedding of them into the OpenSCADA core, where modTp and modNm correspond to the previous function.

Common to all modules is the inheritance of the root object-class of the module from the class of the module subsystem TModule, which indicates the presence of a common part of the module interface, which we will consider further. To get a vision of the architecture of the modules in the context of the overall OpenSCADA architecture, it is strongly recommended to have the overall OpenSCADA class diagram in front of your eyes!

All module interface objects inherit the node class TCntrNode, which provides the control interface mechanism. One task of the mechanism is to provide the object configuration interface in any OpenSCADA configurator.

Common API
TCntrNode — OpenSCADA Node:
  • virtual void preEnable( int flag );, virtual void postEnable( int flag ); — connecting the module to the dynamic tree of objects, called before and after the actual activation of the module, respectively.
  • virtual void preDisable( int flag );, virtual void postDisable( int flag ); — excluding the module from the dynamic tree of objects before freeing the object, called before and after the actual exclusion of the module, respectively.
  • virtual void load_( TConfig *cfg );, virtual void load_( ); — loading the module from the "cfg" storage context and in general, called at the stage of loading the module configuration from the storage.
  • virtual void save_( ); — saving the module, called at the stage of saving the configuration of the module to the storage, usually at the initiative of the user.
TModule — OpenSCADA Module:
  • virtual void modStart( ); — module starting, called at the stage of starting tasks of the module's background functions, if these are provided by the module.
  • virtual void modStop( ); — stopping the module, called at the stage of stopping the tasks of performing the background functions of the module, if these are provided by the module.
  • virtual void modInfo( vector<string> &list ); — a request for a list of information properties of the module, which is provided with a standard set of properties "Module", "Name", "Type", "Source", "Version", "Author", "Description", "License", and which can be extended by own-specific properties.
  • virtual string modInfo( const string &name ); — a request for the information element name at which there performed also the requests processing of own-specific properties of the module.
  • void modFuncReg( ExpFunc *func ); — registration of the module's exported function, which is part of the mechanism of intermodule interaction that registers the internal function of the module for external call by the name-symbol of the function and its pointer relative to the object of the module. Currently, this mechanism is used by few modules!
  • virtual void perSYSCall( unsigned int cnt ); — a call from the system-service thread-task with the periodicity 10 seconds and a second counter "cnt", can be used to perform periodic-rare service procedures.
API of the modules of the "Data Bases (DB)" subsystem
Intended for the integration of OpenSCADA with a database or DBMS which is implemented by the module. Provides two common approaches in the modules implementation:
  1. ANSI SQL Mode — is the simplest way which means of direct using the core functions fieldSQLSeek(), fieldSQLGet(), fieldSQLSet(), fieldSQLDel() in fieldSeek(), fieldGet(), fieldSet(), fieldDel() respectively; all SQL-modules are used now this approach.
  2. Full Implementation — is the hardest way which means of the complete implementation; modules of such approach using are whether old or specific ones: DBF, LDAP.
TTypeBD->TModule — the root module object of the "DB" subsystem:
  • virtual string features( ); — keyword list of features supported by the DB.
  • virtual int lsPr( ); — the DB priority base [0...9] in the generic storages list.
  • virtual TBD *openBD( const string &id ); — called when a new DB object is opened or created by this module with the identifier id.
TBD — the database object:
  • virtual void enable( ); — enabling the DB.
  • virtual void disable( ); — disabling the DB.
  • virtual void allowList( vector<string> &list ) const; — requesting the table list in the DB.
  • virtual void sqlReq( const string &req, vector< vector<string> > *tbl = NULL, char intoTrans = EVAL_BOOL ); — processing the SQL-query req to the DB and receiving the result in the form of the tbl table, if the selection request and the pointer are non-zero. When intoTrans is set to TRUE, a transaction must be open for the request, and closed to FALSE. This function should be implemented for DBMSs that support SQL-queries.
  • virtual void transCloseCheck( ); — the periodically called function to check the transactions and closing the old or contain many requests ones.
  • virtual TTable *openTable( const string &name, bool create ); — called when you open or create a new table object.
TTable — the table object in the database:
  • void fieldStruct( TConfig &cfg ); — getting the current structure of the table in the object cfg.
  • bool fieldSeek( int row, TConfig &cfg, const string &cacheKey = "" ); — sequential scanning of table entries by incrementing row at the object cfg and returning FALSE after completion, with addressing by active keyUse() key fields. The cache key cacheKey is specified to prefetch the full response to the cache, extracting the following records from there.
  • void fieldGet( TConfig &cfg ); — request of the record specified in the "cfg" object with addressing by key fields.
  • void fieldSet( TConfig &cfg ); — transfer of the record specified in the "cfg" object with addressing by key fields.
  • void fieldDel( TConfig &cfg ); — deletion of the specified record by the key fields of the "cfg" object.
Specific for SQL Data Bases
  • void fieldFix( TConfig &cfg, const string &langLs = "" ); — correction of DB table structure to cfg and for translation languages langLs, usually after a failed transfer.
  • string getSQLVal( TCfg &cf, uint8_t RqFlg = 0 ); — return a SQL-specific wrapped cf value for the ReqFlg flags of the RqFlg call.
  • void setSQLVal( TCfg &cf, const string &vl, bool tr = false ); — parsing the SQL value vl to translate tr and with writing to cf.
API of the modules of the "Transports" subsystem
Provides OpenSCADA communications through the interface, often it is the network one which is implemented by the module.
TTypeTransport->TModule — the root module object of the "Transports" subsystem:
  • virtual bool isNetwork( ); — the sign of network implementation by this module.
  • virtual string outAddrHelp( ); — address format help of the output transports.
  • virtual TTransportIn *In( const string &id, const string &stor ); — called when a new input transport object is opened or created by this module with the identifier id and the storage stor.
  • virtual TTransportOut *Out( const string &name, const string &stor ); — called when a new output transport object is opened or created by this module with the identifier id and the storage stor.
TTransportIn — the input transport object:
  • virtual unsigned keepAliveReqs( ); — maximum Keep Alive requests.
  • virtual unsigned keepAliveTm( ); — keep Alive time.
  • virtual string getStatus( ); — getting the status of the transport.
  • virtual void start( ); — starting the transport.
  • virtual void stop( ); — stopping the transport.
  • virtual int writeTo( const string &sender, const string &data ); — sending data backward to the sender.
TTransportOut — the output transport object:
  • virtual string timings( ); — transport timeouts.
  • virtual unsigned short attempts( ); — connection attempts.
  • virtual string getStatus( ); — getting the status of the transport.
  • virtual void setTimings( const string &vl, bool isDef = false ); — setting the transport timeouts, as default one for isDef.
  • virtual void setAttempts( unsigned short vl ); — setting the connection attempts.
  • virtual void start( int time = 0 ); — starting the transport with the connection timeout time. When you start the output transport the actual connection to the remote station is established for the interfaces that works by the connection. At this time the errors can occur if the connection is impossible and the transport should return to the stopped state.
  • virtual void stop( ); — stopping the transport.
  • virtual int messIO( const char *oBuf, int oLen, char *iBuf = NULL, int iLen = 0, int time = 0 ); — sending of the data over the transport. The waiting timeout time of the connection in milliseconds. The time in negative disables the transport's request/respond mode and allows for the independently reading/writing to a buffer IO, with the reading timeout time in absolute.
API of the modules of the "Transport protocols" subsystem
Provides OpenSCADA with the protocol layer communications, implemented by the module, for the data access from the external systems and for the OpenSCADA data providing for the external systems.
TProtocol->TModule — the root module object of the "Transport protocols" subsystem:
  • virtual void itemListIn( vector<string> &ls, const string &curIt = "" ); — the list ls of the input protocol sub-elements from the current item curIt, if the protocol provides them. It is used when selecting an object in the input transport configuration.
  • virtual void outMess( XMLNode &io, TTransportOut &tro ); — the data transfer by the objects of the OpenSCADA core in the XML tree io to the remote system via the tro transport and the current output protocol. Presenting the data in the XML tree is non-standardized and specific to the logical structure of the protocol. This data are serialized — converted in a sequence of bytes according to the protocol, and are sent via the specified tro output transport by the messIO() function.
  • virtual TProtocolIn *in_open( const string &id ); — called when a new transport protocol object is opened or created by this module with the identifier id.
TProtocolIn — the input object of the transport protocol of the input requests processing from the input transport object TTransportIn. For each session of the input request the object of the associated input protocol is created, which remains alive until completion of the full "request->answer" session. Address of the transport, which opened the protocol instance, is specified in srcTr():
  • virtual unsigned waitReqTm( ) — the request waiting time on the input transport in milliseconds, call after what to the protocol with the empty message — the polling mode. Setting it to zero disable the polling mode.
  • virtual void setSrcTr( TTransportIn *vl ) — setting of the transport-source of the opening of the session of the input protocol.
  • virtual void setSrcAddr( const string &vl ); — setting of the sender address.
  • virtual bool mess( const string &request, string &answer ); — transfer of the request data sequence to the protocol object for it parsing accordingly to the protocol implementation. The protocol function should process the request, generate the response in answer and return FALSE in the case of the completeness of the request. If the request is not complete, it is necessary to return TRUE for the transport to indicate the "expectation of the completion", the previous parts of the request should be saved in the context of the protocol object.
API of the modules of the "Data AcQuisition" subsystem
Provides the realtime data acquisition from the external systems or it formation in the calculators, implemented by the module. That is the main subsystem since SCADA is about the Data Acquisition primarily. As the main subsystem it provides several approaches in the modules implementation, which mostly about the attributes structure formation and storing:
  1. Static formation through definition a set of the parameter types inherited from TTypeParam, that is the structures applying is performed as an attributes set with the parameter type change. This method is least flexible and it used by such modules: GPIO, SMH2Gi, AMRDevs.
  2. Dynamic formation with the structure container TElem managing in the parameter object TParamContr. This method is most flexible and used in most modules which mean of the structure be configurable.
  3. As an extension of the dynamic formation there is the Logical Level parameter type, what can be added to any module, but that used mostly in the universal data sources: LogicLev, ModBus, Siemens, OPC_UA.
TTypeDAQ->TModule — the root module object of the "Data AcQuisition" subsystem:
  • virtual bool compileFuncLangs( vector<string> *ls = NULL ); — request the list ls of languages for which it is realised the possibility of formation of user procedures in this module, and check for fact of that support.
  • virtual void compileFuncSnthHgl( const string &lang, XMLNode &shgl ); — request the rules of the syntax highlight shgl for the specified language lang.
  • virtual string compileFunc( const string &lang, TFunction &fnc_cfg, const string &prog_text, const string &usings = "", int maxCalcTm = 0 ); — compiling-registering of the user function on the supported programming language lang and on the source code of procedure prog_text, based on the procedure parameters fnc_cfg. Returns address of the compiled function's object, ready for execution.
  • virtual bool redntAllow( ); — state of support the redundancy mechanisms by the module. Should be overridden and return TRUE if supported, otherwise FALSE.
  • virtual TController *ContrAttach( const string &id, const string &daq_db ); — called when a new controller object is opened or created by this module with the identifier id.
TController — the data source controller object. In the context of the object is usually run a task of the periodic or scheduled polling of the realtime data of one physical controller or physically separated block of data. In the case of data getting by the packages, they are placed directly into the archive associated with the parameter attribute TVAl::arch(), and the current value is set by the TVAl::set() function with the attribute "sys"=TRUE:
  • virtual string getStatus( ); — request function of the controller status.
  • virtual void enable_( ); — enabling of the controller object. Usually at this stage the initialisation of the parameters' objects and their interfaces in the form of attributes is made, the attributes can sometimes be requested from the associated remote source.
  • virtual void disable_( ); — disabling the controller object.
  • virtual void start_( ); — starting the controller object. Usually at this stage the task of periodic or scheduled polling is created and started.
  • virtual void stop_( ); — stopping the controller object.
  • virtual void redntDataUpdate( ); — operation of the data receiving from the backup station, called automatically by the service procedure of the redundancy scheme of the subsystem.
  • virtual string catsPat( ); — list of the regular expression rules, separated by '|', for matching by category the messages generated by the object.
  • virtual void messSet( const string &mess, int lev, const string &type2Code = "OP", const string &prm = "", const string &cat = "" ); — formation of the DAQ-sourced messages for the parameter object prm (PrmId) or the controller object in whole if the parameter object is not specified, for the message mess, level lev and for the type code type2Code. This function generates the messages with the unified DAQ-transparency category "{type2Code}{ModId}:{CntrId}[.{prm}][:{cat}]".
  • virtual TParamContr *ParamAttach( const string &id, int type ); — called when a new object of the controller parameter is opened or created by this module with the identifier id.
TParamContr->TValue — the controller parameter object of the data source. Contains attributes with real data in a set defined by physically available data. The values to the attributes come from the polling task of the controller, in the asynchronous mode, or are requested during the access, in the synchronous mode, and through the methods of the inherited type TValue:
  • virtual TElem *dynElCntr( ); — container of the dynamic elements of the DAQ attributes. Defined mostly by the logical level sources what provide such kind containers.
  • virtual void enable( ); — enabling the parameter object, the formation of the attributes set and filling them with the value of unreliability is made.
  • virtual void disable( ); — disabling the parameter object.
  • virtual void setType( const string &tpId ); — called to change the parameter type to tpId and can be processed in the module object to change own data.
  • virtual TVal* vlNew( ); — called at the stage of a new attribute creation. Can be overridden to implement special behavior within its object, inherited from TVal, when accessing the attribute.
  • virtual void vlGet( TVal &vo ); — called for the attribute vo with the direct reading mode TVal::DirRead when reading the value in order to directly-synchronous read from the physical source or the object buffer.
  • virtual void vlSet( TVal &vo, const TVariant &vl, const TVariant &pvl ); — called for the attribute vo with the direct recording mode TVal::DirWrite when setting the value in order to directly-synchronous set to the physical source or the object buffer, with the previous value pvl.
  • virtual void vlArchMake( TVal &val ); — called at the stage of creation the values archive with the val attribute as the source in the order to initialise the qualitative characteristics of the archive buffer according to the characteristics of the data source and polling.
API of the modules of the "Archives-History" subsystem
Used for archiving and maintaining the history of messages and realtime values received in the "Data AcQuisition" subsystem, and in the means implemented by the module.
TTypeArchivator->TModule — the root module object of the "Archives-History" subsystem:
  • virtual TMArchivator *AMess( const string &id, const string &stor ); — called when a new object of the message archiver is opened or created by this module with the identifier id and in the storage stor.
  • virtual TVArchivator *AVal( const string &id, const string &stor ); — called when a new object of the value archiver is opened or created by this module with the identifier id and in the storage stor.
TMArchivator — the message archiver object.
  • virtual void redntDataUpdate( ); — operation of the data receiving from the backup station, called automatically by the service procedure of the redundancy scheme of the subsystem.
  • virtual void start( ); — starting the archiver object, the archiver starts for receiving messages and placing them into the storage.
  • virtual void stop( ); — stopping the archiver object.
  • virtual time_t begin( ); — begin time of the archiver data accordingly with the current state of the storage.
  • virtual time_t end( ); — end time of the archiver data accordingly with the current state of the storage.
  • virtual bool put( vector<TMess::SRec> &mess, bool force = false ); — placing the message group mess to the archiver. Returns TRUE on the successful operation. Set force for direct writing to the archiver omit the redundancy.
  • virtual time_t get( time_t bTm, time_t eTm, vector<TMess::SRec> &mess, const string &category = "", char level = 0, time_t upTo = 0 ); — getting the messages to mess from the archiver for the specified filter parameters. Returns time of the request stop, useful for proceeding from this position as the end time, i.e. iteratively digging into the story. The filter specified by the time range [bTm...eTm], category rules, level and limited up to the time upTo. In the absence of a direct definition of the limiting time upTo, this limitation is set to prmInterf_TM — 7 seconds.
TVArchivator — the value archiver object.
  • virtual void start( ); — starting the archiver object, the archiver starts for receiving values and placing them into the storage.
  • virtual void stop( bool full_del = false ); — stopping the archiver object with the ability to completely remove its data from the storage at full_del.
  • virtual TVArchEl *getArchEl( TVArchive &arch ); — getting the element object of the value archive for the specified archive arch.
  • virtual void pushAccumVals( ); — pushing the accumulated values by the archivation task, for the accumulative archivers.
TVArchEl — the element object of the value archiver.
  • virtual void fullErase( ); — called to complete removal of the archive part in the archiver.
  • virtual int64_t end( ); — end time in microseconds of the available values in the archive of the archiver.
  • virtual int64_t begin( ); — begin time in microseconds of the available values in the archive of the archiver.
  • virtual TVariant getValProc( int64_t *tm, bool up_ord ); — requesting of one value from the archive for the time tm and fine-tuning to the upper value in the sampling grid up_ord.
  • virtual void getValsProc( TValBuf &buf, int64_t beg, int64_t end ); — requesting of a value group to buf from the archive and for the time range [beg...end].
  • virtual void setValsProc( TValBuf &buf, int64_t beg, int64_t end, bool toAccum ); — setting of the value group buf to the archive, for the time range [beg...end] and through the accumulation toAccum.
API of the modules of the "User Interfaces" subsystem
The user interface is formed according to the concept and mechanisms of external known standards and libraries.
TUI->TModule — the root module object of the "User Interfaces" subsystem:

At.png It contains no specific functions!

API of the modules of the "Special" subsystem
Implements the specific functions that are not included in any of the above subsystems. The specific functions are formed accordingly to their own need and with using all features of the OpenSCADA API.
TSpecial->TModule — the root module object of the "User Interfaces" subsystem:

At.png It contains no specific functions!


Для зручності прямої адресації до кореневого об'єкта модуля із будь якого об'єкта нижче за ієрархією, рекомендується визначити глобальну змінну "mod" у області імен модуля, з ініціалізацією її у конструкторі кореневого об'єкта. Також, для прозорого перекладу текстових повідомлень модуля рекомендується визначити шаблони функцій виклику перекладу повідомлень модуля "_({Повідомлення})" та "trS({Повідомлення})" як:

#undef _
#define _(mess) mod->I18N(mess).c_str()
#undef trS
#define trS(mess) mod->I18N(mess,mess_PreSave)

У конструкторі кореневого об'єкту модуля успадкованого від TModule необхідно встановити основну інформацію модуля викликом функції void modInfoMainSet({Ім'я}, {Тип}, {Версія}, {Автори}, {Опис}, {Ліцензія}, {Джерело}) після ініціалізації швидкого посилання "mod" на кореневий об'єкт цього модуля.

Подальше отримання файлу шаблону перекладів "po/oscd_NewMod.pot" текстових повідомлень "_({Повідомлення})" та "trS({Повідомлення})", а також оновлення-актуалізація файлів вже існуючих перекладів "po/{uk|de|ru|...}.po" здійснюється командою у теці модуля make messages.

При вирішенні завдань нового модуля може знадобитися розширення параметрів конфігурації, що здійснюється у віртуальній функції void cntrCmdProc( XMLNode *req );. Вміст цієї функції, який додає властивості, у модулі SQLite має вигляд:

void MBD::cntrCmdProc( XMLNode *opt )
{
    //Getting the page info
    if(opt->name() == "info") {
        TBD::cntrCmdProc(opt);
        ctrMkNode("fld",opt,-1,"/prm/cfg/ADDR",EVAL_STR,enableStat()?R_R___:RWRW__,"root",SDB_ID,3,
            "dest","sel_ed","select","/prm/cfg/dbFsList","help",
                    _("SQLite DB address must be written as: \"{FileDBPath}\".\n"
                      "Where:\n"
                      "  FileDBPath - full path to DB file (./oscada/Main.db).\n"
                      "               Use the empty path to create a temporary database on the disk.\n"
                      "               Use \":memory:\" to create a temporary database in memory."));
        if(reqCnt)
            ctrMkNode("comm",opt,-1,"/prm/st/end_tr",_("Close opened transaction"),RWRW__,"root",SDB_ID);
    }
    //Processing for commands to the page
    string a_path = opt->attr("path");
    if(a_path == "/prm/cfg/dbFsList" && ctrChkNode(opt)) {
        opt->childAdd("el")->setText(":memory:");
        TSYS::ctrListFS(opt, addr(), "db;");
    }
    else if(a_path == "/prm/st/end_tr" && ctrChkNode(opt,"set",RWRW__,"root",SDB_ID,SEC_WR) && reqCnt) transCommit();
    else TBD::cntrCmdProc(opt);
}

Перша половина цієї функції обслуговує інформаційні запити "info" з переліком та властивостями полів конфігурації. Друга половина обслуговує решту команд на отримання, встановлення значення та інше. Виклик TBD::cntrCmdProc(opt); використовується для отримання успадкованого інтерфейсу. Детальніше про призначення використаних функцій дивіться у інтерфейсі управління, а також у вихідних текстах існуючих модулів.

Об'єкт TCntrNode окрім функції інтерфейсу управління надає уніфіковані механізми контролю за модифікацією конфігурації об'єкта, завантаження, збереження та видалення дублікатів конфігурації у сховищі. Для встановлення прапорця модифікації даних об'єкта можна використовувати функції modif() та modifG(), а специфічні до модуля дії із завантаження та збереження можна розташовувати у віртуальні функції:

  • void load_( TConfig *cfg );, void load_( ); — завантаження об'єкта зі сховища.
  • void save_( ); — збереження об'єкта у сховищі.

Дії із конфігурацією типово відбуваються за посередництвом об'єкта TConfig, яких містить набір визначених властивостей зі структурою та значеннями. Для прямого відображення властивостей об'єкта модуля він успадковується від TConfig, а нові властивості додаються командою:

fldAdd(new TFld("MOD_PRMS",trS("Module addition parameters"),TFld::String,TFld::FullText|TCfg::NoVal,"100000"));

Завантаження/збереження/видалення властивостей, вказаних у об'єкті TConfig, із/у/в сховище здійснюється командами:

TBDS::dataGet(fullDB(), owner().nodePath()+tbl(), *this);
TBDS::dataSet(fullDB(), owner().nodePath()+tbl(), *this);
TBDS::dataDel(fullDB(flag&NodeRemoveOnlyStor), owner().nodePath()+tbl(), *this, TBDS::UseAllKeys);

Де:

  • fullDB() — повна назва сховища у загальній формі;
  • owner().nodePath()+tbl() — загальний шлях до вузла об'єкта у конфігураційному файлі, представлений таблицею;
  • *this — цей об'єкт, успадкований від TConfig.

Для генерації налагоджувальних повідомлень відповідно до загальної концепції налаштувань необхідно використовувати функцію mess_debug() з умовою виклику залежно від ділянки вихідного тексту програми:

  • рідко викликувана ділянка — прямий виклик функції mess_debug(...);;
  • часто викликувана ділянка — умовний виклик if(mess_lev() == TMess::Debug) mess_debug(...);;
  • критична до продуктивності ділянка коду — обгортання у визначення OSC_DEBUG:
#ifdef OSC_DEBUG
  mess_debug(...);
#endif

2 Creating New Internal Items and Libraries with them

2.1 JavaLikeCalc Functions

2.2 DAQ-Templates

2.3 UI-Widgets