Commit 9bddf978 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusSlave): начал работу над тестами

parent e4a2ead8
......@@ -12,14 +12,6 @@ AC_CONFIG_HEADER(uniset-config.h)
dnl Initialize maintainer mode
AM_MAINTAINER_MODE
dnl Initialize test suite
AC_CONFIG_TESTDIR(testsuite)
AC_CONFIG_TESTDIR(tests)
AC_CONFIG_TESTDIR(extensions/tests)
AC_CONFIG_TESTDIR(extensions/LogicProcessor/tests)
TESTSUITE_DIR="\$(top_builddir)/testsuite"
AC_SUBST(TESTSUITE_DIR)
dnl Checks for programs.
AC_PROG_INSTALL
......@@ -285,6 +277,7 @@ AC_CONFIG_FILES([Makefile
extensions/ModbusMaster/libUniSet2MBTCPMaster.pc
extensions/ModbusSlave/Makefile
extensions/ModbusSlave/libUniSet2MBSlave.pc
extensions/ModbusSlave/tests/Makefile
extensions/LogicProcessor/Makefile
extensions/LogicProcessor/libUniSet2LogicProcessor.pc
extensions/LogicProcessor/tests/Makefile
......@@ -305,7 +298,19 @@ AC_CONFIG_FILES([Makefile
python/lib/pyUniSet/Makefile
python/Makefile])
dnl Initialize test suite
AC_CONFIG_TESTDIR(testsuite)
AC_CONFIG_TESTDIR(tests)
AC_CONFIG_TESTDIR(extensions/tests)
AC_CONFIG_TESTDIR(extensions/LogicProcessor/tests)
AC_CONFIG_TESTDIR(extensions/ModbusSlave/tests)
TESTSUITE_DIR="\$(top_builddir)/testsuite"
AC_SUBST(TESTSUITE_DIR)
AC_OUTPUT
# extensions/SMDBServer/Makefile
# extensions/SMDBServer/libUniSet2SMDBServer.pc
#!/bin/sh
./uniset-start.sh -f ./uniset2-mbtcpmaster \
./uniset2-start.sh -f ./uniset2-mbtcpmaster \
--confile test.xml \
--mbtcp-name MBMaster1 \
--smemory-id SharedMemory \
......
#!/bin/sh
./uniset-start.sh -f ./uniset2-mbtcpmultimaster \
./uniset2-start.sh -f ./uniset2-mbtcpmultimaster \
--confile test.xml \
--mbtcp-name MBMultiMaster1 \
--smemory-id SharedMemory \
......
......@@ -35,3 +35,5 @@ pkgconfig_DATA = libUniSet2MBSlave.pc
all-local:
ln -sf ../ModbusSlave/$(devel_include_HEADERS) ../include
SUBDIRS=tests
noinst_PROGRAMS = tests-with-sm
tests_with_sm_SOURCES = tests_with_sm.cc mbslave-tests.cc
tests_with_sm_LDADD = $(top_builddir)/lib/libUniSet2.la $(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(top_builddir)/extensions/ModbusSlave/libUniSet2MBSlave.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/ModbusSlave \
-I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
$(top_builddir)/extensions/lib/libUniSet2Extensions.la:
cd $(top_builddir)/extensions/lib/ && make
$(top_builddir)/extensions/ModbusSlave/libUniSet2MBSlave.la:
cd $(top_builddir)/extensions/ModbusSlave/ && make
include $(top_builddir)/testsuite/testsuite-common.mk
check-local: atconfig package.m4 $(TESTSUITE)
$(SHELL) $(TESTSUITE) $(TESTSUITEFLAGS)
clean-local:
rm -rf $(CLEANFILES)
<?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="LocalhostNode"/>
<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></Services>
</UniSet>
<dlog name="dlog"/>
<settings>
<SharedMemory name="SharedMemory" shmID="SharedMemory">
<History savetime="200">
<item filter="a1" fuse_id="AlarmFuse1_S" fuse_invert="1" id="1" size="30"/>
<item filter="a2" fuse_id="AlarmFuse2_AS" fuse_value="2" id="2" size="30"/>
</History>
</SharedMemory>
<MBSlave1 addr="0x31" aftersend-pause="0" dev="/dev/ttyS0" levels="info,warn,crit" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
<filelist>
<!-- Список файлов разрешённых для передачи по modbus
directory - каталог где лежит файл. Можно не задавать
'ConfDir' - берётся из настроек (см. начало этого файла)
'DataDir' - берётся из настроек (см. начало этого файла)
'xxx' - прямое указание каталога
-->
<item directory="ConfDir" id="1" name="configure.xml"/>
<item directory="ConfDir" id="2" name="VERSION"/>
<item directory="/tmp/" id="3" name="configure.xml.gz"/>
<item directory="ConfDir" id="4" name="SERIAL"/>
</filelist>
<MEI>
<!-- ВНИМАНИЕ: должен заполняться в соответсвии со стандартом. ObjectID и DeviceID не случайны.. -->
<device id="0x01">
<object id="0" comm="VendorName">
<string value="etersoft"/>
</object>
<object id="1" comm="ProductCode">
<string value="uniset"/>
</object>
<object id="2" comm="MajorMinorRevision">
<string value="1.6"/>
</object>
</device>
<device id="0x02">
<object id="3" comm="VendorURL">
<string value="http://www.etersoft.ru"/>
</object>
<object id="4" comm="ProductName">
<string value="uniset"/>
</object>
<object id="5" comm="ModelName">
<string value="uniset:MBSlave"/>
</object>
<object id="6" comm="UserApplicationName">
<string value="MBSlave1"/>
</object>
</device>
<device id="0x03">
<object id="128" comm="private objects">
<string id="129" value="etersoft"/>
<string id="130" value="uniset"/>
<string id="131" value="1.6"/>
<string id="132" value="http://www.etersoft.ru"/>
<string id="133" value="MBSlave1"/>
</object>
</device>
</MEI>
</MBSlave1>
</settings>
<ObjectsMap idfromfile="1">
<!--
Краткие пояснения к полям секции 'sensors'
==========================================
node - узел на котором физически находится данный датчик
iotype - тип датчика
priority - приоритет сообщения об изменении данного датчика
textname - текстовое имя датчика
-->
<nodes port="2809">
<item id="3000" infserver="InfoServer" ip="127.0.0.1" name="LocalhostNode" textname="Локальный узел"/>
</nodes>
<!-- ************************ Датчики ********************** -->
<sensors name="Sensors">
<item default="1" id="1000" mbs="1" mbreg="0x01" nbit="0" iotype="DI" name="TestReadCoil_S" textname="Тестовый регистр для ReadCoil"/>
<item default="1" id="1001" mbs="1" mbreg="0x01" nbit="1" iotype="DI" name="TestReadCoil_S" textname="Тестовый регистр для ReadCoil"/>
<item id="1002" mbs="1" mbreg="0x01" nbit="2" iotype="DI" name="TestReadCoil_S" textname="Тестовый регистр для ReadCoil"/>
<item default="10" id="1003" mbs="1" mbreg="10" iotype="AI" name="TestRead03" textname="Тестовый регистр для 0x03"/>
<item default="11" id="1004" mbs="1" mbreg="11" iotype="AI" name="TestRead03" textname="Тестовый регистр для 0x03"/>
<item default="-10" id="1005" mbs="1" mbreg="12" iotype="AI" name="TestRead03" textname="Тестовый регистр для 0x03"/>
<item default="-10000" id="1006" mbs="1" mbreg="13" iotype="AI" name="TestRead03" textname="Тестовый регистр для 0x03"/>
<item id="1007" mbs="1" mbreg="14" iotype="AI" name="TestRead05" textname="Тестовый регистр для 0x05"/>
<item id="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/>
</sensors>
<thresholds/>
<controllers name="Controllers">
<item id="5000" name="SharedMemory"/>
</controllers>
<!-- ******************* Идентификаторы сервисов ***************** -->
<services name="Services">
</services>
<!-- ******************* Идентификаторы объектов ***************** -->
<objects name="UniObjects">
<item id="6000" name="TestProc"/>
<item id="6004" name="MBSlave1"/>
</objects>
</ObjectsMap>
<messages idfromfile="1" name="messages"/>
</UNISETPLC>
AT_SETUP([ModbusSlave tests])
AT_CHECK([$abs_top_builddir/testsuite/at-test-launch.sh $abs_top_builddir/extensions/ModbusSlave/tests tests_with_sm.sh],[0],[ignore],[ignore])
AT_CLEANUP
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <time.h>
#include "MBSlave.h"
#include "UniSetTypes.h"
#include "modbus/ModbusTCPMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
TEST_CASE("Modbus Slave","[modbus]")
{
CHECK( conf!=0 );
ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
int port = 20048; // conf->getArgInt("--mbs-inet-port");
string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
ObjectId slaveID = 6004; // conf->getObjectID( conf->getArgParam("--mbs-name"));
// UI понадобиться для проверки записанных в SM значений.
UInterface ui;
CHECK( ui.getObjectIndex() != 0 );
CHECK( ui.getConf() == UniSetTypes::conf );
CHECK( ui.waitReady(slaveID,5000) );
ModbusTCPMaster mb;
ost::InetAddress ia(addr.c_str());
mb.setTimeout(2000);
REQUIRE_NOTHROW( mb.connect(ia,port) );
#if 0
SECTION("(0x01): read coil status")
{
// read 1 bit
{
ModbusRTU::ReadCoilRetMessage ret(slaveaddr);
REQUIRE_NOTHROW( ret = mb.read01(slaveaddr,1000,1) );
ModbusRTU::DataBits b(ret.data[0]);
REQUIRE( b[0] == 1 );
}
// read 3 bit
{
ModbusRTU::ReadCoilRetMessage ret(slaveaddr);
REQUIRE_NOTHROW( ret = mb.read01(slaveaddr,1000,3) );
ModbusRTU::DataBits b(ret.data[0]);
REQUIRE( b[0] == 1 );
REQUIRE( b[1] == 1 );
REQUIRE( b[2] == 0 );
}
}
#endif
#if 0
SECTION("(0x02): read input status")
{
// read 1 bit
{
ModbusRTU::ReadInputStatusRetMessage ret(slaveaddr);
REQUIRE_NOTHROW( ret = mb.read02(slaveaddr,1000,1) );
ModbusRTU::DataBits b(ret.data[0]);
REQUIRE( b[0] == 1 );
}
// read 3 bit
{
ModbusRTU::ReadInputStatusRetMessage ret(slaveaddr);
REQUIRE_NOTHROW( ret = mb.read02(slaveaddr,1000,3) );
ModbusRTU::DataBits b(ret.data[0]);
REQUIRE( b[0] == 1 );
REQUIRE( b[1] == 1 );
REQUIRE( b[2] == 0 );
}
}
#endif
SECTION("Function (0x03): 'read register outputs or memories or read word outputs or memories'")
{
SECTION("Test: read one reg..")
{
ModbusRTU::ReadOutputRetMessage ret = mb.read03(slaveaddr,10,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read many registers..")
{
ModbusRTU::ReadOutputRetMessage ret = mb.read03(slaveaddr,10,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,10,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,10,-3);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
}
SECTION("Function (0x04): 'read input registers or memories or read word outputs or memories'")
{
SECTION("Test: read one reg..")
{
ModbusRTU::ReadInputRetMessage ret = mb.read04(slaveaddr,10,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read one reg..")
{
ModbusRTU::ReadInputRetMessage ret = mb.read04(slaveaddr,10,1);
REQUIRE( ret.data[0] == 10 );
}
SECTION("Test: read many registers..")
{
ModbusRTU::ReadInputRetMessage ret = mb.read04(slaveaddr,10,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,10,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,10,-3);
}
catch( ModbusRTU::mbException& ex )
{
REQUIRE( ex.err == ModbusRTU::erTimeOut );
}
}
}
SECTION("(0x05): forces a single coil to either ON or OFF")
{
ObjectId tID = 1007;
SECTION("Test: ON")
{
ModbusRTU::ForceSingleCoilRetMessage ret = mb.write05(slaveaddr,14,true);
CHECK( ret.start == 14 );
CHECK( ret.cmd() == true );
CHECK( ui.getValue(tID) == 1 );
}
SECTION("Test: OFF")
{
ModbusRTU::ForceSingleCoilRetMessage ret = mb.write05(slaveaddr,14,false);
CHECK( ret.start == 14 );
CHECK( ret.cmd() == false );
CHECK( ui.getValue(tID) == 0 );
}
}
#if 0
SECTION("(0x06): write register outputs or memories")
{
}
#endif
#if 0
SECTION("(0x08): Diagnostics (Serial Line only)")
{
}
#endif
#if 0
SECTION("(0x0F): force multiple coils")
{
}
SECTION("(0x10): write register outputs or memories")
{
}
#endif
#if 0
SECTION("(0x10): write register outputs or memories")
{
fnReadFileRecord = 0x14, /*!< read file record */
}
SECTION("(0x10): write register outputs or memories")
{
fnWriteFileRecord = 0x15, /*!< write file record */
}
SECTION("(0x10): write register outputs or memories")
{
fnMEI = 0x2B, /*!< Modbus Encapsulated Interface */
}
SECTION("(0x10): write register outputs or memories")
{
fnSetDateTime = 0x50, /*!< set date and time */
}
SECTION("(0x10): write register outputs or memories")
{
fnRemoteService = 0x53, /*!< call remote service */
}
SECTION("(0x10): write register outputs or memories")
{
fnJournalCommand = 0x65, /*!< read,write,delete alarm journal */
}
SECTION("(0x10): write register outputs or memories")
{
fnFileTransfer = 0x66 /*!< file transfer */
}
#endif
}
#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 "MBSlave.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");
SharedMemory* shm = SharedMemory::init_smemory(argc, argv);
if( !shm )
return 1;
MBSlave* mbs = MBSlave::init_mbslave(argc,argv,shm->getId(),shm);
if( !mbs )
return 1;
UniSetActivator* act = UniSetActivator::Instance();
act->addObject(static_cast<class UniSetObject*>(shm));
act->addObject(static_cast<class UniSetObject*>(mbs));
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 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([ModbusSlave tests])
m4_include(mbslave-tests.at)
../../../Utilities/scripts/uniset2-functions.sh
\ No newline at end of file
../../../Utilities/scripts/uniset2-start.sh
\ No newline at end of file
../../Utilities/scripts/uniset2-stop.sh
\ No newline at end of file
#!/bin/sh
# '--' - нужен для отделения аоргументов catch, от наших..
uniset-start.sh -f ./tests_with_conf $* -- --confile tests_with_conf.xml --prop-id2 -10
uniset2-start.sh -f ./tests_with_conf $* -- --confile tests_with_conf.xml --prop-id2 -10
#!/bin/sh
# '--' - нужен для отделения аоргументов catch, от наших..
# '--' - нужен для отделения аргументов catch, от наших..
cd ../../Utilities/Admin/
uniset-start.sh -f ./create_links.sh
uniset-start.sh -f ./create
uniset2-start.sh -f ./create_links.sh
uniset2-start.sh -f ./create
uniset-start.sh -f ./exist | grep -q UNISET_PLC/Controllers || exit 1
uniset2-start.sh -f ./exist | grep -q UNISET_PLC/Controllers || exit 1
cd -
uniset-start.sh -f ./tests_with_sm $* -- --confile tests_with_sm.xml --e-startup-pause 10 --ulog-levels warn,crit --dlog-levels warn,crit
uniset2-start.sh -f ./tests_with_sm $* -- --confile tests_with_sm.xml --e-startup-pause 10 --ulog-levels warn,crit --dlog-levels warn,crit
../../Utilities/scripts/uniset2-functions.sh
\ No newline at end of file
../../Utilities/scripts/uniset2-start.sh
\ No newline at end of file
......@@ -862,6 +862,11 @@ namespace ModbusRTU
ModbusData data; /*!< данные */
ModbusCRC crc;
/*! получить значение команды */
inline bool cmd()
{
return (data & 0xFF00);
}
// ------- from slave -------
ForceSingleCoilRetMessage( ModbusMessage& m );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment