Commit 765d93f8 authored by Pavel Vainerman's avatar Pavel Vainerman

(UNetUDP): работа над "ОПТИМИЗАЦИЯ N1", дополнительно начал реализовывать тесты

parent 2a9b5be2
......@@ -219,6 +219,7 @@ if test ${buildtests} = true; then
AC_CONFIG_TESTDIR(extensions/tests)
AC_CONFIG_TESTDIR(extensions/LogicProcessor/tests)
AC_CONFIG_TESTDIR(extensions/ModbusSlave/tests)
AC_CONFIG_TESTDIR(extensions/UNetUDP/tests)
TESTSUITE_DIR="\$(top_builddir)/testsuite"
AC_SUBST(TESTSUITE_DIR)
......@@ -338,6 +339,7 @@ AC_CONFIG_FILES([Makefile
extensions/UniNetwork/libUniSet2Network.pc
extensions/UNetUDP/Makefile
extensions/UNetUDP/libUniSet2UNetUDP.pc
extensions/UNetUDP/tests/Makefile
extensions/SharedMemory/Makefile
extensions/SharedMemory/libUniSet2SharedMemory.pc
extensions/SharedMemoryPlus/Makefile
......
......@@ -4,7 +4,7 @@
if HAVE_EXTENTIONS
SUBDIRS = lib include SharedMemory IOControl LogicProcessor \
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP DBServer-MySQL DBServer-SQLite \
ModbusMaster ModbusSlave SMViewer UniNetwork UNetUDP UNetUDP/tests DBServer-MySQL DBServer-SQLite \
RRDServer SharedMemoryPlus tests ModbusSlave/tests
#SMDBServer
......
......@@ -3,6 +3,79 @@
using namespace std;
using namespace UniSetUDP;
// -----------------------------------------------------------------------------
#define USE_CRC_TAB 1 // при расчёте использовать таблицы
// -------------------------------------------------------------------------
#ifdef USE_CRC_TAB
static unsigned short crc_16_tab[] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
#endif
// -------------------------------------------------------------------------
/* CRC-16 is based on the polynomial x^16 + x^15 + x^2 + 1. Bits are */
/* sent LSB to MSB. */
static int get_crc_16( unsigned short crc, unsigned char* buf, int size )
{
while( size-- )
{
#ifdef USE_CRC_TAB
crc = (crc >> 8) ^ crc_16_tab[ (crc ^ *(buf++)) & 0xff ];
#else
register int i, ch;
ch = *(buf++);
for (i = 0; i < 8; i++)
{
if ((crc ^ ch) & 1)
crc = (crc >> 1) ^ 0xa001;
else
crc >>= 1;
ch >>= 1;
}
#endif
// crc = crc & 0xffff;
}
return crc;
}
// -------------------------------------------------------------------------
unsigned short UniSetUDP::makeCRC( unsigned char* buf, size_t len )
{
unsigned short crc = 0xffff;
crc = get_crc_16(crc,(unsigned char*)(buf), len);
return crc;
}
// -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader& p )
{
return os << "nodeID=" << p.nodeID
......@@ -202,3 +275,12 @@ size_t UDPMessage::getMessage( UDPMessage& m, UDPPacket& p )
return i+sz;
}
// -----------------------------------------------------------------------------
unsigned short UDPMessage::getDataCRC()
{
unsigned short crc[3];
crc[0] = makeCRC( (unsigned char*)(a_dat), sizeof(a_dat) );
crc[1] = makeCRC( (unsigned char*)(d_id), sizeof(d_id) );
crc[2] = makeCRC( (unsigned char*)(d_dat), sizeof(d_dat) );
return makeCRC( (unsigned char*)(&crc), sizeof(crc) );
}
// -----------------------------------------------------------------------------
\ No newline at end of file
......@@ -82,6 +82,7 @@ namespace UniSetUDP
inline bool isFull(){ return ((dcount<MaxDCount) && (acount<MaxACount)); }
inline int dsize(){ return dcount; }
inline int asize(){ return acount; }
unsigned short getDataCRC();
// количество байт в пакете с булевыми переменными...
int d_byte(){ return dcount*sizeof(long) + dcount; }
......@@ -92,6 +93,8 @@ namespace UniSetUDP
friend std::ostream& operator<<( std::ostream& os, UDPMessage& p );
};
unsigned short makeCRC( unsigned char* buf, size_t len );
}
// -----------------------------------------------------------------------------
#endif // UDPPacket_H_
......
......@@ -508,6 +508,7 @@ void UNetExchange::sysCommand( const UniSetTypes::SystemMessage *sm )
case SystemMessage::WatchDog:
{
startReceivers(); // если уже запущены, то это приведёт к вызову UNetReceiver::forceUpdate() ( см. UNetReceiver::start() )
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт автономная работа, то нужно заказывать датчики
// если запущены в одном процессе с SharedMemory2,
......@@ -655,7 +656,7 @@ void UNetExchange::help_print( int argc, const char* argv[] )
cout << "--prefix-filter-value name - Значение фильтрующего поля при формировании списка датчиков посылаемых данным узлом" << endl;
}
// -----------------------------------------------------------------------------
UNetExchange* UNetExchange::init_unetexchange( int argc, const char* argv[], UniSetTypes::ObjectId icID,
UNetExchange* UNetExchange::init_unetexchange( int argc, const char* const argv[], UniSetTypes::ObjectId icID,
SharedMemory* ic, const std::string& prefix )
{
auto conf = uniset_conf();
......
......@@ -84,7 +84,7 @@ class UNetExchange:
virtual ~UNetExchange();
/*! глобальная функция для инициализации объекта */
static UNetExchange* init_unetexchange( int argc, const char* argv[],
static UNetExchange* init_unetexchange( int argc, const char* const argv[],
UniSetTypes::ObjectId shmID, SharedMemory* ic=0, const std::string& prefix="unet" );
/*! глобальная функция для вывода help-а */
......
......@@ -164,6 +164,8 @@ void UNetReceiver::start()
u_thr->start();
r_thr->start();
}
else
forceUpdate();
}
// -----------------------------------------------------------------------------
void UNetReceiver::update()
......@@ -213,6 +215,13 @@ void UNetReceiver::update()
}
}
// -----------------------------------------------------------------------------
void UNetReceiver::forceUpdate()
{
uniset_rwmutex_wrlock l(packMutex);
pnum = 0; // сбрасываем запомненый номер последнего обработанного пакета
// и тем самым заставляем обновить данные в SM (см. real_update)
}
// -----------------------------------------------------------------------------
void UNetReceiver::real_update()
{
UniSetUDP::UDPMessage p;
......
......@@ -45,6 +45,8 @@
* и данные которые в ней были теряются! Аналог ограниченного буфера (у любых карт), когда новые данные
* затирают старые, если их не успели вынуть и обработать.
* \todo Сделать защиту от бесконечного ожидания "очистки" основной очереди.
* =========================================================================
* ОПТИМИЗАЦИЯ N1: см. UNetSender.h. Если номер последнего принятого пакета не менялся.. не обрабатываем..
*/
// -----------------------------------------------------------------------------
class UNetReceiver
......@@ -81,6 +83,8 @@ class UNetReceiver
void setMaxProcessingCount( int set );
void forceUpdate(); // пересохранить очередной пакет в SM даже если данные не менялись
inline ost::IPV4Address getAddress(){ return addr; }
inline ost::tpport_t getPort(){ return port; }
......
......@@ -19,6 +19,7 @@ activated(false),
dlist(100),
maxItem(0),
packetnum(1),
lastcrc(0),
s_thr(0)
{
......@@ -176,11 +177,21 @@ void UNetSender::send()
dinfo << "************* execute FINISH **********" << endl;
}
// -----------------------------------------------------------------------------
// #define UNETUDP_DISABLE_OPTIMIZATION_N1
void UNetSender::real_send()
{
UniSetTypes::uniset_rwmutex_rlock l(pack_mutex);
#ifdef UNETUDP_DISABLE_OPTIMIZATION_N1
mypack.num = packetnum++;
#else
unsigned short crc = mypack.getDataCRC();
if( crc != lastcrc )
{
mypack.num = packetnum++;
lastcrc = crc;
}
#endif
if( packetnum > UniSetUDP::MaxPacketNum )
packetnum = 1;
......
......@@ -14,7 +14,9 @@
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
/*
*
* ОПТИМИЗАЦИЯ N1: Для оптимизации обработки посылаемых пакетов (на стороне UNetReceiver) следана следующая логика:
* Номер очередного посылаемого пакета меняется (увеличивается) только, если изменились данные с момента
последней посылки. Для по данным каждый раз производится расчёт UNetUDP::makeCRC() и сравнивается с последним..
*/
class UNetSender
{
......@@ -93,6 +95,7 @@ class UNetSender
DMap dlist;
int maxItem;
unsigned long packetnum;
unsigned short lastcrc;
UniSetUDP::UDPPacket s_msg;
ThreadCreator<UNetSender>* s_thr; // send thread
......
if HAVE_TESTS
noinst_PROGRAMS = tests-with-sm
tests_with_sm_SOURCES = tests_with_sm.cc test_unetudp.cc
tests_with_sm_LDADD = $(top_builddir)/lib/libUniSet2.la $(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(top_builddir)/extensions/UNetUDP/libUniSet2UNetUDP.la \
$(top_builddir)/extensions/SharedMemory/libUniSet2SharedMemory.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
tests_with_sm_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/extensions/include \
-I$(top_builddir)/extensions/UNetUDP \
-I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
include $(top_builddir)/testsuite/testsuite-common.mk
check-local: atconfig package.m4 $(TESTSUITE) unetudp-tests.at
$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS)
clean-local:
rm -rf $(CLEANFILES)
rm -rf $(COVERAGE_REPORT_DIR)
if HAVE_COVERAGE
include $(top_builddir)/testsuite/testsuite-coverage-common.mk
endif
endif
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <cc++/socket.h>
#include "UniSetTypes.h"
#include "UInterface.h"
#include "UDPPacket.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static int port = 3000;
static ost::IPV4Host host("127.255.255.255");
static UInterface* ui = nullptr;
static ObjectId aid = 2;
static ost::UDPDuplex* udp_r = nullptr;
// -----------------------------------------------------------------------------
void InitTest()
{
auto conf = uniset_conf();
CHECK( conf!=nullptr );
if( ui == nullptr )
{
ui = new UInterface();
// UI понадобиться для проверки записанных в SM значений.
CHECK( ui->getObjectIndex() != nullptr );
CHECK( ui->getConf() == conf );
CHECK( ui->waitReady(aid,10000) );
}
if( udp_r == nullptr )
udp_r = new ost::UDPDuplex(host,port);
}
// -----------------------------------------------------------------------------
static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 2000, int ncycle = 1000 )
{
UniSetUDP::UDPMessage pack;
UniSetUDP::UDPPacket buf;
while( ncycle > 0 )
{
if( !udp_r->isInputReady(tout) )
break;
size_t ret = udp_r->UDPReceive::receive( &(buf.data), sizeof(buf.data) );
size_t sz = UniSetUDP::UDPMessage::getMessage(pack,buf);
if( pnum ==0 || ( pnum > 0 && pack.num >= pnum ) )
break;
ncycle--;
}
return std::move(pack);
}
// -----------------------------------------------------------------------------
TEST_CASE("[UNetUDP]: respond sensor","[unetudp]")
{
InitTest();
// в запускающем файле стоит --unet-recv-timeout 2000
msleep(2500);
ObjectId node1_not_respond_s = 1;
REQUIRE( ui->getValue(node1_not_respond_s) == 1 );
}
// -----------------------------------------------------------------------------
TEST_CASE("[UNetUDP]: check sender","[unetudp][sender]")
{
InitTest();
SECTION("Test: read default pack...")
{
UniSetUDP::UDPMessage pack = receive();
REQUIRE( pack.num!=0 );
REQUIRE( pack.asize()==4 );
REQUIRE( pack.dsize()==2 );
for( int i=0; i<pack.asize(); i++ )
{
REQUIRE( pack.a_dat[i].val == i+1 );
}
REQUIRE( pack.dValue(0) == 1 );
REQUIRE( pack.dValue(1) == 0 );
// т.к. данные в SM не менялись, то должен придти пакет с тем же номером что и был..
UniSetUDP::UDPMessage pack2 = receive();
REQUIRE( pack2.num == pack.num );
}
SECTION("Test: change data...")
{
UniSetUDP::UDPMessage pack0 = receive();
ui->setValue(2,100);
REQUIRE( ui->getValue(2) == 100 );
msleep(120);
UniSetUDP::UDPMessage pack = receive( pack0.num+1 );
REQUIRE( pack.num!=0 );
REQUIRE( pack.asize()==4 );
REQUIRE( pack.dsize()==2 );
REQUIRE( pack.a_dat[0].val == 100 );
ui->setValue(2,250);
REQUIRE( ui->getValue(2) == 250 );
msleep(120);
UniSetUDP::UDPMessage pack2 = receive( pack.num+1 );
REQUIRE( pack2.num!=0 );
REQUIRE( pack2.num > pack.num );
REQUIRE( pack2.asize()==4 );
REQUIRE( pack2.dsize()==2 );
REQUIRE( pack2.a_dat[0].val == 250 );
}
}
// -----------------------------------------------------------------------------
#if 0
TEST_CASE("Function (0x03): 'read register outputs or memories or read word outputs or memories'","[modbus][mbslave][mbtcpslave]")
{
InitTest();
ModbusRTU::ModbusData tREG=10;
SECTION("Test: read one reg..")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read many registers..")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,3);
REQUIRE( ret.data[0] == 10 );
REQUIRE( ret.data[1] == 11 );
REQUIRE( (signed short)(ret.data[2]) == -10 );
}
SECTION("Test: read MAXDATA count..")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,ModbusRTU::MAXDATALEN);
REQUIRE( ret.count == ModbusRTU::MAXDATALEN );
}
SECTION("Test: read TOO many registers")
{
try
{
mb->read03(slaveaddr,-23,1200);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
SECTION("Test: read unknown registers")
{
try
{
mb->read03(slaveaddr,-23,1);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: incorrect number")
{
try
{
mb->read03(slaveaddr,tREG,-3);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
SECTION("Test: zero number")
{
try
{
mb->read03(slaveaddr,tREG,0);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
}
TEST_CASE("Function (0x04): 'read input registers or memories or read word outputs or memories'","[modbus][mbslave][mbtcpslave]")
{
InitTest();
ModbusRTU::ModbusData tREG=10;
SECTION("Test: read one reg..")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read one reg..")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read many registers..")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,4);
REQUIRE( ret.data[0] == 10 );
REQUIRE( ret.data[1] == 11 );
REQUIRE( (signed short)(ret.data[2]) == -10 );
REQUIRE( (signed short)(ret.data[3]) == -10000 );
}
SECTION("Test: read MAXDATA count..")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,ModbusRTU::MAXDATALEN);
REQUIRE( ret.count == ModbusRTU::MAXDATALEN );
}
SECTION("Test: read TOO many registers")
{
try
{
mb->read04(slaveaddr,-23,1200);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
SECTION("Test: read unknown registers")
{
try
{
mb->read04(slaveaddr,-23,1);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: incorrect number")
{
try
{
mb->read04(slaveaddr,tREG,-3);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
SECTION("Test: zero number")
{
try
{
mb->read04(slaveaddr,tREG,0);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
}
TEST_CASE("(0x05): forces a single coil to either ON or OFF","[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1007;
ModbusRTU::ModbusData tREG=14;
SECTION("Test: ON")
{
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(slaveaddr,tREG,true);
CHECK( ret.start == tREG );
CHECK( ret.cmd() == true );
CHECK( ui->getValue(tID) == 1 );
}
SECTION("Test: OFF")
{
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(slaveaddr,tREG,false);
CHECK( ret.start == tREG );
CHECK( ret.cmd() == false );
CHECK( ui->getValue(tID) == 0 );
}
}
TEST_CASE("(0x06): write register outputs or memories","[modbus][mbslave][mbtcpslave]")
{
InitTest();
ObjectId tID = 1008;
ModbusRTU::ModbusData tREG=15;
SECTION("Test: write register")
{
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr,tREG,10);
REQUIRE( ret.start == tREG );
REQUIRE( ret.data == 10 );
REQUIRE( ui->getValue(tID) == 10 );
}
SECTION("Test: write negative value")
{
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr,tREG,-10);
REQUIRE( ret.start == tREG );
REQUIRE( (signed short)ret.data == -10 );
REQUIRE( (signed short)ui->getValue(tID) == -10 );
}
SECTION("Test: write zero value")
{
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr,tREG,0);
REQUIRE( ret.start == tREG );
REQUIRE( ret.data == 0 );
REQUIRE( ui->getValue(tID) == 0 );
}
SECTION("Test: write OVERFLOW VALUE")
{
WARN("FIXME: what to do in this situation?!");
#if 0
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr,15,100000);
REQUIRE( ret.start == 15 );
REQUIRE( ret.data == 34464 );
REQUIRE( ui->getValue(1008) == 34464 );
#endif
}
SECTION("Test: write unknown register")
{
try
{
mb->write06(slaveaddr,-23,10);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
}
#if 0
SECTION("(0x08): Diagnostics (Serial Line only)")
{
}
#endif
#if 0
/*! \TODO Переписать реализацию MBSlave... ввести понятие nbit. */
TEST_CASE("(0x0F): force multiple coils","[modbus][mbslave][mbtcpslave]")
{
WARN("FIXME: 'force coil status'. Use 'nbit'?"):
InitTest();
ObjectId tID = 1009;
ModbusRTU::ModbusData tREG=16;
SECTION("Test: write 2 bit to 1")
{
ModbusRTU::ForceCoilsMessage msg(slaveaddr,tREG);
ModbusRTU::DataBits b(3);
msg.addData(b);
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 8 );
REQUIRE( ui->getValue(tID) == 1 );
REQUIRE( ui->getValue(tID+1) == 1 );
}
SECTION("Test: write 2 bit to 0")
{
ModbusRTU::ForceCoilsMessage msg(slaveaddr,tREG);
ModbusRTU::DataBits b(0);
msg.addData(b);
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 8 );
REQUIRE( ui->getValue(tID) == 0 );
REQUIRE( ui->getValue(tID+1) == 0 );
}
}
#endif
TEST_CASE("(0x10): write register outputs or memories","[modbus][mbslave][mbtcpslave]")
{
InitTest();
InitTest();
ObjectId tID = 1025;
ModbusRTU::ModbusData tREG=18;
SECTION("Test: write one register")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(10);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 1 );
REQUIRE( ui->getValue(tID) == 10 );
}
SECTION("Test: write 3 register")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(10);
msg.addData(11);
msg.addData(12);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 3 );
REQUIRE( ui->getValue(tID) == 10 );
REQUIRE( ui->getValue(tID+1) == 11 );
REQUIRE( ui->getValue(tID+2) == 1 ); // 1 - т.к. это "DI"
}
SECTION("Test: write negative value")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(-10);
msg.addData(-100);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 2 );
REQUIRE( (signed short)ui->getValue(tID) == -10 );
REQUIRE( (signed short)ui->getValue(tID+1) == -100 );
}
SECTION("Test: write zero registers")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(0);
msg.addData(0);
msg.addData(0);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 3 );
REQUIRE( ui->getValue(tID) == 0 );
REQUIRE( ui->getValue(tID+1) == 0 );
REQUIRE( ui->getValue(tID+2) == 0 );
}
SECTION("Test: write OVERFLOW VALUE")
{
WARN("FIXME: what to do in this situation?!");
#if 0
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(slaveaddr,15,100000);
REQUIRE( ret.start == 15 );
REQUIRE( ret.data == 34464 );
REQUIRE( ui->getValue(1008) == 34464 );
#endif
}
SECTION("Test: write 2 good registers and unknown register")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG+1);
msg.addData(10);
msg.addData(11);
msg.addData(12); // BAD REG..
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG+1 );
WARN("FIXME: 'ret.quant' must be '3' or '2'?!");
REQUIRE( ret.quant == 3 ); // "2" ?!! \TODO узнать как нужно поступать по стандарту!
REQUIRE( ui->getValue(tID+1) == 10 );
REQUIRE( ui->getValue(tID+2) == 1 ); // 1 - т.к. это "DI"
REQUIRE( ui->getValue(tID+3) == 0 );
}
SECTION("Test: write ALL unknown registers")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG+20000);
msg.addData(10);
msg.addData(11);
msg.addData(12);
try
{
mb->write10(msg);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: write bad format packet..(incorrect data count)")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG+20000);
msg.addData(10);
msg.addData(11);
msg.addData(12);
msg.quant-=1;
try
{
mb->write10(msg);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("Test: write bad format packet..(incorrect size of bytes)")
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG+20000);
msg.addData(10);
msg.addData(11);
msg.addData(12);
msg.bcnt -= 1;
try
{
mb->write10(msg);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
}
TEST_CASE("Read(0x03,0x04): vtypes..","[modbus][mbslave][mbtcpslave]")
{
using namespace VTypes;
InitTest();
SECTION("Test: read vtype 'I2'")
{
ModbusRTU::ModbusData tREG = 100;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,I2::wsize());
I2 i2(ret.data,ret.count);
REQUIRE( (int)i2 == -100000 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,I2::wsize());
I2 i2(ret.data,ret.count);
REQUIRE( (int)i2 == -100000 );
}
}
SECTION("Test: read vtype 'I2r'")
{
ModbusRTU::ModbusData tREG = 102;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,I2r::wsize());
I2r i2r(ret.data,ret.count);
REQUIRE( (int)i2r == -100000 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,I2r::wsize());
I2r i2r(ret.data,ret.count);
REQUIRE( (int)i2r == -100000 );
}
}
SECTION("Test: read vtype 'U2'")
{
ModbusRTU::ModbusData tREG = 104;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,U2::wsize());
U2 u2(ret.data,ret.count);
REQUIRE( (unsigned int)u2 == 4294967295 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,U2::wsize());
U2 u2(ret.data,ret.count);
REQUIRE( (unsigned int)u2 == 4294967295 );
}
}
SECTION("Test: read vtype 'U2r'")
{
ModbusRTU::ModbusData tREG = 106;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,U2r::wsize());
U2r u2r(ret.data,ret.count);
REQUIRE( (unsigned int)u2r == 4294967295 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,U2r::wsize());
U2r u2r(ret.data,ret.count);
REQUIRE( (unsigned int)u2r == 4294967295 );
}
}
SECTION("Test: read vtype 'F2'")
{
ModbusRTU::ModbusData tREG = 110;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,F2::wsize());
F2 f2(ret.data,ret.count);
REQUIRE( (float)f2 == 2.5 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,F2::wsize());
F2 f2(ret.data,ret.count);
REQUIRE( (float)f2 == 2.5 );
}
}
SECTION("Test: read vtype 'F2r'")
{
ModbusRTU::ModbusData tREG = 112;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,F2r::wsize());
F2r f2r(ret.data,ret.count);
REQUIRE( (float)f2r == 2.5 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,F2r::wsize());
F2r f2r(ret.data,ret.count);
REQUIRE( (float)f2r == 2.5 );
}
}
SECTION("Test: read vtype 'F4'")
{
ModbusRTU::ModbusData tREG = 114;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,F4::wsize());
F4 f4(ret.data,ret.count);
REQUIRE( (float)f4 == 2.5 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,F4::wsize());
F4 f4(ret.data,ret.count);
REQUIRE( (float)f4 == 2.5 );
}
}
SECTION("Test: read vtype 'Byte N1'")
{
ModbusRTU::ModbusData tREG = 108;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,Byte::wsize());
Byte b(ret.data[0]);
REQUIRE( (unsigned short)b == 200 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,Byte::wsize());
Byte b(ret.data[0]);
REQUIRE( (unsigned short)b == 200 );
}
}
SECTION("Test: read vtype 'Byte N2'")
{
ModbusRTU::ModbusData tREG = 109;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,Byte::wsize());
Byte b(ret.data[0]);
REQUIRE( (unsigned short)b == 200 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,Byte::wsize());
Byte b(ret.data[0]);
REQUIRE( (unsigned short)b == 200 );
}
}
}
// -------------------------------------------------------------
static void test_write10_I2( int val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 100;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
I2 tmp(val);
msg.addData( tmp.raw.v[0] );
msg.addData( tmp.raw.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == I2::wsize() );
REQUIRE( ui->getValue(2001) == val );
}
static void test_write10_I2r( int val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 102;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
I2r tmp(val);
msg.addData( tmp.raw_backorder.v[0] );
msg.addData( tmp.raw_backorder.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == I2r::wsize() );
REQUIRE( ui->getValue(2002) == val );
}
static void test_write10_U2( unsigned int val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 104;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
U2 tmp(val);
msg.addData( tmp.raw.v[0] );
msg.addData( tmp.raw.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == U2::wsize() );
REQUIRE( (unsigned int)ui->getValue(2003) == val );
}
static void test_write10_U2r( unsigned int val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 106;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
U2r tmp(val);
msg.addData( tmp.raw_backorder.v[0] );
msg.addData( tmp.raw_backorder.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == U2r::wsize() );
REQUIRE( (unsigned int)ui->getValue(2004) == val );
}
static void test_write10_F2( const float& val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 110;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
F2 tmp(val);
msg.addData( tmp.raw.v[0] );
msg.addData( tmp.raw.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == F2::wsize() );
auto conf = uniset_conf();
IOController_i::SensorInfo si;
si.id = 2007;
si.node = conf->getLocalNode();
IOController_i::CalibrateInfo cal = ui->getCalibrateInfo(si);
float fval = (float)ui->getValue(si.id) / pow10(cal.precision);
REQUIRE( fval == val );
}
static void test_write10_F2r( const float& val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 112;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
F2r tmp(val);
msg.addData( tmp.raw_backorder.v[0] );
msg.addData( tmp.raw_backorder.v[1] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == F2r::wsize() );
auto conf = uniset_conf();
IOController_i::SensorInfo si;
si.id = 2008;
si.node = conf->getLocalNode();
IOController_i::CalibrateInfo cal = ui->getCalibrateInfo(si);
float fval = (float)ui->getValue(si.id) / pow10(cal.precision);
REQUIRE( fval == val );
}
static void test_write10_F4raw( const float& val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 120;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
F4 tmp(val);
msg.addData( tmp.raw.v[0] );
msg.addData( tmp.raw.v[1] );
msg.addData( tmp.raw.v[2] );
msg.addData( tmp.raw.v[3] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == F4::wsize() );
auto conf = uniset_conf();
IOController_i::SensorInfo si;
si.id = 2013;
si.node = conf->getLocalNode();
long raw = ui->getValue(si.id);
float fval = 0;
memcpy( &fval,&raw,std::min(sizeof(fval),sizeof(raw)) );
REQUIRE( fval == val );
}
static void test_write10_F4prec( const float& val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 114;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
F4 tmp(val);
msg.addData( tmp.raw.v[0] );
msg.addData( tmp.raw.v[1] );
msg.addData( tmp.raw.v[2] );
msg.addData( tmp.raw.v[3] );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == F4::wsize() );
auto conf = uniset_conf();
IOController_i::SensorInfo si;
si.id = 2009;
si.node = conf->getLocalNode();
IOController_i::CalibrateInfo cal = ui->getCalibrateInfo(si);
float fval = (float)ui->getValue(si.id) / pow10(cal.precision);
REQUIRE( fval == val );
}
static void test_write10_byte1( unsigned char val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 108;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
Byte tmp(val,0);
msg.addData( (unsigned short)tmp );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == Byte::wsize() );
REQUIRE( ui->getValue(2005) == (long)val );
}
static void test_write10_byte2( unsigned char val )
{
using namespace VTypes;
ModbusRTU::ModbusData tREG = 109;
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
Byte tmp(0,val);
msg.addData( (unsigned short)tmp );
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == Byte::wsize() );
REQUIRE( ui->getValue(2006) == (long)val );
}
TEST_CASE("Write(0x10): vtypes..","[modbus][mbslave][mbtcpslave]")
{
using namespace VTypes;
InitTest();
SECTION("Test: write vtype 'I2'")
{
test_write10_I2(numeric_limits<int>::max());
test_write10_I2(0);
test_write10_I2(numeric_limits<int>::min());
}
SECTION("Test: write vtype 'I2r'")
{
test_write10_I2r(numeric_limits<int>::max());
test_write10_I2r(0);
test_write10_I2r(numeric_limits<int>::min());
}
SECTION("Test: write vtype 'U2'")
{
test_write10_U2(numeric_limits<unsigned int>::max());
test_write10_U2(0);
test_write10_U2(numeric_limits<unsigned int>::min());
}
SECTION("Test: write vtype 'U2r'")
{
test_write10_U2r(numeric_limits<unsigned int>::max());
test_write10_U2r(0);
test_write10_U2r(numeric_limits<unsigned int>::min());
}
SECTION("Test: write vtype 'F2'")
{
test_write10_F2(-0.05);
test_write10_F2(0);
test_write10_F2(100000.23);
}
SECTION("Test: write vtype 'F2r'")
{
test_write10_F2r(-0.05);
test_write10_F2r(0);
test_write10_F2r(100000.23);
}
SECTION("Test: write vtype 'F4'(raw)")
{
test_write10_F4raw(numeric_limits<float>::max());
test_write10_F4raw(0);
test_write10_F4raw(numeric_limits<float>::min());
}
SECTION("Test: write vtype 'F4'(precision)")
{
test_write10_F4prec(15.55555);
test_write10_F4prec(0);
test_write10_F4prec(-15.00001);
}
SECTION("Test: write vtype 'Byte N1'")
{
test_write10_byte1(numeric_limits<unsigned char>::max());
test_write10_byte1(0);
test_write10_byte1(numeric_limits<unsigned char>::min());
test_write10_byte1(numeric_limits<char>::max());
test_write10_byte1(numeric_limits<char>::min());
}
SECTION("Test: write vtype 'Byte N2'")
{
test_write10_byte2(numeric_limits<unsigned char>::max());
test_write10_byte2(0);
test_write10_byte2(numeric_limits<unsigned char>::min());
test_write10_byte2(numeric_limits<char>::max());
test_write10_byte2(numeric_limits<char>::min());
}
}
#if 0
TEST_CASE("(0x14): read file record","[modbus][mbslave][mbtcpslave]")
{
}
TEST_CASE("(0x15): write file record","[modbus][mbslave][mbtcpslave]")
{
}
TEST_CASE("(0x2B): Modbus Encapsulated Interface","[modbus][mbslave][mbtcpslave]")
{
}
TEST_CASE("(0x50): set date and time")
{
}
TEST_CASE("(0x53): call remote service")
{
}
TEST_CASE("(0x65): read,write,delete alarm journal")
{
}
TEST_CASE("(0x66): file transfer")
{
}
#endif
TEST_CASE("access mode","[modbus][mbslvae][mbtcpslave]")
{
SECTION("test 'RO' register")
{
ModbusRTU::ModbusData tREG=124;
// read
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,1);
REQUIRE( ret.data[0] == 1002 );
// write
try
{
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(33);
mb->write10(msg);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
}
SECTION("test 'WO' register")
{
ModbusRTU::ModbusData tREG=125;
// read
try
{
mb->read04(slaveaddr,tREG,1);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erBadDataAddress );
}
// write
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(555);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 1 );
REQUIRE( ui->getValue(2015) == 555 );
}
SECTION("test 'RW' register")
{
ModbusRTU::ModbusData tREG=126;
// write
ModbusRTU::WriteOutputMessage msg(slaveaddr,tREG);
msg.addData(555);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
REQUIRE( ret.start == tREG );
REQUIRE( ret.quant == 1 );
REQUIRE( ui->getValue(2016) == 555 );
// read
ModbusRTU::ReadInputRetMessage rret = mb->read04(slaveaddr,tREG,1);
REQUIRE( rret.data[0] == 555 );
}
}
#endif
\ No newline at end of file
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
#include <string>
#include "Debug.h"
#include "UniSetActivator.h"
#include "PassiveTimer.h"
#include "SharedMemory.h"
#include "Extensions.h"
#include "UNetExchange.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// --------------------------------------------------------------------------
int main(int argc, char* argv[] )
{
Catch::Session session;
if( argc>1 && ( strcmp(argv[1],"--help")==0 || strcmp(argv[1],"-h")==0 ) )
{
cout << "--confile - Использовать указанный конф. файл. По умолчанию configure.xml" << endl;
SharedMemory::help_print(argc, argv);
cout << endl << endl << "--------------- CATCH HELP --------------" << endl;
session.showHelp("test_with_sm");
return 0;
}
int returnCode = session.applyCommandLine( argc, argv, Catch::Session::OnUnusedOptions::Ignore );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
try
{
uniset_init(argc,argv);
conf->initDebug(dlog,"dlog");
UNetExchange* unet = UNetExchange::init_unetexchange(argc,argv,getSharedMemoryID());
if( !unet )
return 1;
UniSetActivatorPtr act = UniSetActivator::Instance();
act->addObject(static_cast<class UniSetObject*>(unet));
SystemMessage sm(SystemMessage::StartUp);
act->broadcast( sm.transport_msg() );
act->run(true);
int tout = 6000;
PassiveTimer pt(tout);
while( !pt.checkTime() && !act->exist() )
msleep(100);
if( !act->exist() )
{
cerr << "(tests_with_sm): SharedMemory not exist! (timeout=" << tout << ")" << endl;
return 1;
}
int ret = session.run();
act->oaDestroy();
return ret;
}
catch( SystemError& err )
{
cerr << "(tests_with_sm): " << err << endl;
}
catch( Exception& ex )
{
cerr << "(tests_with_sm): " << ex << endl;
}
catch( std::exception& e )
{
cerr << "(tests_with_sm): " << e.what() << endl;
}
catch(...)
{
cerr << "(tests_with_sm): catch(...)" << endl;
}
return 1;
}
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
#include <string>
#include "Debug.h"
#include "UniSetActivator.h"
#include "PassiveTimer.h"
#include "SharedMemory.h"
#include "Extensions.h"
#include "UNetExchange.h"
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// --------------------------------------------------------------------------
int main(int argc, char* argv[] )
{
Catch::Session session;
if( argc>1 && ( strcmp(argv[1],"--help")==0 || strcmp(argv[1],"-h")==0 ) )
{
cout << "--confile - Использовать указанный конф. файл. По умолчанию configure.xml" << endl;
SharedMemory::help_print(argc, argv);
cout << endl << endl << "--------------- CATCH HELP --------------" << endl;
session.showHelp("test_with_sm");
return 0;
}
int returnCode = session.applyCommandLine( argc, argv, Catch::Session::OnUnusedOptions::Ignore );
if( returnCode != 0 ) // Indicates a command line error
return returnCode;
try
{
auto conf = uniset_init(argc,argv);
conf->initDebug(dlog,"dlog");
bool apart = findArgParam("--apart",argc,argv) != -1;
SharedMemory* shm = SharedMemory::init_smemory(argc, argv);
if( !shm )
return 1;
UNetExchange* unet = UNetExchange::init_unetexchange(argc,argv,shm->getId(), (apart ? nullptr : shm ));
if( !unet )
return 1;
UniSetActivatorPtr act = UniSetActivator::Instance();
act->addObject(static_cast<class UniSetObject*>(shm));
act->addObject(static_cast<class UniSetObject*>(unet));
SystemMessage sm(SystemMessage::StartUp);
act->broadcast( sm.transport_msg() );
act->run(true);
int tout = 6000;
PassiveTimer pt(tout);
while( !pt.checkTime() && !act->exist() )
msleep(100);
if( !act->exist() )
{
cerr << "(tests_with_sm): SharedMemory not exist! (timeout=" << tout << ")" << endl;
return 1;
}
int ret = session.run();
act->oaDestroy();
return ret;
}
catch( SystemError& err )
{
cerr << "(tests_with_sm): " << err << endl;
}
catch( Exception& ex )
{
cerr << "(tests_with_sm): " << ex << endl;
}
catch( std::exception& e )
{
cerr << "(tests_with_sm): " << e.what() << endl;
}
catch(...)
{
cerr << "(tests_with_sm): catch(...)" << endl;
}
return 1;
}
#!/bin/sh
# '--' - нужен для отделения аргументов catch, от наших..
cd ../../../Utilities/Admin/
./uniset2-start.sh -f ./create_links.sh
./uniset2-start.sh -f ./create
./uniset2-start.sh -f ./exist | grep -q UNISET_PLC/Controllers || exit 1
cd -
./uniset2-start.sh -f ./tests-with-sm $* -- --confile unetudp-test-configure.xml --e-startup-pause 10 \
--unet-name UNetExchange --unet-filter-field unet --unet-filter-value 1 --unet-maxdifferense 40 \
--unet-recv-timeout 2000
#!/bin/sh
# '--' - нужен для отделения аргументов catch, от наших..
cd ../../../Utilities/Admin/
./uniset2-start.sh -f ./create_links.sh
./uniset2-start.sh -f ./create
./uniset2-start.sh -f ./exist | grep -q UNISET_PLC/Controllers || exit 1
cd -
./uniset2-start.sh -f ./tests-with-sm $* -- --apart --confile mbslave-test-configure.xml --e-startup-pause 10 \
--mbs-name MBSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 20048 --mbs-my-addr 0x01 \
--mbs-askcount-id SVU_AskCount_AS --mbs-respond-id RespondRTU_S --mbs-respond-invert 1 \
--mbs-filter-field mbs --mbs-filter-value 1
m4_include(package.m4)
AT_COLOR_TESTS
AT_INIT([UNetUDP tests])
m4_include(unetudp-tests.at)
<?xml version="1.0" encoding="utf-8"?>
<UNISETPLC xmlns:xi="http://www.w3.org/2001/XInclude">
<UserData/>
<!-- Общие(стартовые) параметры по UniSet -->
<UniSet>
<NameService host="localhost" port="2809"/>
<LocalNode name="localhost"/>
<RootSection name="UNISET_PLC"/>
<CountOfNet name="1"/>
<RepeatCount name="3"/>
<RepeatTimeoutMS name="50"/>
<WatchDogTime name="0"/>
<PingNodeTime name="0"/>
<AutoStartUpTime name="1"/>
<DumpStateTime name="10"/>
<SleepTickMS name="500"/>
<UniSetDebug levels="" name="ulog"/>
<ConfDir name="./"/>
<DataDir name="./"/>
<BinDir name="./"/>
<LogDir name="./"/>
<DocDir name="./"/>
<LockDir name="./"/>
<Services/>
</UniSet>
<dlog name="dlog"/>
<LogServer name="smplus" port="3333" host="localhost" />
<settings>
<SharedMemory name="SharedMemory" shmID="SharedMemory"/>
<UNetExchange name="UNetExchange"/>
</settings>
<ObjectsMap idfromfile="1">
<nodes port="2809" unet_broadcast_ip="127.255.255.255">
<item id="3000" ip="127.0.0.1" name="localhost" textname="Локальный узел" unet_ignore="0" unet_port="3000"/>
<item id="3001" ip="127.0.0.1" name="localhost1" textname="Локальный узел" unet_ignore="1" unet_port="3001"/>
<item id="3002" ip="192.168.56.10" name="Node1" textname="Node1" unet_ignore="0" unet_ip="192.168.56.255" unet_port="3001" unet_respond_id="Node1_Respond_S" unet_respond_invert="1"/>
<item id="3003" ip="192.168.56.11" name="Node2" textname="Node2" unet_ignore="0" unet_ip="192.168.56.255" unet_port="3002"/>
</nodes>
<!-- ************************ Датчики ********************** -->
<sensors name="Sensors">
<item id="100" iotype="DI" name="TestMode_S" textname="Test sensor"/>
<item id="1" iotype="DI" name="Node1_Respond_S" textname="Node1 respond"/>
<item id="2" iotype="AI" name="AI1_S" textname="AI sensor 1" unet="1" default="1"/>
<item id="3" iotype="AI" name="AI2_S" textname="AI sensor 2" unet="1" default="2"/>
<item id="4" iotype="AI" name="AI3_S" textname="AI sensor 3" unet="1" default="3"/>
<item id="5" iotype="AI" name="AI4_S" textname="AI sensor 4" unet="1" default="4"/>
<item id="6" iotype="DI" name="DI1_S" textname="DI sensor 1" unet="1" default="1"/>
<item id="7" iotype="DI" name="DI2_S" textname="DI sensor 2" unet="1"/>
</sensors>
<thresholds name="thresholds"/>
<controllers name="Controllers">
<item id="5000" name="SharedMemory1"/>
<item id="5003" name="SharedMemory"/>
</controllers>
<!-- ******************* Идентификаторы сервисов ***************** -->
<services name="Services">
<item id="5010" name="InfoServer"/>
<item id="5011" name="DBServer1"/>
<item id="5012" name="PrintServer"/>
<item id="5013" name="TimeService"/>
</services>
<!-- ******************* Идентификаторы объектов ***************** -->
<objects name="UniObjects">
<item id="6000" name="TestProc"/>
<item id="6008" name="UNetExchange"/>
</objects>
</ObjectsMap>
</UNISETPLC>
AT_SETUP([UNetUDP tests (with SM)])
AT_CHECK([$abs_top_builddir/testsuite/at-test-launch.sh $abs_top_builddir/extensions/UNetUDP/tests tests_with_sm.sh],[0],[ignore],[ignore])
AT_CLEANUP
# AT_SETUP([UNetUDP tests (Apart)])
# AT_CHECK([$abs_top_builddir/testsuite/at-test-launch.sh $abs_top_builddir/extensions/UNetUDP/tests tests_with_sm_apart.sh],[0],[ignore],[ignore])
# AT_CLEANUP
../../../Utilities/scripts/uniset2-functions.sh
\ No newline at end of file
/home/pv/Projects.com/uniset-2.0/extensions/SharedMemory/uniset2-smemory
\ No newline at end of file
../../../Utilities/scripts/uniset2-start.sh
\ No newline at end of file
......@@ -3,8 +3,11 @@
#include <getopt.h>
#include <cstring>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <cc++/socket.h>
#include "UDPPacket.h"
#include "PassiveTimer.h"
// --------------------------------------------------------------------------
static struct option longopts[] = {
{ "help", no_argument, 0, 'h' },
......@@ -20,11 +23,13 @@ static struct option longopts[] = {
{ "check-lost", no_argument, 0, 'l' },
{ "verbode", required_argument, 0, 'v' },
{ "num-cycles", required_argument, 0, 'z' },
{ "prof", required_argument, 0, 'y' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
using namespace std;
using namespace UniSetUDP;
using namespace std::chrono;
// --------------------------------------------------------------------------
enum Command
{
......@@ -64,8 +69,9 @@ int main(int argc, char* argv[])
bool lost = false;
bool show = false;
int ncycles = -1;
unsigned int nprof = 0;
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:y:",longopts,&optindex)) != -1 )
{
switch (opt)
{
......@@ -83,6 +89,7 @@ int main(int argc, char* argv[])
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 << "[-y|--prof] num - Print receive statistics every NUM packets (for -r only)" << endl;
cout << endl;
return 0;
......@@ -104,6 +111,10 @@ int main(int argc, char* argv[])
usecpause = atoi(optarg)*1000;
break;
case 'y':
nprof = atoi(optarg);
break;
case 'c':
count = atoi(optarg);
break;
......@@ -195,10 +206,23 @@ int main(int argc, char* argv[])
if( ncycles > 0 )
nc = ncycles;
auto t_start = high_resolution_clock::now();
unsigned int npack = 0;
while( nc )
{
try
{
if( nprof > 0 && npack >= nprof )
{
auto t_end = high_resolution_clock::now();
float sec = duration_cast<duration<float>>(t_end - t_start).count();
cout << "Receive " << setw(5) << npack << " packets for " << setw(8) << sec << " sec "
<< " [ 1 packet per " << setw(10) << ( sec / (float)npack ) << " sec ]" << endl;
t_start = t_end;
npack = 0;
}
if( !udp.isInputReady(tout) )
{
cout << "(recv): Timeout.." << endl;
......@@ -223,6 +247,8 @@ int main(int argc, char* argv[])
prev_num = pack.num;
}
npack++;
if( verb )
cout << "receive OK: "
<< " bytes: " << ret << endl;
......
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