Commit 754a7b5e authored by Pavel Vainerman's avatar Pavel Vainerman

backported to p9 as 2.9.1-alt0.M90P.1 (with rpmbph script)

parents bb6930e3 2cad3bd5
......@@ -14,10 +14,10 @@ name: "CodeQL"
on:
push:
branches: [ master, github-actions ]
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [ "*" ]
schedule:
- cron: '44 6 * * 4'
......@@ -46,7 +46,9 @@ jobs:
- name: install packages
run: |
sudo apt-get install libcomedi-dev libpoco-dev libmysqlclient-dev libomniorb4-dev libev-dev omniidl xsltproc libpqxx3-dev librrd-dev libsigc++-2.0-dev libsqlite3-dev python-dev libmosquittopp-dev
sudo apt-get install libcomedi-dev libpoco-dev libmysqlclient-dev libomniorb4-dev \
libev-dev omniidl xsltproc libpqxx3-dev librrd-dev libsigc++-2.0-dev \
libsqlite3-dev python-dev libmosquittopp-dev libpoco-dev swig
wget https://github.com/catchorg/Catch2/releases/download/v1.11.0/catch.hpp -O include/catch.hpp
- name: build
......@@ -55,7 +57,7 @@ jobs:
# due broken comedi
export CXXFLAGS="$CXXFLAGS -Wl,--unresolved-symbols=ignore-in-shared-libs"
autoreconf -fiv
./configure --enable-mysql --enable-sqlite --enable-rrd --enable-io --disable-python --disable-mqtt --disable-pgsql --disable-api --disable-netdata --disable-logdb
./configure --disable-python --disable-netdata
make
- name: Perform CodeQL Analysis
......
name: C/C++ CI
name: testsuite
on:
push:
branches: [ master, github-actions ]
branches: [ "*" ]
pull_request:
branches: [ master ]
branches: [ "*" ]
jobs:
build:
runs-on: ubuntu-latest
container:
image: alt:sisyphus
steps:
- uses: actions/checkout@v2
- name: install packages
run: |
sudo apt-get install libcomedi-dev libpoco-dev libmysqlclient-dev libomniorb4-dev libev-dev omniidl xsltproc libpqxx3-dev librrd-dev libsigc++-2.0-dev libsqlite3-dev python-dev libmosquittopp-dev
wget https://github.com/catchorg/Catch2/releases/download/v1.11.0/catch.hpp -O include/catch.hpp
apt-get update && apt-get -y install etersoft-build-utils su sudo \
git-core ccache gcc-c++ etersoft-build-utils catch-devel \
libcomedi-devel libmariadb-devel libpqxx-devel librrd-devel libsqlite3-devel \
libxml2-devel libsigc++2-devel libpoco-devel libev-devel libomniORB-devel libmosquitto-devel \
xsltproc python-devel python-module-distribute libomniORB-names libomniORB-idl libomniORB-utils swig
- uses: actions/checkout@v2
- name: configure
run: |
export CXXFLAGS='-pipe -O2 -pedantic -Wall'
# due broken comedi
export CXXFLAGS="$CXXFLAGS -Wl,--unresolved-symbols=ignore-in-shared-libs"
autoreconf -fiv
./configure --enable-mysql --enable-sqlite --enable-rrd --enable-io --disable-python --disable-mqtt --disable-pgsql --disable-api --disable-netdata --disable-logdb
./configure --disable-netdata
- name: make
run: make
- name: simple tests
- name: testsuite
run: |
cd tests;
cd testsuite;
make check
......@@ -17,25 +17,6 @@ cache:
matrix:
include:
- os: linux
# dist: precise
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8']
env:
- MATRIX_EVAL="CXX=g++-4.8 CC=gcc-4.8"
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9']
env:
- MATRIX_EVAL="CXX=g++-4.9 CC=gcc-4.9"
- os: linux
compiler: gcc
addons:
apt:
......@@ -75,24 +56,6 @@ matrix:
compiler: clang
addons:
apt:
sources: ['llvm-toolchain-trusty-5.0']
packages: ['clang-5.0']
env:
- MATRIX_EVAL="CXX=clang++-5.0 CC=clang-5.0 COMPILER_NAME=clang"
- os: linux
compiler: clang
addons:
apt:
sources: ['llvm-toolchain-trusty-6.0', 'ubuntu-toolchain-r-test']
packages: ['clang-6.0']
env:
- MATRIX_EVAL="CXX=clang++-6.0 CC=clang-6.0 COMPILER_NAME=clang"
- os: linux
compiler: clang
addons:
apt:
sources: ['llvm-toolchain-trusty-7', 'ubuntu-toolchain-r-test']
packages: ['clang-7']
env:
......@@ -154,4 +117,4 @@ addons:
notification_email: lav@etersoft.ru
build_command_prepend: "make clean"
build_command: make -j4
branch_pattern: coverity_scan
branch_pattern: master
......@@ -69,6 +69,9 @@ interface IOController_i : UniSetManager_i
void setUndefinedState(in uniset::ObjectId sid, in boolean undefined, in uniset::ObjectId sup_id )
raises(NameNotFound);
// "заморозка"/"разморозка" значения. set=true - выставить value и не менять, пока не будет вызван set=false
void freezeValue(in uniset::ObjectId sid, in boolean set, in long value, in uniset::ObjectId sup_id ) raises(NameNotFound);
UniversalIO::IOType getIOType(in uniset::ObjectId sid) raises(NameNotFound);
// --- Интерфейс для конфигурирования ---
......@@ -95,7 +98,8 @@ interface IOController_i : UniSetManager_i
long value; /*!< значение */
boolean undefined; /*!< признак неопределённости значения */
boolean blocked; /*!< данное значение блокировано другим */
long real_value; /*!< запомненное состояние, до блокировки */
boolean frozen; /*!< данное значение "заморожено" */
long real_value; /*!< запомненное состояние, до блокировки или заморозки */
UniversalIO::IOType type; /*!< тип */
long priority; /*!< приоритет уведомления */
IOController_i::SensorInfo si;
......
......@@ -56,6 +56,7 @@ static struct option longopts[] =
{ "quiet", no_argument, 0, 'q' },
{ "csv", required_argument, 0, 'z' },
{ "sendText", required_argument, 0, 'm' },
{ "freezeValue", required_argument, 0, 'n' },
{ NULL, 0, 0, 0 }
};
......@@ -76,9 +77,10 @@ int getRawValue( const string& args, UInterface& ui );
int getTimeChange( const string& args, UInterface& ui );
int getState( const string& args, UInterface& ui );
int getCalibrate( const string& args, UInterface& ui );
int oinfo(const string& args, UInterface& ui , const string& userparam );
int oinfo(const string& args, UInterface& ui, const string& userparam );
int apiRequest( const string& args, UInterface& ui, const string& query );
void sendText( const string& args, UInterface& ui, const string& txt, int mtype );
int freezeValue( const string& args, bool set, UInterface& ui );
// --------------------------------------------------------------------------
static void print_help(int width, const string& cmd, const string& help, const string& tab = " " )
{
......@@ -126,6 +128,7 @@ static void usage()
print_help(36, "-q|--quiet", "Выводит только результат.\n");
print_help(36, "-z|--csv", "Вывести результат (getValue) в виде val1,val2,val3...\n");
print_help(36, "-m|--sendText id1@node1,id2@node2,id3,.. mtype text", "Послать объектам текстовое сообщение text типа mtype\n");
print_help(36, "-n|--freezeValue id1@node1=val1,id2@node2=val2,id3=val3,.. set", "Выставить указанным датчикам соответствующие значения и заморозить их (set=true) или разморозить (set=false).\n");
cout << endl;
}
......@@ -199,6 +202,26 @@ int main(int argc, char** argv)
}
break;
case 'n': //--freezeValue
{
// смотрим второй параметр
if( checkArg(optind, argc, argv) == 0 )
{
if( !quiet )
cerr << "admin(freezeValue): Unknown 'set'. Use: id=v1,name=v2,name2@nodeX=v3 set" << endl;
return 1;
}
std::string sensors(optarg);
bool set = uni_atoi(argv[optind]);
auto conf = uniset_init(argc, argv, conffile);
UInterface ui(conf);
ui.initBackId(uniset::AdminID);
return freezeValue(sensors, set, ui);
}
break;
case 'g': //--getValue
case 'z': //--csv
{
......@@ -303,6 +326,7 @@ int main(int argc, char** argv)
commandToAll(conf->getControllersSection(), rep, (Command)cmd);
commandToAll(conf->getObjectsSection(), rep, (Command)cmd);
}
return 0;
case 'r': //--configure
......@@ -331,6 +355,7 @@ int main(int argc, char** argv)
if( verb )
cout << "(finish): done" << endl;
}
return 0;
case 'l': //--logrotate
......@@ -386,7 +411,7 @@ int main(int argc, char** argv)
std::string consumers(optarg);
ostringstream txt;
if( checkArg(optind+1, argc, argv) == 0 )
if( checkArg(optind + 1, argc, argv) == 0 )
{
if( !quiet )
cerr << "admin(sendText): Unknown 'text'. Use: id,name,name2@nodeX mtype text" << endl;
......@@ -394,7 +419,7 @@ int main(int argc, char** argv)
return 1;
}
for( int i=optind+1; i<argc; i++ )
for( int i = optind + 1; i < argc; i++ )
{
if( checkArg(i, argc, argv) == 0 )
break;
......@@ -669,7 +694,7 @@ int setValue( const string& args, UInterface& ui )
if( verb )
cout << "====== setValue ======" << endl;
for( auto && it : sl )
for( auto&& it : sl )
{
try
{
......@@ -738,7 +763,7 @@ int getValue( const string& args, UInterface& ui )
size_t num = 0;
for( auto && it : sl )
for( auto&& it : sl )
{
try
{
......@@ -808,6 +833,69 @@ int getValue( const string& args, UInterface& ui )
return err;
}
// --------------------------------------------------------------------------------------
int freezeValue( const string& args, bool set, UInterface& ui )
{
int err = 0;
auto conf = ui.getConf();
auto sl = uniset::getSInfoList(args, conf);
if( verb )
cout << "====== freezeValue ======" << endl;
for( auto&& it : sl )
{
try
{
UniversalIO::IOType t = conf->getIOType(it.si.id);
if( verb )
{
cout << " set: " << set << endl;
cout << " value: " << it.val << endl;
cout << " name: (" << it.si.id << ") " << it.fname << endl;
cout << " iotype: " << t << endl;
cout << " text: " << conf->oind->getTextName(it.si.id) << "\n\n";
}
if( it.si.node == DefaultObjectId )
it.si.node = conf->getLocalNode();
switch(t)
{
case UniversalIO::DI:
case UniversalIO::DO:
case UniversalIO::AI:
case UniversalIO::AO:
ui.freezeValue(it.si, set, it.val, AdminID);
break;
default:
if( !quiet )
cerr << "FAILED: Unknown 'iotype' for " << it.fname << endl;
err = 1;
break;
}
}
catch( const uniset::Exception& ex )
{
if( !quiet )
cerr << "(setValue): " << ex << endl;;
err = 1;
}
catch( const std::exception& ex )
{
if( !quiet )
cerr << "std::exception: " << ex.what() << endl;
err = 1;
}
}
return err;
}
// --------------------------------------------------------------------------------------
int getCalibrate( const std::string& args, UInterface& ui )
{
int err = 0;
......@@ -817,7 +905,7 @@ int getCalibrate( const std::string& args, UInterface& ui )
if( !quiet )
cout << "====== getCalibrate ======" << endl;
for( auto && it : sl )
for( auto&& it : sl )
{
if( it.si.node == DefaultObjectId )
it.si.node = conf->getLocalNode();
......@@ -867,7 +955,7 @@ int getRawValue( const std::string& args, UInterface& ui )
if( !quiet )
cout << "====== getRawValue ======" << endl;
for( auto && it : sl )
for( auto&& it : sl )
{
if( it.si.node == DefaultObjectId )
it.si.node = conf->getLocalNode();
......@@ -912,7 +1000,7 @@ int getTimeChange( const std::string& args, UInterface& ui )
if( !quiet )
cout << "====== getChangedTime ======" << endl;
for( auto && it : sl )
for( auto&& it : sl )
{
if( it.si.node == DefaultObjectId )
it.si.node = conf->getLocalNode();
......@@ -1069,7 +1157,7 @@ int oinfo(const string& args, UInterface& ui, const string& userparam )
auto conf = uniset_conf();
auto sl = uniset::getObjectsList( args, conf );
for( auto && it : sl )
for( auto&& it : sl )
{
if( it.node == DefaultObjectId )
it.node = conf->getLocalNode();
......@@ -1103,14 +1191,38 @@ int apiRequest( const string& args, UInterface& ui, const string& query )
// if( verb )
// cout << "apiRequest: query: " << query << endl;
for( auto && it : sl )
if( query.size() < 1 )
{
if( !quiet )
cerr << "query is too small '" << query << "'" << endl;
return 1;
}
string q = query;
if( q.rfind("/api/", 0) != 0 )
{
#ifndef DISABLE_REST_API
q = "/api/" + uniset::UHttp::UHTTP_API_VERSION;
#else
q = "/api/v01";
#endif
if( query[0] != '/' )
q += "/";
q += query;
}
for( auto&& it : sl )
{
if( it.node == DefaultObjectId )
it.node = conf->getLocalNode();
try
{
cout << ui.apiRequest(it.id, query, it.node) << endl;
cout << ui.apiRequest(it.id, q, it.node) << endl;
}
catch( const std::exception& ex )
{
......@@ -1137,7 +1249,7 @@ void sendText( const string& args, UInterface& ui, const string& txt, int mtype
cout << "mtype=" << mtype << " txt: " << txt << endl;
for( auto && it : sl )
for( auto&& it : sl )
{
if( it.node == DefaultObjectId )
it.node = conf->getLocalNode();
......
......@@ -19,6 +19,7 @@ ln -s -f admin.sh help
ln -s -f admin.sh oinfo
ln -s -f admin.sh apiRequest
ln -s -f admin.sh sendText
ln -s -f admin.sh freezeValue
ln -s -f ../../Utilities/scripts/uniset2-start.sh
ln -s -f ../../Utilities/scripts/uniset2-stop.sh stop.sh
......
......@@ -29,11 +29,11 @@ MBSlave::MBSlave(const std::unordered_set<ModbusAddr>& _vaddr, const std::string
// if( replyTimeout <= 0 )
// replyTimeout = 2000;
// if( verbose )
// cout << "(init): "
// << " addr=" << ModbusServer::vaddr2str(vaddr)
// << " dev=" << dev
// << " speed=" << speed;
// if( verbose )
// cout << "(init): "
// << " addr=" << ModbusServer::vaddr2str(vaddr)
// << " dev=" << dev
// << " speed=" << speed;
rscomm = new ModbusRTUSlaveSlot(dev, use485);
......
......@@ -102,7 +102,7 @@ struct Interval
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
Interval()
:tmStart(std::chrono::steady_clock::now())
: tmStart(std::chrono::steady_clock::now())
{}
uint64_t microseconds()
......@@ -322,6 +322,7 @@ int main( int argc, char** argv )
}
break;
#if 0
case 'g':
{
if( cmd == cmdNOP )
......@@ -342,6 +343,7 @@ int main( int argc, char** argv )
}
break;
#endif
case 'v':
verb = 1;
break;
......@@ -766,6 +768,7 @@ int main( int argc, char** argv )
Interval i;
mb.fileTransfer( slaveaddr, reg, tofile, tout);
if( verb )
cout << i.microseconds() << " ms" << endl;
}
......
......@@ -90,7 +90,7 @@ struct Interval
using time_point = std::chrono::time_point<std::chrono::steady_clock>;
Interval()
:tmStart(std::chrono::steady_clock::now())
: tmStart(std::chrono::steady_clock::now())
{}
uint64_t microseconds()
......
......@@ -60,7 +60,7 @@ int main( int argc, char** argv )
std::list<ExtInfo> l;
for( auto && it : lst )
for( auto&& it : lst )
{
UniversalIO::IOType t = conf->getIOType( it.si.id );
......
......@@ -8,6 +8,7 @@
#include "Exceptions.h"
#include "LogReader.h"
#include "LogServerTypes.h"
#include "LogAgregator.h"
// --------------------------------------------------------------------------
using namespace uniset;
using namespace std;
......@@ -41,6 +42,7 @@ static struct option longopts[] =
// --------------------------------------------------------------------------
static void print_help()
{
printf("Configs:\n");
printf("-h, --help - this message\n");
printf("-v, --verbose - Print all messages to stdout\n");
printf("[-i|--iaddr] addr - LogServer ip or hostname.\n");
......@@ -54,21 +56,42 @@ static void print_help()
printf("\n");
printf("Commands:\n");
printf("[-a | --add] info,warn,crit,... [logfilter] - Add log levels.\n");
printf("[-d | --del] info,warn,crit,... [logfilter] - Delete log levels.\n");
printf("[-s | --set] info,warn,crit,... [logfilter] - Set log levels.\n");
printf("[-o | --off] [logfilter] - Off the write log file (if enabled).\n");
printf("[-e | --on] [logfilter] - On(enable) the write log file (if before disabled).\n");
printf("[-r | --rotate] [logfilter] - rotate log file.\n");
printf("[-u | --save-loglevels] [logfilter] - save log levels (disable restore after disconnected).\n");
printf("[-y | --restore-loglevels] [logfilter] - restore default log levels.\n");
printf("[-b | --view-default-loglevels] [logfilter] - list of default log levels.\n");
printf("[-l | --list] [logfilter] - List of managed logs.\n");
printf("[-l | --list] [objName] - Show logs hierarchy from logname. Default: ALL\n");
printf("[-b | --view-default-loglevels] [objName] - Show current log levels for logname.\n");
printf("[-a | --add] info,warn,crit,... [objName] - Add log levels.\n");
printf("[-d | --del] info,warn,crit,... [objName] - Delete log levels.\n");
printf("[-s | --set] info,warn,crit,... [objName] - Set log levels.\n");
printf("[-f | --filter] logname - ('filter mode'). View log only from 'logname'(regexp)\n");
printf("[-g | --grep pattern - Print lines matching a pattern (c++ regexp)\n");
printf("[-f | --filter] logfilter - ('filter mode'). View log only from 'logfilter'(regexp)\n");
printf("\n");
printf("Note: 'objName' - regexp for name of log. Default: ALL logs.\n");
printf("\n");
printf("Special commands:\n");
printf("[-o | --off] [objName] - Off the write log file (if enabled).\n");
printf("[-e | --on] [objName] - On(enable) the write log file (if before disabled).\n");
printf("[-r | --rotate] [objName] - rotate log file.\n");
printf("[-u | --save-loglevels] [objName] - save log levels (disable restore after disconnected).\n");
printf("[-y | --restore-loglevels] [objName] - restore default log levels.\n");
printf("\n");
printf("Examples:\n");
printf("=========\n");
printf("log hierarchy:\n");
printf("SESControl1/TV1\n");
printf("SESControl1/TV1/HeatExchanger\n");
printf("SESControl1/TV1/MyCustomLog\n");
printf("\n");
printf("Note: 'logfilter' - regexp for name of log. Default: ALL logs.\n");
printf("* Show all logs for SESControl1 (only for SESControl1 and it's childrens)\n");
printf("uniset2-log -i host -p 30202 --del any --set any SESControl1\n");
printf("* Show all logs for TV1\n");
printf("unsiet2-log -i host -p 30201 --del any --set any TV1.*\n");
printf("* Show all logs for MyCustomLog\n");
printf("unsiet2-log -i host -p 30201 --del any --set any MyCustomLog\n");
printf("* Show info logs with special text for TV1\n");
printf("uniset2-log -i host -p 30202 --del any --set info TV1 --grep [Tt]ransient\n");
}
// --------------------------------------------------------------------------
static char* checkArg( int i, int argc, char* argv[] );
......
......@@ -154,15 +154,13 @@ int main( int argc, char** argv )
}
la->add(dlog);
auto la2 = make_shared<LogAgregator>("la2");
auto dlog3 = la2->create("dlog3");
auto dlog4 = la2->create("dlog4");
la2->add(dlog);
la2->add(dlog2);
la2->add(dlog3);
la2->add(dlog4);
la->add(la2);
......
......@@ -287,6 +287,8 @@
virtual void httpGetUserData( Poco::JSON::Object::Ptr&amp; jdata ){} /*!&lt; для пользовательских данных в httpGet() */
virtual Poco::JSON::Object::Ptr httpDumpIO();
virtual Poco::JSON::Object::Ptr httpRequestLog( const Poco::URI::QueryParameters&amp; p );
virtual Poco::JSON::Object::Ptr request_params_set( const std::string&amp; req, const Poco::URI::QueryParameters&amp; p ) override;
virtual Poco::JSON::Object::Ptr request_params_get( const std::string&amp; req, const Poco::URI::QueryParameters&amp; p ) override;
#endif
</xsl:if>
// Выполнение очередного шага программы
......@@ -737,6 +739,116 @@ Poco::JSON::Object::Ptr <xsl:value-of select="$CLASSNAME"/>_SK::httpRequestLog(
return jret;
}
// -----------------------------------------------------------------------------
Poco::JSON::Object::Ptr <xsl:value-of select="$CLASSNAME"/>_SK::request_params_set( const std::string&amp; req, const Poco::URI::QueryParameters&amp; params )
{
Poco::JSON::Object::Ptr jret = new Poco::JSON::Object();
Poco::JSON::Array::Ptr jupdated = uniset::json::make_child_array(jret, "updated");
for( const auto&amp; p: params )
{
if( p.first == "sleep_msec" )
{
int val = uni_atoi(p.second);
if( val &gt; 0 )
{
sleep_msec = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "resetMsgTime" )
{
int val = uni_atoi(p.second);
if( val &gt; 0 )
{
resetMsgTime = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "forceOut" )
{
int val = uni_atoi(p.second);
if( val &gt; 0 )
{
forceOut = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
<xsl:for-each select="//variables/item">
<xsl:if test="normalize-space(@const)=''">
if( p.first == "<xsl:value-of select="@name"/>" )
{
<xsl:if test="normalize-space(@type)='int'"><xsl:value-of select="@name"/> = uni_atoi(p.second);</xsl:if>
<xsl:if test="normalize-space(@type)='long'"><xsl:value-of select="@name"/> = uni_atoi(p.second);</xsl:if>
<xsl:if test="normalize-space(@type)='float'"><xsl:value-of select="@name"/> = atof(p.second.c_str());</xsl:if>
<xsl:if test="normalize-space(@type)='double'"><xsl:value-of select="@name"/> = atof(p.second.c_str());</xsl:if>
<xsl:if test="normalize-space(@type)='bool'"><xsl:value-of select="@name"/> = uni_atoi(p.second);</xsl:if>
<xsl:if test="normalize-space(@type)='str'"><xsl:value-of select="@name"/> = p.second;</xsl:if>
jupdated->add(p.first);
continue;
}
</xsl:if>
</xsl:for-each>
}
jret->set("Result", (jupdated->size() > 0 ? "OK" : "FAIL") );
return jret;
}
// -----------------------------------------------------------------------------
Poco::JSON::Object::Ptr <xsl:value-of select="$CLASSNAME"/>_SK::request_params_get( const std::string&amp; req, const Poco::URI::QueryParameters&amp; params )
{
Poco::JSON::Object::Ptr jret = new Poco::JSON::Object();
if( params.empty() )
{
jret->set("sleep_msec",sleep_msec);
jret->set("resetMsgTime",resetMsgTime);
jret->set("forceOut",forceOut);
<xsl:for-each select="//variables/item">
<xsl:if test="normalize-space(@const)=''">
jret->set("<xsl:value-of select="@name"/>", <xsl:value-of select="@name"/>);
</xsl:if>
</xsl:for-each>
return jret;
}
for( const auto&amp; p: params )
{
if( p.first == "sleep_msec" )
{
jret->set(p.first,sleep_msec);
continue;
}
if( p.first == "resetMsgTime" )
{
jret->set(p.first,resetMsgTime);
continue;
}
if( p.first == "forceOut" )
{
jret->set(p.first,forceOut);
continue;
}
<xsl:for-each select="//variables/item">
<xsl:if test="normalize-space(@const)=''">
if( p.first == "<xsl:value-of select="@name"/>" )
{
jret->set(p.first, <xsl:value-of select="@name"/>);
continue;
}
</xsl:if>
</xsl:for-each>
}
return jret;
}
#endif
</xsl:if>
// -----------------------------------------------------------------------------
......
......@@ -2,11 +2,11 @@ noinst_PROGRAMS = test test2
#test2
test_LDADD = $(top_builddir)/lib/libUniSet2.la $(POCO_LIBS)
test_CXXFLAGS = -I$(top_builddir)/include $(POCO_CGLAGS)
test_CXXFLAGS = -I$(top_builddir)/include $(POCO_CGLAGS) -Wno-unused-function
test_SOURCES = TestGen_SK.cc TestGen.cc TestGen-main.cc
test2_LDADD = $(top_builddir)/lib/libUniSet2.la $(POCO_LIBS)
test2_CXXFLAGS = -I$(top_builddir)/include $(POCO_CGLAGS)
test2_CXXFLAGS = -I$(top_builddir)/include $(POCO_CGLAGS) -Wno-unused-function
test2_SOURCES = TestGenAlone_SK.cc TestGenAlone.cc TestGenAlone-main.cc
GENERATED=TestGen_SK.h TestGen_SK.cc TestGen-main.cc
......
......@@ -86,6 +86,7 @@ void TestGen::httpGetUserData( Poco::JSON::Object::Ptr& jdata )
jdata->set("myFloatVar", 42.42);
jdata->set("myMessage", "This is text fot test httpGetUserData");
}
// -----------------------------------------------------------------------------
#endif
// -----------------------------------------------------------------------------
void TestGen::sysCommand( const uniset::SystemMessage* sm )
......
......@@ -15,6 +15,7 @@
%def_enable api
%def_enable logdb
%def_enable opentsdb
%def_enable uresolver
%ifarch %ix86
%def_enable com485f
......@@ -25,11 +26,11 @@
%define oname uniset2
Name: libuniset2
Version: 2.9.0
Version: 2.9.1
Release: alt0.M90P.1
Summary: UniSet - library for building distributed industrial control systems
License: LGPL
License: LGPL-2.1
Group: Development/C++
Url: http://wiki.etersoft.ru/UniSet
......@@ -184,6 +185,14 @@ Obsoletes: %name-extentions-devel
%description extension-common-devel
Libraries needed to develop for uniset extensions
%if_enabled uresolver
%package extension-uresolver
Group: Development/Tools
Summary: CORBA object reference resolver based on http
%description extension-uresolver
CORBA object reference resolver based on http
%endif
%if_enabled mysql
%package extension-mysql
......@@ -523,6 +532,11 @@ rm -f %buildroot%_docdir/%oname/html/*.md5
%_includedir/%oname/extensions/mqtt/
%endif
%if_enabled uresolver
%files extension-uresolver
%_bindir/%oname-httpresolver*
%endif
%files extension-common-devel
%dir %_includedir/%oname/extensions
%_includedir/%oname/extensions/*.*
......@@ -546,14 +560,28 @@ rm -f %buildroot%_docdir/%oname/html/*.md5
# history of current unpublished changes
%changelog
* Sun Dec 13 2020 Pavel Vainerman <pv@altlinux.ru> 2.9.0-alt0.M90P.1
* Fri Jan 08 2021 Pavel Vainerman <pv@altlinux.ru> 2.9.1-alt0.M90P.1
- backport to ALTLinux p9 (by rpmbph script)
* Sun Dec 13 2020 Pavel Vainerman <pv@altlinux.ru> 2.9.0-alt1
- (unet): message processing (zeop-copy optimization)
* Fri Jan 08 2021 Pavel Vainerman <pv@altlinux.ru> 2.9.1-alt1
- supported http-resolver (when localIOR=1)
* Thu Jan 07 2021 Pavel Vainerman <pv@altlinux.ru> 2.8.2-alt1
- supported "freeze vaule"
- modbus master: runtime reload config
- update docs
* Sat Jan 02 2021 Pavel Vainerman <pv@altlinux.ru> 2.8.1-alt3
- make style
- fixed docs
* Sun Dec 27 2020 Pavel Vainerman <pv@altlinux.ru> 2.8.1-alt2
- ALT spec: some fixes
* Sat Dec 05 2020 Pavel Vainerman <pv@altlinux.ru> 2.8.1-alt1
- (unet): unet recevier refactoring (optimization)
* Fri Dec 25 2020 Pavel Vainerman <pv@altlinux.ru> 2.8.1-alt1
- logserver/logreader refactoring
- update docs
- some python-module refactoring
* Sun Oct 25 2020 Pavel Vainerman <pv@altlinux.ru> 2.8-alt15
- minor fixes
......
......@@ -25,7 +25,9 @@
<BinDir name="./"/>
<LogDir name="./"/>
<DocDir name="./"/>
<LockDir name="./"/>
<LockDir name="/tmp/"/>
<HttpResolver name="HttpResolver"/>
<LocalIOR name="0"/>
<Services>
<LocalTimeService AskLifeTimeSEC="10" MaxCountTimers="100" name="TimeService"/>
<LocalInfoServer dbrepeat="1" name="InfoServer">
......
......@@ -3,10 +3,15 @@
# See doc: http://www.gnu.org/software/hello/manual/autoconf/Generic-Programs.html
# AC_PREREQ(2.59)
<<<<<<< HEAD
AC_INIT([uniset2], [2.8.1], pv@etersoft.ru)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME,AC_PACKAGE_VERSION)
=======
AC_INIT([uniset2], [2.9.1], pv@etersoft.ru)
AM_INIT_AUTOMAKE
>>>>>>> 2.9.1-alt1
LIBVER=2:8:0
LIBVER=11:1:9
AC_SUBST(LIBVER)
# AC_CONFIG_MACRO_DIR([m4])
......@@ -32,9 +37,10 @@ AC_ENABLE_SHARED(yes)
AC_ENABLE_STATIC(no)
AM_PROG_LIBTOOL
ASTYLE_OPT="-A1 -T -C -S -N -L -w -Y -M -f -p --mode=c --lineend=linux --align-reference=type --align-pointer=type --suffix=none --style=ansi"
ASTYLE_OPT="-A1 -T -C -S -L -w -N -Y -M -f -p --mode=c --lineend=linux --align-reference=type --align-pointer=type --suffix=none --style=ansi --convert-tabs -s4"
AC_SUBST(ASTYLE_OPT)
# Checks for libraries.
PKG_CHECK_MODULES(XML, libxml-2.0)
PKG_CHECK_MODULES(OMNI, omniORB4)
......@@ -73,6 +79,7 @@ else
fi
AM_CONDITIONAL(DISABLE_REST_API, test ${buildapi} = false)
AM_CONDITIONAL(ENABLE_REST_API, test ${buildapi} = true)
AC_SUBST(DISABLE_REST_API)
AC_SUBST(REST_API_CFLAGS)
AC_SUBST(REST_API_CLIBS)
......@@ -117,6 +124,7 @@ else
fi
AM_CONDITIONAL(DISABLE_SQLITE, test ${buildsqlite} = false)
AM_CONDITIONAL(ENABLE_SQLITE, test ${buildsqlite} = true)
# check xsltproc
AC_CHECK_PROG([XSLTPROC],[xsltproc],[yes])
......@@ -143,6 +151,8 @@ else
fi
AM_CONDITIONAL(DISABLE_MYSQL, test ${buildmysql} = false)
AM_CONDITIONAL(ENABLE_MYSQL, test ${buildmysql} = true)
#check pgsql support
AC_MSG_CHECKING([postgresql support])
......@@ -160,6 +170,7 @@ else
fi
AM_CONDITIONAL(DISABLE_PGSQL, test ${buildpgsql} = false)
AM_CONDITIONAL(ENABLE_PGSQL, test ${buildpgsql} = true)
#check rrd support
......@@ -178,6 +189,7 @@ else
fi
AM_CONDITIONAL(DISABLE_RRD, test ${buildrrd} = false)
AM_CONDITIONAL(ENABLE_RRD, test ${buildrrd} = true)
#check opentsdb support
AC_MSG_CHECKING([OpenTSDB backend])
......@@ -192,6 +204,7 @@ else
fi
AM_CONDITIONAL(DISABLE_OPENTSDB, test ${buildtsdb} = false)
AM_CONDITIONAL(ENABLE_OPENTSDB, test ${buildtsdb} = true)
#check io support
AC_MSG_CHECKING([io support])
......@@ -241,7 +254,7 @@ AC_SUBST(COMPORT_485F_CFLAGS)
#check logicproc build
AC_MSG_CHECKING([build logic processor extension])
buildlproc=true
AC_ARG_ENABLE(rrd, AC_HELP_STRING([--disable-logicproc], [disable build LogicProcessor extension]),
AC_ARG_ENABLE(logicproc, AC_HELP_STRING([--disable-logicproc], [disable build LogicProcessor extension]),
[ if test $enableval = yes; then buildlproc=true; else buildlproc=false; fi],[ buildlproc=true; ])
if test ${buildlproc} = true; then
AC_MSG_RESULT([enabled])
......@@ -250,6 +263,7 @@ else
fi
AM_CONDITIONAL(DISABLE_LOGICPROC, test ${buildlproc} = false)
AM_CONDITIONAL(ENABLE_LOGICPROC, test ${buildlproc} = true)
#check build extensions
ext=true
......@@ -297,6 +311,7 @@ else
fi
AM_CONDITIONAL(DISABLE_PYTHON, test ${buildpython} = false)
AM_CONDITIONAL(ENABLE_PYTHON, test ${buildpython} = true)
#check mqtt support
AC_MSG_CHECKING([mqtt support])
......@@ -316,6 +331,7 @@ else
fi
AM_CONDITIONAL(DISABLE_MQTT, test ${buildmqtt} = false)
AM_CONDITIONAL(ENABLE_MQTT, test ${buildmqtt} = true)
# check Doxygen
......@@ -388,6 +404,7 @@ else
fi
AM_CONDITIONAL(DISABLE_LOGDB, test ${buildlogdb} = false)
AM_CONDITIONAL(ENABLE_LOGDB, test ${buildlogdb} = true)
COV_LIBS=
COV_CFLAGS=
......@@ -579,6 +596,8 @@ AC_CONFIG_FILES([Makefile
extensions/tests/MQPerfTest/Makefile
extensions/LogDB/Makefile
extensions/LogDB/tests/Makefile
extensions/HttpResolver/Makefile
extensions/HttpResolver/tests/Makefile
testsuite/Makefile
wrappers/Makefile
wrappers/python/lib/Makefile
......
......@@ -13,22 +13,21 @@
- \ref sec_Concept_Process
\section sec_Concept_Object Объект
\section sec_Concept_Object Объект
В разных местах описаний, в зависимости от контекста,
под "объектом" подразумевается либо объект класса так или иначе наследующегося
от базового класса библиотеки UniSetObject, либо
некий концептуальный программный объект способный
получать и обрабатывать сообщения.
\section sec_Concept_ObjectTypes Основные типы объектов
\section sec_Concept_ObjectTypes Основные типы объектов
В библиотеке произведено условное деление на следующие типы объектов:
- (простые) объекты - наследуются от класса UniSetObject
- контроллеры - являются наследниками класса IOController
- сервисы - являются наследниками специальных классов
- узлы - в строгом смысле, не являются объектами,
но обладают уникальным идентификатором.
- (простые) объекты - наследуются от класса UniSetObject
- контроллеры - являются наследниками класса IOController
- сервисы - являются наследниками специальных классов
- узлы - в строгом смысле, не являются объектами, но обладают уникальным идентификатором.
\section sec_Concept_Message Сообщения
\section sec_Concept_Message Сообщения
Вся система взаимодействия между объектами в основном
построена на использовании сообщений (передаваемых
путём удаленного вызова специальных функций,
......@@ -52,8 +51,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
};
\endcode
\section sec_Concept_ObjectId Идентификатор объекта
\section sec_Concept_ObjectId Идентификатор объекта
Каждый объект, которому необходимо взаимодействовать с другими объектами
(в том числе датчиками см. \ref sec_Concept_Sensor) должен обладать уникальным
идентификатором. В качестве идентификатора выступает любое число типа \b UniSetTypes::ObjectId.
......@@ -74,7 +72,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
\code
<Configurations>
...
<ObjectsMap idfromfile="0">
<ObjectsMap idfromfile="0">
<nodes port="2809">
<item name="LocalhostNode" alias="" textname="Локальный узел" ip="127.0.0.1" dbserver=""/>
<item name="Node2" alias="" textname="Локальный узел" ip="127.0.0.1" dbserver=""/>
......@@ -100,7 +98,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
<item name="TestProc1"/>
<item name="TestProc2"/>
</objects>
</ObjectsMap>
</ObjectsMap>
...
</Configurations>
\endcode
......@@ -130,7 +128,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
\code
<Configurations>
...
<ObjectsMap idfromfile="1">
<ObjectsMap idfromfile="1">
<nodes port="2809">
<item id="1000" name="LocalhostNode" alias="" textname="Локальный узел" ip="127.0.0.1" dbserver=""/>
<item id="1001" name="Node2" alias="" textname="Локальный узел" ip="127.0.0.1" dbserver=""/>
......@@ -156,7 +154,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
<item id="200" name="TestProc1"/>
<item id="201" name="TestProc2"/>
</objects>
</ObjectsMap>
</ObjectsMap>
...
</Configurations>
\endcode
......@@ -166,17 +164,23 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
не сложными скриптами).
\section sec_Concept_Repository Репозиторий объектов
\section sec_Concept_Repository Сервис имён (Names service)
Сервис имён предназначен для получения ссылок на объекты (для возможности удалённого вызова)
по имени объекта. Все объекты и датчики регистрируются в этом сервисе и становятся доступны
для удалённого вызова. В данном проекте используется реализация службы имён входящая в состав
библиотеки omniORB. Сервис поставляется отдельной утилитой под названием omniNames.
см. \ref ConfigurationPage_secOmniNames
\section sec_Concept_Sensor Датчик
\section sec_Concept_Sensor Датчик
Датчик - это одно из базовых понятий при построении систем на основе libuniset.
Датчик - это информационная единица. Практически любая информация
(о событиях, о состоянии того или иного процесса, объекта, сообщение оператору и т.п.)
передаётся через состояние "датчика". В библиотеке предусмотрено четыре типа датчиков.
- DI - UniversalIO::DigitalInput - дискретный вход
- DO - UniversalIO::DigitalOutput - дискретный выход
- AI - UniversalIO::AnalogInput - аналоговый вход
- AO - UniversalIO::AnalogOutput - аналоговый выход
- DI - UniversalIO::DigitalInput - дискретный вход
- DO - UniversalIO::DigitalOutput - дискретный выход
- AI - UniversalIO::AnalogInput - аналоговый вход
- AO - UniversalIO::AnalogOutput - аналоговый выход
Исходно данные типы используются непосредственно процессами ввода/вывода.
"Выходы"(DO,AO) - это, команды "от системы управления"
......@@ -191,7 +195,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
на передачу цифровой информации (не текстовой).
Например CAN, ModbusRTU, ModbusTCP и т.п.
\section sec_Concept_Process Процесс
\section sec_Concept_Process Процесс
Под процессом в документации чаще всего подразумевается системный
процесс (запущенная программа) выполняющий те или иные функции управления
и обменивающийся для этого с другими процессами сообщениями или
......
/*! \page ConfigurationPage Конфигурирование системы
- \ref ConfigurationPage_secCommon
- \ref ConfigurationPage_secOmniORB
- \ref ConfigurationPage_secCommon
- \ref ConfigurationPage_secOmniORB
- \ref ConfigurationPage_secOmniNames
- \ref ConfigurationPage_secLocalIOR
\section ConfigurationPage_secCommon Общее описание
\section ConfigurationPage_secCommon Общее описание
Для конфигурирования системы используется файл (обычно "configure.xml").
Конфигурация является глобальным объектом. Для получения доступа к ней используется функция auto conf = uniset_conf();
До начала работы, обычно в функции main(), конфигурация должна быть инициализирована при помощи функции uniset_init().
При этом третий параметр, указывающий название конфигурационного файла, является не обязательным.
По умолчанию обрабатывается аргумент командной строки --confile filename.
Для конфигурирования системы используется файл (обычно "configure.xml").
Конфигурация является глобальным объектом. Для получения доступа к ней используется функция auto conf = uniset_conf();
До начала работы, обычно в функции main(), конфигурация должна быть инициализирована при помощи функции uniset_init().
При этом третий параметр, указывающий название конфигурационного файла, является не обязательным.
По умолчанию обрабатывается аргумент командной строки --confile filename.
\code
...
......@@ -23,7 +25,6 @@ int main(int argc, char **argv)
uniset_init(argc, argv, "configure.xml");
...
...
}
catch(Exception& ex )
{
......@@ -33,28 +34,63 @@ int main(int argc, char **argv)
{
cerr << "Неизвестное исключение!!!!"<< endl;
}
...
...
}
\endcode
\section ConfigurationPage_secOmniORB Конфигурирование OmniORB
Для возможности задать напрямую параметры для omniORB заложена специальная секция <omniORB>.
\section ConfigurationPage_secOmniORB Конфигурирование OmniORB
Для возможности задать напрямую параметры для omniORB заложена специальная секция <omniORB>.
В данную секцию можно записывать любые параметры поддерживаемые библиотекой omniORB.
Формат и название параметров см. документацию по omniORB.
В данную секцию можно записывать любые параметры поддерживаемые библиотекой omniORB.
Формат и название параметров см. документацию по omniORB.
Пример:
Пример:
\code
<omniORB>
<omniORB>
<option name="endPoint" arg="giop:tcp:host1:"/>
<option name="endPoint" arg="giop:tcp:host2:" error_if_not_available="1"/>
</omniORB>
</omniORB>
\endcode
Для параметра 'endPoint' встроена дополнительная проверка доступности указанного адреса.
\warning По умолчанию \b недоступность \b игнорируется, если не указан параметр \a error_if_not_available="1"
Помимо этого можно задать параметр \a ignore_checking="1", чтобы не происходило проверки доступности endPoint.
\section ConfigurationPage_secOmniNames Сервис имён
Сервис имён предназначен для получения ссылок на объекты (для возможности удалённого вызова)
по имени объекта. В данном проекте используется реализация службы имён входящая в состав
библиотеки omniORB. Сервис поставляется отдельной утилитой под названием omniNames, которая запускается отдельно.
В файле настроек проекта необходимо указать адрес сервиса
\code
<UniSet>
...
<NameService host="localhost" port="2809"/>
</UniSet>
\endcode
Для параметра 'endPoint' встроена дополнительная проверка доступности указанной адреса.
\warning По умолчанию \b недоступность \b игнорируется, если не указан параметр \a error_if_not_available="1"
Для большей надёжности рекомендуется запускать сервис имён на каждом узле отдельно, чтобы локальные объекты регистрировались в нём.
Но в общем случае сервис имён может быть запущен один на всю систему. Режим работы с использованием сервиса имён, позволяет
прозрачно обращаться к объектам где бы они не находились, на других узлах или локально.
Помимо этого можно задать параметр \a ignore_checking="1", чтобы не происходило проверки доступности endPoint.
\section ConfigurationPage_secLocalIOR Режим работы без сервиса имён
Режим работы без сервиса имён включается в настройках
\code
<UniSet>
...
<LocalIOR name="1"/>
<LockDir name="/var/lock/projectname/"/>
...
</<UniSet>
\endcode
или при запуске, при помощи аргумента командной строки `--localIOR 1`
Данный режим предназначен для работы без использования сервиса имён (omniNames). При этом IOR-ссылки на объекты и датчики
публикуются локально в файлах, в каталоге `LockDir`. Такой режим значительно ускоряет запуск приложений, т.к. регистрация большого
количества датчиков в сервисе имён занимает много времени. Но по умолчанию в данном режиме работы недоступны удалённые вызовы на другие узлы. Т.е. например такой вызов работать не будет
\code
uniset2-admin --confile xxx --getValue sensor1@node2
\endcode
Для того чтобы удалённые вызовы были доступны, необходимо на каждом узле запустить специальный сервис HttpResolver
(см. \ref page_HttpResolver).
*/
/* OBSOLETE DOC!!!
\page ControlProcessPage Как писать процесс управления
\page ControlProcessPage Как писать процесс управления
- \ref pgCP_secDeclareIDL
- \ref pgCP_secImplementation
- \ref pgCP_secMain
- \ref pgCP_secLT_Object
- \ref pgCP_secRecomendation
- \ref pgCP_secDeclareIDL
- \ref pgCP_secImplementation
- \ref pgCP_secMain
- \ref pgCP_secLT_Object
- \ref pgCP_secRecomendation
Все рядовые процессы управления должны наследоваться от класса UniSetObject.
\par
Все рядовые процессы управления должны наследоваться от класса UniSetObject.
\par
Рассмотрим процесс написания на примере самого простого процесса управления реализующего
две функции \c on() и \c off(). Чтобы эти функции были доступны другим процессам необходимо
объявить интерфейс на языке IDL.
\section pgCP_secDeclareIDL Объявление интерфейса на IDL
\section pgCP_secDeclareIDL Объявление интерфейса на IDL
Как писалось выше процесс управления должен наследоваться UniSetObject, это касается и IDL-интерфейса.
Пример объявления
\code
......@@ -24,8 +24,8 @@
// ------------------------------------------------------------------------------------------
interface TestActiveProcess_i: UniSetObject_i
{
void on();
void off();
void on();
void off();
};
#endif
\endcode
......@@ -37,24 +37,24 @@ interface TestActiveProcess_i: UniSetObject_i
На основе этих файлов вы реализуете свой интерфейс на С++.
\section pgCP_secImplementation Реализация интерфейса на C++
\section pgCP_secImplementation Реализация интерфейса на C++
Необходимо создать класс реализующий объявленый интерфейс. Формирование названия класса и правила наследования
см. \ref UniSetLibStylePage.
\par
Базовые функции интерфейса UniSetObject_i уже реализованы в классе UniSetObject. Поэтому остается только
наследоваться от него и реализовать недостающие функции. В итоге получаем
\code
#ifndef TestActiveProcess_H_
#define TestActiveProcess_H_
// ------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------
#include "UniSetObject.h"
#include "TestActiveProcess_i.hh"
// ------------------------------------------------------------------------------------------
class TestActiveProcess:
#ifndef TestActiveProcess_H_
#define TestActiveProcess_H_
// ------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------
#include "UniSetObject.h"
#include "TestActiveProcess_i.hh"
// ------------------------------------------------------------------------------------------
class TestActiveProcess:
public POA_TestActiveProcess_i,
public UniSetObject
{
{
public:
// ------- Конструктор с заданием обязательных параметров ---------------
......@@ -79,20 +79,20 @@ interface TestActiveProcess_i: UniSetObject_i
// Сделан protected чтобы нельзя было создать объект класса
// не задав обязательных параметров
TestActiveProcess();
};
};
\endcode
Реализация функций может выглядеть примерно следующим образом:
\code
// ------------------------------------------------------------------------------------------
void TestActiveProcess::TestActiveProcess( UniSetTypes::ObjectId id ):
// ------------------------------------------------------------------------------------------
void TestActiveProcess::TestActiveProcess( UniSetTypes::ObjectId id ):
UniSetObject(id)
{
}
// ------------------------------------------------------------------------------------------
{
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::processingMessage( UniSetTypes::VoidMessage *msg)
{
void TestActiveProcess::processingMessage( UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
......@@ -129,11 +129,11 @@ interface TestActiveProcess_i: UniSetObject_i
cout << myname << "(processingMessage): " << ex << endl;
}
catch(...){}
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::askSensors(UniversalIO::UIOCommand cmd)
{
void TestActiveProcess::askSensors(UniversalIO::UIOCommand cmd)
{
try
{
// дискретные датчики
......@@ -148,18 +148,18 @@ interface TestActiveProcess_i: UniSetObject_i
{
cout << myname << ex << endl;
}
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::sigterm( int signo )
{
void TestActiveProcess::sigterm( int signo )
{
cout << myname << "(sigterm): signo " << signo << endl;
askSensors( UniversalIO::UIODontNotify );
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::sysCommand( SystemMessage* sm )
{
void TestActiveProcess::sysCommand( SystemMessage* sm )
{
cout << myname << "(sysCommand): command= "<< sm->command << endl;
switch(sm->command)
{
......@@ -178,20 +178,20 @@ interface TestActiveProcess_i: UniSetObject_i
default:
break;
}
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::sensorInfo( SensorMessage *si )
{
void TestActiveProcess::sensorInfo( SensorMessage *si )
{
cout << myname << "(sensorInfo): name" << conf->oind.getNameById(si->id,si.node) << endl;
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
void TestActiveProcess::timerInfo( UniSetTypes::TimerMessage* tm )
{
void TestActiveProcess::timerInfo( UniSetTypes::TimerMessage* tm )
{
cout << myname << "(timerInfo): timerId=" << tm->id << endl;
}
// ------------------------------------------------------------------------------------------
}
// ------------------------------------------------------------------------------------------
\endcode
......@@ -199,16 +199,16 @@ interface TestActiveProcess_i: UniSetObject_i
\code
#include "ObjectsMap.h"
#include "TestActiveProcess.h"
#include "ObjectsActivator.h"
#include "Configuration.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
#include "ObjectsMap.h"
#include "TestActiveProcess.h"
#include "ObjectsActivator.h"
#include "Configuration.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
int main( int argc, char **argv )
{
int main( int argc, char **argv )
{
try
{
conf = new Configuration(argc, (const char**)argv, "configure.xml", (ObjectInfo*)ObjectsMap);
......@@ -230,7 +230,7 @@ interface TestActiveProcess_i: UniSetObject_i
}
return 0;
}
}
\endcode
......@@ -263,8 +263,8 @@ interface TestActiveProcess_i: UniSetObject_i
\endcode
Функция UniSetObject_LT::askTimer() повторяет интерфейс UniversalInterface::askTimer().
Реализация построена, на переопределении функции UniSetObject::callback(), поэтому если поток
не будет создан, таймеры работать не будут.
\sa LT_Object, UniSetObject_LT, ObjectsManager_LT
не будет создан, таймеры работать не будут.
\sa LT_Object, UniSetObject_LT, ObjectsManager_LT
......@@ -282,7 +282,7 @@ interface TestActiveProcess_i: UniSetObject_i
\warning Заказ датчиков может (и должен) происходить \b только после активизации. Ваш процесс НЕ будет доступен
для приема команд и сообщений пока он не активизирован.
\par
\par
Вот вроде и все пока...
*/
\ No newline at end of file
/*! \page DebugPage Описание использования функций отладки
Класс для вывода отладочных сообщений называется DebugStream.
Сообщения могут выводится на экран и в файл, отбираться по
определённым критериям и до определённого уровня.
Класс для вывода отладочных сообщений называется DebugStream.
Сообщения могут выводится на экран и в файл, отбираться по
определённым критериям и до определённого уровня.
- \ref subUsing
- \ref subConf
- \ref subUsing
- \ref subConf
\subsection subUsing Использование
Для использования нужно создать свой объект класса DebugStream или
использовать глобальный объект UniSetTypes::unideb.
Для переключения вывода отладки в файл, используйте функцию logFile(char const *f);
\subsection subUsing Использование
Для использования нужно создать свой объект класса DebugStream или
использовать глобальный объект UniSetTypes::unideb.
Для переключения вывода отладки в файл, используйте функцию logFile(char const *f);
Описание всех имеющихся функций находится в файле DebugStream.h
на английском языке.
Описание всех имеющихся функций находится в файле DebugStream.h
на английском языке.
Функция unideb[...] по умолчанию выводит в строку дату и время.
Функция unideb(...) просто выводит строку (в конец предыдущему потоку).
Функция unideb[...] по умолчанию выводит в строку дату и время.
Функция unideb(...) просто выводит строку (в конец предыдущему потоку).
\par Пример использования:
\code
......@@ -40,8 +40,8 @@
\endcode
Если вы хотите использовать отладочный вывод из критичного к времени
кода, используйте следующую конструкцию:
Если вы хотите использовать отладочный вывод из критичного к времени
кода, используйте следующую конструкцию:
\code
if (unideb.debugging(Debug::INFO)) {
......@@ -50,7 +50,7 @@
\endcode
\subsection subConf Конфигурирование логов
\subsection subConf Конфигурирование логов
Конфигурирование логов можно производить, при помощи файла конфигурации или через командную строку.
Например UniSetTypes::unideb настраивается в конфигурационном файле следующим образом:
......
/*!
\page MutexHowToPage Как пользоваться uniset_mutex и uniset_mutex_lock
\page MutexHowToPage Как пользоваться uniset_mutex и uniset_mutex_lock
\par
"мьютекс"(mutex) - получено от англ. Mutual Exclusive. (нечто вроде "взаимоисключение")
\par
"мьютекс"(mutex) - получено от англ. Mutual Exclusive. (нечто вроде "взаимоисключение")
\par
Основными операциями для мьютексов, помимо создания и уничтожения, являются операции lock и unlock.
Логически работа с мьютексом могла бы выглядеть так (псевдокод)
Основными операциями для мьютексов, помимо создания и уничтожения, являются операции lock и unlock.
Логически работа с мьютексом могла бы выглядеть так (псевдокод)
\code
\code
Mutex mutex;
...
mutex.lock();
DoSomething();
mutex.unlock();
\endcode
\endcode
Но в общем случае это ни к чему хорошему не приведет, т.к. если в \c DoSomething() возникнет исключение, то
\c mutex.unlock() уже не выполнится. Конечно можно использовать \c try...catch, но желательно, чтобы
код работал независимо от ситуации. Для этого введен класс \b uniset_mutex_lock. При его использовании получается
следующий код (один из вариантов использования):
\code
using namespase UniSetTypes;
...
uniset_mutex mutex;
...
{
Но в общем случае это ни к чему хорошему не приведет, т.к. если в \c DoSomething() возникнет исключение, то
\c mutex.unlock() уже не выполнится. Конечно можно использовать \c try...catch, но желательно, чтобы
код работал независимо от ситуации. Для этого введен класс \b uniset_mutex_lock. При его использовании получается
следующий код (один из вариантов использования):
\code
using namespase UniSetTypes;
...
uniset_mutex mutex;
...
{
uniset_mutex_lock lock(mutex); // вызов mutex.lock() как часть кода конструктора
DoSomething();
} // <-- Заканчивается зона видимости lock-а и происходит вызов mutex.unlock() как часть кода деструктора
\endcode
В этом случае, даже если в \c DoSomethig() будет сгенерировано исключение ресурс будет освобожден
при вызове деструктора. Вот и все решение...
\par
} // <-- Заканчивается зона видимости lock-а и происходит вызов mutex.unlock() как часть кода деструктора
\endcode
В этом случае, даже если в \c DoSomethig() будет сгенерировано исключение ресурс будет освобожден
при вызове деструктора. Вот и все решение...
\par
Главное не забывайте ставить скобочки...
\par
Желательно не использовать \c mutex.lock() и \c uniset_mutex.unlock() в чистом виде, а только совместно с
\b uniset_mutex_lock. Кроме особых случаев (см. \ref secWarning).
\par
Следует помнить, что мьютексы \b фактически никаких ресурсов не захватывают, это только флаг означающий,
что ресурс занят. Поэтому работать с ними надо внимательно и не забывать блокировать ресурс там где это надо.
\par
\par
Желательно не использовать \c mutex.lock() и \c uniset_mutex.unlock() в чистом виде, а только совместно с
\b uniset_mutex_lock. Кроме особых случаев (см. \ref secWarning).
\par
Следует помнить, что мьютексы \b фактически никаких ресурсов не захватывают, это только флаг означающий,
что ресурс занят. Поэтому работать с ними надо внимательно и не забывать блокировать ресурс там где это надо.
\par
Описания классов см. UniSetTypes::uniset_mutex и UniSetTypes::uniset_mutex_lock
\section secWarning Особые случаи
Если в \c DoSomethig() будет вызвана \c exit(0), \c abort() или что-нибудь подобное,
то unlock не произойдет. В таком случае следовало бы напрямую вызывать \c unlock() до вызова сигнала, но эти случаи редкие и если
возникнет необходимость, то можно будет вместо \a protected сделать их \a public.
\section secWarning Особые случаи
Если в \c DoSomethig() будет вызвана \c exit(0), \c abort() или что-нибудь подобное,
то unlock не произойдет. В таком случае следовало бы напрямую вызывать \c unlock() до вызова сигнала, но эти случаи редкие и если
возникнет необходимость, то можно будет вместо \a protected сделать их \a public.
\note Описание составлено на основе описания мьютексов из книги А.Цимбала "Технология CORBA для профессионалов".
\note Описание составлено на основе описания мьютексов из книги А.Цимбала "Технология CORBA для профессионалов".
*/
\ No newline at end of file
/* OBSOLETE DOC!!!
\page IONotifyControllerPage Как писать IONotifyController (процесс ввода/вывода)
\page IONotifyControllerPage Как писать IONotifyController (процесс ввода/вывода)
- \ref pgIONC_secDeclareIDL
- \ref pgIONC_secImplementation
- \ref pgIONC_secMain
- \ref pgIONC_secLT_Object
- \ref pgIONC_secRecomendation
- \ref pgIONC_secDeclareIDL
- \ref pgIONC_secImplementation
- \ref pgIONC_secMain
- \ref pgIONC_secLT_Object
- \ref pgIONC_secRecomendation
Все i/o процессы должны наследоваться от класса IOController. Если вам необходимо написать i/o процесс, который
помимо операций i/o еще и уведомляет об изменении состояния входов(выходов), то наследуйтесь от класса IONotifyController.
Эти классы объявляют минимальный(базовый) интерфейс для IOController-ов, который вы можете расширять.
Все i/o процессы должны наследоваться от класса IOController. Если вам необходимо написать i/o процесс, который
помимо операций i/o еще и уведомляет об изменении состояния входов(выходов), то наследуйтесь от класса IONotifyController.
Эти классы объявляют минимальный(базовый) интерфейс для IOController-ов, который вы можете расширять.
\par
Рассмотрим написание на примере простого процесса ввода/вывода, позволяющего заказывать у себя уведомления, а
так же обладающего дополнительной функцией CardIOTypes getCardIOType();
\par
Рассмотрим написание на примере простого процесса ввода/вывода, позволяющего заказывать у себя уведомления, а
так же обладающего дополнительной функцией CardIOTypes getCardIOType();
\section pgIONC_secDeclareIDL Объявление интерфейса на IDL
\section pgIONC_secDeclareIDL Объявление интерфейса на IDL
\note Написание интерфейса на IDL требуется, только если вам необходимо расширить базовый набор
IDL-функций. Все функции объявленные здесь станут доступны внешним объекта (локальным и удалённым).
......@@ -47,7 +47,7 @@
На основе этих файлов вы реализуете свой интерфейс на С++.
\section pgIONC_secImplementation Реализация интерфейса на C++
\section pgIONC_secImplementation Реализация интерфейса на C++
Необходимо создать класс реализующий объявленый интерфейс. Формирование названия класса и правила наследования
см. \ref UniSetLibStylePage.
\par
......@@ -148,19 +148,19 @@
\par
В завершение реализация запуска
\section pgIONC_secMain Написание функции main() для подключения процесса
\section pgIONC_secMain Написание функции main() для подключения процесса
\code
#include "ObjectsMap.h"
#include "MyNotifyController.h"
#include "ObjectsActivator.h"
#include "Configuration.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
int main( int argc, char **argv )
{
#include "ObjectsMap.h"
#include "MyNotifyController.h"
#include "ObjectsActivator.h"
#include "Configuration.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
int main( int argc, char **argv )
{
conf = new Configuration(argc, (const char**)argv, "configure.xml", (ObjectInfo*)ObjectsMap);
MyNotifyController nc( idMyNotifyController ); // idMyNotifyController - уникальный идентификатор объекта
......@@ -174,8 +174,8 @@
catch(...)
{
}
}
\endcode
}
\endcode
\section pgIONC_secLT_Object Создание автономного процесса, не зависящего от TimerService-а
......@@ -206,11 +206,11 @@
\endcode
Функция IONotifyController_LT::askTimer() повторяет интерфейс UniversalInterface::askTimer().
Реализация построена, на переопределении функции UniSetObject::callback(), поэтому если поток
не будет создан, таймеры работать не будут.
\sa LT_Object
не будет создан, таймеры работать не будут.
\sa LT_Object
\section pgIONC_secRecomendation Некоторые общие рекомендации
\section pgIONC_secRecomendation Некоторые общие рекомендации
-# Все функции и параметры должны быть откоментированы.
-# Заказ датчиков, таймеров, работа с информацией в основном происходит при помощи UniversalInterface. В каждом
......@@ -218,9 +218,9 @@
-# Не регистрируйте датчики в конструкторе.
-# Не вызывайте разрегистрацию в деструкторе.
\par
\par
Вот вроде и все пока...
\sa \ref ControlProcessPage
\sa \ref ControlProcessPage
*/
\ No newline at end of file
/* OBSOLETE DOC!!!
\page ObjectRepositoryPage Репозиторий объектов
\page ObjectRepositoryPage Репозиторий объектов
Репозиторий объектов предназначен для хранения и получения ссылок на объекты, с целью дальнейшего
использования функций предоставленных этими объектами. Объекты регистрирующиеся в репозитории могут быть удаленными...
использования функций предоставленных этими объектами. Объекты регистрирующиеся в репозитории могут быть удаленными...
- \ref subRegCommon
- \ref subReg
- \ref subResolve
- \ref subRegCommon
- \ref subReg
- \ref subResolve
\section subRegCommon Вводная
\section subRegCommon Вводная
При наследовании от UniSetObject (и его потомков) регистрация в репозитории происходит автоматически.
Поэтому регистрироваться отдельно нет необходимости.
Поэтому регистрироваться отдельно нет необходимости.
\section subReg Регистрация
\section subReg Регистрация
Для регистрации существует следующие функции.
По текстовому имени
......@@ -72,7 +72,7 @@
\endcode
\section subResolve Получение ссылки на объект
\section subResolve Получение ссылки на объект
Для получения ссылки лучше всего пользоваться
- UniSetTypes::ObjectPtr UniversalInterface::resolve( UniSetTypes::ObjectId id )
......
......@@ -2,10 +2,29 @@
В библиотеке предусмотрен REST API. Есть два "уровня" доступа к REST API.
Первый - это встроенный в UniSetActivator http-сервер.
\ref sec_SM_REST_API
\sa \ref sec_SM_REST_API
\sa \ref sec_act_HttpAPI
Второй уровень. Это функция apiRequest(query) которую можно вызывать у каждого
объекта посредством RPC. Её вызов не требует наличия запущенного http-сервера.
объекта посредством RPC. Её вызов \b не \b требует наличия запущенного http-сервера.
Из консоли вызов можно делать при помощи утилиты uniset2-admin.
<br>Например так можно получить свойство "textname" для датчика ID=100
\code
uniset2-admin --apiRequest ObjectName "/api/v01/configure/get?100&props=textname"
\endcode
<br>А так можно посмотреть текущие параметры для объекта MyProcess
\code
uniset2-admin --apiRequest MyProcess "/api/v01/params/get"
\endcode
<br>Разные процессы могут расширять список базовых поддерживаемых команд.
Для того, чтобы узнать какие объект поддерживает команды, можно вызвать команду help
\code
uniset2-admin --apiRequest MyProcess "/api/v01/help"
\endcode
\warning С точки зрения надёжности функционирования системы наличие запущенного
http-сервера, а так же наличие функций \b getInfo(userparam) и \b apiRequest(query)
......
// эти разделы сформируются автоматически из описаний сделанных в соответствующих h-файлах
/*!
\page ServicesPage Сервисы
- \ref secDBServer
\section secDBServer Сервер БД
\sa \ref page_DBServer_MySQL
*/
\ No newline at end of file
......@@ -45,10 +45,10 @@
\section secORep Функции работы с репозиторием объектов
- \ref void UniversalInterface::registered(...)
- \ref void UniversalInterface::unregister(...)
- \ref void UniversalInterface::resolve(...)
- \ref ObjectId UniversalInterface::getIdByName(...)
- \ref const char* UniversalInterface::getNameById(...)
- \ref void UniversalInterface::unregister(...)
- \ref void UniversalInterface::resolve(...)
- \ref ObjectId UniversalInterface::getIdByName(...)
- \ref const char* UniversalInterface::getNameById(...)
\section secTimers Заказ таймеров
- \ref void UniversalInterface::askTimer(...)
......
/*!
\page DependsPage Зависимости между датчиками
Существует два механизма реализующих зависимость между датчиками:
Существует два механизма реализующих зависимость между датчиками:
- \ref pgDep_secIOControl
- \ref pgDep_secIOBase
\section pgDep_secIOControl Зависимость на уровне IOController (SharedMemmory)
\section pgDep_secIOControl Зависимость на уровне IOController (SharedMemmory)
Механизм зависимостей реализован в классе IOController.
Механизм зависимостей реализован в классе IOController.
Пример записи "зависимости" в configure.xml:
Пример записи "зависимости" в configure.xml:
\code
<item textname="...." iotype="..." .../>
<item textname="...." iotype="..." .../>
<consumers>
<consumers>
<depends>
<depend name="Sensor1" filter="val" />
<depend name="Sensor2" filter2="val1" />
</depends>
</item>
</item>
\endcode
При считывании конф. файла можно задавать фильтры.
При считывании конф. файла можно задавать фильтры.
ПОКА РЕАЛИЗОВАНА ЗАВИСИМОСТЬ ТОЛЬКО ОТ ОДНОГО ДАТЧИКА!
т.е. <depend> может быть только один.
ПОКА РЕАЛИЗОВАНА ЗАВИСИМОСТЬ ТОЛЬКО ОТ ОДНОГО ДАТЧИКА!
т.е. <depend> может быть только один.
\section pgDep_secIOBase Зависимость на уровне IOBase
Механизм зависимостей между датчиками на уровне IOBase,
\section pgDep_secIOBase Зависимость на уровне IOBase
Механизм зависимостей между датчиками на уровне IOBase,
работает на уровне процессов обмена использующих IOBase.
В ним относятся IOControl, ModbusMaster (RTU,TCP) и т.п.
Плюсом данного механизма является, то, что он обеспечивает
......@@ -42,9 +42,9 @@
Следует иметь ввиду, что этот механизм не действует при сохранении значений, например при помощи uniset-admin,
в отличие от механизма \ref pgDep_secIOControl
Пример записи "зависимости" в configure.xml:
Пример записи "зависимости" в configure.xml:
\code
<item textname="...." iotype="..." ... depend="OtherSensor_AS" depend_value="2" />
<item textname="...." iotype="..." ... depend="OtherSensor_AS" depend_value="2" />
\endcode
В данном случае подразумевается, что разрешающим датчиком является OtherSensor_AS=2.
......
# Заморозка (фиксация) значения датчика в SM
В библиотеке поддерживается механизм, позволяющий замораживать значение датчика и оно не будет меняться,
пока не будет обратно"разморожено". При этом функция `setValue()` будет продолжать работать и будет менять
значение датчика в памяти SM. Но пока датчик не будет разморожен эти изменения не будут видны.
После разморозки датчика, будет выставлено текущее значение.
Для управления "заморозкой" существует две возможности
### Заморозка значения при помощи утилиты uniset2-admin
Для того, чтобы заморозить какое-то значение достаточно вызвать команду
```
uniset2-admin --confile xxx --freezeValue SID@node=value 1
```
Где:
- `SID` - это имя или идентификатор датчика
- `node` - узел на котором датчик находится (необязательный параметр)
- `value` - значение которое будет установлено у датчика (при "разморозке" значение не важно)
- `1` - заморозить
Можно замораживать или размораживать сразу несколько датчиков.
- Заморозить датчики
```
uniset2-admin --confile xxx --freezeValue sens1=10,sens2=100,sens3=42 1
```
- Разморозить датчики
```
uniset2-admin --confile xxx --freezeValue sens1,sens2,sens3 0
```
### Заморозка значения при помощи UInterface (в коде)
Для "заморозки/разморозки" значений в коде в UInterface предусмотрена функция
```
void freezeValue( const IOController_i::SensorInfo& si, bool set, long value, uniset::ObjectId supplier );
```
Пример заморозки:
```
...
IOController_i::SensorInfo si;
si.id = 100; // sensorID
si.node = conf->getLocalNode();
ui->freezeValue(si, true, 100);
```
/*! \page page_Uniset Краткое описание библиотеки libuniset
- \ref pg_UniSet_Common
- \ref pg_Uniset_Processes
- \ref pg_UniSet_Network
- \ref pg_UniSet_Utilities
- \ref pg_UniSet_Common
- \ref pg_Uniset_Processes
- \ref pg_UniSet_Network
- \ref pg_UniSet_Utilities
\section pg_UniSet_Common Общее описание libuniset
......
/*!
\mainpage
\mainpage
\image html uniset.png
\image html uniset.png
\section MainSection Оглавление
\section MainSection Оглавление
- \ref page_Concept
- \ref page_Uniset
- \ref UniSetLibStylePage
- \ref page_Concept
- \ref page_Uniset
*/
/*!
\page PythonPage Интерфейс на python
В проект входит два простых интерфейса для python:
- \ref pgPython_secUniSet
- \ref pgPython_secModbus
\section pgPython_secUniSet Простой python-интерфейс для работы с uniset
В данном интерфейсе реализован только самые просты функции \b getValue и \b setValue.
\sa UConnector
Пример использования:
\code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from uniset import *
if __name__ == "__main__":
lst = Params_inst()
for i in range(0, len(sys.argv)):
if i >= Params.max:
break;
lst.add( sys.argv[i] )
p = []
print "lst: class: " + str(p.__class__.__name__)
try:
uc1 = UConnector( lst, "test.xml" )
# print "(0)UIType: %s" % uc1.getUIType()
print "(1)getShortName: id=%d name=%s" % (1, uc1.getShortName(1))
# print " getName: id=%d name=%s" % (1, uc1.getName(101))
# print " getTextName: id=%d name=%s" % (1, uc1.getTextName(101))
# print "\n"
# print "getShortName: id=%d name=%s" % (2, uc1.getShortName(109))
# print " getName: id=%d name=%s" % (2, uc1.getName(109))
# print " getTextName: id=%d name=%s" % (2, uc1.getTextName(109))
try:
print "(1)setValue: %d=%d" % (3,22)
uc1.setValue(3,22,DefaultID)
except UException, e:
print "(1)setValue exception: " + str(e.getError())
try:
print "(1)getValue: %d=%d" % ( 3, uc1.getValue(3,DefaultID) )
except UException, e:
print "(1)getValue exception: " + str(e.getError())
except UException, e:
print "(testUI): catch exception: " + str(e.getError())
\endcode
\section pgPython_secModbus Простой python-интерфейс для работы с modbus
В данном интерфейсе реализованы функции Modbus master на основе использования libuniset.
Он имеет ряд простых функций getWord(), getByte(), getBit(), а так же универсальная функция
UModbus::mbread() позволяющая более тонко определять параметры запроса.
Для записи одного регистра (!) реализована UModbus::mbwrite()
\sa UModbus
Пример использования:
\code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from uniset import *
if __name__ == "__main__":
try:
mb = UModbus()
print "UIType: %s" % mb.getUIType()
mb.connect("localhost",2048)
try:
print "Test READ functions..."
for f in range(1,5):
print "func=%d reg=%d" % (f,22)
val = mb.mbread(0x01,22,f,"unsigned",-1)
# val = mb.mbread(0x01,22)
print "val=%d"%val
print "getWord: %d" % mb.getWord(0x01,22)
print "getByte: %d" % mb.getByte(0x01,22)
print "getBit: %d" % mb.getBit(0x01,22,3)
# print ""
# print "Test WRITE functions..."
# for f in range(1,6):
# print "func=%d reg=%d" % (f,22)
# val = mb.getValue(f,0x01,22,"unsigned",-1)
except UException, e:
print "exception: " + str(e.getError())
except UException, e:
print "(testUModbus): catch exception: " + str(e.getError())
\endcode
*/
# Интерфейс на python
В проект входит несколько python-интерфейсов
## Интерфейс для работы с uniset
В данном интерфейсе реализованы только самые просты функции \b getValue и \b setValue и некоторые вспомогательные,
позволяющие получать дополнительную информацию по датчикам.
\sa [UConnector](\ref UConnector)
Пример использования:
```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from uniset import *
if __name__ == "__main__":
lst = Params_inst()
for i in range(0, len(sys.argv)):
if i >= Params.max:
break;
lst.add( sys.argv[i] )
try:
uc = UConnector( lst, "test.xml" )
print "(0)UIType: %s" % uc1.getUIType()
print "(1)getShortName: id=%d name=%s" % (1, uc.getShortName(1))
print " getName: id=%d name=%s" % (1, uc.getName(101))
print " getTextName: id=%d name=%s" % (1, uc.getTextName(101))
print "\n"
print "getShortName: id=%d name=%s" % (2, uc.getShortName(109))
print " getName: id=%d name=%s" % (2, uc.getName(109))
print " getTextName: id=%d name=%s" % (2, uc.getTextName(109))
try:
print "(1)setValue: %d=%d" % (3,22)
uc.setValue(3,22,DefaultID)
except UException, e:
print "(1)setValue exception: " + str(e.getError())
try:
print "(1)getValue: %d=%d" % ( 3, uc.getValue(3,DefaultID) )
except UException, e:
print "(1)getValue exception: " + str(e.getError())
except UException, e:
print "(testUI): catch exception: " + str(e.getError())
```
## Интерфейс для работы с modbus
В данном интерфейсе реализованы функции Modbus master на основе использования libuniset.
Он имеет ряд простых функций getWord(), getByte(), getBit(), а так же универсальная функция
UModbus::mbread(...) позволяющая более тонко определять параметры запроса.
Для записи одного регистра реализована UModbus::mbwrite()
\sa UModbus
Пример использования:
```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from uniset import *
if __name__ == "__main__":
try:
mb = UModbus()
print "UIType: %s" % mb.getUIType()
mb.connect("localhost",2048)
try:
print "Test READ functions..."
for f in range(1,5):
print "func=%d reg=%d" % (f,22)
val = mb.mbread(0x01,22,f,"unsigned",-1)
# val = mb.mbread(0x01,22)
print "val=%d"%val
print "getWord: %d" % mb.getWord(0x01,22)
print "getByte: %d" % mb.getByte(0x01,22)
print "getBit: %d" % mb.getBit(0x01,22,3)
except UException, e:
print "exception: " + str(e.getError())
except UException, e:
print "(testUModbus): catch exception: " + str(e.getError())
```
## Работа c заказом датчиков
В данной реализации в фоне (в отдельном от питон системном потоке) создаётся proxy-объект,
который заказывает датчики и асинхронно в фоне получает уведомления об их изменении.
При этом из python-программы путём периодического опроса при помощи getValue() можно значения
забирать. Такой режим работы позволяет не делать каждый раз "удалённые вызовы" для получения
значений датчиков, обновление будет происходить асинхронно в фоновом потоке.
При этом после создания такого объекта, необходимо при помощи функции `addToAsk(id)` добавить
интересующие датчики, после чего для активации объекта необходимо вызвать функцию
`uniset_activate_objects()`
**warning:** функция `uniset_activate_objects()` должна быть вызвана только один раз в начале работы программы.
Пример:
```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from uniset import *
if __name__ == "__main__":
# command line arguments
lst = Params_inst()
for i in range(0, len(sys.argv)):
if i >= Params.max:
break;
lst.add(sys.argv[i])
try:
uniset_init_params(lst, "test.xml");
# create proxxy-object
obj1 = UProxyObject("TestProc")
# ask sensors
obj1.addToAsk(1)
obj1.addToAsk(10)
# run proxy objects
uniset_activate_objects()
# work..
while True:
print "get current value..."
print "getValue: sensorID=%d value=%d" % (10, getValue(10))
time.sleep(2) # do some work
except UException, e:
print "(testUI): catch exception: " + str(e.getError())
```
/*!
\page ToDoPage Необходимо доделать
\page ToDoPage Необходимо доделать
-# утилиты мониторинга работы системы
-# настройку "политик" для ORB сделать из конф. файла
-# по максимуму переход на xml
-# дополнить описание IOController-ов разделом про XML-файл заказчиков(создание,работа)
-# сделать описание принципов и деталей межобъектного взаимодействия
(об ограничениях на размер сообщений, очередь сообщений, приоритеты и т.п.)
-# попытаться сделать работу с сервисами более универсальной
(что то типа "UniSetTypes::ObjectId conf->getService(const string name)" )
-# откорректировать и дописать "общее описание" библиотеки
-# сделать тип в UniSetObject::getType string-ом
(для универсальности и простоты будущих расширений)
-# переписать тестовые примеры, под текущую ситуацию.
-# в будущем попытаться отказаться от ObjectId и перейти на строки (это надо ещё обдумать)
-# в InfoServer-е по routeList-у сообщения пересылаются, только если они локальные.
Надо переделать механизм, чтобы можно было отделять тех кому пересылать все сообщения,
от тех кому пересылать только локальные....
-# Для IOController-ов разработать спец. интерфейс для работы с датчиками (сохранение, получение состояния и т.п.)
-# утилиты мониторинга работы системы
-# настройку "политик" для ORB сделать из конф. файла
-# по максимуму переход на xml
-# дополнить описание IOController-ов разделом про XML-файл заказчиков(создание,работа)
-# сделать описание принципов и деталей межобъектного взаимодействия
(об ограничениях на размер сообщений, очередь сообщений, приоритеты и т.п.)
-# попытаться сделать работу с сервисами более универсальной
(что то типа "UniSetTypes::ObjectId conf->getService(const string name)" )
-# откорректировать и дописать "общее описание" библиотеки
-# сделать тип в UniSetObject::getType string-ом
(для универсальности и простоты будущих расширений)
-# переписать тестовые примеры, под текущую ситуацию.
-# в будущем попытаться отказаться от ObjectId и перейти на строки (это надо ещё обдумать)
-# в InfoServer-е по routeList-у сообщения пересылаются, только если они локальные.
Надо переделать механизм, чтобы можно было отделять тех кому пересылать все сообщения,
от тех кому пересылать только локальные....
-# Для IOController-ов разработать спец. интерфейс для работы с датчиками (сохранение, получение состояния и т.п.)
Для того, чтобы можно было использовать разные способы хранения (БД, STL-контейнеры, файлы и т.п.). Т.к. сейчас
жёсткая реализация на STL-контейнерах.
-# дописать Mutex как надо (или перейти на omni_mutex-ы) . Сделать RWMutex и RMutex.
-# стартовые скрипты для локальной отладки (откорректировать старые)
-# управление очередью сообщений, очистка по фильтру и т.п. (может перейти на несколько очередей по приоритетам)
-# У NotifyController-а две функции с название calibrate (надо переименовать)
-# Сделать свойство tick у процессов обмена по Modbus, чтобы можно было с разной периодичностью опрашивать разные регистры
жёсткая реализация на STL-контейнерах.
-# дописать Mutex как надо (или перейти на omni_mutex-ы) . Сделать RWMutex и RMutex.
-# стартовые скрипты для локальной отладки (откорректировать старые)
-# управление очередью сообщений, очистка по фильтру и т.п. (может перейти на несколько очередей по приоритетам)
-# У NotifyController-а две функции с название calibrate (надо переименовать)
-# Сделать свойство tick у процессов обмена по Modbus, чтобы можно было с разной периодичностью опрашивать разные регистры
*/
......@@ -817,7 +817,8 @@ FILE_PATTERNS = *.dox \
*.cc \
*.h \
*.idl \
*.py
*.py \
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
......@@ -2294,7 +2295,7 @@ CALLER_GRAPH = NO
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GRAPHICAL_HIERARCHY = YES
GRAPHICAL_HIERARCHY = NO
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
......
......@@ -817,7 +817,8 @@ FILE_PATTERNS = *.dox \
*.cc \
*.h \
*.idl \
*.py
*.py \
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
......
......@@ -66,6 +66,7 @@ void BackendOpenTSDB::init( xmlNode* cnode )
bufSyncTime = conf->getArgPInt("--" + prefix + "-buf-sync-time", it.getProp("bufSyncTimeout"), bufSyncTime);
int sz = conf->getArgPInt("--" + prefix + "-uniset-object-size-message-queue", it.getProp("sizeOfMessageQueue"), 10000);
if( sz > 0 )
setMaxSizeOfMessageQueue(sz);
......@@ -347,6 +348,7 @@ bool BackendOpenTSDB::flushBuffer()
if( ret < 0 )
{
int errnum = errno;
if( errnum == EPIPE || errnum == EBADF )
{
mywarn << "(flushBuffer): send error (" << errnum << "): " << strerror(errnum) << endl;
......@@ -369,6 +371,7 @@ bool BackendOpenTSDB::flushBuffer()
{
mywarn << "(flushBuffer): (io): " << ex.displayText() << endl;
lastError = ex.displayText();
if( !reconnect() )
askTimer(tmReconnect, reconnectTime);
}
......
......@@ -31,7 +31,7 @@ namespace uniset
{
// -----------------------------------------------------------------------------
/*!
\page page_BackendOpenTSDB Реализация шлюза к БД поддерживающей интерфейс OpenTSDB
\page page_BackendOpenTSDB (DBServer_OpenTSDB) Реализация шлюза к БД поддерживающей интерфейс OpenTSDB
- \ref sec_OpenTSDB_Comm
- \ref sec_OpenTSDB_Conf
......@@ -98,6 +98,8 @@ namespace uniset
\todo Нужна ли поддержка авторизации для TSDB (возможно придётся перейти на HTTP REST API)
\todo Доделать возможность задать политику при переполнении буфера (удалять последние или первые, сколько чистить)
*/
// -----------------------------------------------------------------------------
/*! Реализация DBServer для OpenTSDB */
class BackendOpenTSDB:
public UObject_SK
{
......
if DISABLE_OPENTSDB
else
if ENABLE_OPENTSDB
bin_PROGRAMS = @PACKAGE@-backend-opentsdb
TSDB_VER=@LIBVER@
......
......@@ -53,7 +53,7 @@ namespace uniset
\par
Для повышения надежности DBServer периодически ( DBServer_MySQL::PingTimer ) проверяет наличие связи с сервером БД.
В случае если связь пропала (или не была установлена при старте) DBServer пытается вновь каждые DBServer::ReconnectTimer
произвести соединение. При этом все запросы которые поступают для записи в БД, но не могут быть записаны складываются
произвести соединение.При этом все запросы которые поступают для записи в БД, но не могут быть записаны складываются
в буфер (см. \ref sec_DBS_Buffer).
\warning При каждой попытке восстановить соединение DBServer заново читает конф. файл. Поэтому он может подхватить
новые настройки.
......@@ -147,6 +147,8 @@ namespace uniset
\warning Временно, для обратной совместимости поле 'time_usec' в таблицах оставлено с таким названием,
хотя фактически туда сейчас сохраняется значение в наносекундах!
*/
//------------------------------------------------------------------------------------------
/*! Реализация DBServer для MySQL */
class DBServer_MySQL:
public DBServer
{
......
if DISABLE_MYSQL
else
if ENABLE_MYSQL
UMYSQL_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet2-mysql.la
......
if DISABLE_PGSQL
else
if ENABLE_PGSQL
UPGSQL_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet2-pgsql.la
......
......@@ -60,12 +60,12 @@ bool PostgreSQLInterface::ping() const
}
catch( const std::exception& e )
{
// lastE = string(e.what());
// lastE = string(e.what());
}
return false;
// return db && db->is_open();
// return db && db->is_open();
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::reconnect(const string& host, const string& user, const string& pswd, const string& dbname, unsigned int port )
......@@ -73,7 +73,7 @@ bool PostgreSQLInterface::reconnect(const string& host, const string& user, cons
if( db )
close();
return nconnect(host,user,pswd, dbname, port);
return nconnect(host, user, pswd, dbname, port);
}
// -----------------------------------------------------------------------------------------
bool PostgreSQLInterface::nconnect(const string& host, const string& user, const string& pswd, const string& dbname, unsigned int port )
......@@ -254,7 +254,7 @@ void PostgreSQLInterface::save_inserted_id( const pqxx::result& res )
bool PostgreSQLInterface::isConnection() const
{
return db && ping();
// return (db && db->is_open())
// return (db && db->is_open())
}
// -----------------------------------------------------------------------------------------
DBResult PostgreSQLInterface::makeResult( const pqxx::result& res )
......
......@@ -71,6 +71,7 @@ void DBServer_SQLite::sysCommand( const uniset::SystemMessage* sm )
case SystemMessage::Finish:
{
activate = false;
if(db)
db->close();
}
......@@ -79,6 +80,7 @@ void DBServer_SQLite::sysCommand( const uniset::SystemMessage* sm )
case SystemMessage::FoldUp:
{
activate = false;
if(db)
db->close();
}
......
......@@ -53,7 +53,7 @@ namespace uniset
\par
Для повышения надежности DBServer периодически ( DBServer_SQLite::PingTimer ) проверяет наличие связи с сервером БД.
В случае если связь пропала (или не была установлена при старте) DBServer пытается вновь каждые DBServer::ReconnectTimer
произвести соединение. При этом все запросы которые поступают для записи в БД, но не могут быть записаны складываются
произвести соединение.При этом все запросы которые поступают для записи в БД, но не могут быть записаны складываются
в буфер (см. \ref sec_DBS_Buffer).
\warning При каждой попытке восстановить соединение DBServer заново читает конф. файл. Поэтому он может подхватить
новые настройки.
......@@ -147,6 +147,8 @@ namespace uniset
\warning Временно, для обратной совместимости поле 'time_usec' в таблицах оставлено с таким названием,
хотя фактически туда сейчас сохраняется значение в наносекундах!
*/
//------------------------------------------------------------------------------------------
/*! Реализация DBServer для SQLite */
class DBServer_SQLite:
public DBServer
{
......
if DISABLE_SQLITE
else
if ENABLE_SQLITE
USQLITE_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet2-sqlite.la
......@@ -28,4 +25,3 @@ pkgconfig_DATA = libUniSet2SQLite.pc
include $(top_builddir)/include.mk
endif
\ No newline at end of file
/*
* Copyright (c) 2020 Pavel Vainerman.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef HttpResolver_H_
#define HttpResolver_H_
// --------------------------------------------------------------------------
#include <Poco/JSON/Object.h>
#include "UniSetTypes.h"
#include "DebugStream.h"
#include "UHttpRequestHandler.h"
#include "UHttpServer.h"
#include "IORFile.h"
// -------------------------------------------------------------------------
const std::string HTTP_RESOLVER_API_VERSION = "v01";
// -------------------------------------------------------------------------
namespace uniset
{
//------------------------------------------------------------------------------------------
/*!
\page page_HttpResolver Http-cервис для получения CORBA-ссылок на объекты (HttpResolver)
- \ref sec_HttpResolver_Comm
- \ref sec_HttpResolver_Conf
\section sec_HttpResolver_Comm Общее описание работы HttpResolver
HttpResolver это сервис, который отдаёт CORBA-ссылки (в виде строки)
на объекты запущенные на данном узле в режиме LocalIOR. Т.е. когда ссылки
публикуются в файлах.
\sa \ref ConfigurationPage_secLocalIOR
\section sec_HttpResolver_Conf Настройка работы HttpResolver
Для запуска HttpResolver необходимо настроить на каком порту и сетевом интерфейсе будут приниматься запросы.
Для этого необходимо в настройках прописать следующую секцию
\code
<UniSet>
...
<HttpResolver name="HttpResolver" port="8008" host="0.0.0.0"/>
...
</UniSet>
\endcode
- 0.0.0.0 - слушать на всех доступных интерфейсах
Помимо этого, настройки можно указать в аргументах командной строки
- `--httpresolver-host` - интерфейс на котором слушать запросы. По умолчанию: 0.0.0.0
- `--httpresolver-port` - порт на котором слушать запросы. По умолчанию: 8008
Длполнительные параметры:
- `--httpresolver-max-queued num ` - Размер очереди запросов к http серверу. По умолчанию: 100.
- `--httpresolver-max-threads num` - Разрешённое количество потоков для http-сервера. По умолчанию: 3.
- `--httpresolver-cors-allow addr` - (CORS): Access-Control-Allow-Origin. Default: *
- `--httpresolver-logs-add-levels any` - Управление логами
- `--confile configure.xml` - Файл с настройками
*/
class HttpResolver:
public Poco::Net::HTTPRequestHandler
{
public:
HttpResolver( const std::string& name, int argc, const char* const* argv, const std::string& prefix );
virtual ~HttpResolver();
/*! глобальная функция для инициализации объекта */
static std::shared_ptr<HttpResolver> init_resolver( int argc, const char* const* argv, const std::string& prefix = "httpresolver-" );
/*! глобальная функция для вывода help-а */
static void help_print();
inline std::shared_ptr<DebugStream> log()
{
return rlog;
}
virtual void handleRequest( Poco::Net::HTTPServerRequest& req, Poco::Net::HTTPServerResponse& resp ) override;
void run();
protected:
Poco::JSON::Object::Ptr respError( Poco::Net::HTTPServerResponse& resp, Poco::Net::HTTPResponse::HTTPStatus s, const std::string& message );
Poco::JSON::Object::Ptr httpGetRequest( const std::string& cmd, const Poco::URI::QueryParameters& p );
Poco::JSON::Object::Ptr httpJsonResolve( const std::string& query, const Poco::URI::QueryParameters& p );
std::string httpTextResolve( const std::string& query, const Poco::URI::QueryParameters& p );
std::shared_ptr<Poco::Net::HTTPServer> httpserv;
std::string httpHost = { "" };
int httpPort = { 8008 };
std::string httpCORS_allow = { "*" };
std::string httpReplyAddr = { "" };
std::shared_ptr<DebugStream> rlog;
std::string myname;
std::shared_ptr<IORFile> iorfile;
class HttpResolverRequestHandlerFactory:
public Poco::Net::HTTPRequestHandlerFactory
{
public:
HttpResolverRequestHandlerFactory( HttpResolver* r ): resolver(r) {}
virtual ~HttpResolverRequestHandlerFactory() {}
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& req ) override;
private:
HttpResolver* resolver;
};
private:
};
// ----------------------------------------------------------------------------------
} // end of namespace uniset
//------------------------------------------------------------------------------------------
#endif
#ifndef HttpResolverSugar_H_
#define HttpResolverSugar_H_
// "синтаксический сахар"..для логов
#ifndef rinfo
#define rinfo if( rlog->debugging(Debug::INFO) ) rlog->info()
#endif
#ifndef rwarn
#define rwarn if( rlog->debugging(Debug::WARN) ) rlog->warn()
#endif
#ifndef rcrit
#define rcrit if( rlog->debugging(Debug::CRIT) ) rlog->crit()
#endif
#ifndef rlog1
#define rlog1 if( rlog->debugging(Debug::LEVEL1) ) rlog->level1()
#endif
#ifndef rlog2
#define rlog2 if( rlog->debugging(Debug::LEVEL2) ) rlog->level2()
#endif
#ifndef rlog3
#define rlog3 if( rlog->debugging(Debug::LEVEL3) ) rlog->level3()
#endif
#ifndef rlog4
#define rlog4 if( rlog->debugging(Debug::LEVEL4) ) rlog->level4()
#endif
#ifndef rlog5
#define rlog5 if( rlog->debugging(Debug::LEVEL5) ) rlog->level5()
#endif
#ifndef rlog6
#define rlog6 if( rlog->debugging(Debug::LEVEL6) ) rlog->level6()
#endif
#ifndef rlog7
#define rlog7 if( rlog->debugging(Debug::LEVEL7) ) rlog->level7()
#endif
#ifndef rlog8
#define rlog8 if( rlog->debugging(Debug::LEVEL8) ) rlog->level8()
#endif
#ifndef rlog9
#define rlog9 if( rlog->debugging(Debug::LEVEL9) ) rlog->level9()
#endif
#ifndef rlogany
#define rlogany rlog->any()
#endif
#endif
if ENABLE_REST_API
bin_PROGRAMS = @PACKAGE@-httpresolver
@PACKAGE@_httpresolver_LDADD = $(top_builddir)/lib/libUniSet2.la
@PACKAGE@_httpresolver_SOURCES = HttpResolver.cc main.cc
include $(top_builddir)/include.mk
endif
\ No newline at end of file
#include "Configuration.h"
#include "HttpResolver.h"
// --------------------------------------------------------------------------
using namespace uniset;
using namespace std;
// --------------------------------------------------------------------------
int main(int argc, char** argv)
{
// std::ios::sync_with_stdio(false);
try
{
if( argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) )
{
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
HttpResolver::help_print();
return 0;
}
auto resolver = HttpResolver::init_resolver(argc, argv);
if( !resolver )
return 1;
resolver->run();
return 0;
}
catch( const std::exception& ex )
{
cerr << "(HttpResolver::main): " << ex.what() << endl;
}
catch(...)
{
cerr << "(HttpResolver::main): catch ..." << endl;
}
return 1;
}
if ENABLE_REST_API
if HAVE_TESTS
noinst_PROGRAMS = run_test_uresolver
run_test_uresolver_SOURCES = run_test_uresolver.cc test_uresolver.cc TestObject.cc
run_test_uresolver_LDADD = $(top_builddir)/lib/libUniSet2.la $(top_builddir)/extensions/lib/libUniSet2Extensions.la $(SIGC_LIBS) $(POCO_LIBS)
run_test_uresolver_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/extensions/include $(SIGC_CFLAGS) $(POCO_CFLAGS)
include $(top_builddir)/testsuite/testsuite-common.mk
check-local: atconfig package.m4 $(TESTSUITE) uresolver-tests.at
$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS)
clean-local:
rm -rf $(CLEANFILES)
rm -rf $(COVERAGE_REPORT_DIR)
include $(top_builddir)/include.mk
endif
endif
// -----------------------------------------------------------------------------
#include "TestObject.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace uniset;
// -----------------------------------------------------------------------------
TestObject::TestObject( uniset::ObjectId objId, xmlNode* cnode ):
UObject_SK(objId, cnode)
{
}
// -----------------------------------------------------------------------------
TestObject::~TestObject()
{
}
// -----------------------------------------------------------------------------
#ifndef _TestObject_H_
#define _TestObject_H_
// -----------------------------------------------------------------------------
#include "UObject_SK.h"
// -----------------------------------------------------------------------------
class TestObject:
public UObject_SK
{
public:
TestObject( uniset::ObjectId objId, xmlNode* cnode );
virtual ~TestObject();
protected:
TestObject();
};
// -----------------------------------------------------------------------------
#endif // _TestObject_H_
// -----------------------------------------------------------------------------
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
#include <string>
#include "Debug.h"
#include "UniSetActivator.h"
#include "UHelpers.h"
#include "TestObject.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace uniset;
// --------------------------------------------------------------------------
int main( int argc, const char* argv[] )
{
try
{
Catch::Session session;
if( argc > 1 && ( strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ) )
{
session.showHelp("tests_httpresolver");
return 0;
}
int returnCode = session.applyCommandLine( argc, argv, Catch::Session::OnUnusedOptions::Ignore );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
auto conf = uniset_init(argc, argv);
auto to = make_object<TestObject>("TestProc", "TestProc");
if( !to )
return 1;
auto act = UniSetActivator::Instance();
act->add(to);
SystemMessage sm(SystemMessage::StartUp);
act->broadcast( sm.transport_msg() );
act->run(true);
return session.run();
}
catch( const uniset::Exception& ex )
{
cerr << "(tests_httpresolver): " << ex << endl;
}
catch( const std::exception& e )
{
cerr << "(tests_httpresolver): " << e.what() << endl;
}
catch(...)
{
cerr << "(tests_httpresolver): catch(...)" << endl;
}
return 1;
}
#!/bin/sh
HTTP_RESOLVER_PID=
function atexit()
{
trap - EXIT
[ -n "$HTTP_RESOLVER_PID" ] && kill $HTTP_RESOLVER_PID 2>/dev/null
sleep 3
[ -n "$HTTP_RESOLVER_PID" ] && kill -9 $HTTP_RESOLVER_PID 2>/dev/null
exit $RET
}
trap atexit EXIT
# '--' - нужен для отделения аргументов catch, от наших..
cd ../../../Utilities/Admin/
./uniset2-start.sh -f ./create_links.sh
./uniset2-start.sh -f ./create
./uniset2-start.sh -f ./exist | grep -q UNISET_PLC/Controllers || exit 1
cd -
../uniset2-httpresolver --confile uresolver-test-configure.xml &
HTTP_RESOLVER_PID=$!
sleep 5
./uniset2-start.sh -f ./run_test_uresolver $* -- --confile uresolver-test-configure.xml && RET=0 || RET=1
exit $RET
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include "UniSetTypes.h"
#include "Exceptions.h"
#include "UInterface.h"
#include "UHttpClient.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace uniset;
// -----------------------------------------------------------------------------
static shared_ptr<UInterface> ui;
static const ObjectId TestProc = 6000;
static const ObjectId Node1 = 3001;
// -----------------------------------------------------------------------------
static void InitTest()
{
auto conf = uniset_conf();
CHECK( conf != nullptr );
if( !ui )
{
ui = make_shared<UInterface>();
// UI понадобиться для проверки записанных в SM значений.
CHECK( ui->getObjectIndex() != nullptr );
CHECK( ui->getConf() == conf );
}
REQUIRE( conf->getHttpResovlerPort() == 8008 );
REQUIRE( conf->isLocalIOR() );
REQUIRE_NOTHROW( ui->resolve(TestProc) );
REQUIRE( ui->isExist(TestProc) );
}
// -----------------------------------------------------------------------------
TEST_CASE("HttpResolver: cli resolve", "[httpresolver][cli]")
{
InitTest();
UHttp::UHttpClient cli;
auto ret = cli.get("localhost", 8008, "api/v01/resolve/text?" + std::to_string(TestProc));
REQUIRE_FALSE( ret.empty() );
}
// -----------------------------------------------------------------------------
TEST_CASE("HttpResolver: resolve", "[httpresolver][ui]")
{
InitTest();
REQUIRE_NOTHROW( ui->resolve(TestProc, Node1) );
REQUIRE_NOTHROW( ui->resolve("UNISET_PLC/UniObjects/TestProc") );
REQUIRE_THROWS_AS( ui->resolve(DefaultObjectId, Node1), uniset::ResolveNameError& );
REQUIRE( ui->isExist(TestProc, Node1) );
}
// -----------------------------------------------------------------------------
m4_include(package.m4)
AT_COLOR_TESTS
AT_INIT([HttpResolver tests])
m4_include(uresolver-tests.at)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment