Commit 85d1b0f9 authored by Pavel Vainerman's avatar Pavel Vainerman

Rename UNet2 --> UNetUDP (production of new release 1.4)

parent 5d030cda
......@@ -2,8 +2,8 @@
%define oname uniset
Name: libuniset
Version: 1.3
Release: alt19
Version: 1.4
Release: alt1
Summary: UniSet - library for building distributed industrial control systems
License: GPL
Group: Development/C++
......@@ -183,7 +183,7 @@ rm -f %buildroot%_libdir/*.la
%_libdir/libUniSetRT*.so.*
%_libdir/libUniSetShared*.so.*
%_libdir/libUniSetNetwork*.so.*
%_libdir/libUniSetUNet2*.so.*
%_libdir/libUniSetUNetUDP*.so.*
#%_libdir/libUniSetSMDBServer*.so.*
%files extensions-devel
......@@ -195,7 +195,7 @@ rm -f %buildroot%_libdir/*.la
%_libdir/libUniSetRT*.so
%_libdir/libUniSetShared*.so
%_libdir/libUniSetNetwork.so
%_libdir/libUniSetUNet2.so
%_libdir/libUniSetUNetUDP.so
#%_libdir/libUniSetSMDBServer.so
%_pkgconfigdir/*Extensions.pc
%_pkgconfigdir/libUniSetIO*.pc
......@@ -213,6 +213,10 @@ rm -f %buildroot%_libdir/*.la
%changelog
* Thu May 31 2012 Pavel Vainerman <pv@altlinux.ru> 1.4-alt1
- rename unet2 -->unetudp
- release version 1.4
* Thu May 31 2012 Pavel Vainerman <pv@altlinux.ru> 1.3-alt19
- DBServer: set log info level - LEVEL9
- minor fixies for linker errors (new gcc)
......
......@@ -3,7 +3,7 @@
# See doc: http://www.gnu.org/software/hello/manual/autoconf/Generic-Programs.html
# AC_PREREQ(2.59)
AC_INIT([uniset], [1.3.0], pv@etersoft.ru)
AC_INIT([uniset], [1.4.0], pv@etersoft.ru)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME,AC_PACKAGE_VERSION)
# AC_CONFIG_MACRO_DIR([m4])
......@@ -30,7 +30,7 @@ AC_ENABLE_SHARED(yes)
AC_ENABLE_STATIC(no)
AM_PROG_LIBTOOL
LIBVER=1:3:0
LIBVER=1:4:0
AC_SUBST(LIBVER)
# Checks for libraries.
......@@ -189,8 +189,8 @@ AC_CONFIG_FILES([Makefile
extensions/SMViewer/Makefile
extensions/UniNetwork/Makefile
extensions/UniNetwork/libUniSetNetwork.pc
extensions/UNet2/Makefile
extensions/UNet2/libUniSetUNet2.pc
extensions/UNetUDP/Makefile
extensions/UNetUDP/libUniSetUNetUDP.pc
extensions/SharedMemory/Makefile
extensions/SharedMemory/libUniSetSharedMemory.pc
extensions/SharedMemoryPlus/Makefile
......
bin_PROGRAMS = @PACKAGE@-unetexchange @PACKAGE@-unet2-tester
# не забывайте править версию в pc-файле
UNET2_VER=@LIBVER@
lib_LTLIBRARIES = libUniSetUNet2.la
libUniSetUNet2_la_LDFLAGS = -version-info $(UNET2_VER)
libUniSetUNet2_la_LIBADD = $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/SharedMemory/libUniSetSharedMemory.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
libUniSetUNet2_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libUniSetUNet2_la_SOURCES = UDPPacket.cc UNetReceiver.cc UNetSender.cc UNetExchange.cc
@PACKAGE@_unetexchange_SOURCES = unetexchange.cc
@PACKAGE@_unetexchange_LDADD = libUniSetUNet2.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)
@PACKAGE@_unet2_tester_SOURCES = UDPPacket.cc unet2-tester.cc
@PACKAGE@_unet2_tester_LDADD = $(COMCPP_LIBS)
@PACKAGE@_unet2_tester_CXXFLAGS = $(COMCPP_CFLAGS)
# install
devel_include_HEADERS = *.h
devel_includedir = $(pkgincludedir)/extensions
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libUniSetUNet2.pc
all-local:
ln -sf ../UNet2/$(devel_include_HEADERS) ../include
#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
<< " acount=" << p.acount
<< " pnum=" << p.num;
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader* p )
{
return os << (*p);
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPAData& p )
{
return os << "id=" << p.id << " val=" << p.val;
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPMessage& p )
{
os << (UDPHeader*)(&p) << endl;
os << "DIGITAL:" << endl;
for( size_t i=0; i<p.dcount; i++ )
os << "[" << i << "]={" << p.dID(i) << "," << p.dValue(i) << "}" << endl;
os << "ANALOG:" << endl;
for( size_t i=0; i<p.acount; i++ )
os << "[" << i << "]={" << p.a_dat[i].id << "," << p.a_dat[i].val << "}" << endl;
return os;
}
// -----------------------------------------------------------------------------
UDPMessage::UDPMessage()
{
}
// -----------------------------------------------------------------------------
size_t UDPMessage::addAData( const UniSetUDP::UDPAData& dat )
{
if( acount >= MaxACount )
return MaxACount;
a_dat[acount] = dat;
acount++;
return acount-1;
}
// -----------------------------------------------------------------------------
size_t UDPMessage::addAData( long id, long val)
{
UDPAData d(id,val);
return addAData(d);
}
// -----------------------------------------------------------------------------
bool UDPMessage::setAData( size_t index, long val )
{
if( index < MaxACount )
{
a_dat[index].val = val;
return true;
}
return false;
}
// -----------------------------------------------------------------------------
size_t UDPMessage::addDData( long id, bool val )
{
if( dcount >= MaxDCount )
return MaxDCount;
// сохраняем ID
d_id[dcount] = id;
bool res = setDData( dcount, val );
if( res )
{
dcount++;
return dcount-1;
}
return MaxDCount;
}
// -----------------------------------------------------------------------------
bool UDPMessage::setDData( size_t index, bool val )
{
if( index >= MaxDCount )
return false;
size_t nbyte = index / sizeof(unsigned char);
size_t nbit = index % sizeof(unsigned char);
// выставляем бит
unsigned char d = d_dat[nbyte];
if( val )
d |= (1<<nbit);
else
d &= ~(1<<nbit);
d_dat[nbyte] = d;
return true;
}
// -----------------------------------------------------------------------------
long UDPMessage::dID( size_t index )
{
if( index >= MaxDCount )
return UniSetTypes::DefaultObjectId;
return d_id[index];
}
// -----------------------------------------------------------------------------
bool UDPMessage::dValue( size_t index )
{
if( index >= MaxDCount )
return UniSetTypes::DefaultObjectId;
size_t nbyte = index / sizeof(unsigned char);
size_t nbit = index % sizeof(unsigned char);
return ( d_dat[nbyte] & (1<<nbit) );
}
// -----------------------------------------------------------------------------
size_t UDPMessage::transport_msg( UDPPacket& p )
{
memset(&p,0,sizeof(UDPPacket));
size_t i = 0;
memcpy(&(p.data[i]),this,sizeof(UDPHeader));
i += sizeof(UDPHeader);
// копируем аналоговые данные
size_t sz = acount*sizeof(UDPAData);
memcpy(&(p.data[i]),a_dat,sz);
i += sz;
// копируем булевые индексы
sz = dcount*sizeof(long);
memcpy(&(p.data[i]),d_id,sz);
i += sz;
// копируем булевые данные
size_t nbyte = dcount / sizeof(unsigned char);
size_t nbit = dcount % sizeof(unsigned char);
sz = nbit > 0 ? nbyte + 1 : nbyte;
memcpy(&(p.data[i]),d_dat,sz);
i += sz;
p.len = i;
return i;
}
// -----------------------------------------------------------------------------
UDPMessage::UDPMessage( UDPPacket& p )
{
getMessage(*this,p);
}
// -----------------------------------------------------------------------------
size_t UDPMessage::getMessage( UDPMessage& m, UDPPacket& p )
{
memset(&m,0,sizeof(m));
size_t i = 0;
memcpy(&m,&(p.data[i]),sizeof(UDPHeader));
i += sizeof(UDPHeader);
// копируем аналоговые данные
size_t sz = m.acount*sizeof(UDPAData);
if( sz > sizeof(m.a_dat) )
sz = sizeof(m.a_dat);
memcpy(m.a_dat,&(p.data[i]),sz);
i += sz;
// копируем булевые индексы
sz = m.dcount*sizeof(long);
if( sz > sizeof(m.d_id) )
sz = sizeof(m.d_id);
memcpy(m.d_id,&(p.data[i]),sz);
i += sz;
// копируем булевые данные
size_t nbyte = m.dcount / sizeof(unsigned char);
size_t nbit = m.dcount % sizeof(unsigned char);
sz = nbit > 0 ? nbyte + 1 : nbyte;
if( sz > sizeof(m.d_dat) )
sz = sizeof(m.d_dat);
memcpy(m.d_dat,&(p.data[i]),sz);
return i+sz;
}
// -----------------------------------------------------------------------------
#ifndef UDPPacket_H_
#define UDPPacket_H_
// -----------------------------------------------------------------------------
#include <list>
#include <limits>
#include <ostream>
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
namespace UniSetUDP
{
/*! Для оптимизации размера передаваемх данных, но с учётом того, что ID могут идти не подряд.
Сделан следующие формат:
Для аналоговых величин передаётся массив пар "id-value".
Для булевых величин - отдельно массив ID и отдельно битовый массив со значениями,
(по количеству битов такого же размера).
*/
struct UDPHeader
{
UDPHeader():num(0),nodeID(0),procID(0),dcount(0),acount(0){}
unsigned long num;
long nodeID;
long procID;
size_t dcount; /*!< количество булевых величин */
size_t acount; /*!< количество аналоговых величин */
friend std::ostream& operator<<( std::ostream& os, UDPHeader& p );
friend std::ostream& operator<<( std::ostream& os, UDPHeader* p );
}__attribute__((packed));
static unsigned long MaxPacketNum = std::numeric_limits<unsigned long>::max();
struct UDPAData
{
UDPAData():id(UniSetTypes::DefaultObjectId),val(0){}
UDPAData(long id, long val):id(id),val(val){}
long id;
long val;
friend std::ostream& operator<<( std::ostream& os, UDPAData& p );
}__attribute__((packed));
static const size_t MaxACount = 200;
static const size_t MaxDCount = 400;
static const size_t MaxDDataCount = MaxDCount / sizeof(unsigned char);
struct UDPPacket
{
UDPPacket():len(0){}
int len;
unsigned char data[ sizeof(UDPHeader) + MaxDCount*sizeof(long) + MaxDDataCount + MaxACount*sizeof(UDPAData) ];
}__attribute__((packed));
static const int MaxDataLen = sizeof(UDPPacket);
struct UDPMessage:
public UDPHeader
{
UDPMessage();
UDPMessage( UDPPacket& p );
size_t transport_msg( UDPPacket& p );
static size_t getMessage( UDPMessage& m, UDPPacket& p );
size_t addDData( long id, bool val );
bool setDData( size_t index, bool val );
long dID( size_t index );
bool dValue( size_t index );
size_t addAData( const UDPAData& dat );
size_t addAData( long id, long val );
bool setAData( size_t index, long val );
inline bool isFull(){ return ((dcount<MaxDCount) && (acount<MaxACount)); }
inline int dsize(){ return dcount; }
inline int asize(){ return acount; }
// inline int byte_size(){ return (dcount*sizeof(long)*UDPDData) + acount*sizeof(UDPAData)); }
// количество байт в пакете с булевыми переменными...
int d_byte(){ return dcount*sizeof(long) + dcount; }
UDPAData a_dat[MaxACount]; /*!< аналоговые величины */
long d_id[MaxDCount]; /*!< список дискретных ID */
unsigned char d_dat[MaxDDataCount]; /*!< битовые значения */
friend std::ostream& operator<<( std::ostream& os, UDPMessage& p );
};
}
// -----------------------------------------------------------------------------
#endif // UDPPacket_H_
// -----------------------------------------------------------------------------
#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"
// -----------------------------------------------------------------------------
/*!
\page pageUNetExchange2 Сетевой обмен на основе UDP (UNet2)
- \ref pgUnet2_Common
- \ref pgUnet2_Conf
- \ref pgUnet2_Reserv
\section pgUnet2_Common Общее описание
Обмен построен на основе протокола UDP.
Основная идея заключается в том, что каждый узел на порту равном своему ID
посылает в сеть UDP-пакеты содержащие данные считанные из локальной SM. Формат данных - это набор
пар "id - value". Другие узлы принимают их. Помимо этого данный процесс запускает
по потоку приёма для каждого другого узла и ловит пакеты от них, сохраняя данные в SM.
\par
При своём старте процесс считывает из секции \<nodes> список узлов с которыми необходимо
вести обмен, а также параметры своего узла. Открывает по потоку приёма на каждый узел и поток
передачи для своих данных. Помимо этого такие же потоки для резервных каналов, если они включены
(см. \ref pgUnet2_Reserv ).
\section pgUnet2_Conf Пример конфигурирования
По умолчанию при считывании используется \b unet_broadcast_ip (указанный в секции \<nodes>)
и \b id узла - в качестве порта.
Но можно переопределять эти параметры, при помощи указания \b unet_port и/или \b unet_broadcast_ip,
для конкретного узла (\<item>).
\code
<nodes port="2809" unet_broadcast_ip="192.168.56.255">
<item ip="127.0.0.1" name="LocalhostNode" textname="Локальный узел" unet_ignore="1" unet_port="3000" unet_broadcast_ip="192.168.57.255">
<iocards>
...
</iocards>
</item>
<item ip="192.168.56.10" name="Node1" textname="Node1" unet_port="3001"/>
<item ip="192.168.56.11" name="Node2" textname="Node2" unet_port="3002"/>
</nodes>
\endcode
\section pgUnet2_Reserv Настройка резервного канала связи
В текущей реализации поддерживается возможность обмена по двум подсетям (эзернет-каналам).
Она основана на том, что, для каждого узла помимо основного "читателя",
создаётся дополнительный "читатель"(поток) слушающий другой ip-адрес и порт.
А так же, для локального узла создаётся дополнительный "писатель"(поток),
который посылает данные в (указанную) вторую подсеть. Для того, чтобы задействовать
второй канал, достаточно объявить в настройках переменные
\b unet_broadcast_ip2. А также в случае необходимости для конкретного узла
можно указать \b unet_broadcast_ip2 и \b unet_port2.
Переключение между "каналами" происходит по следующей логике:
При старте включается только первый канал. Второй канал работает в режиме "пассивного" чтения.
Т.е. все пакеты принимаются, но данные в SharedMemory не обновляются.
Если во время работы пропадает связь по первому каналу, идёт переключение на второй канал.
Первый канал переводиться в "пассивный" режим, а второй канал, переводится в "нормальный"(активный)
режим. Далее работа ведётся по второму каналу, независимо от того, что связь на первом
канале может восстановиться. Это сделано для защиты от постоянных перескакиваний
с канала на канал. Работа на втором канале будет вестись, пока не пропадёт связь
на нём. Тогда будет попытка переключиться обратно на первый канал и так "по кругу".
В свою очередь "писатели"(если они не отключены) всегда посылают данные в оба канала.
*/
// -----------------------------------------------------------------------------
class UNetExchange:
public UniSetObject_LT
{
public:
UNetExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UNetExchange();
/*! глобальная функция для инициализации объекта */
static UNetExchange* init_unetexchange( int argc, const char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, const 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();
void receiverEvent( UNetReceiver* r, UNetReceiver::Event ev );
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
void startReceivers();
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;
struct ReceiverInfo
{
ReceiverInfo():r1(0),r2(0),
sidRespond(UniSetTypes::DefaultObjectId),
sidLostPackets(UniSetTypes::DefaultObjectId)
{}
ReceiverInfo(UNetReceiver* _r1, UNetReceiver* _r2 ):
r1(_r1),r2(_r2),
sidRespond(UniSetTypes::DefaultObjectId),
respondInvert(false),
sidLostPackets(UniSetTypes::DefaultObjectId)
{}
UNetReceiver* r1; /*!< приём по первому каналу */
UNetReceiver* r2; /*!< приём по второму каналу */
void step( SMInterface* shm, const std::string myname );
inline void setRespondID( UniSetTypes::ObjectId id, bool invert=false )
{
sidRespond = id;
respondInvert = invert;
}
inline void setLostPacketsID( UniSetTypes::ObjectId id ){ sidLostPackets = id; }
inline void initIterators( SMInterface* shm )
{
shm->initAIterator(aitLostPackets);
shm->initDIterator(ditRespond);
}
// Сводная информация по двум каналам
// сумма потерянных пакетов и наличие связи
// хотя бы по одному каналу
// ( реализацию см. ReceiverInfo::step() )
UniSetTypes::ObjectId sidRespond;
IOController::DIOStateList::iterator ditRespond;
bool respondInvert;
UniSetTypes::ObjectId sidLostPackets;
IOController::AIOStateList::iterator aitLostPackets;
};
typedef std::list<ReceiverInfo> ReceiverList;
ReceiverList recvlist;
bool no_sender; /*!< флаг отключения посылки сообщений (создания потока для посылки)*/
UNetSender* sender;
UNetSender* sender2;
};
// -----------------------------------------------------------------------------
#endif // UNetExchange_H_
// -----------------------------------------------------------------------------
#ifndef UNetReceiver_H_
#define UNetReceiver_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <queue>
#include <cc++/socket.h>
#include <sigc++/sigc++.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 stop();
void receive();
void update();
inline std::string getName(){ return myname; }
// блокировать сохранение данный в SM
void setLockUpdate( bool st );
void resetTimeout();
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 setRespondID( UniSetTypes::ObjectId id, bool invert=false );
void setLostPacketsID( UniSetTypes::ObjectId id );
void setMaxProcessingCount( int set );
inline ost::IPV4Address getAddress(){ return addr; }
inline ost::tpport_t getPort(){ return port; }
/*! Коды событий */
enum Event
{
evOK, /*!< связь есть */
evTimeout /*!< потеря связи */
};
typedef sigc::slot<void,UNetReceiver*,Event> EventSlot;
void connectEvent( EventSlot sl );
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; /*!< счётчик потерянных пакетов */
UniSetTypes::ObjectId sidRespond;
IOController::DIOStateList::iterator ditRespond;
bool respondInvert;
UniSetTypes::ObjectId sidLostPackets;
IOController::AIOStateList::iterator aitLostPackets;
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>
{
inline bool operator()(const UniSetUDP::UDPMessage& lhs,
const UniSetUDP::UDPMessage& rhs) const
{ return lhs.num > rhs.num; }
};
typedef std::priority_queue<UniSetUDP::UDPMessage,std::vector<UniSetUDP::UDPMessage>,PacketCompare> PacketQueue;
PacketQueue qpack; /*!< очередь принятых пакетов (отсортированных по возрастанию номера пакета) */
UniSetUDP::UDPMessage pack; /*!< просто буфер для получения очередного сообщения */
UniSetUDP::UDPPacket r_buf;
UniSetTypes::uniset_mutex packMutex; /*!< mutex для работы с очередью */
unsigned long pnum; /*!< текущий номер обработанного сообщения, для проверки непрерывности последовательности пакетов */
/*! максимальная разница межд номерами пакетов, при которой считается, что счётчик пакетов
* прошёл через максимум или сбился...
*/
unsigned long maxDifferens;
PacketQueue qtmp; /*!< очередь на время обработки(очистки) основной очереди */
bool waitClean; /*!< флаг означающий, что ждём очистики очереди до конца */
unsigned long rnum; /*!< текущий номер принятого сообщения, для проверки "переполнения" или "сбоя" счётчика */
int maxProcessingCount; /*!< максимальное число обрабатываемых за один раз сообщений */
bool lockUpdate; /*!< флаг блокировки сохранения принятых данных в SM */
UniSetTypes::uniset_mutex lockMutex;
EventSlot slEvent;
Trigger trTimeout;
UniSetTypes::uniset_mutex tmMutex;
struct ItemInfo
{
long id;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
UniversalIO::IOTypes iotype;
ItemInfo():
id(UniSetTypes::DefaultObjectId),
iotype(UniversalIO::UnknownIOType){}
};
typedef std::vector<ItemInfo> ItemVec;
ItemVec d_icache; /*!< кэш итераторов для булевых */
ItemVec a_icache; /*!< кэш итераторов для аналоговых */
bool d_cache_init_ok;
bool a_cache_init_ok;
void initDCache( UniSetUDP::UDPMessage& pack, bool force=false );
void initACache( UniSetUDP::UDPMessage& pack, bool force=false );
};
// -----------------------------------------------------------------------------
#endif // UNetReceiver_H_
// -----------------------------------------------------------------------------
#include <sstream>
#include <iomanip>
#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(" << setw(15) << s_host << ":" << setw(4) << port << ")";
myname = s.str();
}
// определяем фильтр
// s_field = conf->getArgParam("--udp-filter-field");
// s_fvalue = conf->getArgParam("--udp-filter-value");
dlog[Debug::INFO] << myname << "(init): read filter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << "(UNetSender): UDP set to " << s_host << ":" << port << endl;
ost::Thread::setException(ost::Thread::throwException);
try
{
addr = s_host.c_str();
udp = new ost::UDPBroadcast(addr,port);
}
catch( std::exception& e )
{
ostringstream s;
s << myname << ": " << e.what();
dlog[Debug::CRIT] << s.str() << std::endl;
throw SystemError(s.str());
}
catch( ... )
{
ostringstream s;
s << myname << ": catch...";
dlog[Debug::CRIT] << s.str() << std::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.nodeID = conf->getLocalNode();
mypack.procID = shm->ID();
}
// -----------------------------------------------------------------------------
UNetSender::~UNetSender()
{
delete s_thr;
delete udp;
delete shm;
}
// -----------------------------------------------------------------------------
void UNetSender::updateFromSM()
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
long value = 0;
if( it->iotype == UniversalIO::DigitalInput || it->iotype == UniversalIO::DigitalOutput )
value = shm->localGetState(it->dit,it->id) ? 1 : 0;
else if( it->iotype == UniversalIO::AnalogInput || it->iotype == UniversalIO::AnalogOutput )
value = shm->localGetValue(it->ait,it->id);
else
{
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << it->id << endl;
continue;
}
updateItem(it,value);
}
}
// -----------------------------------------------------------------------------
void UNetSender::updateSensor( UniSetTypes::ObjectId id, long value )
{
// cerr << myname << ": UPDATE SENSOR id=" << id << " value=" << value << endl;
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
{
if( it->id == id )
{
updateItem( it, value );
break;
}
}
}
// -----------------------------------------------------------------------------
void UNetSender::updateItem( DMap::iterator& it, long value )
{
if( it == dlist.end() )
return;
if( it->iotype == UniversalIO::DigitalInput || it->iotype == UniversalIO::DigitalOutput )
{
UniSetTypes::uniset_mutex_lock l(pack_mutex,100);
mypack.setDData(it->pack_ind,value);
}
else if( it->iotype == UniversalIO::AnalogInput || it->iotype == UniversalIO::AnalogOutput )
{
UniSetTypes::uniset_mutex_lock l(pack_mutex,100);
mypack.setAData(it->pack_ind,value);
}
}
// -----------------------------------------------------------------------------
void UNetSender::send()
{
dlist.resize(maxItem);
dlog[Debug::INFO] << myname << "(send): 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
{
if( !shm->isLocalwork() )
updateFromSM();
real_send();
}
catch( ost::SockException& e )
{
dlog[Debug::WARN] << myname << "(send): " << e.getString() << endl;
}
catch( UniSetTypes::Exception& ex)
{
dlog[Debug::WARN] << myname << "(send): " << ex << std::endl;
}
catch( std::exception& e )
{
dlog[Debug::WARN] << myname << "(send): " << e.what() << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(send): catch ..." << std::endl;
}
msleep(sendpause);
}
dlog[Debug::INFO] << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::real_send()
{
UniSetTypes::uniset_mutex_lock l(pack_mutex,300);
mypack.num = packetnum++;
if( packetnum > UniSetUDP::MaxPacketNum )
packetnum = 1;
if( !udp->isPending(ost::Socket::pendingOutput) )
return;
mypack.transport_msg(s_msg);
size_t ret = udp->send( (char*)s_msg.data, s_msg.len );
if( ret < s_msg.len )
dlog[Debug::CRIT] << myname << "(real_send): FAILED ret=" << ret << " < sizeof=" << s_msg.len << endl;
}
// -----------------------------------------------------------------------------
void UNetSender::stop()
{
activated = false;
// s_thr->stop();
}
// -----------------------------------------------------------------------------
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_filter(it,s_field,s_fvalue) )
initItem(it);
}
}
// ------------------------------------------------------------------------------------------
bool UNetSender::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( UniSetTypes::check_filter(it,s_field,s_fvalue) )
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.iotype = UniSetTypes::getIOType(it.getProp("iotype"));
if( p.iotype == UniversalIO::UnknownIOType )
{
dlog[Debug::CRIT] << myname << "(readItem): Unknown iotype for sid=" << sid << endl;
return false;
}
p.id = sid;
if( p.iotype == UniversalIO::DigitalInput || p.iotype == UniversalIO::DigitalOutput )
{
p.pack_ind = mypack.addDData(sid,0);
if ( p.pack_ind >= UniSetUDP::MaxDCount )
{
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP DIGITAL DATA LIMIT! max="
<< UniSetUDP::MaxDCount << endl;
return false;
}
}
else if( p.iotype == UniversalIO::AnalogInput || p.iotype == UniversalIO::AnalogOutput )
{
p.pack_ind = mypack.addAData(sid,0);
if ( p.pack_ind >= UniSetUDP::MaxACount )
{
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP ANALOG DATA LIMIT! max="
<< UniSetUDP::MaxACount << endl;
return false;
}
}
if( maxItem >= dlist.size() )
dlist.resize(maxItem+10);
dlist[maxItem] = p;
maxItem++;
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;
return true;
}
// ------------------------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, UNetSender::UItem& p )
{
return os << " sid=" << p.id;
}
// -----------------------------------------------------------------------------
void UNetSender::initIterators()
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); it++ )
{
shm->initDIterator(it->dit);
shm->initAIterator(it->ait);
}
}
// -----------------------------------------------------------------------------
void UNetSender::askSensors( UniversalIO::UIOCommand cmd )
{
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); it++ )
shm->askSensor(it->id,cmd);
}
// -----------------------------------------------------------------------------
#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"
// -----------------------------------------------------------------------------
/*
*
*/
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():
iotype(UniversalIO::UnknownIOType),
id(UniSetTypes::DefaultObjectId),
pack_ind(-1){}
UniversalIO::IOTypes iotype;
UniSetTypes::ObjectId id;
IOController::AIOStateList::iterator ait;
IOController::DIOStateList::iterator dit;
int pack_ind;
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
typedef std::vector<UItem> DMap;
void start();
void stop();
void send();
void real_send();
/*! (принудительно) обновить все данные (из SM) */
void updateFromSM();
/*! Обновить значение по ID датчика */
void updateSensor( UniSetTypes::ObjectId id, long value );
/*! Обновить значение по итератору */
void updateItem( DMap::iterator& it, long value );
inline void setSendPause( int msec ){ sendpause = msec; }
/*! заказать датчики */
void askSensors( UniversalIO::UIOCommand cmd );
/*! инициализация итераторов */
void initIterators();
protected:
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void readConfiguration();
private:
UNetSender();
ost::UDPBroadcast* udp;
ost::IPV4Address addr;
ost::tpport_t port;
std::string s_host;
std::string myname;
int sendpause;
bool activated;
UniSetTypes::uniset_mutex pack_mutex;
UniSetUDP::UDPMessage mypack;
DMap dlist;
int maxItem;
unsigned long packetnum;
UniSetUDP::UDPPacket s_msg;
ThreadCreator<UNetSender>* s_thr; // send thread
};
// -----------------------------------------------------------------------------
#endif // UNetSender_H_
// -----------------------------------------------------------------------------
#!/bin/sh
ln -s -f ../../Utilities/scripts/uniset-start.sh
ln -s -f ../../Utilities/scripts/uniset-stop.sh stop.sh
ln -s -f ../../Utilities/scripts/uniset-functions.sh
ln -s -f ../../conf/test.xml test.xml
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libUniSetUNet2
Description: Support library for UniSetUNet2
Requires: libUniSetExtensions
Version: @VERSION@
Libs: -L${libdir} -lUniSetUNet2
Cflags: -I${includedir}/uniset
#!/bin/sh
uniset-start.sh -f ./uniset-unetexchange --unet-name UNetExchange \
--confile test.xml --smemory-id SharedMemory \
--unet-filter-field rs --unet-filter-value 2 --unet-maxdifferense 40 \
--dlog-add-levels info,crit,warn
#include <cstdlib>
#include <errno.h>
#include <getopt.h>
#include <cstring>
#include <iostream>
#include <cc++/socket.h>
#include "UDPPacket.h"
// --------------------------------------------------------------------------
static struct option longopts[] = {
{ "help", no_argument, 0, 'h' },
{ "send", required_argument, 0, 's' },
{ "receive", required_argument, 0, 'r' },
{ "proc-id", required_argument, 0, 'p' },
{ "node-id", required_argument, 0, 'n' },
{ "send-pause", required_argument, 0, 'x' },
{ "timeout", required_argument, 0, 't' },
{ "data-count", required_argument, 0, 'c' },
{ "disable-broadcast", no_argument, 0, 'b' },
{ "show-data", no_argument, 0, 'd' },
{ "check-lost", no_argument, 0, 'l' },
{ "verbode", required_argument, 0, 'v' },
{ "num-cycles", required_argument, 0, 'z' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetUDP;
// --------------------------------------------------------------------------
enum Command
{
cmdNOP,
cmdSend,
cmdReceive
};
// --------------------------------------------------------------------------
static bool split_addr( const string addr, string& host, ost::tpport_t& port )
{
string::size_type pos = addr.rfind(':');
if( pos != string::npos )
{
host = addr.substr(0,pos);
string s_port(addr.substr(pos+1,addr.size()-1));
port = UniSetTypes::uni_atoi(s_port.c_str());
return true;
}
return false;
}
// --------------------------------------------------------------------------
int main(int argc, char* argv[])
{
int optindex = 0;
int opt = 0;
Command cmd = cmdNOP;
int verb = 0;
std::string addr = "";
ost::tpport_t port=0;
int usecpause = 2000000;
timeout_t tout = TIMEOUT_INF;
bool broadcast = true;
int procID = 1;
int nodeID = 1;
size_t count = 50;
bool lost = false;
bool show = false;
int ncycles = -1;
while( (opt = getopt_long(argc, argv, "hs:c:r:p:n:t:x:blvdz:",longopts,&optindex)) != -1 )
{
switch (opt)
{
case 'h':
cout << "-h|--help - this message" << endl;
cout << "[-s|--send] host:port - Send message." << endl;
cout << "[-c|--data-count] num - Send num count of value. Default: 50." << endl;
cout << "[-r|--receive] host:port - Receive message." << endl;
cout << "[-p|--proc-id] id - Set packet header. From 'procID'. Default: 1" << endl;
cout << "[-n|--node-id] id - Set packet header. From 'nodeID'. Default: 1" << endl;
cout << "[-t|--timeout] msec - timeout for receive. Default: 0 msec (waitup)." << endl;
cout << "[-x|--send-pause] msec - pause for send packets. Default: 200 msec." << endl;
cout << "[-b|--disable-broadcast] - Disable broadcast mode." << endl;
cout << "[-l|--check-lost] - Check the lost packets." << endl;
cout << "[-v|--verbose] - verbose mode." << endl;
cout << "[-d|--show-data] - show receive data." << endl;
cout << "[-z|--num-cycles] num - Number of cycles of exchange. Default: -1 - infinitely." << endl;
cout << endl;
return 0;
case 'r':
cmd = cmdReceive;
addr = string(optarg);
break;
case 's':
addr = string(optarg);
cmd = cmdSend;
break;
case 't':
tout = UniSetTypes::uni_atoi(optarg);
break;
case 'x':
usecpause = UniSetTypes::uni_atoi(optarg)*1000;
break;
case 'c':
count = UniSetTypes::uni_atoi(optarg);
break;
case 'p':
procID = UniSetTypes::uni_atoi(optarg);
break;
case 'n':
nodeID = UniSetTypes::uni_atoi(optarg);
break;
case 'b':
broadcast = false;
break;
case 'd':
show = true;
break;
case 'l':
lost = true;
break;
case 'v':
verb = 1;
break;
case 'z':
ncycles = UniSetTypes::uni_atoi(optarg);
break;
case '?':
default:
cerr << "? argumnet" << endl;
return 0;
}
}
if( cmd == cmdNOP )
{
cerr << "No command... Use -h for help" << endl;
return -1;
}
if( tout < 0 )
tout = TIMEOUT_INF;
ost::Thread::setException(ost::Thread::throwException);
try
{
string s_host;
if( !split_addr(addr,s_host,port) )
{
cerr << "(main): Unknown 'host:port' for '" << addr << "'" << endl;
return 1;
}
if( verb )
{
cout << " host=" << s_host
<< " port=" << port
<< " timeout=";
if( tout == TIMEOUT_INF )
cout << "Waitup";
else
cout << tout;
cout << " msecpause=" << usecpause/1000
<< endl;
}
ost::IPV4Host host(s_host.c_str());
// udp.UDPTransmit::setBroadcast(broadcast);
switch( cmd )
{
case cmdReceive:
{
ost::UDPDuplex udp(host,port);
// char buf[UniSetUDP::MaxDataLen];
UniSetUDP::UDPMessage pack;
UniSetUDP::UDPPacket buf;
unsigned long prev_num=1;
int nc = 1;
if( ncycles > 0 )
nc = ncycles;
while( nc )
{
try
{
if( !udp.isInputReady(tout) )
{
cout << "(recv): Timeout.." << endl;
continue;
}
size_t ret = udp.UDPReceive::receive( &(buf.data), sizeof(buf.data) );
size_t sz = UniSetUDP::UDPMessage::getMessage(pack,buf);
if( sz == 0 )
{
cerr << "(recv): FAILED header ret=" << ret
<< " sizeof=" << sz<< endl;
continue;
}
if( lost )
{
if( prev_num != (pack.num-1) )
cerr << "WARNING! Incorrect sequence of packets! current=" << pack.num
<< " prev=" << prev_num << endl;
prev_num = pack.num;
}
if( verb )
cout << "receive OK: "
<< " bytes: " << ret << endl;
if( show )
cout << "receive data: " << pack << endl;
}
catch( ost::SockException& e )
{
cerr << "(recv): " << e.getString() << " (" << addr << ")" << endl;
}
catch( ... )
{
cerr << "(recv): catch ..." << endl;
}
if( ncycles > 0 )
{
nc--;
if( nc <=0 )
break;
}
}
}
break;
case cmdSend:
{
ost::UDPSocket* udp;
if( !broadcast )
udp = new ost::UDPSocket();
else
udp = new ost::UDPBroadcast(host,port);
UniSetUDP::UDPMessage mypack;
mypack.nodeID = nodeID;
mypack.procID = procID;
for( size_t i=0; i < count; i++ )
{
UDPAData d(i,i);
mypack.addAData(d);
}
for( unsigned int i=0; i < count; i++ )
mypack.addDData(i,i);
udp->setPeer(host,port);
unsigned long packetnum = 0;
UniSetUDP::UDPPacket s_buf;
int nc = 1;
if( ncycles > 0 )
nc = ncycles;
while( nc )
{
mypack.num = packetnum++;
if( packetnum > UniSetUDP::MaxPacketNum )
packetnum = 1;
try
{
if( udp->isPending(ost::Socket::pendingOutput,tout) )
{
mypack.transport_msg(s_buf);
if( verb )
cout << "(send): to addr=" << addr << " d_count=" << mypack.dcount
<< " a_count=" << mypack.acount << " bytes=" << s_buf.len << endl;
size_t ret = udp->send((char*)&s_buf.data, s_buf.len);
if( ret < s_buf.len )
cerr << "(send): FAILED ret=" << ret << " < sizeof=" << s_buf.len << endl;
}
}
catch( ost::SockException& e )
{
cerr << "(send): " << e.getString() << " (" << addr << ")" << endl;
}
catch( ... )
{
cerr << "(send): catch ..." << endl;
}
if( ncycles > 0 )
{
nc--;
if( nc <=0 )
break;
}
usleep(usecpause);
}
}
break;
default:
cerr << endl << "Unknown command: '" << cmd << "'. Use -h for help" << endl;
return -1;
break;
}
}
catch( std::exception& e )
{
cerr << "(main): " << e.what() << endl;
}
catch( ... )
{
cerr << "(main): catch ..." << endl;
return 1;
}
return 0;
}
// --------------------------------------------------------------------------
#include <sstream>
#include <sys/wait.h>
#include "ObjectsActivator.h"
#include "Extensions.h"
#include "UNetExchange.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, const 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;
}
uniset_init(argc,argv);
string logfilename(conf->getArgParam("--unet-logfile"));
if( logfilename.empty() )
logfilename = "udpexchange.log";
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
unideb.logFile( logname.str() );
UniSetExtensions::dlog.logFile( logname.str() );
conf->initDebug(UniSetExtensions::dlog,"dlog");
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);
while( waitpid(-1, 0, 0) > 0 );
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << "(unetexchange): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << "(unetexchange): catch ..." << std::endl;
}
while( waitpid(-1, 0, 0) > 0 );
return 0;
}
......@@ -5,8 +5,8 @@ using namespace UniSetUDP;
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader& p )
{
return os << "nodeID=" << p.nodeID
<< " procID=" << p.procID
return os << "nodeID=" << p.nodeID
<< " procID=" << p.procID
<< " dcount=" << p.dcount
<< " acount=" << p.acount
<< " pnum=" << p.num;
......@@ -30,11 +30,11 @@ std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPMessage& p
os << "DIGITAL:" << endl;
for( size_t i=0; i<p.dcount; i++ )
os << "[" << i << "]={" << p.dID(i) << "," << p.dValue(i) << "}" << endl;
os << "ANALOG:" << endl;
for( size_t i=0; i<p.acount; i++ )
os << "[" << i << "]={" << p.a_dat[i].id << "," << p.a_dat[i].val << "}" << endl;
return os;
}
// -----------------------------------------------------------------------------
......@@ -65,7 +65,7 @@ bool UDPMessage::setAData( size_t index, long val )
a_dat[index].val = val;
return true;
}
return false;
}
// -----------------------------------------------------------------------------
......@@ -76,7 +76,7 @@ size_t UDPMessage::addDData( long id, bool val )
// сохраняем ID
d_id[dcount] = id;
bool res = setDData( dcount, val );
if( res )
{
......@@ -92,18 +92,18 @@ bool UDPMessage::setDData( size_t index, bool val )
if( index >= MaxDCount )
return false;
size_t nbyte = index / 8*sizeof(unsigned char);
size_t nbit = index % 8*sizeof(unsigned char);
size_t nbyte = index / sizeof(unsigned char);
size_t nbit = index % sizeof(unsigned char);
// выставляем бит
unsigned char d = d_dat[nbyte];
if( val )
d |= (1<<nbit);
else
else
d &= ~(1<<nbit);
d_dat[nbyte] = d;
return true;
return true;
}
// -----------------------------------------------------------------------------
long UDPMessage::dID( size_t index )
......@@ -119,8 +119,8 @@ bool UDPMessage::dValue( size_t index )
if( index >= MaxDCount )
return UniSetTypes::DefaultObjectId;
size_t nbyte = index / 8*sizeof(unsigned char);
size_t nbit = index % 8*sizeof(unsigned char);
size_t nbyte = index / sizeof(unsigned char);
size_t nbit = index % sizeof(unsigned char);
return ( d_dat[nbyte] & (1<<nbit) );
}
......@@ -137,15 +137,15 @@ size_t UDPMessage::transport_msg( UDPPacket& p )
size_t sz = acount*sizeof(UDPAData);
memcpy(&(p.data[i]),a_dat,sz);
i += sz;
// копируем булевые индексы
sz = dcount*sizeof(long);
memcpy(&(p.data[i]),d_id,sz);
i += sz;
// копируем булевые данные
size_t nbyte = dcount / 8*sizeof(unsigned char);
size_t nbit = dcount % 8*sizeof(unsigned char);
size_t nbyte = dcount / sizeof(unsigned char);
size_t nbit = dcount % sizeof(unsigned char);
sz = nbit > 0 ? nbyte + 1 : nbyte;
memcpy(&(p.data[i]),d_dat,sz);
i += sz;
......@@ -162,7 +162,7 @@ UDPMessage::UDPMessage( UDPPacket& p )
size_t UDPMessage::getMessage( UDPMessage& m, UDPPacket& p )
{
memset(&m,0,sizeof(m));
size_t i = 0;
memcpy(&m,&(p.data[i]),sizeof(UDPHeader));
i += sizeof(UDPHeader);
......@@ -171,7 +171,7 @@ size_t UDPMessage::getMessage( UDPMessage& m, UDPPacket& p )
size_t sz = m.acount*sizeof(UDPAData);
if( sz > sizeof(m.a_dat) )
sz = sizeof(m.a_dat);
memcpy(m.a_dat,&(p.data[i]),sz);
i += sz;
......@@ -182,16 +182,16 @@ size_t UDPMessage::getMessage( UDPMessage& m, UDPPacket& p )
memcpy(m.d_id,&(p.data[i]),sz);
i += sz;
// копируем булевые данные
size_t nbyte = m.dcount / 8*sizeof(unsigned char);
size_t nbit = m.dcount % 8*sizeof(unsigned char);
size_t nbyte = m.dcount / sizeof(unsigned char);
size_t nbit = m.dcount % sizeof(unsigned char);
sz = nbit > 0 ? nbyte + 1 : nbyte;
if( sz > sizeof(m.d_dat) )
sz = sizeof(m.d_dat);
memcpy(m.d_dat,&(p.data[i]),sz);
return i+sz;
}
// -----------------------------------------------------------------------------
......@@ -2,7 +2,7 @@
#define UDPPacket_H_
// -----------------------------------------------------------------------------
#include <list>
#include <limits>
#include <limits>
#include <ostream>
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
......@@ -23,13 +23,13 @@ namespace UniSetUDP
long procID;
size_t dcount; /*!< количество булевых величин */
size_t acount; /*!< количество аналоговых величин */
friend std::ostream& operator<<( std::ostream& os, UDPHeader& p );
friend std::ostream& operator<<( std::ostream& os, UDPHeader* p );
}__attribute__((packed));
static unsigned long MaxPacketNum = std::numeric_limits<unsigned long>::max();
struct UDPAData
{
UDPAData():id(UniSetTypes::DefaultObjectId),val(0){}
......@@ -37,15 +37,13 @@ namespace UniSetUDP
long id;
long val;
friend std::ostream& operator<<( std::ostream& os, UDPAData& p );
}__attribute__((packed));
// Хотелось бы не вылезать за общий размер посылаемых пакетов 8192. (550,900 --> 8133)
static const size_t MaxACount = 550;
static const size_t MaxDCount = 900;
static const size_t MaxDDataCount = 1 + MaxDCount / 8*sizeof(unsigned char);
static const size_t MaxACount = 200;
static const size_t MaxDCount = 400;
static const size_t MaxDDataCount = MaxDCount / sizeof(unsigned char);
struct UDPPacket
{
......@@ -63,14 +61,14 @@ namespace UniSetUDP
UDPMessage();
UDPMessage( UDPPacket& p );
size_t transport_msg( UDPPacket& p );
size_t transport_msg( UDPPacket& p );
static size_t getMessage( UDPMessage& m, UDPPacket& p );
size_t addDData( long id, bool val );
bool setDData( size_t index, bool val );
long dID( size_t index );
bool dValue( size_t index );
size_t addAData( const UDPAData& dat );
size_t addAData( long id, long val );
bool setAData( size_t index, long val );
......@@ -79,14 +77,14 @@ namespace UniSetUDP
inline int dsize(){ return dcount; }
inline int asize(){ return acount; }
// inline int byte_size(){ return (dcount*sizeof(long)*UDPDData) + acount*sizeof(UDPAData)); }
// количество байт в пакете с булевыми переменными...
int d_byte(){ return dcount*sizeof(long) + dcount; }
UDPAData a_dat[MaxACount]; /*!< аналоговые величины */
long d_id[MaxDCount]; /*!< список дискретных ID */
unsigned char d_dat[MaxDDataCount]; /*!< битовые значения */
friend std::ostream& operator<<( std::ostream& os, UDPMessage& p );
};
}
......
......@@ -15,26 +15,26 @@
#include "UNetSender.h"
// -----------------------------------------------------------------------------
/*!
\page pageUNetExchangeUDP Сетевой обмен на основе UDP (UNetUDP)
- \ref pgUNetUDP_Common
- \ref pgUNetUDP_Conf
- \ref pgUNetUDP_Reserv
\section pgUNetUDP_Common Общее описание
Обмен построен на основе протокола UDP.
\page pageUNetExchange2 Сетевой обмен на основе UDP (UNet2)
- \ref pgUnet2_Common
- \ref pgUnet2_Conf
- \ref pgUnet2_Reserv
\section pgUnet2_Common Общее описание
Обмен построен на основе протокола UDP.
Основная идея заключается в том, что каждый узел на порту равном своему ID
посылает в сеть UDP-пакеты содержащие данные считанные из локальной SM. Формат данных - это набор
пар [id,value]. Другие узлы принимают их. Помимо этого данный процесс запускает
пар "id - value". Другие узлы принимают их. Помимо этого данный процесс запускает
по потоку приёма для каждого другого узла и ловит пакеты от них, сохраняя данные в SM.
\par
При своём старте процесс считывает из секции \<nodes> список узлов которые необходимо "слушать",
а также параметры своего узла. Открывает по потоку приёма на каждый узел и поток
\par
При своём старте процесс считывает из секции \<nodes> список узлов с которыми необходимо
вести обмен, а также параметры своего узла. Открывает по потоку приёма на каждый узел и поток
передачи для своих данных. Помимо этого такие же потоки для резервных каналов, если они включены
(см. \ref pgUNetUDP_Reserv ).
\section pgUNetUDP_Conf Пример конфигурирования
(см. \ref pgUnet2_Reserv ).
\section pgUnet2_Conf Пример конфигурирования
По умолчанию при считывании используется \b unet_broadcast_ip (указанный в секции \<nodes>)
и \b id узла - в качестве порта.
Но можно переопределять эти параметры, при помощи указания \b unet_port и/или \b unet_broadcast_ip,
......@@ -51,25 +51,25 @@
</nodes>
\endcode
\section pgUNetUDP_Reserv Настройка резервного канала связи
\section pgUnet2_Reserv Настройка резервного канала связи
В текущей реализации поддерживается возможность обмена по двум подсетям (эзернет-каналам).
Она основана на том, что, для каждого узла помимо основного "читателя",
создаётся дополнительный "читатель"(поток) слушающий другой ip-адрес и порт.
А так же, для локального узла создаётся дополнительный "писатель"(поток),
который посылает данные в (указанную) вторую подсеть. Для того, чтобы задействовать
создаётся дополнительный "читатель"(поток) слушающий другой ip-адрес и порт.
А так же, для локального узла создаётся дополнительный "писатель"(поток),
который посылает данные в (указанную) вторую подсеть. Для того, чтобы задействовать
второй канал, достаточно объявить в настройках переменные
\b unet_broadcast_ip2. А также в случае необходимости для конкретного узла
\b unet_broadcast_ip2. А также в случае необходимости для конкретного узла
можно указать \b unet_broadcast_ip2 и \b unet_port2.
Переключение между "каналами" происходит по следующей логике:
При старте включается только первый канал. Второй канал работает в режиме "пассивного" чтения.
Т.е. все пакеты принимаются, но данные в SharedMemory не сохраняются.
Если во время работы пропадает связь по первому каналу, идёт переключение на второй канал.
При старте включается только первый канал. Второй канал работает в режиме "пассивного" чтения.
Т.е. все пакеты принимаются, но данные в SharedMemory не обновляются.
Если во время работы пропадает связь по первому каналу, идёт переключение на второй канал.
Первый канал переводиться в "пассивный" режим, а второй канал, переводится в "нормальный"(активный)
режим. Далее работа ведётся по второму каналу, независимо от того, что связь на первом
канале может восстановиться. Это сделано для защиты от постоянных перескакиваний
с канала на канал. Работа на втором канале будет вестись, пока не пропадёт связь
режим. Далее работа ведётся по второму каналу, независимо от того, что связь на первом
канале может восстановиться. Это сделано для защиты от постоянных перескакиваний
с канала на канал. Работа на втором канале будет вестись, пока не пропадёт связь
на нём. Тогда будет попытка переключиться обратно на первый канал и так "по кругу".
В свою очередь "писатели"(если они не отключены) всегда посылают данные в оба канала.
......@@ -79,17 +79,17 @@ class UNetExchange:
public UniSetObject_LT
{
public:
UNetExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0, const std::string& prefix="unet" );
UNetExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
virtual ~UNetExchange();
/*! глобальная функция для инициализации объекта */
static UNetExchange* init_unetexchange( int argc, const char* argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0, const std::string& prefix="unet" );
UniSetTypes::ObjectId shmID, SharedMemory* ic=0 );
/*! глобальная функция для вывода help-а */
static void help_print( int argc, const char* argv[] );
bool checkExistUNetHost( const std::string& host, ost::tpport_t port );
bool checkExistUNetHost( const std::string host, ost::tpport_t port );
protected:
......@@ -109,13 +109,13 @@ class UNetExchange:
void receiverEvent( UNetReceiver* r, UNetReceiver::Event ev );
virtual bool activateObject();
// действия при завершении работы
virtual void sigterm( int signo );
void initIterators();
void startReceivers();
enum Timer
{
......@@ -142,7 +142,6 @@ class UNetExchange:
{
ReceiverInfo():r1(0),r2(0),
sidRespond(UniSetTypes::DefaultObjectId),
respondInvert(false),
sidLostPackets(UniSetTypes::DefaultObjectId)
{}
......@@ -152,21 +151,21 @@ class UNetExchange:
respondInvert(false),
sidLostPackets(UniSetTypes::DefaultObjectId)
{}
UNetReceiver* r1; /*!< приём по первому каналу */
UNetReceiver* r2; /*!< приём по второму каналу */
void step( SMInterface* shm, const std::string& myname );
void step( SMInterface* shm, const std::string myname );
inline void setRespondID( UniSetTypes::ObjectId id, bool invert=false )
{
sidRespond = id;
{
sidRespond = id;
respondInvert = invert;
}
inline void setLostPacketsID( UniSetTypes::ObjectId id ){ sidLostPackets = id; }
inline void initIterators( SMInterface* shm )
{
shm->initAIterator(aitLostPackets);
shm->initAIterator(aitLostPackets);
shm->initDIterator(ditRespond);
}
......@@ -180,7 +179,7 @@ class UNetExchange:
UniSetTypes::ObjectId sidLostPackets;
IOController::AIOStateList::iterator aitLostPackets;
};
typedef std::list<ReceiverInfo> ReceiverList;
ReceiverList recvlist;
......
......@@ -19,13 +19,12 @@ bool UNetReceiver::PacketCompare::operator()(const UniSetUDP::UDPMessage& lhs,
}
*/
// ------------------------------------------------------------------------------------------
UNetReceiver::UNetReceiver( const std::string& s_host, const ost::tpport_t port, SMInterface* smi ):
UNetReceiver::UNetReceiver( const std::string s_host, const ost::tpport_t port, SMInterface* smi ):
shm(smi),
recvpause(10),
updatepause(100),
udp(0),
recvTimeout(5000),
prepareTime(2000),
lostTimeout(5000),
lostPackets(0),
sidRespond(UniSetTypes::DefaultObjectId),
......@@ -50,7 +49,7 @@ a_cache_init_ok(false)
s << "R(" << setw(15) << s_host << ":" << setw(4) << port << ")";
myname = s.str();
}
ost::Thread::setException(ost::Thread::throwException);
try
{
......@@ -74,12 +73,11 @@ a_cache_init_ok(false)
dlog[Debug::CRIT] << 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);
ptPrepare.setTiming(prepareTime);
}
// -----------------------------------------------------------------------------
UNetReceiver::~UNetReceiver()
......@@ -95,12 +93,6 @@ void UNetReceiver::setReceiveTimeout( timeout_t msec )
ptRecvTimeout.setTiming(msec);
}
// -----------------------------------------------------------------------------
void UNetReceiver::setPrepareTime( timeout_t msec )
{
prepareTime = msec;
ptPrepare.setTiming(msec);
}
// -----------------------------------------------------------------------------
void UNetReceiver::setLostTimeout( timeout_t msec )
{
lostTimeout = msec;
......@@ -141,18 +133,16 @@ void UNetReceiver::setLostPacketsID( UniSetTypes::ObjectId id )
}
// -----------------------------------------------------------------------------
void UNetReceiver::setLockUpdate( bool st )
{
{
uniset_mutex_lock l(lockMutex,200);
lockUpdate = st;
if( !st )
ptPrepare.reset();
lockUpdate = st;
}
// -----------------------------------------------------------------------------
void UNetReceiver::resetTimeout()
{
{
uniset_mutex_lock l(tmMutex,200);
ptRecvTimeout.reset();
trTimeout.change(false);
ptRecvTimeout.reset();
trTimeout.change(false);
}
// -----------------------------------------------------------------------------
void UNetReceiver::start()
......@@ -167,7 +157,7 @@ void UNetReceiver::start()
// -----------------------------------------------------------------------------
void UNetReceiver::update()
{
cerr << "******************* update start" << endl;
cerr << "******************* udpate start" << endl;
while(activated)
{
try
......@@ -182,7 +172,7 @@ void UNetReceiver::update()
{
dlog[Debug::CRIT] << myname << "(update): catch ..." << std::endl;
}
if( sidRespond!=DefaultObjectId )
{
try
......@@ -195,7 +185,7 @@ void UNetReceiver::update()
dlog[Debug::CRIT] << myname << "(step): (respond) " << ex << std::endl;
}
}
if( sidLostPackets!=DefaultObjectId )
{
try
......@@ -207,7 +197,7 @@ void UNetReceiver::update()
dlog[Debug::CRIT] << myname << "(step): (lostPackets) " << ex << std::endl;
}
}
msleep(updatepause);
}
}
......@@ -278,10 +268,10 @@ void UNetReceiver::real_update()
{
try
{
long id = p.dID(i);
bool val = p.dValue(i);
ItemInfo& ii(d_icache[i]);
if( ii.id != id )
{
......@@ -297,17 +287,17 @@ void UNetReceiver::real_update()
if( lockUpdate )
continue;
}
if( ii.iotype == UniversalIO::DigitalInput )
shm->localSaveState(ii.dit,id,val,shm->ID());
else if( ii.iotype == UniversalIO::AnalogInput )
shm->localSaveValue(ii.ait,id,val,shm->ID());
else if( ii.iotype == UniversalIO::AnalogOutput )
shm->localSetValue(ii.ait,id,val,shm->ID());
else if( ii.iotype == UniversalIO::DigitalOutput )
else if( ii.iotype == UniversalIO::DigitalOutput )
shm->localSetState(ii.dit,id,val,shm->ID());
else
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << id << endl;
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << id << endl;
}
catch( UniSetTypes::Exception& ex)
{
......@@ -318,7 +308,7 @@ void UNetReceiver::real_update()
dlog[Debug::CRIT] << myname << "(update): catch ..." << std::endl;
}
}
// Обработка аналоговых
for( size_t i=0; i<p.acount; i++ )
{
......@@ -340,17 +330,17 @@ void UNetReceiver::real_update()
if( lockUpdate )
continue;
}
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 )
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;
dlog[Debug::CRIT] << myname << "(update): Unknown iotype for sid=" << d.id << endl;
}
catch( UniSetTypes::Exception& ex)
{
......@@ -399,7 +389,7 @@ void UNetReceiver::receive()
catch(...)
{
dlog[Debug::WARN] << myname << "(receive): catch ..." << std::endl;
}
}
// делаем через промежуточную переменную
// чтобы поскорее освободить mutex
......@@ -407,9 +397,8 @@ void UNetReceiver::receive()
uniset_mutex_lock l(tmMutex,100);
tout = ptRecvTimeout.checkTime();
}
// только если "режим подготовки закончился, то можем генерировать "события"
if( ptPrepare.checkTime() && trTimeout.change(tout) )
if( trTimeout.change(tout) )
{
if( tout )
slEvent(this,evTimeout);
......@@ -452,7 +441,7 @@ bool UNetReceiver::recv()
while( !qtmp.empty() )
qtmp.pop();
}
waitClean = true;
}
......
......@@ -50,7 +50,7 @@
class UNetReceiver
{
public:
UNetReceiver( const std::string& host, const ost::tpport_t port, SMInterface* smi );
UNetReceiver( const std::string host, const ost::tpport_t port, SMInterface* smi );
~UNetReceiver();
void start();
......@@ -73,7 +73,6 @@ class UNetReceiver
void setReceivePause( timeout_t msec );
void setUpdatePause( timeout_t msec );
void setLostTimeout( timeout_t msec );
void setPrepareTime( timeout_t msec );
void setMaxDifferens( unsigned long set );
void setRespondID( UniSetTypes::ObjectId id, bool invert=false );
......@@ -84,7 +83,7 @@ class UNetReceiver
inline ost::IPV4Address getAddress(){ return addr; }
inline ost::tpport_t getPort(){ return port; }
/*! Коды событий */
/*! Коды событий */
enum Event
{
evOK, /*!< связь есть */
......@@ -117,9 +116,7 @@ class UNetReceiver
UniSetTypes::uniset_mutex pollMutex;
PassiveTimer ptRecvTimeout;
PassiveTimer ptPrepare;
timeout_t recvTimeout;
timeout_t prepareTime;
timeout_t lostTimeout;
PassiveTimer ptLostTimeout;
unsigned long lostPackets; /*!< счётчик потерянных пакетов */
......@@ -131,7 +128,7 @@ class UNetReceiver
IOController::AIOStateList::iterator aitLostPackets;
bool activated;
ThreadCreator<UNetReceiver>* r_thr; // receive thread
ThreadCreator<UNetReceiver>* u_thr; // update thread
......@@ -158,12 +155,12 @@ class UNetReceiver
PacketQueue qtmp; /*!< очередь на время обработки(очистки) основной очереди */
bool waitClean; /*!< флаг означающий, что ждём очистики очереди до конца */
unsigned long rnum; /*!< текущий номер принятого сообщения, для проверки "переполнения" или "сбоя" счётчика */
int maxProcessingCount; /*!< максимальное число обрабатываемых за один раз сообщений */
bool lockUpdate; /*!< флаг блокировки сохранения принятых данных в SM */
UniSetTypes::uniset_mutex lockMutex;
EventSlot slEvent;
Trigger trTimeout;
UniSetTypes::uniset_mutex tmMutex;
......
......@@ -78,7 +78,7 @@ s_thr(0)
// -----------------------------------------------------------------------------
UNetSender::~UNetSender()
{
delete s_thr;
delete s_thr;
delete udp;
delete shm;
}
......@@ -106,9 +106,6 @@ void UNetSender::updateFromSM()
// -----------------------------------------------------------------------------
void UNetSender::updateSensor( UniSetTypes::ObjectId id, long value )
{
if( !shm->isLocalwork() )
return;
// cerr << myname << ": UPDATE SENSOR id=" << id << " value=" << value << endl;
DMap::iterator it=dlist.begin();
for( ; it!=dlist.end(); ++it )
......@@ -145,7 +142,7 @@ void UNetSender::send()
/*
ost::IPV4Broadcast h = s_host.c_str();
try
{
{
udp->setPeer(h,port);
}
catch( ost::SockException& e )
......@@ -162,7 +159,7 @@ void UNetSender::send()
{
if( !shm->isLocalwork() )
updateFromSM();
real_send();
}
catch( ost::SockException& e )
......@@ -180,7 +177,7 @@ void UNetSender::send()
catch(...)
{
dlog[Debug::WARN] << myname << "(send): catch ..." << std::endl;
}
}
msleep(sendpause);
}
......@@ -257,7 +254,7 @@ bool UNetSender::initItem( UniXML_iterator& it )
string sname( it.getProp("name") );
string tid(it.getProp("id"));
ObjectId sid;
if( !tid.empty() )
{
......@@ -275,10 +272,10 @@ bool UNetSender::initItem( UniXML_iterator& it )
<< sname << endl;
return false;
}
UItem p;
p.iotype = UniSetTypes::getIOType(it.getProp("iotype"));
if( p.iotype == UniversalIO::UnknownIOType )
{
dlog[Debug::CRIT] << myname << "(readItem): Unknown iotype for sid=" << sid << endl;
......@@ -292,11 +289,9 @@ bool UNetSender::initItem( UniXML_iterator& it )
p.pack_ind = mypack.addDData(sid,0);
if ( p.pack_ind >= UniSetUDP::MaxDCount )
{
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP DIGITAL DATA LIMIT! max="
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP DIGITAL DATA LIMIT! max="
<< UniSetUDP::MaxDCount << endl;
raise(SIGTERM);
return false;
}
}
......@@ -305,17 +300,16 @@ bool UNetSender::initItem( UniXML_iterator& it )
p.pack_ind = mypack.addAData(sid,0);
if ( p.pack_ind >= UniSetUDP::MaxACount )
{
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP ANALOG DATA LIMIT! max="
dlog[Debug::CRIT] << myname
<< "(readItem): OVERFLOW! MAX UDP ANALOG DATA LIMIT! max="
<< UniSetUDP::MaxACount << endl;
raise(SIGTERM);
return false;
}
}
if( maxItem >= dlist.size() )
dlist.resize(maxItem+10);
dlist[maxItem] = p;
maxItem++;
......
......@@ -23,7 +23,7 @@ class UNetSender
const std::string s_field="", const std::string s_fvalue="", SharedMemory* ic=0 );
~UNetSender();
struct UItem
{
UItem():
......@@ -39,7 +39,7 @@ class UNetSender
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
typedef std::vector<UItem> DMap;
void start();
......@@ -47,7 +47,7 @@ class UNetSender
void send();
void real_send();
/*! (принудительно) обновить все данные (из SM) */
void updateFromSM();
......@@ -58,13 +58,13 @@ class UNetSender
void updateItem( DMap::iterator& it, long value );
inline void setSendPause( int msec ){ sendpause = msec; }
/*! заказать датчики */
void askSensors( UniversalIO::UIOCommand cmd );
/*! инициализация итераторов */
void initIterators();
protected:
std::string s_field;
......@@ -88,7 +88,7 @@ class UNetSender
std::string myname;
int sendpause;
bool activated;
UniSetTypes::uniset_mutex pack_mutex;
UniSetUDP::UDPMessage mypack;
DMap dlist;
......
......@@ -4,4 +4,3 @@ uniset-start.sh -f ./uniset-unetexchange --unet-name UNetExchange \
--confile test.xml --smemory-id SharedMemory \
--unet-filter-field rs --unet-filter-value 2 --unet-maxdifferense 40 \
--dlog-add-levels info,crit,warn
......@@ -33,7 +33,7 @@ enum Command
cmdReceive
};
// --------------------------------------------------------------------------
static bool split_addr( const string& addr, string& host, ost::tpport_t& port )
static bool split_addr( const string addr, string& host, ost::tpport_t& port )
{
string::size_type pos = addr.rfind(':');
if( pos != string::npos )
......@@ -43,7 +43,7 @@ static bool split_addr( const string& addr, string& host, ost::tpport_t& port )
port = UniSetTypes::uni_atoi(s_port.c_str());
return true;
}
return false;
}
// --------------------------------------------------------------------------
......@@ -65,11 +65,11 @@ int main(int argc, char* argv[])
bool show = false;
int ncycles = -1;
while( (opt = getopt_long(argc, argv, "hs:c:r:p:n:t:x:blvdz:",longopts,&optindex)) != -1 )
while( (opt = getopt_long(argc, argv, "hs:c:r:p:n:t:x:blvdz:",longopts,&optindex)) != -1 )
{
switch (opt)
switch (opt)
{
case 'h':
case 'h':
cout << "-h|--help - this message" << endl;
cout << "[-s|--send] host:port - Send message." << endl;
cout << "[-c|--data-count] num - Send num count of value. Default: 50." << endl;
......@@ -86,7 +86,7 @@ int main(int argc, char* argv[])
cout << endl;
return 0;
case 'r':
case 'r':
cmd = cmdReceive;
addr = string(optarg);
break;
......@@ -95,54 +95,54 @@ int main(int argc, char* argv[])
addr = string(optarg);
cmd = cmdSend;
break;
case 't':
tout = UniSetTypes::uni_atoi(optarg);
break;
break;
case 'x':
usecpause = UniSetTypes::uni_atoi(optarg)*1000;
break;
break;
case 'c':
count = UniSetTypes::uni_atoi(optarg);
break;
break;
case 'p':
procID = UniSetTypes::uni_atoi(optarg);
break;
break;
case 'n':
nodeID = UniSetTypes::uni_atoi(optarg);
break;
break;
case 'b':
broadcast = false;
break;
break;
case 'd':
show = true;
break;
break;
case 'l':
lost = true;
break;
case 'v':
break;
case 'v':
verb = 1;
break;
case 'z':
ncycles = UniSetTypes::uni_atoi(optarg);
break;
case '?':
default:
cerr << "? argumnet" << endl;
return 0;
}
}
if( cmd == cmdNOP )
{
cerr << "No command... Use -h for help" << endl;
......@@ -153,7 +153,7 @@ int main(int argc, char* argv[])
tout = TIMEOUT_INF;
ost::Thread::setException(ost::Thread::throwException);
try
{
string s_host;
......@@ -162,10 +162,10 @@ int main(int argc, char* argv[])
cerr << "(main): Unknown 'host:port' for '" << addr << "'" << endl;
return 1;
}
if( verb )
{
cout << " host=" << s_host
cout << " host=" << s_host
<< " port=" << port
<< " timeout=";
if( tout == TIMEOUT_INF )
......@@ -173,7 +173,7 @@ int main(int argc, char* argv[])
else
cout << tout;
cout << " msecpause=" << usecpause/1000
cout << " msecpause=" << usecpause/1000
<< endl;
}
......@@ -185,7 +185,7 @@ int main(int argc, char* argv[])
case cmdReceive:
{
ost::UDPDuplex udp(host,port);
// char buf[UniSetUDP::MaxDataLen];
UniSetUDP::UDPMessage pack;
UniSetUDP::UDPPacket buf;
......@@ -204,22 +204,22 @@ int main(int argc, char* argv[])
cout << "(recv): Timeout.." << endl;
continue;
}
size_t ret = udp.UDPReceive::receive( &(buf.data), sizeof(buf.data) );
size_t sz = UniSetUDP::UDPMessage::getMessage(pack,buf);
if( sz == 0 )
{
cerr << "(recv): FAILED header ret=" << ret
cerr << "(recv): FAILED header ret=" << ret
<< " sizeof=" << sz<< endl;
continue;
}
if( lost )
{
if( prev_num != (pack.num-1) )
cerr << "WARNING! Incorrect sequence of packets! current=" << pack.num
<< " prev=" << prev_num << endl;
prev_num = pack.num;
}
......@@ -238,7 +238,7 @@ int main(int argc, char* argv[])
{
cerr << "(recv): catch ..." << endl;
}
if( ncycles > 0 )
{
nc--;
......@@ -248,14 +248,14 @@ int main(int argc, char* argv[])
}
}
break;
case cmdSend:
{
{
ost::UDPSocket* udp;
if( !broadcast )
udp = new ost::UDPSocket();
else
udp = new ost::UDPBroadcast(host,port);
if( !broadcast )
udp = new ost::UDPSocket();
else
udp = new ost::UDPBroadcast(host,port);
UniSetUDP::UDPMessage mypack;
mypack.nodeID = nodeID;
......@@ -266,7 +266,7 @@ int main(int argc, char* argv[])
UDPAData d(i,i);
mypack.addAData(d);
}
for( unsigned int i=0; i < count; i++ )
mypack.addDData(i,i);
......@@ -274,7 +274,7 @@ int main(int argc, char* argv[])
unsigned long packetnum = 0;
UniSetUDP::UDPPacket s_buf;
int nc = 1;
if( ncycles > 0 )
nc = ncycles;
......@@ -292,12 +292,12 @@ int main(int argc, char* argv[])
mypack.transport_msg(s_buf);
if( verb )
cout << "(send): to addr=" << addr << " d_count=" << mypack.dcount
cout << "(send): to addr=" << addr << " d_count=" << mypack.dcount
<< " a_count=" << mypack.acount << " bytes=" << s_buf.len << endl;
size_t ret = udp->send((char*)&s_buf.data, s_buf.len);
if( ret < s_buf.len )
cerr << "(send): FAILED ret=" << ret << " < sizeof=" << s_buf.len << endl;
cerr << "(send): FAILED ret=" << ret << " < sizeof=" << s_buf.len << endl;
}
}
catch( ost::SockException& e )
......@@ -315,7 +315,7 @@ int main(int argc, char* argv[])
if( nc <=0 )
break;
}
usleep(usecpause);
}
}
......@@ -336,7 +336,7 @@ int main(int argc, char* argv[])
cerr << "(main): catch ..." << endl;
return 1;
}
return 0;
}
// --------------------------------------------------------------------------
......@@ -27,8 +27,8 @@ int main( int argc, const char** argv )
string logfilename(conf->getArgParam("--unet-logfile"));
if( logfilename.empty() )
logfilename = "udpexchange.log";
std::ostringstream logname;
string dir(conf->getLogDir());
logname << dir << logfilename;
......@@ -59,7 +59,7 @@ int main( int argc, const char** argv )
ObjectsActivator act;
act.addObject(static_cast<class UniSetObject*>(unet));
SystemMessage sm(SystemMessage::StartUp);
SystemMessage sm(SystemMessage::StartUp);
act.broadcast( sm.transport_msg() );
unideb(Debug::ANY) << "\n\n\n";
......
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