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;
}
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
#include <sstream>
#include <UniSetTypes.h>
#include "MBTCPTestServer.h"
#include "uniset-config.h"
// -------------------------------------------------------------------------
#ifndef PACKAGE_URL
#define PACKAGE_URL "http://git.etersoft.ru/projects/?p=asu/uniset.git;a=summary"
#endif
// -------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace ModbusRTU;
// -------------------------------------------------------------------------
MBTCPTestServer::MBTCPTestServer( ModbusAddr myaddr, const string& inetaddr, int port, bool verb ):
sslot(NULL),
addr(myaddr),
verbose(verb),
replyVal(-1),
forceSingleCoilCmd(false),
lastWriteOutputSingleRegister(0),
lastForceCoilsQ(0,0),
lastWriteOutputQ(0,0),
thr(0),
isrunning(false)
{
ost::InetAddress ia(inetaddr.c_str());
if( verbose )
cout << "(init): "
<< " addr: " << ia << ":" << port << endl;
sslot = new ModbusTCPServerSlot(ia,port);
// sslot->initLog(conf,name,logfile);
sslot->connectReadCoil( sigc::mem_fun(this, &MBTCPTestServer::readCoilStatus) );
sslot->connectReadInputStatus( sigc::mem_fun(this, &MBTCPTestServer::readInputStatus) );
sslot->connectReadOutput( sigc::mem_fun(this, &MBTCPTestServer::readOutputRegisters) );
sslot->connectReadInput( sigc::mem_fun(this, &MBTCPTestServer::readInputRegisters) );
sslot->connectForceSingleCoil( sigc::mem_fun(this, &MBTCPTestServer::forceSingleCoil) );
sslot->connectForceCoils( sigc::mem_fun(this, &MBTCPTestServer::forceMultipleCoils) );
sslot->connectWriteOutput( sigc::mem_fun(this, &MBTCPTestServer::writeOutputRegisters) );
sslot->connectWriteSingleOutput( sigc::mem_fun(this, &MBTCPTestServer::writeOutputSingleRegister) );
sslot->connectDiagnostics( sigc::mem_fun(this, &MBTCPTestServer::diagnostics) );
sslot->connectMEIRDI( sigc::mem_fun(this, &MBTCPTestServer::read4314) );
sslot->connectJournalCommand( sigc::mem_fun(this, &MBTCPTestServer::journalCommand) );
sslot->connectSetDateTime( sigc::mem_fun(this, &MBTCPTestServer::setDateTime) );
sslot->connectRemoteService( sigc::mem_fun(this, &MBTCPTestServer::remoteService) );
sslot->connectFileTransfer( sigc::mem_fun(this, &MBTCPTestServer::fileTransfer) );
sslot->setRecvTimeout(6000);
// sslot->setAfterSendPause(afterSend);
sslot->setReplyTimeout(10000);
// build file list...
}
// -------------------------------------------------------------------------
MBTCPTestServer::~MBTCPTestServer()
{
if( thr )
{
thr->stop();
if( thr->isRunning() )
thr->join();
}
delete sslot;
}
// -------------------------------------------------------------------------
void MBTCPTestServer::setLog( DebugStream& dlog )
{
if( sslot )
sslot->setLog(dlog);
}
// -------------------------------------------------------------------------
void MBTCPTestServer::runThread()
{
thr = new ThreadCreator<MBTCPTestServer>(this, &MBTCPTestServer::execute);
thr->start();
}
// -------------------------------------------------------------------------
void MBTCPTestServer::execute()
{
isrunning = true;
cerr << "******************** MBTCPTestServer running... " << endl;
// Работа...
while(1)
{
ModbusRTU::mbErrCode res = sslot->receive( addr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
if( prev!=ModbusRTU::erTimeOut )
{
// с проверкой на переполнение
askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1;
if( res!=ModbusRTU::erNoError )
++errmap[res];
prev = res;
}
#endif
if( verbose && res!=ModbusRTU::erNoError && res!=ModbusRTU::erTimeOut )
cerr << "(execute::receive): " << ModbusRTU::mbErr2Str(res) << endl;
}
isrunning = false;
}
// -------------------------------------------------------------------------
void MBTCPTestServer::sigterm( int signo )
{
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
if( verbose )
cout << "(readCoilStatus): " << query << endl;
ModbusRTU::DataBits d;
d.b[0] = 1;
d.b[2] = 1;
d.b[4] = 1;
d.b[6] = 1;
if( query.count <= 1 )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(d);
return ModbusRTU::erNoError;
}
// Фомирование ответа:
int num=0; // добавленное количество данных
ModbusData reg = query.start;
for( ; num<query.count; num++, reg++ )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(d);
}
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if( reply.bcnt < query.count )
{
cerr << "(readCoilStatus): Получили меньше чем ожидали. "
<< " Запросили " << query.count << " получили " << reply.bcnt << endl;
}
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::readInputStatus( ReadInputStatusMessage& query,
ReadInputStatusRetMessage& reply )
{
if( verbose )
cout << "(readInputStatus): " << query << endl;
ModbusRTU::DataBits d;
d.b[0] = 1;
d.b[3] = 1;
d.b[7] = 1;
if( replyVal == -1 )
{
int bnum = 0;
int i=0;
while( i<query.count )
{
reply.addData(0);
for( auto nbit=0; nbit<BitsPerByte && i<query.count; nbit++,i++ )
reply.setBit(bnum,nbit,d.b[nbit]);
bnum++;
}
}
else
{
int bcnt = query.count / ModbusRTU::BitsPerByte;
if( (query.count % ModbusRTU::BitsPerByte) > 0 )
bcnt++;
for( auto i=0; i<bcnt; i++ )
reply.addData(replyVal);
}
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
mbErrCode MBTCPTestServer::readInputRegisters( ReadInputMessage& query,
ReadInputRetMessage& reply )
{
if( verbose )
cout << "(readInputRegisters): " << query << endl;
if( query.count <= 1 )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(query.start);
return ModbusRTU::erNoError;
}
// Фомирование ответа:
int num=0; // добавленное количество данных
ModbusData reg = query.start;
for( ; num<query.count; num++, reg++ )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(reg);
}
// cerr << "************ reply: cnt=" << reply.count << endl;
// cerr << "reply: " << reply << endl;
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if( reply.count < query.count )
{
cerr << "(readInputRegisters): Получили меньше чем ожидали. "
<< " Запросили " << query.count << " получили " << reply.count << endl;
}
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::readOutputRegisters(
ModbusRTU::ReadOutputMessage& query, ModbusRTU::ReadOutputRetMessage& reply )
{
if( verbose )
cout << "(readOutputRegisters): " << query << endl;
if( query.count <= 1 )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(query.start);
return ModbusRTU::erNoError;
}
// Фомирование ответа:
int num=0; // добавленное количество данных
ModbusData reg = query.start;
for( ; num<query.count; num++, reg++ )
{
if( replyVal!=-1 )
reply.addData(replyVal);
else
reply.addData(reg);
}
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if( reply.count < query.count )
{
cerr << "(readOutputRegisters): Получили меньше чем ожидали. "
<< " Запросили " << query.count << " получили " << reply.count << endl;
}
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::forceMultipleCoils( ModbusRTU::ForceCoilsMessage& query,
ModbusRTU::ForceCoilsRetMessage& reply )
{
if( verbose )
cout << "(forceMultipleCoils): " << query << endl;
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
reply.set(query.start,query.quant);
lastForceCoilsQ = query;
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::writeOutputRegisters( ModbusRTU::WriteOutputMessage& query,
ModbusRTU::WriteOutputRetMessage& reply )
{
if( verbose )
cout << "(writeOutputRegisters): " << query << endl;
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
reply.set(query.start,query.quant);
lastWriteOutputQ = query;
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::writeOutputSingleRegister( ModbusRTU::WriteSingleOutputMessage& query,
ModbusRTU::WriteSingleOutputRetMessage& reply )
{
if( verbose )
cout << "(writeOutputSingleRegisters): " << query << endl;
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
lastWriteOutputSingleRegister = (signed short)query.data;
reply.set(query.start,query.data);
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::forceSingleCoil( ModbusRTU::ForceSingleCoilMessage& query,
ModbusRTU::ForceSingleCoilRetMessage& reply )
{
if( verbose )
cout << "(forceSingleCoil): " << query << endl;
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
forceSingleCoilCmd = query.cmd();
reply.set(query.start,query.cmd());
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::journalCommand( ModbusRTU::JournalCommandMessage& query,
ModbusRTU::JournalCommandRetMessage& reply )
{
if( verbose )
cout << "(journalCommand): " << query << endl;
switch( query.cmd )
{
case 0:
{
if( reply.setData( (ModbusRTU::ModbusByte*)(&query.num), sizeof(query.num) ) )
return ModbusRTU::erNoError;
return ModbusRTU::erPacketTooLong;
}
break;
case 1:
{
ModbusRTU::JournalCommandRetOK::set(reply,1,0);
return ModbusRTU::erNoError;
}
break;
case 2: // write по modbus пока не поддерживается
default:
{
// формируем ответ
ModbusRTU::JournalCommandRetOK::set(reply,2,1);
return ModbusRTU::erNoError;
}
break;
}
return ModbusRTU::erTimeOut;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::setDateTime( ModbusRTU::SetDateTimeMessage& query,
ModbusRTU::SetDateTimeRetMessage& reply )
{
if( verbose )
cout << "(setDateTime): " << query << endl;
// подтверждаем сохранение
// в ответе возвращаем установленное время...
ModbusRTU::SetDateTimeRetMessage::cpy(reply,query);
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::remoteService( ModbusRTU::RemoteServiceMessage& query,
ModbusRTU::RemoteServiceRetMessage& reply )
{
cerr << "(remoteService): " << query << endl;
return ModbusRTU::erOperationFailed;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::fileTransfer( ModbusRTU::FileTransferMessage& query,
ModbusRTU::FileTransferRetMessage& reply )
{
if( verbose )
cout << "(fileTransfer): " << query << endl;
return ModbusRTU::erOperationFailed;
#if 0
FileList::iterator it = flist.find(query.numfile);
if( it == flist.end() )
return ModbusRTU::erBadDataValue;
std::string fname(it->second);
int fd = open(fname.c_str(), O_RDONLY | O_NONBLOCK );
if( fd <= 0 )
{
dwarn << "(fileTransfer): open '" << fname << "' with error: " << strerror(errno) << endl;
return ModbusRTU::erOperationFailed;
}
int seek = query.numpacket*ModbusRTU::FileTransferRetMessage::MaxDataLen;
(void)lseek(fd,seek,SEEK_SET);
ModbusRTU::ModbusByte buf[ModbusRTU::FileTransferRetMessage::MaxDataLen];
int ret = ::read(fd,&buf,sizeof(buf));
if( ret < 0 )
{
dwarn << "(fileTransfer): read from '" << fname << "' with error: " << strerror(errno) << endl;
close(fd);
return ModbusRTU::erOperationFailed;
}
// вычисляем общий размер файла в "пакетах"
// (void)lseek(fd,0,SEEK_END);
// int numpacks = lseek(fd,0,SEEK_CUR) / ModbusRTU::FileTransferRetMessage::MaxDataLen;
// if( lseek(fd,0,SEEK_CUR) % ModbusRTU::FileTransferRetMessage::MaxDataLen )
// numpacks++;
struct stat fs;
if( fstat(fd,&fs) < 0 )
{
dwarn << "(fileTransfer): fstat for '" << fname << "' with error: " << strerror(errno) << endl;
close(fd);
return ModbusRTU::erOperationFailed;
}
close(fd);
// cerr << "******************* ret = " << ret << " fsize = " << fs.st_size
// << " maxsize = " << ModbusRTU::FileTransferRetMessage::MaxDataLen << endl;
int numpacks = fs.st_size / ModbusRTU::FileTransferRetMessage::MaxDataLen;
if( fs.st_size % ModbusRTU::FileTransferRetMessage::MaxDataLen )
numpacks++;
if( !reply.set(query.numfile,numpacks,query.numpacket,buf,ret) )
{
dwarn << "(fileTransfer): set date failed..." << endl;
return ModbusRTU::erOperationFailed;
}
return ModbusRTU::erNoError;
#endif
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::diagnostics( ModbusRTU::DiagnosticMessage& query,
ModbusRTU::DiagnosticRetMessage& reply )
{
if( query.subf == ModbusRTU::subEcho )
{
reply = query;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgBusErrCount )
{
reply = query;
reply.data[0] = 10;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgMsgSlaveCount || query.subf == ModbusRTU::dgBusMsgCount )
{
reply = query;
reply.data[0] = 10;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgSlaveNAKCount )
{
reply = query;
reply.data[0] = 10;
return ModbusRTU::erNoError;
}
if( query.subf == ModbusRTU::dgClearCounters )
{
reply = query;
return ModbusRTU::erNoError;
}
return ModbusRTU::erOperationFailed;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBTCPTestServer::read4314( ModbusRTU::MEIMessageRDI& query,
ModbusRTU::MEIMessageRetRDI& reply )
{
if( verbose )
cout << "(read4314): " << query << endl;
if( query.devID <= rdevMinNum || query.devID >= rdevMaxNum )
return erOperationFailed;
if( query.objID == rdiVendorName )
{
reply.mf = 0xFF;
reply.conformity = rdevBasicDevice;
reply.addData(query.objID,"etersoft");
// reply.addData(rdiProductCode, PACKAGE_NAME);
// reply.addData(rdiMajorMinorRevision,PACKAGE_VERSION);
return erNoError;
}
else if( query.objID == rdiProductCode )
{
reply.mf = 0xFF;
reply.conformity = rdevBasicDevice;
reply.addData(query.objID,PACKAGE_NAME);
return erNoError;
}
else if( query.objID == rdiMajorMinorRevision )
{
reply.mf = 0xFF;
reply.conformity = rdevBasicDevice;
reply.addData(query.objID,PACKAGE_VERSION);
return erNoError;
}
else if( query.objID == rdiVendorURL )
{
reply.mf = 0xFF;
reply.conformity = rdevRegularDevice;
reply.addData(query.objID,PACKAGE_URL);
return erNoError;
}
else if( query.objID == rdiProductName )
{
reply.mf = 0xFF;
reply.conformity = rdevRegularDevice;
reply.addData(query.objID,PACKAGE_NAME);
return erNoError;
}
else if( query.objID == rdiModelName )
{
reply.mf = 0xFF;
reply.conformity = rdevRegularDevice;
reply.addData(query.objID,"MBTCPSlaveEcho");
return erNoError;
}
else if( query.objID == rdiUserApplicationName )
{
reply.mf = 0xFF;
reply.conformity = rdevRegularDevice;
reply.addData(query.objID,"uniset-mbtcpslave-echo");
return erNoError;
}
return ModbusRTU::erBadDataAddress;
}
// -------------------------------------------------------------------------
#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