Commit 943e9dc2 authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusMaster): добавил ещё ряд тестов, исправил обнаруженную ошибку

с "не выставлением" датчика связи в режиме emSkipExchange.. (не выставлялось "нет связи").
parent d2fc81fa
......@@ -340,7 +340,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc, long mdev )
if( exchangeMode == emSkipExchange || mdev == emSkipExchange )
{
if( wrFunc )
return true; // данные для посылки, должны обновляться всегда (чтобы быть актуальными)
return true; // данные для посылки, должны обновляться всегда (чтобы быть актуальными, когда режим переключиться обратно..)
dlog3 << "(checkUpdateSM):"
<< " skip... mode='emSkipExchange' " << endl;
......@@ -361,7 +361,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc, long mdev )
return false;
}
if( wrFunc && (exchangeMode == emSkipSaveToSM || mdev == emSkipSaveToSM) )
if( !wrFunc && (exchangeMode == emSkipSaveToSM || mdev == emSkipSaveToSM) )
{
dlog3 << "(checkUpdateSM):"
<< " skip... mode='emSkipSaveToSM' " << endl;
......@@ -385,6 +385,12 @@ bool MBExchange::checkPoll( bool wrFunc )
return false;
}
if( exchangeMode == emSkipExchange )
{
dlog3 << myname << "(checkPoll): skip.. poll mode='emSkipExchange'" << endl;
return false;
}
return true;
}
// -----------------------------------------------------------------------------
......@@ -802,12 +808,12 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dev->mode == emSkipExchange )
if( dev->mode == emSkipExchange )
{
dlog3 << myname << "(pollRTU): SKIP EXCHANGE (mode=emSkipExchange) "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< endl;
return true;
return false;
}
if( dlog.debugging(Debug::LEVEL3) )
......@@ -822,13 +828,13 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
<< " mbval=" << p->mbval
<< endl;
if( p->q_count > ModbusRTU::MAXDATALEN )
{
dlog3 << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
if( p->q_count > ModbusRTU::MAXDATALEN )
{
dlog3 << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
if( !checkPoll(ModbusRTU::isWriteFunction(p->mbfunc)) )
......@@ -854,7 +860,7 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr, p->mbreg,p->q_count);
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr,p->mbreg,p->q_count);
for( unsigned int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
......@@ -2769,6 +2775,12 @@ void MBExchange::poll()
if( !checkProcActive() )
return;
if( exchangeMode == emSkipExchange )
{
d->resp_real = false;
continue;
}
try
{
if( d->dtype==MBExchange::dtRTU || d->dtype==MBExchange::dtMTR )
......@@ -2835,10 +2847,10 @@ void MBExchange::poll()
IOBase::processingThreshold(&(*t),shm,force);
}
if( trReopen.hi(allNotRespond) )
if( trReopen.hi(allNotRespond && exchangeMode!=emSkipExchange) )
ptReopen.reset();
if( allNotRespond && ptReopen.checkTime() )
if( allNotRespond && exchangeMode!=emSkipExchange && ptReopen.checkTime() )
{
dwarn << myname << ": REOPEN timeout..(" << ptReopen.getInterval() << ")" << endl;
......@@ -2947,3 +2959,23 @@ void MBExchange::execute()
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::ExchangeMode& em )
{
if( em == MBExchange::emNone )
return os << "emNone";
if( em == MBExchange::emWriteOnly )
return os << "emWriteOnly";
if( em == MBExchange::emReadOnly )
return os << "emReadOnly";
if( em == MBExchange::emSkipSaveToSM )
return os << "emSkipSaveToSM";
if( em == MBExchange::emSkipExchange )
return os << "emSkipExchange";
return os;
}
// -----------------------------------------------------------------------------
#ifndef MBTCPTestServer_H_
#define MBTCPTestServer_H_
// -------------------------------------------------------------------------
#include <string>
#include <atomic>
#include "ThreadCreator.h"
#include "modbus/ModbusTCPServerSlot.h"
// -------------------------------------------------------------------------
/*! Реализация MBTCPTestServer для тестирования */
class MBTCPTestServer
{
public:
MBTCPTestServer( ModbusRTU::ModbusAddr myaddr, const std::string& inetaddr, int port=502, bool verbose=false );
~MBTCPTestServer();
inline void setVerbose( bool state )
{
verbose = state;
}
inline void setReply( long val )
{
replyVal = val;
}
inline void setIgnoreAddrMode( bool state )
{
if( sslot )
sslot->setIgnoreAddrMode(state);
}
void runThread(); /*!< запуск с отдельным потоком */
void execute(); /*!< основной цикл работы */
void setLog( DebugStream& dlog );
inline bool isRunning(){ return isrunning; }
inline bool getForceSingleCoilCmd(){ return forceSingleCoilCmd; }
inline int getLastWriteOutputSingleRegister(){ return lastWriteOutputSingleRegister; }
inline ModbusRTU::ForceCoilsMessage getLastForceCoilsQ(){ return lastForceCoilsQ; }
inline ModbusRTU::WriteOutputMessage getLastWriteOutput(){ return lastWriteOutputQ; }
protected:
// действия при завершении работы
void sigterm( int signo );
/*! обработка 0x01 */
ModbusRTU::mbErrCode readCoilStatus( ModbusRTU::ReadCoilMessage& query,
ModbusRTU::ReadCoilRetMessage& reply );
/*! обработка 0x02 */
ModbusRTU::mbErrCode readInputStatus( ModbusRTU::ReadInputStatusMessage& query,
ModbusRTU::ReadInputStatusRetMessage& reply );
/*! обработка 0x03 */
ModbusRTU::mbErrCode readOutputRegisters( ModbusRTU::ReadOutputMessage& query,
ModbusRTU::ReadOutputRetMessage& reply );
/*! обработка 0x04 */
ModbusRTU::mbErrCode readInputRegisters( ModbusRTU::ReadInputMessage& query,
ModbusRTU::ReadInputRetMessage& reply );
/*! обработка 0x05 */
ModbusRTU::mbErrCode forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query,
ModbusRTU::ForceSingleCoilRetMessage& reply );
/*! обработка 0x0F */
ModbusRTU::mbErrCode forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query,
ModbusRTU::ForceCoilsRetMessage& reply );
/*! обработка 0x10 */
ModbusRTU::mbErrCode writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
ModbusRTU::WriteOutputRetMessage& reply );
/*! обработка 0x06 */
ModbusRTU::mbErrCode writeOutputSingleRegister( ModbusRTU::WriteSingleOutputMessage& query,
ModbusRTU::WriteSingleOutputRetMessage& reply );
ModbusRTU::mbErrCode diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply );
ModbusRTU::mbErrCode read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply );
/*! обработка запросов на чтение ошибок */
ModbusRTU::mbErrCode journalCommand( ModbusRTU::JournalCommandMessage& query,
ModbusRTU::JournalCommandRetMessage& reply );
/*! обработка запроса на установку времени */
ModbusRTU::mbErrCode setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply );
/*! обработка запроса удалённого сервиса */
ModbusRTU::mbErrCode remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply );
ModbusRTU::mbErrCode fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply );
/*! интерфейс ModbusSlave для обмена по RS */
ModbusTCPServerSlot* sslot;
ModbusRTU::ModbusAddr addr; /*!< адрес данного узла */
bool verbose;
long replyVal;
bool forceSingleCoilCmd;
int lastWriteOutputSingleRegister;
ModbusRTU::ForceCoilsMessage lastForceCoilsQ;
ModbusRTU::WriteOutputMessage lastWriteOutputQ;
#if 0
typedef std::map<ModbusRTU::mbErrCode,unsigned int> ExchangeErrorMap;
ExchangeErrorMap errmap; /*!< статистика обмена */
ModbusRTU::mbErrCode prev;
// можно было бы сделать unsigned, но аналоговые датчики у нас имеют
// тип long. А это число передаётся в графику в виде аналогового датчика
long askCount; /*!< количество принятых запросов */
typedef std::map<int,std::string> FileList;
FileList flist;
#endif
private:
ThreadCreator<MBTCPTestServer>* thr;
std::atomic_bool isrunning;
};
// -------------------------------------------------------------------------
#endif // MBTCPTestServer_H_
// -------------------------------------------------------------------------
......@@ -27,7 +27,7 @@
<settings>
<SharedMemory name="SharedMemory" shmID="SharedMemory"/>
<MBTCPMaster1 name="MBTCPMaster1">
<MBTCPMaster1 name="MBTCPMaster1" exchangeModeID="MBTCPMaster_Mode_AS">
<DeviceList>
<item addr="0x01" invert="1" respondSensor="Slave_Not_Respond_S" timeout="1000"/>
</DeviceList>
......@@ -49,6 +49,7 @@
<sensors name="Sensors">
<item id="10" iotype="DI" name="Slave_Not_Respond_S" textname="Наличие связи со Slave"/>
<item id="11" iotype="AI" name="MBTCPMaster_Mode_AS" textname="Режим работы MBTCPMaster"/>
<item id="1000" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="1" mbfunc="0x01" iotype="DI" name="TestReadCoil1_S" textname="Тестовый регистр для ReadCoil"/>
<item id="1001" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="2" mbfunc="0x01" iotype="DI" name="TestReadCoil2_S" textname="Тестовый регистр для ReadCoil"/>
......
......@@ -17,8 +17,9 @@ static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static shared_ptr<MBTCPTestServer> mbs;
static shared_ptr<UInterface> ui;
static ObjectId mbID = 6004; // MBTCPMaster1
static int polltime=300; // conf->getArgInt("--mbtcp-polltime");
static int polltime=50; // conf->getArgInt("--mbtcp-polltime");
static ObjectId slaveNotRespond = 10; // Slave_Not_Respond_S
static const ObjectId exchangeMode = 11; // MBTCPMaster_Mode_AS
// -----------------------------------------------------------------------------
static void InitTest()
{
......@@ -355,43 +356,185 @@ TEST_CASE("MBTCPMaster: 0x10 (write register outputs or memories)","[modbus][0x1
}
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x14 (read file record","[modbus][0x14][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: exchangeMode","[modbus][exchangemode][mbmaster][mbtcpmaster]")
{
InitTest();
SECTION("None")
{
SECTION("read")
{
mbs->setReply(10);
msleep(polltime+100);
REQUIRE( ui->getValue(1003) == 10 );
}
SECTION("write")
{
ui->setValue(1018,10);
REQUIRE( ui->getValue(1018) == 10 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() == 10 );
}
}
SECTION("WriteOnly")
{
// emWriteOnly=1, /*!< "только посылка данных" (работают только write-функции) */
ui->setValue(exchangeMode,MBExchange::emWriteOnly );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emWriteOnly );
SECTION("read")
{
mbs->setReply(150);
msleep(2*polltime+100);
REQUIRE( ui->getValue(1003) != 150 );
mbs->setReply(-10);
msleep(2*polltime+100);
REQUIRE( ui->getValue(1003) != -10 );
REQUIRE( ui->getValue(1003) != 150 );
}
SECTION("write")
{
ui->setValue(1018,150);
REQUIRE( ui->getValue(1018) == 150 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() == 150 );
ui->setValue(1018,155);
REQUIRE( ui->getValue(1018) == 155 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() == 155 );
}
}
SECTION("ReadOnly")
{
// emReadOnly=2, /*!< "только чтение" (работают только read-функции) */
ui->setValue(exchangeMode,MBExchange::emReadOnly );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emReadOnly );
SECTION("read")
{
mbs->setReply(150);
msleep(polltime+100);
REQUIRE( ui->getValue(1003) == 150 );
mbs->setReply(-100);
msleep(polltime+100);
REQUIRE( ui->getValue(1003) == -100 );
}
SECTION("write")
{
ui->setValue(1018,50);
REQUIRE( ui->getValue(1018) == 50 );
msleep(2*polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() != 50 );
ui->setValue(1018,55);
REQUIRE( ui->getValue(1018) == 55 );
msleep(2*polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() != 55 );
REQUIRE( mbs->getLastWriteOutputSingleRegister() != 50 );
}
}
SECTION("SkipSaveToSM")
{
// emSkipSaveToSM=3, /*!< не писать данные в SM (при этом работают и read и write функции */
ui->setValue(exchangeMode,MBExchange::emSkipSaveToSM );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emSkipSaveToSM );
SECTION("read")
{
mbs->setReply(50);
msleep(polltime+100);
REQUIRE( ui->getValue(1003) != 50 );
}
SECTION("write")
{
// а write работает в этом режиме.. (а чем отличается от writeOnly?)
ui->setValue(1018,60);
REQUIRE( ui->getValue(1018) == 60 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() == 60 );
ui->setValue(1018,65);
REQUIRE( ui->getValue(1018) == 65 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() == 65 );
}
}
SECTION("SkipExchange")
{
// emSkipExchange=4 /*!< отключить обмен */
ui->setValue(exchangeMode,MBExchange::emSkipExchange );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emSkipExchange );
SECTION("read")
{
mbs->setReply(70);
msleep(polltime+100);
REQUIRE( ui->getValue(1003) != 70 );
}
SECTION("write")
{
ui->setValue(1018,70);
REQUIRE( ui->getValue(1018) == 70 );
msleep(polltime+100);
REQUIRE( mbs->getLastWriteOutputSingleRegister() != 70 );
}
SECTION("check connection")
{
msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 1 );
ui->setValue(exchangeMode,MBExchange::emNone );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emNone );
msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 0 );
}
}
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: iobase functions","[modbus][iobase][mbmaster][mbtcpmaster]")
{
WARN("Test of 'iobase functions'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: reconnection","[modbus][reconnection][mbmaster][mbtcpmaster]")
{
WARN("Test of 'reconnection'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x14 (read file record)","[modbus][0x14][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x14'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x15 (write file record","[modbus][0x15][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x15 (write file record)","[modbus][0x15][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x15'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x2B (Modbus Encapsulated Interface","[modbus][0x2B][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x2B (Modbus Encapsulated Interface / MEI /)","[modbus][0x2B][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x2B'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x50 (set date and time","[modbus][0x50][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x50 (set date and time)","[modbus][0x50][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x50'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x53 (call remote service","[modbus][0x53][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x53 (call remote service)","[modbus][0x53][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x53'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x65 (read,write,delete alarm journal","[modbus][0x65][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x65 (read,write,delete alarm journal)","[modbus][0x65][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x65'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: 0x66 (file transfer","[modbus][0x66][mbmaster][mbtcpmaster]")
TEST_CASE("MBTCPMaster: 0x66 (file transfer)","[modbus][0x66][mbmaster][mbtcpmaster]")
{
WARN("Test of '0x66'..not yet.. ");
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: exchangeMode","[modbus][exchangemode][mbmaster][mbtcpmaster]")
{
WARN("Test of 'exchangeMode'..not yet.. ");
}
// -----------------------------------------------------------------------------
......@@ -33,6 +33,7 @@ int main(int argc, char* argv[] )
{
auto conf = uniset_init(argc,argv);
conf->initDebug(dlog,"dlog");
dlog.logFile("./smtest.log");
bool apart = findArgParam("--apart",argc,argv) != -1;
......
......@@ -15,7 +15,8 @@ cd -
--mbtcp-filter-value 1 \
--mbtcp-gateway-iaddr localhost \
--mbtcp-gateway-port 20048 \
--mbtcp-polltime 300 --mbtcp-recv-timeout 1000
--mbtcp-polltime 50 --mbtcp-recv-timeout 1000
#--dlog-add-levels any
#--mbtcp-force-out 1
#--dlog-add-levels any
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