<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html class="client-nojs" dir="ltr" lang="en">
<head>
<meta charset="UTF-8" />
<title>Documents/How to/Create module - OpenSCADAWiki</title>
<meta content="MediaWiki 1.26.4" name="generator" />
<link href="https://www.gnu.org/copyleft/fdl.html" rel="copyright" />
<link href="files/doc.css" rel="stylesheet" /></head>
<body><div class="floatright"><a href="index.html"><img alt="OpenSCADA" src="../en/files/index.png" /></a></div><div id="mw_header">
			<div class="mw-indicators">
</div>
			<h1 id="firstHeading" lang="en">Documents/How to/Create module</h1>
		</div><div class="mw-content-ltr" dir="ltr" id="mw-content-text" lang="en"><div class="mw-pt-languages" dir="ltr" lang="en"><div class="mw-pt-languages-list autonym"><span class="mw-pt-languages-ui mw-pt-languages-selected mw-pt-progress mw-pt-progress--complete">English</span>&nbsp;• ‎<a class="mw-pt-progress mw-pt-progress--stub" href="../ru/How_to_Create_module.html" title="Документация/Как/Создать модуль (8% translated)">mRussian</a>&nbsp;• ‎<a class="mw-pt-progress mw-pt-progress--complete" href="../uk/How_to_Create_module.html" title="Документація/Як/Створити модуль (100% translated)">Українська</a></div></div>
<div style="float:right; border:1px solid gray; width:300px; padding:2px; margin-left: 10pt; margin-bottom: 10pt;">
<ul><li> <b>Author:</b> <a class="external" href="http://oscada.org/wiki/User:RomanSavochenko" title="User:RomanSavochenko">Roman Savochenko</a></li>
<li> <b>Sponsored by, for complete revision on 1.8 HD <span title="human-days, 1 HD — 10 hours">HD<sup style="color: blue">[!]</sup></span>:</b> SINGE SOFTWARE</li>
<li> <b>Initially created:</b> in <a class="external text" href="http://wiki.oscada.org/HomePageEn/Doc/ModuleBuild" rel="nofollow noreferrer noopener" target="_blank">the old Wiki</a> </li></ul>
</div>
<p>This manual is made to help in building the modules for OpenSCADA. The module creation may be required if you wish to add the support for new data source or other extension to OpenSCADA. Since OpenSCADA is an extremely modular system, all interfaces of interaction with the external environment are implemented by expanding it with modules of following types:
</p>
<ul><li> databases;</li>
<li> communication interfaces, transports;</li>
<li> protocols of the communication interfaces;</li>
<li> data sources and data acquisition;</li>
<li> archives-history (messages and values);</li>
<li> user interfaces (GUI, TUI, WebGUI, speech, signal ...);</li>
<li> additional modules, special.</li></ul>
<p><a class="image" href="http://oscada.org/wiki/File:At.png"><img alt="At.png" height="22" src="files/At.png" width="22" /></a> To create modules for OpenSCADA you need to have some experience in C/C++ programming language, the build system <a class="external text" href="http://en.wikipedia.org/wiki/GNU_build_system" rel="nofollow noreferrer noopener" target="_blank">AutoTools</a>, as well as basic knowledge of Linux and the distribution you are using.
</p><p>In order to post the developed module to the <a class="external text" href="http://oscada.org/websvn/listing.php?repname=OpenSCADA" rel="nofollow noreferrer noopener" target="_blank">OpenSCADA source tree repository</a>, you must do the following and comply with the following requirements:
</p>
<ul><li> be the copyright holder or the author of the module code and distribute it under any free license, GPL preferred;</li>
<li> prepare and store the module code as a separated archive of the module folder for any module subsystem of OpenSCADA with demands to the content:
<ul><li> the source texts of the module at the beginning of each file must include correct copyrights information, be written and formatted according to some system where preference should be given to the <a href="API.html#CodeDesign" title="Special:MyLanguage/Documents/API">formatting style of the main OpenSCADA modules</a>;</li>
<li> the localisation files of the module must be also correct, actual and proper formed.</li></ul></li>
<li> write a short information page of the module for placing it to <a class="external" href="http://oscada.org/wiki/Special:MyLanguage/Modules" title="Special:MyLanguage/Modules">the OpenSCADA Wiki</a> in way like to the other ones there;</li>
<li> for placing of this module, write a direct request in the forum topic "<a class="external text" href="http://oscada.org/en/forum/topics/openscada_development/" rel="nofollow noreferrer noopener" target="_blank">OpenSCADA development</a>", including proof of functionality from the OpenSCADA developer or a short demonstration video.</li></ul>
<div class="toc" id="toc"><div id="toctitle"><h2>Contents</h2></div>
<ul>
<li class="toclevel-1 tocsection-1"><a href="#Creating_a_New_Module"><span class="tocnumber">1</span> <span class="toctext">Creating a New Module</span></a>
<ul>
<li class="toclevel-2 tocsection-2"><a href="#Creation_in_the_sources_tree_of_the_OpenSCADA_project"><span class="tocnumber">1.1</span> <span class="toctext">Creation in the sources tree of the OpenSCADA project</span></a></li>
<li class="toclevel-2 tocsection-3"><a href="#Creation_an_external_module_to_OpenSCADA"><span class="tocnumber">1.2</span> <span class="toctext">Creation an external module to OpenSCADA</span></a></li>
</ul>
</li>
<li class="toclevel-1 tocsection-4"><a href="#API_of_the_module"><span class="tocnumber">2</span> <span class="toctext">API of the module</span></a></li>
</ul>
</div>

<h2><span class="mw-headline" id="Creating_a_New_Module"><span class="mw-headline-number">1</span> Creating a New Module</span></h2>
<p>Modules in OpenSCADA are the shared libraries, which are dynamically connected to the OpenSCADA core at startup or during the program operation. Many of the modules can be disabled, connected and updated during the operation from the <a href="Program_manual.html#CfgModSched" title="Special:MyLanguage/Documents/Program manual">module scheduler</a>. Modules can be also builtin-included into the OpenSCADA core during building by an argument <b>-enable-{ModName}=incl</b> to the <b>configure</b> configuration script, what you can learn from the <a href="How_to_Build_from_source.html" title="Special:MyLanguage/Documents/How to/Build from source">building manual</a>. The OpenSCADA modules can be of seven types according to the presented <a href="Program_manual.html#Modularity" title="Special:MyLanguage/Documents/Program manual">modular subsystems</a>. For now the modules to OpenSCADA are written in the "<b>C++</b>" programming language, although bindings for other languages may appear in the future.
</p><p>In the tree of the source texts, in the branch of each subsystem, to simplify the creation of new modules, the folder "=Tmpl=" with the module template of the corresponding subsystem is provided. The developer of the new module can take this folder and copy it with the name of his new module, although he can also always use as a sample any real working module if his new one is close in structure. You can create modules in the OpenSCADA sources tree or as an independent project of the external module for OpenSCADA.
</p>
<h3><span class="mw-headline" id="Creation_in_the_sources_tree_of_the_OpenSCADA_project"><span class="mw-headline-number">1.1</span> Creation in the sources tree of the OpenSCADA project</span></h3>
<p>It makes sense to create new modules in the sources tree of OpenSCADA project in case of further plans for the transfer of the new module to the OpenSCADA project. Since the module should not be contrary to the spirit of the open source project and license on the basis of which <a class="external text" href="http://oscada.org/en/main/about-the-project/licenses/" rel="nofollow noreferrer noopener" target="_blank">OpenSCADA is developed and distributed</a>, license of the new module obviously should be one of the free licenses.
</p><p>The procedure for creating a new module with inclusion in the source text tree based on a template is generally simpler than the procedure for an external module and includes the following steps:
</p>
<dl><dd>1. Get the source tree of the OpenSCADA project for:
<ul><li> <i>the Work branch:</i></li></ul>
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">svn co svn://oscada.org/trunk/OpenSCADA</span></dd></dl>
<ul><li> <i>the stable release branch — NOT RECOMMENDED, as only patches are accepted for stable LTS releases and this instruction requires version 0.9 or higher:</i></li></ul>
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">svn co svn://oscada.org/tags/openscada_0.9</span></dd></dl></dd>
<dd>2. Copy the template folder with the "NewMod" name of the new module, for example, for the "DB" subsystem:
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">cd OpenSCADA/src/moduls/bd; cp -r =Tmpl= NewMod; cd NewMod; rm -f configure.ac</span>
<dl><dd> <i>for the "DAQ" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>daq</b>"</dd>
<dd> <i>for the "Archive-History" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>arhiv</b>"</dd>
<dd> <i>for the "Transport" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>transport</b>"</dd>
<dd> <i>for the "Transport protocol" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>protocol</b>"</dd>
<dd> <i>for the "UI" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>ui</b>"</dd>
<dd> <i>for the "Special" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>special</b>"</dd></dl></dd></dl></dd>
<dd>3. Edit the "module.cpp" file for:
<dl><dd><dl><dd> <i>also can do that automatically by:</i> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">sed -i "s/Tmpl/NewMod/g" *.{cpp,h}</span></dd></dl></dd></dl>
<ul><li> <i>changing the name of the builtin-inclusion functions of the module according to the name of the new module</i>:</li></ul>
<dl><dd> "TModule::SAt <b>bd_Tmpl_module</b>( int n_mod )" —&gt; "TModule::SAt <b>bd_NewMod_module</b>( int n_mod )"</dd>
<dd> "TModule *<b>bd_Tmpl_attach</b>( const TModule::SAt &amp;AtMod, const string &amp;source )" —&gt; "TModule *<b>bd_NewMod_attach</b>( const TModule::SAt &amp;AtMod, const string &amp;source )"</dd></dl>
<ul><li> <i>information about the module in the "module.cpp" file, namely the section:</i></li></ul></dd></dl>
<div class="mw-highlight mw-content-ltr" dir="ltr" style="margin-left: 45px"><pre><span class="c1">//************************************************</span>
<span class="c1">//* Modul info!                                  *</span>
<span class="cp">#define MOD_ID          "NewMod"</span>
<span class="cp">#define MOD_NAME        _("DB NewMod")</span>
<span class="cp">#define MOD_TYPE        SDB_ID</span>
<span class="cp">#define VER_TYPE        SDB_VER</span>
<span class="cp">#define MOD_VER         "0.0.1"</span>
<span class="cp">#define AUTHORS         _("MyName MyFamily")</span>
<span class="cp">#define DESCRIPTION     _("BD NewMod description.")</span>
<span class="cp">#define MOD_LICENSE     "GPL2"</span>
</pre></div>
<dl><dd>4. Edit the module's building configuration in the "Makefile.am" file to:
<dl><dd><dl><dd> <i>also can do that automatically by:</i> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">sed -i "s/Tmpl/NewMod/g" Makefile.am</span></dd></dl></dd></dl></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
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
</pre>
<dl><dd>5. Add an entry of the new module to the end of the subsystem's section of the OpenSCADA building system configuration file "OpenSCADA/configure.ac":
<ul><li> <i>to the section "DB modules" end for the "DB" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_DB_EN(NewMod, [disable or enable[=incl] compilation module DB.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "DAQ modules" end for the "DAQ" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_DAQ_EN(NewMod, [disable or enable[=incl] compilation module DAQ.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "Archive modules" end for the "Archive-History" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_Archive_EN(NewMod, [disable or enable[=incl] compilation module Archive.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "Transport modules" end for the "Transport" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_Transport_EN(NewMod, [disable or enable[=incl] compilation module Transport.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "Transport protocol modules" end for the "Transport protocol" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_TrProt_EN(NewMod, [disable or enable[=incl] compilation module Protocol.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "UI modules" end for the "UI" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_UI_EN(NewMod, [disable or enable[=incl] compilation module UI.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd><ul><li> <i>to the section "Special modules" end for the "Special" subsystem:</i></li></ul></dd></dl>
<pre style="white-space: pre-wrap; margin-left: 30px">
AX_MOD_Special_EN(NewMod, [disable or enable[=incl] compilation module Special.NewMod], disable, incl, [
    # The code for external libraries of the module check
])
</pre>
<dl><dd>6. Now the new module can be built in OpenSCADA after the reorganisation of the building system:
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">autoreconf -if; ./configure --enable-NewMod; make</span></dd></dl></dd>
<dd>7. Publication — form a patch with your module and send it to the OpenSCADA developers:
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">cd OpenSCADA; make distclean; rm -rf src/moduls/bd/NewMod/{Makefile.in,.deps}</span></dd>
<dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">svn add src/moduls/bd/NewMod; svn diff &gt; NewMod.patch</span></dd></dl></dd></dl>
<h3><span class="mw-headline" id="Creation_an_external_module_to_OpenSCADA"><span class="mw-headline-number">1.2</span> Creation an external module to OpenSCADA</span></h3>
<p>Creation an external module to OpenSCADA may make sense in the case of the development the integration interface with business (commercial) systems that require proprietary interaction code, as well as in the case of other commercial interfaces implementations in which the module for the OpenSCADA acquire the status of the separate project, that is distributed and maintained independently often in the form of binary buildings for a specific platform and version of OpenSCADA. The license of such modules, respectively, can be arbitrary.
</p><p>The procedure for creation a new external module based on the template is largely similar to the previous procedure and includes the following steps:
</p>
<dl><dd>1. Get the source texts of the OpenSCADA project — for an external module as a source of the template you can use any OpenSCADA source files of version more than 0.9, because it is necessary to copy only the "=Tmpl=" directory and several files for build.</dd>
<dd>2. Copy the template directory with the "NewMod" name of the new module, for example, for the "DB" subsystem; and in that directory already create and copy the necessary files of the external module. Further, the information files of the project "COPYING", "NEWS", "README", "AUTHORS" and "ChangeLog" must be filled accordingly to the nature of the new module.
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">cp -r OpenSCADA/src/moduls/bd/=Tmpl= NewMod; touch NewMod/{NEWS,README,AUTHORS,ChangeLog}; cp OpenSCADA/I18N.mk NewMod/</span>
<dl><dd> <i>for the "DAQ" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>daq</b>/=Tmpl="</dd>
<dd> <i>for the "Archive-History" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>arhiv</b>/=Tmpl="</dd>
<dd> <i>for the "Transport" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>transport</b>/=Tmpl="</dd>
<dd> <i>for the "Transport protocol" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>protocol</b>/=Tmpl="</dd>
<dd> <i>for the "UI" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>ui</b>/=Tmpl="</dd>
<dd> <i>for the "Special" subsystem the path is</i> — "OpenSCADA/src/moduls/<b>special</b>/=Tmpl="</dd></dl></dd></dl></dd>
<dd>3. Edit the module information in the "module.cpp" file similarly to the appropriate item in the previous section.</dd>
<dd>4. Edit the module building configuration in the "Makefile.am" file similarly to the appropriate item in the previous section, excepts:
<ul><li> instead "db_NewMod_la_LDFLAGS = -module -avoid-version <b>$(top_builddir)/src/liboscada.la</b>" write "db_NewMod_la_LDFLAGS = -module -avoid-version", that is remove "$(top_builddir)/src/liboscada.la"</li>
<li> instead "include <b>../../../../</b>I18N.mk" write "include I18N.mk", that is remove the path "../../../../"</li></ul></dd>
<dd>5. Edit the build system configuration file "configure.ac" for:
<dl><dd><dl><dd> <i>also can do that automatically by:</i> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">sed -i "s/Tmpl/NewMod/g" configure.ac</span></dd></dl></dd></dl>
<ul><li> "AC_INIT([<b>Tmpl</b>],[<b>0.0.1</b>],[<b>my@email.org</b>])" — information about the module: name, version and EMail of the project</li>
<li> "AM_CONDITIONAL([<b>TmplIncl</b>],[test])" — "AM_CONDITIONAL([<b>NewModIncl</b>],[test])"</li></ul></dd>
<dd>6. Install the OpenSCADA development package "openscada-dev" or "openscada-devel" — because the module is an external one and the OpenSCADA source files are needed only at the first stage of the module creation, you need to install the OpenSCADA development package, which contains the header files and libraries.</dd>
<dd>7. Now you can build the new module, after formation of the building system
<dl><dd> <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">autoreconf -if; ./configure; make</span></dd></dl></dd></dl>
<h2><span class="mw-headline" id="API_of_the_module"><span class="mw-headline-number">2</span> API of the module</span></h2>
<p>OpenSCADA API for the developer of OpenSCADA and modules to it is described in the document "<a href="API.html" title="Special:MyLanguage/Documents/API">OpenSCADA API</a>", 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.
</p><p>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.
</p><p>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:
</p>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="c1">//================== CUT =========================</span>
<span class="k">extern</span> <span class="s">"C"</span>
<span class="p">{</span>
<span class="cp">#ifdef MOD_INCL</span>
    <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span> <span class="n">bd_Tmpl_module</span><span class="p">(</span> <span class="kt">int</span> <span class="n">n_mod</span> <span class="p">)</span>
<span class="cp">#else</span>
    <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span> <span class="n">module</span><span class="p">(</span> <span class="kt">int</span> <span class="n">n_mod</span> <span class="p">)</span>
<span class="cp">#endif</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">n_mod</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span><span class="p">(</span><span class="n">MOD_ID</span><span class="p">,</span> <span class="n">MOD_TYPE</span><span class="p">,</span> <span class="n">VER_TYPE</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span><span class="p">(</span><span class="s">""</span><span class="p">);</span>
    <span class="p">}</span>

<span class="o">&lt;!--</span><span class="nl">T</span><span class="p">:</span><span class="mi">348</span><span class="o">--&gt;</span>
<span class="cp">#ifdef MOD_INCL</span>
    <span class="n">TModule</span> <span class="o">*</span><span class="n">bd_Tmpl_attach</span><span class="p">(</span> <span class="k">const</span> <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span> <span class="o">&amp;</span><span class="n">AtMod</span><span class="p">,</span> <span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">source</span> <span class="p">)</span>
<span class="cp">#else</span>
    <span class="n">TModule</span> <span class="o">*</span><span class="n">attach</span><span class="p">(</span> <span class="k">const</span> <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span> <span class="o">&amp;</span><span class="n">AtMod</span><span class="p">,</span> <span class="k">const</span> <span class="n">string</span> <span class="o">&amp;</span><span class="n">source</span> <span class="p">)</span>
<span class="cp">#endif</span>
    <span class="p">{</span>
        <span class="k">if</span><span class="p">(</span><span class="n">AtMod</span> <span class="o">==</span> <span class="n">TModule</span><span class="o">::</span><span class="n">SAt</span><span class="p">(</span><span class="n">MOD_ID</span><span class="p">,</span><span class="n">MOD_TYPE</span><span class="p">,</span><span class="n">VER_TYPE</span><span class="p">))</span> <span class="k">return</span> <span class="k">new</span> <span class="n">BDTmpl</span><span class="o">::</span><span class="n">BDMod</span><span class="p">(</span><span class="n">source</span><span class="p">);</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="c1">//================== CUT =========================</span>
</pre></div>
<p>The entry point of any module are the following functions:
</p>
<ul><li> <i>TModule::SAt module( int n_mod )</i>, <i>TModule::SAt {modTp}_{modNm}_module( int n_mod )</i> — 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 <i>modTp</i> corresponds to the type of the module, and <i>modNm</i> is its ID.</li>
<li> <i>TModule *attach( const TModule::SAt &amp;AtMod, const string &amp;source )</i>, <i>TModule *{modTp}_{modNm}_attach( const TModule::SAt &amp;AtMod, const string &amp;source )</i> — is used to directly connect-open the selected module by creating a root object of the module inherited from <b>TModule</b>. 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 <i>modTp</i> and <i>modNm</i> correspond to the previous function.</li></ul>
<p>Common to all modules is the inheritance of the root object-class of the module from the class of the module subsystem <a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a>, 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 <a class="external" href="http://oscada.org/wiki/File:API_uml_classdep.png" title="File:API uml classdep.png">overall OpenSCADA class diagram</a> in front of your eyes!
</p><p>All module interface objects inherit the node class <a href="API.html#TCntrNode" title="Special:MyLanguage/Documents/API">TCntrNode</a>, which provides the <a href="API.html#CntrNode" title="Special:MyLanguage/Documents/API">control interface</a> mechanism. One task of the mechanism is to provide the object configuration interface in any OpenSCADA configurator.
</p>
<table class="wikitable">

<tr>
<th> Common API
</th></tr>
<tr>
<td><b><a href="API.html#TCntrNode" title="Special:MyLanguage/Documents/API">TCntrNode</a></b> — OpenSCADA Node:
<ul><li> <i>virtual void preEnable( int flag );</i>, <i>virtual void postEnable( int flag );</i> — connecting the module to the dynamic tree of objects, called before and after the actual activation of the module, respectively.</li>
<li> <i>virtual void preDisable( int flag );</i>, <i>virtual void postDisable( int flag );</i> — excluding the module from the dynamic tree of objects before freeing the object, called before and after the actual exclusion of the module, respectively.</li>
<li> <i>virtual void load_( TConfig *cfg );</i>, <i>virtual void load_( );</i> — loading the module from the "cfg" storage context and in general, called at the stage of loading the module configuration from the storage.</li>
<li> <i>virtual void save_( );</i> — saving the module, called at the stage of saving the configuration of the module to the storage, usually at the initiative of the user.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — OpenSCADA Module:<br />
<ul><li> <i>virtual void modStart( );</i> — module starting, called at the stage of starting tasks of the module's background functions, if these are provided by the module.</li>
<li> <i>virtual void modStop( );</i> — 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.</li>
<li> <i>virtual void modInfo( vector&lt;string&gt; &amp;list );</i> — 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.</li>
<li> <i>virtual string modInfo( const string &amp;name );</i> — a request for the information element <i>name</i> at which there performed also the requests processing of own-specific properties of the module.</li>
<li> <i>void modFuncReg( ExpFunc *func );</i> — 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!</li>
<li> <i>virtual void perSYSCall( unsigned int cnt );</i> — 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.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "Data Bases (DB)" subsystem
</th></tr>
<tr>
<td> 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:
<ol><li> ANSI SQL Mode — is the simplest way which means of direct using the core functions <a href="API.html#TTable" title="Special:MyLanguage/Documents/API">fieldSQLSeek(), fieldSQLGet(), fieldSQLSet(), fieldSQLDel()</a> in fieldSeek(), fieldGet(), fieldSet(), fieldDel() respectively; all SQL-modules are used now this approach.</li>
<li> Full Implementation — is the hardest way which means of the complete implementation; modules of such approach using are whether old or specific ones: <a href="Modules/DBF.html" title="Special:MyLanguage/Modules/DBF">DBF</a>, <a href="Modules/LDAP.html" title="Special:MyLanguage/Modules/LDAP">LDAP</a>.</li></ol>
</td></tr>
<tr>
<td><b><a href="API.html#TTypeBD" title="Special:MyLanguage/Documents/API">TTypeBD</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "DB" subsystem:
<ul><li> <i>virtual string features( );</i> — keyword list of <a href="Program_manual.html#DBFeat" title="Special:MyLanguage/Documents/Program manual">features supported by the DB</a>.</li>
<li> <i>virtual int lsPr( );</i> — the DB priority base [0...9] in the generic storages list.</li>
<li> <i>virtual TBD *openBD( const string &amp;id );</i> — called when a new DB object is opened or created by this module with the identifier <i>id</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TBD" title="Special:MyLanguage/Documents/API">TBD</a></b> — the database object:
<ul><li> <i>virtual void enable( );</i> — enabling the DB.</li>
<li> <i>virtual void disable( );</i> — disabling the DB.</li>
<li> <i>virtual void allowList( vector&lt;string&gt; &amp;list ) const;</i> — requesting the table <i>list</i> in the DB.</li>
<li> <i>virtual void sqlReq( const string &amp;req, vector&lt; vector&lt;string&gt; &gt; *tbl = NULL, char intoTrans = EVAL_BOOL );</i> — processing the SQL-query <i>req</i> to the DB and receiving the result in the form of the <i>tbl</i> table, if the selection request and the pointer are non-zero. When <i>intoTrans</i> 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.</li>
<li> <i>virtual void transCloseCheck( );</i> — the periodically called function to check the transactions and closing the old or contain many requests ones.</li>
<li> <i>virtual TTable *openTable( const string &amp;name, bool create );</i> — called when you open or create a new table object.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TTable" title="Special:MyLanguage/Documents/API">TTable</a></b> — the table object in the database:
<ul><li> <i>void fieldStruct( TConfig &amp;cfg );</i> — getting the current structure of the table in the object <i>cfg</i>.</li>
<li> <i>bool fieldSeek( int row, TConfig &amp;cfg, const string &amp;cacheKey = "" );</i> — sequential scanning of table entries by incrementing <i>row</i> at the object <i>cfg</i> and returning FALSE after completion, with addressing by active <a href="API.html#TCfg" title="Special:MyLanguage/Documents/API">keyUse()</a> key fields. The cache key <i>cacheKey</i> is specified to prefetch the full response to the cache, extracting the following records from there.</li>
<li> <i>void fieldGet( TConfig &amp;cfg );</i> — request of the record specified in the "cfg" object with addressing by key fields.</li>
<li> <i>void fieldSet( TConfig &amp;cfg );</i> — transfer of the record specified in the "cfg" object with addressing by key fields.</li>
<li> <i>void fieldDel( TConfig &amp;cfg );</i> — deletion of the specified record by the key fields of the "cfg" object.</li></ul>
<dl><dd> <i><b>Specific for SQL Data Bases</b></i></dd></dl>
<ul><li> <i>void fieldFix( TConfig &amp;cfg, const string &amp;langLs = "" );</i> — correction of DB table structure to <i>cfg</i> and for translation languages <i>langLs</i>, usually after a failed transfer.</li>
<li> <i>string getSQLVal( TCfg &amp;cf, uint8_t RqFlg = 0 );</i> — return a SQL-specific wrapped <i>cf</i> value for the <a href="API.html#TCfg" title="Special:MyLanguage/Documents/API">ReqFlg flags</a> of the <i>RqFlg</i> call.</li>
<li> <i>void setSQLVal( TCfg &amp;cf, const string &amp;vl, bool tr = false );</i> — parsing the SQL value <i>vl</i> to translate <i>tr</i> and with writing to <i>cf</i>.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "Transports" subsystem
</th></tr>
<tr>
<td> Provides OpenSCADA communications through the interface, often it is the network one which is implemented by the module.
</td></tr>
<tr>
<td><b><a href="API.html#TTypeTransport" title="Special:MyLanguage/Documents/API">TTypeTransport</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "Transports" subsystem:
<ul><li> <i>virtual bool isNetwork( );</i> — the sign of network implementation by this module.</li>
<li> <i>virtual string outAddrHelp( );</i> — address format help of the output transports.</li>
<li> <i>virtual TTransportIn *In( const string &amp;id, const string &amp;stor );</i> — called when a new input transport object is opened or created by this module with the identifier <i>id</i> and the storage <i>stor</i>.</li>
<li> <i>virtual TTransportOut *Out( const string &amp;name, const string &amp;stor );</i> — called when a new output transport object is opened or created by this module with the identifier <i>id</i> and the storage <i>stor</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TTransportIn" title="Special:MyLanguage/Documents/API">TTransportIn</a></b> — the input transport object:
<ul><li> <i>virtual unsigned keepAliveReqs( );</i> — maximum Keep Alive requests.</li>
<li> <i>virtual unsigned keepAliveTm( );</i> — keep Alive time.</li>
<li> <i>virtual string getStatus( );</i> — getting the status of the transport.</li>
<li> <i>virtual void start( );</i> — starting the transport.</li>
<li> <i>virtual void stop( );</i> — stopping the transport.</li>
<li> <i>virtual int writeTo( const string &amp;sender, const string &amp;data );</i> — sending <i>data</i> backward to the <i>sender</i>. <a class="image" href="http://oscada.org/wiki/File:At.png"><img alt="At.png" height="22" src="files/At.png" width="22" /></a> Deprecated mostly and replaced by the polling mode of the <a href="API.html#TProtocolIn" title="Special:MyLanguage/Documents/API">input transport protocol</a>, Initially implemented in transports with support of the initiative sending, not only at a request.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TTransportOut" title="Special:MyLanguage/Documents/API">TTransportOut</a></b> — the output transport object:
<ul><li> <i>virtual string timings( );</i> — transport timeouts.</li>
<li> <i>virtual unsigned short attempts( );</i> — connection attempts.</li>
<li> <i>virtual string getStatus( );</i> — getting the status of the transport.</li>
<li> <i>virtual void setTimings( const string &amp;vl, bool isDef = false );</i> — setting the transport timeouts, as default one for <i>isDef</i>.</li>
<li> <i>virtual void setAttempts( unsigned short vl );</i> — setting the connection attempts.</li>
<li> <i>virtual void start( int time = 0 );</i> — starting the transport with the connection timeout <i>time</i>. 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.</li>
<li> <i>virtual void stop( );</i> — stopping the transport. </li>
<li> <i>virtual int messIO( const char *oBuf, int oLen, char *iBuf = NULL, int iLen = 0, int time = 0 );</i> — sending of the data over the transport. The waiting timeout <i>time</i> of the connection in milliseconds. The <i>time</i> in negative disables the transport's request/respond mode and allows for the independently reading/writing to a buffer IO, with the reading timeout <i>time</i> in absolute.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "Transport protocols" subsystem
</th></tr>
<tr>
<td> 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.
</td></tr>
<tr>
<td><b><a href="API.html#TProtocol" title="Special:MyLanguage/Documents/API">TProtocol</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "Transport protocols" subsystem:
<ul><li> <i>virtual void itemListIn( vector&lt;string&gt; &amp;ls, const string &amp;curIt = "" );</i> — the list <i>ls</i> of the input protocol sub-elements from the current item  <i>curIt</i>, if the protocol provides them. It is used when selecting an object in the input transport configuration.</li>
<li> <i>virtual void outMess( XMLNode &amp;io, TTransportOut &amp;tro );</i> — the data transfer by the objects of the OpenSCADA core in the XML tree <i>io</i> to the remote system via the <i>tro</i> 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 <i>tro</i> output transport by the <a href="API.html#TTransportOut" title="Special:MyLanguage/Documents/API">messIO() function</a>.</li>
<li> <i>virtual TProtocolIn *in_open( const string &amp;id );</i> — called when a new transport protocol object is opened or created by this module with the identifier <i>id</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TProtocolIn" title="Special:MyLanguage/Documents/API">TProtocolIn</a></b> — the input object of the transport protocol of the input requests processing from the <a href="API.html#TTransportIn" title="Special:MyLanguage/Documents/API">input transport object TTransportIn</a>. 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-&gt;answer" session. Address of the transport, which opened the protocol instance, is specified in <a href="API.html#TProtocolIn" title="Special:MyLanguage/Documents/API">srcTr()</a>:
<ul><li> <i>virtual unsigned waitReqTm( )</i> — 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.</li>
<li> <i>virtual void setSrcTr( TTransportIn *vl )</i> — setting of the transport-source of the opening of the session of the input protocol.</li>
<li> <i>virtual void setSrcAddr( const string &amp;vl );</i> — setting of the sender address.</li>
<li> <i>virtual bool mess( const string &amp;request, string &amp;answer );</i> — transfer of the <i>request</i> data sequence to the protocol object for it parsing accordingly to the protocol implementation. The protocol function should process the <i>request</i>, generate the response in <i>answer</i> and return FALSE in the case of the completeness of the request. If the <i>request</i> 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.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "Data AcQuisition" subsystem
</th></tr>
<tr>
<td> 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:
<ol><li> Static formation through definition a set of the parameter types inherited from <a href="API.html#TTypeParam" title="Special:MyLanguage/Documents/API">TTypeParam</a>, 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: <a href="Modules/GPIO.html" title="Special:MyLanguage/Modules/GPIO">GPIO</a>, <a href="Modules/SMH2Gi.html" title="Special:MyLanguage/Modules/SMH2Gi">SMH2Gi</a>, <a class="external" href="http://oscada.org/wiki/Special:MyLanguage/Modules/AMRDevs" title="Special:MyLanguage/Modules/AMRDevs">AMRDevs</a>.</li>
<li> Dynamic formation with the structure container <a href="API.html#TElem" title="Special:MyLanguage/Documents/API">TElem</a> managing in the parameter object <a href="API.html#TParamContr" title="Special:MyLanguage/Documents/API">TParamContr</a>. This method is most flexible and used in most modules which mean of the structure be configurable.</li>
<li> As an extension of the dynamic formation there is the <a href="DAQ.html#LogicLev" title="Special:MyLanguage/Documents/DAQ">Logical Level parameter type</a>, what can be added to any module, but that used mostly in the universal data sources: <a href="Modules/LogicLev.html" title="Special:MyLanguage/Modules/LogicLev">LogicLev</a>, <a href="Modules/ModBus.html" title="Special:MyLanguage/Modules/ModBus">ModBus</a>, <a href="Modules/Siemens.html" title="Special:MyLanguage/Modules/Siemens">Siemens</a>, <a href="Modules/OPC_UA.html" title="Special:MyLanguage/Modules/OPC UA">OPC_UA</a>.</li></ol>
</td></tr>
<tr>
<td><b><a href="API.html#TTypeDAQ" title="Special:MyLanguage/Documents/API">TTypeDAQ</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "Data AcQuisition" subsystem:
<ul><li> <i>virtual bool compileFuncLangs( vector&lt;string&gt; *ls = NULL );</i> — request the list <i>ls</i> of languages for which it is realised the possibility of formation of user procedures in this module, and check for fact of that support.</li>
<li> <i>virtual void compileFuncSnthHgl( const string &amp;lang, XMLNode &amp;shgl );</i> — request the rules of the syntax highlight <i>shgl</i> for the specified language <i>lang</i>.</li>
<li> <i>virtual string compileFunc( const string &amp;lang, TFunction &amp;fnc_cfg, const string &amp;prog_text, const string &amp;usings = "", int maxCalcTm = 0 );</i> — compiling-registering of the user function on the supported programming language <i>lang</i> and on the source code of procedure <i>prog_text</i>, based on the procedure parameters <i>fnc_cfg</i>. Returns address of the compiled function's object, ready for execution.</li>
<li> <i>virtual bool redntAllow( );</i> — state of support the redundancy mechanisms by the module. Should be overridden and return TRUE if supported, otherwise FALSE.</li>
<li> <i>virtual TController *ContrAttach( const string &amp;id, const string &amp;daq_db );</i> — called when a new controller object is opened or created by this module with the identifier <i>id</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TController" title="Special:MyLanguage/Documents/API">TController</a></b> — 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 <a href="API.html#TVAl" title="Special:MyLanguage/Documents/API">TVAl::arch()</a>, and the current value is set by the <a href="API.html#TVAl" title="Special:MyLanguage/Documents/API">TVAl::set() function</a> with the attribute "sys"=TRUE:
<ul><li> <i>virtual string getStatus( );</i> — request function of the controller status.</li>
<li> <i>virtual void enable_(  );</i> — 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.</li>
<li> <i>virtual void disable_(  );</i> — disabling the controller object.</li>
<li> <i>virtual void start_( );</i> — starting the controller object. Usually at this stage the task of periodic or scheduled polling is created and started.</li>
<li> <i>virtual void stop_( );</i> — stopping the controller object.</li>
<li> <i>virtual void redntDataUpdate( );</i> — operation of the data receiving from the backup station, called automatically by the service procedure of the redundancy scheme of the subsystem.</li>
<li> <i>virtual string catsPat( );</i> — list of the regular expression rules, separated by '|', for matching by category the messages generated by the object.</li>
<li> <i>virtual void messSet( const string &amp;mess, int lev, const string &amp;type2Code = "OP", const string &amp;prm = "", const string &amp;cat = "" );</i> — formation of the DAQ-sourced messages for the parameter object <i>prm</i> (PrmId) or the controller object in whole if the parameter object is not specified, for the message <i>mess</i>, level <i>lev</i> and for the type code <i>type2Code</i>. This function generates the messages with the unified DAQ-transparency category "<b>{type2Code}{ModId}:{CntrId}[.{prm}][:{cat}]</b>".</li>
<li> <i>virtual TParamContr *ParamAttach( const string &amp;id, int type );</i> — called when a new object of the controller parameter is opened or created by this module with the identifier <i>id</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TParamContr" title="Special:MyLanguage/Documents/API">TParamContr</a>-&gt;<a href="API.html#TValue" title="Special:MyLanguage/Documents/API">TValue</a></b> — 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 <a href="API.html#TValue" title="Special:MyLanguage/Documents/API">TValue</a>:
<ul><li> <i>virtual TElem *dynElCntr( );</i> — container of the dynamic elements of the DAQ attributes. Defined mostly by the logical level sources what provide such kind containers.</li>
<li> <i>virtual void enable( );</i> — enabling the parameter object, the formation of the attributes set and filling them with the value of unreliability is made.</li>
<li> <i>virtual void disable( );</i> — disabling the parameter object.</li>
<li> <i>virtual void setType( const string &amp;tpId );</i> — called to change the parameter type to <i>tpId</i> and can be processed in the module object to change own data.</li>
<li> <i>virtual TVal* vlNew( );</i> — called at the stage of a new attribute creation. Can be overridden to implement special behavior within its object, inherited from <i>TVal</i>, when accessing the attribute.</li>
<li> <i>virtual void vlGet( TVal &amp;vo );</i> — called for the attribute <i>vo</i> with the direct reading mode <b>TVal::DirRead</b> when reading the value in order to directly-synchronous read from the physical source or the object buffer.</li>
<li> <i>virtual void vlSet( TVal &amp;vo, const TVariant &amp;vl, const TVariant &amp;pvl );</i> — called for the attribute <i>vo</i> with the direct recording mode <b>TVal::DirWrite</b> when setting the value in order to directly-synchronous set to the physical source or the object buffer, with the previous value <i>pvl</i>.</li>
<li> <i>virtual void vlArchMake( TVal &amp;val );</i> — called at the stage of creation the values archive with the <i>val</i> 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.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "Archives-History" subsystem
</th></tr>
<tr>
<td> 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.
</td></tr>
<tr>
<td><b><a href="API.html#TTypeArchivator" title="Special:MyLanguage/Documents/API">TTypeArchivator</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "Archives-History" subsystem:
<ul><li> <i>virtual TMArchivator *AMess( const string &amp;id, const string &amp;stor );</i> — called when a new object of the message archiver is opened or created by this module with the identifier <i>id</i> and in the storage <i>stor</i>.</li>
<li> <i>virtual TVArchivator *AVal( const string &amp;id, const string &amp;stor );</i> — called when a new object of the value archiver is opened or created by this module with the identifier <i>id</i> and in the storage <i>stor</i>.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TMArchivator" title="Special:MyLanguage/Documents/API">TMArchivator</a></b> — the message archiver object.
<ul><li> <i>virtual void redntDataUpdate( );</i> — operation of the data receiving from the backup station, called automatically by the service procedure of the redundancy scheme of the subsystem.</li>
<li> <i>virtual void start( );</i> — starting the archiver object, the archiver starts for receiving messages and placing them into the storage.</li>
<li> <i>virtual void stop( );</i> — stopping the archiver object.</li>
<li> <i>virtual time_t begin( );</i> — begin time of the archiver data accordingly with the current state of the storage.</li>
<li> <i>virtual time_t end( );</i> — end time of the archiver data accordingly with the current state of the storage.</li>
<li> <i>virtual bool put( vector&lt;TMess::SRec&gt; &amp;mess, bool force = false );</i> — placing the message group <i>mess</i> to the archiver. Returns TRUE on the successful operation. Set <i>force</i> for direct writing to the archiver omit the redundancy.</li>
<li> <i>virtual time_t get( time_t bTm, time_t eTm, vector&lt;TMess::SRec&gt; &amp;mess, const string &amp;category = "", char level = 0, time_t upTo = 0 );</i> — getting the messages to <i>mess</i> 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 [<i>bTm</i>...<i>eTm</i>], <i>category</i> rules, <i>level</i> and limited up to the time <i>upTo</i>. In the absence of a direct definition of the limiting time <i>upTo</i>, this limitation is set to <i>prmInterf_TM</i> — 7 seconds.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TVArchivator" title="Special:MyLanguage/Documents/API">TVArchivator</a></b> — the value archiver object.
<ul><li> <i>virtual void start( );</i> — starting the archiver object, the archiver starts for receiving values and placing them into the storage.</li>
<li> <i>virtual void stop( bool full_del = false );</i> — stopping the archiver object with the ability to completely remove its data from the storage at <i>full_del</i>.</li>
<li> <i>virtual TVArchEl *getArchEl( TVArchive &amp;arch );</i> — getting the element object of the value archive for the specified archive <i>arch</i>.</li>
<li> <i>virtual void pushAccumVals( );</i> — pushing the accumulated values by the archivation task, for the accumulative archivers.</li></ul>
</td></tr>
<tr>
<td><b><a href="API.html#TVArchEl" title="Special:MyLanguage/Documents/API">TVArchEl</a></b> — the element object of the value archiver.
<ul><li> <i>virtual void fullErase( );</i> — called to complete removal of the archive part in the archiver.</li>
<li> <i>virtual int64_t end( );</i> — end time in microseconds of the available values in the archive of the archiver.</li>
<li> <i>virtual int64_t begin( );</i> — begin time in microseconds of the available values in the archive of the archiver.</li>
<li> <i>virtual TVariant getValProc( int64_t *tm, bool up_ord );</i> — requesting of one value from the archive for the time <i>tm</i> and fine-tuning to the upper value in the sampling grid <i>up_ord</i>.</li>
<li> <i>virtual void getValsProc( TValBuf &amp;buf, int64_t beg, int64_t end );</i> — requesting of a value group to <i>buf</i> from the archive and for the time range [<i>beg</i>...<i>end</i>].</li>
<li> <i>virtual void setValsProc( TValBuf &amp;buf, int64_t beg, int64_t end, bool toAccum );</i> — setting of the value group <i>buf</i> to the archive, for the time range [<i>beg</i>...<i>end</i>] and through the accumulation <i>toAccum</i>.</li></ul>
</td></tr>
<tr>
<th> API of the modules of the "User Interfaces" subsystem
</th></tr>
<tr>
<td> The user interface is formed according to the concept and mechanisms of external known standards and libraries.
</td></tr>
<tr>
<td><b><a href="API.html#TUI" title="Special:MyLanguage/Documents/API">TUI</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "User Interfaces" subsystem:<br />
<p><a class="image" href="http://oscada.org/wiki/File:At.png"><img alt="At.png" height="22" src="files/At.png" width="22" /></a> It contains no specific functions!
</p>
</td></tr>
<tr>
<th> API of the modules of the "Special" subsystem
</th></tr>
<tr>
<td> 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.
</td></tr>
<tr>
<td><b><a href="API.html#TSpecial" title="Special:MyLanguage/Documents/API">TSpecial</a>-&gt;<a href="API.html#TModule" title="Special:MyLanguage/Documents/API">TModule</a></b> — the root module object of the "User Interfaces" subsystem:<br />
<p><a class="image" href="http://oscada.org/wiki/File:At.png"><img alt="At.png" height="22" src="files/At.png" width="22" /></a> It contains no specific functions!
</p>
</td></tr></table>
<p><br />
For the convenience of direct addressing to the root object of the module from any object lower in the hierarchy, it is recommended to define the global variable "mod" in the namespace of the module, with its initialization in the constructor of the root object. Also, for transparent translation of the text messages of the module, it is recommended to define the function templates of the module message translation call "<b>_({Message})</b>" and "<b>trS({Message})</b>" as:
</p>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="cp">#undef _</span>
<span class="cp">#define _(mess) mod-&gt;I18N(mess).c_str()</span>
<span class="cp">#undef trS</span>
<span class="cp">#define trS(mess) mod-&gt;I18N(mess,mess_PreSave)</span>
</pre></div>
<p>In the constructor of the root module's object inherited from the <b>TModule</b> it is necessary to set the main information of the module by call the function <b>void modInfoMainSet({Name}, {Type}, {Version}, {Authors}, {Description}, {License}, {Source})</b> after init the fast link "mod" to the root object of the module.
</p><p>Further receiving of the translation template file "po/oscd_NewMod.pot" of the text messages "<b>_({Message})</b>" and "<b>trS({Message})</b>", as well as updating-actualising the files of already existing translations "po/{uk|de|ru|...}.po" is carried out by the command <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">make messages</span> in the module folder.
</p><p>During solve the tasks of the new module, it may be necessary to expand the configuration parameters, which is carried out in the virtual function <b>void cntrCmdProc( XMLNode *req );</b>. The content of this function, which adds properties, in the <a href="Modules/SQLite.html" title="Special:MyLanguage/Modules/SQLite">SQLite module</a> looks like this:
</p>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="kt">void</span> <span class="n">MBD</span><span class="o">::</span><span class="n">cntrCmdProc</span><span class="p">(</span> <span class="n">XMLNode</span> <span class="o">*</span><span class="n">opt</span> <span class="p">)</span>
<span class="p">{</span>
    <span class="c1">//Getting the page info</span>
    <span class="k">if</span><span class="p">(</span><span class="n">opt</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">()</span> <span class="o">==</span> <span class="s">"info"</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">TBD</span><span class="o">::</span><span class="n">cntrCmdProc</span><span class="p">(</span><span class="n">opt</span><span class="p">);</span>
        <span class="n">ctrMkNode</span><span class="p">(</span><span class="s">"fld"</span><span class="p">,</span><span class="n">opt</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="s">"/prm/cfg/ADDR"</span><span class="p">,</span><span class="n">EVAL_STR</span><span class="p">,</span><span class="n">enableStat</span><span class="p">()</span><span class="o">?</span><span class="nl">R_R___</span><span class="p">:</span><span class="n">RWRW__</span><span class="p">,</span><span class="s">"root"</span><span class="p">,</span><span class="n">SDB_ID</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span>
            <span class="s">"dest"</span><span class="p">,</span><span class="s">"sel_ed"</span><span class="p">,</span><span class="s">"select"</span><span class="p">,</span><span class="s">"/prm/cfg/dbFsList"</span><span class="p">,</span><span class="s">"help"</span><span class="p">,</span>
                    <span class="n">_</span><span class="p">(</span><span class="s">"SQLite DB address must be written as: </span><span class="se">\"</span><span class="s">{FileDBPath}</span><span class="se">\"</span><span class="s">.</span><span class="se">\n</span><span class="s">"</span>
                      <span class="s">"Where:</span><span class="se">\n</span><span class="s">"</span>
                      <span class="s">"  FileDBPath - full path to DB file (./oscada/Main.db).</span><span class="se">\n</span><span class="s">"</span>
                      <span class="s">"               Use the empty path to create a temporary database on the disk.</span><span class="se">\n</span><span class="s">"</span>
                      <span class="s">"               Use </span><span class="se">\"</span><span class="s">:memory:</span><span class="se">\"</span><span class="s"> to create a temporary database in memory."</span><span class="p">));</span>
        <span class="k">if</span><span class="p">(</span><span class="n">reqCnt</span><span class="p">)</span>
            <span class="n">ctrMkNode</span><span class="p">(</span><span class="s">"comm"</span><span class="p">,</span><span class="n">opt</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="s">"/prm/st/end_tr"</span><span class="p">,</span><span class="n">_</span><span class="p">(</span><span class="s">"Close opened transaction"</span><span class="p">),</span><span class="n">RWRW__</span><span class="p">,</span><span class="s">"root"</span><span class="p">,</span><span class="n">SDB_ID</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="c1">//Processing for commands to the page</span>
    <span class="n">string</span> <span class="n">a_path</span> <span class="o">=</span> <span class="n">opt</span><span class="o">-&gt;</span><span class="n">attr</span><span class="p">(</span><span class="s">"path"</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="n">a_path</span> <span class="o">==</span> <span class="s">"/prm/cfg/dbFsList"</span> <span class="o">&amp;&amp;</span> <span class="n">ctrChkNode</span><span class="p">(</span><span class="n">opt</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">opt</span><span class="o">-&gt;</span><span class="n">childAdd</span><span class="p">(</span><span class="s">"el"</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">setText</span><span class="p">(</span><span class="s">":memory:"</span><span class="p">);</span>
        <span class="n">TSYS</span><span class="o">::</span><span class="n">ctrListFS</span><span class="p">(</span><span class="n">opt</span><span class="p">,</span> <span class="n">addr</span><span class="p">(),</span> <span class="s">"db;"</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">a_path</span> <span class="o">==</span> <span class="s">"/prm/st/end_tr"</span> <span class="o">&amp;&amp;</span> <span class="n">ctrChkNode</span><span class="p">(</span><span class="n">opt</span><span class="p">,</span><span class="s">"set"</span><span class="p">,</span><span class="n">RWRW__</span><span class="p">,</span><span class="s">"root"</span><span class="p">,</span><span class="n">SDB_ID</span><span class="p">,</span><span class="n">SEC_WR</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">reqCnt</span><span class="p">)</span> <span class="n">transCommit</span><span class="p">();</span>
    <span class="k">else</span> <span class="n">TBD</span><span class="o">::</span><span class="n">cntrCmdProc</span><span class="p">(</span><span class="n">opt</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>The first half of this function serves the "info" information requests with the list and properties of the configuration fields. The second half serves all the other commands on getting, setting value, and others. The <b>TBD::cntrCmdProc(opt);</b> call is used to obtain the inherited interface. More details on appointment of the used functions are in the <a href="API.html#CntrNode" title="Special:MyLanguage/Documents/API">control interface</a>, as well as in the source code of existing modules.
</p><p>The <b>TCntrNode</b> object, in addition to the control interface function, provides unified control mechanisms for modifying the object's configuration, loading, saving, and deleting configuration duplicates in the storage. You can use the <b>modif()</b> and <b>modifG()</b> functions to set the object data modification flag, and the module-specific loading and saving actions can be placed in virtual functions:
</p>
<ul><li> <i>void load_( TConfig *cfg );</i>, <i>void load_( );</i> — loading the object from a storage.</li>
<li> <i>void save_( );</i> — saving the object to a storage.</li></ul>
<p>Configuration actions typically occur through the <a href="API.html#TConfig" title="Special:MyLanguage/Documents/API">TConfig</a> object, which contains a set of defined properties with structure and values. To directly reflect the properties of a module object, it inherits from <b>TConfig</b>, and new properties are added with the command:
</p>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="n">fldAdd</span><span class="p">(</span><span class="k">new</span> <span class="n">TFld</span><span class="p">(</span><span class="s">"MOD_PRMS"</span><span class="p">,</span><span class="n">trS</span><span class="p">(</span><span class="s">"Module addition parameters"</span><span class="p">),</span><span class="n">TFld</span><span class="o">::</span><span class="n">String</span><span class="p">,</span><span class="n">TFld</span><span class="o">::</span><span class="n">FullText</span><span class="o">|</span><span class="n">TCfg</span><span class="o">::</span><span class="n">NoVal</span><span class="p">,</span><span class="s">"100000"</span><span class="p">));</span>
</pre></div>
<p>Loading/saving/deleting of the properties specified in the <b>TConfig</b> object, from/to/in the storage, is made with the following commands:
</p>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="n">TBDS</span><span class="o">::</span><span class="n">dataGet</span><span class="p">(</span><span class="n">fullDB</span><span class="p">(),</span> <span class="n">owner</span><span class="p">().</span><span class="n">nodePath</span><span class="p">()</span><span class="o">+</span><span class="n">tbl</span><span class="p">(),</span> <span class="o">*</span><span class="k">this</span><span class="p">);</span>
<span class="n">TBDS</span><span class="o">::</span><span class="n">dataSet</span><span class="p">(</span><span class="n">fullDB</span><span class="p">(),</span> <span class="n">owner</span><span class="p">().</span><span class="n">nodePath</span><span class="p">()</span><span class="o">+</span><span class="n">tbl</span><span class="p">(),</span> <span class="o">*</span><span class="k">this</span><span class="p">);</span>
<span class="n">TBDS</span><span class="o">::</span><span class="n">dataDel</span><span class="p">(</span><span class="n">fullDB</span><span class="p">(</span><span class="n">flag</span><span class="o">&amp;</span><span class="n">NodeRemoveOnlyStor</span><span class="p">),</span> <span class="n">owner</span><span class="p">().</span><span class="n">nodePath</span><span class="p">()</span><span class="o">+</span><span class="n">tbl</span><span class="p">(),</span> <span class="o">*</span><span class="k">this</span><span class="p">,</span> <span class="n">TBDS</span><span class="o">::</span><span class="n">UseAllKeys</span><span class="p">);</span>
</pre></div>
<p>Where:
</p>
<ul><li> <i>fullDB()</i> — the full name of the storage in the <a href="API.html#DataConcept" title="Special:MyLanguage/Documents/API">common form</a>;</li>
<li> <i>owner().nodePath()+tbl()</i> — the common path, represented as the table, to the object node in the configuration file;</li>
<li> <i>*this</i> — this object, inherited from <b>TConfig</b>.</li></ul>
<p>To generate the debug messages <a href="Program_manual.html#Config" title="Special:MyLanguage/Documents/Program manual">according the common debugging concept</a>, you need to use the function <b>mess_debug()</b> with call it conditionally at the program source part:
</p>
<ul><li> the rarely invoked part — direct call to the function <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">mess_debug(...);</span>;</li>
<li> the often invoked part — conditional call <span style="border: solid gray 1px; padding: 1px; font-family: monospace; font-size: 1.2em; white-space: nowrap;">if(mess_lev() == TMess::Debug) mess_debug(...);</span>;</li>
<li> the critical to performance code part — wrapping to definition <b>OSC_DEBUG</b>:</li></ul>
<div class="mw-highlight mw-content-ltr" dir="ltr"><pre><span class="cp">#ifdef OSC_DEBUG</span>
  <span class="n">mess_debug</span><span class="p">(...);</span>
<span class="cp">#endif</span>
</pre></div>






</div><table style="border-top: dotted 2px #999999; margin-top: 20pt; color: gray;" width="100%"><tr><td style="text-align: left;" width="40%"><a href="http://oscada.org/wiki/Documents/How_to/Create_module/en">Documents/How_to/Create_module/en</a> - <a href="http://oscada.org/en/main/about-the-project/licenses/">GFDL</a></td><td style="text-align: center;">April 2025</td><td style="text-align: right;" width="40%">OpenSCADA 1+r3018</td></tr></table></body>
</html>