Commit 212cf7fb authored by Pavel Vainerman's avatar Pavel Vainerman

initial commit "1.0-pre"

parent 801f3c9a
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2007/06/17 21:30:49 $
*/
// --------------------------------------------------------------------------
#include <sstream>
#include "DBInterface.h"
using namespace std;
// -----------------------------------------------------------------------------------------
DBInterface::DBInterface():
result(0),
lastQ(""),
queryok(false)
{
mysql = new MYSQL();
}
DBInterface::~DBInterface()
{
close();
delete mysql;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::connect( const string host, const string user, const string pswd, const string dbname)
{
mysql_init(mysql);
// mysql_options(mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
mysql_options(mysql,MYSQL_OPT_COMPRESS,0);
if (!mysql_real_connect(mysql,host.c_str(), user.c_str(),pswd.c_str(),dbname.c_str(),0,NULL,0))
{
cout << error() << endl;
mysql_close(mysql);
return false;
}
return true;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::close()
{
mysql_close(mysql);
return true;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::insert(const string q)
{
if( !mysql )
return false;
if( mysql_query(mysql,q.c_str()) )
{
queryok=false;
return false;
}
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::query(const string q)
{
if( !mysql )
return false;
if( mysql_query(mysql,q.c_str()) )
{
queryok=false;
return false;
}
lastQ = q;
result = mysql_store_result(mysql); // _use_result - некорректно работает с _num_rows
if( numRows()==0 )
{
queryok=false;
return false;
}
queryok=true;
return true;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::nextRecord()
{
if( !mysql || !result || !queryok )
return false;
if( Row == mysql_fetch_row(result) )
return true;
return false;
}
// -----------------------------------------------------------------------------------------
const string DBInterface::error()
{
return mysql_error(mysql);
}
// -----------------------------------------------------------------------------------------
const string DBInterface::lastQuery()
{
return lastQ;
}
// -----------------------------------------------------------------------------------------
void DBInterface::freeResult()
{
if( !mysql || !result || !queryok )
return;
queryok = false;
mysql_free_result( result );
}
// -----------------------------------------------------------------------------------------
int DBInterface::insert_id()
{
if( !mysql )
return 0;
return mysql_insert_id(mysql);
}
// -----------------------------------------------------------------------------------------
unsigned int DBInterface::numCols()
{
if( result )
return mysql_num_fields(result);
return 0;
}
// -----------------------------------------------------------------------------------------
unsigned int DBInterface::numRows()
{
if( result )
return mysql_num_rows(result);
return 0;
}
// -----------------------------------------------------------------------------------------
const MYSQL_ROW DBInterface::getRow()
{
return Row;
}
// -----------------------------------------------------------------------------------------
const char* DBInterface::gethostinfo()
{
return mysql_get_host_info(mysql);
}
// -----------------------------------------------------------------------------------------
/*
bool DBInterface::createDB(const string dbname)
{
if(!mysql)
return false;
if( mysql_create_db(mysql, dbname.c_str()) )
return true;
return false;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::dropDB(const string dbname)
{
if( mysql_drop_db(mysql, dbname.c_str()))
return true;
return false;
}
*/
// -----------------------------------------------------------------------------------------
MYSQL_RES* DBInterface::listFields(const string table, const string wild )
{
if( !mysql || !result )
return false;
MYSQL_RES *res = mysql_list_fields(mysql, table.c_str(),wild.c_str());
unsigned int cols = mysql_num_fields(result); // numCols();
MYSQL_ROW row=mysql_fetch_row(res);
// MYSQL_FIELD *field = mysql_fetch_fields(res);
// cout << field << " | ";
for( unsigned int i = 0; i<cols; i++)
{
cout << row[i] << " | ";
}
return res; // mysql_list_fields(mysql, table,wild);
}
// -----------------------------------------------------------------------------------------
bool DBInterface::moveToRow(int ind)
{
if(!mysql || !result)
return false;
mysql_data_seek(result, ind);
return true;
}
// -----------------------------------------------------------------------------------------
bool DBInterface::ping()
{
if(!mysql)
return false;
// внимание mysql_ping возвращает 0
// если всё хорошо.... (поэтому мы инвертируем)
return !mysql_ping(mysql);
}
// -----------------------------------------------------------------------------------------
bool DBInterface::isConnection()
{
return ping(); //!mysql;
}
// -----------------------------------------------------------------------------------------
string DBInterface::addslashes(const string& str)
{
ostringstream tmp;
for( unsigned int i=0; i<str.size(); i++ )
{
// if( !strcmp(str[i],'\'') )
if( str[i] == '\'' )
tmp << "\\";
tmp << str[i];
}
return tmp.str();
}
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2005/08/28 20:55:53 $
* \version $Id: DBInterface.h,v 1.1 2005/08/28 20:55:53 vpashka Exp $
*/
//----------------------------------------------------------------------------
#ifndef DBInterface_H_
#define DBInterface_H_
// ---------------------------------------------------------------------------
#include <string>
#include <iostream>
//#warning Для использования mysql_create нужен define USE_OLD_FUNCTIONS
//#define USE_OLD_FUNCTIONS
#include <mysql/mysql.h>
using std::string;
// ----------------------------------------------------------------------------
class DBInterface
{
public:
DBInterface();
~DBInterface();
// bool createDB(const string dbname);
// bool dropDB(const string dbname);
MYSQL_RES * listFields(const string table, const string wild );
bool connect( const string host, const string user, const string pswd,
const string dbname);
bool close();
bool query(const string q);
const string lastQuery();
bool insert(const string q);
string addslashes(const string& str);
/*!
проверка связи с БД.
в случае отсутсвия попытка восстановить...
*/
bool ping();
/*! связь с БД установлена (была) */
bool isConnection();
bool nextRecord();
void freeResult();
unsigned int numCols();
unsigned int numRows();
bool moveToRow(int ind);
int insert_id();
const MYSQL_ROW getRow();
const string error();
MYSQL_ROW Row;
// *******************
const char* gethostinfo();
protected:
private:
MYSQL_RES *result;
MYSQL *mysql;
string lastQ;
bool queryok; // успешность текущего запроса
};
// ----------------------------------------------------------------------------------
#endif
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \brief файл реализации DB-сервера
* \author Pavel Vainerman
* \date $Date: 2009/02/26 19:55:37 $
*/
// --------------------------------------------------------------------------
#include <sys/time.h>
#include <sstream>
#include <iomanip>
#include "ORepHelpers.h"
#include "DBServer_MySQL.h"
#include "Configuration.h"
#include "Debug.h"
#include "UniXML.h"
using namespace UniSetTypes;
using namespace std;
// ------------------------------------------------------------------------------------------
DBServer_MySQL::DBServer_MySQL(ObjectId id):
DBServer(id),
db(new DBInterface()),
PingTime(300000),
ReconnectTime(180000),
connect_ok(false),
activate(true)
{
if( getId() == DefaultObjectId )
{
ostringstream msg;
msg << "(DBServer_MySQL): Запуск невозможен! НЕ ОПРЕДЕЛЁН ObjectId !!!!!\n";
// unideb[Debug::CRIT] << msg.str() << endl;
throw Exception(msg.str());
}
}
DBServer_MySQL::DBServer_MySQL():
DBServer(conf->getDBServer()),
db(new DBInterface()),
PingTime(300000),
ReconnectTime(180000),
connect_ok(false),
activate(true)
{
// init();
if( getId() == DefaultObjectId )
{
ostringstream msg;
msg << "(DBServer_MySQL): Запуск невозможен! Для данного узла НЕ ОПРЕДЕЛЁН ObjectId !!!!!\n";
// unideb[Debug::CRIT] << msg.str() << endl;
throw Exception(msg.str());
}
}
//--------------------------------------------------------------------------------------------
DBServer_MySQL::~DBServer_MySQL()
{
if( db != NULL )
{
db->freeResult();
db->close();
delete db;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::processingMessage( UniSetTypes::VoidMessage *msg )
{
switch(msg->type)
{
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
break;
}
default:
DBServer::processingMessage(msg);
break;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
break;
case SystemMessage::Finish:
activate = false;
db->freeResult();
db->close();
break;
case SystemMessage::FoldUp:
activate = false;
db->freeResult();
db->close();
break;
default:
break;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::parse( UniSetTypes::DBMessage* dbm )
{
if( dbm->tblid == UniSetTypes::Message::Unused )
{
unideb[Debug::CRIT] << myname << "(dbmessage): не задан tblId...\n";
return;
}
ostringstream query;
switch( dbm->qtype )
{
case DBMessage::Query:
query << dbm->data;
break;
case DBMessage::Update:
query << "UPDATE " << tblName(dbm->tblid) << " SET " << dbm->data;
break;
case DBMessage::Insert:
query << "INSERT INTO " << tblName(dbm->tblid) << " VALUES (" << dbm->data << ")";
break;
}
if( !writeToBase(query.str()) )
{
unideb[Debug::CRIT] << myname << "(update): error: "<< db->error() << endl;
// if( dbm->qtype == DBMessage::Query )
// db->freeResult();
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::parse( UniSetTypes::InfoMessage* im )
{
string message(im->message);
if( message.empty() && im->infocode != DefaultMessageCode )
message = conf->mi->getMessage(im->infocode);
if( !message.empty() )
message = db->addslashes(message);
// Прежде чем формировать строку обязательно смотрите формат базы данных(порядок полей таблицы)!!!
ostringstream ostr;
ostr << "INSERT INTO " << tblName(im->type);
ostr << "(num,node,id,date,time,time_usec,code,text,haracter,type,confirm,causeid) VALUES(";
ostr << "NULL,'"<< im->node << "','" << im->id;
ostr << "','" << ui.dateToString(im->tm.tv_sec,"/") << "','" << ui.timeToString(im->tm.tv_sec,":");
ostr << "','" << im->tm.tv_usec;
ostr << "','" << im->infocode << "','"<< message << "','" << im->character;
ostr << "','" << im->type << "','0','0')";
if( !writeToBase(ostr.str()) )
{
unideb[Debug::CRIT] << myname << "(insert): info msg error: "<< db->error() << endl;
// db->freeResult();
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::parse( UniSetTypes::AlarmMessage* am )
{
string message(am->message);
if( message.empty() && am->alarmcode != DefaultMessageCode )
message = conf->mi->getMessage(am->alarmcode);
if( !message.empty() )
message = db->addslashes(message);
// Прежде чем формировать строку обязательно смотрите формат базы данных(порядок полей таблицы)!!!
ostringstream ostr;
ostr << "INSERT INTO " << tblName(am->type);
ostr << "(num,node,id,date,time,time_usec,code,text,haracter,type,confirm,causeid) VALUES(";
ostr << "NULL,'"<< am->node << "','" << am->id;
ostr << "','" << ui.dateToString(am->tm.tv_sec,"/") << "','"
<< ui.timeToString(am->tm.tv_sec,":")<< "','" << am->tm.tv_usec;
ostr << "','" << am->alarmcode<< "','" << message;
ostr << "','" << am->character << "','" << am->type << "',0,'" << am->causecode << "')";
if( !writeToBase(ostr.str()) )
{
unideb[Debug::CRIT] << myname << "(insert): alarm msg error: "<< db->error() << endl;
// db->freeResult();
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::parse( UniSetTypes::ConfirmMessage* am )
{
// Сохраняем ПОДТВЕРЖДЕНИЕ в базу
ostringstream query;
query << "UPDATE " << tblName(am->orig_type) << " SET ";
query << "confirm='" << ui.timeToString(am->tm.tv_sec,":") << "'";
query << " where ";
query << " id='" << am->orig_id << "'";
query << " AND type='" << am->orig_type << "'";
query << " AND node='" << am->orig_node << "'";
query << " AND code='" << am->code << "'";
// query << " AND cause='" << am->cause << "'";
query << " AND date='" << ui.dateToString(am->orig_tm.tv_sec,"/") << "'";
query << " AND time='" << ui.timeToString(am->orig_tm.tv_sec,":") << "'";
query << " AND time_usec='" << am->orig_tm.tv_usec << "'";
if( !writeToBase(query.str()) )
{
unideb[Debug::CRIT] << myname << "(insert): confirm msg error: "<< db->error() << endl;
// db->freeResult();
}
}
//--------------------------------------------------------------------------------------------
bool DBServer_MySQL::writeToBase( const string& query )
{
unideb[Debug::INFO] << "DBServer_MySQL: " << query << endl;
// cout << "DBServer_MySQL: " << query << endl;
if( !db || !connect_ok )
{
unideb[Debug::CRIT] << myname << "(writeToBase): соединение с БД не установлено\n"
<< myname << "(writeToBase): lost query: "
<< query << endl;
return false;
}
db->query( query );
// Дело в том что на INSERT И UPDATE запросы
// db->query() может возвращать false и надо самому
// отдельно проверять действительно ли произошла ошибка
// см. DBInterface::query.
string err(db->error());
if( err.empty() )
{
db->freeResult();
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::parse( UniSetTypes::SensorMessage *si )
{
try
{
// если время не было выставлено (указываем время сохранения в БД)
if( !si->tm.tv_sec )
{
struct timezone tz;
gettimeofday(&si->tm,&tz);
}
// см. DBTABLE AnalogSensors, DigitalSensors
ostringstream data;
data << " VALUES( ";
// Поля таблицы
data << "NULL,'"<< si->node << "','"; // num, node
data << si->id << "','"; // id (sensorid)
data << ui.dateToString(si->sm_tv_sec,"/") << "','"; // date
data << ui.timeToString(si->sm_tv_sec,":") << "','"; // time
data << si->sm_tv_usec << "','"; // time_usec
// data << ui.dateToString(si->tm.tv_sec) << "','"; // date
// data << ui.timeToString(si->tm.tv_sec) << "','"; // time
// data << si->tm.tv_usec << "','"; // time_usec
string table;
switch( si->sensor_type )
{
case UniversalIO::DigitalInput:
case UniversalIO::DigitalOutput:
table = "DigitalSensors(num,node,id,date,time,time_usec,state)";
data << si->state; // state
break;
case UniversalIO::AnalogInput:
case UniversalIO::AnalogOutput:
table = "AnalogSensors(num,node,id,date,time,time_usec,value)";
data << si->value; // value
break;
default:
unideb[Debug::WARN] << myname << "(log sensor): неизвестный тип датчика....(сообщение игнорировано)" << endl;
return;
}
data << "')";
if( !writeToBase("INSERT INTO "+table+data.str()) )
{
unideb[Debug::CRIT] << myname << "(insert) sensor msg error: "<< db->error() << endl;
db->freeResult();
}
}
catch( Exception& ex )
{
unideb[Debug::CRIT] << myname << "(parse SensorMessage): " << ex << endl;
}
catch( ... )
{
unideb[Debug::CRIT] << myname << "(parse SensorMessage): неизвестное исключние..." << endl;
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::init_dbserver()
{
DBServer::init_dbserver();
unideb[Debug::INFO] << myname << "(init): ..." << endl;
if( connect_ok )
{
initDBTableMap(tblMap);
initDB(db);
return;
}
if( conf->getDBServer() == UniSetTypes::DefaultObjectId )
{
ostringstream msg;
msg << myname << "(init): на данном узле DBServer - отключён."
<< " В " << conf->getConfFileName()
<< " для данного узла указан параметр dbserver=''";
throw NameNotFound(msg.str());
}
xmlNode* node = conf->getNode("LocalDBServer");
if( !node )
throw NameNotFound(string(myname+"(init): в конфигурационном файле не найден раздел LocalDBServer"));
unideb[Debug::INFO] << myname << "(init): инициализируем соединение" << endl;
string dbname(conf->getProp(node,"dbname"));
string dbnode(conf->getProp(node,"dbnode"));
string user(conf->getProp(node,"dbuser"));
string password(conf->getProp(node,"dbpass"));
tblMap[UniSetTypes::Message::Info] = "Messages";
tblMap[UniSetTypes::Message::Alarm] = "Messages";
tblMap[UniSetTypes::Message::SensorInfo] = "AnalogSensors";
PingTime = conf->getIntProp(node,"pingTime");
ReconnectTime = conf->getIntProp(node,"reconnectTime");
if( dbnode.empty() )
dbnode = "localhost";
unideb[Debug::INFO] << myname << "(init): connect dbnode=" << dbnode
<< "\tdbname=" << dbname
<< " pingTime=" << PingTime
<< " ReconnectTime=" << ReconnectTime << endl;
if( !db->connect(dbnode, user, password, dbname) )
{
// ostringstream err;
unideb[Debug::CRIT] << myname
<< "(init): не смог создать соединение с БД err:\n"
<< db->error() << endl;
// throw Exception( string(myname+"(init): не смогли создать соединение с БД "+db->error()) );
askTimer(DBServer_MySQL::ReconnectTimer,ReconnectTime);
}
else
{
unideb[Debug::INFO] << myname << "(init): connect ok\n";
connect_ok = true;
askTimer(DBServer_MySQL::ReconnectTimer,0);
askTimer(DBServer_MySQL::PingTimer,PingTime);
// createTables(db);
initDB(db);
initDBTableMap(tblMap);
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::createTables( DBInterface *db )
{
UniXML_iterator it( conf->getNode("Tables") );
if(!it)
{
unideb[Debug::CRIT] << myname << ": не найден раздел Tables...."<< endl;
throw Exception();
}
for( it.goChildren();it;it.goNext() )
{
if( it.getName() != "comment" )
{
unideb[Debug::INFO] << myname << "(createTables): создаем " << it.getName() << endl;
ostringstream query;
query << "CREATE TABLE " << conf->getProp(it,"name") << "(" << conf->getProp(it,"create") << ")";
if( !db->query(query.str()) )
unideb[Debug::CRIT] << myname << "(createTables): error: \t\t" << db->error() << endl;
}
}
}
//--------------------------------------------------------------------------------------------
void DBServer_MySQL::timerInfo( UniSetTypes::TimerMessage* tm )
{
switch( tm->id )
{
case DBServer_MySQL::PingTimer:
{
if( !db->ping() )
{
unideb[Debug::WARN] << myname << "(timerInfo): потеряно соединение с сервером БД" << endl;
connect_ok = false;
askTimer(DBServer_MySQL::PingTimer,0);
askTimer(DBServer_MySQL::ReconnectTimer,ReconnectTime);
}
else
{
connect_ok = true;
unideb[Debug::INFO] << myname << "(timerInfo): DB ping ok\n";
}
}
break;
case DBServer_MySQL::ReconnectTimer:
{
unideb[Debug::INFO] << myname << "(timerInfo): reconnect timer" << endl;
if( db->isConnection() )
{
if( db->ping() )
{
connect_ok = true;
askTimer(DBServer_MySQL::ReconnectTimer,0);
askTimer(DBServer_MySQL::PingTimer,PingTime);
}
connect_ok = false;
unideb[Debug::WARN] << myname << "(timerInfo): нет связи с БД" << endl;
}
else
init_dbserver();
}
break;
default:
unideb[Debug::WARN] << myname << "(timerInfo): неизвестный таймер tid=" << tm->id << endl;
break;
}
}
//--------------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2005/08/28 20:55:53 $
* \version $Id: DBServer_MySQL.h,v 1.1 2005/08/28 20:55:53 vpashka Exp $
*/
// --------------------------------------------------------------------------
#ifndef DBServer_MySQL_H_
#define DBServer_MySQL_H_
// --------------------------------------------------------------------------
#include <map>
#include "UniSetTypes.h"
#include "DBInterface.h"
#include "DBServer.h"
//------------------------------------------------------------------------------------------
/*!
\page page_DBServer_MySQL (DBServer_MySQL) Реализация сервиса ведения БД на основе MySQL
- \ref sec_DBS_Comm
- \ref sec_DBS_Conf
- \ref sec_DBS_Tables
\section sec_DBS_Comm Общее описание работы DBServer_MySQL
Сервис предназначен для работы с БД MySQL. В его задачи входит
сохранение всех событий происходищих в системе в БД. К этим
событиям относятся изменение состояния датчиков, различные логи
работы процессов и т.п.
К моменту запуска, подразумевается, что неободимые таблицы уже
созданы, все необходимые настройки mysql сделаны.
\par
При работе с БД, сервис в основном пишет в БД. Обработка накопленных данных
ведётся уже другими программами (web-интерфейс).
\par
Для повышения надежности DBServer переодически ( DBServer_MySQL::PingTimer ) проверяет наличие связи с сервером БД.
В случае если связь пропала (или не была установлена при старте) DBServer пытается вновь переодически ( DBServer::ReconnectTimer )
произвести соединение. При этом все запросы которые поступают для запии в БД, пишутся в лог-файл.
\warning При каждой попытке восстановить соединение DBServer заново читает конф. файл. Поэтому он может подхватить
новые настройки.
\todo Может не сохранять текст, если задан код... (для экономии в БД)
\section sec_DBS_Conf Настройка DBServer
Объект DBServer берёт настройки из конфигурационного файла из секции \b<LocalDBServer>.
Возможно задать следующие параметры:
- \b dbname - название БД
- \b dbnode - узел БД
- \b dbuser - пользователь
- \b dbpass - пароль для доступа к БД
- \b pingTime - период проверки связи с сервером MySQL
- \b reconnectTime - время повторной попытки соединения с БД
\section sec_DBS_Tables Таблицы MySQL
К основным таблицам относятся следующие:
\code
DROP TABLE IF EXISTS ObjectsMap;
CREATE TABLE ObjectsMap (
name varchar(80) NOT NULL default '',
rep_name varchar(80) default NULL,
id int(4) NOT NULL default '0',
msg int(1) default 0,
PRIMARY KEY (id),
KEY rep_name (rep_name),
KEY msg (msg)
) TYPE=MyISAM;
DROP TABLE IF EXISTS AnalogSensors;
CREATE TABLE AnalogSensors (
num int(11) NOT NULL auto_increment,
node int(3) default NULL,
id int(4) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
value int(6) default NULL,
PRIMARY KEY (num),
KEY date (date,time,time_usec),
KEY node (node,id)
) TYPE=MyISAM;
--
-- Table structure for table `DigitalSensors`
--
DROP TABLE IF EXISTS DigitalSensors;
CREATE TABLE DigitalSensors (
num int(11) NOT NULL auto_increment,
node int(3) default NULL,
id int(4) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
state char(1) default NULL,
confirm time NOT NULL default '00:00:00',
PRIMARY KEY (num),
KEY date (date,time,time_usec),
KEY node (node,id),
KEY confirm(confirm)
) TYPE=MyISAM;
DROP TABLE IF EXISTS SensorsThreshold;
CREATE TABLE SensorsThreshold (
sid int(11) NOT NULL default '0',
alarm int(8) NOT NULL default '0',
warning int(8) NOT NULL default '0'
) TYPE=MyISAM;
\endcode
*/
class DBServer_MySQL:
public DBServer
{
public:
DBServer_MySQL( UniSetTypes::ObjectId id );
DBServer_MySQL();
~DBServer_MySQL();
protected:
typedef std::map<int, std::string> DBTableMap;
virtual void initDB(DBInterface *db){};
virtual void initDBTableMap(DBTableMap& tblMap){};
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
virtual void timerInfo( UniSetTypes::TimerMessage* tm );
virtual void sysCommand( UniSetTypes::SystemMessage* sm );
// Функции обработки пришедших сообщений
virtual void parse( UniSetTypes::SensorMessage* sm );
virtual void parse( UniSetTypes::DBMessage* dbmsg );
virtual void parse( UniSetTypes::InfoMessage* imsg );
virtual void parse( UniSetTypes::AlarmMessage* amsg );
virtual void parse( UniSetTypes::ConfirmMessage* cmsg );
bool writeToBase( const string& query );
virtual void init_dbserver();
void createTables( DBInterface* db );
inline const char* tblName(int key)
{
return tblMap[key].c_str();
}
enum Timers
{
PingTimer, /*!< таймер на переодическую проверку соединения с сервером БД */
ReconnectTimer /*!< таймер на повторную попытку соединения с сервером БД (или восстановления связи) */
};
DBInterface *db;
int PingTime;
int ReconnectTime;
bool connect_ok; /*! признак наличия соеднинения с сервером БД */
bool activate;
private:
DBTableMap tblMap;
};
//------------------------------------------------------------------------------------------
#endif
############################################################################
# This file is part of the UniSet library #
############################################################################
UMYSQL_VER=@LIBVER@
lib_LTLIBRARIES = libUniSet-mysql.la
libUniSet_mysql_la_LDFLAGS = -version-info $(UMYSQL_VER)
libUniSet_mysql_la_SOURCES = DBInterface.cc DBServer_MySQL.cc
libUniSet_mysql_la_LIBADD = $(top_builddir)/lib/libUniSet.la -lmysqlclient
libUniSet_mysql_la_LDFLAGS = -version-info @LIBVER@
bin_PROGRAMS = uniset-mysql-dbserver
uniset_mysql_dbserver_LDADD = libUniSet-mysql.la $(top_builddir)/lib/libUniSet.la
uniset_mysql_dbserver_SOURCES = main.cc
include $(top_builddir)/conf/setting.mk
# install
devel_include_HEADERS = *.h
devel_includedir = $(includedir)/@PACKAGE@/mysql
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../../conf/test.xml test.xml
-- MySQL dump 9.10
--
-- Host: localhost Database: TESTBASE
-- ------------------------------------------------------
-- Server version 4.0.18-log
-- Создание пользователя для dbadmin-а
GRANT SELECT,INSERT,UPDATE,DELETE,INDEX,LOCK TABLES,CREATE,DROP ON TESTBASE.* TO dbadmin@localhost IDENTIFIED BY 'dbadmin';
-- Создание пользователя для просмотра
GRANT SELECT ON TESTBASE.* TO dbreader@"%" IDENTIFIED BY 'dbreader';
--
-- Table structure for table `AnalogSensors`
--
DROP TABLE IF EXISTS AnalogSensors;
CREATE TABLE AnalogSensors (
num int(11) NOT NULL auto_increment,
node int(3) default NULL,
id int(4) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
value int(6) default NULL,
PRIMARY KEY (num),
KEY date (date,time,time_usec),
KEY node (node,id)
) TYPE=MyISAM;
--
-- Table structure for table `DigitalSensors`
--
DROP TABLE IF EXISTS DigitalSensors;
CREATE TABLE DigitalSensors (
num int(11) NOT NULL auto_increment,
node int(3) default NULL,
id int(4) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
state char(1) default NULL,
confirm time NOT NULL default '00:00:00',
PRIMARY KEY (num),
KEY date (date,time,time_usec),
KEY node (node,id),
KEY confirm(confirm)
) TYPE=MyISAM;
--
-- Table structure for table `EmergencyLog`
--
DROP TABLE IF EXISTS EmergencyLog;
CREATE TABLE EmergencyLog (
num int(11) NOT NULL auto_increment,
eid int(3) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
PRIMARY KEY (num),
KEY eid (eid,date,time,time_usec)
) TYPE=MyISAM;
--
-- Dumping data for table `EmergencyLog`
--
--
-- Table structure for table `EmergencyRecords`
--
DROP TABLE IF EXISTS EmergencyRecords;
CREATE TABLE EmergencyRecords (
num int(11) NOT NULL auto_increment,
enum int(11) default '-1',
sid int(4) default NULL,
time time NOT NULL default '00:00:00',
time_usec int(3) unsigned default '0',
value int(6) default NULL,
PRIMARY KEY (num),
KEY enum (enum),
KEY sid (sid,time,time_usec)
) TYPE=MyISAM;
--
-- Dumping data for table `EmergencyRecords`
--
--
-- Table structure for table `ObjectsMap`
--
DROP TABLE IF EXISTS ObjectsMap;
CREATE TABLE ObjectsMap (
name varchar(80) NOT NULL default '',
rep_name varchar(80) default NULL,
id int(4) NOT NULL default '0',
msg int(1) default 0,
PRIMARY KEY (id),
KEY rep_name (rep_name),
KEY msg (msg)
) TYPE=MyISAM;
--
-- Table structure for table `RSChannel`
--
DROP TABLE IF EXISTS RSChannel;
CREATE TABLE RSChannel (
num int(11) NOT NULL auto_increment,
node int(3) default NULL,
channel int(2) default NULL,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(8) unsigned default '0',
query int(3) default NULL,
errquery int(3) default NULL,
notaskquery int(3) default NULL,
PRIMARY KEY (num),
KEY node (node,channel),
KEY time (time,date,time_usec)
) TYPE=MyISAM;
DROP TABLE IF EXISTS Network;
CREATE TABLE Network(
num int(11) NOT NULL auto_increment,
date date NOT NULL default '0000-00-00',
time time NOT NULL default '00:00:00',
time_usec int(8) unsigned default 0,
master int(3) default NULL,
slave int(3) default NULL,
connection int(2) default NULL,
PRIMARY KEY (num),
KEY (master, slave, connection),
KEY (time, date,time_usec)
) TYPE=MyISAM;
--
-- Table structure for table `SensorsThreshold`
--
DROP TABLE IF EXISTS SensorsThreshold;
CREATE TABLE SensorsThreshold (
sid int(11) NOT NULL default '0',
alarm int(8) NOT NULL default '0',
warning int(8) NOT NULL default '0'
) TYPE=MyISAM;
DELETE FROM DigitalSensors WHERE date<кTE_SUB(NOW(),INTERVAL 10 DAY);
DELETE FROM AnalogSensors WHERE date<кTE_SUB(NOW(),INTERVAL 10 DAY);
DELETE FROM Messages WHERE date<кTE_SUB(NOW(),INTERVAL 10 DAY);
DELETE FROM RSChannel WHERE date<кTE_SUB(NOW(),INTERVAL 10 DAY);
DELETE FROM Network WHERE date<кTE_SUB(NOW(),INTERVAL 10 DAY);
#include "Configuration.h"
#include "DBServer_MySQL.h"
#include "ObjectsActivator.h"
#include "Debug.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static void short_usage()
{
cout << "Usage: uniset-mysql-dbserver [--name ObjectId] [--confile configure.xml]\n";
}
// --------------------------------------------------------------------------
int main(int argc, char** argv)
{
try
{
if( argc > 1 && !strcmp(argv[1],"--help") )
{
short_usage();
return 0;
}
uniset_init(argc,argv,"configure.xml");
ObjectId ID = conf->getDBServer();
// определяем ID объекта
string name = conf->getArgParam("--name");
if( !name.empty())
{
if( ID != UniSetTypes::DefaultObjectId )
{
unideb[Debug::WARN] << "(DBServer::main): переопределяем ID заданнй в "
<< conf->getConfFileName() << endl;
}
ID = conf->oind->getIdByName(conf->getServicesSection()+"/"+name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getServicesSection() << endl;
return 1;
}
}
else if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): Не удалось определить ИДЕНТИФИКАТОР сервера" << endl;
short_usage();
return 1;
}
DBServer_MySQL dbs(ID);
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(&dbs));
act.run(false);
}
catch(Exception& ex)
{
cerr << "(DBServer::main): " << ex << endl;
}
catch(...)
{
cerr << "(DBServer::main): catch ..." << endl;
}
return 0;
}
#!/bin/sh
ulimit -Sc 1000000
uniset-start.sh -f ./uniset-mysql-dbserver --confile test.xml --name DBServer --unideb-add-levels info,crit,warn,level9,system
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../../conf/test.xml test.xml
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../../conf/test.xml test.xml
...@@ -27,7 +27,7 @@ int main( int argc, const char **argv ) ...@@ -27,7 +27,7 @@ int main( int argc, const char **argv )
ID = conf->getObjectID(name); ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId ) if( ID == UniSetTypes::DefaultObjectId )
{ {
cerr << "(main): идентификатор '" << name cerr << "(main): идентификатор '" << name
<< "' не найден в конф. файле!" << "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl; << " в секции " << conf->getObjectsSection() << endl;
return 0; return 0;
...@@ -37,10 +37,9 @@ int main( int argc, const char **argv ) ...@@ -37,10 +37,9 @@ int main( int argc, const char **argv )
SMonitor tp(ID); SMonitor tp(ID);
act.addObject(&tp); act.addObject(&tp);
SystemMessage sm(SystemMessage::StartUp); SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() ); act.broadcast( sm.transport_msg() );
act.run(false); act.run(false);
return 0;
} }
catch( Exception& ex ) catch( Exception& ex )
{ {
...@@ -51,6 +50,6 @@ int main( int argc, const char **argv ) ...@@ -51,6 +50,6 @@ int main( int argc, const char **argv )
cout << "(main): Неизвестное исключение!!!!"<< endl; cout << "(main): Неизвестное исключение!!!!"<< endl;
} }
return 1; return 0;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../../conf/test.xml test.xml
<?xml version='1.0' encoding="utf-8" ?> <?xml version='1.0' encoding="koi8-r" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0' <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'
xmlns:date="http://exslt.org/dates-and-times"> xmlns:date="http://exslt.org/dates-and-times">
<xsl:import href="ctl-cpp-common.xsl"/> <xsl:import href="ctl-cpp-common.xsl"/>
<xsl:output method="text" indent="yes" encoding="utf-8"/> <xsl:output method="text" indent="yes" encoding="koi8-r"/>
<xsl:variable name="CLASSNAME"> <xsl:variable name="CLASSNAME">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'class-name'"/></xsl:call-template> <xsl:call-template name="settings"><xsl:with-param name="varname" select="'class-name'"/></xsl:call-template>
...@@ -14,12 +14,6 @@ ...@@ -14,12 +14,6 @@
<xsl:variable name="OID"> <xsl:variable name="OID">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'ID'"/></xsl:call-template> <xsl:call-template name="settings"><xsl:with-param name="varname" select="'ID'"/></xsl:call-template>
</xsl:variable> </xsl:variable>
<xsl:variable name="TESTMODE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'testmode'"/></xsl:call-template>
</xsl:variable>
<xsl:variable name="ARGPREFIX">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'arg-prefix'"/></xsl:call-template>
</xsl:variable>
<!-- Генерирование cc-файла --> <!-- Генерирование cc-файла -->
<xsl:template match="/"> <xsl:template match="/">
...@@ -39,7 +33,6 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback() ...@@ -39,7 +33,6 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback()
return; return;
try try
{ {
<xsl:if test="normalize-space($TESTMODE)!=''">
isTestMode = checkTestMode(); isTestMode = checkTestMode();
if( trTestMode.change(isTestMode) ) if( trTestMode.change(isTestMode) )
testMode(isTestMode); testMode(isTestMode);
...@@ -52,7 +45,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback() ...@@ -52,7 +45,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback()
msleep( sleep_msec ); msleep( sleep_msec );
return; return;
} }
</xsl:if>
// проверка таймеров // проверка таймеров
checkTimers(this); checkTimers(this);
...@@ -69,7 +62,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback() ...@@ -69,7 +62,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback()
break; break;
processingMessage(&amp;msg); processingMessage(&amp;msg);
updateOutputs(false); updateOutputs(false);
// updatePreviousValues(); updatePreviousValues();
} }
// Выполнение шага программы // Выполнение шага программы
...@@ -102,7 +95,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback() ...@@ -102,7 +95,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::callback()
if( !active ) if( !active )
return; return;
msleep( sleep_msec ); msleep( sleep_msec );
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -119,20 +112,26 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setValue( UniSetTypes::ObjectId _si ...@@ -119,20 +112,26 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setValue( UniSetTypes::ObjectId _si
return; return;
} }
</xsl:if> </xsl:if>
<xsl:if test="normalize-space(@vartype)='io'">
if( _sid == <xsl:value-of select="@name"/> )
{
unideb[Debug::LEVEL2] &lt;&lt; "(setState): <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = " &lt;&lt; _val &lt;&lt; endl;
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = _val;
<xsl:call-template name="setdata"/>
return;
}
</xsl:if>
</xsl:for-each> </xsl:for-each>
ui.setValue( _sid, _val );
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void <xsl:value-of select="$CLASSNAME"/>_SK::updateOutputs( bool _force ) void <xsl:value-of select="$CLASSNAME"/>_SK::updateOutputs( bool _force )
{ {
<xsl:for-each select="//smap/item"> <xsl:for-each select="//smap/item">
<xsl:if test="normalize-space(@force)=''">
if( _force || prev_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> != <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> ) if( _force || prev_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> != <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> )
</xsl:if>
{ {
<xsl:choose> <xsl:choose>
<xsl:when test="normalize-space(@vartype)='out'"><xsl:call-template name="setdata"/></xsl:when> <xsl:when test="normalize-space(@vartype)='out'"><xsl:call-template name="setdata"/></xsl:when>
<xsl:when test="normalize-space(@vartype)='io'"><xsl:call-template name="setdata"/></xsl:when>
</xsl:choose> </xsl:choose>
prev_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; prev_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
} }
...@@ -145,7 +144,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::updateOutputs( bool _force ) ...@@ -145,7 +144,7 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::updateOutputs( bool _force )
{ {
si.id = <xsl:value-of select="@name"/>; si.id = <xsl:value-of select="@name"/>;
ui.saveState( si,m_<xsl:value-of select="@name"/>,UniversalIO::DigitalInput,getId() ); ui.saveState( si,m_<xsl:value-of select="@name"/>,UniversalIO::DigitalInput,getId() );
prev_m_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = m_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; prev_m_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = m_<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
} }
</xsl:for-each> </xsl:for-each>
--> -->
...@@ -155,20 +154,15 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::preSensorInfo( UniSetTypes::SensorM ...@@ -155,20 +154,15 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::preSensorInfo( UniSetTypes::SensorM
{ {
<xsl:for-each select="//smap/item"> <xsl:for-each select="//smap/item">
<xsl:if test="normalize-space(@vartype)='in'"> <xsl:if test="normalize-space(@vartype)='in'">
<xsl:if test="normalize-space(@loglevel)=''">
if( _sm->id == <xsl:value-of select="@name"/> ) if( _sm->id == <xsl:value-of select="@name"/> )
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = _sm->value; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = _sm->value;
</xsl:if> </xsl:if>
<xsl:if test="normalize-space(@loglevel)!=''"> <xsl:if test="normalize-space(@vartype)='io'">
if( _sm->id == <xsl:value-of select="@name"/> ) if( _sm->id == <xsl:value-of select="@name"/> )
{ <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = _sm->value;
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = _sm->value;
dlog.level( Debug::type(_sm->value) );
}
</xsl:if>
</xsl:if> </xsl:if>
</xsl:for-each> </xsl:for-each>
sensorInfo(_sm); sensorInfo(_sm);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -184,61 +178,50 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::askValue( UniSetTypes::ObjectId _si ...@@ -184,61 +178,50 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::askValue( UniSetTypes::ObjectId _si
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool <xsl:value-of select="$CLASSNAME"/>_SK::getState( UniSetTypes::ObjectId _sid ) bool <xsl:value-of select="$CLASSNAME"/>_SK::getState( UniSetTypes::ObjectId _sid )
{ {
return (bool)getValue(_sid);
}
// -----------------------------------------------------------------------------
long <xsl:value-of select="$CLASSNAME"/>_SK::getValue( UniSetTypes::ObjectId _sid )
{
try
{
<xsl:for-each select="//smap/item"> <xsl:for-each select="//smap/item">
if( _sid == <xsl:value-of select="@name"/> &amp;&amp; <xsl:value-of select="@name"/> != DefaultObjectId ) if( _sid == <xsl:value-of select="@name"/> &amp;&amp; <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
<xsl:choose> <xsl:choose>
<xsl:when test="normalize-space(@iotype)='DI'"> <xsl:when test="normalize-space(@iotype)='DI'">
<xsl:text> </xsl:text><xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='DO'"> <xsl:when test="normalize-space(@iotype)='DI'">
<xsl:text> </xsl:text><xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='AO'"> <xsl:when test="normalize-space(@iotype)='AO'">
<xsl:text> </xsl:text><xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='AI'"> <xsl:when test="normalize-space(@iotype)='AI'">
<xsl:text> </xsl:text><xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>; return <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>;
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
} }
</xsl:for-each> </xsl:for-each>
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(getState): Обращение к неизвестному ДИСКРЕТНОМУ датчику sid="
&lt;&lt; _sid &lt;&lt; endl;
return ui.getValue(_sid); return false;
}
catch(Exception&amp; ex)
{
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(getState): " &lt;&lt; ex &lt;&lt; endl;
throw;
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void <xsl:value-of select="$CLASSNAME"/>_SK::preAskSensors( UniversalIO::UIOCommand _cmd ) void <xsl:value-of select="$CLASSNAME"/>_SK::askSensors( UniversalIO::UIOCommand _cmd )
{ {
PassiveTimer ptAct(activateTimeout); PassiveTimer ptAct(activateTimeout);
while( !activated &amp;&amp; !ptAct.checkTime() ) while( !activated &amp;&amp; !ptAct.checkTime() )
{ {
cout &lt;&lt; myname &lt;&lt; "(preAskSensors): wait activate..." &lt;&lt; endl; cout &lt;&lt; myname &lt;&lt; "(askSensors): wait activate..." &lt;&lt; endl;
msleep(300); msleep(300);
if( activated ) if( activated )
break; break;
} }
if( !activated ) if( !activated )
unideb[Debug::CRIT] &lt;&lt; myname unideb[Debug::CRIT] &lt;&lt; myname
&lt;&lt; "(preAskSensors): ************* don`t activated?! ************" &lt;&lt; endl; &lt;&lt; "(askSensors): ************* don`t activated?! ************" &lt;&lt; endl;
for( ;; ) for( ;; )
{ {
...@@ -248,21 +231,25 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::preAskSensors( UniversalIO::UIOComm ...@@ -248,21 +231,25 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::preAskSensors( UniversalIO::UIOComm
<xsl:if test="normalize-space(@vartype)='in'"> <xsl:if test="normalize-space(@vartype)='in'">
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
ui.askRemoteSensor(<xsl:value-of select="@name"/>,_cmd,node_<xsl:value-of select="@name"/>,getId()); ui.askRemoteSensor(<xsl:value-of select="@name"/>,_cmd,node_<xsl:value-of select="@name"/>,getId());
</xsl:if> </xsl:if>
<xsl:if test="normalize-space(@vartype)='io'">
if( <xsl:value-of select="@name"/> != DefaultObjectId )
ui.askRemoteSensor(<xsl:value-of select="@name"/>,_cmd,node_<xsl:value-of select="@name"/>,getId());
</xsl:if>
</xsl:for-each> </xsl:for-each>
return; return;
} }
catch(SystemError&amp; err) catch(SystemError&amp; err)
{ {
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(preAskSensors): " &lt;&lt; err &lt;&lt; endl; unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(askSensors): " &lt;&lt; err &lt;&lt; endl;
} }
catch(Exception&amp; ex) catch(Exception&amp; ex)
{ {
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(preAskSensors): " &lt;&lt; ex &lt;&lt; endl; unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(askSensors): " &lt;&lt; ex &lt;&lt; endl;
} }
catch(...) catch(...)
{ {
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(preAskSensors): catch(...)" &lt;&lt; endl; unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(askSensors): catch(...)" &lt;&lt; endl;
} }
msleep(askPause); msleep(askPause);
} }
...@@ -274,22 +261,20 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -274,22 +261,20 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
if( !_state ) if( !_state )
{ {
ptResetMsg.reset(); ptResetMsg.reset();
return; return;
} }
alarm( _code, _state ); alarm( _code, _state );
ptResetMsg.reset(); ptResetMsg.reset();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
<!-- END CC-FILE --> <!-- END CC-FILE -->
</xsl:template> </xsl:template>
<xsl:template name="getdata"> <xsl:template name="getdata">
<xsl:param name="output">0</xsl:param> <xsl:param name="output">0</xsl:param>
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
try
{
<xsl:choose> <xsl:choose>
<xsl:when test="normalize-space(@iotype)='DI'"> <xsl:when test="normalize-space(@iotype)='DI'">
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
...@@ -297,6 +282,8 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -297,6 +282,8 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
<xsl:when test="normalize-space(@iotype)='AI'"> <xsl:when test="normalize-space(@iotype)='AI'">
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
</xsl:when> </xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="normalize-space(@iotype)='DO'"> <xsl:when test="normalize-space(@iotype)='DO'">
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getState(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
</xsl:when> </xsl:when>
...@@ -304,83 +291,61 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -304,83 +291,61 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>); <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> = ui.getValue(<xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/>);
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
}
catch( UniSetTypes::Exception&amp; ex )
{
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(getdata): " &lt;&lt; ex &lt;&lt; endl;
throw;
}
} }
</xsl:template> </xsl:template>
<xsl:template name="setdata"> <xsl:template name="setdata">
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
try <xsl:choose>
{ <xsl:when test="normalize-space(@iotype)='DI'">
<xsl:choose> si.id = <xsl:value-of select="@name"/>;
<xsl:when test="normalize-space(@iotype)='DI'"> si.node = node_<xsl:value-of select="@name"/>;
si.id = <xsl:value-of select="@name"/>; ui.saveState( si, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>,UniversalIO::DigitalInput,getId() );
si.node = node_<xsl:value-of select="@name"/>; </xsl:when>
ui.saveState( si, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>,UniversalIO::DigitalInput,getId() ); <xsl:when test="normalize-space(@iotype)='DO'">
</xsl:when> ui.setState( <xsl:value-of select="@name"/>, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/> );
<xsl:when test="normalize-space(@iotype)='DO'"> </xsl:when>
ui.setState( <xsl:value-of select="@name"/>, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/> ); <xsl:when test="normalize-space(@iotype)='AI'">
</xsl:when> si.id = <xsl:value-of select="@name"/>;
<xsl:when test="normalize-space(@iotype)='AI'"> si.node = node_<xsl:value-of select="@name"/>;
si.id = <xsl:value-of select="@name"/>; ui.saveValue( si, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>,UniversalIO::AnalogInput, getId() );
si.node = node_<xsl:value-of select="@name"/>; </xsl:when>
ui.saveValue( si, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>,UniversalIO::AnalogInput, getId() ); <xsl:when test="normalize-space(@iotype)='AO'">
</xsl:when> ui.setValue( <xsl:value-of select="@name"/>, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/> );
<xsl:when test="normalize-space(@iotype)='AO'"> </xsl:when>
ui.setValue( <xsl:value-of select="@name"/>, <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, node_<xsl:value-of select="@name"/> ); </xsl:choose>
</xsl:when> }
</xsl:choose>
}
catch( UniSetTypes::Exception&amp; ex )
{
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(setdata): " &lt;&lt; ex &lt;&lt; endl;
throw;
}
}
</xsl:template> </xsl:template>
<xsl:template name="setdata_value"> <xsl:template name="setdata_value">
<xsl:param name="setval">0</xsl:param> <xsl:param name="setval">0</xsl:param>
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
try
{
<xsl:choose> <xsl:choose>
<xsl:when test="normalize-space(@iotype)='DI'"> <xsl:when test="normalize-space(@iotype)='DI'">
si.id = <xsl:value-of select="@name"/>; si.id = <xsl:value-of select="@name"/>;
si.node = node_<xsl:value-of select="@name"/>; si.node = node_<xsl:value-of select="@name"/>;
ui.saveState( si,<xsl:value-of select="$setval"/>,UniversalIO::DigitalInput,getId() ); ui.saveState( si,<xsl:value-of select="$setval"/>,UniversalIO::DigitalInput,getId() );
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='DO'"> <xsl:when test="normalize-space(@iotype)='DO'">
ui.setState( <xsl:value-of select="@name"/>,<xsl:value-of select="$setval"/>, node_<xsl:value-of select="@name"/>); ui.setState( <xsl:value-of select="@name"/>,<xsl:value-of select="$setval"/>, node_<xsl:value-of select="@name"/>);
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='AI'"> <xsl:when test="normalize-space(@iotype)='AI'">
si.id = <xsl:value-of select="@name"/>; si.id = <xsl:value-of select="@name"/>;
si.node = node_<xsl:value-of select="@name"/>; si.node = node_<xsl:value-of select="@name"/>;
ui.saveValue( si,<xsl:value-of select="$setval"/>,UniversalIO::AnalogInput, getId() ); ui.saveValue( si,<xsl:value-of select="$setval"/>,UniversalIO::AnalogInput, getId() );
</xsl:when> </xsl:when>
<xsl:when test="normalize-space(@iotype)='AO'"> <xsl:when test="normalize-space(@iotype)='AO'">
ui.setValue( <xsl:value-of select="@name"/>,<xsl:value-of select="$setval"/>, node_<xsl:value-of select="@name"/> ); ui.setValue( <xsl:value-of select="@name"/>,<xsl:value-of select="$setval"/>, node_<xsl:value-of select="@name"/> );
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
}
catch( UniSetTypes::Exception&amp; ex )
{
unideb[Debug::CRIT] &lt;&lt; myname &lt;&lt; "(setdata): " &lt;&lt; ex &lt;&lt; endl;
throw;
}
} }
</xsl:template> </xsl:template>
<xsl:template name="check_changes"> <xsl:template name="check_changes">
<xsl:param name="onlymsg"></xsl:param> <xsl:param name="onlymsg"></xsl:param>
<xsl:choose> <xsl:choose>
<xsl:when test="normalize-space(@iotype)='DI'"> <xsl:when test="normalize-space(@iotype)='DI'">
<xsl:if test="normalize-space($onlymsg)=''"> <xsl:if test="normalize-space($onlymsg)=''">
...@@ -389,12 +354,11 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -389,12 +354,11 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
{ {
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
<xsl:if test="normalize-space($onlymsg)=''"> <xsl:if test="normalize-space($onlymsg)=''">
// cout &lt;&lt; myname &lt;&lt; ": (DI) change state <xsl:value-of select="@name"/> set " // cout &lt;&lt; myname &lt;&lt; ": (DI) change state <xsl:value-of select="@name"/> set "
// &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl; // &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl;
</xsl:if> </xsl:if>
SensorMessage _sm( <xsl:value-of select="@name"/>, (bool)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, Message::Medium); SensorMessage _sm( <xsl:value-of select="@name"/>, (bool)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>);
_sm.sensor_type = UniversalIO::DigitalInput;
sensorInfo(&amp;_sm); sensorInfo(&amp;_sm);
} }
} }
...@@ -407,15 +371,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -407,15 +371,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
<xsl:if test="normalize-space($onlymsg)=''"> <xsl:if test="normalize-space($onlymsg)=''">
// cout &lt;&lt; myname &lt;&lt; ": (AI) change value <xsl:value-of select="@name"/> set " // cout &lt;&lt; myname &lt;&lt; ": (AI) change value <xsl:value-of select="@name"/> set "
// &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl; // &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl;
</xsl:if> </xsl:if>
// приходится искуственно использовать третий параметр, SensorMessage _sm( <xsl:value-of select="@name"/>, (long)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>);
// что-бы компилятор выбрал
// правильный(для аналоговых) конструктор у SensorMessage
IOController_i::CalibrateInfo _ci;
SensorMessage _sm( <xsl:value-of select="@name"/>, (long)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, _ci);
_sm.sensor_type = UniversalIO::AnalogInput;
sensorInfo(&amp;_sm); sensorInfo(&amp;_sm);
} }
} }
...@@ -428,11 +387,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -428,11 +387,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
<xsl:if test="normalize-space($onlymsg)=''"> <xsl:if test="normalize-space($onlymsg)=''">
// cout &lt;&lt; myname &lt;&lt; ": (DO) change state <xsl:value-of select="@name"/> set " // cout &lt;&lt; myname &lt;&lt; ": (DO) change state <xsl:value-of select="@name"/> set "
// &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl; // &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl;
</xsl:if> </xsl:if>
SensorMessage _sm( <xsl:value-of select="@name"/>, (bool)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, Message::Medium); SensorMessage _sm( <xsl:value-of select="@name"/>, (bool)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>);
_sm.sensor_type = UniversalIO::DigitalOutput;
sensorInfo(&amp;_sm); sensorInfo(&amp;_sm);
} }
} }
...@@ -445,15 +403,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code ...@@ -445,15 +403,10 @@ void <xsl:value-of select="$CLASSNAME"/>_SK::setMsg( UniSetTypes::ObjectId _code
if( <xsl:value-of select="@name"/> != DefaultObjectId ) if( <xsl:value-of select="@name"/> != DefaultObjectId )
{ {
<xsl:if test="normalize-space($onlymsg)=''"> <xsl:if test="normalize-space($onlymsg)=''">
// cout &lt;&lt; myname &lt;&lt; ": (AO) change value <xsl:value-of select="@name"/> set " // cout &lt;&lt; myname &lt;&lt; ": (AO) change value <xsl:value-of select="@name"/> set "
// &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl; // &lt;&lt; <xsl:call-template name="setprefix"/><xsl:value-of select="@name"/> &lt;&lt; endl;
</xsl:if> </xsl:if>
// приходится искуственно использовать третий параметр, SensorMessage _sm( <xsl:value-of select="@name"/>, (long)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>);
// что-бы компилятор выбрал
// правильный(для аналоговых) конструктор у SensorMessage
IOController_i::CalibrateInfo _ci;
SensorMessage _sm( <xsl:value-of select="@name"/>, (long)<xsl:call-template name="setprefix"/><xsl:value-of select="@name"/>, _ci);
_sm.sensor_type = UniversalIO::AnalogOutput;
sensorInfo(&amp;_sm); sensorInfo(&amp;_sm);
} }
} }
......
<?xml version='1.0' encoding="utf-8" ?> <?xml version='1.0' encoding="koi8-r" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0' <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'
xmlns:date="http://exslt.org/dates-and-times"> xmlns:date="http://exslt.org/dates-and-times">
<xsl:import href="ctl-cpp-common.xsl"/> <xsl:import href="ctl-cpp-common.xsl"/>
<xsl:output method="text" indent="yes" encoding="utf-8"/> <xsl:output method="text" indent="yes" encoding="koi8-r"/>
<xsl:variable name="CLASSNAME"> <xsl:variable name="CLASSNAME">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'class-name'"/></xsl:call-template> <xsl:call-template name="settings"><xsl:with-param name="varname" select="'class-name'"/></xsl:call-template>
...@@ -14,9 +14,7 @@ ...@@ -14,9 +14,7 @@
<xsl:variable name="OID"> <xsl:variable name="OID">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'ID'"/></xsl:call-template> <xsl:call-template name="settings"><xsl:with-param name="varname" select="'ID'"/></xsl:call-template>
</xsl:variable> </xsl:variable>
<xsl:variable name="TESTMODE">
<xsl:call-template name="settings"><xsl:with-param name="varname" select="'testmode'"/></xsl:call-template>
</xsl:variable>
<!-- Генерирование main для UniSet_FSM --> <!-- Генерирование main для UniSet_FSM -->
<xsl:template match="/"> <xsl:template match="/">
...@@ -24,10 +22,10 @@ ...@@ -24,10 +22,10 @@
/* /*
DO NOT EDIT THIS FILE. IT IS AUTOGENERATED FILE. DO NOT EDIT THIS FILE. IT IS AUTOGENERATED FILE.
ALL YOUR CHANGES WILL BE LOST. ALL YOUR CHANGES WILL BE LOST.
НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ. ЭТОТ ФАЙЛ СОЗДАН АВТОМАТИЧЕСКИ. НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ. ЭТОТ ФАЙЛ СОЗДАН АВТОМАТИЧЕСКИ.
ВСЕ ВАШИ ИЗМЕНЕНИЯ БУДУТ ПОТЕРЯНЫ. ВСЕ ВАШИ ИЗМЕНЕНИЯ БУДУТ ПОТЕРЯНЫ.
*/ */
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// generate timestamp: <xsl:value-of select="date:date()"/> // generate timestamp: <xsl:value-of select="date:date()"/>
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -58,7 +56,7 @@ int main( int argc, const char** argv ) ...@@ -58,7 +56,7 @@ int main( int argc, const char** argv )
string logfilename = conf->getArgParam("--logfile","<xsl:value-of select="$CLASSNAME"/>.log"); string logfilename = conf->getArgParam("--logfile","<xsl:value-of select="$CLASSNAME"/>.log");
string logname( conf->getLogDir() + logfilename ); string logname( conf->getLogDir() + logfilename );
unideb.logFile( logname.c_str() ); unideb.logFile( logname.c_str() );
<xsl:if test="not(normalize-space(//@OID))=''"> <xsl:if test="not(normalize-space(//@OID))=''">
<xsl:value-of select="$CLASSNAME"/> obj; <xsl:value-of select="$CLASSNAME"/> obj;
...@@ -72,7 +70,7 @@ int main( int argc, const char** argv ) ...@@ -72,7 +70,7 @@ int main( int argc, const char** argv )
ID = conf->getObjectID(name); ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId ) if( ID == UniSetTypes::DefaultObjectId )
{ {
cerr &lt;&lt; "(main): идентификатор '" &lt;&lt; name cerr &lt;&lt; "(main): идентификатор '" &lt;&lt; name
&lt;&lt; "' не найден в конф. файле!" &lt;&lt; "' не найден в конф. файле!"
&lt;&lt; " в секции " &lt;&lt; conf->getObjectsSection() &lt;&lt; endl; &lt;&lt; " в секции " &lt;&lt; conf->getObjectsSection() &lt;&lt; endl;
return 0; return 0;
...@@ -80,11 +78,11 @@ int main( int argc, const char** argv ) ...@@ -80,11 +78,11 @@ int main( int argc, const char** argv )
} }
<xsl:value-of select="$CLASSNAME"/> obj(ID); <xsl:value-of select="$CLASSNAME"/> obj(ID);
</xsl:if> </xsl:if>
ObjectsActivator act; ObjectsActivator act;
act.addObject(static_cast&lt;class UniSetObject*&gt;(&amp;obj)); act.addObject(static_cast&lt;class UniSetObject*&gt;(&amp;obj));
SystemMessage sm(SystemMessage::StartUp); SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() ); act.broadcast( sm.transport_msg() );
act.run(false); act.run(false);
pause(); // пауза, чтобы дочерние потоки успели завершить работ pause(); // пауза, чтобы дочерние потоки успели завершить работ
......
/*! \page page_Concept Основные понятия /*! \page page_Concept Основные понятия
В библиотеке \b uniset имеется ряд основопологающих кубиков (терминов), В библиотеке \b uniset имеется ряд основопологающих кубиков (терминов),
из которых складывается библиотека, и которые используются во многих из которых складывается библиотека, и которые используются во многих
местах данной документации. Здесь приводятся определения этих терминов. местах данной документации. Здесь приводятся определения этих терминов.
- \ref sec_Concept_Object - \ref sec_Cnpt_Object
- \ref sec_Concept_ObjectTypes - \ref sec_Cnpt_ObjectTypes
- \ref sec_Concept_Message - \ref sec_Cnpt_Message
- \ref sec_Concept_ObjectId - \ref sec_Cnpt_ObjectId
- \ref sec_Concept_Repository - \ref sec_Cnpt_Repository
- \ref sec_Concept_Sensor - \ref sec_Cnpt_Sensor
- \ref sec_Concept_Process - \ref sec_Cnpt_Process
\section sec_Concept_Object Объект \section sec_Cnpt_Object Объект
В разных местах описаний, в зависимости от контекста, В разных местах описаний, в зависимости от контекста,
под "объектом" подразумевается либо объект класса так или иначе наследующегося под "объектом" подразумевается либо объект класса так или иначе наследующегося
от базового класса библиотеки UniSetObject, либо от базового класса библиотеки UniSetObject, либо
некий концептуальный программный объект способный некий концептуальный программный объект способный
получать и обрабатывать сообщения. получать и обрабатывать сообщения.
\section sec_Concept_ObjectTypes Основные типы объектов \section sec_Cnpt_ObjectTypes Основные типы объектов
В библиотеке произведено условное деление на следующие типы объектов: В библиотеке произведено условное деление на следующие типы объектов:
- (простые) объекты - наследуются от класса UniSetObject - (простые) объекты - наследуются от класса UniSetObject
- контроллеры - являются наследниками класса IOController - контроллеры - являются наследниками класса IOController
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
- узлы - в строгом смысле, не являются объектами, - узлы - в строгом смысле, не являются объектами,
но обладают уникальным идентификатором. но обладают уникальным идентификатором.
\section sec_Concept_Message Сообщения \section sec_Cnpt_Message Сообщения
Вся система взаимодейтсвия между объектами в основном Вся система взаимодейтсвия между объектами в основном
построена на использовании сообщений (передаваемых построена на использовании сообщений (передаваемых
путём удаленного вызова специальных функций, путём удаленного вызова специальных функций,
...@@ -39,29 +39,29 @@ ...@@ -39,29 +39,29 @@
Для разработчиков систем на основе libuniset, заложена Для разработчиков систем на основе libuniset, заложена
возможность определять свои типы сообщений, при этом их возможность определять свои типы сообщений, при этом их
идентификаторы \b должны начинатся от значения идентификаторы \b должны начинатся от значения
UniSetTypes::Message::TheLastFieldOfTypeOfMessage. UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
\code \code
enum MyMessageTypes enum MyMessageTypes
{ {
myBegin = UniSetTypes::Message::TheLastFieldOfTypeOfMessage, myBegin = UniSetTypes::Message::TheLastFieldOfTypeOfMessage,
myMessageType1, myMessgeType1,
myMessageType2, myMessgeType2,
myMessageType3, myMessgeType3,
... ...
}; };
\endcode \endcode
\section sec_Concept_ObjectId Идентификатор объекта \section sec_Cnpt_ObjectId Идентификатор объекта
Каждый объект, которому необходимо взаимодействовать с другими объектами Каждый объект, которому необходимо взаимодействовать с другими объектами
(в том числе датчиками см. \ref sec_Concept_Sensor) должен обладать уникальным (в том числе датчиками см. \ref sec_Cnpt_Sensor) должен обладать уникальным
идентификатором. В качестве идентификатора выступает любое число типа \b UniSetTypes::ObjectId. идентификатором. В качестве идентификатора выступает любое число типа \b UniSetTypes::ObjectId.
Зарезервированным числом является UniSetTypes::DefaultObjectId. Зарезервированным числом является UniSetTypes::DefaultObjectId.
Минимальное требование - это уникальность в рамках одного узла. Минимальное требование - это уникальность в рамках одного узла.
Так как полный идентификатор объекта формируется парой \b <id,\b node> Так как полный идентификатор объекта формируется парой \b <id,\b node>
Где \b node - такое же число, являющееся идентификатором узла. Где \b node - такое же число, являющееся идентификатором узла.
При этом приветствуется использование идентификатора уникального При этом приветствуется использование идентификатора уникального
в рамках всей создаваемой системы. Т.к. в последствии возможен в рамках всей создаваемой системы. Т.к. в последствии возможен
уход от использования параметра node. уход от использования параметра node.
...@@ -101,7 +101,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage. ...@@ -101,7 +101,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
<objects name="UniObjects"> <objects name="UniObjects">
<item name="TestProc1"/> <item name="TestProc1"/>
<item name="TestProc2"/> <item name="TestProc2"/>
</objects> </objects>
</ObjectsMap> </ObjectsMap>
... ...
</Configurations> </Configurations>
...@@ -110,9 +110,9 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage. ...@@ -110,9 +110,9 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
будет присвоен идентификатор (просто по порядку). См. \ref UniSetTypes::ObjectIndex_XML будет присвоен идентификатор (просто по порядку). См. \ref UniSetTypes::ObjectIndex_XML
\note Следует иметь ввиду, что автоматическое присвоение идентификаторов, \note Следует иметь ввиду, что автоматическое присвоение идентификаторов,
\b зависит \b от \b положения описания объекта в конфигурацинном файле. \b зависит \b от \b положения описания объекта в конфигурацинном фале.
Поэтому если вставить новый объект в любой секции, то все идентификаторы после него, Поэтому если вставить новый объект в любой секции, то все идентификаторы после него,
станут недействительными (сместятся на единицу). Т.е. необходимо отслеживать, станут недействительными (сместяться на единицу). Т.е. необходимо отслеживать,
что конфигурационные файлы на всех узлах собвпадают между собой. что конфигурационные файлы на всех узлах собвпадают между собой.
\note Из-за не надёжности это способ не рекомендуется к использованию. \note Из-за не надёжности это способ не рекомендуется к использованию.
...@@ -159,7 +159,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage. ...@@ -159,7 +159,7 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
<objects name="UniObjects"> <objects name="UniObjects">
<item id="200" name="TestProc1"/> <item id="200" name="TestProc1"/>
<item id="201" name="TestProc2"/> <item id="201" name="TestProc2"/>
</objects> </objects>
</ObjectsMap> </ObjectsMap>
... ...
</Configurations> </Configurations>
...@@ -169,13 +169,13 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage. ...@@ -169,13 +169,13 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
следить сам разработчик (хотя эта проверка может быть автоматизирована следить сам разработчик (хотя эта проверка может быть автоматизирована
не сложными скриптами). не сложными скриптами).
\section sec_Concept_Repository Репозиторий объектов
\section sec_Concept_Sensor Датчик \section sec_Cnpt_Repository Репозиторий объектов
\section sec_Cnpt_Sensor Датчик
Датчик - это одно из базовых понятий при построении систем на основе libuniset. Датчик - это одно из базовых понятий при построении систем на основе libuniset.
Датчик - это информационная единица. Практически любая информация Датчик - это информационная единица. Практически любая информация
(о событиях, о состоянии того или иного процесса, объекта, сообщение оператору и т.п.) (о событиях, о состоянии того или иного процесса, объекта, сообщение оператору и т.п.)
передаётся через состояние "датчика". В библиотеке предусмотрено четыре типа датчиков. передаётся через состояние "датчика". В библиотеке предусмотрено четыре типа датчиков.
- DI - UniversalIO::DigitalInput - дискретный вход - DI - UniversalIO::DigitalInput - дискретный вход
- DO - UniversalIO::DigitalOutput - дискретный выход - DO - UniversalIO::DigitalOutput - дискретный выход
...@@ -187,15 +187,15 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage. ...@@ -187,15 +187,15 @@ UniSetTypes::Message::TheLastFieldOfTypeOfMessage.
"Входы"(DI,AI) - это информация от объекта "в систему управления". "Входы"(DI,AI) - это информация от объекта "в систему управления".
Помимо этого, датчики не обязательно должны быть "живыми" входами или выходами. Помимо этого, датчики не обязательно должны быть "живыми" входами или выходами.
При помощи этих четырёх типов, можно кодировать любую информацию, При помощи этих четырёх типов, можно кодировать любую информацию,
Например можно передавать сообщения оператору, заранее создавая для каждого Например можно передавать сообщения оператору, заранее создавая для каждого
сообщения свой "датчик" и в случае необходимости послать сообщение сообщения свой "датчик" и в случае необходимости послать сообщение
выставлять его в "1". выставлять его в "1".
Удобство и универсальность датчиков (цифр) позволяет использовать для Удобство и универсальность датчиков (цифр) позволяет использовать для
передачи данных большое число различных протоколов, расчитанных передачи данных большое число различных протоколов, расчитанных
на передачу цифровой информации (не текстовой). на передачу цифровой информации (не текстовой).
Например CAN, ModbusRTU, ModbusTCP и т.п. Например CAN, ModbusRTU, ModbusTCP и т.п.
\section sec_Concept_Process Процесс \section sec_Cnpt_Process Процесс
Под процессом в документации чаще всего подразумевается системный Под процессом в документации чаще всего подразумевается системный
процесс (запущенная программа) выполняющий те или иные функции управления процесс (запущенная программа) выполняющий те или иные функции управления
и обменивающийся для этого с другими процессами сообщениями или и обменивающийся для этого с другими процессами сообщениями или
......
...@@ -8,17 +8,17 @@ ...@@ -8,17 +8,17 @@
- \ref pgIONC_secRecomendation - \ref pgIONC_secRecomendation
Все i/o процессы должны наследоватся от класса IOController. Если вам необходимо написать i/o процесс, который Все i/o процессы должны наследоватся от класса IOController. Если вам необходимо написать i/o процесс, который
помимо операций i/o еще и уведомляет об изменении состояния входов(выходов), то наследуйтесь от класса IONotifyController. помимо операций i/o еще и уведомляет об изменении состояния входов(выходов), то наследуйтесь от класса IONotifyController.
Эти классы объявляют минимальный(базовый) интерфейс для IOController-ов, который вы можете расширять. Эти классы объявляют минимальный(базовый) интерфейс для IOController-ов, который вы можете расширять.
\par \par
Рассмотрим написание на примере простого процесса ввода/вывода, позволяющего заказывать у себя уведомления, а Рассмотрим написание на примере простого процесса ввода/вывода, позволяющего заказывать у себя уведомления, а
так же обладающего дополнительной функцией CardIOTypes getCardIOType(); так же обладающего дополнительной функцией CardIOTypes getCardIOType();
\section pgIONC_secDeclareIDL Объявление интерфейса на IDL \section pgIONC_secDeclareIDL Объявление интерфейса на IDL
\note Написание интерфейса на IDL требуется, только если вам необходимо расширить базовый набор \note Написание интерфейса на IDL требуется, только если вам необходимо расширить базовый набор
IDL-функций. Все функции обяъвленные здесь станут доступны внешним объекта (локальныйм и удалённым). IDL-функций. Все функции обяъвленные здесь станут доступны внешним объекта (локальныйм и удалённым).
При написании интерфейса на IDL действуют те же правила, а именно наследование от соответствующего интерфейса. При написании интерфейса на IDL действуют те же правила, а именно наследование от соответствующего интерфейса.
Пример объявления: Пример объявления:
\code \code
...@@ -34,26 +34,26 @@ ...@@ -34,26 +34,26 @@
DIO5600, DIO5600,
AIO5720 AIO5720
}; };
CardIOTypes getCardIOType(); CardIOTypes getCardIOType();
}; };
#endif #endif
\endcode \endcode
\par \par
После компиляции (компилятором для idl) автоматически генерируются следующие файлы: После компиляции (компилятором для idl) автоматически генерируются следующие файлы:
- MyNotifyController_iSK.cc - MyNotifyController_iSK.cc
- MyNotifyController_iSK.hh - MyNotifyController_iSK.hh
На основе этих файлов вы реализуете свой интерфейс на С++. На основе этих файлов вы реализуете свой интерфейс на С++.
\section pgIONC_secImplementation Реализация интерфейса на C++ \section pgIONC_secImplementation Реализация интерфейса на C++
Необходимо создать класс реализующий объявленный интерфейс. Формирование названия класса и правила наследования Необходимо создать класс реализующий объявленный интерфейс. Формирование названия класса и правила наследования
см. \ref UniSetLibStylePage. см. \ref UniSetLibStylePage.
\par \par
Базовые функции интерфейса IONotifyController_i уже реализованы в классе IONotifyController. Поэтому остается только Базовые функции интерфейса IONotifyController_i уже реализованы в классе IONotifyController. Поэтому остается только
наследоваться от него и реализовать недостающие функции. В итоге получаем наследоваться от него и реализовать недостающие функции. В итоге получаем
\code \code
#ifndef MyNotifyController_H_ #ifndef MyNotifyController_H_
#define MyNotifyController_H_ #define MyNotifyController_H_
...@@ -62,48 +62,48 @@ ...@@ -62,48 +62,48 @@
#include "NotifyController.h" #include "NotifyController.h"
#include "TestActiveProcess_i.hh" #include "TestActiveProcess_i.hh"
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
class MyNotifyController: class MyNotifyController:
public POA_MyNotifyController_i, // <--- этого наследования не будет, если вы не писали интерфейс на IDL public POA_MyNotifyController_i, // <--- этого наследования не будет, если вы не писали интерфейс на IDL
public IONotifyController public IONotifyController
{ {
public: public:
// ------- Конструктор с заданием обязательных параметров --------------- // ------- Конструктор с заданием обязательных параметров ---------------
MyNotifyController( ObjectId id ); MyNotifyController( ObjectId id );
~MyNotifyController(); ~MyNotifyController();
// ------- функции объевленные в IDL(интерфейс данного объекта) --------- // ------- функции объевленные в IDL(интерфейс данного объекта) ---------
virtual MyNotifyController_i::CardIOTypes getCardIOType(); virtual MyNotifyController_i::CardIOTypes getCardIOType();
// ------- обязательные для реализации функции ------------------------- // ------- обязательные для реализации функции -------------------------
// т.к. они объявленны в базовых классах как чисто виртуальные // т.к. они объявленны в базовых классах как чисто виртуальные
virtual void processingMessage( UniSetTypes::VoidMessage *msg); virtual void processingMessage( UniSetTypes::VoidMessage *msg);
virtual void setState( ObjectId id, CORBA::Boolean state); virtual void setState( ObjectId id, CORBA::Boolean state);
virtual void setValue( ObjectId id, CORBA::Long value); virtual void setValue( ObjectId id, CORBA::Long value);
// просто главная функция (не обязательная) // просто главная функция (не обязательная)
virtual void execute(); virtual void execute();
protected: protected:
// Сделан protected чтобы нельзя было создать объект класса // Сделан protected чтобы нельзя было создать объект класса
// не задав обязательных параметров // не задав обязательных параметров
MyNotifyController(); MyNotifyController();
// ------- обязательные для реализации функции ------------------------- // ------- обязательные для реализации функции -------------------------
virtual void sensorsRegister(); // регистрация датчиков за которые отвечает данный контроллер virtual void sensorsRegister(); // регистрация датчиков за которые отвечает данный контроллер
// если требуются специальные действия при РАЗрегистрации // если требуются специальные действия при РАЗрегистрации
// то можно переопределить эту функцию примерно так // то можно переопределить эту функцию примерно так
// virtual void sensorsUnregistration(); // virtual void sensorsUnregistration();
// { // {
// IONotifyController::sensorsUnRegister(); // IONotifyController::sensorsUnRegister();
// // свои действия // // свои действия
// // ... // // ...
// } // }
}; };
\endcode \endcode
Теперь реализация... Теперь реализация...
\par \par
-# Не забывайте в конструкторе вызывать конструктор базового класса и передавать ему ObjectId. -# Не забывайте в конструкторе вызывать конструктор базового класса и передавать ему ObjectId.
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
{ {
... ...
}; };
\endcode \endcode
-# В конструкторе регистрировать датчики \b ЗАПРЕЩЕНО, для этого есть функция sensorsRegister(). -# В конструкторе регистрировать датчики \b ЗАПРЕЩЕНО, для этого есть функция sensorsRegister().
\code \code
MyNotifyController::sensorsRegistration() MyNotifyController::sensorsRegistration()
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
asRegistration(SensotInfo(Sens2)); // аналоговый датчик asRegistration(SensotInfo(Sens2)); // аналоговый датчик
... ...
}; };
\endcode \endcode
\note Функции sensorsRegistration() и sensorsUnregistration() будут вызваны автоматически (при активизации и завершении работы) \note Функции sensorsRegistration() и sensorsUnregistration() будут вызваны автоматически (при активизации и завершении работы)
поэтому отдельно(самостоятельно) их вызывать \b НЕ \b НАДО. поэтому отдельно(самостоятельно) их вызывать \b НЕ \b НАДО.
...@@ -137,8 +137,8 @@ ...@@ -137,8 +137,8 @@
{ {
// Здесь происходит фактический опрос датчиков // Здесь происходит фактический опрос датчиков
.... ....
// далее сохранение нового состояния // далее сохранение нового состояния
saveState(SensotInfo(Sens1), state, UniversalIO::DigitalInput); saveState(SensotInfo(Sens1), state, UniversalIO::DigitalInput);
saveValue(SensotInfo(Sens2), value, UniversalIO::AnalogInput); saveValue(SensotInfo(Sens2), value, UniversalIO::AnalogInput);
} }
...@@ -149,7 +149,7 @@ ...@@ -149,7 +149,7 @@
В завершение реализация запуска В завершение реализация запуска
\section pgIONC_secMain Написание функции main() для подключения процесса \section pgIONC_secMain Написание функции main() для подключения процесса
\code \code
#include "ObjectsMap.h" #include "ObjectsMap.h"
#include "MyNotifyController.h" #include "MyNotifyController.h"
...@@ -158,11 +158,11 @@ ...@@ -158,11 +158,11 @@
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
using namespace UniSetTypes; using namespace UniSetTypes;
using namespace std; using namespace std;
int main( int argc, char **argv ) int main( int argc, char **argv )
{ {
conf = new Configuration(argc, (const char**)argv, "configure.xml", (ObjectInfo*)ObjectsMap); conf = new Configuration(argc, (const char**)argv, "configure.xml", (ObjectInfo*)ObjectsMap);
MyNotifyController nc( idMyNotifyController ); // idMyNotifyController - уникальный идентификатор объекта MyNotifyController nc( idMyNotifyController ); // idMyNotifyController - уникальный идентификатор объекта
ObjectsActivator activator; ObjectsActivator activator;
activator.addObject(static_cast<class UniSetObject*>(&tnc)); activator.addObject(static_cast<class UniSetObject*>(&tnc));
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
nc.execute(); nc.execute();
} }
catch(...) catch(...)
{ {
} }
} }
\endcode \endcode
...@@ -184,18 +184,18 @@ ...@@ -184,18 +184,18 @@
Т.е. код будет выглядеть так: Т.е. код будет выглядеть так:
\code \code
... ...
class MyNotifyController: class MyNotifyController:
public POA_MyNotifyController_i, // <--- этого наследования не будет, если вы не писали интерфейс на IDL public POA_MyNotifyController_i, // <--- этого наследования не будет, если вы не писали интерфейс на IDL
public IONotifyController_LT public IONotifyController_LT
{ {
public: public:
... ...
} }
\endcode \endcode
И при заказе таймеров надо использовать не \a ui.askTimer(...), а просто \a askTimer(...). И при заказе таймеров надо использовать не \a ui.askTimer(...), а просто \a askTimer(...).
\code \code
function my_func() function my_func()
{ {
...@@ -203,22 +203,22 @@ ...@@ -203,22 +203,22 @@
askTimer(TimerId1, Time); askTimer(TimerId1, Time);
... ...
} }
\endcode \endcode
Функция IONotifyController_LT::askTimer() повторяет интерфейс UniversalInterface::askTimer(). Функция IONotifyController_LT::askTimer() повторяет интерфейс UniversalInterface::askTimer().
Реализация построена, на переопределении функции UniSetObject::callback(), поэтому если поток Реализация построена, на переопределении функции UniSetObject::callback(), поэтому если поток
не будет создан, таймеры работать не будут. не будет создан, таймеры работать не будут.
\sa LT_Object \sa LT_Object
\section pgIONC_secRecomendation Некоторые общие рекомендации \section pgIONC_secRecomendation Некоторые общие рекомендации
-# Все функции и параметры должны быть откоментированы. -# Все функции и параметры должны быть откоментированы.
-# Заказ датчиков, таймеров, работа с информацией в основном происходит при помощи UniversalInterface. В каждом -# Заказ датчиков, таймеров, работа с информацией в основном происходит при помощи UniversalInterface. В каждом
классе имеется объект этого интерфейса (UniSetObject::ui), поэтому необходимости в отдельном его создании нет. классе имеется объект этого интерфейса (UniSetObject::ui), поэтому необходимости в отдельном его создании нет.
-# Не регистрируйте датчики в конструкторе. -# Не регистрируйте датчики в конструкторе.
-# Не вызывайте разрегистрацию в деструкторе. -# Не вызывайте разрегистрацию в деструкторе.
\par \par
Вот вроде и все пока... Вот вроде и все пока...
\sa \ref ControlProcessPage \sa \ref ControlProcessPage
......
<<<<<<< HEAD
/*! OBSOLETE DOC!!
\page CommitPage Общее описание библиотеки UniSet
- \ref secSection1
- \ref subIO
- Алгоритмы управления
- \ref UniSetGraphics
- \ref subInfoServer
- \ref UniDiag
- \ref subTimer
- \ref secSection2
- \ref subTransfer
- \ref subDBSave
- \ref secDetail
- \ref subObjects
- \ref subProcesses
- \ref secResourses
- \ref secDirStruct
\section secSection1 Назначение
Библиотека предназначена для разработки распределенных систем управления. В ней собраны основные компоненты из которых
строятся подобные системы (базовые интерфейсы для разработки процессов управления, процессов управления вводом/выводом,
менеджеров сообщений и т.п.). Любую систему управления можно поделить на относительно независимые объекты рещающие
следующие задачи:
- ввод/вывод (опрос физических датчиков, обмен с другими устройствами)
- алгоритмы управления тем или иным устройстов или группой устройств
- отображение информации (графический интерфейс пользователя)
- накопление и хранение информации
- просмотр накопленной информации
\par
Для каждой из задач в библиотеке разработан определенный компонент(группа компонентов).
И разработаны универсальные механизмы взаимдействия объектов между собой.
\section secSection2 Общие принципы работы
Библиотека позволяет объектам системы обмениватся сообщениями, а так же непосредственно вызывать функции друг-друга. В системе объектами
управляют менеджеры. Которые позволяют управлять (через этот) менеджер сразу набором подчиненных ему объектов. Менеджер может
содержать в себе в качестве подчиненного объекта другой менеджер, что позволяет строить довольно гибкую иерархическую структуру
управления. Всё взаимодейтсвие объектов( сетевое и межпроцессовое) строится на базе CORBA-ы.
\subsection subTransfer Взаимодействие объектов системы
Взаимодействие объектов между собой происходит через ObjectRepository. Каждый объект становится доступным другим объектам только
после регистрации в репозитории. Для получения доступа к другому объекту (даже удаленному) необхоимо знать его идентификатор(UniSetTypes::ObjectId)
и при помощи репозитория получить на него ссылку, с которой можно работать как с указателем на объект.
...
Каждый узел по возможности должен работать с максимальной автономностью. Т.е. все основные сервисы (TimerService, InfoServer, DBServer)
должны быть запущены локально. Минимизирован объем данных передаваемых между узлами системы.
\subsection subDBSave Система накопления информации
Хранение накопленной информации реализовано на основе БД. Для этого предусмотрен специальный процесс(сервис)
называемый DBServer, обладающий специальным интерфейсом, скрывающим детали работы с конкретной БД. Основная идея состоит
в том, что данный сервис запускается на каждом узле и все процессы, которым необходимо сохранять в БД информацию работают,
с всегда доступным локальным DBServer-ом. В свою очередь этот локальный DBServer при необходимости пересылает всю
информацию на другие узлы, на которых производится реальная запись в БД. Помимо это локальный DBServer может обеспечивать
буферизацию данных на время недоступности других узлов.
\sa \ref secDBServer
\subsection subInfoServer Система оповещения
Некоторым алгоритмам требуются сообщать о том или ином событии оператору. Для этой цели служит InfoServer.
Идея заключается в следующем: Все объекты, которым необходимо послать информацию, работают с локальным зараннее известным
объектом InfoServer. Все сообщения посылаются ему. В его задачи входит переслать это сообщение объекту отображающему
информацию на экране, а также переслать сообщение на другие узлы(в случае необходимости). Помимо этого InfoServer пересылает
сообщения DBServer-у для сохранения их в БД. То что этот объект является локальным, гарантирует, что он будет
доступен...
\sa \ref secInfoServer
\subsection subIO Ввод/вывод
Процессы ввода/вывода строятся на основе классов IOController и IONotifyController.
\par IOController
Это унифицированный интерфейс для сохранения и получения информации о состоянии дискретных и
аналоговых датчиков.
\par IONotifyController
Раширение IOController-а. Предоставляющее интерфейс для заказа уведомлений об изменении состояния датчиков.
\subsection subTimer Таймеры
В библиотеку включен компонент TimerService. Данный сервис реализует функции генератора переодический событий (таймеров).
TimeService предоставляет интерфейс для заказа уведомлений с заданной переодичностью.
\warning TimerService - НЕ является реализацией спецификации CORBA::TimerService.
\sa \ref secTimerService
\subsection UniSetGraphics Графический интерфейс пользователя
...
\subsection UniDiag Просмотр накопленной информации
Для большей универсальности слежение за работой системы, диагностирование и просмотр накопленной информации
сделаны в виде web-интерфейса написанного на PHP. \a в \a процессе \a разработаки...
\section secDetail Подробности
\subsection subObjects Объекты, Менеджеры, Активаторы
\par Объекты (UniSetObject)
Объекты являются пасивными единицами, так как не могут функционировать без менеджера или активатора. Для того, чтобы объект
мог принимать сообщения и предоставлять свои функции другим объектам он должен быть зарегистрирован в менеджере объектов
(ObjectsManager) или напрямую в активаторе (ObjectsActivator) при помощи функции ObjectsManager::addObject(...).
\par Менеджеры (ObjectsManager)
Менеджеры используются для управления сразу группой объектов, а также сами являются объектами и могут быть
зарегитстрированы в другом менеджере (или активаторе). Они тоже являются пасивными единицами, так как не могут функционировать без
активатора.
\par Активаторы (ObjectsActivator)
Активатор предназначен для активизации объектов и менеджеров. Он обладает свойствами менеджера (позволяет регистрировать в себе
другие объекты и менеджеры) и свойствами объекта (может быть зарегистрирован в другом активаторе или менеджере). Обычно для
запуска достаточно одного активатора.
\subsection subProcesses Процессы и потоки
Для активизации объектов должен быть создан хотя-бы один активатор. После вызова функции ObjectsActivator::run( thread ) он
активизирует свои подчиненные объекты. В зависимости от заданного параметра функции ObjectsActivator::run()
он создает поток (thread=true) или захватывает ресурсы основного потока откуда вызван (thread=false) для передачи его
ресурсов ORB (брокеру запросов). После чего все его подчиненные объекты активизируются и могут функционировать (принимать сообщения,
предоставлять свои функции для удаленного доступа). При этом orb может создавать несколько потоков.
\warning При уничтожении активатора, объекты (за которые он отвечает) становятся недоступными.
\par
Каждый объект после активизации порождает поток для обработки приходящих сообщений. После того как сообщение помещено в очередь
(функция UniSetObject::push() ) будится поток в котором происходит вызов UniSetObject::processingMessage() для обработки пришедшего сообщения.
Обработка сообщения и его помещение в очередь происходят в разных потоках, это позволяет помещать новые сообщения не дожидаясь завершения
обработки старого. На время помещения или извлечения сообщения из очереди, очередь блокируется.
\par
Менеджер, так как сам является объектом, может самостоятельно функционировать по своему алгоритму, принимать сообщения,
предоставлять свои функции для удаленного доступа.
\par
Если обобщить все выше сказанное то: в программе порождается поток для каждого объекта, и один для каждого активатора
(поток для "распихивания" приходящих сообщений по объектам). Хотя активатор может не порождать отдельного потока, а работать
в основном потоке программы. А также несколько потоков для orb.
\section secResourses Используемые библиотеки
- libmysqlclient, libtcpwrapGK - работа с MySQL
- linomniORB3(4) - реализация CORBA (удаленный доступ к объектам)
\section secDirStruct Структура каталогов
- \b /conf - общие конфигурационные файлы библиотеки UniSet
- \b /Documents - документация к библиотеке
- \b /IDL - декларации написанные на IDL
- \b /include - h-файлы
- \b /lib - библиотека \c libUniSet.a
- \b /src - сс-файлы
- \b /Tests - отладочные и тестовые программы
- \b /Utilities - вспомогательные утилиты входящие в состав UniSet
*/
...@@ -9,8 +9,10 @@ uniset-start.sh -f ./uniset-iocontrol --smemory-id SharedMemory \ ...@@ -9,8 +9,10 @@ uniset-start.sh -f ./uniset-iocontrol --smemory-id SharedMemory \
--io-polltime 100 \ --io-polltime 100 \
--io-s-filter-field io \ --io-s-filter-field io \
--io-s-filter-value 1 \ --io-s-filter-value 1 \
--io-numcards 2 \
--iodev1 /dev/null \
--iodev2 /dev/null \
--io-test-lamp Input1_S \ --io-test-lamp Input1_S \
--io-heartbeat-id AI_AS \ --io-heartbeat-id AI_AS \
--io-sm-ready-test-sid Input1_S \ --io-sm-ready-test-sid Input1_S \
--unideb-add-levels any --dlog-add-levels any --unideb-add-levels info,crit,warn,level9,system
...@@ -6,36 +6,13 @@ using namespace std; ...@@ -6,36 +6,13 @@ using namespace std;
using namespace UniSetTypes; using namespace UniSetTypes;
using namespace UniSetExtensions; using namespace UniSetExtensions;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
PassiveLProcessor::PassiveLProcessor( std::string lfile, UniSetTypes::ObjectId objId, PassiveLProcessor::PassiveLProcessor( std::string lfile, UniSetTypes::ObjectId objId,
UniSetTypes::ObjectId shmID, SharedMemory* ic, const std::string& prefix ): UniSetTypes::ObjectId shmID, SharedMemory* ic ):
UniSetObject_LT(objId), UniSetObject_LT(objId),
shm(0) shm(0)
{ {
logname = myname;
shm = new SMInterface(shmID,&(UniSetObject_LT::ui),objId,ic); shm = new SMInterface(shmID,&(UniSetObject_LT::ui),objId,ic);
build(lfile); build(lfile);
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix + "-heartbeat-id",""); // it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": ID not found ('HeartBeat') for " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = conf->getArgPInt("--" + prefix + "-heartbeat-time",conf->getHeartBeatTime());
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--" + prefix + "-heartbeat-max","10", 10);
}
} }
PassiveLProcessor::~PassiveLProcessor() PassiveLProcessor::~PassiveLProcessor()
...@@ -54,7 +31,7 @@ void PassiveLProcessor::step() ...@@ -54,7 +31,7 @@ void PassiveLProcessor::step()
dlog[Debug::CRIT] << myname dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl; << "(step): (hb) " << ex << std::endl;
} }
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() ) if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{ {
try try
...@@ -81,7 +58,7 @@ void PassiveLProcessor::askSensors( UniversalIO::UIOCommand cmd ) ...@@ -81,7 +58,7 @@ void PassiveLProcessor::askSensors( UniversalIO::UIOCommand cmd )
try try
{ {
for( EXTList::iterator it=extInputs.begin(); it!=extInputs.end(); ++it ) for( EXTList::iterator it=extInputs.begin(); it!=extInputs.end(); ++it )
shm->askSensor(it->sid,cmd); UniSetObject::ui.askState(it->sid,cmd);
} }
catch( Exception& ex ) catch( Exception& ex )
{ {
...@@ -111,14 +88,13 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm ) ...@@ -111,14 +88,13 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm )
{ {
case SystemMessage::StartUp: case SystemMessage::StartUp:
{ {
if( !shm->waitSMready(smReadyTimeout) ) if( !shm->waitSMready(10000) )
{ {
dlog[Debug::CRIT] << myname << "(ERR): SM not ready. Terminated... " << endl; cerr << "(ERR): SM not ready. Terminated... " << endl;
raise(SIGTERM); raise(SIGTERM);
return; return;
} }
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify); askSensors(UniversalIO::UIONotify);
askTimer(tidStep,LProcessor::sleepTime); askTimer(tidStep,LProcessor::sleepTime);
break; break;
...@@ -128,11 +104,11 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm ) ...@@ -128,11 +104,11 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm )
case SystemMessage::Finish: case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify); askSensors(UniversalIO::UIODontNotify);
break; break;
case SystemMessage::WatchDog: case SystemMessage::WatchDog:
{ {
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте) // ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа // Если идёт локальная работа
// (т.е. RTUExchange запущен в одном процессе с SharedMemory2) // (т.е. RTUExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM // то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(RTUExchange) // при заказе датчиков, а если SM вылетит, то вместе с этим процессом(RTUExchange)
...@@ -169,25 +145,6 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm ) ...@@ -169,25 +145,6 @@ void PassiveLProcessor::sysCommand( UniSetTypes::SystemMessage *sm )
} }
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
bool PassiveLProcessor::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
}
return true;
}
// ------------------------------------------------------------------------------------------
void PassiveLProcessor::initIterators()
{
shm->initAIterator(aitHeartBeat);
}
// -------------------------------------------------------------------------
void PassiveLProcessor::setOuts() void PassiveLProcessor::setOuts()
{ {
// выcтавляем выходы // выcтавляем выходы
...@@ -198,25 +155,25 @@ void PassiveLProcessor::setOuts() ...@@ -198,25 +155,25 @@ void PassiveLProcessor::setOuts()
switch(it->iotype) switch(it->iotype)
{ {
case UniversalIO::DigitalInput: case UniversalIO::DigitalInput:
shm->saveLocalState(it->sid,it->lnk->from->getOut(),it->iotype); UniSetObject::ui.saveState(it->sid,it->lnk->from->getOut(),it->iotype);
break; break;
case UniversalIO::DigitalOutput: case UniversalIO::DigitalOutput:
shm->setState(it->sid,it->lnk->from->getOut()); UniSetObject::ui.setState(it->sid,it->lnk->from->getOut());
break; break;
default: default:
dlog[Debug::CRIT] << myname << "(setOuts): неподдерживаемый тип iotype=" << it->iotype << endl; cerr << "(LProcessor::setOuts): неподдерживаемый тип iotype=" << it->iotype << endl;
break; break;
} }
} }
catch( Exception& ex ) catch( Exception& ex )
{ {
dlog[Debug::CRIT] << myname << "(setOuts): " << ex << endl; cerr << "(LProcessor::setOuts): " << ex << endl;
} }
catch(...) catch(...)
{ {
dlog[Debug::CRIT] << myname << "(setOuts): catch...\n"; cerr << "(LProcessor::setOuts): catch...\n";
} }
} }
} }
...@@ -230,25 +187,25 @@ void PassiveLProcessor::sigterm( int signo ) ...@@ -230,25 +187,25 @@ void PassiveLProcessor::sigterm( int signo )
switch(it->iotype) switch(it->iotype)
{ {
case UniversalIO::DigitalInput: case UniversalIO::DigitalInput:
shm->saveLocalState(it->sid,false,it->iotype); UniSetObject::ui.saveState(it->sid,false,it->iotype);
break; break;
case UniversalIO::DigitalOutput: case UniversalIO::DigitalOutput:
shm->setState(it->sid,false); UniSetObject::ui.setState(it->sid,false);
break; break;
default: default:
dlog[Debug::CRIT] << myname << "(sigterm): неподдерживаемый тип iotype=" << it->iotype << endl; cerr << "(LProcessor::sigterm): неподдерживаемый тип iotype=" << it->iotype << endl;
break; break;
} }
} }
catch( Exception& ex ) catch( Exception& ex )
{ {
dlog[Debug::CRIT] << myname << "(sigterm): " << ex << endl; cerr << "(LProcessor::sigterm): " << ex << endl;
} }
catch(...) catch(...)
{ {
dlog[Debug::CRIT] << myname << "(sigterm): catch...\n"; cerr << "(LProcessor::sigterm): catch...\n";
} }
} }
} }
...@@ -282,11 +239,11 @@ void PassiveLProcessor::processingMessage( UniSetTypes::VoidMessage* msg ) ...@@ -282,11 +239,11 @@ void PassiveLProcessor::processingMessage( UniSetTypes::VoidMessage* msg )
default: default:
break; break;
} }
} }
catch(Exception& ex) catch(Exception& ex)
{ {
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << endl; cout << myname << "(processingMessage): " << ex << endl;
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
#include <cmath>
#include <sstream>
#include <Exceptions.h>
#include <extensions/Extensions.h>
#include "MBTCPMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
MBTCPMaster::MBTCPMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId,
SharedMemory* ic, const std::string prefix ):
UniSetObject_LT(objId),
mb(0),
shm(0),
initPause(0),
force(false),
force_out(false),
mbregFromID(false),
activated(false),
noQueryOptimization(false),
force_disconnect(false),
allNotRespond(false),
prefix(prefix),
no_extimer(false),
poll_count(0)
{
// cout << "$ $" << endl;
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(MBTCPMaster): objId=-1?!! Use --" + prefix + "-name" );
// xmlNode* cnode = conf->getNode(myname);
string conf_name = conf->getArgParam("--" + prefix + "-confnode",myname);
cnode = conf->getNode(conf_name);
if( cnode == NULL )
throw UniSetTypes::SystemError("(MBTCPMaster): Not found node <" + conf_name + " ...> for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--" + prefix + "-filter-field");
s_fvalue = conf->getArgParam("--" + prefix + "-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
stat_time = conf->getArgPInt("--" + prefix + "-statistic-sec",it.getProp("statistic_sec"),0);
if( stat_time > 0 )
ptStatistic.setTiming(stat_time*1000);
// ---------- init MBTCP ----------
string pname("--" + prefix + "-gateway-iaddr");
iaddr = conf->getArgParam(pname,it.getProp("gateway_iaddr"));
if( iaddr.empty() )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet addr...(Use: " + pname +")" );
string tmp("--" + prefix + "-gateway-port");
port = conf->getArgInt(tmp,it.getProp("gateway_port"));
if( port <= 0 )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet port...(Use: " + tmp +")" );
recv_timeout = conf->getArgPInt("--" + prefix + "-recv-timeout",it.getProp("recv_timeout"), 50);
int alltout = conf->getArgPInt("--" + prefix + "-all-timeout",it.getProp("all_timeout"), 2000);
ptAllNotRespond.setTiming(alltout);
noQueryOptimization = conf->getArgInt("--" + prefix + "-no-query-optimization",it.getProp("no_query_optimization"));
mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id",it.getProp("reg_from_id"));
dlog[Debug::INFO] << myname << "(init): mbregFromID=" << mbregFromID << endl;
polltime = conf->getArgPInt("--" + prefix + "-polltime",it.getProp("polltime"), 100);
initPause = conf->getArgPInt("--" + prefix + "-initPause",it.getProp("initPause"), 3000);
force = conf->getArgInt("--" + prefix + "-force",it.getProp("force"));
force_out = conf->getArgInt("--" + prefix + "-force-out",it.getProp("force_out"));
force_disconnect = conf->getArgInt("--" + prefix + "-force-disconnect",it.getProp("force_disconnect"));
if( shm->isLocalwork() )
{
readConfiguration();
rtuQueryOptimization(rmap);
initDeviceList();
}
else
ic->addReadItem( sigc::mem_fun(this,&MBTCPMaster::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix + "-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": ID not found ('HeartBeat') for " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--" + prefix + "-heartbeat-max",it.getProp("heartbeat_max"), 10);
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = conf->getArgPInt("--" + prefix + "-activate-timeout", 20000);
// initMB(false);
printMap(rmap);
// abort();
poll_count = -1;
}
// -----------------------------------------------------------------------------
MBTCPMaster::~MBTCPMaster()
{
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
delete it->second;
delete it1->second;
}
delete mb;
delete shm;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::initMB( bool reopen )
{
if( mb )
{
if( !reopen )
return;
delete mb;
mb = 0;
}
try
{
ost::Thread::setException(ost::Thread::throwException);
mb = new ModbusTCPMaster();
ost::InetAddress ia(iaddr.c_str());
mb->connect(ia,port);
mb->setForceDisconnect(force_disconnect);
if( recv_timeout > 0 )
mb->setTimeout(recv_timeout);
dlog[Debug::INFO] << myname << "(init): ipaddr=" << iaddr << " port=" << port << endl;
if( dlog.debugging(Debug::LEVEL9) )
mb->setLog(dlog);
}
catch( ModbusRTU::mbException& ex )
{
cerr << "(init): " << ex << endl;
}
catch(...)
{
if( mb )
delete mb;
mb = 0;
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--mbm-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout, 50) )
{
ostringstream err;
err << myname << "(waitSMReady): failed waiting SharedMemory " << ready_timeout << " msec";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
{
if( no_extimer )
askTimer(tm->id,0);
else
step();
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::step()
{
{
uniset_mutex_lock l(pollMutex,2000);
poll();
}
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::poll()
{
if( trAllNotRespond.hi(allNotRespond) )
ptAllNotRespond.reset();
if( allNotRespond && mb && ptAllNotRespond.checkTime() )
{
ptAllNotRespond.reset();
// initMB(true);
}
if( !mb )
{
initMB(false);
if( !mb )
{
for( MBTCPMaster::RTUDeviceMap::iterator it=rmap.begin(); it!=rmap.end(); ++it )
it->second->resp_real = false;
}
updateSM();
return;
}
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype==MBTCPMaster::dtRTU || d->dtype==MBTCPMaster::dtMTR )
{
if( pollRTU(d,it) )
d->resp_real = true;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; print_plist(dlog(Debug::LEVEL3),it->second->slst);
dlog(Debug::LEVEL3) << " err: " << ex << endl;
}
// }
// d->resp_real = false;
if( !d->ask_every_reg )
break;
}
if( it==d->regmap.end() )
break;
}
if( stat_time > 0 )
{
poll_count++;
if( ptStatistic.checkTime() )
{
cout << endl << "(poll statistic): number of calls is " << poll_count << " (poll time: " << stat_time << " sec)" << endl << endl;
ptStatistic.reset();
poll_count=0;
}
}
// mb->disconnect();
}
// update SharedMemory...
updateSM();
// check thresholds
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
RegInfo* r(it->second);
for( PList::iterator i=r->slst.begin(); i!=r->slst.end(); ++i )
IOBase::processingThreshold( &(*i),shm,force);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mboffset=" << p->offset
<< " mbfunc=" << p->mbfunc
<< " q_count=" << p->q_count
<< " mb_init=" << p->mb_init
<< endl;
if( p->q_count > ModbusRTU::MAXDATALEN )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
if( p->q_count == 0 )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(pollRTU): q_count=0 for mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE register..." << endl;
return false;
}
switch( p->mbfunc )
{
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(dev->mbaddr,p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr, p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadInputStatus:
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m=0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k];
}
it--;
}
break;
case ModbusRTU::fnReadCoilStatus:
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m = 0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k] ? 1 : 0;
}
it--;
}
break;
case ModbusRTU::fnWriteOutputSingleRegister:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE WRITE SINGLE REGISTER (0x06) q_count=" << p->q_count << " ..." << endl;
return false;
}
if( !p->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(p->mbreg) << endl;
ModbusRTU::ReadInputRetMessage ret1 = mb->read04(dev->mbaddr,p->mb_init_mbreg,1);
p->mbval = ret1.data[0];
p->sm_init = true;
return true;
}
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnWriteOutputRegisters:
{
ModbusRTU::WriteOutputMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
{
if( !it->second->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(it->second->mbreg)
// << " mb_init mbreg=" << ModbusRTU::dat2str(it->second->mb_init_mbreg) << endl;
ModbusRTU::ReadOutputRetMessage ret1 = mb->read03(dev->mbaddr,it->second->mb_init_mbreg,1);
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(it->second->mbreg)
// << " mb_init mbreg=" << ModbusRTU::dat2str(it->second->mb_init_mbreg)
// << " mbval=" << ret1.data[0] << endl;
it->second->mbval = ret1.data[0];
it->second->sm_init = true;
}
msg.addData(it->second->mbval);
}
it--;
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
}
break;
case ModbusRTU::fnForceSingleCoil:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE FORCE SINGLE COIL (0x05) q_count=" << p->q_count << " ..." << endl;
return false;
}
if( !p->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(p->mbreg)
// << " init mbreg=" << ModbusRTU::dat2str(p->mb_init_mbreg) << endl;
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,p->mb_init_mbreg,1);
ModbusRTU::DataBits b(ret1.data[0]);
// cerr << "******* mb_init_mbreg=" << ModbusRTU::dat2str(p->mb_init_mbreg)
// << " read val=" << (int)b[0] << endl;
p->mbval = b[0];
p->sm_init = true;
return true;
}
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnForceMultipleCoils:
{
if( !p->mb_init )
{
// every register ask... (for mb_init_mbreg no some)
for( int i=0; i<p->q_count; i++,it++ )
{
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,it->second->mb_init_mbreg,1);
ModbusRTU::DataBits b(ret1.data[0]);
it->second->mbval = b[0] ? 1 : 0;
it->second->sm_init = true;
}
/*
// alone query for all register (if mb_init_mbreg ++ )
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,p->mb_init_mbreg,p->q_count);
int m=0;
for( int i=0; i<ret1.bcnt; i++ )
{
ModbusRTU::DataBits b(ret1.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
{
it->second->mbval = b[k] ? 1 : 0;
it->second->sm_init = true;
}
}
*/
p->sm_init = true;
it--;
return true;
}
ModbusRTU::ForceCoilsMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
msg.addBit( (it->second->mbval ? true : false) );
it--;
// cerr << "*********** (write multiple): " << msg << endl;
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
}
break;
default:
{
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE mfunc=" << (int)p->mbfunc << " ..." << endl;
return false;
}
break;
}
return true;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::RTUDevice::checkRespond()
{
bool prev = resp_state;
if( resp_trTimeout.hi(resp_real) )
{
if( resp_real )
resp_state = true;
resp_ptTimeout.reset();
}
if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if( !resp_init )
{
resp_state = resp_real;
resp_init = true;
prev = resp_state;
return true;
}
return ( prev != resp_state );
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateSM()
{
allNotRespond = true;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( dlog.debugging(Debug::LEVEL4) )
{
dlog[Debug::LEVEL4] << "check respond addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " respond=" << d->resp_id
<< " real=" << d->resp_real
<< " state=" << d->resp_state
<< endl;
}
if( d->resp_real )
allNotRespond = false;
// update respond sensors...
if( d->checkRespond() && d->resp_id != DefaultObjectId )
{
try
{
bool set = d->resp_invert ? !d->resp_state : d->resp_state;
shm->localSaveState(d->resp_dit,d->resp_id,set,getId());
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (respond) " << ex << std::endl;
}
}
// cerr << "*********** allNotRespond=" << allNotRespond << endl;
// update values...
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype == dtRTU )
updateRTU(it);
else if( d->dtype == dtMTR )
updateMTR(it);
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): catch ..." << endl;
}
if( it==d->regmap.end() )
break;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
if( rmap.empty() )
{
dlog[Debug::CRIT] << myname << "(sysCommand): ************* ITEM MAP EMPTY! terminated... *************" << endl;
raise(SIGTERM);
return;
}
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(sysCommand): device map size= " << rmap.size() << endl;
if( !shm->isLocalwork() )
initDeviceList();
waitSMReady();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
initOutput();
}
// начальная инициализация
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
askTimer(tmExchange,polltime);
break;
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. MBTCPMaster запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBTCPMaster)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
initOutput();
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
}
break;
case SystemMessage::LogRotate:
{
// переоткрываем логи
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::initOutput()
{
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str());
}
if( force_out )
return;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
try
{
shm->askSensor(i->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): catch..." << std::endl;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
if( sm->id == i->si.id && sm->node == i->si.node )
{
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname<< "(sensorInfo): si.id=" << sm->id
<< " reg=" << ModbusRTU::dat2str(i->reg->mbreg)
<< " val=" << sm->value
<< " mb_init=" << i->reg->mb_init << endl;
}
if( !i->reg->mb_init )
continue;
i->value = sm->value;
updateRSProperty( &(*i),true);
return;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(rmap);
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
/*! \todo Доделать выставление безопасного состояния на выходы.
И нужно ли это. Ведь может не хватить времени на "обмен"
*/
// выставление безопасного состояния на выходы....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
if( it->safety == NoSafetyState )
continue;
try
{
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
catch(...){}
}
*/
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::readConfiguration()
{
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// просто проверка на не пустой field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// просто проверка что field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RTUDevice* MBTCPMaster::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML_iterator& xmlit )
{
RTUDeviceMap::iterator it = mp.find(a);
if( it != mp.end() )
{
DeviceType dtype = getDeviceType(xmlit.getProp("tcp_mbtype"));
if( it->second->dtype != dtype )
{
dlog[Debug::CRIT] << myname << "(addDev): OTHER mbtype=" << dtype << " for " << xmlit.getProp("name")
<< ". Already used devtype=" << it->second->dtype
<< " for mbaddr=" << ModbusRTU::addr2str(it->second->mbaddr)
<< endl;
return 0;
}
dlog[Debug::INFO] << myname << "(addDev): device for addr=" << ModbusRTU::addr2str(a)
<< " already added. Ignore device params for " << xmlit.getProp("name") << " ..." << endl;
return it->second;
}
MBTCPMaster::RTUDevice* d = new MBTCPMaster::RTUDevice();
d->mbaddr = a;
if( !initRTUDevice(d,xmlit) )
{
delete d;
return 0;
}
mp.insert(RTUDeviceMap::value_type(a,d));
return d;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RegInfo* MBTCPMaster::addReg( RegMap& mp, ModbusRTU::ModbusData r,
UniXML_iterator& xmlit, MBTCPMaster::RTUDevice* dev,
MBTCPMaster::RegInfo* rcopy )
{
RegMap::iterator it = mp.find(r);
if( it != mp.end() )
{
if( !it->second->dev )
{
dlog[Debug::CRIT] << myname << "(addReg): for reg=" << ModbusRTU::dat2str(r)
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
dlog[Debug::CRIT] << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for reg=" << ModbusRTU::dat2str(r)
<< ". Already used devtype=" << it->second->dev->dtype << " for " << it->second->dev << endl;
return 0;
}
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname << "(addReg): reg=" << ModbusRTU::dat2str(r)
<< " already added. Ignore register params for " << xmlit.getProp("name") << " ..." << endl;
}
it->second->rit = it;
return it->second;
}
MBTCPMaster::RegInfo* ri;
if( rcopy )
{
ri = new MBTCPMaster::RegInfo(*rcopy);
ri->slst.clear();
ri->mbreg = r;
}
else
{
ri = new MBTCPMaster::RegInfo();
if( !initRegInfo(ri,xmlit,dev) )
{
delete ri;
return 0;
}
ri->mbreg = r;
}
mp.insert(RegMap::value_type(r,ri));
ri->rit = mp.find(r);
return ri;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RSProperty* MBTCPMaster::addProp( PList& plist, RSProperty& p )
{
for( PList::iterator it=plist.begin(); it!=plist.end(); ++it )
{
if( it->si.id == p.si.id && it->si.node == p.si.node )
return &(*it);
}
plist.push_back(p);
PList::iterator it = plist.end();
it--;
return &(*it);
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRSProperty( RSProperty& p, UniXML_iterator& it )
{
if( !IOBase::initItem(&p,it,shm,&dlog,myname) )
return false;
if( it.getIntProp("tcp_rawdata") )
{
p.cal.minRaw = 0;
p.cal.maxRaw = 0;
p.cal.minCal = 0;
p.cal.maxCal = 0;
p.cal.precision = 0;
p.cdiagram = 0;
}
string stype( it.getProp("tcp_iotype") );
if( !stype.empty() )
{
p.stype = UniSetTypes::getIOType(stype);
if( p.stype == UniversalIO::UnknownIOType )
{
if( dlog )
dlog[Debug::CRIT] << myname << "(IOBase::readItem): неизвестный iotype=: "
<< stype << " for " << it.getProp("name") << endl;
return false;
}
}
string sbit(it.getProp("tcp_nbit"));
if( !sbit.empty() )
{
p.nbit = UniSetTypes::uni_atoi(sbit.c_str());
if( p.nbit < 0 || p.nbit >= ModbusRTU::BitsPerData )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbit=" << p.nbit
<< ". (0 >= nbit < " << ModbusRTU::BitsPerData <<")." << endl;
return false;
}
}
if( p.nbit > 0 &&
( p.stype == UniversalIO::AnalogInput ||
p.stype == UniversalIO::AnalogOutput ) )
{
dlog[Debug::WARN] << "(initRSProperty): (ignore) uncorrect param`s nbit>1 (" << p.nbit << ")"
<< " but iotype=" << p.stype << " for " << it.getProp("name") << endl;
}
string sbyte(it.getProp("tcp_nbyte"));
if( !sbyte.empty() )
{
p.nbyte = UniSetTypes::uni_atoi(sbyte.c_str());
if( p.nbyte < 0 || p.nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbyte=" << p.nbyte
<< ". (0 >= nbyte < " << VTypes::Byte::bsize << ")." << endl;
return false;
}
}
string vt(it.getProp("tcp_vtype"));
if( vt.empty() )
{
p.rnum = VTypes::wsize(VTypes::vtUnknown);
p.vType = VTypes::vtUnknown;
}
else
{
VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): Unknown rtuVType=" << vt << " for "
<< it.getProp("name")
<< endl;
return false;
}
p.vType = v;
p.rnum = VTypes::wsize(v);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRegInfo( RegInfo* r, UniXML_iterator& it, MBTCPMaster::RTUDevice* dev )
{
r->dev = dev;
r->mbval = it.getIntProp("default");
r->offset = it.getIntProp("tcp_mboffset");
r->mb_init = it.getIntProp("tcp_mbinit");
if( dev->dtype == MBTCPMaster::dtRTU )
{
// dlog[Debug::INFO] << myname << "(initRegInfo): init RTU.."
}
else if( dev->dtype == MBTCPMaster::dtMTR )
{
// only for MTR
if( !initMTRitem(it,r) )
return false;
}
else
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbtype='" << dev->dtype
<< "' for " << it.getProp("name") << endl;
return false;
}
if( mbregFromID )
{
if( it.getProp("id").empty() )
r->mbreg = conf->getSensorID(it.getProp("name"));
else
r->mbreg = it.getIntProp("id");
}
else
{
string sr = it.getProp("tcp_mbreg");
if( sr.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl;
return false;
}
r->mbreg = ModbusRTU::str2mbData(sr);
}
{
string sr = it.getProp("tcp_init_mbreg");
if( sr == "-1" )
{
r->mb_init = true; // OFF mb_init
r->sm_init = true;
}
else if( sr.empty() )
r->mb_init_mbreg = r->mbreg;
else
r->mb_init_mbreg = ModbusRTU::str2mbData(sr);
}
r->mbfunc = ModbusRTU::fnUnknown;
string f = it.getProp("tcp_mbfunc");
if( !f.empty() )
{
r->mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(f.c_str());
if( r->mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbfunc ='" << f
<< "' for " << it.getProp("name") << endl;
return false;
}
}
return true;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::DeviceType MBTCPMaster::getDeviceType( const std::string dtype )
{
if( dtype.empty() )
return dtUnknown;
if( dtype == "mtr" || dtype == "MTR" )
return dtMTR;
if( dtype == "rtu" || dtype == "RTU" )
return dtRTU;
return dtUnknown;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRTUDevice( RTUDevice* d, UniXML_iterator& it )
{
d->dtype = getDeviceType(it.getProp("tcp_mbtype"));
if( d->dtype == dtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown tcp_mbtype=" << it.getProp("tcp_mbtype")
<< ". Use: rtu "
<< " for " << it.getProp("name") << endl;
return false;
}
string addr = it.getProp("tcp_mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown mbaddr for " << it.getProp("name") << endl;
return false;
}
d->mbaddr = ModbusRTU::str2mbAddr(addr);
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initItem( UniXML_iterator& it )
{
RSProperty p;
if( !initRSProperty(p,it) )
return false;
string addr = it.getProp("tcp_mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown mbaddr='" << addr << " for " << it.getProp("name") << endl;
return false;
}
ModbusRTU::ModbusAddr mbaddr = ModbusRTU::str2mbAddr(addr);
RTUDevice* dev = addDev(rmap,mbaddr,it);
if( !dev )
{
dlog[Debug::CRIT] << myname << "(initItem): " << it.getProp("name") << " CAN`T ADD for polling!" << endl;
return false;
}
ModbusRTU::ModbusData mbreg;
if( mbregFromID )
mbreg = p.si.id; // conf->getSensorID(it.getProp("name"));
else
{
string reg = it.getProp("tcp_mbreg");
if( reg.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
RegInfo* ri = addReg(dev->regmap,mbreg,it,dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown word size for " << it.getProp("name") << endl;
return false;
}
}
if( !ri )
return false;
ri->dev = dev;
// п÷п═п·п▓п•п═п п░!
// п╣я│п╩п╦ я└я┐п╫п╨я├п╦я▐ п╫п╟ п╥п╟п©п╦я│я▄, я┌п╬ п╫п╟п╢п╬ п©я─п╬п╡п╣я─п╦я┌я▄
// я┤я┌п╬ п╬п╢п╦п╫ п╦ я┌п╬я┌п╤п╣ я─п╣пЁп╦я│я┌я─ п╫п╣ п©п╣я─п╣п╥п╟п©п╦я┬я┐я┌ п╫п╣я│п╨п╬п╩я▄п╨п╬ п╢п╟я┌я┤п╦п╨п╬п╡
// я█я┌п╬ п╡п╬п╥п╪п╬п╤п╫п╬ я┌п╬п╩я▄п╨п╬, п╣я│п╩п╦ п╬п╫п╦ п©п╦я┬я┐я┌ п╠п╦я┌я▀!!
// п≤п╒п·п⌠:
// п•я│п╩п╦ п╢п╩я▐ я└я┐п╫п╨я├п╦п╧ п╥п╟п©п╦я│п╦ я│п©п╦я│п╬п╨ п╢п╟я┌я┤п╦п╨п╬п╡ п╫п╟ п╬п╢п╦п╫ я─п╣пЁп╦я│я┌я─ > 1
// п╥п╫п╟я┤п╦я┌ п╡ я│п©п╦я│п╨п╣ п╪п╬пЁя┐я┌ п╠я▀я┌я▄ я┌п╬п╩я▄п╨п╬ п╠п╦я┌п╬п╡я▀п╣ п╢п╟я┌я┤п╦п╨п╦
// п╦ п╣я│п╩п╦ п╦п╢я▒я┌ п©п╬п©я▀я┌п╨п╟ п╡п╫п╣я│я┌п╦ п╡ я│п©п╦я│п╬п╨ п╫п╣ п╠п╦я┌п╬п╡я▀п╧ п╢п╟я┌я┤п╦п╨ я┌п╬ п·п╗п≤п▒п п░!
// п≤ п╫п╟п╬п╠п╬я─п╬я┌: п╣я│п╩п╦ п╦п╢я▒я┌ п©п╬п©я▀я┌п╨п╟ п╡п╫п╣я│я┌п╦ п╠п╦я┌п╬п╡я▀п╧ п╢п╟я┌я┤п╦п╨, п╟ п╡ я│п©п╦я│п╨п╣
// я┐п╤п╣ я│п╦п╢п╦я┌ п╢п╟я┌я┤п╦п╨ п╥п╟п╫п╦п╪п╟я▌я┴п╦п╧ я├п╣п╩я▀п╧ я─п╣пЁп╦я│я┌я─, я┌п╬ я┌п╬п╤п╣ п·п╗п≤п▒п п░!
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
if( p.nbit<0 && ri->slst.size() > 1 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (not bit saving) to "
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
if( p.nbit >= 0 && ri->slst.size() == 1 )
{
PList::iterator it2 = ri->slst.begin();
if( it2->nbit < 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (mbreg="
<< ModbusRTU::dat2str(ri->mbreg) << " already used)!"
<< " IGNORE --> " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
}
}
RSProperty* p1 = addProp(ri->slst,p);
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
for( int i=1; i<p1->rnum; i++ )
{
MBTCPMaster::RegInfo* ri1 = addReg(dev->regmap,mbreg+i,it,dev,ri);
ri1->mb_init_mbreg = ri->mb_init_mbreg+i;
}
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initMTRitem( UniXML_iterator& it, RegInfo* p )
{
p->mtrType = MTR::str2type(it.getProp("mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
dlog[Debug::CRIT] << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp("mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::initIterators()
{
shm->initAIterator(aitHeartBeat);
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
shm->initDIterator(d->resp_dit);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
for( PList::iterator it2=it->second->slst.begin();it2!=it->second->slst.end(); ++it2 )
{
shm->initDIterator(it2->dit);
shm->initAIterator(it2->ait);
}
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::help_print( int argc, const char* const* argv )
{
cout << "--mbm-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек." << endl;
cout << "--mbm-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--mbm-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--mbm-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--mbm-force - Сохранять значения в SM, независимо от, того менялось ли значение" << endl;
cout << "--mbm-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
// cout << "--mbm-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола TCP: " << endl;
cout << "--mbm-recv-timeout - Таймаут на ожидание ответа." << endl;
}
// -----------------------------------------------------------------------------
MBTCPMaster* MBTCPMaster::init_mbmaster( int argc, const char* const* argv, UniSetTypes::ObjectId icID, SharedMemory* ic,
const std::string prefix )
{
string name = conf->getArgParam("--" + prefix + "-name","MBTCPMaster1");
if( name.empty() )
{
cerr << "(MBTCPMaster): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(MBTCPMaster): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(MBTCPMaster): name = " << name << "(" << ID << ")" << endl;
return new MBTCPMaster(ID,icID,ic,prefix);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBTCPMaster::DeviceType& dt )
{
switch(dt)
{
case MBTCPMaster::dtRTU:
os << "RTU";
break;
case MBTCPMaster::dtMTR:
os << "MTR";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBTCPMaster::RSProperty& p )
{
os << " (" << ModbusRTU::dat2str(p.reg->mbreg) << ")"
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " nbit=" << p.nbit
<< " nbyte=" << p.nbyte
<< " rnum=" << p.rnum
<< " safety=" << p.safety
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AnalogInput || p.stype == UniversalIO::AnalogOutput )
{
os << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::initDeviceList()
{
xmlNode* respNode = conf->findNode(cnode,"DeviceList");
if( respNode )
{
UniXML_iterator it1(respNode);
if( it1.goChildren() )
{
for(;it1.getCurrent(); it1.goNext() )
{
ModbusRTU::ModbusAddr a = ModbusRTU::str2mbAddr(it1.getProp("addr"));
initDeviceInfo(rmap,a,it1);
}
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> empty section..." << endl;
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> not found..." << endl;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it )
{
RTUDeviceMap::iterator d = m.find(a);
if( d == m.end() )
{
dlog[Debug::WARN] << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
d->second->ask_every_reg = it.getIntProp("ask_every_reg");
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a)
<< " ask_every_reg=" << d->second->ask_every_reg << endl;
string s(it.getProp("respondSensor"));
if( !s.empty() )
{
d->second->resp_id = conf->getSensorID(s);
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << s << endl;
return false;
}
}
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout", UniSetTimer::WaitUpTime);
d->second->resp_ptTimeout.setTiming(tout);
d->second->resp_invert = it.getIntProp("invert");
// d->second->no_clean_input = it.getIntProp("no_clean_input");
// dlog[Debug::INFO] << myname << "(initDeviceInfo): add " << d->second << endl;
return true;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::printMap( MBTCPMaster::RTUDeviceMap& m )
{
cout << "devices: " << endl;
for( MBTCPMaster::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
cout << " " << *(it->second) << endl;
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( MBTCPMaster::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
os << " " << *(it->second) << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RTUDevice& d )
{
os << "addr=" << ModbusRTU::addr2str(d.mbaddr)
<< " type=" << d.dtype
<< " respond_id=" << d.resp_id
<< " respond_timeout=" << d.resp_ptTimeout.getInterval()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< endl;
os << " regs: " << endl;
for( MBTCPMaster::RegMap::iterator it=d.regmap.begin(); it!=d.regmap.end(); ++it )
os << " " << *(it->second) << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RegInfo& r )
{
os << " mbreg=" << ModbusRTU::dat2str(r.mbreg)
<< " mbfunc=" << r.mbfunc
<< " q_num=" << r.q_num
<< " q_count=" << r.q_count
<< " value=" << ModbusRTU::dat2str(r.mbval) << "(" << (int)r.mbval << ")"
<< " mtrType=" << MTR::type2str(r.mtrType)
<< endl;
for( MBTCPMaster::PList::iterator it=r.slst.begin(); it!=r.slst.end(); ++it )
os << " " << (*it) << endl;
return os;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::rtuQueryOptimization( RTUDeviceMap& m )
{
if( noQueryOptimization )
return;
dlog[Debug::INFO] << myname << "(rtuQueryOptimization): optimization..." << endl;
for( MBTCPMaster::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
MBTCPMaster::RegMap::iterator beg = it;
ModbusRTU::ModbusData reg = it->second->mbreg + it->second->offset;
beg->second->q_num = 1;
beg->second->q_count = 1;
it++;
for( ;it!=d->regmap.end(); ++it )
{
if( (it->second->mbreg + it->second->offset - reg) > 1 )
break;
if( beg->second->mbfunc != it->second->mbfunc )
break;
beg->second->q_count++;
if( beg->second->q_count >= ModbusRTU::MAXDATALEN )
break;
reg = it->second->mbreg + it->second->offset;
it->second->q_num = beg->second->q_count;
it->second->q_count = 0;
}
// check correct function...
if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnWriteOutputSingleRegister )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnWriteOutputSingleRegister
<< " <--> func=" << ModbusRTU::fnWriteOutputRegisters
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnForceSingleCoil )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnForceSingleCoil
<< " <--> func=" << ModbusRTU::fnForceMultipleCoils
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnForceMultipleCoils;
}
if( it==d->regmap.end() )
break;
it--;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateRTU( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
updateRSProperty( &(*it),false );
if( r->sm_init )
r->mb_init = true;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateRSProperty( RSProperty* p, bool write_only )
{
using namespace ModbusRTU;
RegInfo* r(p->reg->rit->second);
bool save = isWriteFunction( r->mbfunc );
if( !save && write_only )
return;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "updateP: sid=" << p->si.id
<< " mbval=" << r->mbval
<< " vtype=" << p->vType
<< " rnum=" << p->rnum
<< " nbit=" << p->nbit
<< " save=" << save
<< " ioype=" << p->stype
<< " mb_init=" << r->mb_init
<< endl;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(r->mbval);
if( p->nbit >= 0 )
{
if( save && r->mb_init )
{
bool set = IOBase::processingAsDO( p, shm, force_out );
b.set(p->nbit,set);
r->mbval = b.mdata();
}
else
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
}
return;
}
if( p->rnum <= 1 )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(r->mbval), shm, force );
}
return;
}
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: rnum=" << p->rnum
<< " > 1 ?!! for id=" << p->si.id << endl;
return;
}
else if( p->vType == VTypes::vtSigned )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (signed short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (signed short)IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (signed short)(r->mbval), shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (unsigned short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (unsigned short)IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (unsigned short)r->mbval, shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtByte )
{
if( p->nbyte <= 0 || p->nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: reg=" << ModbusRTU::dat2str(r->mbreg)
<< " vtype=" << p->vType << " but nbyte=" << p->nbyte << endl;
return;
}
if( save && r->mb_init )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::Byte b(r->mbval);
b.raw.b[p->nbyte-1] = v;
r->mbval = b.raw.w;
}
else
{
VTypes::Byte b(r->mbval);
IOBase::processingAsAI( p, b.raw.b[p->nbyte-1], shm, force );
}
return;
}
else if( p->vType == VTypes::vtF2 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F2 f2(f);
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
i->second->mbval = f2.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F2::wsize()];
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F2 f(data,VTypes::F2::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
else if( p->vType == VTypes::vtF4 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F4 f4(f);
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
i->second->mbval = f4.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F4::wsize()];
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F4 f(data,VTypes::F4::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
else if( p->vType == VTypes::vtI2 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::I2 i2(v);
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
i->second->mbval = i2.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::I2::wsize()];
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::I2 i2(data,VTypes::I2::wsize());
delete[] data;
IOBase::processingAsAI( p, (int)i2, shm, force );
}
}
else if( p->vType == VTypes::vtU2 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::U2 u2(v);
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
i->second->mbval = u2.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::U2::wsize()];
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::U2 u2(data,VTypes::U2::wsize());
delete[] data;
IOBase::processingAsAI( p, (unsigned int)u2, shm, force );
}
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): catch ..." << endl;
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateMTR( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
{
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
{
try
{
if( r->mtrType == MTR::mtT1 )
{
if( save )
r->mbval = IOBase::processingAsAO( &(*it), shm, force_out );
else
{
MTR::T1 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT2 )
{
if( save )
{
MTR::T2 t(IOBase::processingAsAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T2 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT3 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T3 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T3::wsize()];
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T3 t(data,MTR::T3::wsize());
delete[] data;
IOBase::processingAsAI( &(*it), (long)t, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT4 )
{
if( save )
cerr << myname << "(updateMTR): write (T4) reg(" << dat2str(r->mbreg) << ") to MTR NOT YET!!!" << endl;
else
{
MTR::T4 t(r->mbval);
IOBase::processingAsAI( &(*it), uni_atoi(t.sval), shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT5 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T5 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T5::wsize()];
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T5 t(data,MTR::T5::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT6 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T6 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T6::wsize()];
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T6 t(data,MTR::T6::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT7 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T7 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T7::wsize()];
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T7 t(data,MTR::T7::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT16 )
{
if( save )
{
MTR::T16 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T16 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT17 )
{
if( save )
{
MTR::T17 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T17 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtF1 )
{
RegMap::iterator i(rit);
if( save )
{
float f = IOBase::processingFasAO( &(*it), shm, force_out );
MTR::F1 f1(f);
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
i->second->mbval = f1.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::F1::wsize()];
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::F1 t(data,MTR::F1::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t, shm, force );
}
continue;
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): catch ..." << endl;
}
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::execute()
{
no_extimer = true;
try
{
askTimer(tmExchange,0);
}
catch(...){}
initMB(false);
while(1)
{
try
{
step();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(execute): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(execute): catch ..." << endl;
}
msleep(polltime);
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBTCPMaster::PList& lst )
std::ostream& MBTCPMaster::print_plist( std::ostream& os, MBTCPMaster::PList& lst )
{
os << "[ ";
for( MBTCPMaster::PList::const_iterator it=lst.begin(); it!=lst.end(); ++it )
os << "(" << it->si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(it->si.id)) << " ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
\ No newline at end of file
#ifndef _MBTCPMaster_H_
#define _MBTCPMaster_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <map>
#include <vector>
#include "IONotifyController.h"
#include "UniSetObject_LT.h"
#include "modbus/ModbusTCPMaster.h"
#include "PassiveTimer.h"
#include "Trigger.h"
#include "Mutex.h"
#include "Calibration.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "IOBase.h"
#include "VTypes.h"
#include "MTR.h"
// -----------------------------------------------------------------------------
/*!
\page page_ModbusTCP Реализация ModbusTCP master
- \ref sec_MBTCP_Comm
- \ref sec_MBTCP_Conf
- \ref sec_MBTCP_ConfList
\section sec_MBTCP_Comm Общее описание ModbusTCP master
Класс реализует процесс обмена (опрос/запись) с RTU-устройствами,
через TCP-шлюз. Список регистров с которыми работает процесс задаётся в конфигурационном файле
в секции \b <sensors>. см. \ref sec_MBTCP_Conf
\section sec_MBTCP_Conf Конфигурирование ModbusTCP master
Конфигурирование процесса осуществляется либо параметрами командной строки либо
через настроечную секцию.
\par Секция с настройками
При своём старте, в конфигурационном файле ищётся секция с названием объекта,
в которой указываются настроечные параметры по умолчанию.
Пример:
\code
<MBMaster1 name="MBMaster1" gateway_iaddr="127.0.0.1" gateway_port="30000" polltime="200">
<DeviceList>
<item addr="0x01" respondSensor="RTU1_Not_Respond_FS" timeout="2000" invert="1"/>
<item addr="0x02" respondSensor="RTU2_Respond_FS" timeout="2000" invert="0"/>
</DeviceList>
</MBMaster1>
\endcode
Секция <DeviceList> позволяет задать параметры обмена с конкретным RTU-устройством.
- \b addr - адрес устройства для которого, задаются параметры
- \b timeout msec - таймаут, для определения отсутствия связи
- \b invert - инвертировать логику. По умолчанию датчик выставляется в "1" при \b наличии связи.
- \b respondSensor - идентификатор датчика связи.
\par Параметры запуска
При создании объекта в конструкторе передаётся префикс для определения параметров командной строки.
По умолчанию \b xxx="mbtcp".
Далее приведены основные параметры:
\b --xxx-name ID - идентификатор процесса.
IP-адрес шлюза задаётся параметром в конфигурационном файле \b gateway_iaddr или
параметром командной строки \b --xxx-gateway-iaddr.
Порт задаётся в конфигурационном файле параметром \b gateway_port или
параметром командной строки \b --xxx-gateway-port. По умолчанию используется порт \b 502.
\b --xxx-recv-timeout или \b recv_timeout msec - таймаут на приём сообщений. По умолчанию 2000 мсек.
\b --xxx-all-timeout или \b all_timeout msec - таймаут на определение отсутсвия связи
(после этого идёт попытка реинициализировать соединение)
\b --xxx-no-query-optimization или \b no_query_optimization - [1|0] отключить оптимизацию запросов
Оптимизация заключается в том, что регистры идущие подряд автоматически запрашиваются/записываются одним запросом.
В связи с чем, функция указанная в качестве \b mbfunc игнорируется и подменяется на работающую с многими регистрами.
\b --xxx-poll-time или \b poll_time msec - пауза между опросами. По умолчанию 100 мсек.
\b --xxx-initPause или \b initPause msec - пауза перед началом работы, после активации. По умолчанию 50 мсек.
\b --xxx-force или \b force [1|0]
- 1 - перечитывать значения входов из SharedMemory на каждом цикле
- 0 - обновлять значения только по изменению
\b --xxx-force-disconnect или \b force_disconnect - закрывать соединение после каждого запроса.
\b --xxx-force-out или \b force_out [1|0]
- 1 - перечитывать значения выходов из SharedMemory на каждом цикле
- 0 - обновлять значения только по изменению
\b --xxx-reg-from-id или \b reg_from_id [1|0]
- 1 - в качестве регистра использовать идентификатор датчика
- 0 - регистр брать из поля tcp_mbreg
\b --xxx-heartbeat-id или \b heartbeat_id ID - идентификатор датчика "сердцебиения" (см. \ref sec_SM_HeartBeat)
\b --xxx-heartbeat-max или \b heartbeat_max val - сохраняемое значение счётчика "сердцебиения".
\b --xxx-activate-timeout msec . По умолчанию 2000. - время ожидания готовности SharedMemory к работе.
\section sec_MBTCP_ConfList Конфигурирование списка регистров для ModbusTCP master
Конфигурационные параметры задаются в секции <sensors> конфигурационного файла.
Список обрабатываемых регистров задаётся при помощи двух параметров командной строки
\b --xxx-filter-field - задаёт фильтрующее поле для датчиков
\b --xxx-filter-value - задаёт значение фильтрующего поля. Необязательный параметр.
\b --xxx-statistic-sec sec - при наличии выведет кол-во посланных запросов за этот промежуток времени.
Если параметры не заданы, будет произведена попытка загрузить все датчики, у которых
присутствуют необходимые настроечные параметры.
\warning Если в результате список будет пустым, процесс завершает работу.
Пример конфигурационных параметров:
\code
<sensors name="Sensors">
...
<item name="MySensor_S" textname="my sesnsor" iotype="DI"
tcp_mbtype="rtu" tcp_mbaddr="0x01" tcp_mbfunc="0x04" tcp_mbreg="0x02" my_tcp="1"
/>
...
</sensors>
\endcode
К основным параметрам относятся следующие:
- \b tcp_mbtype - [rtu] - пока едиственный разрешённый тип.
- \b tcp_mbaddr - адрес RTU-устройства.
- \b tcp_mbreg - запрашиваемый/записываемый регистр.
- \b tcp_mbfunc - [0x1,0x2,0x3,...] функция опроса/записи. Разрешённые см. ModbusRTU::SlaveFunctionCode.
Помимо этого можно задавать следующие параметры:
- \b tcp_vtype - тип переменной. см VTypes::VType.
- \b tcp_rawdata - [1|0] - игнорировать или нет параметры калибровки
- \b tcp_iotype - [DI,DO,AI,AO] - переназначить тип датчика. По умолчанию используется поле iotype.
- \b tcp_nbit - номер бита в слове. Используется для DI,DO в случае когда для опроса используется
функция читающая слова (03
- \b tcp_nbyte - [1|2] номер байта. Используется если tcp_vtype="byte".
- \b tcp_mboffset - "сдвиг"(может быть отрицательным) при опросе/записи.
Т.е. фактически будет опрошен/записан регистр "mbreg+mboffset".
\warning Регистр должен быть уникальным. И может повторятся только если указан параметр \a nbit или \a nbyte.
*/
// -----------------------------------------------------------------------------
/*!
Реализация Modbus TCP Master для обмена с многими ModbusRTU устройствами
через один modbus tcp шлюз.
*/
class MBTCPMaster:
public UniSetObject_LT
{
public:
MBTCPMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0,
const std::string prefix="mbtcp" );
virtual ~MBTCPMaster();
/*! глобальная функция для инициализации объекта */
static MBTCPMaster* init_mbmaster( int argc, const char* const* argv,
UniSetTypes::ObjectId shmID, SharedMemory* ic=0,
const std::string prefix="mbtcp" );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, const char* const* argv );
void execute();
static const int NoSafetyState=-1;
enum Timer
{
tmExchange
};
enum DeviceType
{
dtUnknown, /*!< неизвестный */
dtRTU, /*!< RTU (default) */
dtMTR /*!< MTR (DEIF) */
};
static DeviceType getDeviceType( const std::string dtype );
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
// -------------------------------------------------------------------------------
struct RTUDevice;
struct RegInfo;
struct RSProperty:
public IOBase
{
// only for RTU
short nbit; /*!< bit number) */
VTypes::VType vType; /*!< type of value */
short rnum; /*!< count of registers */
short nbyte; /*!< byte number (1-2) */
RSProperty():
nbit(-1),vType(VTypes::vtUnknown),
rnum(VTypes::wsize(VTypes::vtUnknown)),
nbyte(0),reg(0)
{}
RegInfo* reg;
};
friend std::ostream& operator<<( std::ostream& os, const RSProperty& p );
typedef std::list<RSProperty> PList;
static std::ostream& print_plist( std::ostream& os, PList& p );
typedef std::map<ModbusRTU::ModbusData,RegInfo*> RegMap;
struct RegInfo
{
RegInfo():
mbval(0),mbreg(0),mbfunc(ModbusRTU::fnUnknown),
dev(0),offset(0),mtrType(MTR::mtUnknown),
q_num(0),q_count(1),mb_init(false),sm_init(false),
mb_init_mbreg(0)
{}
ModbusRTU::ModbusData mbval;
ModbusRTU::ModbusData mbreg; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< функция для чтения/записи */
PList slst;
RTUDevice* dev;
int offset;
// only for MTR
MTR::MTRType mtrType; /*!< тип регистра (согласно спецификации на MTR) */
// optimization
int q_num; /*!< number in query */
int q_count; /*!< count registers for query */
RegMap::iterator rit;
bool mb_init; /*!< init before use */
bool sm_init; /*!< SM init value */
ModbusRTU::ModbusData mb_init_mbreg; /*!< mb_init register */
};
friend std::ostream& operator<<( std::ostream& os, RegInfo& r );
struct RTUDevice
{
RTUDevice():
respnond(false),
mbaddr(0),
dtype(dtUnknown),
resp_id(UniSetTypes::DefaultObjectId),
resp_state(false),
resp_invert(false),
resp_real(false),
resp_init(false),
ask_every_reg(false)
{
resp_trTimeout.change(false);
}
bool respnond;
ModbusRTU::ModbusAddr mbaddr; /*!< адрес устройства */
RegMap regmap;
DeviceType dtype; /*!< тип устройства */
UniSetTypes::ObjectId resp_id;
IOController::DIOStateList::iterator resp_dit;
PassiveTimer resp_ptTimeout;
Trigger resp_trTimeout;
bool resp_state;
bool resp_invert;
bool resp_real;
bool resp_init;
bool ask_every_reg;
// return TRUE if state changed
bool checkRespond();
};
friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
typedef std::map<ModbusRTU::ModbusAddr,RTUDevice*> RTUDeviceMap;
friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
void printMap(RTUDeviceMap& d);
// ----------------------------------
protected:
RTUDeviceMap rmap;
ModbusTCPMaster* mb;
UniSetTypes::uniset_mutex mbMutex;
std::string iaddr;
// ost::InetAddress* ia;
int port;
int recv_timeout;
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void step();
void poll();
bool pollRTU( RTUDevice* dev, RegMap::iterator& it );
void updateSM();
void updateRTU(RegMap::iterator& it);
void updateMTR(RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only=false );
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void timerInfo( UniSetTypes::TimerMessage *tm );
void askSensors( UniversalIO::UIOCommand cmd );
void initOutput();
void waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initMB( bool reopen=false );
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void initDeviceList();
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
RegInfo* addReg( RegMap& rmap, ModbusRTU::ModbusData r, UniXML_iterator& it,
RTUDevice* dev, RegInfo* rcopy=0 );
RSProperty* addProp( PList& plist, RSProperty& p );
bool initMTRitem( UniXML_iterator& it, RegInfo* p );
bool initRSProperty( RSProperty& p, UniXML_iterator& it );
bool initRegInfo( RegInfo* r, UniXML_iterator& it, RTUDevice* dev );
bool initRTUDevice( RTUDevice* d, UniXML_iterator& it );
bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
void rtuQueryOptimization( RTUDeviceMap& m );
void readConfiguration();
bool check_item( UniXML_iterator& it );
private:
MBTCPMaster();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
bool force; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */
bool force_out; /*!< флаг означающий, принудительного чтения выходов */
bool mbregFromID;
int polltime; /*!< переодичность обновления данных, [мсек] */
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
UniSetTypes::uniset_mutex pollMutex;
bool activated;
int activateTimeout;
bool noQueryOptimization;
bool force_disconnect;
bool allNotRespond;
Trigger trAllNotRespond;
PassiveTimer ptAllNotRespond;
std::string prefix;
bool no_extimer;
timeout_t stat_time; /*!< время сбора статистики обмена */
int poll_count;
PassiveTimer ptStatistic; /*!< таймер для сбора статистики обмена */
};
// -----------------------------------------------------------------------------
#endif // _MBTCPMaster_H_
// -----------------------------------------------------------------------------
bin_PROGRAMS = @PACKAGE@-mbtcpmaster
UMBTCP_VER=@LIBVER@
lib_LTLIBRARIES = libUniSetMBTCPMaster.la
libUniSetMBTCPMaster_la_LDFLAGS = -version-info $(UMBTCP_VER)
libUniSetMBTCPMaster_la_LIBADD = $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS)
libUniSetMBTCPMaster_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
libUniSetMBTCPMaster_la_SOURCES = MBTCPMaster.cc
@PACKAGE@_mbtcpmaster_SOURCES = main.cc
@PACKAGE@_mbtcpmaster_LDADD = libUniSetMBTCPMaster.la $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS)
@PACKAGE@_mbtcpmaster_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
# install
devel_include_HEADERS = *.h
devel_includedir = $(pkgincludedir)/extensions
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libUniSetMBTCPMaster.pc
all-local:
ln -sf ../MBTCPMaster/$(devel_include_HEADERS) ../include
#!/bin/sh
ln -s -f ../../Utilities/scripts/uniset-start.sh
ln -s -f ../../Utilities/scripts/uniset-stop.sh stop.sh
ln -s -f ../../Utilities/scripts/uniset-functions.sh
ln -s -f ../../conf/test.xml test.xml
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetMBTCPMaster
Description: Support library for UniSetModbusTCPMaster
Requires: libUniSetExtensions libUniSetSharedMemory
Version: @VERSION@
Libs: -L${libdir} -lUniSetMBTCPMaster
Cflags: -I${includedir}/uniset
#include <sstream>
#include "MBTCPMaster.h"
#include "Configuration.h"
#include "Debug.h"
#include "ObjectsActivator.h"
#include "Extensions.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, const char** argv )
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
cout << "--smemory-id objectName - SharedMemory objectID. Default: autodetect" << endl;
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--mbtcp-logfile filename - logfilename. Default: mbtcpmaster.log" << endl;
cout << endl;
MBTCPMaster::help_print(argc, argv);
return 0;
}
try
{
string confile=UniSetTypes::getArgParam("--confile",argc, argv, "configure.xml");
conf = new Configuration( argc, argv, confile );
string logfilename(conf->getArgParam("--mbtcp-logfile"));
if( logfilename.empty() )
logfilename = "mbtcpmaster.log";
conf->initDebug(dlog,"dlog");
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
dlog.logFile( logname.str() );
ObjectId shmID = DefaultObjectId;
string sID = conf->getArgParam("--smemory-id");
if( !sID.empty() )
shmID = conf->getControllerID(sID);
else
shmID = getSharedMemoryID();
if( shmID == DefaultObjectId )
{
cerr << sID << "? SharedMemoryID not found in " << conf->getControllersSection() << " section" << endl;
return 1;
}
MBTCPMaster* mb = MBTCPMaster::init_mbmaster(argc,argv,shmID);
if( !mb )
{
dlog[Debug::CRIT] << "(mbmaster): init MBTCPMaster failed." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(mb));
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
unideb[Debug::ANY] << "(main): -------------- MBTCP Exchange START -------------------------\n\n";
dlog(Debug::ANY) << "\n\n\n";
dlog[Debug::ANY] << "(main): -------------- MBTCP Exchange START -------------------------\n\n";
act.run(false);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(mbtcpmaster): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(mbtcpmaster): catch ..." << std::endl;
}
return 0;
}
#!/bin/sh
uniset-start.sh -f ./uniset-mbtcpmaster \
--confile test.xml \
--mbtcp-name MBMaster1 \
--smemory-id SharedMemory \
--dlog-add-levels info,crit,warn,level4,level3 \
--mbtcp-filter-field mbtcp \
--mbtcp-filter-value 1 \
--mbtcp-gateway-iaddr 127.0.0.1 \
--mbtcp-gateway-port 2048 \
--mbtcp-recv-timeout 5000 \
--mbtcp-force-disconnect 1
#--mbtcp-filter-field mbtcp --mbtcp-filter-value 1
...@@ -11,7 +11,7 @@ using namespace UniSetTypes; ...@@ -11,7 +11,7 @@ using namespace UniSetTypes;
using namespace UniSetExtensions; using namespace UniSetExtensions;
using namespace ModbusRTU; using namespace ModbusRTU;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
MBSlave::MBSlave( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, MBSlave::MBSlave( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId,
SharedMemory* ic, string prefix ): SharedMemory* ic, string prefix ):
UniSetObject_LT(objId), UniSetObject_LT(objId),
mbslot(0), mbslot(0),
...@@ -35,7 +35,7 @@ prefix(prefix) ...@@ -35,7 +35,7 @@ prefix(prefix)
// xmlNode* cnode = conf->getNode(myname); // xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname); cnode = conf->getNode(myname);
if( cnode == NULL ) if( cnode == NULL )
throw UniSetTypes::SystemError("(MBSlave): Not found conf-node for " + myname ); throw UniSetTypes::SystemError("(MBSlave): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic); shm = new SMInterface(shmId,&ui,objId,ic);
...@@ -65,7 +65,7 @@ prefix(prefix) ...@@ -65,7 +65,7 @@ prefix(prefix)
respond_invert = conf->getArgInt("--" + prefix + "-respond-invert",it.getProp("respond_invert")); respond_invert = conf->getArgInt("--" + prefix + "-respond-invert",it.getProp("respond_invert"));
string stype = conf->getArgParam("--" + prefix + "-type",it.getProp("type")); string stype = conf->getArgParam("--" + prefix + "-type",it.getProp("type"));
if( stype == "RTU" ) if( stype == "RTU" )
{ {
// ---------- init RS ---------- // ---------- init RS ----------
...@@ -77,8 +77,8 @@ prefix(prefix) ...@@ -77,8 +77,8 @@ prefix(prefix)
if( speed.empty() ) if( speed.empty() )
speed = "38400"; speed = "38400";
bool use485F = conf->getArgInt("--" + prefix +"-use485F",it.getProp("use485F")); bool use485F = conf->getArgInt("--rs-use485F",it.getProp("use485F"));
bool transmitCtl = conf->getArgInt("--" + prefix + "-transmit-ctl",it.getProp("transmitCtl")); bool transmitCtl = conf->getArgInt("--rs-transmit-ctl",it.getProp("transmitCtl"));
ModbusRTUSlaveSlot* rs = new ModbusRTUSlaveSlot(dev,use485F,transmitCtl); ModbusRTUSlaveSlot* rs = new ModbusRTUSlaveSlot(dev,use485F,transmitCtl);
rs->setSpeed(speed); rs->setSpeed(speed);
...@@ -90,7 +90,7 @@ prefix(prefix) ...@@ -90,7 +90,7 @@ prefix(prefix)
mbslot = rs; mbslot = rs;
thr = new ThreadCreator<MBSlave>(this,&MBSlave::execute_rtu); thr = new ThreadCreator<MBSlave>(this,&MBSlave::execute_rtu);
dlog[Debug::INFO] << myname << "(init): type=RTU myaddr=" << ModbusRTU::addr2str(addr) dlog[Debug::INFO] << myname << "(init): type=RTU myaddr=" << ModbusRTU::addr2str(addr)
<< " dev=" << dev << " speed=" << speed << endl; << " dev=" << dev << " speed=" << speed << endl;
} }
else if( stype == "TCP" ) else if( stype == "TCP" )
...@@ -98,12 +98,12 @@ prefix(prefix) ...@@ -98,12 +98,12 @@ prefix(prefix)
string iaddr = conf->getArgParam("--" + prefix + "-inet-addr",it.getProp("iaddr")); string iaddr = conf->getArgParam("--" + prefix + "-inet-addr",it.getProp("iaddr"));
if( iaddr.empty() ) if( iaddr.empty() )
throw UniSetTypes::SystemError(myname+"(MBSlave): Unknown TCP server address. Use: --prefix-inet-addr [ XXX.XXX.XXX.XXX| hostname ]"); throw UniSetTypes::SystemError(myname+"(MBSlave): Unknown TCP server address. Use: --prefix-inet-addr [ XXX.XXX.XXX.XXX| hostname ]");
int port = conf->getArgPInt("--" + prefix + "-inet-port",it.getProp("iport"), 502); int port = conf->getArgPInt("--" + prefix + "-inet-port",it.getProp("iport"), 502);
dlog[Debug::INFO] << myname << "(init): type=TCP myaddr=" << ModbusRTU::addr2str(addr) dlog[Debug::INFO] << myname << "(init): type=TCP myaddr=" << ModbusRTU::addr2str(addr)
<< " inet=" << iaddr << " port=" << port << endl; << " inet=" << iaddr << " port=" << port << endl;
ost::InetAddress ia(iaddr.c_str()); ost::InetAddress ia(iaddr.c_str());
mbslot = new ModbusTCPServerSlot(ia,port); mbslot = new ModbusTCPServerSlot(ia,port);
thr = new ThreadCreator<MBSlave>(this,&MBSlave::execute_tcp); thr = new ThreadCreator<MBSlave>(this,&MBSlave::execute_tcp);
...@@ -117,18 +117,15 @@ prefix(prefix) ...@@ -117,18 +117,15 @@ prefix(prefix)
mbslot->connectReadInputStatus( sigc::mem_fun(this, &MBSlave::readInputStatus) ); mbslot->connectReadInputStatus( sigc::mem_fun(this, &MBSlave::readInputStatus) );
mbslot->connectReadOutput( sigc::mem_fun(this, &MBSlave::readOutputRegisters) ); mbslot->connectReadOutput( sigc::mem_fun(this, &MBSlave::readOutputRegisters) );
mbslot->connectReadInput( sigc::mem_fun(this, &MBSlave::readInputRegisters) ); mbslot->connectReadInput( sigc::mem_fun(this, &MBSlave::readInputRegisters) );
mbslot->connectForceSingleCoil( sigc::mem_fun(this, &MBSlave::forceSingleCoil) ); // mbslot->connectForceSingleCoil( sigc::mem_fun(this, &MBSlave::forceSingleCoil) );
mbslot->connectForceCoils( sigc::mem_fun(this, &MBSlave::forceMultipleCoils) ); // mbslot->connectForceCoils( sigc::mem_fun(this, &MBSlave::forceMultipleCoils) );
mbslot->connectWriteOutput( sigc::mem_fun(this, &MBSlave::writeOutputRegisters) ); mbslot->connectWriteOutput( sigc::mem_fun(this, &MBSlave::writeOutputRegisters) );
mbslot->connectWriteSingleOutput( sigc::mem_fun(this, &MBSlave::writeOutputSingleRegister) ); mbslot->connectWriteSingleOutput( sigc::mem_fun(this, &MBSlave::writeOutputSingleRegister) );
mbslot->connectMEIRDI( sigc::mem_fun(this, &MBSlave::read4314) );
if( findArgParam("--" + prefix + "-allow-setdatetime",conf->getArgc(),conf->getArgv())!=-1 ) if( findArgParam("--" + prefix + "-allow-setdatetime",conf->getArgc(),conf->getArgv())!=-1 )
mbslot->connectSetDateTime( sigc::mem_fun(this, &MBSlave::setDateTime) ); mbslot->connectSetDateTime( sigc::mem_fun(this, &MBSlave::setDateTime) );
mbslot->connectDiagnostics( sigc::mem_fun(this, &MBSlave::diagnostics) ); mbslot->connectFileTransfer( sigc::mem_fun(this, &MBSlave::fileTransfer) );
mbslot->connectFileTransfer( sigc::mem_fun(this, &MBSlave::fileTransfer) );
// mbslot->connectJournalCommand( sigc::mem_fun(this, &MBSlave::journalCommand) ); // mbslot->connectJournalCommand( sigc::mem_fun(this, &MBSlave::journalCommand) );
// mbslot->connectRemoteService( sigc::mem_fun(this, &MBSlave::remoteService) ); // mbslot->connectRemoteService( sigc::mem_fun(this, &MBSlave::remoteService) );
// ------------------------------- // -------------------------------
...@@ -141,11 +138,7 @@ prefix(prefix) ...@@ -141,11 +138,7 @@ prefix(prefix)
dlog[Debug::INFO] << myname << "(init): iomap size = " << iomap.size() << endl; dlog[Debug::INFO] << myname << "(init): iomap size = " << iomap.size() << endl;
} }
else else
{
ic->addReadItem( sigc::mem_fun(this,&MBSlave::readItem) ); ic->addReadItem( sigc::mem_fun(this,&MBSlave::readItem) );
// при работе с SM через указатель принудительно включаем force
force = true;
}
// ********** HEARTBEAT ************* // ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix + "-heartbeat-id",it.getProp("heartbeat_id")); string heart = conf->getArgParam("--" + prefix + "-heartbeat-id",it.getProp("heartbeat_id"));
...@@ -160,7 +153,7 @@ prefix(prefix) ...@@ -160,7 +153,7 @@ prefix(prefix)
throw SystemError(err.str()); throw SystemError(err.str());
} }
int heartbeatTime = conf->getArgPInt("--" + prefix + "-heartbeat-time",it.getProp("heartbeatTime"),conf->getHeartBeatTime()); int heartbeatTime = getHeartBeatTime();
if( heartbeatTime ) if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime); ptHeartBeat.setTiming(heartbeatTime);
else else
...@@ -186,7 +179,7 @@ prefix(prefix) ...@@ -186,7 +179,7 @@ prefix(prefix)
dlog[Debug::INFO] << myname << ": init test_id=" << test_id << endl; dlog[Debug::INFO] << myname << ": init test_id=" << test_id << endl;
wait_msec = conf->getHeartBeatTime() - 100; wait_msec = getHeartBeatTime() - 100;
if( wait_msec < 500 ) if( wait_msec < 500 )
wait_msec = 500; wait_msec = 500;
...@@ -197,12 +190,9 @@ prefix(prefix) ...@@ -197,12 +190,9 @@ prefix(prefix)
dlog[Debug::INFO] << myname << "(init): rs-timeout=" << msec << " msec" << endl; dlog[Debug::INFO] << myname << "(init): rs-timeout=" << msec << " msec" << endl;
// build file list...
xmlNode* fnode = 0;
UniXML* xml = conf->getConfXML();
if( xml )
fnode = xml->extFindNode(cnode,1,1,"filelist");
// build file list...
xmlNode* fnode = conf->findNode(cnode,"filelist");
if( fnode ) if( fnode )
{ {
UniXML_iterator fit(fnode); UniXML_iterator fit(fnode);
...@@ -222,7 +212,7 @@ prefix(prefix) ...@@ -222,7 +212,7 @@ prefix(prefix)
dlog[Debug::WARN] << myname << "(build file list): FAILED ID for " << nm << "... ignore..." << endl; dlog[Debug::WARN] << myname << "(build file list): FAILED ID for " << nm << "... ignore..." << endl;
continue; continue;
} }
std::string dir = fit.getProp("directory"); std::string dir = fit.getProp("directory");
if( !dir.empty() ) if( !dir.empty() )
{ {
...@@ -236,7 +226,7 @@ prefix(prefix) ...@@ -236,7 +226,7 @@ prefix(prefix)
dlog[Debug::INFO] << myname << "(init): add to filelist: " dlog[Debug::INFO] << myname << "(init): add to filelist: "
<< "id=" << id << "id=" << id
<< " file=" << nm << " file=" << nm
<< endl; << endl;
flist[id] = nm; flist[id] = nm;
...@@ -248,105 +238,6 @@ prefix(prefix) ...@@ -248,105 +238,6 @@ prefix(prefix)
else else
dlog[Debug::INFO] << myname << "(init): <filelist> not found..." << endl; dlog[Debug::INFO] << myname << "(init): <filelist> not found..." << endl;
// Формирование "карты" ответов на запрос 0x2B(43)/0x0E(14)
xmlNode* mnode = 0;
if( xml )
mnode = xml->extFindNode(cnode,1,1,"MEI");
if( mnode )
{
// Считывается структура для формирования ответов на запрос 0x2B(43)/0x0E(14)
// <MEI>
// <device id="">
// <objects id="">
// <string id="" value=""/>
// <string id="" value=""/>
// <string id="" value=""/>
// ...
// </objects>
// </device>
// <device devID="">
// ...
// </device>
// </MEI>
UniXML_iterator dit(mnode);
if( dit.goChildren() )
{
// Device ID list..
for( ;dit.getCurrent(); dit.goNext() )
{
if( dit.getProp("id").empty() )
{
dlog[Debug::WARN] << myname << "(init): read <MEI>. Unknown <device id=''>. Ignore.." << endl;
continue;
}
int devID = dit.getIntProp("id");
UniXML_iterator oit(dit);
if( oit.goChildren() )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(init): MEI: read dev='" << devID << "'" << endl;
MEIObjIDMap meiomap;
// Object ID list..
for( ;oit.getCurrent(); oit.goNext() )
{
if( dit.getProp("id").empty() )
{
dlog[Debug::WARN] << myname
<< "(init): read <MEI>. Unknown <object id='' (for device id='"
<< devID << "'). Ignore.."
<< endl;
continue;
}
int objID = oit.getIntProp("id");
UniXML_iterator sit(oit);
if( sit.goChildren() )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(init): MEI: read obj='" << objID << "'" << endl;
MEIValMap meivmap;
// request (string) list..
for( ;sit.getCurrent(); sit.goNext() )
{
int vid = objID;
if( sit.getProp("id").empty() )
{
if( dlog.debugging(Debug::WARN) )
dlog[Debug::INFO] << myname << "(init): MEI: dev='" << devID
<< "' obj='" << objID << "'"
<< ". Unknown id='' for value='" << sit.getProp("value") << "'"
<< ". Set objID='" << objID << "'"
<< endl;
}
else
vid = sit.getIntProp("id");
meivmap[vid] = sit.getProp("value");
}
if( !meivmap.empty() )
meiomap[objID] = meivmap;
}
}
if( !meiomap.empty() )
meidev[devID] = meiomap;
}
}
}
if( !meidev.empty() && dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(init): <MEI> init ok." << endl;
}
else
dlog[Debug::INFO] << myname << "(init): <MEI> empty..." << endl;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
MBSlave::~MBSlave() MBSlave::~MBSlave()
...@@ -377,8 +268,7 @@ void MBSlave::waitSMReady() ...@@ -377,8 +268,7 @@ void MBSlave::waitSMReady()
void MBSlave::execute_rtu() void MBSlave::execute_rtu()
{ {
ModbusRTUSlaveSlot* rscomm = dynamic_cast<ModbusRTUSlaveSlot*>(mbslot); ModbusRTUSlaveSlot* rscomm = dynamic_cast<ModbusRTUSlaveSlot*>(mbslot);
ModbusRTU::mbErrCode prev = erNoError;
while(1) while(1)
{ {
try try
...@@ -387,7 +277,7 @@ void MBSlave::execute_rtu() ...@@ -387,7 +277,7 @@ void MBSlave::execute_rtu()
if( res!=ModbusRTU::erTimeOut ) if( res!=ModbusRTU::erTimeOut )
ptTimeout.reset(); ptTimeout.reset();
// собираем статистику обмена // собираем статистику обмена
if( prev!=ModbusRTU::erTimeOut ) if( prev!=ModbusRTU::erTimeOut )
{ {
...@@ -395,9 +285,9 @@ void MBSlave::execute_rtu() ...@@ -395,9 +285,9 @@ void MBSlave::execute_rtu()
askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1; askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1;
if( res!=ModbusRTU::erNoError ) if( res!=ModbusRTU::erNoError )
errmap[res]++; errmap[res]++;
}
prev = res; prev = res;
}
if( res!=ModbusRTU::erNoError && res!=ModbusRTU::erTimeOut ) if( res!=ModbusRTU::erNoError && res!=ModbusRTU::erTimeOut )
dlog[Debug::WARN] << myname << "(execute_rtu): " << ModbusRTU::mbErr2Str(res) << endl; dlog[Debug::WARN] << myname << "(execute_rtu): " << ModbusRTU::mbErr2Str(res) << endl;
...@@ -448,7 +338,7 @@ void MBSlave::execute_rtu() ...@@ -448,7 +338,7 @@ void MBSlave::execute_rtu()
<< "(execute_rtu): (askCount) " << ex << std::endl; << "(execute_rtu): (askCount) " << ex << std::endl;
} }
} }
for( IOMap::iterator it=iomap.begin(); it!=iomap.end(); ++it ) for( IOMap::iterator it=iomap.begin(); it!=iomap.end(); ++it )
IOBase::processingThreshold(&it->second,shm,force); IOBase::processingThreshold(&it->second,shm,force);
} }
...@@ -460,8 +350,6 @@ void MBSlave::execute_tcp() ...@@ -460,8 +350,6 @@ void MBSlave::execute_tcp()
{ {
ModbusTCPServerSlot* sslot = dynamic_cast<ModbusTCPServerSlot*>(mbslot); ModbusTCPServerSlot* sslot = dynamic_cast<ModbusTCPServerSlot*>(mbslot);
ModbusRTU::mbErrCode prev = erNoError;
while(1) while(1)
{ {
try try
...@@ -470,7 +358,7 @@ void MBSlave::execute_tcp() ...@@ -470,7 +358,7 @@ void MBSlave::execute_tcp()
if( res!=ModbusRTU::erTimeOut ) if( res!=ModbusRTU::erTimeOut )
ptTimeout.reset(); ptTimeout.reset();
// собираем статистику обмена // собираем статистику обмена
if( prev!=ModbusRTU::erTimeOut ) if( prev!=ModbusRTU::erTimeOut )
{ {
...@@ -478,10 +366,10 @@ void MBSlave::execute_tcp() ...@@ -478,10 +366,10 @@ void MBSlave::execute_tcp()
askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1; askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1;
if( res!=ModbusRTU::erNoError ) if( res!=ModbusRTU::erNoError )
errmap[res]++; errmap[res]++;
prev = res;
} }
prev = res;
if( res!=ModbusRTU::erNoError && res!=ModbusRTU::erTimeOut ) if( res!=ModbusRTU::erNoError && res!=ModbusRTU::erTimeOut )
dlog[Debug::WARN] << myname << "(execute_tcp): " << ModbusRTU::mbErr2Str(res) << endl; dlog[Debug::WARN] << myname << "(execute_tcp): " << ModbusRTU::mbErr2Str(res) << endl;
...@@ -589,9 +477,9 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm) ...@@ -589,9 +477,9 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm)
{ {
dlog[Debug::CRIT] << myname << "(sysCommand): iomap EMPTY! terminated..." << endl; dlog[Debug::CRIT] << myname << "(sysCommand): iomap EMPTY! terminated..." << endl;
raise(SIGTERM); raise(SIGTERM);
return; return;
} }
waitSMReady(); waitSMReady();
// подождать пока пройдёт инициализация датчиков // подождать пока пройдёт инициализация датчиков
...@@ -599,16 +487,16 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm) ...@@ -599,16 +487,16 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm)
msleep(initPause); msleep(initPause);
PassiveTimer ptAct(activateTimeout); PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() ) while( !activated && !ptAct.checkTime() )
{ {
cout << myname << "(sysCommand): wait activate..." << endl; cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300); msleep(300);
if( activated ) if( activated )
break; break;
} }
if( !activated ) if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl; dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
else else
{ {
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000); UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify); askSensors(UniversalIO::UIONotify);
...@@ -621,11 +509,11 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm) ...@@ -621,11 +509,11 @@ void MBSlave::sysCommand(UniSetTypes::SystemMessage *sm)
case SystemMessage::Finish: case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify); askSensors(UniversalIO::UIODontNotify);
break; break;
case SystemMessage::WatchDog: case SystemMessage::WatchDog:
{ {
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте) // ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа // Если идёт локальная работа
// (т.е. MBSlave запущен в одном процессе с SharedMemory2) // (т.е. MBSlave запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM // то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBSlave) // при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBSlave)
...@@ -666,10 +554,10 @@ void MBSlave::askSensors( UniversalIO::UIOCommand cmd ) ...@@ -666,10 +554,10 @@ void MBSlave::askSensors( UniversalIO::UIOCommand cmd )
if( !shm->waitSMworking(test_id,activateTimeout,50) ) if( !shm->waitSMworking(test_id,activateTimeout,50) )
{ {
ostringstream err; ostringstream err;
err << myname err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение " << "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек"; << activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl; dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс... kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str()); throw SystemError(err.str());
...@@ -682,7 +570,7 @@ void MBSlave::askSensors( UniversalIO::UIOCommand cmd ) ...@@ -682,7 +570,7 @@ void MBSlave::askSensors( UniversalIO::UIOCommand cmd )
for( ; it!=iomap.end(); ++it ) for( ; it!=iomap.end(); ++it )
{ {
IOProperty* p(&it->second); IOProperty* p(&it->second);
// if( p->stype != UniversalIO::DigitalOutput && p->stype != UniversalIO::AnalogOutput ) // if( p->stype != UniversalIO::DigitalOutput && p->stype != UniversalIO::AnalogOutput )
// continue; // continue;
...@@ -720,38 +608,14 @@ void MBSlave::sensorInfo( UniSetTypes::SensorMessage* sm ) ...@@ -720,38 +608,14 @@ void MBSlave::sensorInfo( UniSetTypes::SensorMessage* sm )
uniset_spin_lock lock(p->val_lock); uniset_spin_lock lock(p->val_lock);
p->value = sm->value; p->value = sm->value;
} }
break;
int sz = VTypes::wsize(p->vtype);
if( sz < 1 )
return;
// если размер больше одного слова
// то надо обновить значение "везде"
// они если "всё верно инициализировано" идут подряд
int i=0;
for( ;i<sz && it!=iomap.end(); i++,it++ )
{
p = &it->second;
if( p->si.id == sm->id )
p->value = sm->value;
}
if( dlog.debugging(Debug::CRIT) )
{
// вообще этого не может случиться
// потому-что корректность проверяется при загрузке
if( i != sz )
dlog[Debug::CRIT] << myname << "(sensorInfo): update failed for sid=" << sm->id
<< " (i=" << i << " sz=" << sz << ")" << endl;
}
return;
} }
} }
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
bool MBSlave::activateObject() bool MBSlave::activateObject()
{ {
// блокирование обработки Starsp // блокирование обработки Starsp
// пока не пройдёт инициализация датчиков // пока не пройдёт инициализация датчиков
// см. sysCommand() // см. sysCommand()
{ {
...@@ -775,7 +639,7 @@ void MBSlave::sigterm( int signo ) ...@@ -775,7 +639,7 @@ void MBSlave::sigterm( int signo )
mbslot->sigterm(signo); mbslot->sigterm(signo);
} }
catch(...){} catch(...){}
UniSetObject_LT::sigterm(signo); UniSetObject_LT::sigterm(signo);
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
...@@ -799,16 +663,33 @@ void MBSlave::readConfiguration() ...@@ -799,16 +663,33 @@ void MBSlave::readConfiguration()
for( ;it.getCurrent(); it.goNext() ) for( ;it.getCurrent(); it.goNext() )
{ {
if( UniSetTypes::check_filter(it,s_field,s_fvalue) ) if( check_item(it) )
initItem(it); initItem(it);
} }
// readconf_ok = true; // readconf_ok = true;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
bool MBSlave::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// просто проверка на не пустой field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// просто проверка что field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool MBSlave::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec ) bool MBSlave::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{ {
if( UniSetTypes::check_filter(it,s_field,s_fvalue) ) if( check_item(it) )
initItem(it); initItem(it);
return true; return true;
} }
...@@ -831,10 +712,10 @@ bool MBSlave::initItem( UniXML_iterator& it ) ...@@ -831,10 +712,10 @@ bool MBSlave::initItem( UniXML_iterator& it )
dlog[Debug::CRIT] << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl; dlog[Debug::CRIT] << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl;
return false; return false;
} }
p.mbreg = ModbusRTU::str2mbData(r); p.mbreg = ModbusRTU::str2mbData(r);
} }
string stype( it.getProp("mb_iotype") ); string stype( it.getProp("mb_iotype") );
if( stype.empty() ) if( stype.empty() )
stype = it.getProp("iotype"); stype = it.getProp("iotype");
...@@ -868,8 +749,8 @@ bool MBSlave::initItem( UniXML_iterator& it ) ...@@ -868,8 +749,8 @@ bool MBSlave::initItem( UniXML_iterator& it )
VTypes::VType v(VTypes::str2type(vt)); VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown ) if( v == VTypes::vtUnknown )
{ {
dlog[Debug::CRIT] << myname << "(initItem): Unknown rtuVType=" << vt << " for " dlog[Debug::CRIT] << myname << "(initItem): Unknown rtuVType=" << vt << " for "
<< it.getProp("name") << it.getProp("name")
<< endl; << endl;
return false; return false;
...@@ -885,7 +766,7 @@ bool MBSlave::initItem( UniXML_iterator& it ) ...@@ -885,7 +766,7 @@ bool MBSlave::initItem( UniXML_iterator& it )
dlog[Debug::INFO] << myname << "(initItem): add " << p << endl; dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;
} }
} }
return true; return true;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
...@@ -905,15 +786,11 @@ void MBSlave::initIterators() ...@@ -905,15 +786,11 @@ void MBSlave::initIterators()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBSlave::help_print( int argc, const char* const* argv ) void MBSlave::help_print( int argc, const char* const* argv )
{ {
cout << "Default: prefix='mbs'" << endl; cout << "Default: prefix='mbtcp'" << endl;
cout << "--prefix-reg-from-id 0,1 - Использовать в качестве регистра sensor ID" << endl; cout << "--prefix-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--prefix-filter-field name - Считывать список опрашиваемых датчиков, только у которых есть поле field" << endl; cout << "--prefix-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--prefix-filter-value val - Считывать список опрашиваемых датчиков, только у которых field=value" << endl; cout << "--prefix-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--prefix-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl; cout << "--prefix-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--prefix-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--prefix-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--prefix-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--prefix-force 1 - Читать данные из SM каждый раз, а не по изменению." << endl;
cout << "--prefix-respond-id - respond sensor id" << endl; cout << "--prefix-respond-id - respond sensor id" << endl;
cout << "--prefix-respond-invert [0|1] - invert respond logic" << endl; cout << "--prefix-respond-invert [0|1] - invert respond logic" << endl;
cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl; cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
...@@ -944,7 +821,7 @@ MBSlave* MBSlave::init_mbslave( int argc, const char* const* argv, UniSetTypes:: ...@@ -944,7 +821,7 @@ MBSlave* MBSlave::init_mbslave( int argc, const char* const* argv, UniSetTypes::
ObjectId ID = conf->getObjectID(name); ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId ) if( ID == UniSetTypes::DefaultObjectId )
{ {
cerr << "(mbslave): идентификатор '" << name cerr << "(mbslave): идентификатор '" << name
<< "' не найден в конф. файле!" << "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl; << " в секции " << conf->getObjectsSection() << endl;
return 0; return 0;
...@@ -967,12 +844,12 @@ std::ostream& operator<<( std::ostream& os, MBSlave::IOProperty& p ) ...@@ -967,12 +844,12 @@ std::ostream& operator<<( std::ostream& os, MBSlave::IOProperty& p )
{ {
os << p.cal os << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" ); << " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
} }
return os; return os;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage& query, ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage& query,
ModbusRTU::ReadOutputRetMessage& reply ) ModbusRTU::ReadOutputRetMessage& reply )
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
...@@ -996,7 +873,7 @@ ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage& ...@@ -996,7 +873,7 @@ ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage&
for( int i=0; i<query.count; i++ ) for( int i=0; i<query.count; i++ )
reply.addData( buf[i] ); reply.addData( buf[i] );
} }
return ret; return ret;
} }
...@@ -1010,7 +887,7 @@ ModbusRTU::mbErrCode MBSlave::writeOutputRegisters( ModbusRTU::WriteOutputMessag ...@@ -1010,7 +887,7 @@ ModbusRTU::mbErrCode MBSlave::writeOutputRegisters( ModbusRTU::WriteOutputMessag
// Формирование ответа: // Формирование ответа:
ModbusRTU::mbErrCode ret = much_real_write(query.start,query.data,query.quant); ModbusRTU::mbErrCode ret = much_real_write(query.start,query.data,query.quant);
if( ret == ModbusRTU::erNoError ) if( ret == ModbusRTU::erNoError )
reply.set(query.start,query.quant); reply.set(query.start,query.quant);
return ret; return ret;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -1027,14 +904,9 @@ ModbusRTU::mbErrCode MBSlave::writeOutputSingleRegister( ModbusRTU::WriteSingleO ...@@ -1027,14 +904,9 @@ ModbusRTU::mbErrCode MBSlave::writeOutputSingleRegister( ModbusRTU::WriteSingleO
return ret; return ret;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::much_real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, ModbusRTU::mbErrCode MBSlave::much_real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
int count ) int count )
{ if( dlog.debugging(Debug::INFO) ) {
{
dlog[Debug::INFO] << myname << "(much_real_write): read mbID="
<< ModbusRTU::dat2str(reg) << " count=" << count << endl;
}
int i=0; int i=0;
IOMap::iterator it = iomap.end(); IOMap::iterator it = iomap.end();
for( ; i<count; i++ ) for( ; i<count; i++ )
...@@ -1058,7 +930,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( ModbusRTU::ModbusData reg, Modbus ...@@ -1058,7 +930,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( ModbusRTU::ModbusData reg, Modbus
it++; it++;
} }
} }
return ModbusRTU::erNoError; return ModbusRTU::erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -1066,8 +938,8 @@ ModbusRTU::mbErrCode MBSlave::real_write( ModbusRTU::ModbusData reg, ModbusRTU:: ...@@ -1066,8 +938,8 @@ ModbusRTU::mbErrCode MBSlave::real_write( ModbusRTU::ModbusData reg, ModbusRTU::
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
{ {
dlog[Debug::INFO] << myname << "(write): save mbID=" dlog[Debug::INFO] << myname << "(write): save mbID="
<< ModbusRTU::dat2str(reg) << ModbusRTU::dat2str(reg)
<< " data=" << ModbusRTU::dat2str(mbval) << " data=" << ModbusRTU::dat2str(mbval)
<< "(" << (int)mbval << ")" << endl; << "(" << (int)mbval << ")" << endl;
} }
...@@ -1112,7 +984,7 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod ...@@ -1112,7 +984,7 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod
long val = (signed short)(mbval); long val = (signed short)(mbval);
IOBase::processingAsAI( p, val, shm, force ); IOBase::processingAsAI( p, val, shm, force );
} }
/* /*
else if( p->vtype == VTypes::vtByte ) else if( p->vtype == VTypes::vtByte )
{ {
VTypes::Byte b(r->mbval); VTypes::Byte b(r->mbval);
...@@ -1125,10 +997,10 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod ...@@ -1125,10 +997,10 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F2::wsize()]; ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F2::wsize()];
for( int k=0; k<VTypes::F2::wsize(); k++, i++ ) for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
data[k] = i->second->mbval; data[k] = i->second->mbval;
VTypes::F2 f(data,VTypes::F2::wsize()); VTypes::F2 f(data,VTypes::F2::wsize());
delete[] data; delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force ); IOBase::processingFasAI( p, (float)f, shm, force );
} }
else if( p->vtype == VTypes::vtF4 ) else if( p->vtype == VTypes::vtF4 )
...@@ -1138,10 +1010,10 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod ...@@ -1138,10 +1010,10 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F4::wsize()]; ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F4::wsize()];
for( int k=0; k<VTypes::F4::wsize(); k++, i++ ) for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
data[k] = i->second->mbval; data[k] = i->second->mbval;
VTypes::F4 f(data,VTypes::F4::wsize()); VTypes::F4 f(data,VTypes::F4::wsize());
delete[] data; delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force ); IOBase::processingFasAI( p, (float)f, shm, force );
} }
*/ */
...@@ -1188,20 +1060,20 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod ...@@ -1188,20 +1060,20 @@ ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::Mod
if( pingOK ) if( pingOK )
dlog[Debug::CRIT] << myname << "(write) catch ..." << endl; dlog[Debug::CRIT] << myname << "(write) catch ..." << endl;
} }
pingOK = false; pingOK = false;
return ModbusRTU::erTimeOut; return ModbusRTU::erTimeOut;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
int count ) int count )
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
{ {
dlog[Debug::INFO] << myname << "(much_real_read): read mbID=" dlog[Debug::INFO] << myname << "(mush_real_read): read mbID="
<< ModbusRTU::dat2str(reg) << " count=" << count << endl; << ModbusRTU::dat2str(reg) << " count=" << count << endl;
} }
IOMap::iterator it = iomap.end(); IOMap::iterator it = iomap.end();
int i=0; int i=0;
for( ; i<count; i++ ) for( ; i<count; i++ )
...@@ -1218,7 +1090,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR ...@@ -1218,7 +1090,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR
if( it == iomap.end() ) if( it == iomap.end() )
return ModbusRTU::erBadDataAddress; return ModbusRTU::erBadDataAddress;
ModbusRTU::ModbusData val=0; ModbusRTU::ModbusData val=0;
for( ; (it!=iomap.end()) && (i<count); i++,reg++ ) for( ; (it!=iomap.end()) && (i<count); i++,reg++ )
{ {
...@@ -1238,7 +1110,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR ...@@ -1238,7 +1110,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR
{ {
for( ; i<count; i++ ) for( ; i<count; i++ )
dat[i] = 0; dat[i] = 0;
} }
return ModbusRTU::erNoError; return ModbusRTU::erNoError;
} }
...@@ -1247,7 +1119,7 @@ ModbusRTU::mbErrCode MBSlave::real_read( ModbusRTU::ModbusData reg, ModbusRTU::M ...@@ -1247,7 +1119,7 @@ ModbusRTU::mbErrCode MBSlave::real_read( ModbusRTU::ModbusData reg, ModbusRTU::M
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
{ {
dlog[Debug::INFO] << myname << "(real_read): read mbID=" dlog[Debug::INFO] << myname << "(real_read): read mbID="
<< ModbusRTU::dat2str(reg) << endl; << ModbusRTU::dat2str(reg) << endl;
} }
...@@ -1267,14 +1139,14 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb ...@@ -1267,14 +1139,14 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
dlog[Debug::INFO] << myname << "(real_read_it): read mbID=" dlog[Debug::INFO] << myname << "(real_read_it): read mbID="
<< ModbusRTU::dat2str(it->first) << endl; << ModbusRTU::dat2str(it->first) << endl;
} }
IOProperty* p(&it->second); IOProperty* p(&it->second);
val = 0; val = 0;
if( p->amode == MBSlave::amWO ) if( p->amode == MBSlave::amWO )
return ModbusRTU::erBadDataAddress; return ModbusRTU::erBadDataAddress;
if( p->stype == UniversalIO::DigitalInput || if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput ) p->stype == UniversalIO::DigitalOutput )
{ {
val = IOBase::processingAsDO(p,shm,force) ? 1 : 0; val = IOBase::processingAsDO(p,shm,force) ? 1 : 0;
...@@ -1285,21 +1157,11 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb ...@@ -1285,21 +1157,11 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
if( p->vtype == VTypes::vtUnknown ) if( p->vtype == VTypes::vtUnknown )
{ {
val = IOBase::processingAsAO(p,shm,force); val = IOBase::processingAsAO(p,shm,force);
}
else if( p->vtype == VTypes::vtF2 )
{
float f = IOBase::processingFasAO(p,shm,force);
VTypes::F2 f2(f);
// оптимизируем и проверку не делаем
// считая, что при "загрузке" всё было правильно
// инициализировано
// if( p->wnum >=0 && p->wnum < f4.wsize()
val = f2.raw.v[p->wnum];
} }
else if( p->vtype == VTypes::vtF2r ) if( p->vtype == VTypes::vtF2 )
{ {
float f = IOBase::processingFasAO(p,shm,force); float f = IOBase::processingFasAO(p,shm,force);
VTypes::F2r f2(f); VTypes::F2 f2(f);
// оптимизируем и проверку не делаем // оптимизируем и проверку не делаем
// считая, что при "загрузке" всё было правильно // считая, что при "загрузке" всё было правильно
// инициализировано // инициализировано
...@@ -1326,16 +1188,6 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb ...@@ -1326,16 +1188,6 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
// if( p->wnum >=0 && p->wnum < i2.wsize() // if( p->wnum >=0 && p->wnum < i2.wsize()
val = i2.raw.v[p->wnum]; val = i2.raw.v[p->wnum];
} }
else if( p->vtype == VTypes::vtI2r )
{
long v = IOBase::processingAsAO(p,shm,force);
VTypes::I2r i2(v);
// оптимизируем и проверку не делаем
// считая, что при "загрузке" всё было правильно
// инициализировано
// if( p->wnum >=0 && p->wnum < i2.wsize()
val = i2.raw.v[p->wnum];
}
else if( p->vtype == VTypes::vtU2 ) else if( p->vtype == VTypes::vtU2 )
{ {
unsigned long v = IOBase::processingAsAO(p,shm,force); unsigned long v = IOBase::processingAsAO(p,shm,force);
...@@ -1346,16 +1198,6 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb ...@@ -1346,16 +1198,6 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
// if( p->wnum >=0 && p->wnum < u2.wsize() // if( p->wnum >=0 && p->wnum < u2.wsize()
val = u2.raw.v[p->wnum]; val = u2.raw.v[p->wnum];
} }
else if( p->vtype == VTypes::vtU2r )
{
unsigned long v = IOBase::processingAsAO(p,shm,force);
VTypes::U2r u2(v);
// оптимизируем и проверку не делаем
// считая, что при "загрузке" всё было правильно
// инициализировано
// if( p->wnum >=0 && p->wnum < u2.wsize()
val = u2.raw.v[p->wnum];
}
else else
val = IOBase::processingAsAO(p,shm,force); val = IOBase::processingAsAO(p,shm,force);
} }
...@@ -1391,7 +1233,7 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb ...@@ -1391,7 +1233,7 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
if( pingOK ) if( pingOK )
dlog[Debug::CRIT] << myname << "(real_read_it) catch ..." << endl; dlog[Debug::CRIT] << myname << "(real_read_it) catch ..." << endl;
} }
pingOK = false; pingOK = false;
return ModbusRTU::erTimeOut; return ModbusRTU::erTimeOut;
} }
...@@ -1410,7 +1252,7 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess ...@@ -1410,7 +1252,7 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess
reply.addData(d); reply.addData(d);
else else
reply.addData(0); reply.addData(0);
return ret; return ret;
} }
...@@ -1421,24 +1263,24 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess ...@@ -1421,24 +1263,24 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess
for( int i=0; i<query.count; i++ ) for( int i=0; i<query.count; i++ )
reply.addData( buf[i] ); reply.addData( buf[i] );
} }
return ret; return ret;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::setDateTime( ModbusRTU::SetDateTimeMessage& query, ModbusRTU::mbErrCode MBSlave::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply ) ModbusRTU::SetDateTimeRetMessage& reply )
{ {
return ModbusServer::replySetDateTime(query,reply,&dlog); return ModbusServer::replySetDateTime(query,reply,&dlog);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::remoteService( ModbusRTU::RemoteServiceMessage& query, ModbusRTU::mbErrCode MBSlave::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply ) ModbusRTU::RemoteServiceRetMessage& reply )
{ {
// cerr << "(remoteService): " << query << endl; // cerr << "(remoteService): " << query << endl;
return ModbusRTU::erOperationFailed; return ModbusRTU::erOperationFailed;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::fileTransfer( ModbusRTU::FileTransferMessage& query, ModbusRTU::mbErrCode MBSlave::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply ) ModbusRTU::FileTransferRetMessage& reply )
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
...@@ -1450,16 +1292,16 @@ ModbusRTU::mbErrCode MBSlave::fileTransfer( ModbusRTU::FileTransferMessage& quer ...@@ -1450,16 +1292,16 @@ ModbusRTU::mbErrCode MBSlave::fileTransfer( ModbusRTU::FileTransferMessage& quer
std::string fname(it->second); std::string fname(it->second);
return ModbusServer::replyFileTransfer( fname,query,reply,&dlog ); return ModbusServer::replyFileTransfer( fname,query,reply,&dlog );
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query, ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply ) ReadCoilRetMessage& reply )
{ {
// cout << "(readInputStatus): " << query << endl; // cout << "(readInputStatus): " << query << endl;
return ModbusRTU::erOperationFailed; return ModbusRTU::erOperationFailed;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query, ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply ) ReadInputStatusRetMessage& reply )
{ {
if( dlog.debugging(Debug::INFO) ) if( dlog.debugging(Debug::INFO) )
...@@ -1471,27 +1313,41 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query, ...@@ -1471,27 +1313,41 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
{ {
ModbusRTU::ModbusData d = 0; ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start,d); ModbusRTU::mbErrCode ret = real_read(query.start,d);
reply.addData(0);
if( ret == ModbusRTU::erNoError ) if( ret == ModbusRTU::erNoError )
reply.setBit(0,0,d); reply.addData(d);
else else
reply.setBit(0,0,0); reply.addData(0);
pingOK = true; pingOK = true;
return ret; return ret;
} }
// Фомирование ответа: // Фомирование ответа:
much_real_read(query.start,buf,query.count); much_real_read(query.start,buf,query.count);
int bnum = 0; for( int i=0; i<query.count; i++ )
int i=0; reply.addData( buf[i] );
while( i<query.count ) /*
int num=0; // добавленное количество данных
ModbusRTU::ModbusData d = 0;
ModbusRTU::ModbusData reg = query.start;
for( ; num<query.count; num++, reg++ )
{ {
reply.addData(0); ModbusRTU::mbErrCode ret = real_read(reg,d);
for( int nbit=0; nbit<BitsPerByte && i<query.count; nbit++,i++ ) if( ret == ModbusRTU::erNoError )
reply.setBit(bnum,nbit,buf[i]); reply.addData(d);
bnum++; else
reply.addData(0);
} }
*/
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
// if( reply.bcnt < query.count )
// {
// dlog[Debug::WARN] << myname
// << "(readInputStatus): query.count=" << query.count
// << " > reply.count=" << reply.count << endl;
// }
pingOK = true; pingOK = true;
return ModbusRTU::erNoError; return ModbusRTU::erNoError;
...@@ -1517,117 +1373,22 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query, ...@@ -1517,117 +1373,22 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
if( pingOK ) if( pingOK )
dlog[Debug::CRIT] << myname << "(readInputStatus): catch ..." << endl; dlog[Debug::CRIT] << myname << "(readInputStatus): catch ..." << endl;
} }
pingOK = false; pingOK = false;
return ModbusRTU::erTimeOut; return ModbusRTU::erTimeOut;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query, ModbusRTU::mbErrCode MBSlave::forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query,
ModbusRTU::ForceCoilsRetMessage& reply ) ModbusRTU::ForceCoilsRetMessage& reply )
{ {
if( dlog.debugging(Debug::INFO) ) // cout << "(forceMultipleCoils): " << query << endl;
dlog[Debug::INFO] << myname << "(forceMultipleCoils): " << query << endl; return ModbusRTU::erOperationFailed;
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
int nbit = 0;
for( int i = 0; i<query.bcnt; i++ )
{
ModbusRTU::DataBits b(query.data[i]);
for( int k=0; k<ModbusRTU::BitsPerByte && nbit<query.quant; k++, nbit++ )
{
// ModbusRTU::mbErrCode ret =
real_write(query.start+nbit, (b[k] ? 1 : 0) );
//if( ret == ModbusRTU::erNoError )
}
}
//if( ret == ModbusRTU::erNoError )
if( nbit == query.quant )
reply.set(query.start,query.quant);
return ret;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query, ModbusRTU::mbErrCode MBSlave::forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query,
ModbusRTU::ForceSingleCoilRetMessage& reply ) ModbusRTU::ForceSingleCoilRetMessage& reply )
{ {
if( dlog.debugging(Debug::INFO) ) // cout << "(forceSingleCoil): " << query << endl;
dlog[Debug::INFO] << myname << "(forceSingleCoil): " << query << endl; return ModbusRTU::erOperationFailed;
ModbusRTU::mbErrCode ret = real_write(query.start, (query.cmd() ? 1 : 0) );
if( ret == ModbusRTU::erNoError )
reply.set(query.start,query.data);
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply )
{
if( query.subf == ModbusRTU::subEcho )
{
reply = query;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgBusErrCount )
{
reply = query;
reply.data[0] = errmap[ModbusRTU::erBadCheckSum];
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgMsgSlaveCount || query.subf == ModbusRTU::dgBusMsgCount )
{
reply = query;
reply.data[0] = askCount;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgSlaveNAKCount )
{
reply = query;
reply.data[0] = errmap[erOperationFailed];
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgClearCounters )
{
askCount = 0;
errmap[erOperationFailed] = 0;
errmap[ModbusRTU::erBadCheckSum] = 0;
// другие счётчики пока не сбрасываем..
reply = query;
return ModbusRTU::erNoError;
}
return ModbusRTU::erOperationFailed;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(read4314): " << query << endl;
// if( query.devID <= rdevMinNum || query.devID >= rdevMaxNum )
// return erOperationFailed;
MEIDevIDMap::iterator dit = meidev.find(query.devID);
if( dit == meidev.end() )
return ModbusRTU::erBadDataAddress;
MEIObjIDMap::iterator oit = dit->second.find(query.objID);
if( oit == dit->second.end() )
return ModbusRTU::erBadDataAddress;
reply.mf = 0xFF;
reply.conformity = query.devID;
for( MEIValMap::iterator i=oit->second.begin(); i!=oit->second.end(); i++ )
reply.addData( i->first, i->second );
return erNoError;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
bin_PROGRAMS = @PACKAGE@-rtuexchange mtr-conv uniset-rtu188-state vtconv mtr-setup
URTU_VER=@LIBVER@
lib_LTLIBRARIES = libUniSetRTU.la
libUniSetRTU_la_LDFLAGS = -version-info $(URTU_VER)
libUniSetRTU_la_LIBADD = $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS)
libUniSetRTU_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
libUniSetRTU_la_SOURCES = RTUStorage.cc RTUExchange.cc
@PACKAGE@_rtuexchange_SOURCES = rtuexchange.cc
@PACKAGE@_rtuexchange_LDADD = libUniSetRTU.la $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS)
@PACKAGE@_rtuexchange_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
mtr_conv_SOURCES = mtrconv.cc
mtr_conv_LDADD = $(top_builddir)/extensions/lib/libUniSetExtensions.la $(top_builddir)/lib/libUniSet.la
mtr_conv_CXXFLAGS = -I$(top_builddir)/extensions/include
mtr_setup_SOURCES = mtr-setup.cc
mtr_setup_LDADD = $(top_builddir)/extensions/lib/libUniSetExtensions.la $(top_builddir)/lib/libUniSet.la
mtr_setup_CXXFLAGS = -I$(top_builddir)/extensions/include
vtconv_SOURCES = vtconv.cc
vtconv_LDADD = $(top_builddir)/extensions/lib/libUniSetExtensions.la $(top_builddir)/lib/libUniSet.la
vtconv_CXXFLAGS = -I$(top_builddir)/extensions/include
uniset_rtu188_state_LDADD = libUniSetRTU.la $(top_builddir)/extensions/lib/libUniSetExtensions.la $(top_builddir)/lib/libUniSet.la
uniset_rtu188_state__CXXFLAGS = -I$(top_builddir)/extensions/include
uniset_rtu188_state_SOURCES = rtustate.cc
# install
devel_include_HEADERS = *.h
devel_includedir = $(pkgincludedir)/extensions
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libUniSetRTU.pc
all-local:
ln -sf ../RTUExchange/$(devel_include_HEADERS) ../include
// -----------------------------------------------------------------------------
#include <cmath>
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "RTUExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
RTUExchange::RTUExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
mb(0),
defSpeed(ComPort::ComSpeed0),
use485F(false),
transmitCtl(false),
shm(0),
initPause(0),
force(false),
force_out(false),
mbregFromID(false),
activated(false),
rs_pre_clean(false),
noQueryOptimization(false),
allNotRespond(false)
{
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(RTUExchange): objId=-1?!! Use --rs-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(RTUExchange): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--rs-filter-field");
s_fvalue = conf->getArgParam("--rs-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
// ---------- init RS ----------
// UniXML_iterator it(cnode);
devname = conf->getArgParam("--rs-dev",it.getProp("device"));
if( devname.empty() )
throw UniSetTypes::SystemError(myname+"(RTUExchange): Unknown device..." );
string speed = conf->getArgParam("--rs-speed",it.getProp("speed"));
if( speed.empty() )
speed = "38400";
use485F = conf->getArgInt("--rs-use485F",it.getProp("use485F"));
transmitCtl = conf->getArgInt("--rs-transmit-ctl",it.getProp("transmitCtl"));
defSpeed = ComPort::getSpeed(speed);
recv_timeout = conf->getArgPInt("--rs-recv-timeout",it.getProp("recv_timeout"), 50);
int alltout = conf->getArgPInt("--rs-all-timeout",it.getProp("all_timeout"), 2000);
ptAllNotRespond.setTiming(alltout);
rs_pre_clean = conf->getArgInt("--rs-pre-clean",it.getProp("pre_clean"));
noQueryOptimization = conf->getArgInt("--rs-no-query-optimization",it.getProp("no_query_optimization"));
mbregFromID = conf->getArgInt("--mbs-reg-from-id",it.getProp("reg_from_id"));
dlog[Debug::INFO] << myname << "(init): mbregFromID=" << mbregFromID << endl;
polltime = conf->getArgPInt("--rs-polltime",it.getProp("polltime"), 100);
initPause = conf->getArgPInt("--rs-initPause",it.getProp("initPause"), 3000);
force = conf->getArgInt("--rs-force",it.getProp("force"));
force_out = conf->getArgInt("--rs-force-out",it.getProp("force_out"));
if( shm->isLocalwork() )
{
readConfiguration();
rtuQueryOptimization(rmap);
initDeviceList();
}
else
ic->addReadItem( sigc::mem_fun(this,&RTUExchange::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--rs-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": ID not found ('HeartBeat') for " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--rs-heartbeat-max",it.getProp("heartbeat_max"), 10);
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = conf->getArgPInt("--activate-timeout", 20000);
initMB(false);
printMap(rmap);
// abort();
}
// -----------------------------------------------------------------------------
RTUExchange::~RTUExchange()
{
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
if( it1->second->rtu )
{
delete it1->second->rtu;
it1->second->rtu = 0;
}
RTUDevice* d(it1->second);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
delete it->second;
delete it1->second;
}
delete mb;
delete shm;
}
// -----------------------------------------------------------------------------
void RTUExchange::initMB( bool reopen )
{
if( !file_exist(devname) )
{
if( mb )
{
delete mb;
mb = 0;
}
return;
}
if( mb )
{
if( !reopen )
return;
delete mb;
mb = 0;
}
try
{
mb = new ModbusRTUMaster(devname,use485F,transmitCtl);
if( defSpeed != ComPort::ComSpeed0 )
mb->setSpeed(defSpeed);
// mb->setLog(dlog);
if( recv_timeout > 0 )
mb->setTimeout(recv_timeout);
dlog[Debug::INFO] << myname << "(init): dev=" << devname << " speed=" << ComPort::getSpeed(defSpeed) << endl;
}
catch(...)
{
if( mb )
delete mb;
mb = 0;
}
}
// -----------------------------------------------------------------------------
void RTUExchange::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--rs-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): Не дождались готовности SharedMemory к работе в течение " << ready_timeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void RTUExchange::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
step();
}
// -----------------------------------------------------------------------------
void RTUExchange::step()
{
{
uniset_mutex_lock l(pollMutex,2000);
poll();
}
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void RTUExchange::poll()
{
if( trAllNotRespond.hi(allNotRespond) )
ptAllNotRespond.reset();
if( allNotRespond && mb && ptAllNotRespond.checkTime() )
{
ptAllNotRespond.reset();
initMB(true);
}
if( !mb )
{
initMB(false);
if( !mb )
{
for( RTUExchange::RTUDeviceMap::iterator it=rmap.begin(); it!=rmap.end(); ++it )
it->second->resp_real = false;
}
updateSM();
return;
}
ComPort::Speed s = mb->getSpeed();
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( d->speed != s )
{
s = d->speed;
mb->setSpeed(d->speed);
}
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr) << endl;
if( d->dtype==RTUExchange::dtRTU188 )
{
if( !d->rtu )
continue;
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname << "(pollRTU188): poll RTU188 "
<< " mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< endl;
}
try
{
if( rs_pre_clean )
mb->cleanupChannel();
d->rtu->poll(mb);
d->resp_real = true;
}
catch( ModbusRTU::mbException& ex )
{
if( d->resp_real )
{
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::CRIT] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " -> " << ex << endl;
}
d->resp_real = false;
}
}
}
else
{
d->resp_real = false;
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype==RTUExchange::dtRTU || d->dtype==RTUExchange::dtMTR )
{
if( rs_pre_clean )
mb->cleanupChannel();
if( pollRTU(d,it) )
d->resp_real = true;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; print_plist(dlog(Debug::LEVEL3), it->second->slst);
dlog(Debug::LEVEL3) << " err: " << ex << endl;
}
// d->resp_real = false;
// }
}
if( it==d->regmap.end() )
break;
}
}
}
// update SharedMemory...
updateSM();
// check thresholds
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
RegInfo* r(it->second);
for( PList::iterator i=r->slst.begin(); i!=r->slst.end(); ++i )
IOBase::processingThreshold( &(*i),shm,force);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
bool RTUExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mboffset=" << p->offset
<< " mbfunc=" << p->mbfunc
<< " q_count=" << p->q_count
<< " mb_init=" << p->mb_init
<< endl;
}
if( p->q_count == 0 )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(pollRTU): q_count=0 for mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE register..." << endl;
return false;
}
switch( p->mbfunc )
{
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(dev->mbaddr,p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr, p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadInputStatus:
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m=0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k];
}
it--;
}
break;
case ModbusRTU::fnReadCoilStatus:
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m = 0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k] ? 1 : 0;
}
it--;
}
break;
case ModbusRTU::fnWriteOutputSingleRegister:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE WRITE SINGLE REGISTER (0x06) q_count=" << p->q_count << " ..." << endl;
return false;
}
if( !p->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(p->mbreg) << endl;
ModbusRTU::ReadInputRetMessage ret1 = mb->read04(dev->mbaddr,p->mb_init_mbreg,1);
p->mbval = ret1.data[0];
p->sm_init = true;
return true;
}
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnWriteOutputRegisters:
{
ModbusRTU::WriteOutputMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
{
if( !it->second->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(it->second->mbreg)
// << " mb_init mbreg=" << ModbusRTU::dat2str(it->second->mb_init_mbreg) << endl;
ModbusRTU::ReadOutputRetMessage ret1 = mb->read03(dev->mbaddr,it->second->mb_init_mbreg,1);
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(it->second->mbreg)
// << " mb_init mbreg=" << ModbusRTU::dat2str(it->second->mb_init_mbreg)
// << " mbval=" << ret1.data[0] << endl;
it->second->mbval = ret1.data[0];
it->second->sm_init = true;
}
msg.addData(it->second->mbval);
}
it--;
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
}
break;
case ModbusRTU::fnForceSingleCoil:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE FORCE SINGLE COIL (0x05) q_count=" << p->q_count << " ..." << endl;
return false;
}
if( !p->mb_init )
{
// cerr << "******* mb_init: mbreg=" << ModbusRTU::dat2str(p->mbreg)
// << " init mbreg=" << ModbusRTU::dat2str(p->mb_init_mbreg) << endl;
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,p->mb_init_mbreg,1);
ModbusRTU::DataBits b(ret1.data[0]);
// cerr << "******* mb_init_mbreg=" << ModbusRTU::dat2str(p->mb_init_mbreg)
// << " read val=" << (int)b[0] << endl;
p->mbval = b[0];
p->sm_init = true;
return true;
}
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnForceMultipleCoils:
{
if( !p->mb_init )
{
// every register ask... (for mb_init_mbreg no some)
for( int i=0; i<p->q_count; i++,it++ )
{
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,it->second->mb_init_mbreg,1);
ModbusRTU::DataBits b(ret1.data[0]);
it->second->mbval = b[0] ? 1 : 0;
it->second->sm_init = true;
}
/*
// alone query for all register (if mb_init_mbreg ++ )
ModbusRTU::ReadInputStatusRetMessage ret1 = mb->read02(dev->mbaddr,p->mb_init_mbreg,p->q_count);
int m=0;
for( int i=0; i<ret1.bcnt; i++ )
{
ModbusRTU::DataBits b(ret1.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
{
it->second->mbval = b[k] ? 1 : 0;
it->second->sm_init = true;
}
}
*/
p->sm_init = true;
it--;
return true;
}
ModbusRTU::ForceCoilsMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
msg.addBit( (it->second->mbval ? true : false) );
it--;
// cerr << "*********** (write multiple): " << msg << endl;
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
}
break;
default:
{
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE mfunc=" << (int)p->mbfunc << " ..." << endl;
return false;
}
break;
}
return true;
}
// -----------------------------------------------------------------------------
bool RTUExchange::RTUDevice::checkRespond()
{
bool prev = resp_state;
if( resp_trTimeout.hi(resp_real) )
{
if( resp_real )
resp_state = true;
resp_ptTimeout.reset();
}
if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if( !resp_init )
{
resp_state = resp_real;
resp_init = true;
prev = resp_state;
return true;
}
return ( prev != resp_state );
}
// -----------------------------------------------------------------------------
void RTUExchange::updateSM()
{
allNotRespond = true;
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( dlog.debugging(Debug::LEVEL4) )
{
dlog[Debug::LEVEL4] << "check respond addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " respond=" << d->resp_id
<< " real=" << d->resp_real
<< " state=" << d->resp_state
<< endl;
}
if( d->resp_real )
allNotRespond = false;
// update respond sensors...
if( d->checkRespond() && d->resp_id != DefaultObjectId )
{
try
{
bool set = d->resp_invert ? !d->resp_state : d->resp_state;
shm->localSaveState(d->resp_dit,d->resp_id,set,getId());
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (respond) " << ex << std::endl;
}
}
// cerr << "*********** allNotRespond=" << allNotRespond << endl;
// update values...
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype == dtRTU )
updateRTU(it);
else if( d->dtype == dtMTR )
updateMTR(it);
else if( d->dtype == dtRTU188 )
updateRTU188(it);
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): catch ..." << endl;
}
if( it==d->regmap.end() )
break;
}
}
}
// -----------------------------------------------------------------------------
void RTUExchange::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void RTUExchange::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
if( rmap.empty() )
{
dlog[Debug::CRIT] << myname << "(sysCommand): ************* rmap EMPTY! terminated... *************" << endl;
raise(SIGTERM);
return;
}
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(sysCommand): rmap size= " << rmap.size() << endl;
if( !shm->isLocalwork() )
initDeviceList();
waitSMReady();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
initOutput();
}
// начальная инициализация
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
askTimer(tmExchange,polltime);
break;
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. RTUExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(RTUExchange)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
initOutput();
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
}
break;
case SystemMessage::LogRotate:
{
// переоткрываем логи
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void RTUExchange::initOutput()
{
}
// ------------------------------------------------------------------------------------------
void RTUExchange::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str());
}
if( force_out )
return;
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
try
{
shm->askSensor(i->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): catch..." << std::endl;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void RTUExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
if( sm->id == i->si.id && sm->node == i->si.node )
{
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname<< "(sensorInfo): si.id=" << sm->id
<< " reg=" << ModbusRTU::dat2str(i->reg->mbreg)
<< " val=" << sm->value
<< " mb_init=" << i->reg->mb_init << endl;
}
if( !i->reg->mb_init )
continue;
i->value = sm->value;
updateRSProperty( &(*i),true);
return;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(rmap);
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void RTUExchange::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
/*! \todo Нужно ли выставлять безопасное состояние. МОжно ведь не успеть совершить "обемен" */
// выставление безопасного состояния на выходы....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
if( it->safety == NoSafetyState )
continue;
try
{
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
catch(...){}
}
*/
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void RTUExchange::readConfiguration()
{
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// просто проверка на не пустой field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// просто проверка что field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
RTUExchange::RTUDevice* RTUExchange::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML_iterator& xmlit )
{
RTUDeviceMap::iterator it = mp.find(a);
if( it != mp.end() )
{
DeviceType dtype = getDeviceType(xmlit.getProp("mbtype"));
if( it->second->dtype != dtype )
{
dlog[Debug::CRIT] << myname << "(addDev): OTHER mbtype=" << dtype << " for " << xmlit.getProp("name")
<< ". Already used devtype=" << it->second->dtype
<< " for mbaddr=" << ModbusRTU::addr2str(it->second->mbaddr)
<< endl;
return 0;
}
dlog[Debug::INFO] << myname << "(addDev): device for addr=" << ModbusRTU::addr2str(a)
<< " already added. Ignore device params for " << xmlit.getProp("name") << " ..." << endl;
return it->second;
}
RTUExchange::RTUDevice* d = new RTUExchange::RTUDevice();
d->mbaddr = a;
if( !initRTUDevice(d,xmlit) )
{
delete d;
return 0;
}
mp.insert(RTUDeviceMap::value_type(a,d));
return d;
}
// ------------------------------------------------------------------------------------------
RTUExchange::RegInfo* RTUExchange::addReg( RegMap& mp, ModbusRTU::ModbusData r,
UniXML_iterator& xmlit, RTUExchange::RTUDevice* dev,
RTUExchange::RegInfo* rcopy )
{
RegMap::iterator it = mp.find(r);
if( it != mp.end() )
{
if( !it->second->dev )
{
dlog[Debug::CRIT] << myname << "(addReg): for reg=" << ModbusRTU::dat2str(r)
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
dlog[Debug::CRIT] << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for reg=" << ModbusRTU::dat2str(r)
<< ". Already used devtype=" << it->second->dev->dtype << " for " << it->second->dev << endl;
return 0;
}
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname << "(addReg): reg=" << ModbusRTU::dat2str(r)
<< " already added. Ignore register params for " << xmlit.getProp("name") << " ..." << endl;
}
it->second->rit = it;
return it->second;
}
RTUExchange::RegInfo* ri;
if( rcopy )
{
ri = new RTUExchange::RegInfo(*rcopy);
ri->slst.clear();
ri->mbreg = r;
}
else
{
ri = new RTUExchange::RegInfo();
if( !initRegInfo(ri,xmlit,dev) )
{
delete ri;
return 0;
}
ri->mbreg = r;
}
mp.insert(RegMap::value_type(r,ri));
ri->rit = mp.find(r);
return ri;
}
// ------------------------------------------------------------------------------------------
RTUExchange::RSProperty* RTUExchange::addProp( PList& plist, RSProperty& p )
{
for( PList::iterator it=plist.begin(); it!=plist.end(); ++it )
{
if( it->si.id == p.si.id && it->si.node == p.si.node )
return &(*it);
}
plist.push_back(p);
PList::iterator it = plist.end();
it--;
return &(*it);
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initRSProperty( RSProperty& p, UniXML_iterator& it )
{
if( !IOBase::initItem(&p,it,shm,&dlog,myname) )
return false;
string sbit(it.getProp("nbit"));
if( !sbit.empty() )
{
p.nbit = UniSetTypes::uni_atoi(sbit);
if( p.nbit < 0 || p.nbit >= ModbusRTU::BitsPerData )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbit=" << p.nbit
<< ". (0 >= nbit < " << ModbusRTU::BitsPerData <<")." << endl;
return false;
}
}
if( p.nbit > 0 &&
( p.stype == UniversalIO::AnalogInput ||
p.stype == UniversalIO::AnalogOutput ) )
{
dlog[Debug::WARN] << "(initRSProperty): (ignore) uncorrect param`s nbit>1 (" << p.nbit << ")"
<< " but iotype=" << p.stype << " for " << it.getProp("name") << endl;
}
string sbyte(it.getProp("nbyte"));
if( !sbyte.empty() )
{
p.nbyte = UniSetTypes::uni_atoi(sbyte);
if( p.nbyte < 0 || p.nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbyte=" << p.nbyte
<< ". (0 >= nbyte < " << VTypes::Byte::bsize << ")." << endl;
return false;
}
}
string vt(it.getProp("vtype"));
if( vt.empty() )
{
p.rnum = VTypes::wsize(VTypes::vtUnknown);
p.vType = VTypes::vtUnknown;
}
else
{
VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): Unknown rtuVType=" << vt << " for "
<< it.getProp("name")
<< endl;
return false;
}
p.vType = v;
p.rnum = VTypes::wsize(v);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initRegInfo( RegInfo* r, UniXML_iterator& it, RTUExchange::RTUDevice* dev )
{
r->dev = dev;
r->mbval = it.getIntProp("default");
r->offset= it.getIntProp("mboffset");
r->mb_init = it.getIntProp("mbinit");
if( dev->dtype == RTUExchange::dtMTR )
{
// only for MTR
if( !initMTRitem(it,r) )
return false;
}
else if( dev->dtype == RTUExchange::dtRTU188 )
{ // only for RTU188
if( !initRTU188item(it,r) )
return false;
}
else if( dev->dtype == RTUExchange::dtRTU )
{
}
else
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbtype='" << dev->dtype
<< "' for " << it.getProp("name") << endl;
return false;
}
if( mbregFromID )
r->mbreg = conf->getSensorID(it.getProp("name"));
else if( dev->dtype != RTUExchange::dtRTU188 )
{
string reg = it.getProp("mbreg");
if( reg.empty() )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
r->mbreg = ModbusRTU::str2mbData(reg);
}
else // if( dev->dtype == RTUExchange::dtRTU188 )
{
UniversalIO::IOTypes stype = UniSetTypes::getIOType(it.getProp("iotype"));
r->mbreg = RTUStorage::getRegister(r->rtuJack,r->rtuChan,stype);
if( r->mbreg == -1 )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): (RTU188) unknown mbreg for " << it.getProp("name") << endl;
return false;
}
}
{
string sr = it.getProp("init_mbreg");
if( sr == "-1" )
{
r->mb_init = true; // OFF mb_init
r->sm_init = true;
}
else if( sr.empty() )
r->mb_init_mbreg = r->mbreg;
else
r->mb_init_mbreg = ModbusRTU::str2mbData(sr);
}
r->mbfunc = ModbusRTU::fnUnknown;
string f = it.getProp("mbfunc");
if( !f.empty() )
{
r->mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(f);
if( r->mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbfunc ='" << f
<< "' for " << it.getProp("name") << endl;
return false;
}
}
return true;
}
// ------------------------------------------------------------------------------------------
RTUExchange::DeviceType RTUExchange::getDeviceType( const std::string dtype )
{
if( dtype.empty() )
return dtUnknown;
if( dtype == "mtr" || dtype == "MTR" )
return dtMTR;
if( dtype == "rtu" || dtype == "RTU" )
return dtRTU;
if ( dtype == "rtu188" || dtype == "RTU188" )
return dtRTU188;
return dtUnknown;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initRTUDevice( RTUDevice* d, UniXML_iterator& it )
{
d->dtype = getDeviceType(it.getProp("mbtype"));
if( d->dtype == dtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown mbtype=" << it.getProp("mbtype")
<< ". Use: rtu | mtr | rtu188"
<< " for " << it.getProp("name") << endl;
return false;
}
string addr = it.getProp("mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown mbaddr for " << it.getProp("name") << endl;
return false;
}
d->speed = defSpeed;
d->mbaddr = ModbusRTU::str2mbAddr(addr);
return true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initItem( UniXML_iterator& it )
{
RSProperty p;
if( !initRSProperty(p,it) )
return false;
string addr = it.getProp("mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown mbaddr='" << addr << " for " << it.getProp("name") << endl;
return false;
}
ModbusRTU::ModbusAddr mbaddr = ModbusRTU::str2mbAddr(addr);
RTUDevice* dev = addDev(rmap,mbaddr,it);
if( !dev )
{
dlog[Debug::CRIT] << myname << "(initItem): " << it.getProp("name") << " CAN`T ADD for polling!" << endl;
return false;
}
ModbusRTU::ModbusData mbreg;
if( mbregFromID )
mbreg = p.si.id; // conf->getSensorID(it.getProp("name"));
else if( dev->dtype != RTUExchange::dtRTU188 )
{
string reg = it.getProp("mbreg");
if( reg.empty() )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
else // if( dev->dtype == RTUExchange::dtRTU188 )
{
RegInfo rr;
initRegInfo(&rr,it,dev);
mbreg = RTUStorage::getRegister(rr.rtuJack,rr.rtuChan,p.stype);
if( mbreg == -1 )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
}
RegInfo* ri = addReg(dev->regmap,mbreg,it,dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown word size for " << it.getProp("name") << endl;
return false;
}
}
if( !ri )
return false;
ri->dev = dev;
// п÷п═п·п▓п•п═п п░!
// п╣я│п╩п╦ я└я┐п╫п╨я├п╦я▐ п╫п╟ п╥п╟п©п╦я│я▄, я┌п╬ п╫п╟п╢п╬ п©я─п╬п╡п╣я─п╦я┌я▄
// я┤я┌п╬ п╬п╢п╦п╫ п╦ я┌п╬я┌п╤п╣ я─п╣пЁп╦я│я┌я─ п╫п╣ п©п╣я─п╣п╥п╟п©п╦я┬я┐я┌ п╫п╣я│п╨п╬п╩я▄п╨п╬ п╢п╟я┌я┤п╦п╨п╬п╡
// я█я┌п╬ п╡п╬п╥п╪п╬п╤п╫п╬ я┌п╬п╩я▄п╨п╬, п╣я│п╩п╦ п╬п╫п╦ п©п╦я┬я┐я┌ п╠п╦я┌я▀!!
// п≤п╒п·п⌠:
// п•я│п╩п╦ п╢п╩я▐ я└я┐п╫п╨я├п╦п╧ п╥п╟п©п╦я│п╦ я│п©п╦я│п╬п╨ п╢п╟я┌я┤п╦п╨п╬п╡ п╫п╟ п╬п╢п╦п╫ я─п╣пЁп╦я│я┌я─ > 1
// п╥п╫п╟я┤п╦я┌ п╡ я│п©п╦я│п╨п╣ п╪п╬пЁя┐я┌ п╠я▀я┌я▄ я┌п╬п╩я▄п╨п╬ п╠п╦я┌п╬п╡я▀п╣ п╢п╟я┌я┤п╦п╨п╦
// п╦ п╣я│п╩п╦ п╦п╢я▒я┌ п©п╬п©я▀я┌п╨п╟ п╡п╫п╣я│я┌п╦ п╡ я│п©п╦я│п╬п╨ п╫п╣ п╠п╦я┌п╬п╡я▀п╧ п╢п╟я┌я┤п╦п╨ я┌п╬ п·п╗п≤п▒п п░!
// п≤ п╫п╟п╬п╠п╬я─п╬я┌: п╣я│п╩п╦ п╦п╢я▒я┌ п©п╬п©я▀я┌п╨п╟ п╡п╫п╣я│я┌п╦ п╠п╦я┌п╬п╡я▀п╧ п╢п╟я┌я┤п╦п╨, п╟ п╡ я│п©п╦я│п╨п╣
// я┐п╤п╣ я│п╦п╢п╦я┌ п╢п╟я┌я┤п╦п╨ п╥п╟п╫п╦п╪п╟я▌я┴п╦п╧ я├п╣п╩я▀п╧ я─п╣пЁп╦я│я┌я─, я┌п╬ я┌п╬п╤п╣ п·п╗п≤п▒п п░!
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
if( p.nbit<0 && ri->slst.size() > 1 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (not bit saving) to "
<< " mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
if( p.nbit >= 0 && ri->slst.size() == 1 )
{
PList::iterator it2 = ri->slst.begin();
if( it2->nbit < 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (mbreg="
<< ModbusRTU::dat2str(ri->mbreg) << " already used)!"
<< " IGNORE --> " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
}
}
RSProperty* p1 = addProp(ri->slst,p);
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
for( int i=1; i<p1->rnum; i++ )
{
RTUExchange::RegInfo* ri1 = addReg(dev->regmap,mbreg+i,it,dev,ri);
ri1->mb_init_mbreg = ri->mb_init_mbreg+i;
}
}
if( dev->dtype == dtRTU188 )
{
if( !dev->rtu )
dev->rtu = new RTUStorage(mbaddr);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initMTRitem( UniXML_iterator& it, RegInfo* p )
{
p->mtrType = MTR::str2type(it.getProp("mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
dlog[Debug::CRIT] << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp("mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool RTUExchange::initRTU188item( UniXML_iterator& it, RegInfo* p )
{
string jack = it.getProp("jack");
string chan = it.getProp("channel");
if( jack.empty() )
{
dlog[Debug::CRIT] << myname << "(readRTU188Item): Unknown jack='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuJack = RTUStorage::s2j(jack);
if( p->rtuJack == RTUStorage::nUnknown )
{
dlog[Debug::CRIT] << myname << "(readRTU188Item): Unknown jack=" << jack
<< " for " << it.getProp("name") << endl;
return false;
}
if( chan.empty() )
{
dlog[Debug::CRIT] << myname << "(readRTU188Item): Unknown channel='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuChan = UniSetTypes::uni_atoi(chan);
if( dlog.debugging(Debug::LEVEL2) )
dlog[Debug::LEVEL2] << myname << "(readRTU188Item): " << p << endl;
return true;
}
// -----------------------------------------------------------------------------
void RTUExchange::initIterators()
{
shm->initAIterator(aitHeartBeat);
for( RTUExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
shm->initDIterator(d->resp_dit);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
for( PList::iterator it2=it->second->slst.begin();it2!=it->second->slst.end(); ++it2 )
{
shm->initDIterator(it2->dit);
shm->initAIterator(it2->ait);
}
}
}
}
// -----------------------------------------------------------------------------
void RTUExchange::help_print( int argc, const char* const* argv )
{
cout << "--rs-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек." << endl;
cout << "--rs-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--rs-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--rs-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--rs-force - Сохранять значения в SM, независимо от, того менялось ли значение" << endl;
cout << "--rs-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--rs-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола RS: " << endl;
cout << "--rs-dev devname - файл устройства" << endl;
cout << "--rs-speed - Скорость обмена (9600,19920,38400,57600,115200)." << endl;
cout << "--rs-my-addr - адрес текущего узла" << endl;
cout << "--rs-recv-timeout - Таймаут на ожидание ответа." << endl;
}
// -----------------------------------------------------------------------------
RTUExchange* RTUExchange::init_rtuexchange( int argc, const char* const* argv, UniSetTypes::ObjectId icID, SharedMemory* ic )
{
string name = conf->getArgParam("--rs-name","RTUExchange1");
if( name.empty() )
{
cerr << "(rtuexchange): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(rtuexchange): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(rtuexchange): name = " << name << "(" << ID << ")" << endl;
return new RTUExchange(ID,icID,ic);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const RTUExchange::DeviceType& dt )
{
switch(dt)
{
case RTUExchange::dtRTU:
os << "RTU";
break;
case RTUExchange::dtRTU188:
os << "RTU188";
break;
case RTUExchange::dtMTR:
os << "MTR";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const RTUExchange::RSProperty& p )
{
os << " (" << ModbusRTU::dat2str(p.reg->mbreg) << ")"
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " nbit=" << p.nbit
<< " nbyte=" << p.nbyte
<< " rnum=" << p.rnum
<< " safety=" << p.safety
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AnalogInput || p.stype == UniversalIO::AnalogOutput )
{
os << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void RTUExchange::initDeviceList()
{
xmlNode* respNode = conf->findNode(cnode,"DeviceList");
if( respNode )
{
UniXML_iterator it1(respNode);
if( it1.goChildren() )
{
for(;it1.getCurrent(); it1.goNext() )
{
ModbusRTU::ModbusAddr a = ModbusRTU::str2mbAddr(it1.getProp("addr"));
initDeviceInfo(rmap,a,it1);
}
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> empty section..." << endl;
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> not found..." << endl;
}
// -----------------------------------------------------------------------------
bool RTUExchange::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it )
{
RTUDeviceMap::iterator d = m.find(a);
if( d == m.end() )
{
dlog[Debug::WARN] << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
if( !it.getProp("respondSensor").empty() )
{
d->second->resp_id = conf->getSensorID(it.getProp("respondSensor"));
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << it.getProp("respondSensor") << endl;
return false;
}
}
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout", UniSetTimer::WaitUpTime);
d->second->resp_ptTimeout.setTiming(tout);
d->second->resp_invert = it.getIntProp("invert");
string s = it.getProp("speed");
if( !s.empty() )
{
d->second->speed = ComPort::getSpeed(s);
if( d->second->speed == ComPort::ComSpeed0 )
{
d->second->speed = defSpeed;
dlog[Debug::CRIT] << myname << "(initDeviceInfo): Unknown speed=" << s <<
" for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
}
return true;
}
// -----------------------------------------------------------------------------
void RTUExchange::printMap( RTUExchange::RTUDeviceMap& m )
{
cout << "devices: num=" << m.size() << endl;
for( RTUExchange::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
cout << " " << *(it->second) << endl;
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, RTUExchange::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( RTUExchange::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
os << " " << *(it->second) << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, RTUExchange::RTUDevice& d )
{
os << "addr=" << ModbusRTU::addr2str(d.mbaddr)
<< " type=" << d.dtype;
os << " rtu=" << (d.rtu ? "yes" : "no" );
os << " respond_id=" << d.resp_id
<< " respond_timeout=" << d.resp_ptTimeout.getInterval()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< endl;
os << " regs: " << endl;
for( RTUExchange::RegMap::iterator it=d.regmap.begin(); it!=d.regmap.end(); ++it )
os << " " << *(it->second) << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, RTUExchange::RegInfo& r )
{
os << " mbreg=" << ModbusRTU::dat2str(r.mbreg)
<< " mbfunc=" << r.mbfunc
<< " mtrType=" << MTR::type2str(r.mtrType)
<< " jack=" << RTUStorage::j2s(r.rtuJack)
<< " chan=" << r.rtuChan
<< " q_num=" << r.q_num
<< " q_count=" << r.q_count
<< " value=" << ModbusRTU::dat2str(r.mbval) << "(" << (int)r.mbval << ")"
<< endl;
for( RTUExchange::PList::iterator it=r.slst.begin(); it!=r.slst.end(); ++it )
os << " " << (*it) << endl;
return os;
}
// -----------------------------------------------------------------------------
void RTUExchange::rtuQueryOptimization( RTUDeviceMap& m )
{
if( noQueryOptimization )
return;
dlog[Debug::INFO] << myname << "(rtuQueryOptimization): optimization..." << endl;
for( RTUExchange::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( RTUExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
RTUExchange::RegMap::iterator beg = it;
ModbusRTU::ModbusData reg = it->second->mbreg + it->second->offset;
beg->second->q_num = 1;
beg->second->q_count = 1;
it++;
for( ;it!=d->regmap.end(); ++it )
{
if( (it->second->mbreg + it->second->offset - reg) > 1 )
break;
if( beg->second->mbfunc != it->second->mbfunc )
break;
beg->second->q_count++;
if( beg->second->q_count >= ModbusRTU::MAXDATALEN )
break;
reg = it->second->mbreg + it->second->offset;
it->second->q_num = beg->second->q_count;
it->second->q_count = 0;
}
// check correct function...
if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnWriteOutputSingleRegister )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnWriteOutputSingleRegister
<< " <--> func=" << ModbusRTU::fnWriteOutputRegisters
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnForceSingleCoil )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnForceSingleCoil
<< " <--> func=" << ModbusRTU::fnForceMultipleCoils
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnForceMultipleCoils;
}
if( it==d->regmap.end() )
break;
it--;
}
}
}
// -----------------------------------------------------------------------------
void RTUExchange::updateRTU( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
updateRSProperty( &(*it),false );
if( r->sm_init )
r->mb_init = true;
}
// -----------------------------------------------------------------------------
void RTUExchange::updateRSProperty( RSProperty* p, bool write_only )
{
using namespace ModbusRTU;
RegInfo* r(p->reg->rit->second);
bool save = isWriteFunction( r->mbfunc );
if( !save && write_only )
return;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(r->mbval);
if( p->nbit >= 0 )
{
if( save && r->mb_init )
{
bool set = IOBase::processingAsDO( p, shm, force_out );
b.set(p->nbit,set);
r->mbval = b.mdata();
}
else
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
}
return;
}
if( p->rnum <= 1 )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
IOBase::processingAsAI( p, (signed short)r->mbval, shm, force );
}
return;
}
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: rnum=" << p->rnum
<< " > 1 ?!! for id=" << p->si.id << endl;
return;
}
else if( p->vType == VTypes::vtSigned )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (signed short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (signed short)IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (signed short)(r->mbval), shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( save && r->mb_init )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (unsigned short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (unsigned short)IOBase::processingAsAO( p, shm, force_out );
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (unsigned short)r->mbval, shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtByte )
{
if( p->nbyte <= 0 || p->nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: reg=" << ModbusRTU::dat2str(r->mbreg)
<< " vtype=" << p->vType << " but nbyte=" << p->nbyte << endl;
return;
}
if( save && r->mb_init )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::Byte b(r->mbval);
b.raw.b[p->nbyte-1] = v;
r->mbval = b.raw.w;
}
else
{
VTypes::Byte b(r->mbval);
IOBase::processingAsAI( p, b.raw.b[p->nbyte-1], shm, force );
}
return;
}
else if( p->vType == VTypes::vtF2 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F2 f2(f);
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
i->second->mbval = f2.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F2::wsize()];
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F2 f(data,VTypes::F2::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
else if( p->vType == VTypes::vtF4 )
{
RegMap::iterator i(p->reg->rit);
if( save && r->mb_init )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F4 f4(f);
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
i->second->mbval = f4.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F4::wsize()];
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F4 f(data,VTypes::F4::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): catch ..." << endl;
}
}
// -----------------------------------------------------------------------------
void RTUExchange::updateMTR( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
{
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
{
try
{
if( r->mtrType == MTR::mtT1 )
{
if( save )
r->mbval = IOBase::processingAsAO( &(*it), shm, force_out );
else
{
MTR::T1 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT2 )
{
if( save )
{
MTR::T2 t(IOBase::processingAsAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T2 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT3 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T3 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T3::wsize()];
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T3 t(data,MTR::T3::wsize());
delete[] data;
IOBase::processingAsAI( &(*it), (long)t, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT4 )
{
if( save )
cerr << myname << "(updateMTR): write (T4) reg(" << dat2str(r->mbreg) << ") to MTR NOT YET!!!" << endl;
else
{
MTR::T4 t(r->mbval);
IOBase::processingAsAI( &(*it), uni_atoi(t.sval), shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT5 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T5 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T5::wsize()];
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T5 t(data,MTR::T5::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT6 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T6 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T6::wsize()];
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T6 t(data,MTR::T6::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT7 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T7 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T7::wsize()];
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T7 t(data,MTR::T7::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT16 )
{
if( save )
{
MTR::T16 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T16 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT17 )
{
if( save )
{
MTR::T17 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T17 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtF1 )
{
RegMap::iterator i(rit);
if( save )
{
float f = IOBase::processingFasAO( &(*it), shm, force_out );
MTR::F1 f1(f);
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
i->second->mbval = f1.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::F1::wsize()];
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::F1 t(data,MTR::F1::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t, shm, force );
}
continue;
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): catch ..." << endl;
}
}
}
}
// -----------------------------------------------------------------------------
void RTUExchange::updateRTU188( RegMap::iterator& it )
{
RegInfo* r(it->second);
if( !r->dev->rtu )
return;
using namespace ModbusRTU;
// bool save = false;
if( isWriteFunction(r->mbfunc) )
{
// save = true;
cerr << myname << "(updateRTU188): write reg(" << dat2str(r->mbreg) << ") to RTU188 NOT YET!!!" << endl;
return;
}
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
{
try
{
if( it->stype == UniversalIO::DigitalInput )
{
bool set = r->dev->rtu->getState(r->rtuJack,r->rtuChan,it->stype);
IOBase::processingAsDI( &(*it), set, shm, force );
continue;
}
if( it->stype == UniversalIO::AnalogInput )
{
long val = r->dev->rtu->getInt(r->rtuJack,r->rtuChan,it->stype);
IOBase::processingAsAI( &(*it),val, shm, force );
continue;
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateRTU188): catch ..." << endl;
}
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBTCPMaster::PList& lst )
std::ostream& RTUExchange::print_plist( std::ostream& os, RTUExchange::PList& lst )
{
os << "[ ";
for( RTUExchange::PList::const_iterator it=lst.begin(); it!=lst.end(); ++it )
os << "(" << it->si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(it->si.id)) << " ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
// $Id: RTUExchange.h,v 1.2 2009/01/11 19:08:45 vpashka Exp $
// -----------------------------------------------------------------------------
#ifndef _RTUEXCHANGE_H_
#define _RTUEXCHANGE_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <map>
#include <vector>
#include "IONotifyController.h"
#include "UniSetObject_LT.h"
#include "modbus/ModbusRTUMaster.h"
#include "PassiveTimer.h"
#include "Trigger.h"
#include "Mutex.h"
#include "Calibration.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "MTR.h"
#include "RTUStorage.h"
#include "IOBase.h"
#include "VTypes.h"
// -----------------------------------------------------------------------------
class RTUExchange:
public UniSetObject_LT
{
public:
RTUExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~RTUExchange();
/*! глобальная функция для инициализации объекта */
static RTUExchange* init_rtuexchange( int argc, const char* const* argv,
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, const char* const* argv );
static const int NoSafetyState=-1;
enum Timer
{
tmExchange
};
enum DeviceType
{
dtUnknown, /*!< неизвестный */
dtRTU, /*!< RTU (default) */
dtRTU188, /*!< RTU188 (Fastwell) */
dtMTR /*!< MTR (DEIF) */
};
static DeviceType getDeviceType( const std::string dtype );
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
// -------------------------------------------------------------------------------
struct RTUDevice;
struct RegInfo;
struct RSProperty:
public IOBase
{
// only for RTU
short nbit; /*!< bit number) */
VTypes::VType vType; /*!< type of value */
short rnum; /*!< count of registers */
short nbyte; /*!< byte number (1-2) */
RSProperty():
nbit(-1),vType(VTypes::vtUnknown),
rnum(VTypes::wsize(VTypes::vtUnknown)),
nbyte(0),reg(0)
{}
RegInfo* reg;
};
friend std::ostream& operator<<( std::ostream& os, const RSProperty& p );
typedef std::list<RSProperty> PList;
static std::ostream& print_plist( std::ostream& os, PList& p );
typedef std::map<ModbusRTU::ModbusData,RegInfo*> RegMap;
struct RegInfo
{
RegInfo():
mbval(0),mbreg(0),mbfunc(ModbusRTU::fnUnknown),
mtrType(MTR::mtUnknown),
rtuJack(RTUStorage::nUnknown),rtuChan(0),
dev(0),offset(0),
q_num(0),q_count(1),mb_init(false),sm_init(false),
mb_init_mbreg(0)
{}
ModbusRTU::ModbusData mbval;
ModbusRTU::ModbusData mbreg; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< функция для чтения/записи */
PList slst;
// only for MTR
MTR::MTRType mtrType; /*!< тип регистра (согласно спецификации на MTR) */
// only for RTU188
RTUStorage::RTUJack rtuJack;
int rtuChan;
RTUDevice* dev;
int offset;
// optimization
int q_num; /*! number in query */
int q_count; /*! count registers for query */
RegMap::iterator rit;
bool mb_init; /*!< init before use */
bool sm_init; /*!< SM init value */
ModbusRTU::ModbusData mb_init_mbreg; /*!< mb_init register */
};
friend std::ostream& operator<<( std::ostream& os, RegInfo& r );
struct RTUDevice
{
RTUDevice():
speed(ComPort::ComSpeed38400),
respnond(false),
mbaddr(0),
dtype(dtUnknown),
resp_id(UniSetTypes::DefaultObjectId),
resp_state(false),
resp_invert(false),
resp_real(false),
resp_init(false),
rtu(0)
{
resp_trTimeout.change(false);
}
ComPort::Speed speed;
bool respnond;
ModbusRTU::ModbusAddr mbaddr; /*!< адрес устройства */
RegMap regmap;
DeviceType dtype; /*!< тип устройства */
UniSetTypes::ObjectId resp_id;
IOController::DIOStateList::iterator resp_dit;
PassiveTimer resp_ptTimeout;
Trigger resp_trTimeout;
bool resp_state;
bool resp_invert;
bool resp_real;
bool resp_init;
RTUStorage* rtu;
// return TRUE if state changed
bool checkRespond();
};
friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
typedef std::map<ModbusRTU::ModbusAddr,RTUDevice*> RTUDeviceMap;
friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
void printMap(RTUDeviceMap& d);
// ----------------------------------
protected:
RTUDeviceMap rmap;
ModbusRTUMaster* mb;
UniSetTypes::uniset_mutex mbMutex;
std::string devname;
ComPort::Speed defSpeed;
int recv_timeout;
bool use485F;
bool transmitCtl;
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void step();
void poll();
bool pollRTU( RTUDevice* dev, RegMap::iterator& it );
void updateSM();
void updateRTU(RegMap::iterator& it);
void updateMTR(RegMap::iterator& it);
void updateRTU188(RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only=false );
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void timerInfo( UniSetTypes::TimerMessage *tm );
void askSensors( UniversalIO::UIOCommand cmd );
void initOutput();
void waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initMB( bool reopen=false );
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void initDeviceList();
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
RegInfo* addReg( RegMap& rmap, ModbusRTU::ModbusData r, UniXML_iterator& it,
RTUDevice* dev, RegInfo* rcopy=0 );
RSProperty* addProp( PList& plist, RSProperty& p );
bool initMTRitem( UniXML_iterator& it, RegInfo* p );
bool initRTU188item( UniXML_iterator& it, RegInfo* p );
bool initRSProperty( RSProperty& p, UniXML_iterator& it );
bool initRegInfo( RegInfo* r, UniXML_iterator& it, RTUDevice* dev );
bool initRTUDevice( RTUDevice* d, UniXML_iterator& it );
bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
void rtuQueryOptimization( RTUDeviceMap& m );
void readConfiguration();
bool check_item( UniXML_iterator& it );
private:
RTUExchange();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
bool force; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */
bool force_out; /*!< флаг означающий, принудительного чтения выходов */
bool mbregFromID;
int polltime; /*!< переодичность обновления данных, [мсек] */
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
UniSetTypes::uniset_mutex pollMutex;
bool activated;
int activateTimeout;
bool rs_pre_clean;
bool noQueryOptimization;
bool allNotRespond;
Trigger trAllNotRespond;
PassiveTimer ptAllNotRespond;
};
// -----------------------------------------------------------------------------
#endif // _RS_EXCHANGE_H_
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include "modbus/ModbusRTUMaster.h"
#include "RTUStorage.h"
// -----------------------------------------------------------------------------
using namespace std;
// -----------------------------------------------------------------------------
RTUStorage::RTUStorage( ModbusRTU::ModbusAddr a ):
addr(a),
pingOK(false),
pollADC(true),
pollDI(true),
pollDIO(true),
pollUNIO(true)
{
memset(adc,0,sizeof(adc));
memset(di,0,sizeof(di));
memset(dio_do,0,sizeof(dio_do));
memset(dio_di,0,sizeof(dio_di));
memset(dio_ai,0,sizeof(dio_ai));
memset(dio_ao,0,sizeof(dio_ao));
memset(unio_di,0,sizeof(unio_di));
memset(unio_do,0,sizeof(unio_do));
memset(unio_ai,0,sizeof(unio_ai));
memset(unio_ao,0,sizeof(unio_ao));
}
// -----------------------------------------------------------------------------
RTUStorage::~RTUStorage()
{
}
// -----------------------------------------------------------------------------
void RTUStorage::poll( ModbusRTUMaster* mb )
throw( ModbusRTU::mbException )
{
try
{
pingOK = true;
// опрос АЦП
if( pollADC )
{
ModbusRTU::ReadInputRetMessage ret = mb->read04( addr,1016, 16 );
for( int i=0,k=0; i<16; i+=2,k++ )
adc[k] = ModbusRTU::dat2f(ret.data[i],ret.data[i+1]);
}
// -----------------------------------
// опрос 16 DI
if( pollDI )
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02( addr,0,16 );
ModbusRTU::DataBits bits;
for( int b=0; b<2; b++ )
{
if( ret.getData(b,bits) )
{
for( int i=0; i<8; i++ )
di[i+8*b] = bits[i];
}
}
}
// -----------------------------------
// опрос 16DIO DO
if( pollDIO )
{
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01( addr,0,16 );
ModbusRTU::DataBits bits;
for( int b=0; b<2; b++ )
{
if( ret.getData(b,bits) )
{
for( int i=0; i<8; i++ )
dio_do[i+8*b] = bits[i];
}
}
}
// -----------------------------------
// опрос 16DIO DI
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02( addr,16,16 );
ModbusRTU::DataBits bits;
for( int b=0; b<2; b++ )
{
if( ret.getData(b,bits) )
{
for( int i=0; i<8; i++ )
dio_di[i+8*b] = bits[i];
}
}
}
// -----------------------------------
// опрос 16DIO AI
{
ModbusRTU::ReadInputRetMessage ret = mb->read04( addr, 1000, 16 );
int k = 0;
for( int i=0; i<16; i+=2,k++ )
dio_ai[k] = ModbusRTU::dat2f(ret.data[i],ret.data[i+1]);
}
// -----------------------------------
// опрос 16DIO AO
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03( addr, 1000, 16 );
int k = 0;
for( int i=0; i<16; i+=2,k++ )
dio_ao[k] = ModbusRTU::dat2f(ret.data[i],ret.data[i+1]);
}
// -----------------------------------
}
// опрос UNIO48 DO
if( pollUNIO )
{
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01( addr,16,48 );
ModbusRTU::DataBits bits;
for( int b=0; b<8; b++ )
{
if( ret.getData(b,bits) )
{
for( int i=0; i<8; i++ )
unio_do[i+8*b] = bits[i];
}
}
}
// -----------------------------------
// опрос UNIO48 DI
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02( addr,32,48 );
ModbusRTU::DataBits bits;
for( int b=0; b<8; b++ )
{
if( ret.getData(b,bits) )
{
for( int i=0; i<8; i++ )
unio_di[i+8*b] = bits[i];
}
}
}
// -----------------------------------
// опрос UNIO48 AI
{
ModbusRTU::ReadInputRetMessage ret = mb->read04( addr, 1032, 48 );
int k = 0;
for( int i=0; i<48; i+=2,k++ )
unio_ai[k] = ModbusRTU::dat2f(ret.data[i],ret.data[i+1]);
}
// -----------------------------------
// опрос UNIO48 AO
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03( addr, 1016, 48 );
int k = 0;
for( int i=0; i<48; i+=2,k++ )
unio_ao[k] = ModbusRTU::dat2f(ret.data[i],ret.data[i+1]);
}
}
}
catch(...)
{
pingOK = false;
throw;
}
}
// -----------------------------------------------------------------------------
long RTUStorage::getInt( RTUJack jack, unsigned short int chan, UniversalIO::IOTypes t )
{
return lroundf( getFloat(jack,chan,t) );
}
// -----------------------------------------------------------------------------
float RTUStorage::getFloat( RTUJack jack, unsigned short int chan, UniversalIO::IOTypes t )
{
if( t == UniversalIO::AnalogInput )
{
switch( jack )
{
case nJ1:
return unio_ai[chan];
case nJ2:
return unio_ai[24+chan];
case nJ5:
return dio_ai[chan];
case nX1:
return adc[chan];
case nX2:
return adc[4+chan];
default:
break;
}
return 0;
}
if( t == UniversalIO::AnalogOutput )
{
switch( jack )
{
case nJ1:
return unio_ao[chan];
case nJ2:
return unio_ao[24+chan];
case nJ5:
return dio_ao[chan];
case nX1:
return adc[chan];
case nX2:
return adc[4+chan];
default:
break;
}
return 0;
}
return 0;
}
// -----------------------------------------------------------------------------
bool RTUStorage::getState( RTUJack jack, unsigned short int chan, UniversalIO::IOTypes t )
{
if( t == UniversalIO::DigitalInput )
{
switch( jack )
{
case nJ1:
return unio_di[chan];
case nJ2:
return unio_di[24+chan];
case nJ5:
return dio_di[chan];
case nX4:
return di[chan];
case nX5:
return di[8+chan];
default:
break;
}
return false;
}
if( t == UniversalIO::DigitalOutput )
{
switch( jack )
{
case nJ1:
return unio_do[chan];
case nJ2:
return unio_do[24+chan];
case nJ5:
return dio_do[chan];
default:
break;
}
return false;
}
return false;
}
// -----------------------------------------------------------------------------
ModbusRTU::ModbusData RTUStorage::getRegister( RTUJack jack, unsigned short chan, UniversalIO::IOTypes t )
{
if( t == UniversalIO::AnalogInput )
{
switch( jack )
{
case nJ1:
return 1032+chan;
case nJ2:
return 1032+24+chan;
case nJ5:
return 1000+chan;
case nX1:
return 1016+chan;
case nX2:
return 1016+4+chan;
default:
break;
}
return -1;
}
if( t == UniversalIO::AnalogOutput )
{
switch( jack )
{
case nJ1:
return 1016+chan;
case nJ2:
return 1016+24+chan;
case nJ5:
return 1000+chan;
case nX1:
return 1016+chan;
case nX2:
return 1016+4+chan;
default:
break;
}
return -1;
}
if( t == UniversalIO::DigitalInput )
{
switch( jack )
{
case nJ1:
return 32+chan;
case nJ2:
return 32+24+chan;
case nJ5:
return 16+chan;
case nX4:
return chan;
case nX5:
return 8+chan;
default:
break;
}
return -1;
}
if( t == UniversalIO::DigitalOutput )
{
switch( jack )
{
case nJ1:
return 16+chan;
case nJ2:
return 16+24+chan;
case nJ5:
return chan;
default:
break;
}
return -1;
}
return -1;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, RTUStorage& m )
{
os << "-------------------" << endl
<< " АЦП (8 каналов): " << endl;
for( int i=0; i<8; i++ ) // номера каналов
os << setw(12) << i << "|";
os << endl;
for( int i=0; i<8; i++ )
os << setw(12) << m.adc[i] << "|";
os << endl;
os << "-------------------" << endl
<< " DI (16 каналов): " << endl;
for( int i=0; i<16; i++ ) // номера каналов
os << setw(2) << i << "|";
os << endl;
for( int i=0; i<16; i++ )
os << setw(2) << m.di[i] << "|";
os << endl;
os << "-------------------" << endl
<< " DIO DO(16 каналов): " << endl;
for( int i=0; i<16; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<16; i++ )
os << setw(2) << m.dio_do[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " DIO DI(16 каналов): " << endl;
for( int i=0; i<16; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<16; i++ )
os << setw(2) << m.dio_di[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " DIO AI (16 каналов): " << endl;
for( int i=0; i<16; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<16; i++ )
os << setw(2) << m.dio_ai[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " DIO AO (16 каналов): " << endl;
for( int i=0; i<16; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<16; i++ )
os << setw(2) << m.dio_ao[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " UNIO48 DI: " << endl;
for( int i=0; i<24; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<24; i++ )
os << setw(2) << m.unio_di[i] << " | ";
os << endl;
for( int i=24; i<48; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=24; i<48; i++ )
os << setw(2) << m.unio_di[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " UNIO48 DO: " << endl;
for( int i=0; i<24; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=0; i<24; i++ )
os << setw(2) << m.unio_do[i] << " | ";
os << endl;
for( int i=24; i<48; i++ ) // номера каналов
os << setw(2) << i << " | ";
os << endl;
for( int i=24; i<48; i++ )
os << setw(2) << m.unio_do[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " UNIO48 AI: " << endl;
for( int i=0; i<12; i++ ) // номера каналов
os << setw(6) << i << " | ";
os << endl;
for( int i=0; i<12; i++ )
os << setw(6) << m.unio_ai[i] << " | ";
os << endl;
for( int i=12; i<24; i++ ) // номера каналов
os << setw(6) << i << " | ";
os << endl;
for( int i=12; i<24; i++ )
os << setw(6) << m.unio_ai[i] << " | ";
os << endl;
os << "-------------------" << endl
<< " UNIO48 AO: " << endl;
for( int i=0; i<12; i++ ) // номера каналов
os << setw(6) << i << " | ";
os << endl;
for( int i=0; i<12; i++ )
os << setw(6) << m.unio_ao[i] << " | ";
os << endl;
for( int i=12; i<24; i++ ) // номера каналов
os << setw(6) << i << " | ";
os << endl;
for( int i=12; i<24; i++ )
os << setw(6) << m.unio_ao[i] << " | ";
os << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, RTUStorage* m )
{
return os << (*m);
}
// -----------------------------------------------------------------------------
void RTUStorage::print()
{
cout << this;
}
// -----------------------------------------------------------------------------
RTUStorage::RTUJack RTUStorage::s2j( const std::string jack )
{
if( jack == "J1" )
return nJ1;
if( jack == "J2" )
return nJ2;
if( jack == "J5" )
return nJ5;
if( jack == "X1" )
return nX1;
if( jack == "X2" )
return nX2;
if( jack == "X4" )
return nX4;
if( jack == "X5" )
return nX5;
return nUnknown;
}
// -----------------------------------------------------------------------------
std::string RTUStorage::j2s( RTUStorage::RTUJack jack )
{
if( jack == nJ1 )
return "J1";
if( jack == nJ2 )
return "J2";
if( jack == nJ5 )
return "J5";
if( jack == nX1 )
return "X1";
if( jack == nX2 )
return "X2";
if( jack == nX4 )
return "X4";
if( jack == nX5 )
return "X5";
return "";
}
// -----------------------------------------------------------------------------
// --------------------------------------------------------------------------
//! \version $Id: RTUStorage.h,v 1.1 2008/12/14 21:57:50 vpashka Exp $
// --------------------------------------------------------------------------
#ifndef _RTUSTORAGE_H_
#define _RTUSTORAGE_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include "modbus/ModbusTypes.h"
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
class ModbusRTUMaster;
// -----------------------------------------------------------------------------
class RTUStorage
{
public:
RTUStorage( ModbusRTU::ModbusAddr addr );
~RTUStorage();
void poll( ModbusRTUMaster* mb )
throw(ModbusRTU::mbException);
inline ModbusRTU::ModbusAddr getAddress(){ return addr; }
inline bool ping(){ return pingOK; }
inline void setPollADC( bool set ){ pollADC = set; }
inline void setPollDI( bool set ){ pollDI = set; }
inline void setPollDIO( bool set ){ pollDIO = set; }
inline void setPollUNIO( bool set ){ pollUNIO = set; }
enum RTUJack
{
nUnknown,
nJ1, // UNIO48 (FPGA0)
nJ2, // UNIO48 (FPGA1)
nJ5, // DIO 16
nX1, // АЦП (8)
nX2, // АЦП (8)
nX4, // DI (8)
nX5 // DI (8)
};
static RTUJack s2j( const std::string jack );
static std::string j2s( RTUJack j );
long getInt( RTUJack jack, unsigned short channel, UniversalIO::IOTypes t );
float getFloat( RTUJack jack, unsigned short channel, UniversalIO::IOTypes t );
bool getState( RTUJack jack, unsigned short channel, UniversalIO::IOTypes t );
static ModbusRTU::ModbusData getRegister( RTUJack jack, unsigned short channel, UniversalIO::IOTypes t );
// ДОДЕЛАТЬ: setState, setValue
void print();
friend std::ostream& operator<<(std::ostream& os, RTUStorage& m );
friend std::ostream& operator<<(std::ostream& os, RTUStorage* m );
protected:
ModbusRTU::ModbusAddr addr;
bool pingOK;
bool pollADC;
bool pollDI;
bool pollDIO;
bool pollUNIO;
float adc[8]; // АЦП
bool di[16]; // Порт 16DI
bool dio_do[16]; // Порт 16DIO DO
bool dio_di[16]; // Порт 16DIO DI
float dio_ai[16]; // Порт 16DIO AI
float dio_ao[16]; // Порт 16DIO AO
bool unio_do[48]; // Порт UNIO48 DO
bool unio_di[48]; // Порт UNIO48 DI
float unio_ai[24]; // Порт UNIO48 AI
float unio_ao[24]; // Порт UNIO48 AO
};
// --------------------------------------------------------------------------
#endif // _RTUSTORAGE_H_
// -----------------------------------------------------------------------------
#!/bin/sh
ln -s -f ../../Utilities/scripts/uniset-start.sh
ln -s -f ../../Utilities/scripts/uniset-stop.sh stop.sh
ln -s -f ../../Utilities/scripts/uniset-functions.sh
ln -s -f ../../conf/test.xml test.xml
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetRTU
Description: Support library for UniSetRTUExchange
Requires: libUniSetExtensions
Version: @VERSION@
Libs: -L${libdir} -lUniSetRTU
Cflags: -I${includedir}/uniset
// --------------------------------------------------------------------------
#include <string>
#include <map>
#include <list>
#include <fstream>
#include <iomanip>
#include <getopt.h>
#include <math.h>
#include "Debug.h"
#include "modbus/ModbusRTUMaster.h"
#include "modbus/ModbusHelpers.h"
#include "extensions/MTR.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static struct option longopts[] = {
{ "help", no_argument, 0, 'h' },
{ "read", required_argument, 0, 'r' },
{ "save", required_argument, 0, 'w' },
{ "timeout", required_argument, 0, 't' },
{ "autodetect-slave", required_argument, 0, 'l' },
{ "autodetect-speed", required_argument, 0, 'n' },
{ "device", required_argument, 0, 'd' },
{ "verbose", no_argument, 0, 'v' },
{ "speed", required_argument, 0, 's' },
{ "stop-bits", required_argument, 0, 'i' },
{ "parity", required_argument, 0, 'p' },
{ "use485F", no_argument, 0, 'y' },
{ "min-addr", required_argument, 0, 'b' },
{ "max-addr", required_argument, 0, 'e' },
{ "model", required_argument, 0, 'x' },
{ "serial", required_argument, 0, 'z' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
static void print_help()
{
printf("-h|--help - this message\n");
printf("[--read] mtraddr - read configuration from MTR\n");
printf("[--save] mtraddr confile - save configureation to MTR\n");
printf(" mtraddr=0x00 - autodetect addr\n");
printf("[-d|--device] dev - use device dev. Default: /dev/ttyS0\n");
printf("[-s|--speed] speed - 9600,14400,19200,38400,57600,115200. Default: 38400.\n");
printf("[--stop-bits] n - stop bits [1,2]. Default: 1\n");
printf("[--parity] par - parity [odd,even,no]. Default: no\n");
printf("[-t|--timeout] msec - Timeout. Default: 2000.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-y|--use485F] - use RS485 Fastwel.\n");
printf("[--autodetect-speed] slaveaddr [reg fn] - detect speed\n");
printf(" reg - register of test. Default: 0\n");
printf(" fn - function of test [0x01,0x02,0x03,0x04]. Default: 0x04\n");
printf("[--autodetect-slave] [reg fn] - find slave\n");
printf(" reg - register of test. Default: 0\n");
printf(" fn - function of test [0x01,0x02,0x03,0x04]. Default: 0x04\n");
printf("[--min-addr] - start addres for autodetect. Default: 0\n");
printf("[--max-addr] - end addres for autodetect. Default: 255\n");
printf("\n");
}
// --------------------------------------------------------------------------
enum Command
{
cmdNOP,
cmdRead,
cmdSave,
cmdDetectSpeed,
cmdDetectSlave,
cmdGetModel,
cmdGetSerial
};
// --------------------------------------------------------------------------
static char* checkArg( int ind, int argc, char* argv[] );
// --------------------------------------------------------------------------
int main( int argc, char **argv )
{
Command cmd = cmdNOP;
int optindex = 0;
int opt = 0;
int verb = 0;
string dev("/dev/ttyS0");
string speed("38400");
string mtrconfile("");
string par("");
ModbusRTU::ModbusData reg = 0;
ModbusRTU::ModbusAddr slaveaddr = 0x00;
ModbusRTU::SlaveFunctionCode fn = ModbusRTU::fnReadInputRegisters;
ModbusRTU::ModbusAddr beg = 0;
ModbusRTU::ModbusAddr end = 255;
int tout = 20;
DebugStream dlog;
string tofile("");
int use485 = 0;
ComPort::StopBits sbits = ComPort::OneBit;
ComPort::Parity parity = ComPort::NoParity;
// ModbusRTU::ModbusAddr b=255;
//
// cout << "b=" << (int)b << " b++=" << (int)(b++) << endl;
// return 0;
try
{
while( (opt = getopt_long(argc, argv, "hvw:r:x:d:s:t:l:n:yb:e:x:z:",longopts,&optindex)) != -1 )
{
switch (opt)
{
case 'h':
print_help();
return 0;
case 'r':
cmd = cmdRead;
slaveaddr = ModbusRTU::str2mbAddr(optarg);
break;
case 'w':
cmd = cmdSave;
slaveaddr = ModbusRTU::str2mbAddr( optarg );
if( !checkArg(optind,argc,argv) )
{
cerr << "read command error: bad or no arguments..." << endl;
return 1;
}
else
mtrconfile = string(argv[optind]);
break;
case 'x':
cmd = cmdGetModel;
slaveaddr = ModbusRTU::str2mbAddr(optarg);
break;
case 'z':
cmd = cmdGetSerial;
slaveaddr = ModbusRTU::str2mbAddr(optarg);
break;
case 'y':
use485 = 1;
break;
case 'd':
dev = string(optarg);
break;
case 's':
speed = string(optarg);
break;
case 'p':
par = string(optarg);
if( !par.compare("odd") )
parity = ComPort::Odd;
else if( !par.compare("even") )
parity = ComPort::Even;
break;
#undef atoi
case 't':
tout = atoi(optarg);
break;
case 'i':
if( atoi(optarg) == 2 )
sbits = ComPort::TwoBits;
break;
case 'b':
beg = atoi(optarg);
break;
case 'e':
end = atoi(optarg);
break;
// case 'a':
// myaddr = ModbusRTU::str2mbAddr(optarg);
// break;
case 'v':
verb = 1;
break;
case 'l':
{
if( cmd == cmdNOP )
cmd = cmdDetectSlave;
if( !checkArg(optind,argc,argv) )
break;
reg = ModbusRTU::str2mbData(argv[optind+2]);
if( !checkArg(optind+1,argc,argv) )
break;
fn = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(argv[optind+3]);
}
break;
case 'n':
{
if( cmd == cmdNOP )
cmd = cmdDetectSpeed;
slaveaddr = ModbusRTU::str2mbAddr(optarg);
if( !checkArg(optind,argc,argv) )
break;
reg = ModbusRTU::str2mbData(argv[optind]);
if( !checkArg(optind+1,argc,argv) )
break;
fn = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(argv[optind+1]);
}
break;
case '?':
default:
printf("? argumnet\n");
return 0;
}
}
if( verb )
{
cout << "(init): dev=" << dev << " speed=" << speed
<< " timeout=" << tout << " msec "
<< endl;
}
ModbusRTUMaster mb(dev,use485);
if( verb )
dlog.addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
mb.setTimeout(tout);
mb.setSpeed(speed);
mb.setParity(parity);
mb.setStopBits(sbits);
mb.setLog(dlog);
switch(cmd)
{
case cmdRead:
{
if( verb )
cout << "(mtr-setup): read: slaveaddr=" << ModbusRTU::addr2str(slaveaddr) << endl;
}
break;
case cmdSave:
{
if( slaveaddr == 0x00 )
{
if( verb )
cout << "(mtr-setup): save: autodetect slave addr... (speed=" << speed << ")" << endl;
mb.setTimeout(50);
slaveaddr = ModbusHelpers::autodetectSlave(&mb,beg,end,MTR::regModelNumber,ModbusRTU::fnReadInputRegisters);
mb.setTimeout(tout);
}
if( speed.empty() )
{
if( verb )
cout << "(mtr-setup): save: autodetect speed... (addr=" << ModbusRTU::addr2str(slaveaddr) << ")" << endl;
mb.setTimeout(50);
ComPort::Speed s = ModbusHelpers::autodetectSpeed(&mb,slaveaddr,MTR::regModelNumber,ModbusRTU::fnReadInputRegisters);
mb.setSpeed(s);
mb.setTimeout(tout);
}
if( verb )
cout << "(mtr-setup): save: "
<< " slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< " confile=" << mtrconfile
<< " speed=" << speed
<< endl;
return MTR::update_configuration(&mb,slaveaddr,mtrconfile,verb) ? 0 : 1;
}
break;
case cmdDetectSlave:
{
if( verb )
{
cout << "(mtr-setup): autodetect slave: "
<< " beg=" << ModbusRTU::addr2str(beg)
<< " end=" << ModbusRTU::addr2str(end)
<< " reg=" << ModbusRTU::dat2str(reg)
<< " fn=" << ModbusRTU::b2str(fn)
<< endl;
}
try
{
ModbusRTU::ModbusAddr a = ModbusHelpers::autodetectSlave(&mb,beg,end,reg,fn);
cout << "(mtr-setup): autodetect modbus slave: " << ModbusRTU::addr2str(a) << endl;
}
catch( UniSetTypes::TimeOut )
{
cout << "(mtr-setup): slave not autodetect..." << endl;
}
break;
}
case cmdDetectSpeed:
{
if( verb )
{
cout << "(mtr-setup): autodetect speed: slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< " reg=" << ModbusRTU::dat2str(reg)
<< " fn=" << ModbusRTU::b2str(fn)
<< endl;
}
try
{
ComPort::Speed s = ModbusHelpers::autodetectSpeed(&mb,slaveaddr,reg,fn);
cout << "(mtr-setup): autodetect: slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< " speed=" << ComPort::getSpeed(s) << endl;
}
catch( UniSetTypes::TimeOut )
{
cout << "(mtr-setup): speed not autodetect for slaveaddr="
<< ModbusRTU::addr2str(slaveaddr) << endl;
}
}
break;
case cmdGetModel:
{
if( verb )
{
cout << "(mtr-setup): model: "
<< " slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< endl;
}
cout << "model: " << MTR::getModelNumber(&mb,slaveaddr) << endl;
}
break;
case cmdGetSerial:
{
if( verb )
{
cout << "(mtr-setup): serial: "
<< " slaveaddr=" << ModbusRTU::addr2str(slaveaddr)
<< endl;
}
cout << "serial: " << MTR::getSerialNumber(&mb,slaveaddr) << endl;
}
break;
case cmdNOP:
default:
cerr << "No command. Use -h for help." << endl;
return 1;
}
}
catch( ModbusRTU::mbException& ex )
{
cerr << "(mtr-setup): " << ex << endl;
}
catch(SystemError& err)
{
cerr << "(mtr-setup): " << err << endl;
}
catch(Exception& ex)
{
cerr << "(mtr-setup): " << ex << endl;
}
catch(...)
{
cerr << "(mtr-setup): catch(...)" << endl;
}
return 0;
}
// --------------------------------------------------------------------------
char* checkArg( int i, int argc, char* argv[] )
{
if( i<argc && (argv[i])[0]!='-' )
return argv[i];
return 0;
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include "UniSetTypes.h"
#include "MTR.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace MTR;
// --------------------------------------------------------------------------
static void print_help()
{
printf("Usage: mtrconv TYPE[T1...T12,T16,T17] hex1 hex2\n");
}
// --------------------------------------------------------------------------
int main( int argc, const char **argv )
{
unsigned short v1 = 0;
unsigned short v2 = 0;
const char* type="";
if( argc<2 )
{
print_help();
return 1;
}
type = argv[1];
v1 = UniSetTypes::uni_atoi(argv[2]);
if( argc>=4 )
{
v1 = UniSetTypes::uni_atoi(argv[3]);
v2 = UniSetTypes::uni_atoi(argv[2]);
}
if( !strcmp(type,"T1") )
cout << "(T1): v1=" << v1 << " --> (unsigned) " << v1 << endl;
else if( !strcmp(type,"T2") )
cout << "(T2): v1=" << v1 << " --> (signed) " << (signed short)v1 << endl;
else if( !strcmp(type,"T16") )
{
T16 t(v1);
cout << "(T16): v1=" << t.val << " float=" << t.fval << endl;
}
else if( !strcmp(type,"T17") )
{
T17 t(v1);
cout << "(T17): v1=" << t.val << " float=" << t.fval << endl;
}
else if( !strcmp(type,"T3") )
{
T3 t(v1,v2);
cout << "(T3): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " --> " << (long)t << endl;
}
else if( !strcmp(type,"T4") )
{
T4 t(v1);
cout << "(T4): v1=" << t.raw
<< " --> " << t.sval << endl;
}
else if( !strcmp(type,"T5") )
{
T5 t(v1,v2);
cout << "(T5): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " --> " << t.raw.u2.val << " * 10^" << (int)t.raw.u2.exp
<< " ===> " << t.val << endl;
}
else if( !strcmp(type,"T6") )
{
T6 t(v1,v2);
cout << "(T6): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " --> " << t.raw.u2.val << " * 10^" << (int)t.raw.u2.exp
<< " ===> " << t.val << endl;
}
else if( !strcmp(type,"T7") )
{
T7 t(v1,v2);
cout << "(T7): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
// << " --> " << T7.val << " * 10^-4"
<< " ===> " << t.val
<< " [" << ( t.raw.u2.ic == 0xFF ? "CAP" : "IND" ) << "|"
<< ( t.raw.u2.ie == 0xFF ? "EXP" : "IMP" ) << "]"
<< endl;
}
else if( !strcmp(type,"T8") )
{
T8 t(v1,v2);
cout << "(T8): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " ===> " << setfill('0') << hex
<< setw(2) << t.hour() << ":" << setw(2) << t.min()
<< " " << setw(2) << t.day() << "/" << setw(2) << t.mon()
<< endl;
}
else if( !strcmp(type,"T9") )
{
T9 t(v1,v2);
cout << "(T9): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " ===> " << setfill('0') << hex
<< setw(2) << t.hour() << ":" << setw(2) << t.min()
<< ":" << setw(2) << t.sec() << "." << setw(2) << t.ssec()
<< endl;
}
else if( !strcmp(type,"T10") )
{
T10 t(v1,v2);
cout << "(T10): v1=" << t.raw.v[0] << " v2=" << t.raw.v[1]
<< " ===> " << setfill('0') << dec
<< setw(4) << t.year() << "/" << setw(2) << t.mon()
<< "/" << setw(2) << t.day()
<< endl;
}
else if( !strcmp(type,"F1") )
{
F1 f(v1,v2);
cout << "(F1): v1=" << f.raw.v[0] << " v2=" << f.raw.v[1]
<< " ===> " << f.raw.val << endl;
}
else
{
cout << " Unknown type: " << type << endl;
}
return 0;
}
// --------------------------------------------------------------------------
#include <sstream>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "RTUExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, char** argv )
{
try
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
cout << "--smemory-id objectName - SharedMemory objectID. Default: read from <SharedMemory>" << endl;
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--rs-logfile filename - logfilename. Default: rtuexchange.log" << endl;
cout << endl;
RTUExchange::help_print(argc, argv);
return 0;
}
string confile=UniSetTypes::getArgParam("--confile", argc, argv, "configure.xml");
conf = new Configuration( argc, argv, confile );
string logfilename(conf->getArgParam("--rs-logfile"));
if( logfilename.empty() )
logfilename = "rtuexchange.log";
conf->initDebug(dlog,"dlog");
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
dlog.logFile( logname.str() );
ObjectId shmID = DefaultObjectId;
string sID = conf->getArgParam("--smemory-id");
if( !sID.empty() )
shmID = conf->getControllerID(sID);
else
shmID = getSharedMemoryID();
if( shmID == DefaultObjectId )
{
cerr << sID << "? SharedMemoryID not found in " << conf->getControllersSection() << " section" << endl;
return 1;
}
RTUExchange* rs = RTUExchange::init_rtuexchange(argc,argv,shmID);
if( !rs )
{
dlog[Debug::CRIT] << "(rtuexchange): init не прошёл..." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(rs));
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
unideb[Debug::ANY] << "(main): -------------- RTU Exchange START -------------------------\n\n";
dlog(Debug::ANY) << "\n\n\n";
dlog[Debug::ANY] << "(main): -------------- RTU Exchange START -------------------------\n\n";
act.run(false);
// msleep(500);
// rs->execute();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(rtuexchange): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(rtuexchange): catch ..." << std::endl;
}
return 0;
}
// --------------------------------------------------------------------------
#include <string>
#include <getopt.h>
#include "modbus/ModbusRTUMaster.h"
#include "RTUStorage.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static struct option longopts[] = {
{ "help", no_argument, 0, 'h' },
{ "slave", required_argument, 0, 'q' },
{ "device", required_argument, 0, 'd' },
{ "verbose", no_argument, 0, 'v' },
{ "speed", required_argument, 0, 's' },
{ "use485F", no_argument, 0, 'y' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
static void print_help()
{
printf("Usage: rtustate -q addr\n");
printf("-h|--help - this message\n");
printf("[-q|--slave] addr - Slave address. Default: 0x01.\n");
printf("[-d|--device] dev - use device dev. Default: /dev/ttyS0\n");
printf("[-s|--speed] speed - 9600,14400,19200,38400,57600,115200. Default: 38400.\n");
printf("[-t|--timeout] msec - Timeout. Default: 2000.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-y|--use485F] - use RS485 Fastwel.\n");
}
// --------------------------------------------------------------------------
int main( int argc, char **argv )
{
int optindex = 0;
int opt = 0;
int verb = 0;
string dev("/dev/ttyS0");
string speed("38400");
ModbusRTU::ModbusAddr slaveaddr = 0x01;
int tout = 2000;
DebugStream dlog;
int use485 = 0;
try
{
while( (opt = getopt_long(argc, argv, "hva:d:s:t:q:",longopts,&optindex)) != -1 )
{
switch (opt)
{
case 'h':
print_help();
return 0;
case 'd':
dev = string(optarg);
break;
case 's':
speed = string(optarg);
break;
case 't':
tout = uni_atoi(optarg);
break;
case 'q':
slaveaddr = ModbusRTU::str2mbAddr(optarg);
break;
case 'v':
verb = 1;
break;
case 'y':
use485 = 1;
break;
case '?':
default:
printf("? argumnet\n");
return 0;
}
}
if( verb )
{
cout << "(init): dev=" << dev
<< " speed=" << speed
<< " timeout=" << tout << " msec "
<< endl;
}
ModbusRTUMaster mb(dev,use485);
if( verb )
dlog.addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
mb.setTimeout(tout);
mb.setSpeed(speed);
mb.setLog(dlog);
RTUStorage rtu(slaveaddr);
rtu.poll(&mb);
cout << rtu << endl;
for( int i=0; i<24; i++ )
cout << "UNIO1 AI" << i << ": " << rtu.getFloat( RTUStorage::nJ1, i, UniversalIO::AnalogInput ) << endl;
for( int i=0; i<24; i++ )
cout << "UNIO1 DI" << i << ": " << rtu.getState( RTUStorage::nJ1, i, UniversalIO::DigitalInput ) << endl;
}
catch( ModbusRTU::mbException& ex )
{
cerr << "(rtustate): " << ex << endl;
}
catch(SystemError& err)
{
cerr << "(rtustate): " << err << endl;
}
catch(Exception& ex)
{
cerr << "(rtustate): " << ex << endl;
}
catch(...)
{
cerr << "(rtustate): catch(...)" << endl;
}
return 0;
}
// --------------------------------------------------------------------------
#!/bin/sh
uniset-start.sh -f ./uniset-rtuexchange --confile test.xml \
--smemory-id SharedMemory \
--rs-dev /dev/cbsideA0 \
--rs-name RTUExchange \
--rs-speed 38400 \
--rs-filter-field rs \
--rs-filter-value 1 \
--dlog-add-levels info,crit,warn,level4,level3 \
--rs-force 0 \
--rs-force-out 0 \
#,level3
# --rs-force 1 \
// --------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include "UniSetTypes.h"
#include "VTypes.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace VTypes;
// --------------------------------------------------------------------------
static void print_help()
{
printf("Usage: vtconv TYPE[F2|F4|I2|U2] hex1 hex2 [hex3 hex4]\n");
}
// --------------------------------------------------------------------------
int main( int argc, const char **argv )
{
VTypes::F2 f2;
f2.raw.val = 2.345;
cout << "Example(F2): float=" << f2.raw.val
<< " regs:"
<< " v[0]=" << f2.raw.v[0]
<< " v[1]=" << f2.raw.v[1]
<< endl;
VTypes::F4 f4;
f4.raw.val = 2.345123123;
cout << "Example(F4): float=" << f4.raw.val
<< " regs:"
<< " v[0]=" << f4.raw.v[0]
<< " v[1]=" << f4.raw.v[1]
<< " v[2]=" << f4.raw.v[2]
<< " v[3]=" << f4.raw.v[3]
<< endl;
cout << "-------------" << endl << endl;
VTypes::I2 i2;
i2.raw.val = -6553004;
cout << "Example(I2): int=" << i2.raw.val
<< " regs:"
<< " v[0]=" << i2.raw.v[0]
<< " v[1]=" << i2.raw.v[1]
<< endl;
cout << "-------------" << endl << endl;
VTypes::U2 u2;
u2.raw.val = 655300400;
cout << "Example(U2): unsigned int=" << u2.raw.val
<< " regs:"
<< " v[0]=" << u2.raw.v[0]
<< " v[1]=" << u2.raw.v[1]
<< endl;
cout << "-------------" << endl << endl;
// return 0;
unsigned short v[4];
memset(v,0,sizeof(v));
const char* type="";
if( argc<3 )
{
print_help();
return 1;
}
type = argv[1];
v[0] = UniSetTypes::uni_atoi(argv[2]);
if( argc>3 )
v[1] = UniSetTypes::uni_atoi(argv[3]);
if( argc>4 )
v[2] = UniSetTypes::uni_atoi(argv[4]);
if( argc>5 )
v[3] = UniSetTypes::uni_atoi(argv[5]);
if( !strcmp(type,"F2") )
{
VTypes::F2 f(v,sizeof(v));
cout << "(F2): v[0]=" << v[0]
<< " v[1]=" << v[1]
<< " --> (float) " << (float)f << endl;
}
else if( !strcmp(type,"F4") )
{
VTypes::F4 f(v,sizeof(v));
cout << "(F4): v[0]=" << v[0]
<< " v[1]=" << v[1]
<< " v[2]=" << v[2]
<< " v[3]=" << v[3]
<< " --> (float) " << (float)f << endl;
}
else if( !strcmp(type,"I2") )
{
VTypes::I2 i(v,sizeof(v));
cout << "(I2): v[0]=" << v[0]
<< " v[1]=" << v[1]
<< " --> (int) " << (int)i << endl;
}
else if( !strcmp(type,"U2") )
{
VTypes::U2 i(v,sizeof(v));
cout << "(U2): v[0]=" << v[0]
<< " v[1]=" << v[1]
<< " --> (unsigned int) " << (unsigned int)i << endl;
}
else
{
cout << " Unknown type: " << type << endl;
}
return 0;
}
// --------------------------------------------------------------------------
/*! $Id$ */
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
#ifndef _SMVIEWER_H #ifndef _SMVIEWER_H
#define _SMVIEWER_H #define _SMVIEWER_H
...@@ -8,13 +9,13 @@ ...@@ -8,13 +9,13 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
class SMViewer: class SMViewer:
public SViewer public SViewer
{ {
public: public:
SMViewer( UniSetTypes::ObjectId shmID ); SMViewer( UniSetTypes::ObjectId shmID );
virtual ~SMViewer(); virtual ~SMViewer();
void run(); void run();
protected: protected:
private: private:
......
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../../conf/test.xml test.xml
bin_PROGRAMS = @PACKAGE@-udpexchange @PACKAGE@-udpsender @PACKAGE@-udpreceiver
UUDP_VER=@LIBVER@
lib_LTLIBRARIES = libUniSetUDP.la
libUniSetUDP_la_LDFLAGS = -version-info $(UUDP_VER)
libUniSetUDP_la_LIBADD = $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
libUniSetUDP_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libUniSetUDP_la_SOURCES = UDPPacket.cc UDPExchange.cc UDPSender.cc UDPNReceiver.cc UDPReceiver.cc
#UDPSender.cc
@PACKAGE@_udpexchange_SOURCES = udpexchange.cc
@PACKAGE@_udpexchange_LDADD = libUniSetUDP.la $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
@PACKAGE@_udpexchange_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
@PACKAGE@_udpsender_SOURCES = udpsender.cc
@PACKAGE@_udpsender_LDADD = libUniSetUDP.la $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
@PACKAGE@_udpsender_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
@PACKAGE@_udpreceiver_SOURCES = udpreceiver.cc
@PACKAGE@_udpreceiver_LDADD = libUniSetUDP.la $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
@PACKAGE@_udpreceiver_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
# install
devel_include_HEADERS = *.h
devel_includedir = $(pkgincludedir)/extensions
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libUniSetUDP.pc
all-local:
ln -sf ../UDPExchange/$(devel_include_HEADERS) ../include
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UDPExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UDPExchange::UDPExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
shm(0),
initPause(0),
udp(0),
activated(false),
dlist(100),
maxItem(0)
{
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(UDPExchange): objId=-1?!! Use --udp-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(UDPExchange): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--udp-filter-field");
s_fvalue = conf->getArgParam("--udp-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
// ---------- init RS ----------
// UniXML_iterator it(cnode);
s_host = conf->getArgParam("--udp-host",it.getProp("host"));
if( s_host.empty() )
throw UniSetTypes::SystemError(myname+"(UDPExchange): Unknown host. Use --udp-host" );
host = s_host.c_str();
buildReceiverList();
// port = conf->getArgInt("--udp-port",it.getProp("port"));
if( port <= 0 || port == DefaultObjectId )
throw UniSetTypes::SystemError(myname+"(UDPExchange): Unknown port address" );
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UDPExchange): UDP set to " << s_host << ":" << port << endl;
try
{
udp = new ost::UDPBroadcast(host,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString() << endl;
throw SystemError(s.str());
}
thr = new ThreadCreator<UDPExchange>(this, &UDPExchange::poll);
recvTimeout = conf->getArgPInt("--udp-recv-timeout",it.getProp("recvTimeout"), 5000);
sendTimeout = conf->getArgPInt("--udp-send-timeout",it.getProp("sendTimeout"), 5000);
polltime = conf->getArgPInt("--udp-polltime",it.getProp("polltime"), 100);
// -------------------------------
if( shm->isLocalwork() )
{
readConfiguration();
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
}
else
ic->addReadItem( sigc::mem_fun(this,&UDPExchange::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--udp-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": не найден идентификатор для датчика 'HeartBeat' " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--udp-heartbeat-max", it.getProp("heartbeat_max"), 10);
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = conf->getArgPInt("--activate-timeout", 20000);
timeout_t msec = conf->getArgPInt("--udp-timeout",it.getProp("timeout"), 3000);
dlog[Debug::INFO] << myname << "(init): udp-timeout=" << msec << " msec" << endl;
}
// -----------------------------------------------------------------------------
UDPExchange::~UDPExchange()
{
for( ReceiverList::iterator it=rlist.begin(); it!=rlist.end(); it++ )
delete (*it);
delete udp;
delete shm;
delete thr;
}
// -----------------------------------------------------------------------------
void UDPExchange::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--udp-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): Не дождались готовности SharedMemory к работе в течение " << ready_timeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void UDPExchange::step()
{
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void UDPExchange::poll()
{
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
for( ReceiverList::iterator it=rlist.begin(); it!=rlist.end(); it++ )
{
(*it)->setReceiveTimeout(recvTimeout);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): start exchange for " << (*it)->getName() << endl;
(*it)->start();
}
ost::IPV4Broadcast h = s_host.c_str();
try
{
udp->setPeer(h,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << myname << "(poll): " << s.str() << endl;
throw SystemError(s.str());
}
while( activated )
{
try
{
send();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(step): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(step): catch ..." << std::endl;
}
msleep(polltime);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UDPExchange::send()
{
cout << myname << ": send..." << endl;
/*
UniSetUDP::UDPHeader h;
h.nodeID = conf->getLocalNode();
h.procID = getId();
h.dcount = mypack.size();
if( udp->isPending(ost::Socket::pendingOutput) )
{
ssize_t ret = udp->send((char*)(&h),sizeof(h));
if( ret<(ssize_t)sizeof(h) )
{
cerr << myname << "(send data header): ret=" << ret << " sizeof=" << sizeof(h) << endl;
return;
}
*/
/*! \todo Подумать нужен ли здесь mutex */
UniSetUDP::UDPMessage::UDPDataList::iterator it = mypack.dlist.begin();
for( ; it!=mypack.dlist.end(); ++it )
{
// while( !udp->isPending(ost::Socket::pendingOutput) )
// msleep(30);
cout << myname << "(send): " << (*it) << endl;
ssize_t ret = udp->send((char*)(&(*it)),sizeof(UniSetUDP::UDPData));
if( ret<(ssize_t)sizeof(UniSetUDP::UDPData) )
{
cerr << myname << "(send data): ret=" << ret << " sizeof=" << sizeof(UniSetUDP::UDPData) << endl;
break;
}
}
// }
}
// -----------------------------------------------------------------------------
void UDPExchange::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
raise(SIGTERM);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void UDPExchange::sysCommand(UniSetTypes::SystemMessage *sm)
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
waitSMReady();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
}
thr->start();
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. UDPExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(UDPExchange)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
}
break;
case SystemMessage::LogRotate:
{
// переоткрываем логи
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void UDPExchange::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str());
}
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
try
{
shm->askSensor(it->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...){}
}
}
// ------------------------------------------------------------------------------------------
void UDPExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
if( it->si.id == sm->id )
{
uniset_spin_lock lock(it->val_lock);
it->val = sm->value;
if( it->pack_it != mypack.dlist.end() )
it->pack_it->val = sm->value;
}
break;
}
}
// ------------------------------------------------------------------------------------------
bool UDPExchange::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void UDPExchange::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
udp->disconnect();
for( ReceiverList::iterator it=rlist.begin(); it!=rlist.end(); it++ )
(*it)->stop();
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void UDPExchange::readConfiguration()
{
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool UDPExchange::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// просто проверка на не пустой field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// просто проверка что field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool UDPExchange::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
bool UDPExchange::initItem( UniXML_iterator& it )
{
string sname( it.getProp("name") );
string tid = it.getProp("id");
ObjectId sid;
if( !tid.empty() )
{
sid = UniSetTypes::uni_atoi(tid);
if( sid <= 0 )
sid = DefaultObjectId;
}
else
sid = conf->getSensorID(sname);
if( sid == DefaultObjectId )
{
if( dlog )
dlog[Debug::CRIT] << myname << "(readItem): ID not found for "
<< sname << endl;
return false;
}
UItem p;
p.si.id = sid;
p.si.node = conf->getLocalNode();
mypack.addData(sid,0);
p.pack_it = (mypack.dlist.end()--);
if( maxItem >= dlist.size() )
dlist.resize(maxItem+10);
dlist[maxItem] = p;
maxItem++;
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;
return true;
}
// ------------------------------------------------------------------------------------------
void UDPExchange::initIterators()
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); it++ )
{
shm->initDIterator(it->dit);
shm->initAIterator(it->ait);
}
shm->initAIterator(aitHeartBeat);
}
// -----------------------------------------------------------------------------
void UDPExchange::help_print( int argc, char* argv[] )
{
cout << "--udp-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек." << endl;
cout << "--udp-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--udp-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--udp-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--udp-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--udp-notRespondSensor - датчик связи для данного процесса " << endl;
cout << "--udp-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола UDP: " << endl;
cout << "--udp-host [ip|hostname] - Адрес сервера" << endl;
cout << "--udp-send-timeout - Таймаут на посылку ответа." << endl;
}
// -----------------------------------------------------------------------------
UDPExchange* UDPExchange::init_udpexchange( int argc, char* argv[], UniSetTypes::ObjectId icID, SharedMemory* ic )
{
string name = conf->getArgParam("--udp-name","UDPExchange1");
if( name.empty() )
{
cerr << "(udpexchange): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(udpexchange): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(rsexchange): name = " << name << "(" << ID << ")" << endl;
return new UDPExchange(ID,icID,ic);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UDPExchange::UItem& p )
{
return os << " sid=" << p.si.id;
}
// -----------------------------------------------------------------------------
void UDPExchange::buildReceiverList()
{
xmlNode* n = conf->getXMLNodesSection();
if( !n )
{
dlog[Debug::WARN] << myname << "(buildReceiverList): <nodes> not found! ignore..." << endl;
return;
}
UniXML_iterator it(n);
if( !it.goChildren() )
{
dlog[Debug::WARN] << myname << "(buildReceiverList): <nodes> is empty?! ignore..." << endl;
return;
}
for( ; it.getCurrent(); it.goNext() )
{
ObjectId n_id = conf->getNodeID( it.getProp("name") );
if( n_id == conf->getLocalNode() )
{
port = it.getIntProp("udp_port");
if( port<=0 )
port = n_id;
dlog[Debug::INFO] << myname << "(buildReceiverList): init myport port=" << port << endl;
continue;
}
int p = it.getIntProp("udp_port");
if( p <=0 )
p = n_id;
if( p == DefaultObjectId )
{
dlog[Debug::WARN] << myname << "(buildReceiverList): node=" << it.getProp("name") << " unknown port. ignore..." << endl;
continue;
}
UDPNReceiver* r = new UDPNReceiver(p,host,shm->getSMID(),shm->SM());
rlist.push_back(r);
}
}
// ------------------------------------------------------------------------------------------
#ifndef UDPExchange_H_
#define UDPExchange_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <vector>
#include <cc++/socket.h>
#include "UniSetObject_LT.h"
#include "Trigger.h"
#include "Mutex.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "ThreadCreator.h"
#include "UDPPacket.h"
#include "UDPNReceiver.h"
// -----------------------------------------------------------------------------
class UDPExchange:
public UniSetObject_LT
{
public:
UDPExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UDPExchange();
/*! глобальная функция для инициализации объекта */
static UDPExchange* init_udpexchange( int argc, char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, char* argv[] );
struct UItem
{
UItem():
val(0)
{}
IOController_i::SensorInfo si;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniSetTypes::uniset_spin_mutex val_lock;
UniSetUDP::UDPMessage::UDPDataList::iterator pack_it;
long val;
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
protected:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void poll();
void recv();
void send();
void step();
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void askSensors( UniversalIO::UIOCommand cmd );
void waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void readConfiguration();
bool check_item( UniXML_iterator& it );
void buildReceiverList();
private:
UDPExchange();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
int polltime; /*!< переодичность обновления данных, [мсек] */
ost::UDPBroadcast* udp;
ost::IPV4Host host;
ost::tpport_t port;
std::string s_host;
UniSetTypes::uniset_mutex pollMutex;
Trigger trTimeout;
int recvTimeout;
int sendTimeout;
bool activated;
int activateTimeout;
UniSetUDP::UDPMessage mypack;
typedef std::vector<UItem> DMap;
DMap dlist;
int maxItem;
typedef std::list<UDPNReceiver*> ReceiverList;
ReceiverList rlist;
ThreadCreator<UDPExchange>* thr;
};
// -----------------------------------------------------------------------------
#endif // UDPExchange_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UDPNReceiver.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UDPNReceiver::UDPNReceiver( ost::tpport_t p, ost::IPV4Host h, UniSetTypes::ObjectId shmId, IONotifyController* ic ):
shm(0),
ui(conf),
activate(false),
udp(0),
host(h),
port(p),
recvTimeout(5000),
conn(false)
{
{
ostringstream s;
s << host << ":" << port;
myname = s.str();
}
shm = new SMInterface(shmId,&ui,DefaultObjectId,ic);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UDPNReceiver): UDP set to " << host << ":" << port << endl;
try
{
udp = new ost::UDPDuplex(host,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString() << endl;
throw SystemError(s.str());
}
thr = new ThreadCreator<UDPNReceiver>(this, &UDPNReceiver::poll);
thr->start();
}
// -----------------------------------------------------------------------------
UDPNReceiver::~UDPNReceiver()
{
delete udp;
delete shm;
delete thr;
}
// -----------------------------------------------------------------------------
void UDPNReceiver::poll()
{
while( 1 )
{
if( !activate )
{
msleep(1000);
continue;
}
try
{
recv();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(step): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(step): catch ..." << std::endl;
}
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UDPNReceiver::recv()
{
cout << myname << ": recv....(timeout=" << recvTimeout << ")" << endl;
// UniSetUDP::UDPHeader h;
// receive
if( udp->isInputReady(recvTimeout) )
{
/*
ssize_t ret = udp->UDPReceive::receive(&h,sizeof(h));
if( ret<(ssize_t)sizeof(h) )
{
cerr << myname << "(receive): ret=" << ret << " sizeof=" << sizeof(h) << endl;
return;
}
cout << myname << "(receive): header: " << h << endl;
if( h.dcount <=0 )
{
cout << " data=0" << endl;
return;
}
*/
UniSetUDP::UDPData d;
// ignore echo...
#if 0
if( h.nodeID == conf->getLocalNode() && h.procID == getId() )
{
for( int i=0; i<h.dcount;i++ )
{
ssize_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret < (ssize_t)sizeof(d) )
return;
}
return;
}
#endif
cout << "***** request: " << udp->UDPSocket::getIPV4Peer() << endl;
for( int i=0; i<100;i++ )
{
ssize_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret<(ssize_t)sizeof(d) )
{
cerr << myname << "(receive data " << i << "): ret=" << ret << " sizeof=" << sizeof(d) << endl;
break;
}
cout << myname << "(receive data " << i << "): " << d << endl;
}
}
// else
// {
// cout << "no InputReady.." << endl;
// }
}
// -----------------------------------------------------------------------------
#ifndef UDPNReceiver_H_
#define UDPNReceiver_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <vector>
#include <cc++/socket.h>
#include "Mutex.h"
#include "Trigger.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "ThreadCreator.h"
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
class UDPNReceiver
{
public:
UDPNReceiver( ost::tpport_t port, ost::IPV4Host host, UniSetTypes::ObjectId shmID, IONotifyController* ic=0 );
virtual ~UDPNReceiver();
inline int getPort(){ return port; }
inline bool isConnetcion(){ return conn; }
inline void start(){ activate = true; }
inline void stop(){ activate = false; }
inline void setReceiveTimeout( int t ){ recvTimeout = t; }
inline std::string getName(){ return myname; }
protected:
SMInterface* shm;
UniversalInterface ui;
void poll();
void recv();
std::string myname;
private:
UDPNReceiver();
bool activate;
ost::UDPDuplex* udp;
ost::IPV4Host host;
ost::tpport_t port;
int recvTimeout;
bool conn;
ThreadCreator<UDPNReceiver>* thr;
};
// -----------------------------------------------------------------------------
#endif // UDPNReceiver_H_
// -----------------------------------------------------------------------------
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetUDP;
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader& p )
{
return os << "nodeID=" << p.nodeID
<< " procID=" << p.procID
<< " dcount=" << p.dcount;
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPData& p )
{
return os << "id=" << p.id << " val=" << p.val;
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPMessage& p )
{
return os;
}
// -----------------------------------------------------------------------------
UDPMessage::UDPMessage()
{
}
// -----------------------------------------------------------------------------
void UDPMessage::addData( const UniSetUDP::UDPData& dat )
{
dlist.push_back(dat);
}
// -----------------------------------------------------------------------------
void UDPMessage::addData( long id, long val)
{
UDPData d(id,val);
addData(d);
}
// -----------------------------------------------------------------------------
// $Id: UDPPacket.h,v 1.1 2009/02/10 20:38:27 vpashka Exp $
// -----------------------------------------------------------------------------
#ifndef UDPPacket_H_
#define UDPPacket_H_
// -----------------------------------------------------------------------------
#include <list>
#include <ostream>
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
namespace UniSetUDP
{
struct UDPHeader
{
long nodeID;
long procID;
long dcount;
friend std::ostream& operator<<( std::ostream& os, UDPHeader& p );
}__attribute__((packed));
struct UDPData
{
UDPData():id(UniSetTypes::DefaultObjectId),val(0){}
UDPData(long id, long val):id(id),val(val){}
long id;
long val;
friend std::ostream& operator<<( std::ostream& os, UDPData& p );
}__attribute__((packed));
struct UDPMessage:
public UDPHeader
{
UDPMessage();
void addData( const UDPData& dat );
void addData( long id, long val );
inline int size(){ return dlist.size(); }
typedef std::list<UDPData> UDPDataList;
UDPDataList dlist;
friend std::ostream& operator<<( std::ostream& os, UDPMessage& p );
};
}
// -----------------------------------------------------------------------------
#endif // UDPPacket_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UDPReceiver.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UDPReceiver::UDPReceiver( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
shm(0),
initPause(0),
udp(0),
activated(false)
{
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(UDPReceiver): objId=-1?!! Use --udp-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(UDPReceiver): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--udp-filter-field");
s_fvalue = conf->getArgParam("--udp-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
// ---------- init RS ----------
// UniXML_iterator it(cnode);
string s_host = conf->getArgParam("--udp-host",it.getProp("host"));
if( s_host.empty() )
throw UniSetTypes::SystemError(myname+"(UDPReceiver): Unknown host. Use --udp-host" );
port = conf->getArgInt("--udp-port",it.getProp("port"));
if( port <= 0 )
throw UniSetTypes::SystemError(myname+"(UDPReceiver): Unknown port address. Use --udp-port" );
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UDPReceiver): UDP set to " << s_host << ":" << port << endl;
host = s_host.c_str();
try
{
udp = new ost::UDPDuplex(host,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString() << endl;
throw SystemError(s.str());
}
thr = new ThreadCreator<UDPReceiver>(this, &UDPReceiver::poll);
recvTimeout = conf->getArgPInt("--udp-recv-timeout",it.getProp("recvTimeout"), 5000);
polltime = conf->getArgPInt("--udp-polltime",it.getProp("polltime"), 100);
// -------------------------------
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--udp-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": не найден идентификатор для датчика 'HeartBeat' " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--udp-heartbeat-max", it.getProp("heartbeat_max"), 10);
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = conf->getArgPInt("--activate-timeout", 20000);
timeout_t msec = conf->getArgPInt("--udp-timeout",it.getProp("timeout"), 3000);
dlog[Debug::INFO] << myname << "(init): udp-timeout=" << msec << " msec" << endl;
}
// -----------------------------------------------------------------------------
UDPReceiver::~UDPReceiver()
{
delete udp;
delete shm;
delete thr;
}
// -----------------------------------------------------------------------------
void UDPReceiver::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--udp-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): Не дождались готовности SharedMemory к работе в течение " << ready_timeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
/*
void UDPReceiver::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
step();
}
*/
// -----------------------------------------------------------------------------
void UDPReceiver::step()
{
// {
// uniset_mutex_lock l(pollMutex,2000);
// poll();
// }
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void UDPReceiver::poll()
{
try
{
// udp->connect(host,port);
// udp->UDPSocket::setPeer(host,port);
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(step): " << ex << std::endl;
// reise(SIGTERM);
return;
}
while( activated )
{
try
{
recv();
// send();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(step): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(step): catch ..." << std::endl;
}
msleep(polltime);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UDPReceiver::recv()
{
cout << myname << ": recv....(timeout=" << recvTimeout << ")" << endl;
UniSetUDP::UDPHeader h;
// receive
if( udp->isInputReady(recvTimeout) )
{
ssize_t ret = udp->UDPReceive::receive(&h,sizeof(h));
if( ret<(ssize_t)sizeof(h) )
{
cerr << myname << "(receive): ret=" << ret << " sizeof=" << sizeof(h) << endl;
return;
}
cout << myname << "(receive): header: " << h << endl;
if( h.dcount <=0 )
{
cout << " data=0" << endl;
return;
}
UniSetUDP::UDPData d;
// ignore echo...
#if 0
if( h.nodeID == conf->getLocalNode() && h.procID == getId() )
{
for( int i=0; i<h.dcount;i++ )
{
ssize_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret < (ssize_t)sizeof(d) )
return;
}
return;
}
#endif
for( int i=0; i<h.dcount;i++ )
{
ssize_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret<(ssize_t)sizeof(d) )
{
cerr << myname << "(receive data " << i << "): ret=" << ret << " sizeof=" << sizeof(d) << endl;
break;
}
cout << myname << "(receive data " << i << "): " << d << endl;
}
}
// else
// {
// cout << "no InputReady.." << endl;
// }
}
// -----------------------------------------------------------------------------
void UDPReceiver::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
raise(SIGTERM);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void UDPReceiver::sysCommand(UniSetTypes::SystemMessage *sm)
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
waitSMReady();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
}
thr->start();
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. UDPReceiver запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(UDPReceiver)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
}
break;
case SystemMessage::LogRotate:
{
// переоткрываем логи
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void UDPReceiver::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str());
}
}
// ------------------------------------------------------------------------------------------
void UDPReceiver::sensorInfo( UniSetTypes::SensorMessage* sm )
{
}
// ------------------------------------------------------------------------------------------
bool UDPReceiver::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void UDPReceiver::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
udp->disconnect();
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void UDPReceiver::initIterators()
{
shm->initAIterator(aitHeartBeat);
}
// -----------------------------------------------------------------------------
void UDPReceiver::help_print( int argc, char* argv[] )
{
cout << "--udp-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек." << endl;
cout << "--udp-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--udp-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--udp-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--udp-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--udp-notRespondSensor - датчик связи для данного процесса " << endl;
cout << "--udp-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола RS: " << endl;
cout << "--udp-dev devname - файл устройства" << endl;
cout << "--udp-speed - Скорость обмена (9600,19920,38400,57600,115200)." << endl;
cout << "--udp-my-addr - адрес текущего узла" << endl;
cout << "--udp-recv-timeout - Таймаут на ожидание ответа." << endl;
}
// -----------------------------------------------------------------------------
UDPReceiver* UDPReceiver::init_udpreceiver( int argc, char* argv[], UniSetTypes::ObjectId icID, SharedMemory* ic )
{
string name = conf->getArgParam("--udp-name","UDPReceiver1");
if( name.empty() )
{
cerr << "(udpexchange): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(udpexchange): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(rsexchange): name = " << name << "(" << ID << ")" << endl;
return new UDPReceiver(ID,icID,ic);
}
// -----------------------------------------------------------------------------
#ifndef UDPReceiver_H_
#define UDPReceiver_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <vector>
#include <cc++/socket.h>
#include "UniSetObject_LT.h"
#include "Trigger.h"
#include "Mutex.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "ThreadCreator.h"
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
class UDPReceiver:
public UniSetObject_LT
{
public:
UDPReceiver( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UDPReceiver();
/*! глобальная функция для инициализации объекта */
static UDPReceiver* init_udpreceiver( int argc, char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, char* argv[] );
protected:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void poll();
void recv();
void step();
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void askSensors( UniversalIO::UIOCommand cmd );
void waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
private:
UDPReceiver();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
int polltime; /*!< переодичность обновления данных, [мсек] */
ost::UDPDuplex* udp;
ost::IPV4Host host;
ost::tpport_t port;
UniSetTypes::uniset_mutex pollMutex;
Trigger trTimeout;
int recvTimeout;
bool activated;
int activateTimeout;
ThreadCreator<UDPReceiver>* thr;
};
// -----------------------------------------------------------------------------
#endif // UDPReceiver_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UDPSender.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UDPSender::UDPSender( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
shm(0),
initPause(0),
udp(0),
activated(false),
dlist(100),
maxItem(0)
{
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(UDPSender): objId=-1?!! Use --udp-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(UDPSender): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--udp-filter-field");
s_fvalue = conf->getArgParam("--udp-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
// ---------- init RS ----------
// UniXML_iterator it(cnode);
string s_host = conf->getArgParam("--udp-host",it.getProp("host"));
if( s_host.empty() )
throw UniSetTypes::SystemError(myname+"(UDPSender): Unknown host. Use --udp-host" );
port = conf->getArgInt("--udp-port",it.getProp("port"));
if( port <= 0 )
throw UniSetTypes::SystemError(myname+"(UDPSender): Unknown port address. Use --udp-port" );
bool broadcast = conf->getArgInt("--udp-broadcast",it.getProp("broadcast"));
host = s_host.c_str();
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UDPSender): UDP set to " << s_host << ":" << port
<< " broadcast=" << broadcast
<< endl;
try
{
if( !broadcast )
udp = new ost::UDPSocket();
else
udp = new ost::UDPBroadcast(host,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << myname << "(init): " << s.str() << endl;
throw SystemError(s.str());
}
thr = new ThreadCreator<UDPSender>(this, &UDPSender::poll);
sendTimeout = conf->getArgPInt("--udp-send-timeout",it.getProp("sendTimeout"), 5000);
sendtime = conf->getArgPInt("--udp-sendtime",it.getProp("sendtime"), 100);
// -------------------------------
if( shm->isLocalwork() )
{
readConfiguration();
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
}
else
ic->addReadItem( sigc::mem_fun(this,&UDPSender::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--udp-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": не найден идентификатор для датчика 'HeartBeat' " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgPInt("--udp-heartbeat-max", it.getProp("heartbeat_max"), 10);
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = conf->getArgPInt("--activate-timeout", 20000);
timeout_t msec = conf->getArgPInt("--udp-timeout",it.getProp("timeout"), 3000);
dlog[Debug::INFO] << myname << "(init): udp-timeout=" << msec << " msec" << endl;
}
// -----------------------------------------------------------------------------
UDPSender::~UDPSender()
{
delete udp;
delete shm;
delete thr;
}
// -----------------------------------------------------------------------------
void UDPSender::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--udp-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): Не дождались готовности SharedMemory к работе в течение " << ready_timeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void UDPSender::step()
{
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void UDPSender::poll()
{
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
try
{
udp->setPeer(host,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << myname << "(poll): " << s.str() << endl;
throw SystemError(s.str());
}
while( activated )
{
try
{
send();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(step): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(step): catch ..." << std::endl;
}
msleep(sendtime);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UDPSender::send()
{
cout << myname << ": send..." << endl;
UniSetUDP::UDPHeader h;
h.nodeID = conf->getLocalNode();
h.procID = getId();
h.dcount = mypack.size();
// receive
ssize_t ret = udp->send((char*)(&h),sizeof(h));
if( ret<(ssize_t)sizeof(h) )
{
cerr << myname << "(send data header): ret=" << ret << " sizeof=" << sizeof(h) << endl;
return;
}
/*! \todo Подумать нужен ли здесь mutex */
UniSetUDP::UDPMessage::UDPDataList::iterator it = mypack.dlist.begin();
for( ; it!=mypack.dlist.end(); ++it )
{
cout << myname << "(send): " << (*it) << endl;
ssize_t ret = udp->send((char*)(&(*it)),sizeof(*it));
if( ret<(ssize_t)sizeof(*it) )
{
cerr << myname << "(send data): ret=" << ret << " sizeof=" << sizeof(*it) << endl;
break;
}
}
}
// -----------------------------------------------------------------------------
void UDPSender::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
raise(SIGTERM);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void UDPSender::sysCommand(UniSetTypes::SystemMessage *sm)
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
waitSMReady();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
}
thr->start();
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. UDPSender запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(UDPSender)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
}
break;
case SystemMessage::LogRotate:
{
// переоткрываем логи
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void UDPSender::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<< activateTimeout << " мсек";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // прерываем (перезапускаем) процесс...
throw SystemError(err.str());
}
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
try
{
shm->askSensor(it->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...){}
}
}
// ------------------------------------------------------------------------------------------
void UDPSender::sensorInfo( UniSetTypes::SensorMessage* sm )
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
if( it->si.id == sm->id )
{
uniset_spin_lock lock(it->val_lock);
it->val = sm->value;
if( it->pack_it != mypack.dlist.end() )
it->pack_it->val = sm->value;
}
break;
}
}
// ------------------------------------------------------------------------------------------
bool UDPSender::activateObject()
{
// блокирование обработки StarUp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void UDPSender::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
udp->disconnect();
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void UDPSender::readConfiguration()
{
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool UDPSender::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// просто проверка на не пустой field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// просто проверка что field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool UDPSender::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
bool UDPSender::initItem( UniXML_iterator& it )
{
string sname( it.getProp("name") );
string tid = it.getProp("id");
ObjectId sid;
if( !tid.empty() )
{
sid = UniSetTypes::uni_atoi(tid);
if( sid <= 0 )
sid = DefaultObjectId;
}
else
sid = conf->getSensorID(sname);
if( sid == DefaultObjectId )
{
if( dlog )
dlog[Debug::CRIT] << myname << "(readItem): ID not found for "
<< sname << endl;
return false;
}
UItem p;
p.si.id = sid;
p.si.node = conf->getLocalNode();
mypack.addData(sid,0);
p.pack_it = (mypack.dlist.end()--);
if( maxItem >= dlist.size() )
dlist.resize(maxItem+10);
dlist[maxItem] = p;
maxItem++;
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;
return true;
}
// ------------------------------------------------------------------------------------------
void UDPSender::initIterators()
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); it++ )
{
shm->initDIterator(it->dit);
shm->initAIterator(it->ait);
}
shm->initAIterator(aitHeartBeat);
}
// -----------------------------------------------------------------------------
void UDPSender::help_print( int argc, char* argv[] )
{
cout << "--udp-sendtime msec - Пауза между опросами. По умолчанию 200 мсек." << endl;
cout << "--udp-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--udp-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--udp-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--udp-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--udp-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола UDP: " << endl;
cout << "--udp-host [ip|hostname] - Адрес сервера" << endl;
cout << "--udp-port - Порт." << endl;
cout << "--udp-send-timeout - Таймаут на посылку ответа." << endl;
}
// -----------------------------------------------------------------------------
UDPSender* UDPSender::init_udpsender( int argc, char* argv[], UniSetTypes::ObjectId icID, SharedMemory* ic )
{
string name = conf->getArgParam("--udp-name","UDPSender1");
if( name.empty() )
{
cerr << "(UDPSender): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(UDPSender): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(rsexchange): name = " << name << "(" << ID << ")" << endl;
return new UDPSender(ID,icID,ic);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UDPSender::UItem& p )
{
return os << " sid=" << p.si.id;
}
// -----------------------------------------------------------------------------
#ifndef UDPSender_H_
#define UDPSender_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <vector>
#include <cc++/socket.h>
#include "UniSetObject_LT.h"
#include "Trigger.h"
#include "Mutex.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "ThreadCreator.h"
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
class UDPSender:
public UniSetObject_LT
{
public:
UDPSender( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UDPSender();
/*! глобальная функция для инициализации объекта */
static UDPSender* init_udpsender( int argc, char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, char* argv[] );
struct UItem
{
UItem():
val(0)
{}
IOController_i::SensorInfo si;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniSetTypes::uniset_spin_mutex val_lock;
UniSetUDP::UDPMessage::UDPDataList::iterator pack_it;
long val;
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
protected:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void poll();
void recv();
void send();
void step();
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void askSensors( UniversalIO::UIOCommand cmd );
void waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void readConfiguration();
bool check_item( UniXML_iterator& it );
private:
UDPSender();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
int sendtime; /*!< переодичность посылки данных, [мсек] */
ost::UDPSocket* udp;
ost::IPV4Host host;
ost::tpport_t port;
UniSetTypes::uniset_mutex sendMutex;
Trigger trTimeout;
int sendTimeout;
bool activated;
int activateTimeout;
UniSetUDP::UDPMessage mypack;
typedef std::vector<UItem> DMap;
DMap dlist;
int maxItem;
ThreadCreator<UDPSender>* thr;
};
// -----------------------------------------------------------------------------
#endif // UDPSender_H_
// -----------------------------------------------------------------------------
#!/bin/sh
ln -s -f ../../Utilities/scripts/uniset-start.sh
ln -s -f ../../Utilities/scripts/uniset-stop.sh stop.sh
ln -s -f ../../Utilities/scripts/uniset-functions.sh
ln -s -f ../../conf/test.xml test.xml
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetUDP
Description: Support library for UniSetIOControl
Requires: libUniSetExtensions
Version: @VERSION@
Libs: -L${libdir} -lUniSetUDP
Cflags: -I${includedir}/uniset
#!/bin/sh
uniset-start.sh -f ./uniset-udpexchange --udp-name UDPExchange --udp-host 192.168.56.255 \
--udp-broadcast 1 --udp-polltime 1000 \
--confile test.xml \
--dlog-add-levels info,crit,warn
# --udp-filter-field udp --udp-filter-value 1 \
#!/bin/sh
uniset-start.sh -f ./uniset-udpexchange --udp-name UDPExchange2 --udp-host localhost --udp-port 2049 \
--confile test.xml \
--udp-filter-field udp --udp-filter-value 2 \
--udp-ip \
--dlog-add-levels info,crit,warn
#!/bin/sh
uniset-start.sh -f ./uniset-udpreceiver --udp-name UDPExchange \
--udp-host 192.168.56.255 --udp-port 3000 \
--confile test.xml \
--udp-filter-field udp --udp-filter-value 1 \
--dlog-add-levels info,crit,warn
#!/bin/sh
uniset-start.sh -f ./uniset-udpsender --udp-name UDPExchange \
--udp-host 192.168.56.255 --udp-port 2050 --udp-broadcast 1\
--udp-sendtime 2000 \
--confile test.xml \
--dlog-add-levels info,crit,warn
# --udp-filter-field udp --udp-filter-value 1 \
#include <sstream>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "UDPExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, char** argv )
{
try
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
cout << "--smemory-id objectName - SharedMemory objectID. Default: read from <SharedMemory>" << endl;
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--udp-logfile filename - logfilename. Default: udpexchange.log" << endl;
cout << endl;
UDPExchange::help_print(argc,argv);
return 0;
}
string confile=UniSetTypes::getArgParam("--confile",argc,argv,"configure.xml");
conf = new Configuration( argc, argv, confile );
string logfilename(conf->getArgParam("--udp-logfile"));
if( logfilename.empty() )
logfilename = "udpexchange.log";
conf->initDebug(dlog,"dlog");
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
dlog.logFile( logname.str() );
ObjectId shmID = DefaultObjectId;
string sID = conf->getArgParam("--smemory-id");
if( !sID.empty() )
shmID = conf->getControllerID(sID);
else
shmID = getSharedMemoryID();
if( shmID == DefaultObjectId )
{
cerr << sID << "? SharedMemoryID not found in " << conf->getControllersSection() << " section" << endl;
return 1;
}
UDPExchange* rs = UDPExchange::init_udpexchange(argc,argv,shmID);
if( !rs )
{
dlog[Debug::CRIT] << "(udpexchange): init не прошёл..." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(rs));
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
unideb[Debug::ANY] << "(main): -------------- UDP Exchange START -------------------------\n\n";
dlog(Debug::ANY) << "\n\n\n";
dlog[Debug::ANY] << "(main): -------------- UDP Exchange START -------------------------\n\n";
act.run(false);
// msleep(500);
// rs->execute();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(udpexchange): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(udpexchange): catch ..." << std::endl;
}
return 0;
}
#include <sstream>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "UDPReceiver.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, char** argv )
{
try
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
cout << "--smemory-id objectName - SharedMemory objectID. Default: read from <SharedMemory>" << endl;
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--udp-logfile filename - logfilename. Default: udpexchange.log" << endl;
cout << endl;
UDPReceiver::help_print(argc,argv);
return 0;
}
string confile=UniSetTypes::getArgParam("--confile",argc,argv,"configure.xml");
conf = new Configuration( argc, argv, confile );
string logfilename(conf->getArgParam("--udp-logfile"));
if( logfilename.empty() )
logfilename = "udpexchange.log";
conf->initDebug(dlog,"dlog");
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
dlog.logFile( logname.str() );
ObjectId shmID = DefaultObjectId;
string sID = conf->getArgParam("--smemory-id");
if( !sID.empty() )
shmID = conf->getControllerID(sID);
else
shmID = getSharedMemoryID();
if( shmID == DefaultObjectId )
{
cerr << sID << "? SharedMemoryID not found in " << conf->getControllersSection() << " section" << endl;
return 1;
}
UDPReceiver* udp = UDPReceiver::init_udpreceiver(argc,argv,shmID);
if( !udp )
{
dlog[Debug::CRIT] << "(udpreceiver): init не прошёл..." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(udp));
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
unideb[Debug::ANY] << "(main): -------------- UDPRecevier START -------------------------\n\n";
dlog(Debug::ANY) << "\n\n\n";
dlog[Debug::ANY] << "(main): -------------- UDPReceiver START -------------------------\n\n";
act.run(false);
// msleep(500);
// rs->execute();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(udpexchange): " << ex << std::endl;
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << s.str() << endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(udpexchange): catch ..." << std::endl;
}
return 0;
}
#include <sstream>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "UDPSender.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, char** argv )
{
try
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
cout << "--smemory-id objectName - SharedMemory objectID. Default: read from <SharedMemory>" << endl;
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--udp-logfile filename - logfilename. Default: udpexchange.log" << endl;
cout << endl;
UDPSender::help_print(argc,argv);
return 0;
}
string confile=UniSetTypes::getArgParam("--confile",argc,argv,"configure.xml");
conf = new Configuration( argc, argv, confile );
string logfilename(conf->getArgParam("--udp-logfile"));
if( logfilename.empty() )
logfilename = "udpexchange.log";
conf->initDebug(dlog,"dlog");
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
dlog.logFile( logname.str() );
ObjectId shmID = DefaultObjectId;
string sID = conf->getArgParam("--smemory-id");
if( !sID.empty() )
shmID = conf->getControllerID(sID);
else
shmID = getSharedMemoryID();
if( shmID == DefaultObjectId )
{
cerr << sID << "? SharedMemoryID not found in " << conf->getControllersSection() << " section" << endl;
return 1;
}
UDPSender* udp = UDPSender::init_udpsender(argc,argv,shmID);
if( !udp )
{
dlog[Debug::CRIT] << "(udpsender): init не прошёл..." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(udp));
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
unideb[Debug::ANY] << "(main): -------------- UDPSender START -------------------------\n\n";
dlog(Debug::ANY) << "\n\n\n";
dlog[Debug::ANY] << "(main): -------------- UDPSender START -------------------------\n\n";
act.run(false);
// msleep(500);
// rs->execute();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(udpsender): " << ex << std::endl;
}
catch( ost::SockException& e )
{
dlog[Debug::CRIT] << "(udpsender): " << e.getSystemErrorString() << endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(udpsender): catch ..." << std::endl;
}
return 0;
}
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2008/02/07 21:04:56 $
* \version $Id: CallBackTimer_template.h,v 1.6 2008/02/07 21:04:56 vpashka Exp $
*/
// --------------------------------------------------------------------------
# ifndef CallBackTimer_TEMPLATE_H_
# define CallBackTimer_TEMPLATE_H_
// --------------------------------------------------------------------------
#include <unistd.h>
#include <sstream>
#include "CallBackTimer.h"
// ------------------------------------------------------------------------------------------
template <class Caller> class CallBackTimer;
// ------------------------------------------------------------------------------------------
/*! Создание таймера
\param r - указатель на заказчика
*/
template <class Caller>
CallBackTimer<Caller>::CallBackTimer( Caller* r, Action a ):
cal(r),
act(a),
terminated(false)
{
thr = new ThreadCreator<CallBackTimer>(this, &CallBackTimer<Caller>::work);
}
// ------------------------------------------------------------------------------------------
template <class Caller>
CallBackTimer<Caller>::CallBackTimer():
cal(null),
terminated(false)
{
thr = new ThreadCreator<CallBackTimer>(this, &CallBackTimer<Caller>::work);
}
// ------------------------------------------------------------------------------------------
template <class Caller>
CallBackTimer<Caller>::~CallBackTimer()
{
terminate();
clearTimers();
delete thr;
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::work()
{
terminated = false;
while( !terminated )
{
usleep(UniSetTimer::MIN_QUANTITY_TIME_MKS);
for( typename TimersList::iterator li=lst.begin(); li!=lst.end(); ++li )
{
if( li->pt.checkTime() )
{
(cal->*act)( li->id );
li->pt.reset();
}
}
}
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::run()
{
if( !terminated )
terminate();
startTimers();
// PosixThread::start(static_cast<PosixThread*>(this));
thr->start();
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::terminate()
{
// timeAct = 0;
terminated = true;
usleep(1000);
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::add( int id, int timeMS )throw(UniSetTypes::LimitTimers)
{
if( lst.size() >= MAXCallBackTimer )
{
ostringstream err;
err << "CallBackTimers: превышено максимальное количество таймеров" << MAXCallBackTimer;
throw UniSetTypes::LimitTimers(err.str());
}
PassiveTimer pt(timeMS);
TimerInfo ti(id, pt);
lst.push_back(ti);
// lst[id] = ti;
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::remove( int id )
{
// STL - способ поиска
typename TimersList::iterator li= find_if(lst.begin(),lst.end(),FindId_eq(id));
if( li!=lst.end() )
lst.erase(li);
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::startTimers()
{
for( typename TimersList::iterator li=lst.begin(); li!=lst.end(); ++li)
{
li->pt.reset();
}
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::clearTimers()
{
lst.clear();
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::reset( int id )
{
typename TimersList::iterator li= find_if(lst.begin(),lst.end(),FindId_eq(id));
if( li!=lst.end() )
li->pt.reset();
}
// ------------------------------------------------------------------------------------------
template <class Caller>
void CallBackTimer<Caller>::setTiming( int id, int timeMS )
{
typename TimersList::iterator li= find_if(lst.begin(),lst.end(),FindId_eq(id));
if( li!=lst.end() )
li->pt.setTimer(timeMS);
}
// ------------------------------------------------------------------------------------------
template <class Caller>
int CallBackTimer<Caller>::getInterval( int id )
{
typename TimersList::iterator li= find_if(lst.begin(),lst.end(),FindId_eq(id));
if( li!=lst.end() )
return li->pt.getInterval();
return -1;
}
// ------------------------------------------------------------------------------------------
template <class Caller>
int CallBackTimer<Caller>::getCurrent( int id )
{
typename TimersList::iterator li= find_if(lst.begin(),lst.end(),FindId_eq(id));
if( li!=lst.end() )
return li->pt.getCurrent();
return -1;
}
// ------------------------------------------------------------------------------------------
# endif //CallBackTimer_H_
...@@ -18,47 +18,46 @@ ...@@ -18,47 +18,46 @@
*/ */
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/*! \file /*! \file
* \brief Реализация RepositoryAgent
* \author Pavel Vainerman * \author Pavel Vainerman
* \date $Date: 2005/01/28 20:52:21 $
* \version $Id: RepositoryAgent.h,v 1.5 2005/01/28 20:52:21 vitlav Exp $
*/ */
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#ifndef ProxyManager_H_ #ifndef RepositoryAgent_H_
#define ProxyManager_H_ #define RepositoryAgent_H_
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <map> #include "RepositoryAgent_i.hh"
#include "UniSetObject.h" #include "BaseProcess_i.hh"
#include "BaseProcess.h"
#include "UniSetTypes.h"
#include "ObjectIndex.h"
//----------------------------------------------------------------------------------------
/*! \class RepositoryAgent
*/
class RepositoryAgent:
public POA_RepositoryAgent_i,
public BaseProcess
{
public:
//---------------------------------------------------------------------------- RepositoryAgent( ObjectId id, const UniSetTypes::ObjectInfo *pObjectsMap );
class PassiveObject; ~RepositoryAgent();
//----------------------------------------------------------------------------
/*! \class ProxyManager
* Менеджер пассивных объектов, который выступает вместо них во всех внешних связях....
*/
class ProxyManager:
public UniSetObject
{
public: // virtual void registration(const char* name, ::CORBA::Object_ptr ref);
ProxyManager( UniSetTypes::ObjectId id ); // virtual void unregistration(const char* name, ::CORBA::Object_ptr ref);
~ProxyManager();
void attachObject( PassiveObject* po, UniSetTypes::ObjectId id ); virtual CORBA::Object_ptr resolve(const char* name);
void detachObject( UniSetTypes::ObjectId id ); virtual CORBA::Object_ptr resolveid( UniSetTypes::ObjectId id);
UniversalInterface* uin;
protected: virtual void execute();
ProxyManager();
virtual void processingMessage( UniSetTypes::VoidMessage* msg );
virtual void allMessage( UniSetTypes::VoidMessage* msg );
virtual bool activateObject(); protected:
virtual bool disactivateObject(); RepositoryAgent();
ObjectIndex oind;
private: private:
typedef std::map<UniSetTypes::ObjectId, PassiveObject*> PObjectMap;
PObjectMap omap;
}; };
//----------------------------------------------------------------------------------------
#endif // ProxyManager #endif
//----------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Vitaly Lipatov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*! \file
* \author Vitaly Lipatov
* \date $Date: 2007/01/02 22:30:48 $
* \version $Id: TextFileIndex.h,v 1.7 2007/01/02 22:30:48 vpashka Exp $
* \par
* Базовый класс получения строки по её индексу
*/
#include <string>
class TextFileIndex: public TextIndex
{
public:
virtual ~TextFileIndex(){}
// Получить строку по коду
virtual std::string getText(int id);
// При инициализации указывается название файла для считывания
TextFileIndex(std::string filename);
};
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2008/06/01 21:36:19 $
* \version $Id: TriggerAND_template.h,v 1.8 2008/06/01 21:36:19 vpashka Exp $
*/
// --------------------------------------------------------------------------
#include "TriggerAND.h"
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
TriggerAND<Caller,InputType>::TriggerAND(Caller* c, Action a):
cal(c),
act(a)
{
}
template<class Caller, typename InputType>
TriggerAND<Caller,InputType>::~TriggerAND()
{
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
bool TriggerAND<Caller,InputType>::commit(InputType num, bool state)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
{
inputs[num] = state;
check();
return true;
}
return false;
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerAND<Caller,InputType>::add(InputType num, bool state)
{
inputs[num] = state;
check();
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerAND<Caller,InputType>::remove(InputType num)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
inputs.erase(it);
check();
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
bool TriggerAND<Caller,InputType>::getState(InputType num)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
return it->second;
return false; // throw NotFound
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerAND<Caller,InputType>::check()
{
bool old = out;
for( typename InputMap::iterator it=inputs.begin(); it!=inputs.end(); ++it )
{
if( !it->second )
{
// если хоть один вход "0" на выходе "0"
// и прекращаем дальнейший поиск
out = false;
if( old != out )
{
// try
// {
(cal->*act)(out);
// }
// catch(...){}
}
return;
}
}
out = true;
if( old != out )
{
// try
// {
(cal->*act)(out);
// }
// catch(...){}
}
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerAND<Caller,InputType>::update()
{
(cal->*act)(out);
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerAND<Caller,InputType>::reset()
{
out = false;
(cal->*act)(out);
}
//---------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2008/06/01 21:36:19 $
* \version $Id: TriggerOR_template.h,v 1.8 2008/06/01 21:36:19 vpashka Exp $
*/
// --------------------------------------------------------------------------
#include "TriggerOR.h"
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
TriggerOR<Caller,InputType>::TriggerOR(Caller* c, Action a):
cal(c),
act(a)
{
}
template<class Caller, typename InputType>
TriggerOR<Caller,InputType>::~TriggerOR()
{
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
bool TriggerOR<Caller,InputType>::commit(InputType num, bool state)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
{
inputs[num] = state;
check();
return true;
}
return false;
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerOR<Caller,InputType>::add(InputType num, bool state)
{
inputs[num] = state;
check();
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerOR<Caller,InputType>::remove(InputType num)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
inputs.erase(it);
check();
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
bool TriggerOR<Caller,InputType>::getState(InputType num)
{
typename InputMap::iterator it=inputs.find(num);
if( it!=inputs.end() )
return it->second;
return false; // throw NotFound
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerOR<Caller,InputType>::check()
{
bool old = out;
for( typename InputMap::iterator it=inputs.begin(); it!=inputs.end(); ++it )
{
if( it->second )
{
// если хоть один вход "1" на выходе "1"
// и прекращаем дальнейший поиск
out = true;
if( old != out )
{
// try
// {
(cal->*act)(out);
// }
// catch(...){}
}
return;
}
}
out = false;
if( old != out )
{
// try
// {
(cal->*act)(out);
// }
// catch(...){}
}
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerOR<Caller,InputType>::update()
{
(cal->*act)(out);
}
//---------------------------------------------------------------------------
template<class Caller, typename InputType>
void TriggerOR<Caller,InputType>::reset()
{
out = false;
(cal->*act)(out);
}
//---------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Pavel Vainerman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// --------------------------------------------------------------------------
/*! \file
* \author Pavel Vainerman
* \date $Date: 2008/06/01 21:36:19 $
* \version $Id: TriggerOutput_template.h,v 1.4 2008/06/01 21:36:19 vpashka Exp $
*/
// --------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "TriggerOutput.h"
//---------------------------------------------------------------------------
template<class Caller, typename OutIdType, typename ValueType>
TriggerOutput<Caller,OutIdType,ValueType>::TriggerOutput( Caller* r, Action a):
cal(r),
act(a)
{
}
template <class Caller, typename OutIdType, typename ValueType>
TriggerOutput<Caller,OutIdType,ValueType>::~TriggerOutput()
{
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::add(OutIdType num, ValueType val)
{
outs[num] = val;
set(num,val);
try
{
(cal->*act)(num,val);
}
catch(...){}
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::remove(OutIdType num)
{
typename OutList::iterator it=outs.find(num);
if( it!=outs.end() )
outs.erase(it);
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
bool TriggerOutput<Caller,OutIdType,ValueType>::getState(OutIdType out)
{
typename OutList::iterator it=outs.find(out);
if( it!=outs.end() )
return it->second;
return false;
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::set(OutIdType out, ValueType val)
{
typename OutList::iterator it=outs.find(out);
if( it==outs.end() )
return;
// потом val
ValueType prev(it->second);
it->second = val;
if( prev != val )
{
check(out); // выставляем сперва все нули
try
{
(cal->*act)(it->first, it->second);
}
catch(...){}
}
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::check(OutIdType newout)
{
for( typename OutList::iterator it=outs.begin(); it!=outs.end(); ++it )
{
if( it->first != newout && it->second )
{
it->second = 0;
// try
// {
(cal->*act)(it->first, it->second);
// }
// catch(...){}
}
}
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::update()
{
for( typename OutList::iterator it=outs.begin(); it!=outs.end(); ++it )
(cal->*act)(it->first, it->second);
}
//---------------------------------------------------------------------------
template <class Caller, typename OutIdType, typename ValueType>
void TriggerOutput<Caller,OutIdType,ValueType>::reset()
{
for( typename OutList::iterator it=outs.begin(); it!=outs.end(); ++it )
{
it->second = 0;
(cal->*act)(it->first, it->second);
}
}
//---------------------------------------------------------------------------
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
using namespace std; using namespace std;
using namespace ModbusRTU; using namespace ModbusRTU;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int ModbusTCPCore::readNextData( ost::TCPStream* tcp, int ModbusTCPCore::readNextData( ost::TCPStream* tcp,
std::queue<unsigned char>& qrecv, int max ) std::queue<unsigned char>& qrecv, int max )
{ {
if( !tcp || !tcp->isConnected() ) if( !tcp || !tcp->isConnected() )
...@@ -16,15 +16,15 @@ int ModbusTCPCore::readNextData( ost::TCPStream* tcp, ...@@ -16,15 +16,15 @@ int ModbusTCPCore::readNextData( ost::TCPStream* tcp,
tcp->read(&c,sizeof(c)); tcp->read(&c,sizeof(c));
if( tcp->gcount() <= 0 ) if( tcp->gcount() <= 0 )
break; break;
qrecv.push( (unsigned char)(c) ); qrecv.push( (unsigned char)(c) );
} }
return i; return i;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int ModbusTCPCore::getNextData( unsigned char* buf, int len, int ModbusTCPCore::getNextData( unsigned char* buf, int len,
std::queue<unsigned char>& qrecv, std::queue<unsigned char>& qrecv,
ost::TCPStream* tcp ) ost::TCPStream* tcp )
{ {
if( !tcp || !tcp->isConnected() ) if( !tcp || !tcp->isConnected() )
...@@ -60,17 +60,17 @@ mbErrCode ModbusTCPCore::sendData( unsigned char* buf, int len, ost::TCPStream* ...@@ -60,17 +60,17 @@ mbErrCode ModbusTCPCore::sendData( unsigned char* buf, int len, ost::TCPStream*
{ {
for( int i=0; i<len; i++ ) for( int i=0; i<len; i++ )
(*tcp) << buf[i]; (*tcp) << buf[i];
return erNoError; return erNoError;
} }
catch( ost::SockException& e ) catch( ost::SockException& e )
{ {
// cerr << "(send): " << e.getString() << ": " << e.getSystemErrorString() << endl; // cerr << "(send): " << e.getString() << ": " << e.getSystemErrorString() << endl;
} }
catch(...) catch(...)
{ {
// cerr << "(send): cath..." << endl; // cerr << "(send): cath..." << endl;
} }
return erHardwareError; return erHardwareError;
} }
......
...@@ -5,4 +5,3 @@ ...@@ -5,4 +5,3 @@
noinst_LTLIBRARIES = libThreads.la noinst_LTLIBRARIES = libThreads.la
libThreads_la_SOURCES=PosixThread.cc libThreads_la_SOURCES=PosixThread.cc
include $(top_builddir)/conf/setting.mk include $(top_builddir)/conf/setting.mk
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Vitaly Lipatov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*! \file
* \author Vitaly Lipatov
* \date $Date: 2005/01/28 21:14:18 $
* \par
* Базовый класс получения строки по её индексу
*/
#include "TextFileIndex.h"
#include <iostream.h>
// В конструкторе загружаем значения из файла
std::string TextFileIndex::TextFileIndex(string filename)
{
textmap[id] = str;
}
//
std::string TextIndex::getText(int id)
{
return textmap[id];
}
#!/bin/sh
ln -s -f /usr/bin/uniset-stop.sh stop.sh
ln -s -f ../conf/test.xml test.xml
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