Commit 4a0791b7 authored by Pavel Vainerman's avatar Pavel Vainerman

Удалил лишние файлы после синхронизации (rebase + pathes) c uniset/2.0

parent 818ffc50
/* 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/01/28 20:27:06 $
* \version $Id: UniSetObserver_i.idl,v 1.4 2005/01/28 20:27:06 vitlav Exp $
*/
// --------------------------------------------------------------------------
#ifndef UniSetObserver_i_IDL_
#define UniSetObserver_i_IDL_
// --------------------------------------------------------------------------------------------------------------
#include "../UniSetTypes/UniSetTypes_i.idl"
// --------------------------------------------------------------------------------------------------------------
/*!
* \interface UniSetObserver_i
* \brief шаблон "Наблюдатель"
*/
interface UniSetObserver_i
{
// исключения
exception NameNotFound
{
string err;
};
void attach( in UniSetTypes::ObjectId id, in UniSetTypes::ObjectId fromid ) raises(NameNotFound);
void detach( in UniSetTypes::ObjectId id, in UniSetTypes::ObjectId fromid ) raises(NameNotFound);
};
// --------------------------------------------------------------------------------------------------------------
#endif
\ No newline at end of file
/* 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/11/01 21:44:53 $
* \version $Id: DBServer_i.idl,v 1.5 2005/11/01 21:44:53 vpashka Exp $
*/
// --------------------------------------------------------------------------
#ifndef DBServer_i_IDL_
#define DBServer_i_IDL_
// --------------------------------------------------------------------------
#include "../UniSetTypes/UniSetTypes_i.idl"
#include "../UniSetTypes/UniSetObject_i.idl"
// --------------------------------------------------------------------------
/*!
* \interface DBServer_i
* \brief Интерфейс сервера базы данных системы
*/
interface DBServer_i: UniSetObject_i
{
// исключения
exception DBError
{
string errmsg;
};
void query(in string query) raises(DBError);
string hostname();
string dbname();
};
#endif
\ No newline at end of file
/* 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/01/28 20:27:06 $
* \version $Id: InfoServer_i.idl,v 1.4 2005/01/28 20:27:06 vitlav Exp $
*/
// --------------------------------------------------------------------------
#ifndef InfoServer_i_IDL_
#define InfoServer_i_IDL_
// --------------------------------------------------------------------------
#include "../UniSetTypes/UniSetTypes_i.idl"
#include "../UniSetTypes/UniSetObject_i.idl"
// --------------------------------------------------------------------------
/*!
* \interface InfoServer_i
* \brief Интерфейс к серверу сообщений
*/
interface InfoServer_i: UniSetObject_i
{
// исключения
exception MsgNotFound
{
UniSetTypes::MessageCode bad_code;
};
// исключения
exception MsgBadRange
{
};
/*! Заказ информации о приходе сообщения */
void ackMessage(in UniSetTypes::MessageCode mid, in UniSetTypes::ConsumerInfo ci,
in UniversalIO::UIOCommand cmd, in boolean acknotify ) raises(MsgNotFound);
/*! Заказ информации о приходе сообщений из диапазона */
void ackMessageRange(in UniSetTypes::MessageCode from, in UniSetTypes::MessageCode to,
in UniSetTypes::ConsumerInfo ci,
in UniversalIO::UIOCommand cmd, in boolean acknotify ) raises(MsgNotFound,MsgBadRange);
};
// --------------------------------------------------------------------------
#endif
############################################################################
# This file is part of the UniSet library #
############################################################################
# Каталоги для размещения генерируемых CC- и HH-файлов соответственно
CCDIR=$(top_builddir)/src/Services
HHDIR=$(top_builddir)/include
# Исходные файлы IDL
IDLFILES=TimerService_i.idl InfoServer_i.idl
include $(top_builddir)/conf/idl.mk
idl_include_HEADERS = *.idl
idl_includedir = $(datadir)/idl/@PACKAGE@/Services
/* 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/01/28 20:27:06 $
* \version $Id: NetService_i.idl,v 1.4 2005/01/28 20:27:06 vitlav Exp $
*/
// --------------------------------------------------------------------------
#ifndef NetService_i_IDL_
#define BaseProcess_i_IDL_
// --------------------------------------------------------------------------
#include "../UniSetTypes/UniSetTypes_i.idl"
// --------------------------------------------------------------------------
/*!
* \interface NetService_i
*/
interface NetService_i
{
void registration( in BaseObjectName name, in Object ref );
void unregistration( in BaseObjectName name, in Object ref );
Object resolve(in BaseObjectName name);
Object resolveid( in BaseObjectId name);
};
#endif
\ No newline at end of file
/* 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/11/01 21:44:53 $
* \version $Id: RepositoryAgent_i.idl,v 1.5 2005/11/01 21:44:53 vpashka Exp $
*/
// --------------------------------------------------------------------------
#ifndef RepositoryAgent_i_IDL_
#define RepositoryAgent_i_IDL_
// --------------------------------------------------------------------------
#include "../UniSetTypes/UniSetObject_i.idl"
// --------------------------------------------------------------------------------------------------------------
/*!
* \interface RepositoryAgent_i
* \brief Интерфейс агента репозитория
* Агент репозитрория предназначен для получения доступа к объектам с удаленных узлов.
* Он запускается на каждом узле, и с других узлов через него можно получить доступ
* к процессам, датчикам и т.п на данном узле.
*/
interface RepositoryAgent_i: UniSetObject_i
{
// исключения
exception NameNotFound
{
string errmsg;
};
exception ResolveError
{
string errmsg;
};
// void registration( in BaseObjectName name, in Object ref );
// void unregistration( in BaseObjectName name, in Object ref );
// Object resolve(in BaseObjectName name) raises(NameNotFound, ResolveError);
Object resolveid( in UniSetTypes::ObjectId name) raises(NameNotFound, ResolveError);
};
#endif
\ No newline at end of file
/* 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/01/28 21:24:12 $
* \version $Id: TimerService_i.idl,v 1.1 2005/01/28 21:24:12 vitlav Exp $
*/
// --------------------------------------------------------------------------
#ifndef TimerService_i_IDL_
#define TimerService_i_IDL_
// --------------------------------------------------------------------------
#include "../UniSetTypes/UniSetTypes_i.idl"
#include "../UniSetTypes/UniSetObject_i.idl"
// --------------------------------------------------------------------------
/*!
* \interface TimerService_i
*/
interface TimerService_i: UniSetObject_i
{
/*! Превышения максимально возможного
* количества таймеров
*/
exception LimitTimers
{
long maxTimers;
};
/*! Таймер с таким id уже заказан
* (от данного заказчика)
*/
exception TimerAlreadyExist
{
};
/*! Задан интервал меньше
* минимально разрешённого
*/
exception TimeMSLowLimit
{
unsigned long lowLimitMS; // instead timeout_t
};
/*! Информация о таймере */
struct Timer
{
UniSetTypes::TimerId timerid;
unsigned long timeMS;
long ticks; // instead clock_t
short msgPriority;
};
/*! заказ таймера */
void askTimer( in Timer ti, in UniSetTypes::ConsumerInfo ci )
raises(LimitTimers, TimerAlreadyExist, TimeMSLowLimit);
// void setSysTime(...);
// void getSysTime(...);
};
#endif
\ No newline at end of file
/* 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/12/18 20:24:11 $
* \version $Id: ObjectsManager_i.idl,v 1.2 2007/12/18 20:24:11 vpashka Exp $
*/
// --------------------------------------------------------------------------
#ifndef ObjectsManager_i_IDL_
#define ObjectsManager_i_IDL_
// ---------------------------------------------------------------------------
#include "UniSetObject_i.idl"
#include "UniSetTypes_i.idl"
// ---------------------------------------------------------------------------
//module UniSet
//{
/*!
* \interface ObjectsManager_i
* \brief Интерфейс менеджера объектов
* \author Pavel Vainerman
* \version
* \date September 2001-
*
* Базовый класс для менеджеров объектов. Позволяет посылать сообщение
* ко всем объектам сразу.
*/
interface ObjectsManager_i : UniSetObject_i
{
/*!< распространить сообщение всем подчиненным объектам */
void broadcast(in UniSetTypes::TransportMessage msg);
/*! получение информации о состоянии подчиненных объектов(менеджеров)
* \param MaxLength - ограничение размера возвращаемой
* последовательности структур SimpleInfo.
* \note Если у менеджера количество подчиненных объектов
* больше MaxLength, то он вернет информацию только
* о первых MaxLength объектах. Если <=, то количество
* равное количеству объектов.
* \note Возвращаемые данные содержат в себе инфо. о всех
* подчиненных объектах данного менеджера, а также объектах
* подчиненных данному менеджеру менеджерах и их объектах
* и т.п. и т.п. рекурсивно... Так что MaxLength должно быть
* достаточным.
* \todo Подумать насчет применения итератора, при слишком
* большом( >1000 ) количестве подчиненных объектов...
*/
UniSetTypes::SimpleInfoSeq getObjectsInfo( in long MaxLength );
};
//}; // end of module UniSet
#endif
// --------------------------------------------------------------------------------------------------------------
############################################################################
# This file is part of the UniSet library #
############################################################################
bin_PROGRAMS = uniset-infoserver
uniset_infoserver_SOURCES = main.cc
uniset_infoserver_LDADD = $(top_builddir)/lib/libUniSet.la
uniset_infoserver_CPPFLAGS = -I$(top_builddir)/lib $(SIGC_CFLAGS)
include $(top_builddir)/conf/setting.mk
#include "Configuration.h"
#include "InfoServer.h"
#include "ISRestorer.h"
#include "ObjectsActivator.h"
#include "Debug.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// --------------------------------------------------------------------------
static void short_usage()
{
cout << "Usage: uniset-infoserver --name ObjectId [--askfile filename]"
<< " [--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->getInfoServer();
// определяем ID объекта
string name = conf->getArgParam("--name");
if( !name.empty() )
{
if( ID != UniSetTypes::DefaultObjectId )
{
unideb[Debug::WARN] << "(InfoServer::main): переопределяем ID заданнй в "
<< conf->getConfFileName() << endl;
}
ID = conf->oind->getIdByName(conf->getServicesSection()+"/"+name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(InfoServer): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getServicesSection() << endl;
return 1;
}
}
else if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(DBServer::main): Не удалось определить ИДЕНТИФИКАТОР сервера" << endl;
short_usage();
return 1;
}
// определяем ask-файл
string askfile = conf->getArgParam("--askfile",conf->getConfFileName());
if( askfile.empty() )
{
InfoServer is(ID,new ISRestorer_XML(askfile));
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(&is));
act.run(false);
}
else
{
InfoServer is(ID);
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(&is));
act.run(false);
}
return 0;
}
catch(Exception& ex)
{
cerr << "(InfoServer::main): " << ex << endl;
}
catch(...)
{
cerr << "(InfoServer::main): catch ..." << endl;
}
return 1;
}
# This file is a part of the NCS project. (c) 1999-2002 All rights reserved.
# $Id: idl.mk,v 1.2 2006/10/14 16:53:22 vpashka Exp $
# Общий файл для IDL
# Нужно иметь в виду, что когда порождаемые omniidl файлы
# будут кем-либо изменены, они перегенерируются только
# при изменении исходного IDL
IDLFLAGS = -I$(top_builddir)/IDL
# Получения списков генерируемых файлов
HHTARG=$(patsubst %.idl, ${HHDIR}/%.hh, ${IDLFILES})
CCTARG=$(patsubst %.idl, ${CCDIR}/%SK.cc, ${IDLFILES})
########################################################################
all: ${HHTARG} ${CCTARG}
dynamic: all
${HHTARG} ${CCTARG}: ${IDLFILES}
for i in $^; do ${IDL} -v -bcxx ${IDLFLAGS} $$i; done
mv --target-directory=${HHDIR} *.hh
mv --target-directory=${CCDIR} *.cc
.PHONY: clean depend
clean:
${RM} ${HHTARG} ${CCTARG}
depend:
install:
bin_PROGRAMS = @PACKAGE@-udpexchange
noinst_PROGRAMS = @PACKAGE@-udpreceiver @PACKAGE@-unetexchange
#@PACKAGE@-udpsender
# не забывайте править версию в pc-файле
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 UDPNReceiver.cc UDPReceiver.cc UNetReceiver.cc UNetSender.cc UNetExchange.cc
#UDPSender.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)
@PACKAGE@_unetexchange_SOURCES = unetexchange.cc
@PACKAGE@_unetexchange_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@_unetexchange_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),
packetnum(1)
{
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.msg.header.dcount;
h.num = packetnum++;
mypack.msg.header = h;
/*
int ind = 0;
memcpy(udpbuf,(char*)(&h),sizeof(h));
ind += sizeof(h);
memcpy( &(udpbuf[ind]),&(mypack.data),mypack.size());
ind += mypack.size();
*/
cout << "************* send header: " << mypack.msg.header << endl;
int sz = mypack.size() * sizeof(UniSetUDP::UDPHeader);
if( udp->isPending(ost::Socket::pendingOutput) )
{
// ssize_t ret = udp->send( (char*)&(mypack.msg),sizeof(mypack.msg));
// if( ret<sizeof(mypack.msg) )
ssize_t ret = udp->send( (char*)&(mypack.msg),sz);
if( ret < sz )
{
cerr << myname << "(send data header): ret=" << ret << " sizeof=" << sz << endl;
return;
}
cout << "send OK. byte count=" << ret << endl;
}
#if 0
/*
if( udp->isPending(ost::Socket::pendingOutput) )
{
size_t ret = udp->send((char*)(&h),sizeof(h));
if( ret<(size_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;
size_t ret = udp->send((char*)(&(*it)),sizeof(UniSetUDP::UDPData));
if( ret<(size_t)sizeof(UniSetUDP::UDPData) )
{
cerr << myname << "(send data): ret=" << ret << " sizeof=" << sizeof(UniSetUDP::UDPData) << endl;
break;
}
}
// }
#endif
}
// -----------------------------------------------------------------------------
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_ind != -1 )
mypack.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_ind = mypack.size()-1;
if( maxItem >= mypack.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;
int pack_ind;
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;
long packetnum;
};
// -----------------------------------------------------------------------------
#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
UniSetUDP::UDPMessage pack;
if( udp->isInputReady(recvTimeout) )
{
/*
size_t ret = udp->UDPReceive::receive(&h,sizeof(h));
if( ret<(size_t)sizeof(h) )
{
cerr << myname << "(receive): ret=" << ret << " sizeof=" << sizeof(pack.msg) << endl;
return;
}
cerr << myname << "(receive): OK. ret=" << ret << " sizeof=" << sizeof(pack.msg) << endl;
}
/*
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++ )
{
size_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret < (size_t)sizeof(d) )
return;
}
return;
}
#endif
for( int i=0; i<100;i++ )
{
size_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret<(size_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;
// }
#endif
}
// -----------------------------------------------------------------------------
UDPNReceiver* UDPNReceiver::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 UDPNReceiver(ID,icID,ic);
//return new UDPNReceiver(ID,icID,ic);
return 0;
}
// -----------------------------------------------------------------------------
#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; }
/*! глобальная функция для инициализации объекта */
static UDPNReceiver* init_udpreceiver( int argc, char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
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
<< " pnum=" << p.num;
}
// -----------------------------------------------------------------------------
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():
count(0)
{
}
// -----------------------------------------------------------------------------
bool UDPMessage::addData( const UniSetUDP::UDPData& dat )
{
if( count >= MaxDataCount )
return false;
msg.dat[count] = dat;
count++;
msg.header.dcount = count;
return true;
}
// -----------------------------------------------------------------------------
bool UDPMessage::addData( long id, long val)
{
UDPData d(id,val);
return addData(d);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
#ifndef UDPPacket_H_
#define UDPPacket_H_
// -----------------------------------------------------------------------------
#include <cc++/socket.h>
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
namespace UniSetUDP
{
struct UDPHeader
{
UDPHeader():num(0),nodeID(0),procID(0),dcount(0){}
timeout_t num;
long nodeID;
long procID;
size_t dcount;
friend std::ostream& operator<<( std::ostream& os, UDPHeader& p );
}__attribute__((packed));
static unsigned long MaxPacketNum = std::numeric_limits<unsigned long>::max();
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));
static const int MaxDataLen = 8192;
static const int MaxDataCount = ( MaxDataLen - sizeof(UniSetUDP::UDPHeader) ) / sizeof(UDPData);
struct DataPacket
{
UDPHeader header;
UDPData dat[MaxDataCount];
}__attribute__((packed));
struct UDPMessage:
public UDPHeader
{
UDPMessage();
bool addData( const UDPData& dat );
bool addData( long id, long val );
inline bool isFull(){ return count<MaxDataCount; }
inline int size(){ return count; }
inline int byte_size(){ return count*sizeof(UDPData); }
DataPacket msg;
int count;
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;
// -----------------------------------------------------------------------------
bool UDPReceiver::PacketCompare::operator()(const UniSetUDP::UDPMessage& lhs,
const UniSetUDP::UDPMessage& rhs) const
{
// if( lhs.msg.header.num == rhs.msg.header.num )
// return (lhs.msg < rhs.msg);
return lhs.msg.header.num > rhs.msg.header.num;
}
// ------------------------------------------------------------------------------------------
UDPReceiver::UDPReceiver( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
shm(0),
initPause(0),
udp(0),
activated(false),
icache(200),
cache_init_ok(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"), 10);
updatetime = conf->getArgPInt("--udp-updatetime",it.getProp("updatetime"), 100);
steptime = conf->getArgPInt("--udp-steptime",it.getProp("steptime"), 100);
minBufSize = conf->getArgPInt("--udp-minbufsize",it.getProp("minBufSize"), 30);
maxProcessingCount = conf->getArgPInt("--udp-maxprocessingcount",it.getProp("maxProcessingCount"), 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( !activated )
return;
if( tm->id == tmStep )
step();
else if( tm->id == tmUpdate )
update();
}
// -----------------------------------------------------------------------------
void UDPReceiver::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 UDPReceiver::update()
{
UniSetUDP::UDPMessage p;
bool buf_ok = false;
{
uniset_mutex_lock l(packMutex);
if( qpack.size() <= minBufSize )
return;
buf_ok = true;
}
int k = maxProcessingCount;
while( buf_ok && k>0 )
{
{
uniset_mutex_lock l(packMutex);
p = qpack.top();
qpack.pop();
}
if( labs(p.msg.header.num - pnum) > 1 )
{
dlog[Debug::CRIT] << "************ FAILED! ORDER PACKETS! recv.num=" << pack.msg.header.num
<< " num=" << pnum << endl;
}
pnum = p.msg.header.num;
k--;
{
uniset_mutex_lock l(packMutex);
buf_ok = ( qpack.size() > minBufSize );
}
initCache(p, !cache_init_ok);
for( int i=0; i<p.msg.header.dcount; i++ )
{
try
{
UniSetUDP::UDPData& d = p.msg.dat[i];
ItemInfo& ii(icache[i]);
if( ii.id != d.id )
{
dlog[Debug::WARN] << myname << "(update): reinit cache for sid=" << d.id << endl;
ii.id = d.id;
shm->initAIterator(ii.ait);
shm->initDIterator(ii.dit);
}
if( ii.iotype == UniversalIO::DigitalInput )
shm->localSaveState(ii.dit,d.id,d.val,getId());
else if( ii.iotype == UniversalIO::AnalogInput )
shm->localSaveValue(ii.ait,d.id,d.val,getId());
else if( ii.iotype == UniversalIO::AnalogOutput )
shm->localSetValue(ii.ait,d.id,d.val,getId());
else if( ii.iotype == UniversalIO::DigitalOutput )
shm->localSetState(ii.dit,d.id,d.val,getId());
else
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << d.id << endl;
}
catch( UniSetTypes::Exception& ex)
{
dlog[Debug::CRIT] << myname << "(update): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(update): catch ..." << std::endl;
}
}
}
}
// -----------------------------------------------------------------------------
void UDPReceiver::poll()
{
cerr << "******************* pool start" << endl;
while( activated )
{
try
{
recv();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(poll): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(poll): catch ..." << std::endl;
}
msleep(polltime);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UDPReceiver::recv()
{
if( udp->isInputReady(recvTimeout) )
{
size_t ret = udp->UDPReceive::receive(&h,sizeof(h));
if( ret < sizeof(h) )
{
cerr << myname << "(receive): FAILED header ret=" << ret << " sizeof=" << sizeof(UniSetUDP::UDPHeader) << endl;
return;
}
ssize_t sz = pack.msg.header.dcount * sizeof(UniSetUDP::UDPData) + sizeof(UniSetUDP::UDPHeader);
if( ret < sz )
{
cerr << myname << "(receive): FAILED data ret=" << ret << " sizeof=" << sz << endl;
return;
}
cerr << myname << "(receive): recv DATA OK. ret=" << ret << " sizeof=" << sz
<< " header: " << pack.msg.header << endl;
/*
if( labs(pack.msg.header.num - pnum) > 1 )
{
for( int i=0; i<h.dcount;i++ )
{
size_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret < sizeof(d) )
return;
}
return;
}
pnum = pack.msg.header.num;
*/
{
size_t ret = udp->UDPReceive::receive(&d,sizeof(d));
if( ret < sizeof(d) )
{
cerr << myname << "(receive data " << i << "): ret=" << ret << " sizeof=" << sizeof(d) << endl;
break;
}
cout << myname << "(receive data " << i << "): " << d << endl;
}
return;
}
}
// -----------------------------------------------------------------------------
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;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
}
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();
askTimer(tmUpdate,updatetime);
askTimer(tmStep,steptime);
}
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);
for( ItemVec::iterator it=icache.begin(); it!=icache.end(); ++it )
{
shm->initAIterator(it->ait);
shm->initDIterator(it->dit);
}
}
// -----------------------------------------------------------------------------
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);
}
// -----------------------------------------------------------------------------
void UDPReceiver::initCache( UniSetUDP::UDPMessage& pack, bool force )
{
if( !force && pack.msg.header.dcount == icache.size() )
return;
dlog[Debug::INFO] << myname << ": init icache.." << endl;
cache_init_ok = true;
icache.resize(pack.msg.header.dcount);
for( int i=0; i<icache.size(); i++ )
{
ItemInfo& d(icache[i]);
if( d.id != pack.msg.dat[i].id )
{
d.id = pack.msg.dat[i].id;
d.iotype = conf->getIOType(d.id);
shm->initAIterator(d.ait);
shm->initDIterator(d.dit);
}
}
}
// -----------------------------------------------------------------------------
#ifndef UDPReceiver_H_
#define UDPReceiver_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <queue>
#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"
// -----------------------------------------------------------------------------
/* Основная идея: сделать проверку очерёдности пакетов, но при этом использовать UDP.
* ===============
* Собственно реализация сделана так:
* В данных передаётся номер пакета. На случай если несколько пакетов придут не в той последовательности
* что были посланы, сделана очередь с приоритетом. В качестве приориета используется номер пакета
* (чем меньше тем старше). И при этом эта очередь постоянно поддерживается наполненной на minBufSize записей.
* Это гарантирует, что соседние пакеты пришедшие не в той последовательности, тем не менее обработаны будут в правильной.
* Т.к. в очереди они "отсортируются" по номеру пакета, ещё до обработки.
*
*
* КЭШ
* ===
* Для оптимизации работы с SM, т.к. в пакетах приходят только пары [id,value] сделан кэш итераторов.
* Кэш расчитан на то, что принимаемые пакеты всегда имеют одну и ту же длину и последовательность.
* Идея проста: сделан вектор размером с количество принимаемых данных. В векторе хранятся итераторы (и всё что необходимо).
* Порядокый номер данных в пакете является индексом в кэше.
* Для защиты от изменения поседовательности внутри пакета, в кэше хранится ID сохраняемого датчика, и если он не совпадёт с тем,
* ID который пришёл в пакете - элемент кэша обновляется.
* Если количество пришедших данных не совпадают с размером кэша.. кэш обновляется.
*/
// -----------------------------------------------------------------------------
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();
void update();
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 waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
enum Timer
{
tmUpdate,
tmStep
};
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; /*!< пауза меджду приёмами пакетов, [мсек] */
int updatetime; /*!< переодичность обновления данных в SM, [мсек] */
int steptime; /*!< периодичность вызова step, [мсек] */
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;
// функция определения приоритетного сообщения для обработки
struct PacketCompare:
public std::binary_function<UniSetUDP::UDPMessage, UniSetUDP::UDPMessage, bool>
{
bool operator()(const UniSetUDP::UDPMessage& lhs,
const UniSetUDP::UDPMessage& rhs) const;
};
typedef std::priority_queue<UniSetUDP::UDPMessage,std::vector<UniSetUDP::UDPMessage>,PacketCompare> PacketQueue;
PacketQueue qpack; /*!< очередь принятых пакетов (отсортированных по возрастанию номера пакета) */
UniSetUDP::UDPMessage pack; /*!< прсто буфер для получения очерещного сообщения */
UniSetTypes::uniset_mutex packMutex; /*!< mutex для работы с очередью */
long pnum; /*!< текущий номер обработанного сообщения, для проверки непрерывности последовательности пакетов */
/*! Минимальный размер очереди.
* Предназначен для создания буфера, чтобы обработка сообщений шла
* в порядке возрастания номеров пакетов. Даже если при приёме последовательность нарушалась
*/
int minBufSize;
int maxProcessingCount; /*! максимальное число обрабатываемых за один раз сообщений */
struct ItemInfo
{
long id;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniversalIO::IOTypes iotype;
};
typedef std::vector<ItemInfo> ItemVec;
ItemVec icache; /*!< кэш итераторов */
bool cache_init_ok;
void initCache( UniSetUDP::UDPMessage& pack, bool force=false );
};
// -----------------------------------------------------------------------------
#endif // UDPReceiver_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UNetExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
UNetExchange::UNetExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic ):
UniSetObject_LT(objId),
shm(0),
initPause(0),
activated(false),
no_sender(false),
sender(0)
{
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(UNetExchange): objId=-1?!! Use --unet-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(UNetExchange): Not found conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
// определяем фильтр
s_field = conf->getArgParam("--unet-filter-field");
s_fvalue = conf->getArgParam("--unet-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
int recvTimeout = conf->getArgPInt("--unet-recv-timeout",it.getProp("recvTimeout"), 5000);
int lostTimeout = conf->getArgPInt("--unet-lost-timeout",it.getProp("lostTimeout"), recvTimeout);
int recvpause = conf->getArgPInt("--unet-recvpause",it.getProp("recvpause"), 10);
int sendpause = conf->getArgPInt("--unet-sendpause",it.getProp("sendpause"), 150);
int updatepause = conf->getArgPInt("--unet-updatepause",it.getProp("updatepause"), 100);
steptime = conf->getArgPInt("--unet-steptime",it.getProp("steptime"), 1000);
int maxDiff = conf->getArgPInt("--unet-maxdifferense",it.getProp("maxDifferense"), 1000);
int maxProcessingCount = conf->getArgPInt("--unet-maxprocessingcount",it.getProp("maxProcessingCount"), 100);
no_sender = conf->getArgInt("--unet-nosender",it.getProp("nosender"));
xmlNode* nodes = conf->getXMLNodesSection();
if( !nodes )
throw UniSetTypes::SystemError("(UNetExchange): Not found <nodes>");
UniXML_iterator n_it(nodes);
if( !n_it.goChildren() )
throw UniSetTypes::SystemError("(UNetExchange): Items not found for <nodes>");
for( ; n_it.getCurrent(); n_it.goNext() )
{
string h(n_it.getProp("ip"));
if( !n_it.getProp("unet_ip").empty() )
h = n_it.getProp("unet_ip");
int p = n_it.getIntProp("id");
if( !n_it.getProp("unet_port").empty() )
p = n_it.getIntProp("unet_port");
string n(n_it.getProp("name"));
if( n == conf->getLocalNodeName() )
{
dlog[Debug::INFO] << myname << "(init): init sender.. my node " << n_it.getProp("name") << endl;
sender = new UNetSender(h,p,shm,s_field,s_fvalue,ic);
sender->setSendPause(sendpause);
continue;
}
if( !n_it.getProp("unet_ignore").empty() )
{
dlog[Debug::INFO] << myname << "(init): unet_ignore.. for " << n_it.getProp("name") << endl;
continue;
}
dlog[Debug::INFO] << myname << "(init): add UNetReceiver for " << h << ":" << p << endl;
if( checkExistUNetHost(h,p) )
{
dlog[Debug::INFO] << myname << "(init): " << h << ":" << p << " already added! Ignore.." << endl;
continue;
}
UNetReceiver* r = new UNetReceiver(h,p,shm);
r->setReceiveTimeout(recvTimeout);
r->setLostTimeout(lostTimeout);
r->setReceivePause(recvpause);
r->setUpdatePause(updatepause);
r->setMaxDifferens(maxDiff);
r->setMaxProcessingCount(maxProcessingCount);
recvlist.push_back(r);
}
// -------------------------------
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--unet-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("--unet-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("--unet-timeout",it.getProp("timeout"), 3000);
dlog[Debug::INFO] << myname << "(init): udp-timeout=" << msec << " msec" << endl;
}
// -----------------------------------------------------------------------------
UNetExchange::~UNetExchange()
{
for( ReceiverList::iterator it=recvlist.begin(); it!=recvlist.end(); ++it )
delete (*it);
delete sender;
delete shm;
}
// -----------------------------------------------------------------------------
bool UNetExchange::checkExistUNetHost( const std::string addr, ost::tpport_t port )
{
ost::IPV4Address a1(addr.c_str());
for( ReceiverList::iterator it=recvlist.begin(); it!=recvlist.end(); ++it )
{
if( (*it)->getAddress() == a1.getAddress() && (*it)->getPort() == port )
return true;
}
return false;
}
// -----------------------------------------------------------------------------
void UNetExchange::startReceivers()
{
for( ReceiverList::iterator it=recvlist.begin(); it!=recvlist.end(); ++it )
(*it)->start();
}
// -----------------------------------------------------------------------------
void UNetExchange::initSender( const std::string s_host, const ost::tpport_t port, UniXML_iterator& it )
{
if( no_sender )
return;
}
// -----------------------------------------------------------------------------
void UNetExchange::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--unet-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 UNetExchange::timerInfo( TimerMessage *tm )
{
if( !activated )
return;
if( tm->id == tmStep )
step();
}
// -----------------------------------------------------------------------------
void UNetExchange::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 UNetExchange::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;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
}
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 UNetExchange::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);
}
askTimer(tmStep,steptime);
startReceivers();
if( sender )
sender->start();
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. UNetExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(UNetExchange)
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 UNetExchange::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 UNetExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( sender )
sender->update(sm->id,sm->value);
}
// ------------------------------------------------------------------------------------------
bool UNetExchange::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void UNetExchange::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void UNetExchange::initIterators()
{
shm->initAIterator(aitHeartBeat);
}
// -----------------------------------------------------------------------------
void UNetExchange::help_print( int argc, char* argv[] )
{
cout << "--unet-recvpause msec - Пауза между получением пакетов. По умолчанию 10 мсек." << endl;
cout << "--unet-updatepause msec - Пауза между обновлением данных в SM. По умолчанию 100 мсек." << endl;
cout << "--unet-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
cout << "--unet-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10." << endl;
cout << "--unet-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')" << endl;
cout << "--unet-initPause - Задержка перед инициализацией (время на активизация процесса)" << endl;
cout << "--unet-notRespondSensor - датчик связи для данного процесса " << endl;
cout << "--unet-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола RS: " << endl;
}
// -----------------------------------------------------------------------------
UNetExchange* UNetExchange::init_unetexchange( int argc, char* argv[], UniSetTypes::ObjectId icID, SharedMemory* ic )
{
string name = conf->getArgParam("--unet-name","UNetExchange1");
if( name.empty() )
{
cerr << "(unetexchange): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(unetexchange): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(unetexchange): name = " << name << "(" << ID << ")" << endl;
return new UNetExchange(ID,icID,ic);
}
// -----------------------------------------------------------------------------
#ifndef UNetExchange_H_
#define UNetExchange_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <queue>
#include <cc++/socket.h>
#include "UniSetObject_LT.h"
#include "Trigger.h"
#include "Mutex.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "ThreadCreator.h"
#include "UNetReceiver.h"
#include "UNetSender.h"
// -----------------------------------------------------------------------------
class UNetExchange:
public UniSetObject_LT
{
public:
UNetExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UNetExchange();
/*! глобальная функция для инициализации объекта */
static UNetExchange* init_unetexchange( int argc, char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, char* argv[] );
bool checkExistUNetHost( const std::string host, ost::tpport_t port );
protected:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void step();
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 waitSMReady();
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
void startReceivers();
void initSender( const std::string host, const ost::tpport_t port, UniXML_iterator& it );
enum Timer
{
tmStep
};
private:
UNetExchange();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
int steptime; /*!< периодичность вызова step, [мсек] */
bool activated;
int activateTimeout;
typedef std::list<UNetReceiver*> ReceiverList;
ReceiverList recvlist;
bool no_sender; /*!< флаг отключения посылки сообщений */
UNetSender* sender;
};
// -----------------------------------------------------------------------------
#endif // UNetExchange_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UNetReceiver.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
bool UNetReceiver::PacketCompare::operator()(const UniSetUDP::UDPMessage& lhs,
const UniSetUDP::UDPMessage& rhs) const
{
// if( lhs.msg.header.num == rhs.msg.header.num )
// return (lhs.msg < rhs.msg);
return lhs.msg.header.num > rhs.msg.header.num;
}
// ------------------------------------------------------------------------------------------
UNetReceiver::UNetReceiver( const std::string s_host, const ost::tpport_t port, SMInterface* smi ):
shm(smi),
recvpause(10),
updatepause(100),
udp(0),
recvTimeout(5000),
lostTimeout(5000),
lostPackets(0),
activated(false),
r_thr(0),
u_thr(0),
pnum(0),
maxDifferens(1000),
waitClean(false),
rnum(0),
maxProcessingCount(100),
icache(200),
cache_init_ok(false)
{
{
ostringstream s;
s << "(" << s_host << ":" << port << ")";
myname = s.str();
}
try
{
// ost::IPV4Cidr ci(s_host.c_str());
// addr = ci.getBroadcast();
// cerr << "****************** addr: " << addr << endl;
addr = s_host.c_str();
udp = new ost::UDPDuplex(addr,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << myname << "(init): " << s.str() << std::endl;
throw SystemError(s.str());
}
r_thr = new ThreadCreator<UNetReceiver>(this, &UNetReceiver::receive);
u_thr = new ThreadCreator<UNetReceiver>(this, &UNetReceiver::update);
ptRecvTimeout.setTiming(recvTimeout);
}
// -----------------------------------------------------------------------------
UNetReceiver::~UNetReceiver()
{
delete r_thr;
delete u_thr;
delete udp;
}
// -----------------------------------------------------------------------------
void UNetReceiver::setReceiveTimeout( timeout_t msec )
{
recvTimeout = msec;
ptRecvTimeout.setTiming(msec);
}
// -----------------------------------------------------------------------------
void UNetReceiver::setLostTimeout( timeout_t msec )
{
lostTimeout = msec;
ptLostTimeout.setTiming(msec);
}
// -----------------------------------------------------------------------------
void UNetReceiver::setReceivePause( timeout_t msec )
{
recvpause = msec;
}
// -----------------------------------------------------------------------------
void UNetReceiver::setUpdatePause( timeout_t msec )
{
updatepause = msec;
}
// -----------------------------------------------------------------------------
void UNetReceiver::setMaxProcessingCount( int set )
{
maxProcessingCount = set;
}
// -----------------------------------------------------------------------------
void UNetReceiver::setMaxDifferens( unsigned long set )
{
maxDifferens = set;
}
// -----------------------------------------------------------------------------
void UNetReceiver::start()
{
if( !activated )
{
activated = true;
u_thr->start();
r_thr->start();
}
}
// -----------------------------------------------------------------------------
void UNetReceiver::update()
{
cerr << "******************* udpate start" << endl;
while(activated)
{
try
{
real_update();
}
catch( UniSetTypes::Exception& ex)
{
dlog[Debug::CRIT] << myname << "(update): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(update): catch ..." << std::endl;
}
msleep(updatepause);
}
}
// -----------------------------------------------------------------------------
void UNetReceiver::real_update()
{
UniSetUDP::UDPMessage p;
// обрабатываем пока, очередь либо не опустеет
// либо обнаружится "дырка" в последовательности
// но при этом обрабатываем не больше maxProcessingCount
// за один раз..
int k = maxProcessingCount;
while( k>0 )
{
{ // lock qpack
uniset_mutex_lock l(packMutex);
if( qpack.empty() )
return;
p = qpack.top();
unsigned long sub = labs(p.msg.header.num - pnum);
if( pnum > 0 )
{
// если sub > maxDifferens
// значит это просто "разрыв"
// и нам ждать lostTimeout не надо
// сразу начинаем обрабатывать новые пакеты
// а если > 1 && < maxDifferens
// значит это временная "дырка"
// и надо подождать lostTimeout
// чтобы констатировать потерю пакета..
if( sub > 1 && sub < maxDifferens )
{
if( !ptLostTimeout.checkTime() )
return;
lostPackets++;
}
else if( p.msg.header.num == pnum )
{
/* а что делать если идут повторные пакеты ?!
* для надёжности лучше обрабатывать..
* для "оптимизации".. лучше игнорировать
*/
qpack.pop(); // пока выбрали вариант "оптимизации"
continue;
}
}
ptLostTimeout.reset();
// удаляем из очереди, только если
// всё в порядке с последовательностью..
qpack.pop();
pnum = p.msg.header.num;
} // unlock qpack
k--;
// cerr << myname << "(update): " << p.msg.header << endl;
initCache(p, !cache_init_ok);
for( size_t i=0; i<p.msg.header.dcount; i++ )
{
try
{
UniSetUDP::UDPData& d = p.msg.dat[i];
ItemInfo& ii(icache[i]);
if( ii.id != d.id )
{
dlog[Debug::WARN] << myname << "(update): reinit cache for sid=" << d.id << endl;
ii.id = d.id;
shm->initAIterator(ii.ait);
shm->initDIterator(ii.dit);
}
if( ii.iotype == UniversalIO::DigitalInput )
shm->localSaveState(ii.dit,d.id,d.val,shm->ID());
else if( ii.iotype == UniversalIO::AnalogInput )
shm->localSaveValue(ii.ait,d.id,d.val,shm->ID());
else if( ii.iotype == UniversalIO::AnalogOutput )
shm->localSetValue(ii.ait,d.id,d.val,shm->ID());
else if( ii.iotype == UniversalIO::DigitalOutput )
shm->localSetState(ii.dit,d.id,d.val,shm->ID());
else
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << d.id << endl;
}
catch( UniSetTypes::Exception& ex)
{
dlog[Debug::CRIT] << myname << "(update): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(update): catch ..." << std::endl;
}
}
}
}
// -----------------------------------------------------------------------------
void UNetReceiver::receive()
{
cerr << "******************* receive start" << endl;
ptRecvTimeout.setTiming(recvTimeout);
while( activated )
{
try
{
if( recv() )
ptRecvTimeout.reset();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(poll): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(poll): catch ..." << std::endl;
}
msleep(recvpause);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
bool UNetReceiver::recv()
{
if( !udp->isInputReady(recvTimeout) )
return false;
size_t ret = udp->UDPReceive::receive(&(pack.msg),sizeof(pack.msg));
if( ret < sizeof(UniSetUDP::UDPHeader) )
{
dlog[Debug::CRIT] << myname << "(receive): FAILED header ret=" << ret << " sizeof=" << sizeof(UniSetUDP::UDPHeader) << endl;
return false;
}
size_t sz = pack.msg.header.dcount * sizeof(UniSetUDP::UDPData) + sizeof(UniSetUDP::UDPHeader);
if( ret < sz )
{
dlog[Debug::CRIT] << myname << "(receive): FAILED data ret=" << ret << " sizeof=" << sz
<< " packnum=" << pack.msg.header.num << endl;
return false;
}
if( rnum>0 && labs(pack.msg.header.num - rnum) > maxDifferens )
{
/* А что делать если мы уже ждём и ещё не "разгребли предыдущее".. а тут уже повторный "разрыв"
* Можно откинуть всё.. что сложили во временную очередь и заново "копить" (но тогда теряем информацию)
* А можно породолжать складывать во временную, но тогда есть риск "никогда" не разгрести временную
* очередь, при "частых обрывах". Потому-что update будет на каждом разрыве ждать ещё lostTimeout..
*/
// Пока выбираю.. чистить qtmp. Это будет соотвествовать логике работы с картами у которых ограничен буфер приёма.
// Обычно "кольцевой". Т.е. если не успели обработать и "вынуть" из буфера информацию.. он будет переписан новыми данными
if( waitClean )
{
dlog[Debug::CRIT] << myname << "(receive): reset qtmp.." << endl;
while( !qtmp.empty() )
qtmp.pop();
}
waitClean = true;
}
rnum = pack.msg.header.num;
// cerr << myname << "(receive): recv DATA OK. ret=" << ret << " sizeof=" << sz
// << " header: " << pack.msg.header
// << " waitClean=" << waitClean
// << endl;
{ // lock qpack
uniset_mutex_lock l(packMutex,500);
if( !waitClean )
{
qpack.push(pack);
return true;
}
if( !qpack.empty() )
{
// cerr << myname << "(receive): copy to qtmp..."
// << " header: " << pack.msg.header
// << endl;
qtmp.push(pack);
}
else
{
// cerr << myname << "(receive): copy from qtmp..." << endl;
// очередь освободилась..
// то копируем в неё всё что набралось...
while( !qtmp.empty() )
{
qpack.push(qtmp.top());
qtmp.pop();
}
// не забываем и текущий поместить в очередь..
qpack.push(pack);
waitClean = false;
}
} // unlock qpack
return true;
}
// -----------------------------------------------------------------------------
void UNetReceiver::initIterators()
{
for( ItemVec::iterator it=icache.begin(); it!=icache.end(); ++it )
{
shm->initAIterator(it->ait);
shm->initDIterator(it->dit);
}
}
// -----------------------------------------------------------------------------
void UNetReceiver::initCache( UniSetUDP::UDPMessage& pack, bool force )
{
if( !force && pack.msg.header.dcount == icache.size() )
return;
dlog[Debug::INFO] << myname << ": init icache.." << endl;
cache_init_ok = true;
icache.resize(pack.msg.header.dcount);
for( size_t i=0; i<icache.size(); i++ )
{
ItemInfo& d(icache[i]);
if( d.id != pack.msg.dat[i].id )
{
d.id = pack.msg.dat[i].id;
d.iotype = conf->getIOType(d.id);
shm->initAIterator(d.ait);
shm->initDIterator(d.dit);
}
}
}
// -----------------------------------------------------------------------------
#ifndef UNetReceiver_H_
#define UNetReceiver_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <queue>
#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"
// -----------------------------------------------------------------------------
/* Основная идея: сделать проверку очерёдности пакетов, но при этом использовать UDP.
* ===============
* Собственно реализация сделана так:
* В данных передаётся номер пакета. На случай если несколько пакетов придут не в той последовательности
* что были посланы, сделана очередь с приоритетом. В качестве приориета используется номер пакета
* (чем меньше тем старше). При этом обработка ведётся только тех пакетов, которые идут "подряд",
* как только встречается "дырка" происходит ожидание её "заполения". Если в течение времени (lostTimeout)
* "дырка" не исчезает, увеличивается счётчик потерянных пакетов и обработка продолжается дальше..
* Всё это реализовано в функции UNetReceiver::real_update()
*
* КЭШ
* ===
* Для оптимизации работы с SM, т.к. в пакетах приходят только пары [id,value] сделан кэш итераторов.
* Кэш расчитан на то, что принимаемые пакеты всегда имеют одну и ту же длину и последовательность.
* Идея проста: сделан вектор размером с количество принимаемых данных. В векторе хранятся итераторы (и всё что необходимо).
* Порядокый номер данных в пакете является индексом в кэше.
* Для защиты от изменения поседовательности внутри пакета, в кэше хранится ID сохраняемого датчика, и если он не совпадёт с тем,
* ID который пришёл в пакете - элемент кэша обновляется.
* Если количество пришедших данных не совпадают с размером кэша.. кэш обновляется.
*
* Обработка сбоя или переполнения счётчика пакетов(перехода через максимум)
* =========================================================================
* Для защиты от сбоя счётика сделана следующая логика:
* Если номер очередного пришедшего пакета отличается от последнего обработанного на maxDifferens, то считается,
* что произошёл сбой счётчика и происходит ожидание пока функция update, не обработает основную очередь полностью.
* При этом принимаемые пакеты складываются во временную очередь qtmp. Как только основная очередь пустеет,
* в неё копируется всё накопленное во временной очереди..и опять идёт штатная обработка.
* Если во время "ожидания" опять происходит "разрыв" в номерах пакетов, то временная очередь чиститься
* и данные которые в ней были теряются! Аналог ограниченного буфера (у любых карт), когда новые данные
* затирают старые, если их не успели вынуть и обработать.
* \todo Сделать защиту от бесконечного ожидания "очистки" основной очереди.
*/
// -----------------------------------------------------------------------------
class UNetReceiver
{
public:
UNetReceiver( const std::string host, const ost::tpport_t port, SMInterface* smi );
~UNetReceiver();
void start();
void receive();
void update();
inline bool isRecvOK(){ return ptRecvTimeout.checkTime(); }
inline unsigned long getLostPacketsNum(){ return lostPackets; }
void setReceiveTimeout( timeout_t msec );
void setReceivePause( timeout_t msec );
void setUpdatePause( timeout_t msec );
void setLostTimeout( timeout_t msec );
void setMaxDifferens( unsigned long set );
void setMaxProcessingCount( int set );
inline ost::IPV4Address getAddress(){ return addr; }
inline ost::tpport_t getPort(){ return port; }
protected:
SMInterface* shm;
bool recv();
void step();
void real_update();
void initIterators();
private:
UNetReceiver();
int recvpause; /*!< пауза меджду приёмами пакетов, [мсек] */
int updatepause; /*!< переодичность обновления данных в SM, [мсек] */
ost::UDPReceive* udp;
ost::IPV4Address addr;
ost::tpport_t port;
std::string myname;
UniSetTypes::uniset_mutex pollMutex;
PassiveTimer ptRecvTimeout;
timeout_t recvTimeout;
timeout_t lostTimeout;
PassiveTimer ptLostTimeout;
unsigned long lostPackets; /*!< счётчик потерянных пакетов */
bool activated;
ThreadCreator<UNetReceiver>* r_thr; // receive thread
ThreadCreator<UNetReceiver>* u_thr; // update thread
// функция определения приоритетного сообщения для обработки
struct PacketCompare:
public std::binary_function<UniSetUDP::UDPMessage, UniSetUDP::UDPMessage, bool>
{
bool operator()(const UniSetUDP::UDPMessage& lhs,
const UniSetUDP::UDPMessage& rhs) const;
};
typedef std::priority_queue<UniSetUDP::UDPMessage,std::vector<UniSetUDP::UDPMessage>,PacketCompare> PacketQueue;
PacketQueue qpack; /*!< очередь принятых пакетов (отсортированных по возрастанию номера пакета) */
UniSetUDP::UDPMessage pack; /*!< просто буфер для получения очереlного сообщения */
UniSetTypes::uniset_mutex packMutex; /*!< mutex для работы с очередью */
unsigned long pnum; /*!< текущий номер обработанного сообщения, для проверки непрерывности последовательности пакетов */
/*! максимальная разница межд номерами пакетов, при которой считается, что счётчик пакетов
* прошёл через максимум или сбился...
*/
unsigned long maxDifferens;
PacketQueue qtmp; /*!< очередь на время обработки(очистки) основной очереди */
bool waitClean; /*!< флаг означающий, что ждём очистики очереди до конца */
unsigned long rnum; /*!< текущий номер принятого сообщения, для проверки "переполнения" или "сбоя" счётчика */
int maxProcessingCount; /*! максимальное число обрабатываемых за один раз сообщений */
struct ItemInfo
{
long id;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniversalIO::IOTypes iotype;
};
typedef std::vector<ItemInfo> ItemVec;
ItemVec icache; /*!< кэш итераторов */
bool cache_init_ok;
void initCache( UniSetUDP::UDPMessage& pack, bool force=false );
};
// -----------------------------------------------------------------------------
#endif // UNetReceiver_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "UNetSender.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
UNetSender::UNetSender( const std::string s_host, const ost::tpport_t port, SMInterface* smi,
const std::string s_f, const std::string s_val, SharedMemory* ic ):
s_field(s_f),
s_fvalue(s_val),
shm(smi),
s_host(s_host),
sendpause(150),
activated(false),
dlist(100),
maxItem(0),
packetnum(1),
s_thr(0)
{
{
ostringstream s;
s << "(" << s_host << ":" << port << ")";
myname = s.str();
}
// определяем фильтр
// 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;
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UNetSender): UDP set to " << s_host << ":" << port << endl;
try
{
addr = s_host.c_str();
udp = new ost::UDPBroadcast(addr,port);
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString() << endl;
throw SystemError(s.str());
}
s_thr = new ThreadCreator<UNetSender>(this, &UNetSender::send);
// -------------------------------
if( shm->isLocalwork() )
{
readConfiguration();
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
}
else
ic->addReadItem( sigc::mem_fun(this,&UNetSender::readItem) );
// выставляем поля, которые не меняются
mypack.msg.header.nodeID = conf->getLocalNode();
mypack.msg.header.procID = shm->ID();
}
// -----------------------------------------------------------------------------
UNetSender::~UNetSender()
{
delete s_thr;
delete udp;
delete shm;
}
// -----------------------------------------------------------------------------
void UNetSender::update( UniSetTypes::ObjectId id, long value )
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
if( it->si.id == id )
{
uniset_spin_lock lock(it->val_lock);
it->val = value;
}
break;
}
}
// -----------------------------------------------------------------------------
void UNetSender::send()
{
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): dlist size = " << dlist.size() << endl;
/*
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
{
real_send();
}
catch( ost::SockException& e )
{
cerr << e.getString() << ": " << e.getSystemErrorString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
cerr << myname << "(send): " << ex << std::endl;
}
catch(...)
{
cerr << myname << "(send): catch ..." << std::endl;
}
msleep(sendpause);
}
cerr << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::real_send()
{
mypack.msg.header.num = packetnum++;
if( packetnum > UniSetUDP::MaxPacketNum )
packetnum = 1;
// cout << "************* send header: " << mypack.msg.header << endl;
int sz = mypack.byte_size() + sizeof(UniSetUDP::UDPHeader);
if( !udp->isPending(ost::Socket::pendingOutput) )
return;
size_t ret = udp->send( (char*)&(mypack.msg),sz);
if( ret < sz )
dlog[Debug::CRIT] << myname << "(send): FAILED ret=" << ret << " < sizeof=" << sz << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::start()
{
if( !activated )
{
activated = true;
s_thr->start();
}
}
// -----------------------------------------------------------------------------
void UNetSender::readConfiguration()
{
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): not found <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): empty <sensors>?!!" << endl;
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
}
// ------------------------------------------------------------------------------------------
bool UNetSender::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 UNetSender::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
bool UNetSender::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_ind = mypack.size()-1;
if( maxItem >= mypack.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 UNetSender::initIterators()
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); it++ )
{
shm->initDIterator(it->dit);
shm->initAIterator(it->ait);
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UNetSender::UItem& p )
{
return os << " sid=" << p.si.id;
}
// -----------------------------------------------------------------------------
#ifndef UNetSender_H_
#define UNetSender_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"
// -----------------------------------------------------------------------------
/*
* Для защиты от потери пакета при переполнении "номера пакета".
* UNetReceiver при обнаружении "разрыва" в последовательнности, просто игнорирует пакет, обновляет счётчик
* и начинает обработку пока буфер опять не заполнится..
*/
class UNetSender
{
public:
UNetSender( const std::string host, const ost::tpport_t port, SMInterface* smi,
const std::string s_field="", const std::string s_fvalue="", SharedMemory* ic=0 );
~UNetSender();
struct UItem
{
UItem():
val(0)
{}
IOController_i::SensorInfo si;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniSetTypes::uniset_spin_mutex val_lock;
int pack_ind;
long val;
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
void start();
void send();
void real_send();
void update( UniSetTypes::ObjectId id, long value );
inline void setSendPause( int msec ){ sendpause = msec; }
protected:
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
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:
UNetSender();
ost::UDPBroadcast* udp;
ost::IPV4Address addr;
ost::tpport_t port;
std::string s_host;
std::string myname;
int sendpause;
bool activated;
UniSetUDP::UDPMessage mypack;
typedef std::vector<UItem> DMap;
DMap dlist;
int maxItem;
unsigned long packetnum;
ThreadCreator<UNetSender>* s_thr; // send thread
};
// -----------------------------------------------------------------------------
#endif // UNetSender_H_
// -----------------------------------------------------------------------------
#!/bin/sh
uniset-start.sh -f ./uniset-udpexchange --udp-name UDPExchange --udp-host 192.168.1.255 \
--udp-broadcast 1 --udp-polltime 100 \
--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 3001 \
--confile test.xml \
--udp-filter-field udp --udp-filter-value 2we \
--udp-ip \
--dlog-add-levels info,crit,warn
#!/bin/sh
uniset-start.sh -f ./uniset-udpexchange --udp-name UDPExchange \
--confile test.xml \
--udp-filter-field udp --udp-filter-value 1 \
--dlog-add-levels info,crit,warn
#!/bin/sh
uniset-start.sh -f ./uniset-unetexchange --unet-name UNetExchange \
--confile test.xml \
--unet-filter-field rs --unet-filter-value 2 --unet-maxdifferense 40 \
--dlog-add-levels info,crit,warn
#include <sstream>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "UNetExchange.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 << "--unet-logfile filename - logfilename. Default: udpexchange.log" << endl;
cout << endl;
UNetExchange::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("--unet-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;
}
UNetExchange* unet = UNetExchange::init_unetexchange(argc,argv,shmID);
if( !unet )
{
dlog[Debug::CRIT] << "(unetexchange): init failed.." << endl;
return 1;
}
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(unet));
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);
return 0;
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(unetexchange): " << ex << std::endl;
}
catch( ost::SockException& e )
{
ostringstream s;
s << e.getString() << ": " << e.getSystemErrorString();
dlog[Debug::CRIT] << s.str() << endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(unetexchange): catch ..." << std::endl;
}
return 1;
}
../ModbusMaster/MBExchange.h
\ No newline at end of file
/* 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 "Пустая" реализация интерфейса работы с сообщениями
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef DefaultMessageInterface_H_
#define DefaultMessageInterface_H_
// --------------------------------------------------------------------------
#include "MessageInterface.h"
// --------------------------------------------------------------------------
class DefaultMessageInterface:
public MessageInterface
{
public:
DefaultMessageInterface(){}
virtual ~DefaultMessageInterface(){}
virtual std::string getMessage( UniSetTypes::MessageCode code ){ return ""; }
virtual bool isExist(UniSetTypes::MessageCode code){ return false; }
virtual UniSetTypes::MessageCode getCode( const std::string& msg ){ return UniSetTypes::DefaultMessageCode; }
virtual UniSetTypes::MessageCode getCodeByIdName( const std::string& name ){ return UniSetTypes::DefaultMessageCode; }
virtual std::ostream& printMessagesMap(std::ostream& os){ return os; }
};
// --------------------------------------------------------------------------
#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
* \brief Заголовочный файл для организации низкоуровневого ввода-вывода.
* \author Vitaly Lipatov
*/
// --------------------------------------------------------------------------
#ifndef DIGITALCARD_H__
#define DIGITALCARD_H__
/*! Абстрактный класс работы с цифровым вводом/выводом */
class DigitalCard
{
public:
virtual ~DigitalCard(){};
// virtual bool getCurrentState(int module)=0;
virtual bool get(int module) = 0;
virtual void set(int module, bool state) = 0;
};
#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
* \brief Заголовочный файл для дискретной карты DIO5600
* \author Vitaly Lipatov
*/
// --------------------------------------------------------------------------
#ifndef __DIO5600_H_
#define __DIO5600_H_
// --------------------------------------------------------------------------
#include "DigitalCard.h"
#include "IOs/IOAccessOld.h"
// портов для функций ввода/вывода
const int DIO5600_A = 0x10;
const int DIO5600_B = 0x02;
const int DIO5600_C_LO = 0x01;
const int DIO5600_C_HI = 0x08;
const int DIO5600_C = (DIO5600_C_LO | DIO5600_C_HI);
class DigitalCard_O5600: public DigitalCard, IOAccess
{
public:
//inline DIO5600() { }
inline DigitalCard_O5600(int ba, char mode)
{
init(1, 0, ba, mode);
}
bool get(int module);
// bool getCurrentState(int module);
void set(int module, bool state);
protected:
// void reinit();
char getMask(int module);
char getPrevious(int module);
int getPort(int module);
void putByte(int port, char val);
int getByte(int ba);
bool init(bool flagInit, int numOfCard, int base_address,char mode);
int baseadr; //
char iomode; //
char portmap[4];
};
#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
* \brief Заголовочный файл для организации низкоуровневого ввода-вывода.
* \author Vitaly Lipatov
* \par
* Этот файл предназначен для внутреннего использования в классах
* ввода-вывода
*/
// --------------------------------------------------------------------------
#ifndef _IOACCESS_H_
#define _IOACCESS_H_
// --------------------------------------------------------------------------
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include "Exceptions.h"
/*! \class IOAccess
* \brief Предоставление операций для низкоуровневого ввода-вывода.
* \author Vitaly Lipatov
* \par
* Этот класс предназначен для внутреннего использования в классах
* ввода-вывода
*/
class IOAccess
{
public:
/// При создании объекта открываются все порты на запись/чтение
IOAccess()
{
fd_port = open("/dev/port", O_RDWR | O_NDELAY);
if ( fd_port == -1 )
throw UniSetTypes::IOBadParam();
}
~IOAccess()
{
close(fd_port);
}
/*! Получение значений из диапазона портов от port до port+size байт.
Записываются по адресу buf.
*/
void get(int port, void* buf, int size) const
{
if ( lseek(fd_port, port, SEEK_SET) == -1 )
throw UniSetTypes::IOBadParam();
ssize_t s = read(fd_port, buf, size);
if ( s != size )
throw UniSetTypes::IOBadParam();
}
/// Получение байта из указанного порта
int in(int port) const
{
char input;
get(port, &input, 1);
return input;
}
/*! Запись значений в диапазон портов от port до port+size байт.
Значения берутся начиная с адреса buf.
*/
void put(int port, const void* buf, int size) const
{
if ( lseek(fd_port, port, SEEK_SET) == -1 )
throw UniSetTypes::IOBadParam();
ssize_t s = write(fd_port, buf, size);
if ( s != size )
throw UniSetTypes::IOBadParam();
}
/// Вывод байта value в порт port
void out(int port, int value) const
{
char output = value;
put(port,&output,1);
}
private:
/// Дескриптор открытого файла, соотнесённого с портами
int fd_port;
};
#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
* \brief Предоставление операций для низкоуровневого ввода-вывода.
* \author Vitaly Lipatov
*/
// --------------------------------------------------------------------------
#include <unistd.h>
#ifdef __GLIBC__
#include <sys/io.h> // для glibc
#else
#include <asm/io.h>
#endif
#ifndef _IOACCESS_H_
#define _IOACCESS_H_
#include <fcntl.h>
#include <iostream>
#include <iomanip>
#include "Exceptions.h"
/*! \class IOAccess
* \par
* Этот класс предназначен для внутреннего использования в классах
* ввода-вывода
*/
class IOAccess
{
public:
/// При создании объекта открываются все порты на запись/чтение
IOAccess()
{
std::cout << "IOAccess!!" << std::endl;
if (ioperm( 0x100, 0x50, 0666 ) == -1 )
throw UniSetTypes::IOBadParam();
}
~IOAccess()
{
}
/*! Получение значений из диапазона портов от port до port+size байт.
Записываются по адресу buf.
*/
/*
void get(int port, void* buf, int size) const
{
if ( lseek(fd_port, port, SEEK_SET) == -1 )
throw IOBadParam();
ssize_t s = read(fd_port, buf, size);
if ( s != size )
throw IOBadParam();
}
*/
/// Получение байта из указанного порта
int in(int port) const
{
char input;
//get(port, &input, 1);
input = inb( port );
return input;
}
/*! Запись значений в диапазон портов от port до port+size байт.
Значения берутся начиная с адреса buf.
*/
/*
void put(int port, const void* buf, int size) const
{
if ( lseek(fd_port, port, SEEK_SET) == -1 )
throw IOBadParam();
ssize_t s = write(fd_port, buf, size);
if ( s != size )
throw IOBadParam();
}
*/
/// Вывод байта value в порт port
void out(int port, int value) const
{
// char output = value;
//put(port,&output,1);
outb( value, port );
}
private:
/// Дескриптор открытого файла, соотнесённого с портами
int fd_port;
};
#endif
############################################################################
# This file is part of the UniSet library #
############################################################################
# install
ios_include_HEADERS = *.h
#$(shell ls $(top_srcdir)/$(subdir) | grep .h )
ios_includedir = $(includedir)/uniset/IOs
/* 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 Интерфейс к объекту сохраняющему список заказчиков и сообщений для InfoServer-а
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef ISRestorer_H_
#define ISRestorer_H_
// ------------------------------------------------------------------------------------------
#include <string>
#include "UniXML.h"
#include "InfoServer.h"
#include "Restorer.h"
// ------------------------------------------------------------------------------------------
/*!
Это абстрактный интерфейс. В чистом виде не используется.
*/
class ISRestorer
{
public:
ISRestorer();
virtual ~ISRestorer();
virtual void read(InfoServer* is, const std::string fname="")=0;
virtual void dump(InfoServer* is, const UniSetTypes::MessageCode code,
const InfoServer::ConsumerList& lst)=0;
protected:
// добавление списка заказчиков
void addlist( InfoServer* is, const UniSetTypes::MessageCode code,
InfoServer::ConsumerList& lst );
};
// ------------------------------------------------------------------------------------------
#if 0
/*!
* \brief Реализация сохранения списка заказчиков в xml.
* \author Pavel Vainerman
*
Реализует сохранение списка заказчиков в xml-файле.
\sa ISRestorer
*/
class ISRestorer_XML:
public ISRestorer,
public Restorer_XML
{
public:
ISRestorer_XML(const std::string fname, bool createIfNotFound=false );
// ISRestorer_XML( UniXML& xml );
virtual ~ISRestorer_XML();
virtual void dump(InfoServer* is, const UniSetTypes::MessageCode code,
const InfoServer::ConsumerList& lst);
virtual void read(InfoServer* is, const std::string fname="");
virtual void read(InfoServer* is, UniXML& xml );
void setFileName(const std::string& file);
inline std::string getFileName(){ return fname; }
ISRestorer_XML();
protected:
virtual void read_list(UniXML& xml, xmlNode* node, InfoServer* is);
};
// ------------------------------------------------------------------------------------------
#endif
/*!
* \brief Реализация сохранения списка заказчиков в xml(работа с файлом проекта)
* \author Pavel Vainerman
*
Реализует сохранение списка заказчиков в xml-файле (версия для работы с файлом проекта).
\sa ISRestorer
*/
class ISRestorer_XML:
public ISRestorer,
public Restorer_XML
{
public:
ISRestorer_XML( const std::string fname );
// ISRestorer_XML( UniXML& xml );
virtual ~ISRestorer_XML();
virtual void dump(InfoServer* is, const UniSetTypes::MessageCode code,
const InfoServer::ConsumerList& lst);
virtual void read(InfoServer* is, const std::string fname="");
virtual void read(InfoServer* is, UniXML& xml );
void setFileName(const std::string& file);
inline std::string getFileName(){ return fname; }
protected:
void read_list(UniXML& xml, xmlNode* node, InfoServer* is);
void create_new_file(const std::string& fname);
xmlNode* bind_node(UniXML& xml, xmlNode* root, const std::string& nodename, const std::string nm="");
xmlNode* rebind_node(UniXML& xml, xmlNode* root, const std::string& nodename, const std::string nm="");
void init( std::string fname );
std::string fname;
UniXML uxml;
};
// ------------------------------------------------------------------------------------------
#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
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef InfoServer_H_
#define InfoServer_H_
//---------------------------------------------------------------------------
#include <map>
#include <list>
#include "MessageType.h"
#include "UniSetObject.h"
#include "InfoServer_i.hh"
//---------------------------------------------------------------------------
class ISRestorer;
//---------------------------------------------------------------------------
/*!
\page ServicesPage
\section secInfoServer Сервис сообщений
\subsection subIS_common Общие сведения
В его задачи входит обработка всех сообщений для оператора.
При приходе сообщения он производит следующие действия:
- переправляет сообщение в БД (\ref secDBServer)
- рассылает сообщение на все узлы, если оно помечено как broadcast.
- рассылает сообщение всем занесённым в RouteList(см. конф.файл).
- обрабатывает сообщение специфичным для каждого проекта образом (т.е. вызывает виртуальную
функцию InfoServer::processing() )
\subsection subIS_idea Сценарий работы
На узле, где ведётся БД запускается один экземпляр сервиса. Клиенты могут получить доступ, несколькими способами:
- через NameService
- при помощи UniversalInterface::send()
\par
Сервис является системным, поэтому его идентификатор можно получить при помощи
UniSetTypes::Configuration::getInfoServer() объекта UniSetTypes::conf.
\subsection subIS_interface Интерфейс
InfoServer позволяет заказывать уведомелние о приходе тех или иных сообщений,
а также подтверждения(квитирования). Можно производить заказ сообщения по коду
\code
InfoServer::ackMessage(UniSetTypes::MessageCode msgid, const UniSetTypes::ConsumerInfo& ci,
UniversalIO::UIOCommand cmd, CORBA::Boolean acknotify);
\endcode
или сразу из диапазона кодов
\code
InfoServer::ackMessageRange(UniSetTypes::MessageCode from, UniSetTypes::MessageCode to,
const UniSetTypes::ConsumerInfo& ci,
UniversalIO::UIOCommand cmd, CORBA::Boolean acknotify);
\endcode
Реализацию см. \ref InfoServer
*/
/*!
* \class InfoServer
* \brief Интерфейс для вывода информации
*/
class InfoServer:
public UniSetObject,
public POA_InfoServer_i
{
public:
InfoServer( UniSetTypes::ObjectId id=UniSetTypes::DefaultObjectId, ISRestorer* d=0 );
virtual ~InfoServer();
virtual UniSetTypes::ObjectType getType(){ return UniSetTypes::getObjectType("InfoServer"); }
// реализация IDL интерфейса
/*! заказ уведомления о приходе сообщения */
virtual void ackMessage(UniSetTypes::MessageCode msgid, const UniSetTypes::ConsumerInfo& ci,
UniversalIO::UIOCommand cmd, CORBA::Boolean acknotify);
/*! заказ уведомления о приходе сообщения из диапазона */
virtual void ackMessageRange(UniSetTypes::MessageCode from, UniSetTypes::MessageCode to,
const UniSetTypes::ConsumerInfo& ci,
UniversalIO::UIOCommand cmd, CORBA::Boolean acknotify);
/*! информация о потребителе (заказчике) */
struct ConsumerInfoExt:
public UniSetTypes::ConsumerInfo
{
ConsumerInfoExt( UniSetTypes::ConsumerInfo ci,
UniSetObject_i_ptr ref=0):
ConsumerInfo(ci),ref(ref){}
UniSetObject_i_ptr ref;
CORBA::Boolean ask;
};
/*! Список потребителей */
typedef std::list<ConsumerInfoExt> ConsumerList;
/*! массив пар идентификатор->список потребителей */
typedef std::map<UniSetTypes::MessageCode,ConsumerList> AskMap;
protected:
// Функции обработки пришедших сообщений
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
/*! Функция обработки UniSetTypes::AlarmMessage.
Переопределяется в кокретном проекте, если требуется специфичная обработка. */
virtual void processing(UniSetTypes::AlarmMessage &amsg){};
/*! Функция обработки UniSetTypes::InfoMessage.
Переопределяется в кокретном проекте, если требуется специфичная обработка. */
virtual void processing(UniSetTypes::InfoMessage &imsg){};
/*! Функция обработки UniSetTypes::AckMessage.
Переопределяется в кокретном проекте, если требуется специфичная обработка. */
virtual void processing(UniSetTypes::ConfirmMessage &cmsg){};
/*! Предварительная обработка сообщения. Пересылка на другие узлы и
сохранение в базе.
*/
void preprocessing( UniSetTypes::TransportMessage& tmsg, bool broadcast );
void preprocessingConfirm( UniSetTypes::ConfirmMessage& am, bool broadcast );
virtual bool activateObject();
/*! сохранение списка заказчиков
По умолчанию делает dump, если объявлен dumper.
*/
virtual void dumpOrdersList(UniSetTypes::MessageCode mid, const ConsumerList& lst);
/*! чтение dump-файла */
virtual void readDump();
//! посылка информации об приходе сообщения
template<class TMessage>
void event(UniSetTypes::MessageCode key, TMessage& msg, CORBA::Boolean askn);
//----------------------
//! посылка информации об изменении состояния датчика
template <class TMessage>
void send(ConsumerList& lst, TMessage& msg, CORBA::Boolean acknotify);
bool addConsumer(ConsumerList& lst, const UniSetTypes::ConsumerInfo& cons, CORBA::Boolean acknotify); //!< добавить потребителя сообщения
bool removeConsumer(ConsumerList& lst, const UniSetTypes::ConsumerInfo& cons, CORBA::Boolean acknotify); //!< удалить потребителя сообщения
//! обработка заказа
void ask(AskMap& askLst, UniSetTypes::MessageCode key,
const UniSetTypes::ConsumerInfo& cons, UniversalIO::UIOCommand cmd,
CORBA::Boolean acknotify);
/*! указатель на объект реализующий дамп списка заказчиков */
ISRestorer* restorer;
private:
friend class ISRestorer;
bool dbrepeat; /*!< флаг пересылки сообщений DBServer-у */
AskMap askList; /*!< список потребителей */
/*! замок для блокирования совместного доступа к cписку потребителей */
UniSetTypes::uniset_mutex askMutex;
std::list<UniSetTypes::ConsumerInfo> routeList;
};
//---------------------------------------------------------------------------
#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 Класс работы с сообщениями
* \author Pavel Vainerman
*
* Получение сообщения по id
*/
// --------------------------------------------------------------------------
#ifndef __MESSAGEINTERFACE_H__
#define __MESSAGEINTERFACE_H__
// --------------------------------------------------------------------------
#include <string>
#include "UniSetTypes.h"
// --------------------------------------------------------------------------
class MessageInterface
{
public:
virtual ~MessageInterface(){}
virtual std::string getMessage( UniSetTypes::MessageCode code )=0;
virtual bool isExist(UniSetTypes::MessageCode code)=0;
virtual UniSetTypes::MessageCode getCode( const std::string& msg ){ return UniSetTypes::DefaultMessageCode; }
virtual UniSetTypes::MessageCode getCodeByIdName( const std::string& name ){ return UniSetTypes::DefaultMessageCode; }
virtual std::ostream& printMessagesMap(std::ostream& os)=0;
};
// --------------------------------------------------------------------------
#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 Реализация интерфейса работы с сообщениями на основе XML
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef __MESSAGEINTERFACE_XML_H__
#define __MESSAGEINTERFACE_XML_H__
// --------------------------------------------------------------------------
#include <vector>
#include "UniXML.h"
#include "MessageInterface.h"
// --------------------------------------------------------------------------
class MessageInterface_XML:
public MessageInterface
{
public:
MessageInterface_XML(const std::string confile="", int msize=200);
MessageInterface_XML(UniXML& xml, int msize=200);
virtual ~MessageInterface_XML();
virtual std::string getMessage( UniSetTypes::MessageCode code );
virtual bool isExist(UniSetTypes::MessageCode code);
virtual UniSetTypes::MessageCode getCode( const std::string& msg );
virtual UniSetTypes::MessageCode getCodeByIdName( const std::string& name );
virtual std::ostream& printMessagesMap(std::ostream& os);
friend std::ostream& operator<<(std::ostream& os, MessageInterface_XML& mi );
protected:
void read( UniXML& xml );
std::vector<UniSetTypes::MessageInfo> msgmap;
};
// --------------------------------------------------------------------------
#endif
/*! \file
* \brief Класс работы с сообщениями
* \author Pavel Vainerman
*/
/**************************************************************************/
#ifndef MessageInterface_idXML_H_
#define MessageInterface_idXML_H_
// -----------------------------------------------------------------------------------------
#include <map>
#include <string>
#include "UniSetTypes.h"
#include "MessageInterface.h"
#include "UniXML.h"
// -----------------------------------------------------------------------------------------
class MessageInterface_idXML:
public MessageInterface
{
public:
MessageInterface_idXML( const std::string xmlfile );
MessageInterface_idXML( UniXML& xml );
virtual ~MessageInterface_idXML();
virtual std::string getMessage( UniSetTypes::MessageCode code );
virtual bool isExist( UniSetTypes::MessageCode code );
virtual UniSetTypes::MessageCode getCode( const std::string& msg );
virtual UniSetTypes::MessageCode getCodeByIdName( const std::string& name );
virtual std::ostream& printMessagesMap(std::ostream& os);
friend std::ostream& operator<<(std::ostream& os, MessageInterface_idXML& mi );
protected:
void build( UniXML& xml );
private:
typedef std::map<UniSetTypes::MessageCode, UniSetTypes::MessageInfo> MapMessageKey;
MapMessageKey mmk;
};
// -----------------------------------------------------------------------------------------
#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 Активатор объектов
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef ObjectsActivator_H_
#define ObjectsActivator_H_
// --------------------------------------------------------------------------
#include <omniORB4/CORBA.h>
#include "UniSetTypes.h"
#include "UniSetObject.h"
#include "ObjectsManager.h"
#include "ThreadCreator.h"
//#include "OmniThreadCreator.h"
//----------------------------------------------------------------------------------------
/*! \class ObjectsActivator
* Создает POA менеджер и регистрирует в нем объекты.
* Для обработки CORBA-запросов создается поток или передаются ресурсы
* главного потока см. void activate(bool thread)
*
* Активатор в свою очередь сам является менеджером(и объектом) и обладает всеми его свойствами
*
* \todo Разобраться со всякими oaDestroy, stop, oakill и сделать одну надежную завершающую функцию.
*/
class ObjectsActivator:
public ObjectsManager
{
public:
ObjectsActivator();
ObjectsActivator( UniSetTypes::ObjectId id );
virtual ~ObjectsActivator();
virtual void run(bool thread);
virtual void stop();
virtual void oaDestroy(int signo=0);
void waitDestroy();
inline void oakill(int signo){ raise(signo);}
virtual UniSetTypes::ObjectType getType(){ return UniSetTypes::getObjectType("ObjectsActivator"); }
protected:
/*! Команды доступные при заказе сигналов
* см. askSignal()
*/
enum AskSigCommand {
Ask, /*!< заказать получение сигнала */
Denial /*!< отказаться от получения сигнала */
};
/*! заказ на обработку сигнала signo
* Для обработки предназначена функция signal().
* \warning Сообщение о приходе сигналов SITERM, SIGINT, SIGABRT приходит
* вне зависимости от заказа. От этих сообщений нельзя отказаться...
* \warning Заказ других сигналов пока не работает..
* \warning функция временно недоступна (private). Ведуться работы...
* \todo сделать возможность заказа других сигналов
*/
// void askSignal(int signo, AskSigCommand cmd=Ask);
virtual void work();
inline CORBA::ORB_ptr getORB()
{
return orb;
}
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
virtual void sysCommand( UniSetTypes::SystemMessage *sm );
private:
// static void processingSignal(int signo);
static void terminated(int signo);
static void finishterm(int signo);
static void normalexit();
static void normalterminate();
static void set_signals(bool ask);
void term( int signo );
void init();
friend class ThreadCreator<ObjectsActivator>;
ThreadCreator<ObjectsActivator> *orbthr;
CORBA::ORB_var orb;
bool omDestroy;
bool sig;
pid_t thpid; // pid orb потока
struct Info
{
pid_t msgpid; // pid порожденого потока обработки сообщений
};
struct OInfo:
public Info
{
UniSetObject* obj;
};
struct MInfo:
public Info
{
ObjectsManager* mnr;
};
std::list<OInfo> lstOInfo;
std::list<MInfo> lstMInfo;
void getinfo();
};
/*
template<class TClass>
int ObjectsActivator::attach(TClass* p, void(TClass:: *f)(void*) )
{
if( next >= MAX_CHILD_THREAD )
return -1;
callpull[next] = new OmniThreadCreator<TClass>( p, f);
next++;
return 0;
}
*/
#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 Реализация интерфейса менеджера объектов.
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef ObjectsManager_H_
#define ObjectsManager_H_
// --------------------------------------------------------------------------
#include <omniORB4/CORBA.h>
#include "UniSetTypes.h"
#include "UniSetObject.h"
#include "ObjectsManager_i.hh"
//---------------------------------------------------------------------------
class ObjectsActivator;
class ObjectsManager;
typedef std::list<ObjectsManager*> ObjectsManagerList;
//---------------------------------------------------------------------------
/*! \class ObjectsManager
* \par
* Содержит в себе функции управления объектами. Их регистрации и т.п.
* Создается менеджер объектов, после чего вызывается initObjects()
* для инициализации объектов которыми управляет
* данный менеджер...
* Менеджер в свою очередь сам является объектом и обладает всеми его свойствами
*
* Для пересылки сообщения всем подчиненным объектам используется
* функция ObjectsManager::broadcast(const TransportMessage& msg)
* \par
* У базового менеджера имеются базовые три функции см. ObjectsManager_i.
* \note Только при вызове функции ObjectsManager::broadcast() происходит
* формирование сообщения всем подчиненным объектам... Если команда проиходит
* при помощи push, то пересылки всем починённым объектам не происходит...
*
*
*/
class ObjectsManager:
public UniSetObject,
public POA_ObjectsManager_i
{
public:
ObjectsManager( UniSetTypes::ObjectId id);
ObjectsManager( const std::string name, const std::string section );
virtual ~ObjectsManager();
virtual UniSetTypes::ObjectType getType(){ return UniSetTypes::getObjectType("ObjectsManager"); }
// ------ функции объявленные в интерфейсе(IDL) ------
virtual void broadcast(const UniSetTypes::TransportMessage& msg);
virtual UniSetTypes::SimpleInfoSeq* getObjectsInfo( CORBA::Long MaxLength=300 );
// --------------------------
void initPOA(ObjectsManager* rmngr);
virtual bool addObject(UniSetObject *obj);
virtual bool removeObject(UniSetObject *obj);
virtual bool addManager( ObjectsManager *mngr );
virtual bool removeManager( ObjectsManager *mngr );
/*! Получение доступа к подчиненному менеджеру по идентификатору
* \return объект ненайден будет возвращен 0.
*/
const ObjectsManager* itemM(const UniSetTypes::ObjectId id);
/*! Получение доступа к подчиненному объекту по идентификатору
* \return объект ненайден будет возвращен 0.
*/
const UniSetObject* itemO( const UniSetTypes::ObjectId id );
// Функции для аботы со списками подчиненных объектов
inline ObjectsManagerList::const_iterator beginMList()
{
return mlist.begin();
}
inline ObjectsManagerList::const_iterator endMList()
{
return mlist.end();
}
inline ObjectsList::const_iterator beginOList()
{
return olist.begin();
}
inline ObjectsList::const_iterator endOList()
{
return olist.end();
}
int objectsCount(); // количество подчиненных объектов
PortableServer::POA_ptr getPOA(){ return PortableServer::POA::_duplicate(poa); }
PortableServer::POAManager_ptr getPOAManager(){ return PortableServer::POAManager::_duplicate(pman); }
protected:
ObjectsManager();
enum OManagerCommand{deactiv, activ, initial, term};
// работа со списком объектов
void objects(OManagerCommand cmd);
// работа со списком менеджеров
void managers(OManagerCommand cmd);
virtual void sigterm( int signo );
//! \note Переопределяя не забывайте вызвать базовую
virtual bool activateObject();
//! \note Переопределяя не забывайте вызвать базовую
virtual bool disactivateObject();
typedef ObjectsManagerList::iterator MListIterator;
int getObjectsInfo( ObjectsManager* mngr, UniSetTypes::SimpleInfoSeq* seq,
int begin, const long uplimit );
PortableServer::POA_var poa;
PortableServer::POAManager_var pman;
private:
friend class ObjectsActivator;
int sig;
ObjectsManagerList mlist;
ObjectsList olist;
UniSetTypes::uniset_mutex olistMutex;
UniSetTypes::uniset_mutex mlistMutex;
};
#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
* \author Pavel Vainerman
*/
//---------------------------------------------------------------------------
#ifndef ObjectsManager_LT_H_
#define ObjectsManager_LT_H_
//--------------------------------------------------------------------------
#include "UniSetTypes.h"
#include "ObjectsManager.h"
#include "LT_Object.h"
//---------------------------------------------------------------------------
/*!
Реализация базового класса с использованием локальных таймеров
*/
class ObjectsManager_LT:
public ObjectsManager
{
public:
ObjectsManager_LT( UniSetTypes::ObjectId id );
ObjectsManager_LT();
virtual ~ObjectsManager_LT();
protected:
/*! заказ локального таймера
\param timerid - идентификатор таймера
\param timeMS - период. 0 - означает отказ от таймера
\param ticks - количество уведомлений. "-1"- постоянно
\return Возвращает время [мсек] оставшееся до срабатывания
очередного таймера
*/
void askTimer( UniSetTypes::TimerId timerid, timeout_t timeMS, short ticks=-1,
UniSetTypes::Message::Priority p=UniSetTypes::Message::High );
/*! функция вызываемая из потока */
virtual void callback();
int sleepTime;
LT_Object lt;
private:
};
//--------------------------------------------------------------------------
#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 Интефес для создания и управления потоками
* \author Anthony Korbin
*/
//----------------------------------------------------------------------------
#ifndef PosixThread_h_
#define PosixThread_h_
//----------------------------------------------------------------------------------------
#include <pthread.h>
#include <iostream>
#include <signal.h>
//----------------------------------------------------------------------------------------
/*! \class PosixThread */
class PosixThread
{
public:
PosixThread();
virtual ~PosixThread();
void start( void *args ); /*!< запуск */
void stop();
void thrkill( int signo ); /*!< послать сигнал signo */
enum TAttr{ SCOPE, DETACH, PRIORITY };
void setAttr( TAttr Attr, int state );
pthread_t getTID(){ return tid; }
void setPriority( int priority );
static void* funcp( void * test );
protected:
void reinit();
virtual void work() = 0; /*!< Функция выполняемая в потоке */
void readlock( pthread_rwlock_t *lock = &lockx );
void writelock( pthread_rwlock_t *lock = &lockx );
void lock( pthread_mutex_t *mute = &mutex );
void unlock( pthread_mutex_t *mute = &mutex );
void rwunlock( pthread_rwlock_t *lock = &lockx );
void wait( pthread_cond_t *cond = &condx, pthread_mutex_t *mute = &mutex );
void continueRun( pthread_cond_t *cond = &condx );
void continueRunAll( pthread_cond_t *cond = &condx );
private:
pthread_t tid;
pthread_attr_t *attrPtr;
static pthread_rwlock_t lockx;
static pthread_mutex_t mutex;
static pthread_cond_t condx;
static int countThreads;
};
#endif // PosixThread_h_
/* 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.
*/
// --------------------------------------------------------------------------
// idea: lav@etersoft.ru
// realisation: pv@etersoft.ru, lav@etersoft.ru
// --------------------------------------------------------------------------
#ifndef SandClock_H_
#define SandClock_H_
// --------------------------------------------------------------------------
/*! WARNING! This class is DEPRECATED! Use HourGlass.. */
// --------------------------------------------------------------------------
#include "PassiveTimer.h"
// --------------------------------------------------------------------------
/*! WARNING! This class is DEPRECATED! Use HourGlass.. */
class SandClock
{
public:
SandClock(): _state(false),_sand(0),_size(0){}
~SandClock(){}
// запустить часы (заново)
inline void run( int msec )
{
t.setTiming(msec);
_state = true;
_sand = msec;
_size = msec;
}
inline void reset ()
{
run(_size);
}
inline int duration()
{
return _size;
}
// перевернуть часы
// true - засечь время
// false - перевернуть часы (обратный ход)
// возвращает аргумент (т.е. идёт ли отсчёт времени)
inline bool rotate( bool st )
{
if( st == _state )
return st;
_state = st;
if( !_state )
{
int cur = t.getCurrent();
_sand -= cur;
if( _sand < 0 )
_sand = 0;
// std::cout << "перевернули: прошло " << cur
// << " осталось " << sand
// << " засекаем " << cur << endl;
t.setTiming(cur);
}
else
{
_sand += t.getCurrent();
if( _sand > _size )
_sand = _size;
// std::cout << "вернули: прошло " << t.getCurrent()
// << " осталось " << sand
// << " засекам " << sand << endl;
t.setTiming(_sand);
}
return st;
}
// получить прошедшее время
// для положения st
inline int current( bool st )
{
return t.getCurrent();
}
// получить заданное время
// для положения st
inline int interval( bool st )
{
return t.getInterval();
}
// проверить наступление
inline bool check()
{
// пока часы не "стоят"
// всегда false
if( !_state )
return false;
return t.checkTime();
}
inline bool state(){ return _state; }
protected:
PassiveTimer t;
bool _state;
int _sand;
int _size;
};
// --------------------------------------------------------------------------
#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
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef StorageInterface_H_
#define StorageInterface_H_
// ---------------------------------------------------------------------------
#include "IOController_i.hh"
// ---------------------------------------------------------------------------
/*! */
class StorageInterface
{
public:
StorageInterface(){};
virtual ~StorageInterface(){};
virtual IOController_i::DigitalIOInfo find( const IOController_i::SensorInfo& si )=0;
virtual void push( IOController_i::DigitalIOInfo& di )=0;
virtual void remove(const IOController_i::SensorInfo& si)=0;
virtual bool getState(const IOController_i::SensorInfo& si)=0;
virtual long getValue(const IOController_i::SensorInfo& si)=0;
virtual void saveState(const IOController_i::DigitalIOInfo& di,bool st)=0;
virtual void saveValue(const IOController_i::AnalogIOInfo& ai, long val)=0;
protected:
private:
};
// ---------------------------------------------------------------------------
class STLStorage:
public StorageInterface
{
public:
STLStorage();
~STLStorage();
virtual IOController_i::DigitalIOInfo find( const IOController_i::SensorInfo& si );
virtual void push( IOController_i::DigitalIOInfo& di );
virtual void remove(const IOController_i::SensorInfo& si);
virtual bool getState(const IOController_i::SensorInfo& si);
virtual long getValue(const IOController_i::SensorInfo& si);
virtual void saveState(const IOController_i::DigitalIOInfo& di,bool st);
virtual void saveValue(const IOController_i::AnalogIOInfo& ai, long val);
protected:
private:
};
// ---------------------------------------------------------------------------
#endif
// ---------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2009 Free Software Foundation, Inc.
* Copyright (c) 2009 Ivan Donchevskiy
*
* 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 Ivan Donchevskiy
*/
// --------------------------------------------------------------------------
#ifndef Storages_H_
#define Storages_H_
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <string>
/*! Эти 2 значения используются в TableBlockStorage как флаги для поля count, чтобы не вводить лишнее поле
в структуре TableBlockStorageElem */
#define EMPTY_BLOCK -5
#define EMPTY_ELEM -1
#define key_size 20
/*! Заголовок таблицы с элементами класса TableBlockStorage */
struct StorageAttr
{
int k_size, inf_size,size,block_number;
int lim, seekpos;
} __attribute__((__packed__));
/*! Заголовок журнала с элементами класса CycleStorage */
struct CycleStorageAttr
{
int size, inf_size, seekpos;
} __attribute__((__packed__));
/*! Основная структура класса TableStorage */
struct TableStorageElem
{
char status;
char key[key_size];
} __attribute__((__packed__));
/*! Основная структура класса TableBlockStorage */
struct TableBlockStorageElem
{
int count;
} __attribute__((__packed__));
/*! Основная структура класса CycleStorage */
struct CycleStorageElem
{
char status;
} __attribute__((__packed__));
class TableStorage
{
FILE *file;
int size,seekpos, inf_size;
int head;
public:
TableStorage(const char* name, int inf_sz, int sz, int seek);
~TableStorage();
int addRow(char* key, char* val);
int delRow(char* key);
char* findKeyValue(char* key, char* val);
};
class TableBlockStorage
{
public:
/*! Конструктор по умолчанию не открывает и не создает новой таблицы */
TableBlockStorage();
/*! Конструктор вызывает функцию Open, а при параметре create=true создает новую таблицу при
несовпадении заголовков или отсутствии старой */
TableBlockStorage(const char* name, int byte_sz, int key_sz, int inf_sz, int inf_count, int block_num, int block_lim, int seek, bool create=false);
~TableBlockStorage();
/*!
\param inf_sz - размер поля информации,
\param key_sz - размер поля ключа,
\param inf_count - кол-во записей в одном блоке таблицы (размером inf_sz+key_sz
+sizeof(int) на ключевое поле)
\param block_num - кол-во блоков (при этом кол-во записей во всей таблице = inf_count*block_num,
\param block_lim - число перезаписей на блок,
\param seek - отступ от начала файла (указывает место, где расположена таблица)
размер всей таблицы будет равен inf_count*block_num*(inf_sz+key_sz+sizeof(int)) +
sizeof(StorageAttr), где последнее слагаемое - размер заголовка,
размер можно получить, вызвав функцию getByteSize()
*/
bool open(const char* name, int byte_sz, int inf_sz, int key_sz, int inf_count, int block_num, int block_lim, int seek);
bool create(const char* name, int byte_sz, int inf_sz, int key_sz, int inf_count, int block_num, int block_lim, int seek);
/*! Добавление информации по ключу, возможна перезапись при совпадении ключа с существующим */
bool addRow(void* key, void* val);
/*! Удаление информации по ключу, фактически освобождения места не происходит, оно только помечается удаленным*/
bool delRow(void* key);
/*! Поиск информации по ключу, при неудаче возвращается 0 */
void* findKeyValue(void* key, void* val);
/*! Получение текущего блока (для тестовой программы) */
int getCurBlock(void);
inline int getByteSize() { return (size*full_size + sizeof(StorageAttr)); }
bool checkAttr( int key_sz, int inf_sz, int sz, int block_num, int block_lim, int seek );
protected:
FILE *file;
int inf_size;
private:
int max,cur_block;
TableBlockStorageElem* mem;
int k_size, lim,seekpos;
int size,block_size,block_number,full_size;
void filewrite(int seek, bool needflush=true);
bool copyToNextBlock();
bool keyCompare(int i, void* key);
void* keyPointer(int num);
void* valPointer(int num);
TableBlockStorageElem* elemPointer(int num);
};
class CycleStorage
{
public:
class CycleStorageIterator
{
public:
typedef CycleStorageIterator Self;
CycleStorageIterator():
str(NULL), cs(NULL), current(0) {}
CycleStorageIterator(CycleStorage* cstor)
{
cs = cstor;
current = 0;
}
CycleStorageIterator(CycleStorage* cstor, int num)
{
cs = cstor;
if( num<0 || num>=cs->getSize() ) current = 0;
current = num;
}
void* operator *() const
{
return str;
}
Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
inline bool operator==(const Self& other) const
{
if( str==NULL || other.str==NULL )
{
if( str==NULL && other.str==NULL )
return true;
else
return false;
}
if( memcmp(str, other.str, cs->getInfSize())==0 )
return true;
return false;
}
inline bool operator!=(const Self& other) const
{
if( str==NULL || other.str==NULL )
{
if( str==NULL && other.str==NULL )
return false;
else
return true;
}
if( memcmp(str, other.str, cs->getInfSize())==0 )
return false;
return true;
}
private:
void* str;
CycleStorage* cs;
int current;
};
typedef CycleStorageIterator iterator;
/*! Конструктор по умолчанию не открывает и не создает нового журнала */
CycleStorage();
/*! Конструктор вызывает функцию Open, а при параметре create=true создает новый журнал при
несовпадении заголовков или отсутствии старого */
CycleStorage(const char* name, int byte_sz, int inf_sz, int inf_count, int seek,bool create=false);
~CycleStorage();
/*!
\param inf_sz - размер поля информации,
\param inf_count - количество записей (размером inf_sz +1 на ключевое поле)
\param seek - отступ от начала файла (указывает место, где расположен журнал)
размер всего журнала будет равен inf_count*(inf_sz+1) + sizeof(CycleStorageAttr),
где последнее слагаемое - размер заголовка
размер можно получить, вызвав функцию getByteSize()
*/
bool open(const char* name, int byte_sz, int inf_sz, int inf_count, int seek);
bool create(const char* name, int byte_sz, int inf_sz, int inf_count, int seek);
bool isOpen(){ return (file!=NULL); }
/*! Добавление информации в конец журнала */
bool addRow(void* str);
/*! Удаление информации с номером ряда row */
bool delRow(int row);
/*! Очистка журнала */
bool delAllRows(void);
/*! \return Функция возвращает информацию из ряда с номером num */
void* readRow(int num, void* str);
/*! Получение кол-ва итерации при поиске начала/конца журнала (для тестовой программы) */
int getIter(void);
/*! Изменение размера журнала (количества записей в нем) */
bool setSize(int count);
inline int getByteSize() { return (size*full_size + sizeof(CycleStorageAttr)); }
inline int getSize(){ return size; }
inline int getInfSize(){ return inf_size; }
inline int getFullSize(){ return full_size; }
bool checkAttr(int inf_sz, int inf_count, int seek);
inline int getHead(){ return head; }
inline int getTail(){ return tail; }
iterator begin()
{
return iterator(this);
}
iterator end()
{
return iterator(this,this->getTail());
}
protected:
FILE *file;
int inf_size;
int head,tail;
private:
int size,seekpos, iter;
int full_size;
void filewrite(CycleStorageElem* jrn,int seek, bool needflush=true);
void* valPointer(void* pnt);
bool findHead();
};
#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 Реализация SystemGuard
* \author Pavel Vainerman
*/
//--------------------------------------------------------------------------------
#ifndef SystemGuard_H_
#define SystemGuard_H_
//--------------------------------------------------------------------------------
#include <omniORB4/CORBA.h>
#include <omnithread.h>
#include "UniSetTypes.h"
#include "PassiveTimer.h"
#include "ThreadCreator.h"
#include "ObjectsActivator.h"
//--------------------------------------------------------------------------------
/*! \class SystemGuard
* Предназначен для слежения за исправностью работы процессов. А так же отслеживает наличие
* связи c узлами и обновляет эту информацию в ListOfNodes.
*/
class SystemGuard:
public ObjectsActivator
{
public:
SystemGuard(UniSetTypes::ObjectId id);
SystemGuard();
~SystemGuard();
virtual void run( bool thread=false );
virtual void stop();
virtual void oaDestroy(int signo=0);
virtual UniSetTypes::SimpleInfo* getInfo();
virtual UniSetTypes::ObjectType getType(){ return UniSetTypes::getObjectType("SystemGuard"); }
protected:
void execute();
virtual void sigterm( int signo );
virtual bool pingNode();
virtual void updateNodeInfo(const UniSetTypes::NodeInfo& newinf){};
virtual void watchDogTime();
virtual void dumpStateInfo();
virtual void autostart();
private:
void init();
// ObjectsActivator* act;
// CORBA::ORB_var orb;
PassiveTimer wdogt;
PassiveTimer rit;
PassiveTimer dumpt;
// PassiveTimer strt;
friend class ThreadCreator<SystemGuard>;
ThreadCreator<SystemGuard> *thr;
bool active;
int expid;
// omni_mutex omutex;
// omni_condition ocond;
UniSetTypes::uniset_mutex actMutex;
};
//--------------------------------------------------------------------------------
#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
* \par
* Базовый класс получения строки по её индексу
*/
#include <string>
class TextDBIndex
{
public:
virtual ~TextDBIndex(){}
// Получить строку по коду
virtual std::string getText(int id){ return ""; }
};
/* 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
* \par
* Базовый класс получения строки по её индексу
*/
#include <string>
class TextIndex
{
public:
virtual ~TextIndex(){}
// Получить строку по коду
virtual std::string getText(int id)=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
* \brief Реализация TimerService
* \author Pavel Vainerman
*/
//---------------------------------------------------------------------------
#ifndef TimerService_H_
#define TimerService_H_
//---------------------------------------------------------------------------
#include <list>
#include <functional>
#include <omnithread.h>
#include <string>
#include "UniSetTypes.h"
#include "UniSetObject.h"
#include "TimerService_i.hh"
#include "PassiveTimer.h"
//#include "OmniThreadCreator.h"
#include "ThreadCreator.h"
//-----------------------------------------------------------------------------------
/*!
\page ServicesPage
\section secTimerService Сервис таймеров
\subsection subTS_common Общие сведения
Данный сервис предоставляет возможность заказа переодических сообщений
UniSetTypes::TimerMessage т.е. таймеров.
Каждый заказчик может заказывать несколько таймеров, различающихся идентификаторами. При этом
идентификаторы определяет сам заказчик. Они должны быть уникальны только для одного заказчика.
\note
Сервис не гарантирует реальное время и точное соблюдение интервала. Т.к. к указанному в заказе времени
добавляется время на обработку и посылку сообщения, но при достаточных системных ресурсах точность увеличивается.
\subsection subTS_idea Сценарий работы
На узле запускается один экземпляр сервиса. Клиенты могут получить доступ, несколькими способами:
- через NameService
- при помощи UniversalInterface::askTimer()
\par
Сервис является системным, поэтому его идентификатор можно получить при помощи
UniSetTypes::Configuration::getTimerService() объекта UniSetTypes::conf.
\subsection subTS_interface Интерфейс
Сервис предоставляет одну функцию
\code
void TimerService::askTimer( CORBA::Short timerid, CORBA::Long timeMS, const UniSetTypes::ConsumerInfo& ci,
CORBA::Short ticks)
\endcode
при помощи которой осуществялется заказ таймера.
\param timerid - уникальный идентификатор таймера
\par
В случае попытки заказать таймер с уже существующим (для данного заказчика) идентификатором вырабатывается
исключение TimerService_i::TimerAlreadyExist.
\param timeMS - период между уведомлениями. Для отказа от таймера необходимо указать timeMS=0.
\param ticks позволяет ограничить количество уведомлений.
\par
Если ticks<0 уведомления будут посылатся, пока заказчик сам не откажется от них.
Общее количество таймеров (\b на \b всех \b заказчиков) ограничено ( TimerService::MaxCountTimers ).
В случае превышения данного предела на все заказы будет вырабатываться исключение TimerService_i::LimitTimers.
Для преодоления этого ограничения, а так же для обеспечения оптимальной работы сервиса, можно запускать на одном
узле несколько TimerService-ов для распределения нагрузки(заказов) между ними. При этом за распределение заказов
отвечает, разработчик.
\subsection subTS_lifetime Время жизни заказа
Для того, чтобы оптимизировать работу сервиса и уменьшить на него нагрузку вводится понятие
"время жизни заказа". В случае, если в течение TimerService::AskLifeTimeSEC не удаётся послать заказчику
уведомление, в следствие его недоступности - заказ анулируется.
\note Параметры можно задавать в конфигурационном файле
Реализацию см. \ref TimerService
*/
/*! \class TimerService
* Построен на основе PassiveTimer.
*/
class TimerService:
public POA_TimerService_i,
public UniSetObject
{
public:
TimerService( UniSetTypes::ObjectId id, const std::string confNodeName="LocalTimerService");
~TimerService();
//! заказ таймера
virtual void askTimer( const TimerService_i::Timer& ti, const UniSetTypes::ConsumerInfo& ci);
void printList();
protected:
TimerService(const std::string confNodeName="LocalTimerService");
/*! Информация о таймере */
struct TimerInfo
{
TimerInfo():id(0), curTimeMS(0){};
TimerInfo(CORBA::Short id, CORBA::Long timeMS, const UniSetTypes::ConsumerInfo& cinf,
CORBA::Short cnt, unsigned int askLifeTime, UniSetTypes::Message::Priority p):
cinf(cinf),
ref(0),
id(id),
curTimeMS(timeMS),
priority(p),
curTick(cnt-1),
not_ping(false)
{
tmr.setTiming(timeMS);
lifetmr.setTiming(askLifeTime*1000); // [сек]
};
inline void reset()
{
curTimeMS = tmr.getInterval();
tmr.reset();
}
UniSetTypes::ConsumerInfo cinf; /*!< инфою о заказчике */
UniSetObject_i_var ref; /*!< ссылка заказчика */
UniSetTypes::TimerId id; /*!< идентификатор таймера */
timeout_t curTimeMS; /*!< остаток времени */
UniSetTypes::Message::Priority priority; /*!< приоритет посылаемого сообщения */
/*!
* текущий такт
* \note Если задано количество -1 то сообщения будут поылатся постоянно
*/
CORBA::Short curTick;
// заказчик с меньшим временем ожидания имеет больший приоритет
bool operator < ( const TimerInfo& ti ) const
{
return curTimeMS > ti.curTimeMS;
}
PassiveTimer tmr;
PassiveTimer lifetmr; /*! таймер жизни заказа в случае если объект не доступен */
bool not_ping; /* признак недоступности заказчика */
};
typedef std::list<TimerInfo> TimersList;
//! посылка сообщения о наступлении времени
virtual bool send(TimerInfo& ti);
//! Дизактивизация объекта (переопределяется для необходимых действий перед деактивацией)
virtual bool disactivateObject();
virtual bool activateObject();
virtual void sigterm( int signo );
unsigned int MaxCountTimers; /*!< максимально возможное количество таймеров */
unsigned int AskLifeTimeSEC; /*!< [сек] время жизни заказа, если объект недоступен */
void init(const std::string& confnode);
void work();
private:
bool terminate;
bool isSleep;
UniSetTimer* sleepTimer; /*!< таймер для реализации засыпания в отсутствие заказов */
class Timer_eq: public std::unary_function<TimerInfo, bool>
{
public:
Timer_eq(const UniSetTypes::ConsumerInfo& coi, CORBA::Short t):tid(t),ci(coi){}
inline bool operator()(const TimerInfo& ti) const
{
return ( ti.cinf.id == ci.id && ti.cinf.node == ci.node && ti.id == tid );
}
protected:
UniSetTypes::TimerId tid;
UniSetTypes::ConsumerInfo ci;
};
TimersList tlst;
/*! замок для блокирования совместного доступа к cписку таймеров */
UniSetTypes::uniset_mutex lstMutex;
int execute_pid;
ThreadCreator<TimerService>* exthread;
};
#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 Базовый класс для реализации шаблона "наблюдатель"
* \author Pavel Vainerman
*/
//---------------------------------------------------------------------------
#ifndef UniSetObserver_H_
#define UniSetObserver_H_
//---------------------------------------------------------------------------
#include <list>
#include "UniSetObject.h"
#include "MessageType.h"
// --------------------------------------------------------------------------
class UniSetSubject
{
public:
UniSetSubject(UniSetTypes::ObjectId id);
~UniSetSubject();
virtual void attach( UniSetObject* o );
virtual void detach( UniSetObject* o );
virtual void attach( UniSetObject* o, int MessageType );
virtual void detach( UniSetObject* o, int MessageType );
protected:
UniSetSubject();
virtual void notify(int notify, int data,
UniSetTypes::Message::Priority priority=UniSetTypes::Message::Low);
virtual void notify( UniSetTypes::TransportMessage& msg );
private:
typedef std::list<UniSetObject*> ObserverList;
ObserverList lst;
UniSetTypes::ObjectId id;
};
//---------------------------------------------------------------------------
#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 Универсальный интерфейс для взаимодействия с объектами системы
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#ifndef UniversalInterface_H_
#define UniversalInterface_H_
// ---------------------------------------------------------------------------
#include <string>
#include <sstream>
#include <map>
#include <functional>
#include <omniORB4/CORBA.h>
#include "Exceptions.h"
#include "UniSetTypes.h"
#include "ObjectIndex.h"
#include "ObjectRepository.h"
#include "IOController_i.hh"
#include "MessageType.h"
#include "Configuration.h"
// -----------------------------------------------------------------------------------------
/*! \namespace UniversalIO
* Пространство имен содержащее классы, функции и т.п. для работы с вводом/выводом
*/
namespace UniversalIO
{
/*! Время ожидания ответа */
const unsigned int defaultTimeOut=3; // [сек]
}
// -----------------------------------------------------------------------------------------
//#define REPEAT_TIMEOUT 100 // [мс] пауза между попытками вызвать удаленную функцию объекта
//#define REPEAT_COUNT 5 // количество попыток, после которого вырабатывается TimeOut
#define IO_THROW_EXCEPTIONS UniSetTypes::TimeOut,UniSetTypes::IOBadParam,UniSetTypes::ORepFailed
// -----------------------------------------------------------------------------------------
/*!
* \class UniversalInterface
* ... а здесь идет кратенькое описание... (коротенько минут на 40!...)
* Для увеличения производительности в функции встроен cache обращений...
*
* См. также \ref UniversalIOControllerPage
*/
class UniversalInterface
{
public:
UniversalInterface( UniSetTypes::ObjectId backid, CORBA::ORB_var orb=NULL, UniSetTypes::ObjectIndex* oind=NULL );
UniversalInterface( UniSetTypes::Configuration* uconf=UniSetTypes::conf );
~UniversalInterface();
inline UniSetTypes::ObjectIndex* getObjectIndex() { return oind; }
inline UniSetTypes::Configuration* getConf() { return uconf; }
// -------- Функции работы с группой датчиков -----------
// Группа должна принадлежать одному процессу!
//! Получение состояния для списка указанных датчиков
IOController_i::ASensorInfoSeq_var getSensorSeq( UniSetTypes::IDList& lst );
// Изменения состояния списка входов/выходов
// Возвращает список не найденных идентификаторов
UniSetTypes::IDSeq_var setOutputSeq( const IOController_i::OutSeq& lst, UniSetTypes::ObjectId sup_id );
//! Заказ по списку
UniSetTypes::IDSeq_var askSensorsSeq( UniSetTypes::IDList& lst, UniversalIO::UIOCommand cmd,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
// ------------------------------------------------------
//! Получение состояния дискретного датчика
bool getState ( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node ) throw(IO_THROW_EXCEPTIONS);
bool getState ( UniSetTypes::ObjectId id );
//! Получение состояния аналогового датчика
long getValue ( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node )throw(IO_THROW_EXCEPTIONS);
long getValue ( UniSetTypes::ObjectId id );
//! Вывод для дискретного датчика
void setState ( UniSetTypes::ObjectId id, bool state, UniSetTypes::ObjectId node ) throw(IO_THROW_EXCEPTIONS);
void setState ( UniSetTypes::ObjectId id, bool state );
void setState ( IOController_i::SensorInfo& si, bool state, UniSetTypes::ObjectId supplier );
//! Вывод для аналогового датчика
void setValue ( UniSetTypes::ObjectId id, long value, UniSetTypes::ObjectId node ) throw(IO_THROW_EXCEPTIONS);
void setValue ( UniSetTypes::ObjectId id, long value);
void setValue ( IOController_i::SensorInfo& si, long value, UniSetTypes::ObjectId supplier );
//! Запись состояния дискретного датчика на удаленный контроллер
bool saveState ( UniSetTypes::ObjectId id, bool state, UniversalIO::IOTypes type, UniSetTypes::ObjectId node ) throw(IO_THROW_EXCEPTIONS);
bool saveState ( UniSetTypes::ObjectId id, bool state, UniversalIO::IOTypes type );
bool saveState ( IOController_i::SensorInfo& si, bool state, UniversalIO::IOTypes type, UniSetTypes::ObjectId supplier );
//! Запись состояния аналогового датчика на удаленный контроллер
bool saveValue ( UniSetTypes::ObjectId id, long value, UniversalIO::IOTypes type, UniSetTypes::ObjectId node ) throw(IO_THROW_EXCEPTIONS);
bool saveValue ( UniSetTypes::ObjectId id, long value, UniversalIO::IOTypes type );
bool saveValue ( IOController_i::SensorInfo& si, long value, UniversalIO::IOTypes type, UniSetTypes::ObjectId supplier );
// функции не вырабатывающие исключений...
void fastSaveValue( IOController_i::SensorInfo& si, long value, UniversalIO::IOTypes type, UniSetTypes::ObjectId supplier );
void fastSaveState( IOController_i::SensorInfo& si, bool state, UniversalIO::IOTypes type, UniSetTypes::ObjectId supplier );
void fastSetState( IOController_i::SensorInfo& si, bool state, UniSetTypes::ObjectId supplier );
void fastSetValue( IOController_i::SensorInfo& si, long value, UniSetTypes::ObjectId supplier );
// установка неопределённого состояния
void setUndefinedState( IOController_i::SensorInfo& si, bool undefined, UniSetTypes::ObjectId supplier );
CORBA::Long getRawValue( const IOController_i::SensorInfo& si );
//! калибровка
void calibrate(const IOController_i::SensorInfo& si,
const IOController_i::CalibrateInfo& ci,
UniSetTypes::ObjectId adminId = UniSetTypes::DefaultObjectId );
IOController_i::CalibrateInfo getCalibrateInfo( const IOController_i::SensorInfo& si );
//! Заказ информации об изменении дискретного датчика
void askRemoteState( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd, UniSetTypes::ObjectId node,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId )throw(IO_THROW_EXCEPTIONS);
void askState( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
//! Заказ информации об изменении аналогового датчика
void askRemoteValue ( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd, UniSetTypes::ObjectId node,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId ) throw(IO_THROW_EXCEPTIONS);
void askValue ( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
void askThreshold ( UniSetTypes::ObjectId sensorId, UniSetTypes::ThresholdId tid,
UniversalIO::UIOCommand cmd,
CORBA::Long lowLimit=0, CORBA::Long hiLimit=0, CORBA::Long sensibility=0,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
void askRemoteThreshold( UniSetTypes::ObjectId sensorId, UniSetTypes::ObjectId node,
UniSetTypes::ThresholdId thresholdId, UniversalIO::UIOCommand cmd,
CORBA::Long lowLimit=0, CORBA::Long hiLimit=0, CORBA::Long sensibility=0,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
//! Универсальный заказ информации об изменении датчика
void askSensor( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
void askRemoteSensor( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd, UniSetTypes::ObjectId node,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId )throw(IO_THROW_EXCEPTIONS);
void askOutput( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId );
void askRemoteOutput( UniSetTypes::ObjectId id, UniversalIO::UIOCommand cmd, UniSetTypes::ObjectId node,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId )throw(IO_THROW_EXCEPTIONS);
//! Заказ таймера
void askTimer( UniSetTypes::TimerId timerid, CORBA::Long timeMS, CORBA::Short ticks=-1,
UniSetTypes::Message::Priority piority=UniSetTypes::Message::High,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId) throw(IO_THROW_EXCEPTIONS);
//! Заказ сообщения
void askMessage( UniSetTypes::MessageCode mid, UniversalIO::UIOCommand cmd, bool ack = true,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId ) throw(IO_THROW_EXCEPTIONS);
void askMessageRange( UniSetTypes::MessageCode from, UniSetTypes::MessageCode to,
UniversalIO::UIOCommand cmd, bool ack = true,
UniSetTypes::ObjectId backid = UniSetTypes::DefaultObjectId ) throw(IO_THROW_EXCEPTIONS);
UniversalIO::IOTypes getIOType(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node) throw(IO_THROW_EXCEPTIONS);
UniversalIO::IOTypes getIOType(UniSetTypes::ObjectId id);
UniSetTypes::ObjectType getType(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node) throw(IO_THROW_EXCEPTIONS);
UniSetTypes::ObjectType getType(UniSetTypes::ObjectId id);
// read from xml (only for xml!)
UniversalIO::IOTypes getConfIOType( UniSetTypes::ObjectId id );
IOController_i::ShortIOInfo getChangedTime( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node );
IOController_i::ShortMapSeq* getSensors( UniSetTypes::ObjectId id,
UniSetTypes::ObjectId node=UniSetTypes::conf->getLocalNode() );
// /*! регистрация объекта в репозитории */
void registered(UniSetTypes::ObjectId id, const UniSetTypes::ObjectPtr oRef, bool force=false)throw(UniSetTypes::ORepFailed);
void registered(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node, const UniSetTypes::ObjectPtr oRef, bool force=false)throw(UniSetTypes::ORepFailed);
// /*! разрегистрация объекта */
void unregister(UniSetTypes::ObjectId id)throw(UniSetTypes::ORepFailed);
void unregister(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node)throw(UniSetTypes::ORepFailed);
/*! получение ссылки на объект */
inline UniSetTypes::ObjectPtr resolve(const char* name)
{
return rep.resolve(name);
}
inline UniSetTypes::ObjectPtr resolve( UniSetTypes::ObjectId id )
{
std::string nm = oind->getNameById(id);
return rep.resolve(nm);
}
UniSetTypes::ObjectPtr resolve( UniSetTypes::ObjectId id, UniSetTypes::ObjectId nodeName, int timeoutMS=UniversalIO::defaultTimeOut)
throw(UniSetTypes::ResolveNameError, UniSetTypes::TimeOut);
bool isExist( UniSetTypes::ObjectId id );
bool isExist( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node );
/*! получение идентификатора объекта по имени */
inline UniSetTypes::ObjectId getIdByName(const char* name)
{
return oind->getIdByName(name);
}
inline UniSetTypes::ObjectId getIdByName(const string name)
{
return getIdByName(name.c_str());
}
/*! получение имени по идентификатору объекта */
inline std::string getNameById( UniSetTypes::ObjectId id )
{
return oind->getNameById(id);
}
inline std::string getNameById( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node )
{
return oind->getNameById(id, node);
}
inline UniSetTypes::ObjectId getNodeId(const std::string& fullname)
{
return oind->getNodeId(fullname);
}
inline std::string getName(const std::string& fullname)
{
return oind->getName(fullname);
}
inline std::string getTextName( UniSetTypes::ObjectId id )
{
return oind->getTextName(id);
}
static std::string timeToString(time_t tm=time(0), const std::string brk=":"); /*!< Преобразование времени в строку HH:MM:SS */
static std::string dateToString(time_t tm=time(0), const std::string brk="/"); /*!< Преобразование даты в строку DD/MM/YYYY */
/*! посылка сообщения msg объекту name на узел node */
void send( UniSetTypes::ObjectId name, UniSetTypes::TransportMessage& msg, UniSetTypes::ObjectId node) throw(IO_THROW_EXCEPTIONS);
void send( UniSetTypes::ObjectId name, UniSetTypes::TransportMessage& msg);
bool info( std::string msg, UniSetTypes::ObjectId messenger,
UniSetTypes::ObjectId fromNode = UniSetTypes::conf->getLocalNode(),
UniSetTypes::InfoMessage::Character ch=UniSetTypes::InfoMessage::Normal,
UniSetTypes::ObjectId from=UniSetTypes::DefaultObjectId );
bool alarm( std::string msg, UniSetTypes::ObjectId messenger,
UniSetTypes::ObjectId fromNode = UniSetTypes::conf->getLocalNode(),
UniSetTypes::AlarmMessage::Character ch=UniSetTypes::AlarmMessage::Alarm,
UniSetTypes::ObjectId from=UniSetTypes::DefaultObjectId );
bool info( UniSetTypes::InfoMessage& msg, UniSetTypes::ObjectId messenger);
bool alarm( UniSetTypes::AlarmMessage& msg, UniSetTypes::ObjectId messenger);
bool waitReady( UniSetTypes::ObjectId id, int msec, int pause=5000,
UniSetTypes::ObjectId node = UniSetTypes::conf->getLocalNode() ); // used exist
bool waitWorking( UniSetTypes::ObjectId id, int msec, int pause=3000,
UniSetTypes::ObjectId node = UniSetTypes::conf->getLocalNode() ); // used getState
inline void setCacheMaxSize( unsigned int newsize)
{
rcache.setMaxSize(newsize);
}
/*!
\todo Убедится в уникальности возвращаемого результата hash(...)
*/
class CacheOfResolve
{
public:
CacheOfResolve(unsigned int maxsize, int cleantime):
MaxSize(maxsize), CleanTime(cleantime){};
~CacheOfResolve(){};
UniSetTypes::ObjectPtr resolve( UniSetTypes::ObjectId id, UniSetTypes::ObjectId node )throw(UniSetTypes::NameNotFound);
void cache(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node, UniSetTypes::ObjectVar ptr);
void erase(UniSetTypes::ObjectId id, UniSetTypes::ObjectId node);
inline void setMaxSize( unsigned int ms)
{
MaxSize = ms;
};
// void setCleanTime();
protected:
CacheOfResolve(){};
private:
bool clean(); /*!< функция очистки кэш-а от старых ссылок */
inline void clear() /*!< удаление всей информации */
{
UniSetTypes::uniset_mutex_lock l(cmutex,200);
mcache.clear();
};
/*!
\todo можно добавить поле CleanTime для каждой ссылки отдельно...
*/
struct Info
{
Info( UniSetTypes::ObjectVar ptr, time_t tm=0):
ptr(ptr)
{
if(!tm)
timestamp = time(NULL);
}
Info():
ptr(NULL), timestamp(0){};
UniSetTypes::ObjectVar ptr;
time_t timestamp; // время последнего обращения
bool operator<( const CacheOfResolve::Info& rhs ) const
{
return this->timestamp < rhs.timestamp;
}
};
typedef std::map<int, Info> CacheMap;
CacheMap mcache;
UniSetTypes::uniset_mutex cmutex;
unsigned int MaxSize; /*!< максимальный размер кэша */
unsigned int CleanTime; /*!< период устаревания ссылок [мин] */
/*
// В последствии написать функцию для использования
// remove_if
typedef std::pair<int, Info> CacheItem;
// функция-объект для поиска устаревших(по времени) ссылок
struct OldRef_eq: public unary_function<CacheItem, bool>
{
OldRef_eq(time_t tm):tm(tm){}
bool operator()( const CacheItem& inf ) const
{
return inf.timestamp < tm;
}
time_t tm;
};
*/
};
void initBackId( UniSetTypes::ObjectId backid );
protected:
std::string set_err(const std::string& pre, UniSetTypes::ObjectId id, UniSetTypes::ObjectId node);
private:
void init();
ObjectRepository rep;
UniSetTypes::ObjectId myid;
CosNaming::NamingContext_var localctx;
CORBA::ORB_var orb;
CacheOfResolve rcache;
UniSetTypes::ObjectIndex* oind;
UniSetTypes::Configuration* uconf;
};
// --------------------------------------------------------------------------
#endif
// --------------------------------------------------------------------------
#include <ostream>
#include <Exceptions.h>
#include <ORepHelpers.h>
#include <UniversalInterface.h>
#include <Configuration.h>
#include <UniSetTypes.h>
#include "UInterface.h"
//---------------------------------------------------------------------------
using namespace std;
//---------------------------------------------------------------------------
static UniversalInterface* ui=0;
//---------------------------------------------------------------------------
void UInterface::uniset_init_params( UTypes::Params* p, const char* xmlfile )throw(UException)
{
UInterface::uniset_init(p->argc,p->argv,xmlfile);
}
//---------------------------------------------------------------------------
void UInterface::uniset_init( int argc, char* argv[], const char* xmlfile )throw(UException)
{
try
{
UniSetTypes::uniset_init(argc,argv,xmlfile);
ui = new UniversalInterface();
return;
}
catch( UniSetTypes::Exception& ex )
{
throw UException(ex.what());
}
catch( ... )
{
throw UException();
}
}
//---------------------------------------------------------------------------
long UInterface::getValue( long id )throw(UException)
{
if( !UniSetTypes::conf || !ui )
throw USysError();
UniversalIO::IOTypes t = UniSetTypes::conf->getIOType(id);
try
{
switch(t)
{
case UniversalIO::DigitalInput:
case UniversalIO::DigitalOutput:
return (ui->getState(id) ? 1 : 0);
break;
case UniversalIO::AnalogInput:
case UniversalIO::AnalogOutput:
return ui->getValue(id);
break;
default:
{
ostringstream e;
e << "(getValue): Unknown iotype for id=" << id;
throw UException(e.str());
}
}
}
catch( UException& ex )
{
throw;
}
catch( UniSetTypes::Exception& ex )
{
throw UException(ex.what());
}
catch( ... )
{
throw UException("(getValue): catch...");
}
throw UException("(getValue): unknown error");
}
//---------------------------------------------------------------------------
void UInterface::setValue( long id, long val )throw(UException)
{
if( !UniSetTypes::conf || !ui )
throw USysError();
UniversalIO::IOTypes t = UniSetTypes::conf->getIOType(id);
try
{
switch(t)
{
case UniversalIO::DigitalInput:
ui->saveState(id,val,t);
break;
case UniversalIO::DigitalOutput:
ui->setState(id,val);
break;
case UniversalIO::AnalogInput:
ui->saveValue(id,val,t);
break;
case UniversalIO::AnalogOutput:
ui->setValue(id,val);
break;
default:
{
ostringstream e;
e << "(setValue): Unknown iotype for id=" << id;
throw UException(e.str());
}
}
}
catch( UException& ex )
{
throw;
}
catch( UniSetTypes::Exception& ex )
{
throw UException(ex.what());
}
catch( ... )
{
throw UException("(setValue): catch...");
}
}
//---------------------------------------------------------------------------
long UInterface::getSensorID( const char* name )
{
if( UniSetTypes::conf )
return UniSetTypes::conf->getSensorID(name);
return -1;
}
//---------------------------------------------------------------------------
const char* UInterface::getName( long id )
{
if( UniSetTypes::conf )
return UniSetTypes::conf->oind->getMapName(id).c_str();
return "";
}
//---------------------------------------------------------------------------
const char* UInterface::getShortName( long id )
{
if( UniSetTypes::conf )
return ORepHelpers::getShortName(UniSetTypes::conf->oind->getMapName(id)).c_str();
return "";
}
//---------------------------------------------------------------------------
const char* UInterface::getTextName( long id )
{
if( UniSetTypes::conf )
return UniSetTypes::conf->oind->getTextName(id).c_str();
return "";
}
//---------------------------------------------------------------------------
const char* UInterface::getConfFileName()
{
if( UniSetTypes::conf )
return UniSetTypes::conf->getConfFileName().c_str();
return "";
}
//---------------------------------------------------------------------------
#ifndef UInterface_H_
#define UInterface_H_
// --------------------------------------------------------------------------
#include <string>
#include "UTypes.h"
#include "UExceptions.h"
// --------------------------------------------------------------------------
namespace UInterface
{
void uniset_init_params( UTypes::Params* p, const char* xmlfile )throw(UException);
void uniset_init( int argc, char** argv, const char* xmlfile )throw(UException);
//---------------------------------------------------------------------------
long getValue( long id )throw(UException);
void setValue( long id, long val )throw(UException);
long getSensorID( const char* );
const char* getShortName( long id );
const char* getName( long id );
const char* getTextName( long id );
const char* getConfFileName();
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
// This file is part of the NCS project. (c) 1999-2000 All rights reserved.
// 14-ти битная аналоговая карта 16 входов (8 дифф), 2 выхода (12-ти битные)
/*
#include <assert.h>
#include "conf.h"
#include "IOPort.h"
#include "IOs/AnalogCardAI165A.h"
#include "SysTimer.h"
#include "Exceptions.h"
//-----------------------------------------------------------------------------
AnalogCardAI165A::AnalogCardAI165A( void )
{
if( ioperm( base_io_adr, 0x10, PORT_PERMISSION ) == -1 )
throw GlobalError("Невозможно открыть порты");
if (!((inb(base_io_adr+14)=='A')&&(inb(base_io_adr+15)==17)))
throw GlobalError("Модуль AI16-5a-STB с FIFO не найден !");
outw(0x0000,base_io_adr+0);
// Умножение входного сигнала
int u=0x0000;
// u=0x5555;
// case 2 : n=0xAAAA; break;
// case 3 : n=0xFFFF; break;
outw(u,base_io_adr+6);
outw(u,base_io_adr+8);
maxInputChannel=16;
}
//-----------------------------------------------------------------------------
AnalogCardAI165A::~AnalogCardAI165A( void )
{
}
//-----------------------------------------------------------------------------
int AnalogCardAI165A::getValue( int io_channel )
{
assert(io_channel>=0);
assert(io_channel<16);
// if(io_channel>=16)
// printf("%d\n",io_channel);
// io_channel&=0x0F;
outb(0x00, base_io_adr+0);
io_channel|=0x20; // Однопроводное подключение
outb(io_channel, base_io_adr+2);
msleep(10); // можно поставить for (int i=0;i<90;i++);
//int o=inb(base_io_adr+0);
//outb((o&240)|0x80, base_io_adr+0);
outb(0x80, base_io_adr+0); // ST_RDY Старт АЦП
//for (int i=0; i<60; i++); // pause
//while(!(inb(base_io_adr+0)&0x80)); // ST_RDY
while(!(inb(base_io_adr+0)&0x20));
int r=inw(base_io_adr+2);
if (r<0) r=-1;
//if (r>8191) r=8191;
return r;
}
void AnalogCardAI165A::getChainValue( long * data, const int NumChannel )
{
assert(NumChannel>=0);
assert(NumChannel<16);
outw(0x00, base_io_adr+0);
int io_channel=0;
io_channel|=0x20; // Однопроводное подключение
outb(io_channel, base_io_adr+2);
msleep(1);
for(int n=0; n< NumChannel; n++)
{
outb(0x80|0x01, base_io_adr+0); // ST_RDY | n++
while(!(inb(base_io_adr+0)&0x80)); // ST_RDY // Опрос бита готовности
data[n]=inw(base_io_adr+2);
// может быть здесь все же нужна пауза?
}
outw(0x00, base_io_adr+0);
}
//-----------------------------------------------------------------------------
// !!! Не устанавливается номер канала
void AnalogCardAI165A::setValue( int io_channel, int value )
// io_channel -- 0 or 1
{
assert(io_channel==0 || io_channel==1 );
if (value<0)
value=0;
else if (value>4095)
value=4095;
io_channel&=1;
io_channel<<=12;
value&=0x0FFF;
outw(value,base_io_adr+14);
outb(value,base_io_adr+14);
}
*/
/***************************************************************************
* This file is part of the UniSet* library *
* Copyright (C) 1999-2002 SET Research Institute. All rights reserved. *
***************************************************************************/
/*! \file
* \brief Класс для дискретной карты O5600
* \author Vitaly Lipatov
*/
/**************************************************************************/
#include <assert.h>
#include "IOs/DigitalCard_O5600.h"
#include "Exceptions.h"
using namespace std;
// Получить маску для модуля module
char DigitalCard_O5600::getMask( int module )
{
assert ( module >= 0 && module < 24 );
return 1 << ( module & 0x07 );
}
// Получить адрес порта для указанного модуля
int DigitalCard_O5600::getPort( int module )
{
//assert( baseadr + 2 < SIZE_OF_PORTMAP );
if ( ( module >= 0 ) && ( module < 8 ) )
{
return baseadr + 2; // C
}
else if ( module > 7 && module < 16 )
{
return baseadr + 0; // A
}
else if ( module > 15 && module < 24 )
{
return baseadr + 1; // B
}
// Чего за ерунду передаете?!!
//logErr.Save( "Неправильный номер модуля для функции GetPort, module=%d", module );
//throw Exceptions::OutOfRange();
return baseadr;
}
bool DigitalCard_O5600::get( int module )
{
char tmp = ~in( getPort( module ) );
return tmp & getMask( module );
}
char DigitalCard_O5600::getPrevious( int module )
{
assert ( getPort( module ) - baseadr >= 0 );
assert ( getPort( module ) - baseadr < 4 );
return portmap[ getPort( module ) - baseadr ];
}
/*
bool DigitalCard_O5600::getCurrentState( int module )
{
return getPrevious( module ) & getMask( module );
}
*/
void DigitalCard_O5600::putByte( int ba, char val )
{
portmap[ba - baseadr] = val;
out( ba, ~val );
}
int DigitalCard_O5600::getByte( int ba )
{
char tmp = ~in( ba );
return tmp;
}
void DigitalCard_O5600::set( int module, bool state )
{
char val = getPrevious( module );
char mask = getMask( module );
if ( state )
val |= mask;
else
val &= ~mask;
putByte( getPort( module ), val );
}
bool DigitalCard_O5600::init( bool flagInit, int numOfCard, int base_address, char mode )
{
//if ( !Card.portmap )
// logIO.Save( "DigitalCard_O5600: Вызвана Init без предварительного получения памяти" );
//this->numOfCard = numOfCard;
baseadr = base_address;
cout << "baseadr=" << baseadr << endl;
iomode = mode;
//logReg.Save( "DigitalCard_O5600: Начали" );
out( baseadr + 0x03, iomode | 0x80 ); // Настройка режима карты
for ( int k = 0;k < 3;k++ )
{
putByte( baseadr + k, 0 );
}
if ( in( baseadr + 0x03 ) == 0xff ) // Нет карты
return false;
//logReg.Save( "DigitalCard_O5600: Установлен" );
return true;
}
############################################################################
# This file is part of the UniSet library #
############################################################################
noinst_LTLIBRARIES = libIOs.la
libIOs_la_SOURCES = AnalogCard_AI165A.cc DigitalCard_O5600.cc
include $(top_builddir)/conf/setting.mk
This source diff could not be displayed because it is too large. You can view the blob instead.
/* 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
*/
// --------------------------------------------------------------------------
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <sstream>
#include "Exceptions.h"
#include "ORepHelpers.h"
#include "UniversalInterface.h"
#include "ObjectsActivator.h"
#include "Debug.h"
#include "Configuration.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// ------------------------------------------------------------------------------------------
/*
Завершение работы организовано следующим образом.
Имеется глобальный указатель gActivator (т.к. активатор в системе должен быть только один).
Он заказывает на себя все сигналы связанные с завершением работы.
В качестве обработчика сигналов регистрируется ObjectsActivator::terminated( int signo ).
В этом обработчике происходит вызов ObjectsActivator::oaDestroy(int signo) для фактического
завершения работы и заказывается сигнал SIG_ALRM на время TERMINATE_TIMEOUT,
c обработчиком ObjectsActivator::finishterm в котором происходит
"надежное" прибивание текущего процесса (raise(SIGKILL)). Это сделано на тот случай, если
в oaDestroy произойдет зависание.
*/
// ------------------------------------------------------------------------------------------
/*! замок для блокирования совместного доступа к функции обрабтки сигналов */
static UniSetTypes::uniset_mutex signalMutex("Activator::signalMutex");
// static UniSetTypes::uniset_mutex waittermMutex("Activator::waittermMutex");
/*! замок для блокирования совместного к списку получателей сигналов */
//UniSetTypes::uniset_mutex sigListMutex("Activator::sigListMutex");
//static omni_mutex pmutex;
//static omni_condition pcondx(&pmutex);
// ------------------------------------------------------------------------------------------
static ObjectsActivator* gActivator=0;
//static omni_mutex termutex;
//static omni_condition termcond(&termutex);
//static ThreadCreator<ObjectsActivator>* termthread=0;
static int SIGNO;
static int MYPID;
static const int TERMINATE_TIMEOUT = 2; // время отведенное на завершение процесса [сек]
volatile sig_atomic_t procterm = 0;
volatile sig_atomic_t doneterm = 0;
// PassiveTimer termtmr;
// ------------------------------------------------------------------------------------------
ObjectsActivator::ObjectsActivator( ObjectId id ):
ObjectsManager(id),
orbthr(0),
omDestroy(false),
sig(false)
{
ObjectsActivator::init();
}
// ------------------------------------------------------------------------------------------
ObjectsActivator::ObjectsActivator():
ObjectsManager(UniSetTypes::DefaultObjectId),
orbthr(0),
omDestroy(false),
sig(false)
{
// thread(false); // отключаем поток (раз не задан id)
ObjectsActivator::init();
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::init()
{
orb = conf->getORB();
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var root_poa = PortableServer::POA::_narrow(obj);
pman = root_poa->the_POAManager();
CORBA::PolicyList pl = conf->getPolicy();
poa = root_poa->create_POA("my poa", pman, pl);
if( CORBA::is_nil(poa) )
unideb[Debug::CRIT] << myname << "(init): init poa failed!!!" << endl;
gActivator=this;
atexit( ObjectsActivator::normalexit );
set_terminate( ObjectsActivator::normalterminate ); // ловушка для неизвестных исключений
}
// ------------------------------------------------------------------------------------------
ObjectsActivator::~ObjectsActivator()
{
if(!procterm )
{
unideb[Debug::SYSTEM] << myname << "(destructor): ..."<< endl << flush;
if( !omDestroy )
oaDestroy();
procterm = 1;
doneterm = 1;
set_signals(false);
gActivator=0;
}
if( orbthr )
delete orbthr;
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::oaDestroy(int signo)
{
// waittermMutex.lock();
if( !omDestroy )
{
omDestroy = true;
unideb[Debug::SYSTEM] << myname << "(oaDestroy): begin..."<< endl;
unideb[Debug::SYSTEM] << myname << "(oaDestroy): terminate... " << endl;
term(signo);
unideb[Debug::SYSTEM] << myname << "(oaDestroy): terminate ok. " << endl;
try
{
stop();
}
catch(...){}
unideb[Debug::SYSTEM] << myname << "(oaDestroy): pman deactivate... " << endl;
pman->deactivate(false,true);
unideb[Debug::SYSTEM] << myname << "(oaDestroy): pman deactivate ok. " << endl;
unideb[Debug::SYSTEM] << myname << "(oaDestroy): orb destroy... " << endl;
try
{
orb->destroy();
}
catch(...){}
unideb[Debug::SYSTEM] << myname << "(oaDestroy): orb destroy ok."<< endl;
if( orbthr )
{
delete orbthr;
orbthr = 0;
}
}
// waittermMutex.unlock();
}
// ------------------------------------------------------------------------------------------
/*!
* Если thread=true то функция создает отдельный поток для обработки приходящих сообщений.
* И передает все ресурсы этого потока orb. А также регистрирует процесс в репозитории.
* \note Только после этого объект становится доступен другим процессам
* А далее выходит...
* Иначе все ресурсы основного потока передаются для обработки приходящих сообщений (и она не выходит)
*
*/
void ObjectsActivator::run(bool thread)
{
unideb[Debug::SYSTEM] << myname << "(run): создаю менеджер "<< endl;
ObjectsManager::initPOA(this);
if( getId() == UniSetTypes::DefaultObjectId )
offThread(); // отключение потока обработки сообщений, раз не задан ObjectId
ObjectsManager::activate(); // а там вызывается активация всех подчиненных объектов и менеджеров
getinfo(); // заполнение информации об объектах
active=true;
unideb[Debug::SYSTEM] << myname << "(run): активизируем менеджер"<<endl;
pman->activate();
msleep(50);
set_signals(true);
if( thread )
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(run): запускаемся с созданием отдельного потока... "<< endl;
orbthr = new ThreadCreator<ObjectsActivator>(this, &ObjectsActivator::work);
if( !orbthr->start() )
{
unideb[Debug::CRIT] << myname << "(run): НЕ СМОГЛИ СОЗДАТЬ ORB-поток"<<endl;
throw SystemError("(ObjectsActivator::run): CREATE ORB THREAD FAILED");
}
}
else
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(run): запускаемся без создания отдельного потока... "<< endl;
work();
}
}
// ------------------------------------------------------------------------------------------
/*!
* Функция останавливает работу orb и завершает поток. А так же удаляет ссылку из репозитория.
* \note Объект становится недоступен другим процессам
*/
void ObjectsActivator::stop()
{
// uniset_mutex_lock l(disactivateMutex, 500);
if( active )
{
active=false;
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(stop): disactivate... "<< endl;
disactivate();
if( unideb.debugging(Debug::SYSTEM) )
{
unideb[Debug::SYSTEM] << myname << "(stop): disactivate ok. "<<endl;
unideb[Debug::SYSTEM] << myname << "(stop): discard request..."<< endl;
}
pman->discard_requests(true);
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(stop): discard request ok."<< endl;
/*
try
{
unideb[Debug::SYSTEM] << myname << "(stop):: shutdown orb... "<<endl;
orb->shutdown(false);
}
catch(...){}
unideb[Debug::SYSTEM] << myname << "(stop): shutdown ok."<< endl;
*/
}
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::work()
{
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(work): запускаем orb на обработку запросов..."<< endl;
try
{
if(orbthr)
thpid = orbthr->getTID();
else
thpid = getpid();
orb->run();
}
catch(CORBA::SystemException& ex)
{
unideb[Debug::CRIT] << myname << "(work): поймали CORBA::SystemException: " << ex.NP_minorString() << endl;
}
catch(CORBA::Exception& ex)
{
unideb[Debug::CRIT] << myname << "(work): поймали CORBA::Exception." << endl;
}
catch(omniORB::fatalException& fe)
{
unideb[Debug::CRIT] << myname << "(work): : поймали omniORB::fatalException:" << endl;
unideb[Debug::CRIT] << myname << "(work): file: " << fe.file() << endl;
unideb[Debug::CRIT] << myname << "(work): line: " << fe.line() << endl;
unideb[Debug::CRIT] << myname << "(work): mesg: " << fe.errmsg() << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(work): catch ..." << endl;
}
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(work): orb стоп!!!"<< endl;
/*
unideb[Debug::SYSTEM] << myname << "(oaDestroy): orb destroy... " << endl;
try
{
orb->destroy();
}
catch(...){}
unideb[Debug::SYSTEM] << myname << "(oaDestroy): orb destroy ok."<< endl;
*/
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::getinfo()
{
for( ObjectsManagerList::const_iterator it= beginMList();
it!= endMList(); ++it )
{
MInfo mi;
mi.mnr = (*it);
mi.msgpid = (*it)->getMsgPID();
lstMInfo.push_back(mi);
}
for( ObjectsList::const_iterator it= beginOList();
it!= endOList(); ++it )
{
OInfo oi;
oi.obj = (*it);
oi.msgpid = (*it)->getMsgPID();
lstOInfo.push_back(oi);
}
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::processingMessage( UniSetTypes::VoidMessage *msg )
{
try
{
switch( msg->type )
{
case Message::SysCommand:
{
SystemMessage sm( msg );
sysCommand(&sm);
}
break;
default:
break;
}
}
catch(Exception& ex)
{
unideb[Debug::CRIT] << myname << "(processingMessage): " << ex << endl;
}
}
// -------------------------------------------------------------------------
void ObjectsActivator::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch(sm->command)
{
case SystemMessage::LogRotate:
{
unideb[Debug::SYSTEM] << myname << "(sysCommand): logRotate" << endl;
// переоткрываем логи
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname.c_str());
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << endl;
}
}
break;
}
}
// -------------------------------------------------------------------------
/*
void ObjectsActivator::sig_child(int signo)
{
unideb[Debug::SYSTEM] << gActivator->getName() << "(sig_child): дочерний процесс закончил работу...(sig=" << signo << ")" << endl;
while( waitpid(-1, 0, WNOHANG) > 0);
}
*/
// ------------------------------------------------------------------------------------------
void ObjectsActivator::set_signals(bool ask)
{
struct sigaction act, oact;
sigemptyset(&act.sa_mask);
sigemptyset(&oact.sa_mask);
// добавляем сигналы, которые будут игнорироваться
// при обработке сигнала
sigaddset(&act.sa_mask, SIGINT);
sigaddset(&act.sa_mask, SIGTERM);
sigaddset(&act.sa_mask, SIGABRT );
sigaddset(&act.sa_mask, SIGQUIT);
// sigaddset(&act.sa_mask, SIGSEGV);
// sigaddset(&act.sa_mask, SIGALRM);
// act.sa_flags = 0;
// act.sa_flags |= SA_RESTART;
// act.sa_flags |= SA_RESETHAND;
if(ask)
act.sa_handler = terminated;
else
act.sa_handler = SIG_DFL;
sigaction(SIGINT, &act, &oact);
sigaction(SIGTERM, &act, &oact);
sigaction(SIGABRT, &act, &oact);
sigaction(SIGQUIT, &act, &oact);
// sigaction(SIGSEGV, &act, &oact);
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::finishterm( int signo )
{
if( !doneterm )
{
if( unideb.debugging(Debug::SYSTEM) && gActivator )
unideb[Debug::SYSTEM] << gActivator->getName()
<< "(finishterm): прерываем процесс завершения...!" << endl<< flush;
if( gActivator )
gActivator->set_signals(false);
sigset(SIGALRM, SIG_DFL);
doneterm = 1;
raise(SIGKILL);
}
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::terminated( int signo )
{
if( !signo || doneterm || !gActivator || procterm )
return;
{ // lock
// на случай прихода нескольких сигналов
uniset_mutex_lock l(signalMutex, TERMINATE_TIMEOUT*1000);
if( !procterm )
{
procterm = 1;
SIGNO = signo;
MYPID = getpid();
if( unideb.debugging(Debug::SYSTEM) && gActivator )
{
unideb[Debug::SYSTEM] << gActivator->getName() << "(terminated): catch SIGNO="<< signo << "("<< strsignal(signo) <<")"<< endl << flush;
unideb[Debug::SYSTEM] << gActivator->getName() << "(terminated): устанавливаем timer завершения на "
<< TERMINATE_TIMEOUT << " сек " << endl << flush;
}
sighold(SIGALRM);
sigset(SIGALRM, ObjectsActivator::finishterm);
alarm(TERMINATE_TIMEOUT);
sigrelse(SIGALRM);
if( gActivator )
gActivator->oaDestroy(SIGNO); // gActivator->term(SIGNO);
doneterm = 1;
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << gActivator->getName() << "(terminated): завершаемся..."<< endl<< flush;
if( gActivator )
ObjectsActivator::set_signals(false);
sigset(SIGALRM, SIG_DFL);
raise(SIGNO);
}
}
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::normalexit()
{
if( gActivator && unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << gActivator->getName() << "(default exit): good bye."<< endl << flush;
}
void ObjectsActivator::normalterminate()
{
if( gActivator )
unideb[Debug::CRIT] << gActivator->getName() << "(default exception terminate): Никто не выловил исключение!!! Good bye."<< endl<< flush;
// abort();
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::term( int signo )
{
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(term): TERM" << endl;
if( doneterm )
return;
if( signo )
sig = true;
try
{
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(term): вызываем sigterm()" << endl;
sigterm(signo);
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(term): sigterm() ok." << endl;
}
catch(Exception& ex)
{
unideb[Debug::CRIT] << myname << "(term): " << ex << endl;
}
catch(...){}
if( unideb.debugging(Debug::SYSTEM) )
unideb[Debug::SYSTEM] << myname << "(term): END TERM" << endl;
}
// ------------------------------------------------------------------------------------------
void ObjectsActivator::waitDestroy()
{
for(;;)
{
if( doneterm || !gActivator )
break;
msleep(50);
}
gActivator = 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
*/
// --------------------------------------------------------------------------
#include <cstdlib>
#include <sstream>
#include <list>
#include <string>
#include <functional>
#include <algorithm>
#include "Exceptions.h"
#include "ORepHelpers.h"
#include "UniversalInterface.h"
#include "ObjectsManager.h"
#include "Debug.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// ------------------------------------------------------------------------------------------
// объект-функция для посылки сообщения менеджеру
class MPush: public unary_function<ObjectsManager*, bool>
{
public:
MPush(const UniSetTypes::TransportMessage& msg):msg(msg){}
bool operator()(ObjectsManager* m) const
{
try
{
m->push( msg );
m->broadcast( msg );
return true;
}
catch(...){}
return false;
}
private:
const UniSetTypes::TransportMessage& msg;
};
// объект-функция для посылки сообщения объекту
class OPush: public unary_function<UniSetObject*, bool>
{
public:
OPush(const UniSetTypes::TransportMessage& msg):msg(msg){}
bool operator()(UniSetObject* o) const
{
try
{
o->push( msg );
return true;
}
catch(...){}
return false;
}
private:
const UniSetTypes::TransportMessage& msg;
};
// ------------------------------------------------------------------------------------------
ObjectsManager::ObjectsManager():
UniSetObject(UniSetTypes::DefaultObjectId)
{
}
// ------------------------------------------------------------------------------------------
ObjectsManager::ObjectsManager( ObjectId id):
UniSetObject(id),
sig(0)
{
}
// ------------------------------------------------------------------------------------------
ObjectsManager::ObjectsManager(const string name, const string section):
UniSetObject(name, section),
sig(0)
{
}
// ------------------------------------------------------------------------------------------
ObjectsManager::~ObjectsManager()
{
try
{
objects(deactiv);
}
catch(...){}
try
{
managers(deactiv);
}
catch(...){}
olist.clear();
mlist.clear();
}
// ------------------------------------------------------------------------------------------
void ObjectsManager::initPOA( ObjectsManager* rmngr )
{
if( CORBA::is_nil(pman) )
this->pman = rmngr->getPOAManager();
/*
string mname(getName());
mname+="_poamngr";
PortableServer::POA_var root_poa = rmngr->getPOA();
poa = root_poa->create_POA(mname.c_str(), pman, policyList);
*/
PortableServer::POA_var rpoa = rmngr->getPOA();
if( rpoa != poa )
poa = rmngr->getPOA();
if( CORBA::is_nil(poa) )
unideb[Debug::CRIT] << myname << "(initPOA): failed init poa " << endl;
// Инициализация самого менеджера и его подобъектов
UniSetObject::init(rmngr);
objects(initial);
managers(initial);
}
// ------------------------------------------------------------------------------------------
bool ObjectsManager::addObject( UniSetObject *obj )
{
{ //lock
uniset_mutex_lock lock(olistMutex, 1000);
ObjectsList::iterator li=find(olist.begin(),olist.end(), obj);
if( li==olist.end() )
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(activator): добавляем объект "<< obj->getName()<< endl;
olist.push_back(obj);
}
} // unlock
return true;
}
// ------------------------------------------------------------------------------------------
bool ObjectsManager::removeObject(UniSetObject* obj)
{
{ //lock
uniset_mutex_lock lock(olistMutex, 1000);
ObjectsList::iterator li=find(olist.begin(),olist.end(), obj);
if( li!=olist.end() )
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(activator): удаляем объект "<< obj->getName()<< endl;
try
{
obj->disactivate();
}
catch(Exception& ex)
{
unideb[Debug::WARN] << myname << "(removeObject): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
unideb[Debug::WARN] << myname << "(removeObject): поймали CORBA::SystemException: " << ex.NP_minorString() << endl;
}
catch(CORBA::Exception& ex)
{
unideb[Debug::WARN] << myname << "(removeObject): CORBA::Exception" << endl;
}
catch( omniORB::fatalException& fe )
{
unideb[Debug::CRIT] << myname << "(managers): Caught omniORB::fatalException:" << endl;
unideb[Debug::CRIT] << myname << "(managers): file: " << fe.file()
<< " line: " << fe.line()
<< " mesg: " << fe.errmsg() << endl;
}
catch(...){}
olist.erase(li);
}
} // unlock
return true;
}
// ------------------------------------------------------------------------------------------
/*!
* Функция работы со списком менеджеров
*/
void ObjectsManager::managers(OManagerCommand cmd)
{
unideb[Debug::INFO] << myname <<"(managers): mlist.size="
<< mlist.size() << " cmd=" << cmd << endl;
{ //lock
uniset_mutex_lock lock(mlistMutex, 1000);
for( ObjectsManagerList::iterator li=mlist.begin();li!=mlist.end();++li )
{
try
{
switch(cmd)
{
case initial:
(*li)->initPOA(this);
break;
case activ:
(*li)->activate();
break;
case deactiv:
(*li)->disactivate();
break;
case term:
(*li)->sigterm(sig);
break;
default:
break;
}
}
catch( Exception& ex )
{
unideb[Debug::CRIT] << myname << "(managers): " << ex << endl;
unideb[Debug::CRIT] << myname << "(managers): не смог зарегистрировать (разрегистрировать) объект -->"<< (*li)->getName() << endl;
}
catch(CORBA::SystemException& ex)
{
unideb[Debug::CRIT] << myname << "(managers): поймали CORBA::SystemException:" << ex.NP_minorString() << endl;
}
catch( CORBA::Exception& ex )
{
unideb[Debug::CRIT] << myname << "(managers): Caught CORBA::Exception. " << ex._name() << endl;
}
catch( omniORB::fatalException& fe )
{
unideb[Debug::CRIT] << myname << "(managers): Caught omniORB::fatalException:" << endl;
unideb[Debug::CRIT] << myname << "(managers): file: " << fe.file()
<< " line: " << fe.line()
<< " mesg: " << fe.errmsg() << endl;
}
}
} // unlock
}
// ------------------------------------------------------------------------------------------
/*!
* Функция работы со списком объектов.
*/
void ObjectsManager::objects(OManagerCommand cmd)
{
unideb[Debug::INFO] << myname <<"(objects): olist.size="
<< olist.size() << " cmd=" << cmd << endl;
{ //lock
uniset_mutex_lock lock(olistMutex, 1000);
for (ObjectsList::iterator li=olist.begin();li!=olist.end();++li)
{
try
{
switch(cmd)
{
case initial:
(*li)->init(this);
break;
case activ:
(*li)->activate();
break;
case deactiv:
(*li)->disactivate();
break;
case term:
(*li)->sigterm(sig);
break;
default:
break;
}
}
catch( Exception& ex )
{
unideb[Debug::CRIT] << myname << "(objects): " << ex << endl;
unideb[Debug::CRIT] << myname << "(objects): не смог зарегистрировать (разрегистрировать) объект -->"<< (*li)->getName() << endl;
}
catch(CORBA::SystemException& ex)
{
unideb[Debug::CRIT] << myname << "(objects): поймали CORBA::SystemException:" << ex.NP_minorString() << endl;
}
catch( CORBA::Exception& ex )
{
unideb[Debug::CRIT] << myname << "(objects): Caught CORBA::Exception. "
<< ex._name()
<< " (" << (*li)->getName() << ")" << endl;
}
catch( omniORB::fatalException& fe )
{
unideb[Debug::CRIT] << myname << "(objects): Caught omniORB::fatalException:" << endl;
unideb[Debug::CRIT] << myname << "(objects): file: " << fe.file()
<< " line: " << fe.line()
<< " mesg: " << fe.errmsg() << endl;
}
}
} // unlock
}
// ------------------------------------------------------------------------------------------
/*!
* Регистрирация объекта и всех его подобъектов в репозитории.
* \note Только после этого он (и они) становятся доступны другим процессам
*/
bool ObjectsManager::activateObject()
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(activateObjects): активизирую объекты"<< endl;
UniSetObject::activateObject();
managers(activ);
objects(activ);
return true;
}
// ------------------------------------------------------------------------------------------
/*!
* Удаление объекта и всех его подобъектов из репозитория.
* \note Объект становится недоступен другим процессам
*/
bool ObjectsManager::disactivateObject()
{
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << "(disactivateObjects): деактивизирую объекты"<< endl;
// именно в такой последовательности!
objects(deactiv);
managers(deactiv);
return true;
}
// ------------------------------------------------------------------------------------------
void ObjectsManager::sigterm( int signo )
{
// unideb[Debug::INFO] << "ObjectsActivator: default processing signo="<< signo << endl;
sig=signo;
objects(term);
managers(term);
UniSetObject::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void ObjectsManager::broadcast(const TransportMessage& msg)
{
// себя не забыть...
// push(msg);
// Всем объектам...
{ //lock
uniset_mutex_lock lock(olistMutex, 2000);
for_each(olist.begin(),olist.end(),OPush(msg)); // STL метод
} // unlock
// Всем менеджерам....
{ //lock
uniset_mutex_lock lock(mlistMutex, 2000);
for_each(mlist.begin(),mlist.end(),MPush(msg)); // STL метод
} // unlock
}
// ------------------------------------------------------------------------------------------
bool ObjectsManager::addManager( ObjectsManager *child )
{
{ //lock
uniset_mutex_lock lock(mlistMutex, 1000);
// Проверка на совпадение
ObjectsManagerList::iterator it= find(mlist.begin(),mlist.end(),child);
if(it == mlist.end() )
{
mlist.push_back( child );
if( unideb.debugging(Debug::INFO) )
unideb[Debug::INFO] << myname << ": добавляем менеджер "<< child->getName()<< endl;
}
else
unideb[Debug::WARN] << myname << ": попытка повторного добавления объекта "<< child->getName() << endl;
} // unlock
return true;
}
// ------------------------------------------------------------------------------------------
bool ObjectsManager::removeManager( ObjectsManager* child )
{
{ //lock
uniset_mutex_lock lock(mlistMutex, 1000);
mlist.remove(child);
} // unlock
return true;
}
// ------------------------------------------------------------------------------------------
const ObjectsManager* ObjectsManager::itemM(const ObjectId id)
{
{ //lock
uniset_mutex_lock lock(mlistMutex, 1000);
for( ObjectsManagerList::iterator li=mlist.begin(); li!=mlist.end();++li )
{
if ( (*li)->getId()==id )
return (*li);
}
} // unlock
return 0;
}
// ------------------------------------------------------------------------------------------
const UniSetObject* ObjectsManager::itemO(const ObjectId id)
{
{ //lock
uniset_mutex_lock lock(olistMutex, 1000);
for (ObjectsList::iterator li=olist.begin(); li!=olist.end();++li)
{
if ( (*li)->getId()==id )
return (*li);
}
} // unlock
return 0;
}
// ------------------------------------------------------------------------------------------
int ObjectsManager::objectsCount()
{
int res( olist.size()+mlist.size() );
for( ObjectsManagerList::const_iterator it= beginMList();
it!= endMList(); ++it )
{
res+= (*it)->objectsCount();
}
return res;
}
// ------------------------------------------------------------------------------------------
int ObjectsManager::getObjectsInfo( ObjectsManager* mngr, SimpleInfoSeq* seq,
int begin, const long uplimit )
{
int ind = begin;
// получаем у самого менджера
SimpleInfo_var msi=mngr->getInfo();
(*seq)[ind] = msi;
ind++;
if( ind > uplimit )
return ind;
for( ObjectsList::const_iterator it= mngr->beginOList();
it!=mngr->endOList(); ++it )
{
try
{
SimpleInfo_var si=(*it)->getInfo();
(*seq)[ind] = si;
ind++;
if( ind>uplimit )
break;
}
catch(CORBA::Exception& ex)
{
unideb[Debug::WARN] << myname << "(getObjectsInfo): CORBA::Exception" << endl;
}
catch(...)
{
unideb[Debug::WARN] << myname << "(getObjectsInfo): не смог получить у объекта "
<< conf->oind->getNameById( (*it)->getId() ) << " информацию" << endl;
}
}
if( ind > uplimit )
return ind;
// а далее у его менеджеров (рекурсивно)
for( ObjectsManagerList::const_iterator it=mngr->beginMList();
it!=mngr->endMList(); ++it )
{
ind = getObjectsInfo((*it),seq,ind,uplimit);
if( ind > uplimit )
break;
}
return ind;
}
// ------------------------------------------------------------------------------------------
SimpleInfoSeq* ObjectsManager::getObjectsInfo( CORBA::Long maxlength )
{
SimpleInfoSeq* res = new SimpleInfoSeq(); // ЗА ОСВОБОЖДЕНИЕ ПАМЯТИ ОТВЕЧАЕТ КЛИЕНТ!!!!!!
// поэтому ему лучше пользоваться при получении _var-классом
int length = objectsCount()+1;
if( length >= maxlength )
length = maxlength;
res->length(length);
// используем рекурсивную функцию
int ind = 0;
const int limit = length;
ind = getObjectsInfo( this, res, ind, limit );
return res;
}
// ------------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include "Exceptions.h"
#include "ObjectsManager_LT.h"
#include "Debug.h"
#include "PassiveTimer.h"
// ------------------------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// ------------------------------------------------------------------------------------------
ObjectsManager_LT::ObjectsManager_LT( UniSetTypes::ObjectId id ):
ObjectsManager(id),
sleepTime(UniSetTimer::WaitUpTime)
{
}
// ------------------------------------------------------------------------------------------
ObjectsManager_LT::ObjectsManager_LT():
sleepTime(UniSetTimer::WaitUpTime)
{
}
// ------------------------------------------------------------------------------------------
ObjectsManager_LT::~ObjectsManager_LT()
{
}
// ------------------------------------------------------------------------------------------
void ObjectsManager_LT::callback()
{
// При реализации с использованием waitMessage() каждый раз при вызове askTimer() необходимо
// проверять возвращаемое значение на UniSetTimers::WaitUpTime и вызывать termWaiting(),
// чтобы избежать ситуации, когда процесс до заказа таймера 'спал'(в функции waitMessage()) и после
// заказа продолжит спать(т.е. обработчик вызван не будет)...
try
{
if( waitMessage(msg, sleepTime) )
processingMessage(&msg);
sleepTime=lt.checkTimers(this);
}
catch(Exception& ex)
{
unideb[Debug::CRIT] << myname << "(callback): " << ex << endl;
}
}
// ------------------------------------------------------------------------------------------
void ObjectsManager_LT::askTimer( UniSetTypes::TimerId timerid, timeout_t timeMS, short ticks, UniSetTypes::Message::Priority p )
{
// проверяйте возвращаемое значение
if( lt.askTimer(timerid, timeMS, ticks, p) != UniSetTimer::WaitUpTime )
termWaiting();
}
// ------------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include "UniSetObserver.h"
#include "Exceptions.h"
#include "UniversalInterface.h"
// ---------------------------------------------------------------------------
using namespace UniSetTypes;
// ---------------------------------------------------------------------------
UniSetSubject::UniSetSubject()
{
}
UniSetSubject::UniSetSubject(ObjectId id):
id(id)
{
}
UniSetSubject::~UniSetSubject()
{
}
// ---------------------------------------------------------------------------
void UniSetSubject::attach( UniSetObject* o )
{
ObserverList::iterator li = find(lst.begin(),lst.end(),o);
if( li==lst.end() )
lst.push_front(o);
}
// ---------------------------------------------------------------------------
void UniSetSubject::detach( UniSetObject* o )
{
lst.remove(o);
}
// ---------------------------------------------------------------------------
void UniSetSubject::notify(int notify, int data, Message::Priority priority)
{
for( ObserverList::iterator li=lst.begin();li!=lst.end();++li )
{
try
{
UpdateMessage msg(id, notify, data, priority, (*li)->getId());
(*li)->push( msg.transport_msg() );
}
catch(Exception& ex)
{
unideb[Debug::WARN] << ex << endl;
}
}
}
// ------------------------------------------------------------------------------------------
void UniSetSubject::notify( UniSetTypes::TransportMessage& msg )
{
for (ObserverList::iterator li=lst.begin();li!=lst.end();++li)
{
try
{
(*li)->push( msg );
}
catch(Exception& ex)
{
unideb[Debug::WARN] << ex << endl;
}
}
}
// ------------------------------------------------------------------------------------------
void UniSetSubject::attach( UniSetObject* o, int MessageType )
{
}
// ------------------------------------------------------------------------------------------
void UniSetSubject::detach( UniSetObject* o, int MessageType )
{
}
// ------------------------------------------------------------------------------------------
/* 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 файл реализации Info-сервера
* \author Pavel Vainerman
*/
// --------------------------------------------------------------------------
#include <string>
#include <sstream>
#include "Configuration.h"
#include "InfoServer.h"
#include "ISRestorer.h"
#include "UniXML.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// ------------------------------------------------------------------------------------------
InfoServer::InfoServer( ObjectId id, ISRestorer* d ):
UniSetObject(id),
restorer(d),
dbrepeat(true)
{
if( id == DefaultObjectId )
{
id = conf->getInfoServer();
if( id == DefaultObjectId )
{
ostringstream msg;
msg << "(InfoServer): Запуск невозможен! НЕ ЗАДАН ObjectId !!!!!\n";
// unideb[Debug::CRIT] << msg.str() << endl;
throw Exception(msg.str());
}
setID(id);
}
routeList.clear();
UniXML* xml = conf->getConfXML();
if( xml )
{
xmlNode* root = xml->findNode(xml->getFirstNode(),"LocalInfoServer");
if( root )
{
dbrepeat = xml->getIntProp(root,"dbrepeat");
if( !dbrepeat )
unideb[Debug::INFO] << myname << "(init): dbrepeat="<< dbrepeat << endl;
xmlNode* node(xml->findNode(root,"RouteList"));
if(!node)
unideb[Debug::WARN] << myname << ": старый формат конф-файла. Нет раздела RouteList" << endl;
else
{
UniXML_iterator it(node);
if( it.goChildren() )
{
for( ;it.getCurrent(); it.goNext() )
{
string cname(xml->getProp(it,"name"));
ConsumerInfo ci;
ci.id = conf->oind->getIdByName(cname);
if( ci.id == UniSetTypes::DefaultObjectId )
{
unideb[Debug::CRIT] << myname << ": НЕ НАЙДЕН ИДЕНТИФИКАТОР объекта -->" << cname << endl;
continue;
}
ci.node = conf->getLocalNode();
string cnodename(xml->getProp(it,"node"));
if( !cnodename.empty() )
ci.node = conf->oind->getIdByName(cnodename);
if( ci.node == UniSetTypes::DefaultObjectId )
{
unideb[Debug::CRIT] << myname << ": НЕ НАЙДЕН ИДЕНТИФИКАТОР узла -->" << cnodename << endl;
continue;
}
routeList.push_back(ci);
}
}
}
}
}
}
InfoServer::~InfoServer()
{
}
// ------------------------------------------------------------------------------------------
void InfoServer::preprocessing(TransportMessage& tmsg, bool broadcast)
{
// unideb[Debug::INFO] << myname << "... preprocessing... "<< endl;
// Пересылаем на другие узлы
if( broadcast )
{
for ( UniSetTypes::ListOfNode::const_iterator it = conf->listNodesBegin();
it != conf->listNodesEnd(); ++it )
{
if( it->infserver!=UniSetTypes::DefaultObjectId && it->connected && it->id != conf->getLocalNode() )
{
try
{
ui.send(it->infserver, tmsg, it->id);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing): не смог послать сообщение узлу "<< conf->oind->getMapName(it->id)<< endl;
}
}
}
}
// unideb[Debug::INFO] << myname << " пишем в базу... "<< endl;
// Сохраняем в базу
try
{
if( dbrepeat )
ui.send(conf->getDBServer(), tmsg);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing): не смог послать сообщение DBServer-у" << endl;
}
// Пересылаем по routeList-у
for( list<UniSetTypes::ConsumerInfo>::const_iterator it=routeList.begin(); it!=routeList.end(); ++it )
{
try
{
ui.send(it->id, tmsg, it->node);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing):"
<< " не смог послать сообщение объекту "
<< conf->oind->getNameById(it->id,it->node)<< endl;
}
}
}
// ------------------------------------------------------------------------------------------
void InfoServer::preprocessingConfirm(UniSetTypes::ConfirmMessage& am, bool broadcast)
{
// unideb[Debug::INFO] << myname << "... preprocessing... "<< endl;
TransportMessage tmsg(am.transport_msg());
// Пересылаем на другие узлы
if( broadcast )
{
for ( UniSetTypes::ListOfNode::const_iterator it = conf->listNodesBegin();
it != conf->listNodesEnd(); ++it )
{
if( it->infserver!=UniSetTypes::DefaultObjectId && it->connected && it->id != conf->getLocalNode() )
{
try
{
ui.send(it->infserver, tmsg, it->id);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing):"
<< " не смог послать сообщение узлу "
<< conf->oind->getMapName(it->id)<< endl;
}
}
}
}
try
{
if( dbrepeat )
ui.send(conf->getDBServer(), tmsg);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing): не смог послать сообщение DBServer-у" << endl;
}
// Пересылаем по routeList-у
for( list<UniSetTypes::ConsumerInfo>::const_iterator it=routeList.begin(); it!=routeList.end(); ++it )
{
try
{
ui.send(it->id, tmsg, it->node);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(preprocessing):"
<< " не смог послать сообщение объекту "
<< conf->oind->getNameById(it->id,it->node) << endl;
}
}
}
// ------------------------------------------------------------------------------------------
void InfoServer::processingMessage( UniSetTypes::VoidMessage *msg )
{
switch( msg->type )
{
case Message::Info:
{
InfoMessage im(msg);
unideb[Debug::INFO] << myname << " InfoMessage code= "<< im.infocode << endl;
try
{
// если это не пересланное сообщение
// то обрабатываем его
if( !im.route )
{
im.route = true; // выставляем признак пересылки
TransportMessage tm(im.transport_msg());
preprocessing(tm, im.broadcast);
}
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(info preprocessing):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(info preprocessing): catch ..." << endl;
}
// посылаем всем зазкачикам уведомление
try
{
event(im.infocode, im, false);
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(info event):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(info event): catch ..." << endl;
}
try
{
processing(im);
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(info processing):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(info processing) catch ..." << endl;
}
break;
}
case Message::Alarm:
{
AlarmMessage am(msg);
unideb[Debug::INFO] << myname
<< " AlarmMessage code= "<< am.alarmcode
<< " cause="<< am.causecode << endl;
try
{
// если это не пересланное сообщение
// то обрабатываем его
if( !am.route )
{
am.route = true; // выставляем признак пересылки
TransportMessage tm(am.transport_msg());
preprocessing(tm, am.broadcast);
}
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(alarm preprocessing):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(alarm preprocessing): catch ..." << endl;
}
try
{
// посылаем всем зазкачикам уведомление
event(am.alarmcode, am, false);
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(alarm event):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(alarm event): catch ..." << endl;
}
try
{
processing(am);
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(alarm processing):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(alarm processing): catch ..." << endl;
}
break;
}
case Message::Confirm:
{
UniSetTypes::ConfirmMessage cm(msg);
unideb[Debug::INFO] << myname << " ConfirmMessage на сообщение sensor_id= "<< cm.sensor_id << endl;
try
{
// если это не пересланное сообщение
// то обрабатываем его
if( !cm.route )
{
cm.route = true;
preprocessingConfirm(cm, cm.broadcast);
}
}
catch(Exception& ex )
{
unideb[Debug::CRIT] << myname << "(alarm processing):" << ex << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(alarm processing): catch ..." << endl;
}
// посылаем всем зазкачикам уведомление
event(cm.sensor_id, cm, true);
try
{
processing(cm);
}
catch(...){}
break;
}
case Message::SysCommand:
unideb[Debug::INFO] << myname << " system command... "<< endl;
break;
default:
unideb[Debug::CRIT] << myname << ": НЕИЗВЕСТНОЕ СООБЩЕНИЕ"<< endl;
break;
}
}
// ------------------------------------------------------------------------------------------
void InfoServer::ackMessage(UniSetTypes::MessageCode mid, const UniSetTypes::ConsumerInfo& ci,
UniversalIO::UIOCommand cmd, CORBA::Boolean acknotify)
{
unideb[Debug::INFO] << myname << "(askMessage): поступил заказ от "
<< conf->oind->getNameById(ci.id, ci.node)
<< " на сообщение " << mid << endl;
// Проверка на существование
if(!conf->mi->isExist(mid) )
{
unideb[Debug::CRIT] << myname << "(askMessage): сообщения с кодом "
<< mid << " НЕТ в MessagesMap" << endl;
// InfoServer_i::MsgNotFound nf;
// nf.bad_code = mid;
// throw nf;
}
{ // lock
uniset_mutex_lock lock(askMutex, 200);
// а раз есть заносим(исключаем) заказчика
ask( askList, mid, ci, cmd, acknotify);
} // unlock
}
// ------------------------------------------------------------------------------------------
void InfoServer::ackMessageRange(UniSetTypes::MessageCode from, UniSetTypes::MessageCode to,
const UniSetTypes::ConsumerInfo& ci, UniversalIO::UIOCommand cmd,
CORBA::Boolean acknotify)
{
// Проверка корректности диапазона
if( from>to )
throw InfoServer_i::MsgBadRange();
for( UniSetTypes::MessageCode c=from; c<=to; c++ )
ackMessage(c,ci,cmd, acknotify);
}
// ------------------------------------------------------------------------------------------
/*!
* \param lst - указатель на список в который необходимо внести потребителя
* \param name - имя вносимого потребителя
* \note Добавление произойдет только если такого потребителя не существует в списке
*/
bool InfoServer::addConsumer(ConsumerList& lst, const ConsumerInfo& ci, CORBA::Boolean acknotify )
{
for( ConsumerList::const_iterator li=lst.begin();li!=lst.end(); ++li )
{
if( li->id == ci.id && li->node == ci.node )
return false;
}
ConsumerInfoExt cinf(ci);
cinf.ask = acknotify;
// получаем ссылку
try
{
UniSetTypes::ObjectVar op = ui.resolve(ci.id,ci.node);
cinf.ref = UniSetObject_i::_narrow(op);
}
catch(...){}
lst.push_front(cinf);
return true;
}
// ------------------------------------------------------------------------------------------
/*!
* \param lst - указатель на список из которго происходит удаление потребителя
* \param name - имя удаляемого потребителя
*/
bool InfoServer::removeConsumer(ConsumerList& lst, const ConsumerInfo& cons, CORBA::Boolean acknotify )
{
for( ConsumerList::iterator li=lst.begin();li!=lst.end();++li)
{
if( li->id == cons.id && li->node == cons.node )
{
lst.erase(li);
return true;
}
}
return false;
}
// ------------------------------------------------------------------------------------------
void InfoServer::ask(AskMap& askLst, UniSetTypes::MessageCode key,
const UniSetTypes::ConsumerInfo& cons,
UniversalIO::UIOCommand cmd,
CORBA::Boolean acknotify)
{
// поиск датчика в списке
AskMap::iterator askIterator = askLst.find(key);
switch( cmd )
{
case UniversalIO::UIONotify: // заказ
{
if( askIterator==askLst.end() )
{
ConsumerList lst; // создаем новый список
addConsumer(lst,cons, acknotify);
askLst.insert(AskMap::value_type(key,lst)); // более оптимальный способ(при условии вставки первый раз)
try
{
dumpOrdersList(key,lst);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << myname << " не смогли сделать dump: " << ex << endl;
}
catch(...)
{
unideb[Debug::WARN] << myname << " не смогли сделать dump" << endl;
}
}
else
{
if( addConsumer(askIterator->second,cons, acknotify) )
{
try
{
dumpOrdersList(key,askIterator->second);
}
catch(...)
{
unideb[Debug::WARN] << myname << " не смогли сделать dump" << endl;
}
}
}
break;
}
case UniversalIO::UIODontNotify: // отказ
{
if( askIterator!=askLst.end() ) // существует
{
if( removeConsumer(askIterator->second, cons, acknotify) )
{
if( askIterator->second.empty() )
askLst.erase(askIterator);
else
{
try
{
dumpOrdersList(key,askIterator->second);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << myname << " не смогли сделать dump: " << ex << endl;
}
catch(...)
{
unideb[Debug::WARN] << myname << " не смогли сделать dump" << endl;
}
}
}
}
break;
}
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void InfoServer::dumpOrdersList(UniSetTypes::MessageCode mid, const ConsumerList& lst)
{
try
{
if(restorer)
restorer->dump(this,mid,lst);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << myname << "(dumpOrdersList): " << ex << endl;
}
}
// ------------------------------------------------------------------------------------------
bool InfoServer::activateObject()
{
UniSetObject::activateObject();
readDump();
return true;
}
// ------------------------------------------------------------------------------------------
void InfoServer::readDump()
{
try
{
if( restorer )
restorer->read(this);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << myname << "(readDump): " << ex << endl;
}
}
// ------------------------------------------------------------------------------------------
/*!
\warning В случае зависания в функции push, будет остановлена рассылка другим объектам.
*/
template<class TMessage>
void InfoServer::send(ConsumerList& lst, TMessage& msg, CORBA::Boolean askn)
{
for( ConsumerList::iterator li=lst.begin();li!=lst.end();++li )
{
// пропускаем всех кто не хочет знать о подтверждении
if( askn && !li->ask )
continue;
for(int i=0; i<2; i++ ) // на каждый объект по две поптыки
{
try
{
if( CORBA::is_nil(li->ref) )
{
CORBA::Object_var op = ui.resolve(li->id, li->node);
li->ref = UniSetObject_i::_narrow(op);
}
msg.consumer = li->id;
li->ref->push( msg.transport_msg() );
// unideb[Debug::INFO] << myname << "(send): посылаем "<< conf->oind->getMapName( li->node ) << "/" << ui.getNameById( li->id ) << " notify" << endl;
break;
}
catch(Exception& ex)
{
unideb[Debug::CRIT] << myname << "(send): " << ex << endl;
}
catch( CORBA::SystemException& ex )
{
unideb[Debug::CRIT] << myname << "(send): "
<< conf->oind->getNameById( li->id )
<< " недоступен!! " << ex.NP_minorString() << endl;
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(send): "
<< conf->oind->getNameById( li->id )
<< " недоступен!!(...)" << endl;
}
// li->ref = 0;
li->ref=UniSetObject_i::_nil();
}
}
}
// ------------------------------------------------------------------------------------------
template <class TMessage>
void InfoServer::event(UniSetTypes::MessageCode key, TMessage& msg, CORBA::Boolean askn)
{
{ // lock
uniset_mutex_lock lock(askMutex, 1000);
// поcылка сообщения об изменении всем потребителям
AskMap::iterator it = askList.find(key);
if( it!=askList.end() )
send(it->second, msg,askn);
} // unlock
}
// ------------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include "Exceptions.h"
#include "RepositoryAgent.h"
// ------------------------------------------------------------------------------------------
using namespace UniSetTypes;
extern const ObjectInfo *pObjectsMap;
// ------------------------------------------------------------------------------------------
RepositoryAgent::RepositoryAgent():
oind(pObjectsMap)
{
}
RepositoryAgent::~RepositoryAgent()
{
}
/*
RepositoryAgent::RepositoryAgent(const string name, const string section, int* argc, char* **argv):
BaseProcess_i(name, section, argc, argv)
{
}
RepositoryAgent::RepositoryAgent( ObjectId id, int* argc, char* **argv):
BaseProcess_i( id, argc, argv)
{
}
*/
RepositoryAgent::RepositoryAgent( ObjectId id, const ObjectInfo *pObjMap):
BaseProcess(id),
oind(pObjMap)
{
// cout << ui.getNameById(id) << endl;
}
// ------------------------------------------------------------------------------------------
/*
void RepositoryAgent::registration(const char* name, ::CORBA::Object_ptr ref)
{
}
// ------------------------------------------------------------------------------------------
void RepositoryAgent::unregistration(const char* name, ::CORBA::Object_ptr ref)
{
}
*/
// ------------------------------------------------------------------------------------------
CORBA::Object_ptr RepositoryAgent::resolve(const char* name)
{
cout << "resolve: " << name << endl;
CORBA::Object_ptr ref;
try
{
ref= ui.resolve(name);
}
catch(NameNotFound)
{
throw RepositoryAgent_i::NameNotFound();
}
catch(ORepFailed)
{
throw RepositoryAgent_i::ResolveError();
}
return CORBA::Object::_duplicate(ref);
}
// ------------------------------------------------------------------------------------------
CORBA::Object_ptr RepositoryAgent::resolveid(BaseObjectId id)
{
cout << "resolveid: " << ui.getNameById(id) << endl;
CORBA::Object_ptr ref;
try
{
ref= ui.resolve(id);
}
catch(NameNotFound)
{
throw RepositoryAgent_i::NameNotFound();
}
catch(ORepFailed)
{
throw RepositoryAgent_i::ResolveError();
}
return CORBA::Object::_duplicate(ref);
}
// ------------------------------------------------------------------------------------------
void RepositoryAgent::execute()
{
while(active)// for(;;)
{
if ( waitMessage(&msg) )
{
/*
switch(msg.type)
{
case MessageType::Command:
{
cout << BaseProcess_i::myname << ": msg id ="<< msg.id << endl;
break;
}
default:
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
*/
// --------------------------------------------------------------------------
#include <unistd.h>
#include <sstream>
#include <algorithm>
#include "TimerService.h"
#include "Debug.h"
#include "UniXML.h"
// ------------------------------------------------------------------------------------------
using namespace UniversalIO;
using namespace UniSetTypes;
using namespace std;
// ------------------------------------------------------------------------------------------
TimerService::TimerService(const string confNodeName):
MaxCountTimers(100),
AskLifeTimeSEC(60),
terminate(false),
isSleep(true),
sleepTimer(new ThrPassiveTimer())
{
init(confNodeName);
}
TimerService::TimerService( ObjectId id, const string confNodeName ):
UniSetObject(id),
MaxCountTimers(100),
AskLifeTimeSEC(60),
terminate(false),
isSleep(true),
sleepTimer(new ThrPassiveTimer())
{
init(confNodeName);
}
TimerService::~TimerService()
{
if(!terminate)
sleepTimer->terminate();
if( exthread )
delete exthread;
delete sleepTimer;
}
// ------------------------------------------------------------------------------------------
/*
* \param ti.timerid - идентификатор заказываемого таймера
* \param ti.timeMS - интервал (0 - означает отказ от таймера)
* \param ci.fromId - идентификатор заказчика
* \param ci.node - узел, на котором находится заказчик
* \exception TimerService_i::TimerAlreadyExist - вырабатывается если от данного заказчика
* \b уже \b есть заказ на таймер с таким идентификатором
*/
void TimerService::askTimer( const TimerService_i::Timer& ti, const UniSetTypes::ConsumerInfo& ci )
{
if( ti.timeMS > 0 ) // заказ
{
if( tlst.size() >= MaxCountTimers )
{
TimerService_i::LimitTimers ex;
ex.maxTimers = MaxCountTimers;
throw ex;
}
if( ti.timeMS < UniSetTimer::MinQuantityTime )
{
TimerService_i::TimeMSLowLimit ex;
ex.lowLimitMS = UniSetTimer::MinQuantityTime;
throw ex;
}
// unideb[Debug::INFO] << "size: "<< tlst.size() << endl;
{ // lock
if( !lstMutex.isRelease() )
unideb[Debug::INFO] << myname << ": придется подождать освобождения lstMutex-а" << endl;
uniset_mutex_lock lock(lstMutex, 2000);
// поищем а может уж такой есть
if( !tlst.empty() )
{
for( TimersList::iterator li=tlst.begin(); li!=tlst.end(); ++li )
{
if ( li->cinf.id == ci.id && li->cinf.node == ci.node && li->id == ti.timerid )
{
li->curTick = ti.ticks;
li->tmr.setTiming(ti.timeMS);
li->not_ping = false;
li->lifetmr.reset();
unideb[Debug::INFO] << myname << ": заказ на таймер(id="<< ti.timerid << ") "
<< ti.timeMS << " [мс] от " << ui.getNameById(ci.id)
<< " уже есть... " << endl;
throw TimerService_i::TimerAlreadyExist();
}
}
}
TimerInfo newti(ti.timerid, ti.timeMS, ci, ti.ticks, AskLifeTimeSEC, (Message::Priority)ti.msgPriority);
try
{
UniSetTypes::ObjectVar op = ui.resolve(ci.id,ci.node);
newti.ref = UniSetObject_i::_narrow(op);
}
catch(...){}
tlst.push_back(newti);
tlst.sort();
newti.reset();
} // unlock
unideb[Debug::INFO] << myname << "(askTimer): поступил заказ на таймер(id="
<< ti.timerid << ") " << ti.timeMS
<< " [мс] от " << ui.getNameById(ci.id,ci.node) << endl;
}
else // отказ
{
unideb[Debug::INFO] << myname << ": поступил отказ от "
<< ui.getNameById(ci.id,ci.node)
<< " по таймеру id="<< ti.timerid << endl;
{ // lock
if( !lstMutex.isRelease() )
unideb[Debug::INFO] << myname << ": придется подождать освобождения lstMutex-а" << endl;
uniset_mutex_lock lock(lstMutex, 2000);
tlst.remove_if(Timer_eq(ci,ti.timerid)); // STL - способ
tlst.sort();
} // unlock
}
if( tlst.empty() )
isSleep = true;
else
{
isSleep = false;
sleepTimer->terminate();
}
}
// ------------------------------------------------------------------------------------------
bool TimerService::send( TimerInfo& ti )
{
TransportMessage tm = TimerMessage(ti.id, ti.priority, ti.cinf.id).transport_msg();
for(int i=0; i<2; i++ ) // на каждый объект по две поптыки
{
try
{
if( CORBA::is_nil(ti.ref) )
{
UniSetTypes::ObjectVar op = ui.resolve(ti.cinf.id, ti.cinf.node);
ti.ref = UniSetObject_i::_narrow(op);
}
ti.ref->push(tm);
return true;
}
catch(...){}
// unideb[Debug::WARN] << ui.getNameById( ti.cinf.id, ti.cinf.node ) << " недоступен!!" << endl;
ti.ref=UniSetObject_i::_nil();
}
return false;
}
// ------------------------------------------------------------------------------------------
// Без повторной сортировки
void TimerService::work()
{
execute_pid = getpid();
bool resort = false;
terminate = false;
// TimerInfo* ti;
while(!terminate)
{
timeout_t sleepTime = UniSetTimer::MinQuantityTime; // мс
{ // lock
uniset_mutex_lock lock(lstMutex, 5000);
resort = false;
sleepTime = UniSetTimer::WaitUpTime;
for( TimersList::iterator li=tlst.begin();li!=tlst.end();++li)
{
if( li->tmr.checkTime() )
{
if( !send(*li) )
{
if( !li->not_ping )
{
unideb[Debug::WARN] << myname << ": не смогли послать сообщение "<< ui.getNameById(li->cinf.id,li->cinf.node) << endl;
if( !AskLifeTimeSEC )
{
unideb[Debug::WARN] << myname << ": удаляем из списка "<< ui.getNameById(li->cinf.id,li->cinf.node) << endl;
li = tlst.erase(li);
if( tlst.empty() )
isSleep = true;
continue;
}
li->not_ping = true;
li->lifetmr.reset();
li->reset();
}
else if( li->lifetmr.checkTime() )
{
unideb[Debug::WARN] << myname << ": удаляем из списка "<< ui.getNameById(li->cinf.id,li->cinf.node) << endl;
li = tlst.erase(li);
if( tlst.empty() )
isSleep = true;
continue;
}
}
else
{
li->not_ping = true;
// Проверка на количество заданных тактов
if( !li->curTick )
{
li = tlst.erase(li);
if( tlst.empty() )
isSleep = true;
continue;
}
else if(li->curTick>0 )
li->curTick--;
}
li->reset();
resort = true;
}
else
{
if( li->curTimeMS < sleepTime)
li->curTimeMS = 0;
else
li->curTimeMS -= sleepTime;
}
if( li->curTimeMS < sleepTime || sleepTime == UniSetTimer::WaitUpTime )
sleepTime = li->curTimeMS;
}
/*! \warning и не оптимально, пересортировывать каждый раз весь список
* \todo потом можно написать самому более оптимальное решение
* т.к. список и так отсортирован, нужно всего лишь перемещать элемент
* в нужное место (у кого больше curTimeMS). Лучше поискать что-нибудь в
* stl...
*/
if( resort ) // пересортировываем в связи с обновлением списка
tlst.sort();
if( sleepTime < UniSetTimer::MinQuantityTime )
sleepTime=UniSetTimer::MinQuantityTime;
} // unlock
if( isSleep )
{
unideb[Debug::INFO] << myname << "(execute): нет активных таймеров... спим..." << endl;
sleepTimer->wait(UniSetTimer::WaitUpTime);
}
else if( sleepTime )
sleepTimer->wait(sleepTime); // msleep(sleepTime);
}
unideb[Debug::INFO] << myname << "(excecute): работу закончил..." << endl << flush;
terminate = true;
}
// ------------------------------------------------------------------------------------------
bool TimerService::activateObject()
{
if( !UniSetObject::activateObject() )
return false;
exthread = new ThreadCreator<TimerService>(this, &TimerService::work);
exthread->start();
return true;
}
// ------------------------------------------------------------------------------------------
bool TimerService::disactivateObject()
{
unideb[Debug::INFO] << myname << ": disactivate..." << endl;
if( !terminate )
{
terminate = true;
sleepTimer->terminate();
}
unideb[Debug::INFO] << myname << ": disactivate ok." << endl;
return true;
}
// ------------------------------------------------------------------------------------------
void TimerService::sigterm( int signo )
{
unideb[Debug::INFO] << myname << "(sigterm): sigterm..." << endl;
terminate = true;
sleepTimer->terminate();
unideb[Debug::INFO] << myname << "(sigterm): ok.." << endl;
msleep(100);
}
// ------------------------------------------------------------------------------------------
/*
void TimerService::insert(TimerInfo& ti)
{
for ( TimersList::iterator li=tlst.begin();li!=tlst.end();++li)
{
// if( (*li)->curTimeMS > ti.curTimeMS )
if( (*li)->tmr.getInterval() > ti.tmr.getInterval() )
{
// вставляем между(перед ним) и выходим
tlst.insert(li, ti);
return;
}
}
tlst.push_back(ti);
}
*/
// ------------------------------------------------------------------------------------------
void TimerService::printList()
{
for ( TimersList::iterator li=tlst.begin();li!=tlst.end();++li)
cout << li->curTimeMS << endl;
}
// ------------------------------------------------------------------------------------------
void TimerService::init(const string& confnode)
{
// инициализация из conf-файла
xmlNode* node = conf->getNode(confnode);
if(!node)
{
unideb[Debug::WARN] << myname << "(init): Не найден конфигурационный раздел " << confnode << endl;
unideb[Debug::WARN] << myname << "(init): инициализируемся по умолчанию "
<< "MaxCountTimers=" << MaxCountTimers
<< " AskLifeTimeSEC=" << AskLifeTimeSEC << endl;
return;
}
MaxCountTimers = conf->getIntProp(node,"MaxCountTimers");
AskLifeTimeSEC = conf->getIntProp(node,"AskLifeTimeSEC");
assert( TimerService::MaxCountTimers > 0 );
assert( TimerService::AskLifeTimeSEC >= 0 );
}
// ------------------------------------------------------------------------------------------
############################################################################
# This file is part of the UniSet library #
############################################################################
noinst_LTLIBRARIES = libThreads.la
libThreads_la_SOURCES=PosixThread.cc
include $(top_builddir)/conf/setting.mk
/* This file is part of the UniSet project
* Copyright (c) 2002 Free Software Foundation, Inc.
* Copyright (c) 2002 Anton Korbin <ahtoh>
*
* 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 Anthony Korbin
*/
// --------------------------------------------------------------------------
#include "PosixThread.h"
#include <iostream>
using namespace std;
int PosixThread::countThreads = 1;
pthread_rwlock_t PosixThread::lockx = PTHREAD_RWLOCK_INITIALIZER;
pthread_mutex_t PosixThread::mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t PosixThread::condx = PTHREAD_COND_INITIALIZER;
//----------------------------------------------------------------------------------------
PosixThread::PosixThread():
tid(0),
attrPtr(NULL)
{
}
//----------------------------------------------------------------------------------------
PosixThread::~PosixThread()
{
countThreads--;
delete attrPtr;
// pthread_exit( NULL );
}
//----------------------------------------------------------------------------------------
void PosixThread::start( void *args )
{
if( tid )
{
cerr << "startThread: You don't RECREATE thread!" << endl;
return;
}
reinit();
// cout << "Создаю поток..."<< endl;
if( pthread_create( &tid, attrPtr, PosixThread::funcp, args ) == -1 )
{/*throw ThreadNotCreate;*/}
else
{
countThreads++;
pthread_attr_destroy( attrPtr );
}
// cout << "создал поток..."<< endl;
}
//----------------------------------------------------------------------------------------
void PosixThread::stop()
{
unlock();
rwunlock();
tid = 0;
countThreads--;
pthread_exit( NULL );
// cout << "PosixThread: завершил поток"<< endl;
// tid = 0;
// countThreads--;
}
//----------------------------------------------------------------------------------------
void PosixThread::reinit()
{
if (attrPtr != NULL)
delete attrPtr;
attrPtr = new pthread_attr_t;
if( pthread_attr_init( attrPtr ) == -1 )
{/*throw AttrNotInit;*/cerr << "PosixThread(reinit): не удалось..."<< endl;}
}
//----------------------------------------------------------------------------------------
void PosixThread::thrkill( int signo )
{
pthread_kill( tid, signo );
}
//----------------------------------------------------------------------------------------
void PosixThread::setAttr( TAttr attr, int state )
{
switch( attr )
{
case SCOPE:
{
if( state == PTHREAD_SCOPE_SYSTEM )
pthread_attr_setscope( attrPtr, PTHREAD_SCOPE_SYSTEM );
else
pthread_attr_setscope( attrPtr, PTHREAD_SCOPE_PROCESS );
break;
}
case DETACH:
{
if( state == PTHREAD_CREATE_DETACHED )
pthread_attr_setdetachstate( attrPtr, PTHREAD_CREATE_DETACHED );
else
pthread_attr_setdetachstate( attrPtr, PTHREAD_CREATE_JOINABLE );
break;
}
case PRIORITY:
{
struct sched_param sched;
sched.sched_priority = state;
pthread_attr_setschedparam( attrPtr, &sched );
break;
}
default:
{
cerr << "Attr not change. See parameters setAtr(...)" << endl;
}
}
}
//----------------------------------------------------------------------------------------
void PosixThread::setPriority( int priority )
{
setAttr( PosixThread::PRIORITY, priority );
}
//----------------------------------------------------------------------------------------
void* PosixThread::funcp( void *args )
{
PosixThread *pt;
pt = (PosixThread*)args;
pt->work();
pthread_exit(NULL); //???
return 0;
}
//----------------------------------------------------------------------------------------
void PosixThread::readlock( pthread_rwlock_t *lock )
{
pthread_rwlock_rdlock( lock );
}
//----------------------------------------------------------------------------------------
void PosixThread::writelock( pthread_rwlock_t *lock )
{
pthread_rwlock_wrlock( lock );
}
//----------------------------------------------------------------------------------------
void PosixThread::lock( pthread_mutex_t *mute )
{
pthread_mutex_lock( mute );
}
//----------------------------------------------------------------------------------------
void PosixThread::rwunlock( pthread_rwlock_t *lock )
{
pthread_rwlock_unlock( lock );
}
//----------------------------------------------------------------------------------------
void PosixThread::unlock( pthread_mutex_t *mute )
{
pthread_mutex_unlock( mute );
}
//----------------------------------------------------------------------------------------
void PosixThread::wait( pthread_cond_t *cond, pthread_mutex_t *mute )
{
pthread_cond_wait( cond, mute );
}
//----------------------------------------------------------------------------------------
void PosixThread::continueRun( pthread_cond_t *cond )
{
pthread_cond_signal( cond );
}
//----------------------------------------------------------------------------------------
void PosixThread::continueRunAll( pthread_cond_t *cond )
{
pthread_cond_broadcast( cond );
}
//----------------------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2009 Free Software Foundation, Inc.
* Copyright (c) 2009 Ivan Donchevskiy
*
* 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 Ivan Donchevskiy
*/
// --------------------------------------------------------------------------
/*! Функции класса CycleStorage, циклически переписываемого журнала,
перезаписываются самые старые элемениты при полном заполнении журнала
*/
#include "Storages.h"
CycleStorage::CycleStorage()
{
file=NULL;
}
CycleStorage::CycleStorage(const char* name, int byte_sz, int inf_sz, int inf_count, int seek, bool cr):
file(NULL)
{
if(!open(name, byte_sz, inf_sz, inf_count, seek))
{
if(cr)
create(name, byte_sz, inf_sz, inf_count, seek);
}
}
CycleStorage::~CycleStorage()
{
if( file!=NULL ) fclose(file);
}
void* CycleStorage::valPointer(void* pnt)
{
return (char*)pnt+sizeof(CycleStorageElem);
}
void CycleStorage::filewrite(CycleStorageElem* jrn,int seek,bool needflush)
{
fseek(file,seekpos+seek*full_size,0);
fwrite(jrn,full_size,1,file);
if(needflush)
fflush(file);
}
/*! Ищем голову и хвост по значениям jrn->status: 0 - пусто, 1 - гоова, 2,4 - два типа существующих элементов
(или 2 слева от головы - 4 справа, или наоборот), 3 - удаленный 2, 5 - удаленный 4, 6 - удаленный 1.
Для нахождения головы|хвоста используется двоичный поиск
*/
bool CycleStorage::findHead()
{
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
int l=-1,r=size,mid;
iter=0;
fread(jrn,full_size,1,file);
if(jrn->status==0)
{
head=-1;
tail=-1;
}
else if((jrn->status==1)||(jrn->status==6))
{
/*! Если первый элемент - голова списка */
head=0;
/*! В этом случае журнал может быть е полностью заполнен, поэтому хвост нужно искать */
while( (r-l)>1 )
{
mid = (l+r)/2;
fseek(file,seekpos+mid*full_size,0);
fread(jrn,full_size,1,file);
iter++;
if( jrn->status==0 )
r = mid;
else
l = mid;
}
tail = (r<size) ? (r-1) : (size-1);
}
else
{
int i,j;
/*! i равно или 2-ум, или 4-ем, в зависимости от этого слева головы списка 2-ки, а справа 4-ки
или наоборот */
i=jrn->status-jrn->status%2;
j = (i==2) ? 4 : 2;
while((jrn->status!=1)&&(jrn->status!=6)&&(r - l > 1))
{
mid = (l+r)/2;
fseek(file,seekpos+mid*full_size,0);
fread(jrn,full_size,1,file);
iter++;
if((jrn->status==i)||(jrn->status==i+1))
l = mid;
else if((jrn->status==j)||(jrn->status==j+1))
r = mid;
else if((jrn->status==1)||(jrn->status==6))
{
r=mid;
break;
}
else
{
delete[] jrn;
return false;
}
}
head = (r<size) ? r : (size-1);
/*! хвост списка на 1 левее головы, т.к. если голова не в начале, то журнал весь заполнен */
tail=head-1;
if(tail<0) tail=size-1;
}
delete[] jrn;
return true;
}
/*! Использовать для проверки совпадения заголовков */
bool CycleStorage::checkAttr(int inf_sz, int inf_count, int seek)
{
if( file==NULL ) return false;
if( fseek(file,seek,0)==-1 )
{
fclose(file);
file=NULL;
return false;
}
/*! Читаем заголовок */
CycleStorageAttr csa;
fread(&csa, sizeof(csa), 1, file);
/*! Проверяем заголовок на совпадение с нашими значениями */
if( ( csa.size!=inf_count ) || ( csa.inf_size!=inf_sz ) || ( csa.seekpos!=seek ) )
{
fclose(file);
file=NULL;
return false;
}
return true;
}
bool CycleStorage::open(const char* name, int byte_sz, int inf_sz, int inf_count, int seek)
{
/*! Если уже был открыт файл в переменной данного класса, он закрывается и открывается новый
*/
if( file!=NULL )
fclose(file);
file = fopen(name, "r+");
if( file==NULL ) return false;
if( fseek(file,seek,0)==-1 )
{
fclose(file);
file=NULL;
return false;
}
if( !checkAttr(inf_sz, inf_count, seek) )
return false;
inf_size=inf_sz;
full_size=sizeof(CycleStorageElem)+inf_size;
size=inf_count;
seekpos=seek+sizeof(CycleStorageAttr);
if( ( byte_sz<getByteSize() ) || !findHead() )
{
fclose(file);
file = NULL;
return false;
}
return true;
}
bool CycleStorage::create(const char* name, int byte_sz, int inf_sz, int inf_count, int seek)
{
if(file!=NULL) fclose(file);
file = fopen(name, "r+");
inf_size=inf_sz;
full_size=sizeof(CycleStorageElem)+inf_size;
size=inf_count;
iter=0;
seekpos=seek;
if( byte_sz<getByteSize() )
{
if( file!= NULL )
fclose(file);
file = NULL;
return false;
}
/*! Создаем файл, если его нет */
if(file==NULL)
{
FILE *f=fopen(name,"w");
if( f==NULL ) return false;
fclose(f);
file = fopen(name, "r+");
}
if( file==NULL ) return false;
if(fseek(file,seekpos,0)==-1) return false;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
for( int i=0; i<full_size; i++ )
*((char*)jrn+i) = 0;
jrn->status=0;
/*! Записываем заголовок журнала */
CycleStorageAttr csa;
csa.inf_size=inf_size;
csa.size=size;
csa.seekpos=seekpos;
fwrite(&csa,sizeof(CycleStorageAttr),1,file);
fflush(file);
seekpos+=sizeof(CycleStorageAttr);
/*! Создаем журнал нужного размера */
for(int i=0;i<size;i++)
{
filewrite(jrn,i,false);
}
fflush(file);
head=tail=-1;
delete[] jrn;
return true;
}
bool CycleStorage::addRow(void* str)
{
if(file==NULL) return false;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
int i=0;
for( i=0; i<full_size; i++ )
*((char*)jrn+i) = 0;
/*! Первые 2 случая - список пуст (head=-1), в списке 1 элемент(head=tail=0) рассматриваю отдельно)
*/
memcpy(valPointer(jrn),str,inf_size);
if(head==-1)
{
jrn->status=1;
filewrite(jrn,0);
head=0;
tail=0;
delete[] jrn;
return true;
}
if(head==tail)
{
jrn->status=2;
filewrite(jrn,1);
tail=1;
delete[] jrn;
return true;
}
fseek(file,seekpos+tail*full_size,0);
fread(jrn,full_size,1,file);
/*! Статус элемента совпадает со статусом последнего элемента в журнале 2, 3 -> 2; 4, 5 -> 4
*/
i = ((jrn->status==2)||(jrn->status==3)) ? 2 : 4;
/*! Если последний элемент журнала в крайней правой позиции выделенной части файла,
переходим в начало части файла и инвертируем статус 2->4, 4->2
*/
if(tail==size-1)
{
fseek(file,seekpos,0);
tail=0;
i = (i==2) ? 4 : 2;
}
else tail++;
fread(jrn,full_size,1,file);
memcpy(valPointer(jrn),str,inf_size);
if(jrn->status==0)
{
jrn->status=2;
filewrite(jrn,tail);
}
else
{
/*! Переписываем головной элемент новым, а второй от начала делаем головным,
т. е. сдвигаем голову на 1 элемент вперед
*/
head++;
if(head>=size) head=0;
jrn->status=i;
filewrite(jrn,tail);
fseek(file,seekpos+head*full_size,0);
fread(jrn,full_size,1,file);
if((jrn->status==3)||(jrn->status==5)) jrn->status=6;
else jrn->status=1;
filewrite(jrn,head);
}
delete[] jrn;
return true;
}
bool CycleStorage::delRow(int row)
{
int i=(head+row)%size,j;
if( row >= size ) return false;
if(file==NULL) return false;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
fseek(file,seekpos+i*full_size,0);
fread(jrn,full_size,1,file);
/*! При удалении меняем стутус 1->6, 2->3, 4->5 или возвращаем false
*/
if(jrn->status==1)
{
jrn->status=6;
filewrite(jrn,i);
delete[] jrn;
return true;
}
if(jrn->status==2) j=3;
else if(jrn->status==4) j=5;
else
{
delete[] jrn;
return false;
}
jrn->status=j;
filewrite(jrn,i);
delete[] jrn;
return true;
}
bool CycleStorage::delAllRows()
{
/*! Переписываем статусы всех элементов нулями */
if(file==NULL) return false;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
int i;
fseek(file,seekpos,0);
for(i=0;i<size;i++)
{
fread(jrn,full_size,1,file);
if(jrn->status!=0)
{
jrn->status=0;
filewrite(jrn,i,false);
}
}
fflush(file);
head=tail=-1;
delete[] jrn;
return true;
}
/*! TODO: можно убрать из параметров str, просто возвращать значение */
void* CycleStorage::readRow(int num, void* str)
{
if( size <= 0 ) return NULL;
/*! Отсчитываем номер элемента от головы журнала */
int j=(head+num)%size;
if((file==NULL)||(num>=size)) return NULL;
if((head!=tail+1)&&(num>tail)&&(head!=tail)) return NULL;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
fseek(file,seekpos+j*full_size,0);
fread(jrn,full_size,1,file);
if((jrn->status==1)||(jrn->status==2)||(jrn->status==4))
{
memcpy(str,valPointer(jrn),inf_size);
delete[] jrn;
return str;
}
delete[] jrn;
return NULL;
}
int CycleStorage::getIter()
{
return iter;
}
/*! Функция для изменения размера журнала. Удаляет все записи, если новый размер меньше. Заполняет новое место
записями, аналогичными удаленным, если новый размер больше. Вызывать лучше не часто, т. к. переписывается заголовок
журнала, расположенный статически в одном месте */
bool CycleStorage::setSize(int count)
{
if( file==NULL ) return false;
if( count==size ) return true;
fseek(file,seekpos-sizeof(CycleStorageAttr),0);
/*! Записываем заголовок журнала */
CycleStorageAttr csa;
csa.inf_size=inf_size;
csa.size=count;
csa.seekpos=seekpos-sizeof(CycleStorageAttr);
fwrite(&csa,sizeof(CycleStorageAttr),1,file);
fflush(file);
if(count<size)
{
if( head>count-1 )
{
head = 0;
tail = count - 1;
}
if( tail>count-1 )
tail = count - 1;
size=count;
return true;
}
int num = count - size;
size = count;
CycleStorageElem *jrn = (CycleStorageElem*)new char[full_size];
if(( head==tail+1 ) || (( tail==size-num-1 ) && ( head==0 )))
{
if( head<size-num-1 )
fseek(file, seekpos + (size-num-1)*full_size, 0);
else
fseek(file, seekpos, 0);
fread(jrn, full_size, 1, file);
if(( jrn->status==2 ) || (jrn->status==3 ))
jrn->status = ( head<size-num-1 ) ? 3 : 5;
else if(( jrn->status==4 ) || (jrn->status==5 ))
jrn->status = ( head<size-num-1 ) ? 5 : 3;
else
{
delete[] jrn;
return false;
}
for( int i=num; i>0; i-- )
{
filewrite(jrn, size-i, false);
}
fflush(file);
if( head==0 )
tail = size-1;
}
else
{
jrn->status=0;
for( int i=num; i>0; i-- )
filewrite(jrn, size-i, false);
fflush(file);
}
delete[] jrn;
return true;
}
/*! Некоторые операции для итератора */
CycleStorage::iterator& CycleStorage::iterator::operator++()
{
current++;
if( current>=cs->getSize() )
{
str = NULL;
current = cs->getSize();
return *this;
}
cs->readRow(current,str);
return *this;
}
CycleStorage::iterator CycleStorage::iterator::operator++(int)
{
Self temp = *this;
temp.current++;
if(temp.current>=temp.cs->getSize())
{
temp.str = NULL;
temp.current = temp.cs->getSize();
return temp;
}
temp.cs->readRow(current,str);
return temp;
}
CycleStorage::iterator& CycleStorage::iterator::operator--()
{
current--;
if(current<=0)
{
str = NULL;
current = -1;;
return *this;
}
cs->readRow(current,str);
return *this;
}
CycleStorage::iterator CycleStorage::iterator::operator--(int)
{
Self temp = *this;
temp.current--;
if(temp.current<=0)
{
temp.str = NULL;
temp.current = -1;
return temp;
}
temp.cs->readRow(current,str);
return temp;
}
\ No newline at end of file
/* 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
*/
// --------------------------------------------------------------------------
#include <sstream>
#include <fstream>
#include "Debug.h"
#include "Configuration.h"
#include "ISRestorer.h"
#include "Exceptions.h"
// ------------------------------------------------------------------------------------------
using namespace std;
using namespace UniversalIO;
using namespace UniSetTypes;
// ------------------------------------------------------------------------------------------
ISRestorer::ISRestorer()
{
}
ISRestorer::~ISRestorer()
{
}
// ------------------------------------------------------------------------------------------
void ISRestorer::addlist( InfoServer* is, const UniSetTypes::MessageCode code,
InfoServer::ConsumerList& lst )
{
is->askList[code]=lst;
}
// ------------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include <sstream>
#include <fstream>
#include "Debug.h"
#include "Configuration.h"
#include "ISRestorer.h"
#include "Exceptions.h"
#include "ORepHelpers.h"
// ------------------------------------------------------------------------------------------
using namespace std;
using namespace UniversalIO;
using namespace UniSetTypes;
// ------------------------------------------------------------------------------------------
ISRestorer_XML::ISRestorer_XML(string fname):
fname(fname)
{
init(fname);
}
// ------------------------------------------------------------------------------------------
ISRestorer_XML::~ISRestorer_XML()
{
}
// ------------------------------------------------------------------------------------------
void ISRestorer_XML::init( std::string fname )
{
/*!
\warning Файл открывается только при создании...
Т.е. не будут учтены изменения в промежутке между записью(dump-а) файла
*/
try
{
uxml.open(fname);
}
catch (...){}
}
// ------------------------------------------------------------------------------------------
void ISRestorer_XML::dump( InfoServer* is, const UniSetTypes::MessageCode code,
const InfoServer::ConsumerList& lst )
{
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << "ISRestorer_XML::dump NOT SUPPORT!!!!" << endl;
}
// ------------------------------------------------------------------------------------------
void ISRestorer_XML::read( InfoServer* is, const string fn )
{
UniXML* confxml = conf->getConfXML();
if( !fn.empty() )
{
// оптимизация (не загружаем второй раз xml-файл)
if( fn == conf->getConfFileName() && confxml )
read( is, *confxml );
else
{
UniXML xml(fn);
read(is,xml);
xml.close();
}
}
else
{
// оптимизация (не загружаем второй раз xml-файл)
if( fname == conf->getConfFileName() && confxml )
read( is, *confxml );
else
{
uxml.close();
uxml.open(fname);
read(is,uxml);
}
}
}
// ------------------------------------------------------------------------------------------
void ISRestorer_XML::read( InfoServer* is, UniXML& xml )
{
xmlNode* node = find_node(xml, xml.getFirstNode(),"messages");
if( node )
read_list(xml, node, is);
}
// ------------------------------------------------------------------------------------------
void ISRestorer_XML::read_list(UniXML& xml, xmlNode* node, InfoServer* is )
{
UniXML_iterator it(node);
bool autoID=it.getIntProp("autoID");
if( !it.goChildren() )
return;
for( ;it.getCurrent(); it.goNext() )
{
if( !check_list_item(it) )
continue;
MessageCode code;
if( !autoID )
code = conf->mi->getCodeByIdName(it.getProp("name"));
else
{
code = xml.getIntProp(it,"id");
}
if( code == UniSetTypes::DefaultMessageCode )
{
unideb[Debug::WARN] << "(read_list): не смог получить message code для "
<< it.getProp("name") << endl;
continue;
}
UniXML_iterator itc(it.getCurrent());
if( !itc.goChildren() )
continue;
InfoServer::ConsumerList lst;
for(;itc.getCurrent();itc.goNext())
{
if( !check_consumer_item(itc) )
continue;
ConsumerInfo ci;
if( !getConsumerInfo(it,ci.id,ci.node) )
continue;
InfoServer::ConsumerInfoExt cinf(ci);
cinf.ask = xml.getIntProp(itc,"ask");
lst.push_front(cinf);
cslot(xml,itc,it.getCurrent());
}
rslot(xml,it,node);
if( !lst.empty() )
addlist(is,code,lst);
}
}
// ------------------------------------------------------------------------------------------
// This file is part of the UniSet project.
/* This file is part of the UniSet project
* Copyright (C) 2003 Pavel Vainerman <pv@etersoft.ru>
*
* 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.
*/
// -----------------------------------------------------------------------------------------
#include <sstream>
#include <iomanip>
#include "MessageInterface_XML.h"
#include "Configuration.h"
// -----------------------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
// -----------------------------------------------------------------------------------------
MessageInterface_XML::MessageInterface_XML( const string xmlfile, int msize ):
msgmap(msize)
{
string mfile(xmlfile);
if( mfile.empty() )
mfile = conf->getConfFileName();
UniXML xml;
// try
// {
xml.open(mfile);
read(xml);
// }
// catch(...){}
}
// ------------------------------------------------------------------------------------------
MessageInterface_XML::MessageInterface_XML( UniXML& xml, int msize ):
msgmap(msize)
{
read(xml);
}
// ------------------------------------------------------------------------------------------
MessageInterface_XML::~MessageInterface_XML()
{
}
// ------------------------------------------------------------------------------------------
string MessageInterface_XML::getMessage( UniSetTypes::MessageCode code )
{
if( (unsigned)code<0 || (unsigned)code>=msgmap.size() )
return "";
return msgmap[code].text;
}
// ------------------------------------------------------------------------------------------
bool MessageInterface_XML::isExist( UniSetTypes::MessageCode code )
{
if( (unsigned)code<0 || (unsigned)code>= msgmap.size() )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
UniSetTypes::MessageCode MessageInterface_XML::getCode( const string& msg )
{
for( unsigned int i=0; i<msgmap.size(); i++ )
{
if( msgmap[i].text == msg )
return msgmap[i].code;
}
return DefaultMessageCode;
}
// ------------------------------------------------------------------------------------------
UniSetTypes::MessageCode MessageInterface_XML::getCodeByIdName( const string& name )
{
for( unsigned int i=0; i<msgmap.size(); i++ )
{
if( msgmap[i].idname == name )
return msgmap[i].code;
}
return DefaultMessageCode;
}
// ------------------------------------------------------------------------------------------
void MessageInterface_XML::read( UniXML& xml )
{
xmlNode* root( xml.findNode(xml.getFirstNode(),"messages") );
if( !root )
{
ostringstream msg;
msg << "(MessageInterface_XML::read): не нашли корневого раздела 'messages'";
throw NameNotFound(msg.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
ostringstream msg;
msg << "(MessageInterface_XML::read): не удалось перейти к списку элементов 'messages'";
throw NameNotFound(msg.str());
}
unsigned int ind=0;
for( ;it.getCurrent(); it.goNext() )
{
msgmap[ind].idname = xml.getProp(it,"name");
msgmap[ind].text = xml.getProp(it,"text");
msgmap[ind].code = ind;
ind++;
if( ind >= msgmap.size() )
{
ostringstream msg;
msg << "(MessageInterface_XML::read): не хватило размера массива maxSize=" << msgmap.size();
unideb[Debug::WARN] << msg.str() << "... Делаем resize + 100\n";
msgmap.resize(msgmap.size()+100);
}
}
// подгоняем под реальный размер
msgmap.resize(ind);
}
// ------------------------------------------------------------------------------------------
std::ostream& MessageInterface_XML::printMessagesMap( std::ostream& os )
{
cout << "size: " << msgmap.size() << endl;
for( unsigned int i=0; i<msgmap.size(); i++ )
{
os << setw(5) << msgmap[i].code << " "
<< setw(10) << msgmap[i].idname << " "
<< setw(45) << msgmap[i].text << endl;
}
return os;
}
// -----------------------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, MessageInterface_XML& mi )
{
return mi.printMessagesMap(os);
}
// -----------------------------------------------------------------------------------------
/*! \file
* \brief Класс работы с сообщениями
* \author Pavel Vainerman
*/
/**************************************************************************/
#include <sstream>
#include <iomanip>
#include "Exceptions.h"
#include "MessageInterface_idXML.h"
#include "Configuration.h"
// -----------------------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------------------
MessageInterface_idXML::MessageInterface_idXML( const std::string xmlfile )
{
UniXML xml;
// try
// {
xml.open(xmlfile);
build(xml);
// }
// catch(...){}
}
// -----------------------------------------------------------------------------------------
MessageInterface_idXML::MessageInterface_idXML( UniXML& xml )
{
build(xml);
}
// -----------------------------------------------------------------------------------------
MessageInterface_idXML::~MessageInterface_idXML()
{
}
// -----------------------------------------------------------------------------------------
string MessageInterface_idXML::getMessage( UniSetTypes::MessageCode code )
{
MapMessageKey::const_iterator it = mmk.find(code);
if( it != mmk.end() )
return it->second.text;
ostringstream err;
err << "Неизвестное сообщение с кодом " << code;
return err.str();
}
// -----------------------------------------------------------------------------------------
bool MessageInterface_idXML::isExist(UniSetTypes::MessageCode code)
{
if( mmk.find(code) != mmk.end() )
return true;
return false;
}
// -----------------------------------------------------------------------------------------
UniSetTypes::MessageCode MessageInterface_idXML::getCode( const string& msg )
{
for( MapMessageKey::const_iterator it = mmk.begin(); it!=mmk.end(); ++it )
{
if( it->second.text == msg )
return it->first;
}
return UniSetTypes::DefaultMessageCode;
}
// -----------------------------------------------------------------------------------------
UniSetTypes::MessageCode MessageInterface_idXML::getCodeByIdName( const string& name )
{
for( MapMessageKey::const_iterator it = mmk.begin(); it!=mmk.end(); ++it )
{
if( it->second.idname == name )
return it->first;
}
return UniSetTypes::DefaultMessageCode;
}
// -----------------------------------------------------------------------------------------
void MessageInterface_idXML::build( UniXML& xml )
{
xmlNode* root = xml.findNode(xml.getFirstNode(),"messages");
if( !root )
{
ostringstream msg;
msg << "(MessageInterface_idXML::build): не нашли корневого раздела <messages>";
throw NameNotFound(msg.str());
}
// Считываем список элементов
UniXML_iterator it(root);
if( !it.goChildren() )
{
ostringstream msg;
msg << "(MessageInterface_idXML::build): не удалось перейти к списку элементов <messages>";
throw NameNotFound(msg.str());
}
for( ;it.getCurrent(); it.goNext() )
{
MessageInfo inf;
inf.code = it.getIntProp("id");
if( inf.code <= 0 )
{
ostringstream msg;
msg << "(MessageInterface_idXML::build): НЕ УКАЗАН id для " << it.getProp("name");
throw NameNotFound(msg.str());
}
inf.idname = it.getProp("name");
inf.text = it.getProp("text");
mmk[inf.code] = inf;
}
}
// -----------------------------------------------------------------------------------------
std::ostream& MessageInterface_idXML::printMessagesMap( std::ostream& os )
{
cout << "size: " << mmk.size() << endl;
for( MapMessageKey::const_iterator it = mmk.begin(); it!=mmk.end(); ++it )
{
os << setw(5) << it->second.code << " "
<< setw(10) << it->second.idname << " "
<< setw(45) << it->second.text << endl;
}
return os;
}
// -----------------------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, MessageInterface_idXML& mi )
{
return mi.printMessagesMap(os);
}
// -----------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include "Debug.h"
#include "Configuration.h"
#include "NCRestorer.h"
#include "Exceptions.h"
// ------------------------------------------------------------------------------------------
using namespace std;
using namespace UniversalIO;
using namespace UniSetTypes;
// ------------------------------------------------------------------------------------------
NCRestorer::NCRestorer()
{
}
NCRestorer::~NCRestorer()
{
}
// ------------------------------------------------------------------------------------------
void NCRestorer::addlist( IONotifyController* ic, SInfo& inf, IONotifyController::ConsumerList& lst, bool force )
{
UniSetTypes::KeyType k( key(inf.si.id,inf.si.node) );
// Проверка зарегистрирован-ли данный датчик
// если такого дискретного датчика нет, то здесь сработает исключение...
if( !force )
{
try
{
ic->getIOType(inf.si);
}
catch(...)
{
// Регистрируем (если не найден)
switch(inf.type)
{
case UniversalIO::DigitalInput:
case UniversalIO::DigitalOutput:
ic->dsRegistration(inf);
break;
case UniversalIO::AnalogInput:
case UniversalIO::AnalogOutput:
ic->asRegistration(inf);
break;
default:
unideb[Debug::CRIT] << ic->getName() << "(askDumper::addlist): НЕИЗВЕСТНЫЙ ТИП ДАТЧИКА! -> "
<< conf->oind->getNameById(inf.si.id,inf.si.node) << endl;
return;
break;
}
}
}
switch(inf.type)
{
case UniversalIO::DigitalInput:
ic->askDIOList[k]=lst;
break;
case UniversalIO::AnalogInput:
ic->askAIOList[k]=lst;
break;
case UniversalIO::DigitalOutput:
ic->askDOList[k]=lst;
break;
case UniversalIO::AnalogOutput:
ic->askAOList[k]=lst;
break;
default:
unideb[Debug::CRIT] << ic->getName() << "(askDumper::addlist): НЕИЗВЕСТНЫЙ ТИП ДАТЧИКА!-> "
<< conf->oind->getNameById(inf.si.id,inf.si.node) << endl;
break;
}
}
// ------------------------------------------------------------------------------------------
void NCRestorer::addthresholdlist( IONotifyController* ic, SInfo& inf, IONotifyController::ThresholdExtList& lst, bool force )
{
// Проверка зарегистрирован-ли данный датчик
// если такого дискретного датчика нет сдесь сработает исключение...
if( !force )
{
try
{
ic->getIOType(inf.si);
}
catch(...)
{
// Регистрируем (если не найден)
switch(inf.type)
{
case UniversalIO::DigitalInput:
case UniversalIO::DigitalOutput:
ic->dsRegistration(inf);
break;
case UniversalIO::AnalogInput:
case UniversalIO::AnalogOutput:
ic->asRegistration(inf);
break;
default:
break;
}
}
}
// default init iterators
for( IONotifyController::ThresholdExtList::iterator it=lst.begin(); it!=lst.end(); ++it )
it->itSID = ic->mydioEnd();
UniSetTypes::KeyType k( key(inf.si.id,inf.si.node) );
ic->askTMap[k].si = inf.si;
ic->askTMap[k].type = inf.type;
ic->askTMap[k].list = lst;
ic->askTMap[k].ait = ic->myaioEnd();
try
{
switch( inf.type )
{
case UniversalIO::DigitalInput:
case UniversalIO::DigitalOutput:
case UniversalIO::AnalogOutput:
break;
case UniversalIO::AnalogInput:
{
IOController::AIOStateList::iterator it(ic->myaioEnd());
ic->checkThreshold(it,inf.si,false);
}
break;
default:
break;
}
}
catch(Exception& ex)
{
unideb[Debug::WARN] << ic->getName() << "(NCRestorer::addthresholdlist): " << ex
<< " для " << conf->oind->getNameById(inf.si.id, inf.si.node) << endl;
throw;
}
catch( CORBA::SystemException& ex )
{
unideb[Debug::WARN] << ic->getName() << "(NCRestorer::addthresholdlist): "
<< conf->oind->getNameById(inf.si.id,inf.si.node) << " недоступен!!(CORBA::SystemException): "
<< ex.NP_minorString() << endl;
throw;
}
}
// ------------------------------------------------------------------------------------------
NCRestorer::SInfo& NCRestorer::SInfo::operator=(IOController_i::DigitalIOInfo& inf)
{
this->si = inf.si;
this->type = inf.type;
this->priority = inf.priority;
this->default_val = inf.default_val;
this->real_value = inf.real_state ? 1 : 0;
this->ci.minRaw = 0;
this->ci.maxRaw = 0;
this->ci.minCal = 0;
this->ci.maxCal = 0;
this->ci.sensibility = 0;
this->db_ignore = false;
this->undefined = false;
this->any = 0;
return *this;
}
// ------------------------------------------------------------------------------------------
NCRestorer::SInfo& NCRestorer::SInfo::operator=(IOController_i::AnalogIOInfo& inf)
{
this->si = inf.si;
this->type = inf.type;
this->priority = inf.priority;
this->default_val = inf.default_val;
this->real_value = inf.real_value;
this->ci = inf.ci;
this->undefined = false;
this->db_ignore = false;
this->any = 0;
return *this;
}
// ------------------------------------------------------------------------------------------
NCRestorer::SInfo::operator IOController::UniDigitalIOInfo()
{
IOController::UniDigitalIOInfo ret;
ret.state = this->value ? true : false;
ret.si = this->si;
ret.type = this->type;
ret.priority = this->priority;
ret.default_val = this->default_val ? true : false;
ret.any = this->any;
ret.undefined = this->undefined;
ret.db_ignore = this->db_ignore;
return ret;
}
// ------------------------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include <sstream>
#include "Debug.h"
#include "Configuration.h"
#include "NCRestorer.h"
#include "Exceptions.h"
#include "ORepHelpers.h"
// ------------------------------------------------------------------------------------------
using namespace std;
using namespace UniversalIO;
using namespace UniSetTypes;
// ------------------------------------------------------------------------------------------
NCRestorer_XML::NCRestorer_XML( const string fname ):
s_filterField(""),
s_filterValue(""),
c_filterField(""),
c_filterValue(""),
d_filterField(""),
d_filterValue(""),
t_filterField(""),
t_filterValue(""),
fname(fname)
{
init(fname);
}
NCRestorer_XML::NCRestorer_XML(const string fname,
const std::string f_field,
const std::string f_value):
s_filterField(f_field),
s_filterValue(f_value),
c_filterField(""),
c_filterValue(""),
d_filterField(""),
d_filterValue(""),
t_filterField(""),
t_filterValue(""),
fname(fname)
{
init(fname);
setItemFilter(f_field,f_value);
}
NCRestorer_XML::NCRestorer_XML():
fname("")
{
}
// ------------------------------------------------------------------------------------------
NCRestorer_XML::~NCRestorer_XML()
{
uxml.close();
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::init( std::string fname )
{
/*!
\warning Файл открывается только при создании...
Т.е. не будут учтены изменения в промежутке между записью(dump-а) файла
*/
try
{
uxml.open(fname);
}
catch(UniSetTypes::NameNotFound& ex)
{
unideb[Debug::WARN] << "(NCRestorer_XML): файл " << fname << " не найден, создаём новый...\n";
}
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::dump(IONotifyController* ic, SInfo& inf,
const IONotifyController::ConsumerList& lst)
{
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << "NCRestorer_XML::dump NOT SUPPORT!!!!" << endl;
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::dumpThreshold(IONotifyController* ic, SInfo& inf,
const IONotifyController::ThresholdExtList& lst)
{
if( unideb.debugging(Debug::WARN) )
unideb[Debug::WARN] << "NCRestorer_XML::dumpThreshold NOT SUPPORT!!!!" << endl;
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::read_list( UniXML& xml, xmlNode* node, IONotifyController* ic )
{
UniXML_iterator it(node);
if( !it.goChildren() )
return;
for( ;it.getCurrent(); it.goNext() )
{
if( !check_list_item(it) )
continue;
NCRestorer_XML::SInfo inf;
if( !getSensorInfo(xml,it,inf) )
{
unideb[Debug::WARN] << ic->getName() << "(read_list): не смог получить информацию по датчику " << endl;
continue;
}
inf.undefined = false;
// т.к. в функции может обновится inf
// вызываем перед регистрацией
// (потому-что в xxRegistration inf будет скопирована
ncrslot(xml,it,node,inf);
switch(inf.type)
{
case UniversalIO::DigitalOutput:
case UniversalIO::DigitalInput:
{
try
{
IOController::UniDigitalIOInfo dinf(inf);
dinf.real_state = dinf.state;
dsRegistration(ic,dinf,true);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << "(read_list): " << ex << endl;
}
}
break;
case UniversalIO::AnalogOutput:
case UniversalIO::AnalogInput:
{
try
{
asRegistration(ic, inf, true);
}
catch(Exception& ex)
{
unideb[Debug::WARN] << "(read_list): " << ex << endl;
}
}
break;
default:
break;
}
rslot(xml,it,node);
read_consumers(xml,it,inf,ic);
}
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::read( IONotifyController* ic, const string fn )
{
UniXML* confxml = conf->getConfXML();
if( !fn.empty() )
{
// оптимизация (не загружаем второй раз xml-файл)
if( fn == conf->getConfFileName() && confxml )
read( ic, *confxml );
else
{
UniXML xml(fn);
read( ic, xml );
xml.close();
}
}
else if( !fname.empty() )
{
// оптимизация (не загружаем второй раз xml-файл)
if( fname == conf->getConfFileName() && confxml )
read( ic, *confxml );
else
{
uxml.close();
uxml.open(fname);
read(ic,uxml);
}
}
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::read( IONotifyController* ic, UniXML& xml )
{
xmlNode* node;
if( (&xml) == conf->getConfXML() )
node = conf->getXMLSensorsSection();
else
node = xml.findNode(xml.getFirstNode(),"sensors");
if( node )
read_list(xml, node, ic);
xmlNode* tnode( xml.findNode(xml.getFirstNode(),"thresholds") );
if( tnode )
read_thresholds(xml, tnode, ic);
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::getBaseInfo( UniXML& xml, xmlNode* it, IOController_i::SensorInfo& si )
{
string sname( xml.getProp(it,"name"));
if( sname.empty() )
{
unideb[Debug::WARN] << "(getSensorInfo): не указано имя датчика... пропускаем..." << endl;
return false;
}
// преобразуем в полное имя
ObjectId sid = UniSetTypes::DefaultObjectId;
string id(xml.getProp(it,"id"));
if( !id.empty() )
sid = uni_atoi( id );
else
sid = conf->getSensorID(sname);
if( sid == UniSetTypes::DefaultObjectId )
{
unideb[Debug::CRIT] << "(getSensorInfo): НЕ НАЙДЕН ИДЕНТИФИКАТОР датчика --> " << sname << endl;
return false;
}
ObjectId snode = conf->getLocalNode();
string snodename(xml.getProp(it,"node"));
if( !snodename.empty() )
snode = conf->getNodeID(snodename);
if( snode == UniSetTypes::DefaultObjectId )
{
unideb[Debug::CRIT] << "(getSensorInfo): НЕ НАЙДЕН ИДЕНТИФИКАТОР узла --> " << snodename << endl;
return false;
}
si.id = sid;
si.node = snode;
return true;
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::getSensorInfo( UniXML& xml, xmlNode* it, SInfo& inf )
{
if( !getBaseInfo(xml,it,inf.si) )
return false;
inf.priority = Message::Medium;
string prior(xml.getProp(it,"priority"));
if( prior == "Low" )
inf.priority = Message::Low;
else if( prior == "Medium" )
inf.priority = Message::Medium;
else if( prior == "High" )
inf.priority = Message::High;
else if( prior == "Super" )
inf.priority = Message::Super;
else
{
inf.priority = Message::Medium;
if( unideb.debugging(Debug::INFO) )
{
unideb[Debug::INFO] << "(NCRestorer_XML:getSensorInfo): не указан приоритет для "
<< xml.getProp(it,"name") << endl;
}
}
inf.type = UniSetTypes::getIOType(xml.getProp(it,"iotype"));
if( inf.type == UniversalIO::UnknownIOType )
{
unideb[Debug::CRIT] << "(NCRestorer_XML:getSensorInfo): unknown iotype=" << xml.getProp(it,"iotype")
<< " for " << xml.getProp(it,"name") << endl;
return false;
}
// калибровка
if( inf.type == UniversalIO::AnalogInput || inf.type == UniversalIO::AnalogOutput )
{
inf.ci.minRaw = xml.getIntProp(it,"rmin");
inf.ci.maxRaw = xml.getIntProp(it,"rmax");
inf.ci.minCal = xml.getIntProp(it,"cmin");
inf.ci.maxCal = xml.getIntProp(it,"cmax");
inf.ci.sensibility = xml.getIntProp(it,"sensibility");
inf.ci.precision = xml.getIntProp(it,"precision");
}
else
{
inf.ci.minRaw = 0;
inf.ci.maxRaw = 0;
inf.ci.minCal = 0;
inf.ci.maxCal = 0;
inf.ci.sensibility = 0;
inf.ci.precision = 0;
}
inf.default_val = xml.getIntProp(it,"default");
inf.db_ignore = xml.getIntProp(it,"db_ignore");
inf.value = inf.default_val;
inf.undefined = false;
inf.real_value = inf.value;
return true;
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::read_thresholds(UniXML& xml, xmlNode* node, IONotifyController* ic )
{
UniXML_iterator it(node);
if( !it.goChildren() )
return;
for( ;it.getCurrent(); it.goNext() )
{
if( !check_thresholds_item(it) )
continue;
NCRestorer_XML::SInfo inf;
if( !getSensorInfo(xml,it.getCurrent(),inf) )
{
unideb[Debug::WARN] << ic->getName()
<< "(read_thresholds): не смог получить информацию по датчику" << endl;
continue;
}
if( unideb.debugging(Debug::INFO) )
{
unideb[Debug::INFO] << ic->getName() << "(read_thresholds): "
<< it.getProp("name") << endl;
// conf->oind->getNameById(inf.si.id,inf.si.node) << endl;
}
UniXML_iterator tit(it);
if( !tit.goChildren() )
continue;
IONotifyController::ThresholdExtList tlst;
for( ;tit; tit.goNext() )
{
IONotifyController::ThresholdInfoExt ti(0,0,0,0);
if( !getThresholdInfo(xml,tit,ti) )
{
unideb[Debug::WARN] << ic->getName()
<< "(read_thresholds): не смог получить информацию о пороге"
<< " для датчика "
<< conf->oind->getNameById(inf.si.id,inf.si.node) << endl;
continue;
}
if( unideb.debugging(Debug::INFO) )
{
unideb[Debug::INFO] << "(read_thresholds): \tthreshold low="
<< ti.lowlimit << " \thi=" << ti.hilimit
<< " \t sb=" << ti.sensibility
<< " \t sid=" << ti.sid
<< " \t inverse=" << ti.inverse
<< endl << flush;
}
xmlNode* cnode = find_node(xml,tit,"consumers","");
if( cnode )
{
UniXML_iterator ask_it(cnode);
if( ask_it.goChildren() )
{
if( !getConsumerList(xml,ask_it,ti.clst) )
{
unideb[Debug::WARN] << ic->getName()
<< "(read_thresholds): не смог получить список заказчиков"
<< " для порога " << ti.id
<< " датчика " << conf->oind->getNameById(inf.si.id,inf.si.node) << endl;
}
}
}
// порог добавляем в любом случае, даже если список заказчиков пуст...
tlst.push_back(ti);
rtslot(xml,tit,it);
}
addthresholdlist(ic,inf,tlst);
}
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::read_consumers( UniXML& xml, xmlNode* it,
NCRestorer_XML::SInfo& inf, IONotifyController* ic )
{
// в новых ask-файлах список выделен <consumers>...</consumers>,
xmlNode* cnode = find_node(xml,it,"consumers","");
if( cnode )
{
UniXML_iterator cit(cnode);
if( cit.goChildren() )
{
IONotifyController::ConsumerList lst;
if( getConsumerList(xml,cit,lst) )
addlist(ic,inf,lst,true);
}
}
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::getConsumerList( UniXML& xml,xmlNode* node,
IONotifyController::ConsumerList& lst )
{
UniXML_iterator it(node);
for(;it;it.goNext())
{
if( !check_consumer_item(it) )
continue;
ConsumerInfo ci;
if( !getConsumerInfo(it,ci.id,ci.node) )
continue;
IONotifyController::ConsumerInfoExt cinf(ci);
lst.push_back(cinf);
cslot(xml,it,node);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::getThresholdInfo( UniXML& xml,xmlNode* node,
IONotifyController::ThresholdInfoExt& ti )
{
UniXML_iterator uit(node);
string sid_name = uit.getProp("sid");
if( !sid_name.empty() )
{
ti.sid = conf->getSensorID(sid_name);
if( ti.sid == UniSetTypes::DefaultObjectId )
{
unideb[Debug::CRIT] << "(NCRestorer_XML:getThresholdInfo): "
<< " Not found ID for " << sid_name << endl;
}
else
{
UniversalIO::IOTypes iotype = conf->getIOType(ti.sid);
// Пока что IONotifyController поддерживает работу только с 'DI'.
if( iotype != UniversalIO::DigitalInput )
{
unideb[Debug::CRIT] << "(NCRestorer_XML:getThresholdInfo): "
<< " Bad iotype(" << iotype << ") for " << sid_name << ". iotype must be 'DI'!" << endl;
return false;
}
}
}
ti.id = uit.getIntProp("id");
ti.lowlimit = uit.getIntProp("lowlimit");
ti.hilimit = uit.getIntProp("hilimit");
ti.sensibility = uit.getIntProp("sensibility");
ti.inverse = uit.getIntProp("inverse");
ti.state = IONotifyController_i::NormalThreshold;
return true;
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::check_thresholds_item( UniXML_iterator& it )
{
return UniSetTypes::check_filter(it,t_filterField,t_filterValue);
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::setReadThresholdItem( ReaderSlot sl )
{
rtslot = sl;
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::setReadDependItem( ReaderSlot sl )
{
depslot = sl;
}
// ------------------------------------------------------------------------------------------
void NCRestorer_XML::setDependsFilter( const std::string field, const std::string val )
{
d_filterField = field;
d_filterValue = val;
}
// -----------------------------------------------------------------------------
void NCRestorer_XML::setThresholdsFilter( const std::string field, const std::string val )
{
t_filterField = field;
t_filterValue = val;
}
// -----------------------------------------------------------------------------
void NCRestorer_XML::setNCReadItem( NCReaderSlot sl )
{
ncrslot = sl;
}
// -----------------------------------------------------------------------------
void NCRestorer_XML::buildDependsList( IONotifyController* ic, const std::string fn )
{
UniXML* confxml = conf->getConfXML();
if( !fn.empty() )
{
// оптимизация (не загружаем второй раз xml-файл)
if( fn == conf->getConfFileName() && confxml )
buildDependsList( ic, *confxml );
else
{
UniXML xml(fn);
buildDependsList( ic, xml );
xml.close();
}
}
else if( !fname.empty() )
{
// оптимизация (не загружаем второй раз xml-файл)
if( fname == conf->getConfFileName() && confxml )
buildDependsList( ic, *confxml );
else
{
uxml.close();
uxml.open(fname);
buildDependsList(ic,uxml);
}
}
else if( confxml )
{
buildDependsList( ic, *confxml );
}
else
{
unideb[Debug::CRIT] << "(NCRestorer_XML:buildDependsList): configure xml-file not defined..." << endl;
}
}
// -----------------------------------------------------------------------------
void NCRestorer_XML::buildDependsList( IONotifyController* ic, UniXML& xml )
{
xmlNode* node;
if( (&xml) == conf->getConfXML() )
node = conf->getXMLSensorsSection();
else
node = xml.findNode(xml.getFirstNode(),"sensors");
if( node )
build_depends(xml, node, ic);
}
// -----------------------------------------------------------------------------
void NCRestorer_XML::build_depends( UniXML& xml, xmlNode* node, IONotifyController* ic )
{
UniXML_iterator it(node);
if( !it.goChildren() )
return;
for( ;it.getCurrent(); it.goNext() )
{
if( !check_list_item(it) )
continue;
xmlNode* dnode = find_node(xml,it,"depends","");
if( !dnode )
continue;
IOController::DependsInfo mydepinfo;
if( !getBaseInfo(xml,it,mydepinfo.si) )
continue;
UniSetTypes::KeyType k = UniSetTypes::key(mydepinfo.si.id,mydepinfo.si.node);
mydepinfo.dit = dioFind(ic,k);
mydepinfo.ait = aioFind(ic,k);
if( mydepinfo.dit==dioEnd(ic) && mydepinfo.ait==aioEnd(ic) )
{
unideb[Debug::CRIT] << "(NCRestorer_XML:build_depends): Датчик "
<< xml.getProp(node,"name")
<< " НЕ НАЙДЕН ВО ВНУТРЕННЕМ СПИСКЕ! " << endl;
continue;
}
UniXML_iterator dit(dnode);
if( dit.goChildren() )
{
for( ;dit.getCurrent(); dit.goNext() )
{
if( !check_depend_item(dit) )
continue;
IOController::DependsInfo blk; // информации о блокировщике данного датчика
if( getDependsInfo(xml,dit,blk) )
{
k = UniSetTypes::key(blk.si.id,blk.si.node);
blk.dit = dioFind(ic,k);
blk.ait = aioFind(ic,k);
if( blk.dit==dioEnd(ic) && blk.ait==aioEnd(ic) )
{
unideb[Debug::CRIT] << ic->getName() << "(NCRestorer_XML:build_depends): "
<< " Не найдена зависимость на " << xml.getProp(dit,"name")
<< " для " << xml.getProp(node,"name") << endl;
continue;
}
mydepinfo.block_invert = dit.getIntProp("block_invert");
long block_val = dit.getIntProp("block_value");
long defval = 0;
if( blk.dit != dioEnd(ic) )
defval = blk.dit->second.default_val;
else if( blk.ait != aioEnd(ic) )
defval = blk.ait->second.default_val;
// Проверка начальных условий для высталения блокировки
bool blk_set = defval ? false : true;
if( mydepinfo.block_invert )
blk_set ^= true;
if( mydepinfo.dit!=dioEnd(ic) )
{
mydepinfo.dit->second.blocked = blk_set;
mydepinfo.dit->second.block_state = (bool)block_val;
mydepinfo.dit->second.state = defval;
mydepinfo.dit->second.real_state = defval;
if( blk_set )
mydepinfo.dit->second.state = (bool)block_val;
}
else if( mydepinfo.ait!=aioEnd(ic) )
{
mydepinfo.ait->second.blocked = blk_set;
mydepinfo.ait->second.block_value = block_val;
if( blk_set )
{
mydepinfo.ait->second.real_value = mydepinfo.ait->second.value;
mydepinfo.ait->second.value = block_val;
}
}
// вносим 'себя' в список зависимостей для указанного датчика
// (без проверки на дублирование
// т.к. не может быть два одинаковых ID
// в конф. файле...
if( blk.dit != dioEnd(ic) )
{
blk.dit->second.dlst.push_back(mydepinfo);
if( unideb.debugging(Debug::INFO) )
{
unideb[Debug::INFO] << ic->getName() << "(NCRestorer_XML:build_depends):"
<< " add " << xml.getProp(it,"name")
<< " to list of depends for " << xml.getProp(dit,"name")
<< " blk_set=" << blk_set
<< endl;
}
}
else if( blk.ait != aioEnd(ic) )
{
blk.ait->second.dlst.push_back(mydepinfo);
if( unideb.debugging(Debug::INFO) )
{
unideb[Debug::INFO] << ic->getName() << "(NCRestorer_XML:build_depends):"
<< " add " << xml.getProp(it,"name")
<< " to list of depends for " << xml.getProp(dit,"name")
<< " blk_set=" << blk_set
<< endl;
}
}
depslot(xml,dit,node);
}
}
}
}
}
// -----------------------------------------------------------------------------
bool NCRestorer_XML::check_depend_item( UniXML_iterator& it )
{
return UniSetTypes::check_filter(it,d_filterField,d_filterValue);
}
// ------------------------------------------------------------------------------------------
bool NCRestorer_XML::getDependsInfo( UniXML& xml, xmlNode* it, IOController::DependsInfo& di )
{
return getBaseInfo(xml,it,di.si);
}
// -----------------------------------------------------------------------------
/* 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.
*/
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
#include "StorageInterface.h"
#include "Configuration.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
// --------------------------------------------------------------------------
STLStorage::STLStorage()
{
}
STLStorage::~STLStorage()
{
}
// --------------------------------------------------------------------------
IOController_i::DigitalIOInfo STLStorage::find( const IOController_i::SensorInfo& si )
{
throw NameNotFound();
}
// --------------------------------------------------------------------------
void STLStorage::push( IOController_i::DigitalIOInfo& di )
{
}
// --------------------------------------------------------------------------
void STLStorage::remove(const IOController_i::SensorInfo& si)
{
}
// --------------------------------------------------------------------------
bool STLStorage::getState(const IOController_i::SensorInfo& si)
{
return false;
}
// --------------------------------------------------------------------------
long STLStorage::getValue(const IOController_i::SensorInfo& si)
{
return 0;
}
// --------------------------------------------------------------------------
void STLStorage::saveState(const IOController_i::DigitalIOInfo& di,bool st)
{
}
// --------------------------------------------------------------------------
void STLStorage::saveValue(const IOController_i::AnalogIOInfo& ai, long val)
{
}
// --------------------------------------------------------------------------
/* 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
*/
// --------------------------------------------------------------------------
#include <sstream>
#include <iomanip>
#include <signal.h>
#include <fstream>
#include "ORepHelpers.h"
#include "Configuration.h"
#include "SystemGuard.h"
//---------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
//---------------------------------------------------------------------------
static int SleepTickMS = 500; // минимальный интервал [мсек]
static int PingNodeTimeOut = 5; // интервал проверки связи с узлами [сек]
static int WatchDogTimeOut = 15; // интервал посылки WathDog message [мин]
static int AutoStartUpTimeOut=1; // интервал перед посылкой StartUp-а
static int DumpStateTime = 0; // интервал записи внутреннего состояния объектов
//---------------------------------------------------------------------------
SystemGuard::SystemGuard():
thr(0),
active(false)
{
thread(false);
init();
}
//---------------------------------------------------------------------------
SystemGuard::SystemGuard( ObjectId id ): //, ObjectsActivator* a ):
ObjectsActivator(id),
thr(0),
active(false)
{
thread(true);
init();
}
//---------------------------------------------------------------------------
void SystemGuard::init()
{
WatchDogTimeOut = conf->getIntField("WatchDogTime") * 60;
PingNodeTimeOut = conf->getIntField("PingNodeTime");
AutoStartUpTimeOut = conf->getIntField("AutoStartUpTime");
DumpStateTime = conf->getIntField("DumpStateTime");
SleepTickMS = conf->getIntField("SleepTickMS");
// act->addManager( static_cast<ObjectsManager*>(this) );
}
// -------------------------------------------------------------------------
SystemGuard::~SystemGuard()
{
unideb[Debug::WARN] << myname << "(" << ui.timeToString(time(0),":") << "): destroy.."<< endl;
if( active )
{
active = false;
uniset_mutex_lock ml(actMutex, 2000);
}
if( thr )
{
delete thr;
thr=0;
}
}
// -------------------------------------------------------------------------
void SystemGuard::execute()
{
active = true;
unideb[Debug::SYSTEM] << myname << ": guard processing run..." << endl;
expid = getpid();
// Сперва инициализируем сеть...
pingNode();
if( SleepTickMS <= 0 )
SleepTickMS = 200;
// int SleepTick = SleepTickMS/1000;
// int SleepTickNS = (SleepTickMS%1000)*1000000;
PassiveTimer ast;
if( AutoStartUpTimeOut )
ast.setTiming(AutoStartUpTimeOut*1000);
else
ast.setTiming(UniSetTimer::WaitUpTime);
if( PingNodeTimeOut )
rit.setTiming(PingNodeTimeOut*1000);
else
rit.setTiming(UniSetTimer::WaitUpTime);
if( WatchDogTimeOut )
wdogt.setTiming(WatchDogTimeOut*1000);
else
wdogt.setTiming(UniSetTimer::WaitUpTime);
if( DumpStateTime )
{
dumpStateInfo();
dumpt.setTiming(DumpStateTime*1000);
}
else
dumpt.setTiming(UniSetTimer::WaitUpTime);
// omutex.lock();
actMutex.lock();
while( active )
{
// cout << myname << "(execute): begin "<< endl << flush;
try
{
if( ast.checkTime() )
{
autostart();
ast.setTiming(UniSetTimer::WaitUpTime);
}
if( wdogt.checkTime() )
{
watchDogTime();
wdogt.reset();
}
if( rit.checkTime() )
{
pingNode();
rit.reset();
}
if( dumpt.checkTime() )
{
dumpStateInfo();
dumpt.reset();
}
}
catch(...)
{
unideb[Debug::CRIT] << myname << ": cacth ..." << endl;
}
// cout << myname << "(execute): end (" << SleepTickMS << ")" << endl << flush;
msleep(SleepTickMS);
// unsigned long s, n;
// omni_thread::get_time(&s, &n, SleepTick, SleepTickNS);
// ocond.timedwait(s,n);
}
actMutex.unlock();
// omutex.unlock();
unideb[Debug::SYSTEM] << myname << "(" << ui.timeToString(time(0),":") << "): guard processing stop..." << endl;
}
// -------------------------------------------------------------------------
void SystemGuard::watchDogTime()
{
// Рассылаем менеджерам
SystemMessage sm(SystemMessage::WatchDog);
broadcast( sm.transport_msg() );
}
// -------------------------------------------------------------------------
bool SystemGuard::pingNode()
{
// unideb[Debug::SYSTEM] << myname << "(initNode)..." << endl;
for( UniSetTypes::ListOfNode::iterator it = conf->lnodes.begin();
it != conf->lnodes.end(); ++it )
{
bool prev = it->connected;
try
{
unideb[Debug::SYSTEM] << myname << "(pingNode): проверяем " << conf->oind->getMapName(it->id) << endl << flush;
CosNaming::NamingContext_var ctx = ORepHelpers::getRootNamingContext( getORB(),
conf->oind->getRealNodeName(it->id) );
it->connected = true;
unideb[Debug::SYSTEM] << myname << "(pingNode): c узлом "<< conf->oind->getMapName(it->id)<< " связь есть ..." << endl;
}
catch(...)
{
it->connected = false;
}
try
{
updateNodeInfo((*it));
}
catch(...){}
// Рассылаем уведомление об изменении состояния в сети
if( prev != it->connected )
{
SystemMessage sm(SystemMessage::NetworkInfo);
sm.data[0] = it->id;
sm.data[1] = it->connected;
broadcast( sm.transport_msg() );
if(!it->connected )
unideb[Debug::SYSTEM] << myname <<"(pingNode): узел "<< conf->oind->getMapName(it->id)<< " НЕДОСТУПЕН!!!!" << endl;
}
}
return true;
}
// -------------------------------------------------------------------------
void SystemGuard::autostart()
{
unideb[Debug::SYSTEM] << myname << ": Рассылаем StartUp!!!!!"<< endl;
SystemMessage sm(SystemMessage::StartUp);
broadcast( sm.transport_msg() );
unideb[Debug::SYSTEM] << myname << ": StartUp ok."<< endl;
}
// -------------------------------------------------------------------------
void SystemGuard::sigterm( int signo )
{
unideb[Debug::CRIT] << myname << "(sigterm): catch sig=" << signo << "("<< strsignal(signo) <<")" << endl;
wdogt.setTiming(UniSetTimer::WaitUpTime);
rit.setTiming(UniSetTimer::WaitUpTime);
dumpt.setTiming(UniSetTimer::WaitUpTime);
try
{
ObjectsActivator::sigterm(signo);
}
catch(...){}
// active = false; // ???
}
// -------------------------------------------------------------------------
void SystemGuard::stop()
{
unideb[Debug::WARN] << myname << "(stop): disactivate..." << endl;
ObjectsActivator::stop();
// active = false;
// uniset_mutex_lock ml(actMutex, 2000); // ждём отключения
}
// -------------------------------------------------------------------------
void SystemGuard::run( bool thread )
{
thr = new ThreadCreator<SystemGuard>(this, &SystemGuard::execute);
if( !thr->start() )
{
unideb[Debug::CRIT] << myname << ": НЕ СМОГЛИ СОЗДАТЬ поток"<<endl;
throw SystemError("CREATE SYSTEMGUARD THREAD FAILED");
}
ObjectsActivator::run(thread);
}
// -------------------------------------------------------------------------
void SystemGuard::oaDestroy( int signo )
{
try
{
active = false;
uniset_mutex_lock ml(actMutex, 2000); // ждём отключения
ObjectsActivator::oaDestroy(signo);
}
catch(...)
{
unideb[Debug::CRIT] << myname << "(oaDestroy) catch ..." << endl;
}
}
// -------------------------------------------------------------------------
void SystemGuard::dumpStateInfo()
{
ostringstream fname;
string dir(conf->getLogDir());
// cout << "!!!!!DIR = " << dir << endl;
string name(ORepHelpers::getShortName(myname));
if( name.empty() )
{
name = conf->getArgv()[0];
}
fname << dir << name << ".log";
fstream fout( fname.str().c_str(), ios::out | ios::trunc );
if(!fout)
{
unideb[Debug::CRIT] << "НЕ СМОГ ОТКРЫТЬ ФАЙЛ " << fname.str() << endl;
return;
}
fout.setf(ios::left, ios::adjustfield);
fout << ui.dateToString(time(0),"/")<< "\t" << ui.timeToString(time(0),";") << endl;
fout << "==========================================================================" << endl;
// fout << "\n--------------------------------------------------------------------------" << endl;
fout << "\nСеть:\n";
fout << "--------------------------------------------------------------------------" << endl;
for( UniSetTypes::ListOfNode::const_iterator it = conf->listNodesBegin();
it != conf->listNodesEnd(); ++it )
{
fout << setw(40) << conf->oind->getMapName(it->id) << setw(2) << "\t"<< it->connected << endl;
}
fout << "\n\n--------------------------------------------------------------------------";
fout << "\nИнформация по объектам:";
fout << "\n--------------------------------------------------------------------------" << endl;
// fout << setw(40)<< "name"<< setw(6) << "\tid"<< setw(8) << "\tmsgTID \textinfo" << endl;
// fout << "--------------------------------------------------------------------------\n" << endl;
SimpleInfoSeq_var res = this->getObjectsInfo();
int size = res->length();
for(int i=0; i<size; i++)
fout << "\n" << res[i].info << "\n" << endl;
fout.close();
}
// -------------------------------------------------------------------------
SimpleInfo* SystemGuard::getInfo()
{
ostringstream info;
SimpleInfo_var si = ObjectsManager::getInfo();
info << si->info;
if( thr )
info << "\texTID= " << thr->getTID();
else
info << "\texpid= " << expid;
SimpleInfo* res = new SimpleInfo();
res->info = info.str().c_str(); // CORBA::string_dup(info.str().c_str());
res->id = getId();
return res; //._retn();
}
// -------------------------------------------------------------------------
/* This file is part of the UniSet project
* Copyright (c) 2009 Free Software Foundation, Inc.
* Copyright (c) 2009 Ivan Donchevskiy
*
* 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 Ivan Donchevskiy
*/
// --------------------------------------------------------------------------
/*! Функции класса TableBlockStorage, таблицы ключ-значение с ограниченным кол-вом перезаписей для
каждого блока памяти, при достижении предела, происходит переход в следующий блок
*/
#include "Storages.h"
TableBlockStorage::TableBlockStorage():
file(NULL),
mem(0)
{
}
TableBlockStorage::TableBlockStorage(const char* name, int byte_sz, int key_sz, int inf_sz, int inf_count, int block_num, int block_lim, int seek, bool cr):
file(NULL),
mem(0)
{
if(!open(name, byte_sz, key_sz, inf_sz, inf_count, block_num, block_lim, seek))
{
if(cr)
create(name, byte_sz, key_sz, inf_sz, inf_count, block_num, block_lim, seek);
else
file=NULL;
}
}
TableBlockStorage::~TableBlockStorage()
{
delete mem;
if(file!=NULL) fclose(file);
}
bool TableBlockStorage::keyCompare(int i, void* key)
{
return !memcmp((char*)elemPointer(i)+sizeof(TableBlockStorageElem),key,k_size);
}
TableBlockStorageElem* TableBlockStorage::elemPointer(int num)
{
return (TableBlockStorageElem*)((char*)mem+num*full_size);
}
void* TableBlockStorage::keyPointer(int num)
{
return (char*)elemPointer(num) + sizeof(TableBlockStorageElem);
}
void* TableBlockStorage::valPointer(int num)
{
return (char*)elemPointer(num) + sizeof(TableBlockStorageElem) + k_size;
}
void TableBlockStorage::filewrite(int seek, bool needflush)
{
/*! Запись элемента с номером i из памяти в текущий блок файла */
fseek(file,seekpos+(seek+cur_block*block_size)*full_size,0);
fwrite(elemPointer(seek),full_size,1,file);
if(needflush) fflush(file);
}
bool TableBlockStorage::copyToNextBlock(void)
{
/*! Переход на следующий блок файла */
max=-1;
int tmp=mem->count;
mem->count=EMPTY_BLOCK;
filewrite(0,false);
mem->count=tmp;
if(cur_block>=block_number-1)
cur_block=0;
else
cur_block++;
/*! Параллельно заново заполняются счетчики записей */
for(int i=0;i<block_size;i++)
{
if(elemPointer(i)->count>=0)
{
elemPointer(i)->count=++max;
filewrite(i,false);
}
}
fflush(file);
/*! если достигнут максимальный, возвращается false */
if(cur_block>=block_number-1)
return false;
return true;
}
/*! Использовать для проверки совпадения заголовков */
bool TableBlockStorage::checkAttr( int key_sz, int inf_sz, int inf_count, int block_num, int block_lim, int seek )
{
if( file==NULL ) return false;
int tmpsize=inf_count*block_num;
fseek(file, seek, 0);
/*! Чтение заголовка таблицы */
StorageAttr sa;
fread(&sa,sizeof(StorageAttr),1,file);
/*! Проверяем заголовок на совпадение с нашими значениями */
if((sa.k_size!=key_sz)||(sa.inf_size!=inf_sz)||(sa.size!=tmpsize)||(sa.block_number!=block_num)||(sa.lim!=block_lim)||(sa.seekpos!=seek))
{
fclose(file);
file=NULL;
return false;
}
return true;
}
bool TableBlockStorage::open(const char* name, int byte_sz, int key_sz, int inf_sz, int inf_count, int block_num, int block_lim, int seek)
{
/*! Если уже был открыт файл в переменной данного класса, он закрывается и открывается новый */
if(file!=NULL) fclose(file);
file = fopen(name, "r+");
if(file==NULL) return false;
seekpos=seek;
if(fseek(file,seekpos,0)==-1)
{
fclose(file);
file=NULL;
return false;
}
full_size = sizeof(TableBlockStorageElem)+key_sz+inf_sz;
if( !checkAttr(key_sz, inf_sz, inf_count, block_num, block_lim, seek ) )
return false;
k_size=key_sz;
inf_size=inf_sz;
lim=block_lim;
block_number=block_num;
block_size=inf_count;
size=block_size*block_num;
if( byte_sz<getByteSize() )
{
fclose(file);
file=NULL;
return false;
}
max=-1;
/*! Инициализация памяти */
mem = (TableBlockStorageElem*) new char[block_size*full_size];
TableBlockStorageElem *t = (TableBlockStorageElem*)new char[full_size];
seekpos+=sizeof(StorageAttr);
/*! Поиск непустого блока, либо если все пустые, текущий устанавливается 0 */
for(cur_block=0; cur_block < block_num; cur_block++)
{
fseek(file,seekpos+cur_block*block_size*(full_size),0);
fread(t,(full_size),1,file);
if(t->count >= 0)
break;
}
if( t->count < 0 )
cur_block = 0;
/*! Чтение в память из нужного блока */
fseek(file,seekpos+(cur_block*block_size)*(full_size),0);
for(int i=0;i<block_size;i++)
{
fread(elemPointer(i),(full_size),1,file);
if(elemPointer(i)->count>max) max=elemPointer(i)->count;
}
delete[] t;
return true;
}
bool TableBlockStorage::create(const char* name, int byte_sz, int key_sz, int inf_sz, int inf_count, int block_num, int block_lim, int seek)
{
if(file!=NULL) fclose(file);
file = fopen(name, "r+");
k_size=key_sz;
inf_size=inf_sz;
seekpos=seek;
lim=block_lim;
full_size = sizeof(TableBlockStorageElem)+k_size+inf_size;
int i;
block_number=block_num;
block_size=inf_count;
size=block_size*block_num;
max=-1;
if( byte_sz<getByteSize() )
{
if( file!=NULL ) fclose(file);
file=NULL;
return false;
}
if(file==NULL)
{
FILE *f=fopen(name,"w");
if( f==NULL ) return false;
fclose(f);
file = fopen(name, "r+");
}
if(fseek(file,seekpos,0)==-1) return false;
/*! Инициализация памяти */
mem = (TableBlockStorageElem*) new char[block_size*full_size];
for( i=0; i<block_size*full_size; i++ )
*((char*)mem+i) = 0;
StorageAttr sa;
sa.k_size=k_size;
sa.inf_size=inf_size;
sa.size=size;
sa.block_number=block_number;
sa.lim=lim;
sa.seekpos=seekpos;
/*! Запись заголовка таблицы */
cur_block=0;
fwrite(&sa,sizeof(StorageAttr),1,file);
fflush(file);
seekpos+=sizeof(StorageAttr);
/*! Поле счетчика записей при создании служит флагом на используемость блока и на пустоту ячейки записи:
EMPTY_BLOCK=(-5) - заполняются первые элементы каждого блока, если там другое значение, то этот блок используется, EMPTY_ELEM=(-1) - все остальные пустые записи
*/
mem->count=EMPTY_BLOCK;
for(i=1;i<block_size;i++)
elemPointer(i)->count=EMPTY_ELEM;
/*! Цикл инициализирует все блоки в файле*/
for(i=0;i<size;i++)
{
if((i!=0)&&(i%block_size==0)) cur_block++;
filewrite(i%block_size,false);
}
cur_block=0;
fflush(file);
return true;
}
bool TableBlockStorage::addRow(void* key, void* value)
{
int i=0,pos=-1,empty=-1;
if(file==NULL) return false;
if(max==lim-1) copyToNextBlock();
for(i=0;i<block_size;i++)
{
if(elemPointer(i)->count>=0)
if(keyCompare(i,key)) pos = i;
if((elemPointer(i)->count<0)&&(empty<0)) empty=i;
}
/*! если нашли совпадение ключа, то pos>=0, записываем на это место, иначе пишем на пустое место empty */
if(pos>=0) empty=pos;
else
{
if( empty<0 ) return false; /*! Возвращаем false, если место в блоке закончилось */
memcpy(keyPointer(empty),key,k_size);
}
elemPointer(empty)->count=++max;
memcpy(valPointer(empty),value,inf_size);
filewrite(empty);
return true;
}
bool TableBlockStorage::delRow(void* key)
{
int i;
if(file==NULL) return false;
/*! При удалении счетчик перезаписей также увеличивается */
if(max==lim-1) copyToNextBlock();
for(i=0;i<block_size;i++)
{
if(elemPointer(i)->count < 0)
continue;
if(keyCompare(i,key))
{
elemPointer(i)->count=++max;
memset(keyPointer(i),0,k_size);
filewrite(i);
return true;
}
}
return false;
}
/*! TODO: можно убрать из параметров val, просто возвращать значение */
void* TableBlockStorage::findKeyValue(void* key, void* val)
{
int i;
if(file==NULL) return 0;
for(i=0;i<block_size;i++)
{
/*! Сравниваем ключи только если счетчик >= 0, т.е. запись существует */
if(elemPointer(i)->count < 0)
continue;
if(keyCompare(i,key))
{
memcpy(val,valPointer(i),inf_size);
return val;
}
}
return NULL;
}
int TableBlockStorage::getCurBlock()
{
return cur_block;
}
/* This file is part of the UniSet project
* Copyright (c) 2009 Free Software Foundation, Inc.
* Copyright (c) 2009 Ivan Donchevskiy
*
* 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 Ivan Donchevskiy
*/
// --------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Storages.h"
TableStorage::TableStorage( const char* name, int inf_sz, int sz, int seek ):
file(0)
{
file = fopen(name, "r+");
inf_size=inf_sz;
int l=-1,r=size,mid;
size=sz/(sizeof(TableStorageElem)+inf_size);
TableStorageElem *t = (TableStorageElem*)malloc(sizeof(TableStorageElem)+inf_size);
if(file==NULL)
{
file = fopen(name,"w");
memset(t,0,sizeof(*t));
for(int i=0;i<size;i++) fwrite(t,(sizeof(TableStorageElem)+inf_size),1,file);
fclose(file);
file = fopen(name,"r+");
seekpos=0;
head=-1;
}
else
{
seekpos=seek;
fseek(file,seekpos,0);
fread(t,(sizeof(TableStorageElem)+inf_size),1,file);
if(t->status==0)
{
head=-1;
}
else if((t->status==1)||(t->status==6))
{
head=0;
}
else if((t->status==2)||(t->status==3))
{
while((t->status!=1)&&(t->status!=6)&&(r - l > 1))
{
mid = (l+r)/2;
fseek(file,seekpos+mid*(sizeof(TableStorageElem)+inf_size),0);
fread(t,(sizeof(TableStorageElem)+inf_size),1,file);
if((t->status==2)||(t->status==3))
l = mid;
else if((t->status==4)||(t->status==5))
r = mid;
else
{
r=mid;
break;
}
}
if(r<size)
head=r;
else head=size-1;
}
else
{
while((t->status!=1)&&(t->status!=6)&&(r - l > 1))
{
mid = (l+r)/2;
fseek(file,seekpos+mid*(sizeof(TableStorageElem)+inf_size),0);
fread(t,(sizeof(TableStorageElem)+inf_size),1,file);
if((t->status==2)||(t->status==3))
r = mid;
else if((t->status==4)||(t->status==5))
l = mid;
else
{
r=mid;
break;
}
}
if(r<size)
head=r;
else head=size-1;
}
}
free(t);
}
TableStorage::~TableStorage()
{
if( file )
fclose(file);
}
int TableStorage::addRow(char* key, char* value)
{
TableStorageElem *tbl = (TableStorageElem*)malloc(sizeof(TableStorageElem)+inf_size);
int i,k,j,st;
if(file!=NULL)
{
if(head==-1)
{
fseek(file,seekpos,0);
tbl->status=1;
strcpy(tbl->key,key);
for(k=0;k<inf_size;k++)
*((char*)(tbl)+sizeof(TableStorageElem)+k)=*(value+k);
fwrite(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
head=0;
free(tbl);
return 0;
}
fseek(file,seekpos+head*(sizeof(TableStorageElem)+inf_size),0);
j=head;
for(i=0;i<size;i++)
{
fread(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
if(tbl->status==0) break;
if(!strcmp(tbl->key,key)&&((tbl->status==2)||(tbl->status==4)||(tbl->status==1)))
{
for(k=0;k<inf_size;k++)
*((char*)(tbl)+sizeof(TableStorageElem)+k)=*(value+k);
fseek(file,seekpos+i*(sizeof(TableStorageElem)+inf_size),0);
fwrite(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
free(tbl);
return 0;
}
j++;
if(j>=size)
{
j=0;
fseek(file,seekpos,0);
}
}
fseek(file,seekpos+j*(sizeof(TableStorageElem)+inf_size),0);
if(j==head)
{
if((tbl->status==2)||(tbl->status==3)) st=2;
else st=4;
if(j==0) {
if(st==2) st=4;
else st=2;
}
tbl->status=st;
strcpy(tbl->key,key);
for(k=0;k<inf_size;k++)
*((char*)(tbl)+sizeof(TableStorageElem)+k)=*(value+k);
fwrite(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
j++;
if(j>=size)
{
j=0;
fseek(file,seekpos,0);
}
fread(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
if((tbl->status==3)||(tbl->status==5)) tbl->status=6;
else tbl->status=1;
fseek(file,seekpos+j*(sizeof(TableStorageElem)+inf_size),0);
fwrite(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
head++;
if(head>=size) head=0;
free(tbl);
return 0;
}
}
free(tbl);
return 1;
}
int TableStorage::delRow(char* key)
{
TableStorageElem *tbl = (TableStorageElem*)malloc(sizeof(TableStorageElem)+inf_size);
int i,j;
if(file!=NULL)
{
fseek(file,seekpos+head*(sizeof(TableStorageElem)+inf_size),0);
j=head;
for(i=0;i<size;i++)
{
fread(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
if(!strcmp(tbl->key,key)&&((tbl->status==2)||(tbl->status==4)||(tbl->status==1)))
{
//tbl->key[0]=0;
if(tbl->status==1) tbl->status=6;
else if(tbl->status==2) tbl->status=3;
else tbl->status=5;
fseek(file,seekpos+j*(sizeof(TableStorageElem)+inf_size),0);
fwrite(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
free(tbl);
return 0;
}
j++;
if(j>=size)
{
j=0;
fseek(file,seekpos,0);
}
}
}
free(tbl);
return 1;
}
char* TableStorage::findKeyValue(char* key, char* val)
{
TableStorageElem *tbl = (TableStorageElem*)malloc(sizeof(TableStorageElem)+inf_size);
int i,k;
if(file!=NULL)
{
fseek(file,seekpos,0);
for(i=0;i<size;i++)
{
fread(tbl,(sizeof(TableStorageElem)+inf_size),1,file);
if(!strcmp(tbl->key,key)&&((tbl->status==2)||(tbl->status==4)||(tbl->status==1)))
{
for(k=0;k<inf_size;k++)
*(val+k)=*((char*)(tbl)+sizeof(TableStorageElem)+k);
free(tbl);
return val;
}
}
}
free(tbl);
return 0;
}
/* 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
* \par
* Базовый класс получения строки по её индексу
*/
// --------------------------------------------------------------------------
#include "TextIndex.h"
/*
std::string TextIndex::getText(int id)
{
};
*/
/* This file is part of the UniSet project
* Copyright (c) 2009 Free Software Foundation, Inc.
* Copyright (c) 2009 Ivan Donchevskiy
*
* 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 Ivan Donchevskiy
*/
// --------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Storages.h>
#include <UniXML.h>
#include <UniSetTypes.h>
int seek=0;
int b_size=25000;
int bj_size=1300000;
void testTable1(void)
{
char *chr=new char[20];
char *val=new char[40];
TableStorage *t;
t = new TableStorage("table.test", 40, 1220, 0);
int i;
for(i=0;i<20;i++)
{
chr[0]=i;
sprintf(val,"%d",i);
t->addRow(chr,val);
}
printf("elements with values=keys added:\n");
for(i=0;i<40;i++)
{
chr[0]=i;
if(t->findKeyValue(chr,val)!=0) printf("%s, ",val);
}
printf("\n");
for(i=9;i<15;i++)
{
chr[0]=i;
t->delRow(chr);
}
printf("elements with keys from 9 to 14 deleted\n");
for(i=9;i<15;i++)
{
chr[0]=i;
sprintf(val,"%d",i+40);
t->addRow(chr,val);
}
printf("elements with keys from 9 to 14 with values=key+40 added, all elements:\n");
for(i=0;i<40;i++)
{
chr[0]=i;
if(t->findKeyValue(chr,val)!=0) printf("%s, ",val);
}
printf("\n");
}
bool testTable2(void)
{
char *val=new char[40];
TableBlockStorage t0;
t0.create("small_file.test", b_size, 4, 40, 100, 5,28,0);
t0.open("small_file.test", b_size, 4, 40, 100, 5,28,0);
TableBlockStorage t;
//t = new TableBlockStorage();
t.create("big_file.test", b_size, 4, 40, 100, 5,28,0);
seek=t.getByteSize();
printf("Table size in bytes = %d\n",seek);
int i;
for(i=1;i<20;i++)
{
if(t.findKeyValue(&i,val)!=0) printf("%s, ",val);
}
printf("\n");
t0.addRow((char*)&i,val);
if(t.getCurBlock()!=0)
{
delete[] val;
return false;
}
for(i=1;i<11;i++)
{
sprintf(val,"%d",i);
t.addRow((char*)&i,val);
}
if(t.getCurBlock()!=0)
{
delete[] val;
return false;
}
for(i=1;i<20;i++)
{
if(t.findKeyValue(&i,val)!=0) printf("%s, ",val);
if(val[0]==0)
{
delete[] val;
return false;
}
}
printf("\n");
if(t.getCurBlock()!=0)
{
delete[] val;
return false;
}
for(i=1;i<8;i++)
{
sprintf(val,"%d",i+10);
t.addRow(&i,val);
}
printf("deleteing 8-10 elements\n");
for(i=8;i<11;i++)
{
t.delRow(&i);
}
for(i=1;i<20;i++)
{
if(t.findKeyValue(&i,val)!=0)
{
printf("%s, ",val);
if((i > 7)&&(i <11))
{
delete[] val;
return false;
}
}
if((val[0] == 0)&&(i < 8))
{
delete[] val;
return false;
}
}
printf("\nrewriting 3-10 elements with values=keys+40\n");
if(t.getCurBlock()!=0)
{
delete[] val;
return false;
}
for(i=3;i<11;i++)
{
sprintf(val,"%d",i+40);
t.addRow(&i,val);
}
for(i=1;i<20;i++)
{
if(t.findKeyValue(&i,val)!=0) printf("%s, ",val);
if((UniSetTypes::uni_atoi(val) != i+40) && (i>2) && (i<11))
{
delete[] val;
return false;
}
if((UniSetTypes::uni_atoi(val) != i+10) && (i<3))
{
delete[] val;
return false;
}
}
if(t.getCurBlock()!=0)
{
delete[] val;
return false;
}
printf("\n");
strcpy(val,"new block");
i=9;
t.addRow(&i,val);
for(i=1;i<20;i++)
{
if(t.findKeyValue((char*)&i,val)!=0) printf("%s, ",val);
}
if(t.getCurBlock()!=1)
{
delete[] val;
return false;
}
printf("after reopen:\n");
t.open("big_file.test", b_size, 4, 40, 100, 5,28,0);
for(i=1;i<20;i++)
{
if(t.findKeyValue(&i,val)!=0) printf("%s, ",val);
}
if(t.getCurBlock()!=1)
{
delete[] val;
return false;
}
delete[] val;
return true;
}
bool reOpen()
{
CycleStorage j;
int i,k=0;
char *str = new char[30];
printf("the same after reopen:\n");
if(!j.open("big_file.test",bj_size,30,33000,seek))
{
printf("Reopen file error\n");
delete[] str;
return false;
}
for(i=0;i<20;i++)
{
if(j.readRow(i,str))
{
printf("%s\n",str);
k++;
}
}
delete[] str;
if(k != 10)
return false;
return true;
}
bool testJournal1(void)
{
CycleStorage *jjj = new CycleStorage();
jjj->create("/dev/hdb2",bj_size,30,32000,seek);
delete jjj;
CycleStorage j("big_file.test",bj_size,30,32000,seek,true);
int i,k=0;
char *str = new char[30];
printf("journal test 1\n");
for(i=1;i<64001;i++)
{
sprintf(str,"%d",i);
j.addRow(str);
}
printf("first 30 elements:\n");
for(i=0;i<30;i++)
{
if(j.readRow(i,str))
{
printf("%s\n",str);
k++;
}
}
if(k < 30)
{
delete[] str;
return false;
}
k = 0;
printf("size changed to 33000 rows (increased)\n");
j.setSize(33000);
TableBlockStorage t("big_file.test", b_size, 4, 40, 100, 5,28,0);
printf("test of 2 classes working in 1 file together\n");
char *val = new char[40];
for(i=1;i<20;i++)
{
if(t.findKeyValue((char*)&i,val)!=0) printf("%s, ",val);
if((UniSetTypes::uni_atoi(val) != i+10) && (i<3))
{
delete[] val;
delete[] str;
return false;
}
}
delete[] val;
printf("\nfirst 30 elements after deleting first 20:\n");
for(i=0;i<20;i++)
{
j.delRow(i);
}
for(i=0;i<30;i++)
{
if(j.readRow(i,str))
{
printf("%s\n",str);
k++;
}
}
if(k != 10)
{
delete[] str;
return false;
}
k = 0;
printf("first 20 after adding 10 elements\n");
for(i=10000001;i<10000011;i++)
{
sprintf(str,"%d",i);
j.addRow(str);
}
for(i=0;i<20;i++)
{
if(j.readRow(i,str))
{
printf("%s\n",str);
k++;
}
}
if(k != 10)
{
delete[] str;
return false;
}
k = 0;
if(!reOpen()){ delete[] str; return false; };
if(!reOpen()){ delete[] str; return false; };
printf("size changed back to 32000 rows\n");
j.setSize(32000);
for(i=0;i<20;i++)
{
if(j.readRow(i,str))
{
printf("%s\n",str);
k++;
}
}
if(k != 10)
{
delete[] str;
return false;
}
k = 0;
delete[] str;
return true;
}
void testJournal2(void)
{
CycleStorage j("big_file.test",bj_size,30,32000,seek);
int i,k;
char *str = new char[30];
printf("journal test 2 - checking number of iterations to find head/tail\n");
printf("iterations = %d\n",j.getIter());
for(i=0;i<20;i++)
{
for(k=1000;k<2999;k++)
{
sprintf(str,"%d",k);
j.addRow(str);
}
j.open("big_file.test",bj_size,30,32000,seek);
printf("i=%d, iterations = %d\n", i, j.getIter());
}
printf("\n");
delete[] str;
}
struct JItem
{
long id;
long val[10];
} __attribute__((__packed__));
bool testJournal3()
{
CycleStorage j("journal3.test",bj_size,sizeof(JItem),10,0,true);
if( !j.isOpen() )
{
printf("create journal3.test failed\n");
return false;
}
printf("Joural size=%d inf_size=%d full_size=%d byte_size=%d\n",
j.getSize(),
j.getInfSize(),
j.getFullSize(),
j.getByteSize()
);
JItem ji;
printf("write 35 elements:\n");
for(int i=0;i<35;i++)
{
JItem ji;
ji.id = i;
for( int k=0; k<10; k++ )
ji.val[k] = i;
j.addRow(&ji);
}
printf("read first 10 elements:\n");
for( int i=0;i<10;i++)
{
if( j.readRow(i,&ji) )
printf("read i=%d j.id=%ld\n", i, ji.id);
else
printf("read num=%d FAILED!\n",i);
}
return true;
}
int main(int args, char **argv)
{
//testTable1();
bool ok = true;
if(testTable2())
printf("\nTest for TableBlockStorage passed\n\n");
else
{
printf("\nTest for TableBlockStorage failed\n\n");
ok = false;
}
if(testJournal1())
printf("\nTest1 for CycleStorage passed\n\n");
else
{
printf("\nTest for CycleStorage failed\n\n");
ok = false;
}
if(ok)
{
testJournal2();
printf("TEST PASSED :)\n");
}
else
printf("TEST FAILED :(\n");
testJournal3();
return 0;
}
\ No newline at end of file
############################################################################
# This file is part of the UniSet library #
############################################################################
noinst_PROGRAMS = jrntest
jrntest_SOURCES = JrnTest.cc
jrntest_LDADD = $(top_builddir)/lib/libUniSet.la
jrntest_CPPFLAGS = -I$(top_builddir)/include
include $(top_builddir)/conf/setting.mk
...@@ -140,6 +140,7 @@ int main( int argc, const char **argv ) ...@@ -140,6 +140,7 @@ int main( int argc, const char **argv )
try try
{ {
#if 0
{ {
uniset_rwmutex m1("mutex1"); uniset_rwmutex m1("mutex1");
uniset_rwmutex m2("mutex2"); uniset_rwmutex m2("mutex2");
...@@ -161,6 +162,7 @@ int main( int argc, const char **argv ) ...@@ -161,6 +162,7 @@ int main( int argc, const char **argv )
} }
return 0; return 0;
#endif
#if 0 #if 0
ost::ThreadLock m; ost::ThreadLock m;
......
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