Commit a405f36f authored by Pavel Vainerman's avatar Pavel Vainerman

(ModbusSlave): добавил поддержку ответов на запросы ко многим

адресам для одного ModbusSlave.
parent eff3d777
......@@ -15,9 +15,9 @@ using namespace std;
using namespace UniSetTypes;
using namespace ModbusRTU;
// -------------------------------------------------------------------------
MBSlave::MBSlave( ModbusRTU::ModbusAddr addr, const std::string& dev, const std::string& speed, bool use485 ):
MBSlave::MBSlave(const std::unordered_set<ModbusAddr>& _vaddr, const std::string& dev, const std::string& speed, bool use485 ):
rscomm(NULL),
addr(addr),
vaddr(_vaddr),
// prev(ModbusRTU::erNoError),
// askCount(0),
verbose(false),
......@@ -31,7 +31,7 @@ MBSlave::MBSlave( ModbusRTU::ModbusAddr addr, const std::string& dev, const std:
if( verbose )
cout << "(init): "
<< " addr=" << ModbusRTU::addr2str(addr)
<< " addr=" << ModbusServer::vaddr2str(vaddr)
<< " dev=" << dev
<< " speed=" << speed;
......@@ -80,7 +80,7 @@ void MBSlave::execute()
// Работа...
while(1)
{
ModbusRTU::mbErrCode res = rscomm->receive( addr, UniSetTimer::WaitUpTime );
ModbusRTU::mbErrCode res = rscomm->receive( vaddr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
......
......@@ -3,6 +3,7 @@
#define MBSlave_H_
// -------------------------------------------------------------------------
#include <map>
#include <unordered_set>
#include <string>
#include "modbus/ModbusRTUSlaveSlot.h"
......@@ -11,7 +12,7 @@
class MBSlave
{
public:
MBSlave( ModbusRTU::ModbusAddr addr, const std::string& dev, const std::string& speed, bool use485 = false );
MBSlave( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, const std::string& dev, const std::string& speed, bool use485 = false );
~MBSlave();
inline void setVerbose( bool state )
......@@ -96,7 +97,7 @@ class MBSlave
/*! интерфейс ModbusRTUSlave для обмена по RS */
ModbusRTUSlaveSlot* rscomm;
ModbusRTU::ModbusAddr addr; /*!< адрес данного узла */
std::unordered_set<ModbusRTU::ModbusAddr> vaddr; /*!< адреса на которые отвечаем */
bool verbose;
#if 0
......
......@@ -15,9 +15,9 @@ using namespace std;
using namespace UniSetTypes;
using namespace ModbusRTU;
// -------------------------------------------------------------------------
MBTCPServer::MBTCPServer( ModbusAddr myaddr, const string& inetaddr, int port, bool verb ):
MBTCPServer::MBTCPServer(const std::unordered_set<ModbusAddr>& myaddr, const string& inetaddr, int port, bool verb ):
sslot(NULL),
addr(myaddr),
vaddr(myaddr),
// prev(ModbusRTU::erNoError),
// askCount(0),
verbose(verb),
......@@ -66,7 +66,7 @@ MBTCPServer::~MBTCPServer()
delete sslot;
}
// -------------------------------------------------------------------------
void MBTCPServer::setLog( std::shared_ptr<DebugStream> dlog )
void MBTCPServer::setLog(std::shared_ptr<DebugStream>& dlog )
{
if( sslot )
sslot->setLog(dlog);
......@@ -77,7 +77,7 @@ void MBTCPServer::execute()
// Работа...
while(1)
{
ModbusRTU::mbErrCode res = sslot->receive( addr, UniSetTimer::WaitUpTime );
ModbusRTU::mbErrCode res = sslot->receive( vaddr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
......
#ifndef MBTCPServer_H_
#define MBTCPServer_H_
// -------------------------------------------------------------------------
//#include <map>
#include <unordered_set>
#include <string>
#include "modbus/ModbusTCPServerSlot.h"
......@@ -10,7 +10,7 @@
class MBTCPServer
{
public:
MBTCPServer( ModbusRTU::ModbusAddr myaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
MBTCPServer( const std::unordered_set<ModbusRTU::ModbusAddr>& myaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
~MBTCPServer();
inline void setVerbose( bool state )
......@@ -23,14 +23,8 @@ class MBTCPServer
replyVal = val;
}
inline void setIgnoreAddrMode( bool state )
{
if( sslot )
sslot->setIgnoreAddrMode(state);
}
void execute(); /*!< основной цикл работы */
void setLog( std::shared_ptr<DebugStream> dlog );
void setLog( std::shared_ptr<DebugStream>& dlog );
protected:
// действия при завершении работы
......@@ -93,7 +87,7 @@ class MBTCPServer
/*! интерфейс ModbusSlave для обмена по RS */
ModbusTCPServerSlot* sslot;
ModbusRTU::ModbusAddr addr; /*!< адрес данного узла */
std::unordered_set<ModbusRTU::ModbusAddr> vaddr; /*!< адреса данного узла */
bool verbose;
long replyVal;
......
......@@ -106,7 +106,11 @@ int main( int argc, char** argv )
dlog->addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
}
MBSlave mbs(myaddr, dev, speed, use485);
/*! \todo Доделать возможность задавать много адресов для ответа */
std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
vaddr.emplace(myaddr);
MBSlave mbs(vaddr, dev, speed, use485);
mbs.setLog(dlog);
mbs.setVerbose(verb);
......
......@@ -21,11 +21,12 @@ static struct option longopts[] =
// --------------------------------------------------------------------------
static void print_help()
{
printf("-h|--help - this message\n");
printf("[-t|--timeout] msec - Timeout. Default: 2000.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-d|--device] dev - use device dev. Default: /dev/ttyS0\n");
printf("[-a|--myaddr] addr - Modbus address for this slave. Default: 0x01.\n");
printf("-h|--help - this message\n");
printf("[-t|--timeout] msec - Timeout. Default: 2000.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-d|--device] dev - use device dev. Default: /dev/ttyS0\n");
printf("[-a|--myaddr] addr1,addr2,... - Modbus address for this slave. Default: 0x01.\n");
printf(" myaddr=255 - Reply to all RTU-addresses.\n");
printf("[-s|--speed] speed - 9600,14400,19200,38400,57600,115200. Default: 38400.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-g|--f485] - Use 485 Fastwel\n");
......@@ -40,7 +41,7 @@ int main( int argc, char** argv )
int f485 = 0;
string dev("/dev/ttyS0");
string speed("38400");
ModbusRTU::ModbusAddr myaddr = 0x01;
std::string myaddr("0x01");
int tout = 2000;
DebugStream dlog;
......@@ -68,7 +69,7 @@ int main( int argc, char** argv )
break;
case 'a':
myaddr = ModbusRTU::str2mbAddr(optarg);
myaddr = string(optarg);
break;
case 'v':
......@@ -86,10 +87,15 @@ int main( int argc, char** argv )
}
}
auto avec = UniSetTypes::explode_str(myaddr,',');
std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
for( const auto& a: avec )
vaddr.emplace( ModbusRTU::str2mbAddr(a) );
if( verb )
{
cout << "(init): dev=" << dev << " speed=" << speed
<< " myaddr=" << ModbusRTU::addr2str(myaddr)
<< " myaddr=" << ModbusServer::vaddr2str(vaddr)
<< " timeout=" << tout << " msec "
<< endl;
......@@ -110,20 +116,20 @@ int main( int argc, char** argv )
return 1;
}
MBSlave mbs(cp, myaddr, speed);
MBSlave mbs(cp, vaddr, speed);
mbs.setLog(dlog);
mbs.setVerbose(verb);
mbs.execute();
}
else
{
MBSlave mbs(myaddr, dev, speed);
MBSlave mbs(vaddr, dev, speed);
mbs.setLog(dlog);
mbs.setVerbose(verb);
mbs.execute();
}
}
catch( ModbusRTU::mbException& ex )
catch( const ModbusRTU::mbException& ex )
{
cerr << "(mbtester): " << ex << endl;
}
......
......@@ -15,7 +15,6 @@ static struct option longopts[] =
{ "verbose", no_argument, 0, 'v' },
{ "myaddr", required_argument, 0, 'a' },
{ "port", required_argument, 0, 'p' },
{ "reply-all", no_argument, 0, 'r' },
{ "const-reply", required_argument, 0, 'c' },
{ NULL, 0, 0, 0 }
};
......@@ -23,13 +22,13 @@ static struct option longopts[] =
static void print_help()
{
printf("Example: uniset-mbtcpserver-echo -i localhost -p 2049 -v \n");
printf("-h|--help - this message\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-i|--iaddr] ip - Server listen ip. Default 127.0.0.1\n");
printf("[-a|--myaddr] addr - Modbus address for master. Default: 0x01.\n");
printf("[-r|--reply-all] - Reply to all RTU-addresses.\n");
printf("[-p|--port] port - Server port. Default: 502.\n");
printf("[-c|--const-reply] val - Reply 'val' for all queries\n");
printf("-h|--help - this message\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
printf("[-i|--iaddr] ip - Server listen ip. Default 127.0.0.1\n");
printf("[-a|--myaddr] addr1,addr2,... - Modbus address for master. Default: 0x01.\n");
printf(" myaddr=255 - Reply to all RTU-addresses.\n");
printf("[-p|--port] port - Server port. Default: 502.\n");
printf("[-c|--const-reply] val - Reply 'val' for all queries\n");
}
// --------------------------------------------------------------------------
int main( int argc, char** argv )
......@@ -40,16 +39,15 @@ int main( int argc, char** argv )
int verb = 0;
int port = 502;
string iaddr("127.0.0.1");
ModbusRTU::ModbusAddr myaddr = 0x01;
string myaddr("0x01");
auto dlog = make_shared<DebugStream>();
bool ignoreAddr = false;
int replyVal = -1;
ost::Thread::setException(ost::Thread::throwException);
try
{
while( (opt = getopt_long(argc, argv, "hva:p:i:brc:", longopts, &optindex)) != -1 )
while( (opt = getopt_long(argc, argv, "hva:p:i:bc:", longopts, &optindex)) != -1 )
{
switch (opt)
{
......@@ -66,17 +64,13 @@ int main( int argc, char** argv )
break;
case 'a':
myaddr = ModbusRTU::str2mbAddr(optarg);
myaddr = string(optarg);
break;
case 'v':
verb = 1;
break;
case 'r':
ignoreAddr = true;
break;
case 'c':
replyVal = uni_atoi(optarg);
break;
......@@ -88,19 +82,23 @@ int main( int argc, char** argv )
}
}
auto avec = UniSetTypes::explode_str(myaddr,',');
std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
for( const auto& a: avec )
vaddr.emplace( ModbusRTU::str2mbAddr(a) );
if( verb )
{
cout << "(init): iaddr: " << iaddr << ":" << port
<< " myaddr=" << ModbusRTU::addr2str(myaddr)
<< " myaddr=" << ModbusServer::vaddr2str(vaddr)
<< endl;
dlog->addLevel( Debug::ANY );
}
MBTCPServer mbs(myaddr, iaddr, port, verb);
MBTCPServer mbs(vaddr, iaddr, port, verb);
mbs.setLog(dlog);
mbs.setVerbose(verb);
mbs.setIgnoreAddrMode(ignoreAddr);
if( replyVal != -1 )
mbs.setReply(replyVal);
......
......@@ -13,7 +13,7 @@
Name: libuniset2
Version: 2.2
Release: alt4
Release: alt5
Summary: UniSet - library for building distributed industrial control systems
......@@ -456,6 +456,9 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
# ..
%changelog
* Fri Oct 02 2015 Pavel Vainerman <pv@altlinux.ru> 2.2-alt5
- (ModbusSlave): added support for multiple addresses for MBSlave
* Fri Oct 02 2015 Pavel Vainerman <pv@altlinux.ru> 2.2-alt4
- (ModbusSlave): added support setBroadcastMode() // addr = 255
- (codegen): change log for 'unknown message id' crit --> level8
......
......@@ -99,7 +99,7 @@
</MBMultiSlave1>
<MBSlave1 addr="0x31" aftersend-pause="0" dev="/dev/ttyS0" levels="info,warn,crit" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
<MBSlave1 aftersend-pause="0" dev="/dev/ttyS0" levels="info,warn,crit" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
<filelist>
<!-- Список файлов разрешённых для передачи по modbus
directory - каталог где лежит файл. Можно не задавать
......
......@@ -18,9 +18,9 @@ std::ostream& operator<<(std::ostream& os, const MBTCPTestServer* m )
return os << m->myname;
}
// -------------------------------------------------------------------------
MBTCPTestServer::MBTCPTestServer( ModbusAddr myaddr, const string& inetaddr, int port, bool verb ):
MBTCPTestServer::MBTCPTestServer( const std::unordered_set<ModbusAddr>& _vaddr, const string& inetaddr, int port, bool verb ):
sslot(NULL),
addr(myaddr),
vaddr(_vaddr),
verbose(verb),
replyVal(-1),
forceSingleCoilCmd(false),
......@@ -51,13 +51,13 @@ MBTCPTestServer::MBTCPTestServer( ModbusAddr myaddr, const string& inetaddr, int
catch( const ost::SockException& e )
{
ostringstream err;
err << "(MBTCPTestServer::init): Can`t create socket " << addr << ":" << port << " err: " << e.getString() << endl;
err << "(MBTCPTestServer::init): Can`t create socket " << inetaddr << ":" << port << " err: " << e.getString() << endl;
cerr << err.str() << endl;
throw SystemError(err.str());
}
catch( const std::exception& ex )
{
cerr << "(MBTCPTestServer::init): Can`t create socket " << addr << ":" << port << " err: " << ex.what() << endl;
cerr << "(MBTCPTestServer::init): Can`t create socket " << inetaddr << ":" << port << " err: " << ex.what() << endl;
throw;
}
......@@ -119,7 +119,7 @@ void MBTCPTestServer::execute()
// Работа...
while(1)
{
ModbusRTU::mbErrCode res = sslot->receive( addr, UniSetTimer::WaitUpTime );
ModbusRTU::mbErrCode res = sslot->receive( vaddr, UniSetTimer::WaitUpTime );
#if 0
// собираем статистику обмена
......
......@@ -4,6 +4,7 @@
#include <string>
#include <atomic>
#include <ostream>
#include <unordered_set>
#include "ThreadCreator.h"
#include "modbus/ModbusTCPServerSlot.h"
// -------------------------------------------------------------------------
......@@ -11,7 +12,7 @@
class MBTCPTestServer
{
public:
MBTCPTestServer( ModbusRTU::ModbusAddr myaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
MBTCPTestServer( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, const std::string& inetaddr, int port = 502, bool verbose = false );
~MBTCPTestServer();
inline void setVerbose( bool state )
......@@ -130,7 +131,7 @@ class MBTCPTestServer
/*! интерфейс ModbusSlave для обмена по RS */
ModbusTCPServerSlot* sslot;
ModbusRTU::ModbusAddr addr; /*!< адрес данного узла */
std::unordered_set<ModbusRTU::ModbusAddr> vaddr; /*!< адреса данного узла */
bool verbose;
long replyVal;
......
......@@ -2,6 +2,7 @@
// -----------------------------------------------------------------------------
#include <time.h>
#include <memory>
#include <unordered_set>
#include <limits>
#include "UniSetTypes.h"
#include "MBTCPTestServer.h"
......@@ -12,8 +13,9 @@ using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
static int port = 20048; // conf->getArgInt("--mbs-inet-port");
static string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static string iaddr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static const ModbusRTU::ModbusAddr slaveADDR = 0x01;
static unordered_set<ModbusRTU::ModbusAddr> vaddr = { slaveADDR };
static shared_ptr<MBTCPTestServer> mbs;
static shared_ptr<UInterface> ui;
static std::shared_ptr<SMInterface> smi;
......@@ -53,18 +55,18 @@ static void InitTest()
{
try
{
mbs = make_shared<MBTCPTestServer>(slaveADDR, addr, port, false);
mbs = make_shared<MBTCPTestServer>(vaddr, iaddr, port, false);
}
catch( const ost::SockException& e )
{
ostringstream err;
err << "(mbs): Can`t create socket " << addr << ":" << port << " err: " << e.getString() << endl;
err << "(mbs): Can`t create socket " << iaddr << ":" << port << " err: " << e.getString() << endl;
cerr << err.str() << endl;
throw SystemError(err.str());
}
catch( const std::exception& ex )
{
cerr << "(mbs): Can`t create socket " << addr << ":" << port << " err: " << ex.what() << endl;
cerr << "(mbs): Can`t create socket " << iaddr << ":" << port << " err: " << ex.what() << endl;
throw;
}
......
......@@ -2,6 +2,7 @@
// -----------------------------------------------------------------------------
#include <time.h>
#include <limits>
#include <unordered_set>
#include "UniSetTypes.h"
#include "MBTCPMultiMaster.h"
// -----------------------------------------------------------------------------
......@@ -22,10 +23,10 @@ using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
static int port = 20053; // conf->getArgInt("--mbs-inet-port");
static string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static string iaddr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static int port2 = 20055;
static string addr2("127.0.0.1");
static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static string iaddr2("127.0.0.1");
static unordered_set<ModbusRTU::ModbusAddr> slaveADDR = { 0x01 };
static shared_ptr<MBTCPTestServer> mbs1;
static shared_ptr<MBTCPTestServer> mbs2;
static shared_ptr<UInterface> ui;
......@@ -55,18 +56,18 @@ static void InitTest()
try
{
ost::Thread::setException(ost::Thread::throwException);
mbs1 = make_shared<MBTCPTestServer>(slaveADDR, addr, port, false);
mbs1 = make_shared<MBTCPTestServer>(slaveADDR, iaddr, port, false);
}
catch( const ost::SockException& e )
{
ostringstream err;
err << "(mb1): Can`t create socket " << addr << ":" << port << " err: " << e.getString() << endl;
err << "(mb1): Can`t create socket " << iaddr << ":" << port << " err: " << e.getString() << endl;
cerr << err.str() << endl;
throw SystemError(err.str());
}
catch( const std::exception& ex )
{
cerr << "(mb1): Can`t create socket " << addr << ":" << port << " err: " << ex.what() << endl;
cerr << "(mb1): Can`t create socket " << iaddr << ":" << port << " err: " << ex.what() << endl;
throw;
}
......@@ -87,18 +88,18 @@ static void InitTest()
try
{
ost::Thread::setException(ost::Thread::throwException);
mbs2 = make_shared<MBTCPTestServer>(slaveADDR, addr2, port2, false);
mbs2 = make_shared<MBTCPTestServer>(slaveADDR, iaddr2, port2, false);
}
catch( const ost::SockException& e )
{
ostringstream err;
err << "(mb2): Can`t create socket " << addr << ":" << port << " err: " << e.getString() << endl;
err << "(mb2): Can`t create socket " << iaddr << ":" << port << " err: " << e.getString() << endl;
cerr << err.str() << endl;
throw SystemError(err.str());
}
catch( const std::exception& ex )
{
cerr << "(mb2): Can`t create socket " << addr << ":" << port << " err: " << ex.what() << endl;
cerr << "(mb2): Can`t create socket " << iaddr << ":" << port << " err: " << ex.what() << endl;
throw;
}
......
......@@ -14,7 +14,6 @@ using namespace ModbusRTU;
// -----------------------------------------------------------------------------
MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const std::shared_ptr<SharedMemory>& ic, const string& prefix ):
UniSetObject_LT(objId),
addr(0x01),
initPause(0),
test_id(DefaultObjectId),
askcount_id(DefaultObjectId),
......@@ -109,9 +108,7 @@ MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const
vmonit(force);
addr = ModbusRTU::str2mbAddr(conf->getArg2Param("--" + prefix + "-my-addr", it.getProp("addr"), "0x01"));
vmonit(addr);
default_mbaddr = conf->getArg2Param("--" + prefix + "-default-mbaddr", it.getProp("default_mbaddr"), "");
default_mbfunc = conf->getArgPInt("--" + prefix + "-default-mbfunc", it.getProp("default_mbfunc"), 0);
mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id", it.getProp("reg_from_id"));
......@@ -120,14 +117,15 @@ MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const
mbinfo << myname << "(init): mbregFromID=" << mbregFromID
<< " checkMBFunc=" << checkMBFunc
<< " default_mbfunc=" << default_mbfunc
<< " default_mbaddr=" << default_mbaddr
<< " noMBFuncOptimize=" << noMBFuncOptimize
<< endl;
vmonit(default_mbaddr);
vmonit(default_mbfunc);
vmonit(checkMBFunc);
vmonit(noMBFuncOptimize);
respond_id = conf->getSensorID(conf->getArgParam("--" + prefix + "-respond-id", it.getProp("respond_id")));
respond_invert = conf->getArgInt("--" + prefix + "-respond-invert", it.getProp("respond_invert"));
......@@ -159,13 +157,11 @@ MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const
rs->setAfterSendPause(aftersend_pause);
rs->setReplyTimeout(reply_tout);
rs->setLog(mblog);
rs->setBroadcastMode( addr == ModbusRTU::BroadcastAddr );
mbslot = std::static_pointer_cast<ModbusServerSlot>(rs);
thr = make_shared< ThreadCreator<MBSlave> >(this, &MBSlave::execute_rtu);
thr->setFinalAction(this, &MBSlave::finalThread);
mbinfo << myname << "(init): type=RTU myaddr=" << ModbusRTU::addr2str(addr)
<< " dev=" << dev << " speed=" << speed << endl;
mbinfo << myname << "(init): type=RTU dev=" << dev << " speed=" << speed << endl;
}
else if( stype == "TCP" )
{
......@@ -176,15 +172,13 @@ MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const
int port = conf->getArgPInt("--" + prefix + "-inet-port", it.getProp("iport"), 502);
mbinfo << myname << "(init): type=TCP myaddr=" << ModbusRTU::addr2str(addr)
<< " inet=" << iaddr << " port=" << port << endl;
mbinfo << myname << "(init): type=TCP inet=" << iaddr << " port=" << port << endl;
ost::InetAddress ia(iaddr.c_str());
auto mbtcp = make_shared<ModbusTCPServerSlot>(ia, port);
mbtcp->setAfterSendPause(aftersend_pause);
mbtcp->setReplyTimeout(reply_tout);
mbtcp->setBroadcastMode( addr == ModbusRTU::BroadcastAddr );
mbslot = std::static_pointer_cast<ModbusServerSlot>(mbtcp);
thr = make_shared< ThreadCreator<MBSlave> >(this, &MBSlave::execute_tcp);
......@@ -222,7 +216,8 @@ MBSlave::MBSlave(UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, const
if( shm->isLocalwork() )
{
readConfiguration();
mbinfo << myname << "(init): iomap size = " << iomap.size() << endl;
mbinfo << myname << "(init): iomap size = " << iomap.size()
<< " myaddr=" << ModbusServer::vaddr2str(vaddr) << endl;
}
else
{
......@@ -491,11 +486,32 @@ void MBSlave::execute_rtu()
ModbusRTU::mbErrCode prev = erNoError;
// ждём чтобы прошла инициализация
// потому-что нужно чтобы наполнилась таблица адресов (vaddr)
if( !shm->isLocalwork() )
{
std::unique_lock<std::mutex> locker(mutexStartNotify);
while( !activated )
startNotifyEvent.wait(locker);
}
if( vaddr.empty() )
{
mbcrit << "(execute_rtu): Unknown my modbus adresses!" << endl;
raise(SIGTERM);
return;
}
mbinfo << myname << "(execute_rtu): thread running.."
<< " iomap size = " << iomap.size()
<< " myaddr=" << ModbusServer::vaddr2str(vaddr)
<< endl;
while( !cancelled )
{
try
{
ModbusRTU::mbErrCode res = rscomm->receive( addr, wait_msec );
ModbusRTU::mbErrCode res = rscomm->receive( vaddr, wait_msec );
if( res != ModbusRTU::erTimeOut )
ptTimeout.reset();
......@@ -561,8 +577,11 @@ void MBSlave::execute_rtu()
}
}
for( auto && it : iomap )
IOBase::processingThreshold(&it.second, shm, force);
for( auto&& rmap: iomap )
{
for( auto&& it: rmap.second )
IOBase::processingThreshold(&it.second, shm, force);
}
}
catch(...) {}
}
......@@ -574,13 +593,32 @@ void MBSlave::execute_tcp()
ModbusRTU::mbErrCode prev = erNoError;
mbinfo << myname << "(execute_tcp): thread running.." << endl;
// ждём чтобы прошла инициализация
// потому-что нужно чтобы наполнилась таблица адресов (vaddr)
if( !shm->isLocalwork() )
{
std::unique_lock<std::mutex> locker(mutexStartNotify);
while( !activated )
startNotifyEvent.wait(locker);
}
if( vaddr.empty() )
{
mbcrit << "(execute_rtu): Unknown my modbus adresses!" << endl;
raise(SIGTERM);
return;
}
mbinfo << myname << "(execute_tcp): thread running.."
<< " iomap size = " << iomap.size()
<< " myaddr=" << ModbusServer::vaddr2str(vaddr)
<< endl;
while( !cancelled )
{
try
{
ModbusRTU::mbErrCode res = sslot->receive( addr, wait_msec );
ModbusRTU::mbErrCode res = sslot->receive( vaddr, wait_msec );
if( res != ModbusRTU::erTimeOut )
ptTimeout.reset();
......@@ -647,8 +685,11 @@ void MBSlave::execute_tcp()
}
}
for( auto && it : iomap )
IOBase::processingThreshold(&it.second, shm, force);
for( auto&& rmap: iomap )
{
for( auto&& it : rmap.second )
IOBase::processingThreshold(&it.second, shm, force);
}
}
catch( const std::exception& ex )
{
......@@ -761,68 +802,75 @@ void MBSlave::askSensors( UniversalIO::UIOCommand cmd )
if( force )
return;
for( const auto& it : iomap )
for( const auto& rmap: iomap )
{
const IOProperty* p(&it.second);
try
{
shm->askSensor(p->si.id, cmd);
}
catch( const UniSetTypes::Exception& ex )
for( const auto& it : rmap.second )
{
mbwarn << myname << "(askSensors): " << ex << std::endl;
const IOProperty* p(&it.second);
try
{
shm->askSensor(p->si.id, cmd);
}
catch( const UniSetTypes::Exception& ex )
{
mbwarn << myname << "(askSensors): " << ex << std::endl;
}
catch(...) {}
}
catch(...) {}
}
}
// ------------------------------------------------------------------------------------------
void MBSlave::sensorInfo( const UniSetTypes::SensorMessage* sm )
{
for( auto it = iomap.begin(); it != iomap.end(); ++it )
for( auto&& regs: iomap )
{
if( it->second.si.id == sm->id )
auto& rmap = regs.second;
for( auto it =rmap.begin(); it != rmap.end(); ++it )
{
IOProperty* p(&it->second);
if( p->stype == UniversalIO::DO ||
p->stype == UniversalIO::DI )
{
uniset_rwmutex_wrlock lock(p->val_lock);
p->value = sm->value ? 1 : 0;
}
else if( p->stype == UniversalIO::AO ||
p->stype == UniversalIO::AI )
if( it->second.si.id == sm->id )
{
uniset_rwmutex_wrlock lock(p->val_lock);
p->value = sm->value;
}
IOProperty* p(&it->second);
int sz = VTypes::wsize(p->vtype);
if( p->stype == UniversalIO::DO ||
p->stype == UniversalIO::DI )
{
uniset_rwmutex_wrlock lock(p->val_lock);
p->value = sm->value ? 1 : 0;
}
else if( p->stype == UniversalIO::AO ||
p->stype == UniversalIO::AI )
{
uniset_rwmutex_wrlock lock(p->val_lock);
p->value = sm->value;
}
if( sz < 1 )
return;
int sz = VTypes::wsize(p->vtype);
// если размер больше одного слова
// то надо обновить значение "везде"
// они если "всё верно инициализировано" идут подряд
int i = 0;
if( sz < 1 )
return;
for( ; i < sz && it != iomap.end(); i++, it++ )
{
p = &it->second;
// если размер больше одного слова
// то надо обновить значение "везде"
// они если "всё верно инициализировано" идут подряд
int i = 0;
if( p->si.id == sm->id )
p->value = sm->value;
}
for( ; i < sz && it != rmap.end(); i++, it++ )
{
p = &it->second;
if( p->si.id == sm->id )
p->value = sm->value;
}
// вообще этого не может случиться
// потому-что корректность проверяется при загрузке
if( i != sz )
mbcrit << myname << "(sensorInfo): update failed for sid=" << sm->id
<< " (i=" << i << " sz=" << sz << ")" << endl;
// вообще этого не может случиться
// потому-что корректность проверяется при загрузке
if( i != sz )
mbcrit << myname << "(sensorInfo): update failed for sid=" << sm->id
<< " (i=" << i << " sz=" << sz << ")" << endl;
return;
return;
}
}
}
}
......@@ -838,6 +886,7 @@ bool MBSlave::activateObject()
UniSetObject_LT::activateObject();
initIterators();
activated = true;
startNotifyEvent.notify_all();
}
return true;
......@@ -921,6 +970,21 @@ bool MBSlave::initItem( UniXML::iterator& it )
if( !IOBase::initItem( static_cast<IOBase*>(&p), it, shm, prop_prefix, false, mblog, myname) )
return false;
std::string s_mbaddr = IOBase::initProp(it, "mbaddr", prop_prefix, false, default_mbaddr);
if( s_mbaddr.empty() )
{
mbcrit << myname << "(initItem): Unknown '" << prop_prefix << "mbaddr' for " << it.getProp("name") << endl;
return false;
}
ModbusAddr mbaddr = ModbusRTU::str2mbAddr(s_mbaddr);
// наполняем "таблицу" адресов устройства
vaddr.emplace(mbaddr); // вставляем всегда (независимо есть или нет уже элемент)
RegMap& rmap = iomap[mbaddr]; // создаём элемент (если его ещё нет) и сразу используем
if( mbregFromID )
p.mbreg = p.si.id;
else
......@@ -968,9 +1032,9 @@ bool MBSlave::initItem( UniXML::iterator& it )
return false;
}
auto i = iomap.find(p.regID);
auto i = rmap.find(p.regID);
if( i != iomap.end() )
if( i != rmap.end() )
{
if( !i->second.bitreg )
{
......@@ -1004,7 +1068,6 @@ bool MBSlave::initItem( UniXML::iterator& it )
IOBase b = p.make_iobase_copy();
AccessMode p_amode = p.amode;
VTypes::VType p_vtype = p.vtype;
int p_nbyte = p.nbyte;
bool p_rawdata = p.rawdata;
......@@ -1022,15 +1085,15 @@ bool MBSlave::initItem( UniXML::iterator& it )
p_dummy.bitreg->bvec[nbit] = std::move(p); // после этого p использовать нельзя!
mbinfo << myname << "(initItem): add bit register: " << p_dummy.bitreg.get() << endl;
iomap[p_dummy.regID] = std::move(p_dummy);
rmap[p_dummy.regID] = std::move(p_dummy);
}
return true;
}
auto i = iomap.find(p.regID);
auto i = rmap.find(p.regID);
if( i != iomap.end() )
if( i != rmap.end() )
{
ostringstream err;
err << myname << "(initItem): FAIL ADD sid='" << it.getProp("name") << "'(" << p.si.id << ")"
......@@ -1053,7 +1116,7 @@ bool MBSlave::initItem( UniXML::iterator& it )
p.vtype = VTypes::vtUnknown;
p.wnum = 0;
mbinfo << myname << "(initItem): add " << p << endl;
iomap[p.regID] = std::move(p);
rmap[p.regID] = std::move(p);
}
else
{
......@@ -1107,7 +1170,7 @@ bool MBSlave::initItem( UniXML::iterator& it )
// после std::move p - использовать нельзя!
mbinfo << myname << "(initItem): add " << p << endl;
iomap[p_regID] = std::move(p);
rmap[p_regID] = std::move(p);
if( wsz > 1 )
{
......@@ -1125,7 +1188,7 @@ bool MBSlave::initItem( UniXML::iterator& it )
p_dummy.regID = p_regID;
mbinfo << myname << "(initItem): add " << p_dummy << endl;
iomap[p_regID] = std::move(p_dummy);
rmap[p_regID] = std::move(p_dummy);
}
}
}
......@@ -1160,18 +1223,23 @@ bool MBSlave::BitRegProperty::check( const IOController_i::SensorInfo& si )
// ------------------------------------------------------------------------------------------
void MBSlave::initIterators()
{
auto it = iomap.begin();
for( ; it != iomap.end(); ++it )
for( auto&& regs: iomap )
{
shm->initIterator(it->second.ioit);
auto& rmap = regs.second;
auto it = rmap.begin();
if( it->second.bitreg )
for( ; it != rmap.end(); ++it )
{
auto b = it->second.bitreg;
shm->initIterator(it->second.ioit);
for( auto i = b->bvec.begin(); i != b->bvec.end(); ++ i )
shm->initIterator(i->ioit);
if( it->second.bitreg )
{
auto b = it->second.bitreg;
for( auto i = b->bvec.begin(); i != b->bvec.end(); ++ i )
shm->initIterator(i->ioit);
}
}
}
......@@ -1302,10 +1370,17 @@ ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage&
{
mbinfo << myname << "(readOutputRegisters): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(readOutputRegisters): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
ModbusRTU::mbErrCode ret = real_read(regmap->second, query.start, d, query.func);
if( ret == ModbusRTU::erNoError )
reply.addData(d);
......@@ -1316,7 +1391,7 @@ ModbusRTU::mbErrCode MBSlave::readOutputRegisters( ModbusRTU::ReadOutputMessage&
}
// Фомирование ответа:
ModbusRTU::mbErrCode ret = much_real_read(query.start, buf, query.count, query.func);
ModbusRTU::mbErrCode ret = much_real_read(regmap->second, query.start, buf, query.count, query.func);
if( ret == ModbusRTU::erNoError )
{
......@@ -1333,9 +1408,16 @@ ModbusRTU::mbErrCode MBSlave::writeOutputRegisters( ModbusRTU::WriteOutputMessag
{
mbinfo << myname << "(writeOutputRegisters): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(writeOutputRegisters): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
// Формирование ответа:
int fn = getOptimizeWriteFunction(query.func);
ModbusRTU::mbErrCode ret = much_real_write(query.start, query.data, query.quant, fn);
ModbusRTU::mbErrCode ret = much_real_write(regmap->second, query.start, query.data, query.quant, fn);
if( ret == ModbusRTU::erNoError )
reply.set(query.start, query.quant);
......@@ -1348,8 +1430,15 @@ ModbusRTU::mbErrCode MBSlave::writeOutputSingleRegister( ModbusRTU::WriteSingleO
{
mbinfo << myname << "(writeOutputSingleRegisters): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(writeOutputRegisters): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
int fn = getOptimizeWriteFunction(query.func);
ModbusRTU::mbErrCode ret = real_write(query.start, query.data, fn);
ModbusRTU::mbErrCode ret = real_write(regmap->second, query.start, query.data, fn);
if( ret == ModbusRTU::erNoError )
reply.set(query.start, query.data);
......@@ -1357,14 +1446,14 @@ ModbusRTU::mbErrCode MBSlave::writeOutputSingleRegister( ModbusRTU::WriteSingleO
return ret;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::much_real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
ModbusRTU::mbErrCode MBSlave::much_real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
int count, const int fn )
{
mbinfo << myname << "(much_real_write): write mbID="
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ")" << " count=" << count << " fn=" << fn << endl;
int i = 0;
auto it = iomap.end();
auto it = rmap.end();
int mbfunc = checkMBFunc ? fn : default_mbfunc;
ModbusRTU::RegID regID = genRegID(reg, mbfunc);
......@@ -1373,28 +1462,28 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( const ModbusRTU::ModbusData reg,
// ведь запросить могут начиная с "несуществующего регистра"
for( ; i < count; i++ )
{
it = iomap.find(regID + i);
it = rmap.find(regID + i);
if( it != iomap.end() )
if( it != rmap.end() )
{
regID += i;
break;
}
}
if( it == iomap.end() )
if( it == rmap.end() )
return ModbusRTU::erBadDataAddress;
int prev_i = i;
int sub = 0;
for( ; (it != iomap.end()) && (i < count); )
for( ; (it != rmap.end()) && (i < count); )
{
if( it->first == regID )
{
prev_i = i;
real_write_it(it, dat, i, count);
real_write_it(rmap, it, dat, i, count);
sub = (i - prev_i);
......@@ -1419,14 +1508,14 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( const ModbusRTU::ModbusData reg,
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn )
ModbusRTU::mbErrCode MBSlave::real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn )
{
ModbusRTU::ModbusData dat[1] = {val};
int i = 0;
return real_write(reg, dat, i, 1, fn);
return real_write(rmap, reg, dat, i, 1, fn);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn )
ModbusRTU::mbErrCode MBSlave::real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn )
{
ModbusRTU::ModbusData mbval = dat[i];
......@@ -1437,13 +1526,13 @@ ModbusRTU::mbErrCode MBSlave::real_write( const ModbusRTU::ModbusData reg, Modbu
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg, fn) : genRegID(reg, default_mbfunc);
auto it = iomap.find(regID);
return real_write_it(it, dat, i, count);
auto it = rmap.find(regID);
return real_write_it(rmap, it, dat, i, count);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_write_it( IOMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count )
ModbusRTU::mbErrCode MBSlave::real_write_it( RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count )
{
if( it == iomap.end() )
if( it == rmap.end() )
return ModbusRTU::erBadDataAddress;
IOProperty* p(&it->second);
......@@ -1690,14 +1779,14 @@ ModbusRTU::mbErrCode MBSlave::real_write_prop( IOProperty* p, ModbusRTU::ModbusD
return ModbusRTU::erTimeOut;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::much_real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
ModbusRTU::mbErrCode MBSlave::much_real_read( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat,
int count, const int fn )
{
mbinfo << myname << "(much_real_read): read mbID="
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ") " << " count=" << count
<< " mbfunc=" << fn << endl;
auto it = iomap.end();
auto it = rmap.end();
int i = 0;
int mbfunc = checkMBFunc ? fn : default_mbfunc;
......@@ -1707,9 +1796,9 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( const ModbusRTU::ModbusData reg, M
// ведь запросить могут начиная с "несуществующего регистра"
for( ; i < count; i++ )
{
it = iomap.find(regID + i);
it = rmap.find(regID + i);
if( it != iomap.end() )
if( it != rmap.end() )
{
regID += i;
break;
......@@ -1718,19 +1807,19 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( const ModbusRTU::ModbusData reg, M
dat[i] = 0;
}
if( it == iomap.end() )
if( it == rmap.end() )
return ModbusRTU::erBadDataAddress;
ModbusRTU::ModbusData val = 0;
for( ; (it != iomap.end()) && (i < count); i++, regID++ )
for( ; (it != rmap.end()) && (i < count); i++, regID++ )
{
val = 0;
// если регистры идут не подряд, то просто вернём ноль
if( it->first == regID )
{
real_read_it(it, val);
real_read_it(rmap, it, val);
++it;
}
......@@ -1748,7 +1837,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( const ModbusRTU::ModbusData reg, M
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn )
ModbusRTU::mbErrCode MBSlave::real_read( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn )
{
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg, fn) : genRegID(reg, default_mbfunc);
......@@ -1760,13 +1849,13 @@ ModbusRTU::mbErrCode MBSlave::real_read( const ModbusRTU::ModbusData reg, Modbus
<< endl;
auto it = iomap.find(regID);
return real_read_it(it, val);
auto it = rmap.find(regID);
return real_read_it(rmap, it, val);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::ModbusData& val )
ModbusRTU::mbErrCode MBSlave::real_read_it( RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData& val )
{
if( it == iomap.end() )
if( it == rmap.end() )
return ModbusRTU::erBadDataAddress;
IOProperty* p(&it->second);
......@@ -1950,10 +2039,17 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess
{
mbinfo << myname << "(readInputRegisters): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(readInputRegisters): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
ModbusRTU::mbErrCode ret = real_read(regmap->second, query.start, d, query.func);
if( ret == ModbusRTU::erNoError )
reply.addData(d);
......@@ -1964,7 +2060,7 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess
}
// Фомирование ответа:
ModbusRTU::mbErrCode ret = much_real_read(query.start, buf, query.count, query.func);
ModbusRTU::mbErrCode ret = much_real_read(regmap->second, query.start, buf, query.count, query.func);
if( ret == ModbusRTU::erNoError )
{
......@@ -2007,12 +2103,19 @@ ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query,
{
mbinfo << myname << "(readCoilStatus): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(readCoilStatus): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
try
{
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
ModbusRTU::mbErrCode ret = real_read(regmap->second,query.start, d, query.func);
reply.addData(0);
if( ret == ModbusRTU::erNoError )
......@@ -2024,7 +2127,7 @@ ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query,
return ret;
}
much_real_read(query.start, buf, query.count, query.func);
much_real_read(regmap->second, query.start, buf, query.count, query.func);
int bnum = 0;
unsigned int i = 0;
......@@ -2072,12 +2175,19 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
{
mbinfo << myname << "(readInputStatus): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(readInputStatus): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
try
{
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
ModbusRTU::mbErrCode ret = real_read(regmap->second, query.start, d, query.func);
reply.addData(0);
if( ret == ModbusRTU::erNoError )
......@@ -2089,7 +2199,7 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
return ret;
}
much_real_read(query.start, buf, query.count, query.func);
much_real_read(regmap->second, query.start, buf, query.count, query.func);
int bnum = 0;
unsigned int i = 0;
......@@ -2137,6 +2247,13 @@ ModbusRTU::mbErrCode MBSlave::forceMultipleCoils( ModbusRTU::ForceCoilsMessage&
{
mbinfo << myname << "(forceMultipleCoils): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(forceMultipleCoils): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
ModbusRTU::mbErrCode ret = ModbusRTU::erNoError;
int nbit = 0;
......@@ -2149,7 +2266,7 @@ ModbusRTU::mbErrCode MBSlave::forceMultipleCoils( ModbusRTU::ForceCoilsMessage&
for( auto k = 0; k < ModbusRTU::BitsPerByte && nbit < query.quant; k++, nbit++ )
{
// ModbusRTU::mbErrCode ret =
real_write(query.start + nbit, (b[k] ? 1 : 0), fn);
real_write(regmap->second, query.start + nbit, (b[k] ? 1 : 0), fn);
//if( ret == ModbusRTU::erNoError )
}
}
......@@ -2166,8 +2283,15 @@ ModbusRTU::mbErrCode MBSlave::forceSingleCoil( ModbusRTU::ForceSingleCoilMessage
{
mbinfo << myname << "(forceSingleCoil): " << query << endl;
auto regmap = iomap.find(query.addr);
if( regmap == iomap.end() )
{
mbinfo << myname << "(forceSingleCoil): Unknown addr=" << ModbusRTU::addr2str(query.addr) << endl;
return ModbusRTU::erTimeOut;
}
int fn = getOptimizeWriteFunction(query.func);
ModbusRTU::mbErrCode ret = real_write(query.start, (query.cmd() ? 1 : 0), fn );
ModbusRTU::mbErrCode ret = real_write(regmap->second, query.start, (query.cmd() ? 1 : 0), fn );
if( ret == ModbusRTU::erNoError )
reply.set(query.start, query.data);
......@@ -2254,7 +2378,7 @@ UniSetTypes::SimpleInfo* MBSlave::getInfo()
inf << i->info << endl;
inf << vmon.pretty_str() << endl;
inf << "LogServer: " << logserv_host << ":" << logserv_port << endl;
inf << " iomap=" << iomap.size() << endl;
inf << "iomap=" << iomap.size() << " myaddr: " << ModbusServer::vaddr2str(vaddr) << endl;
inf << "Statistic: askCount=" << askCount << " pingOK=" << pingOK << endl;
i->info = inf.str().c_str();
......
......@@ -8,6 +8,9 @@
#include <map>
#include <unordered_map>
#include <vector>
#include <condition_variable>
#include <atomic>
#include <mutex>
#include "UniSetObject_LT.h"
#include "modbus/ModbusTypes.h"
#include "modbus/ModbusServerSlot.h"
......@@ -67,7 +70,7 @@
в которой указываются настроечные параметры по умолчанию.
Пример:
\code
<MBSlave1 name="MBSlave1" addr="0x31"
<MBSlave1 name="MBSlave1" default_mbaddr="0x31"
afterSendPause="0"
reg_from_id="0"
replyTimeout="60"
......@@ -81,7 +84,7 @@
...
\endcode
- \b addr - адрес данного устройства. Если указан адрес 255 - ответ будет на любые сообщения.
- \b default_mbaddr - адрес по умолчанию для данного устройства. Если указан адрес 255 - ответ будет на любые сообщения.
- \b afterSendPause - принудительная пауза после посылки ответа
- \b reg_from_id - номер регистра брать из ID датчика
- \b replyTimeout - таймаут на формирование ответа. Если ответ на запрос будет сформирован за большее время, он не будет отослан.
......@@ -118,9 +121,9 @@
\b --xxx-name ID - идентификатор процесса.
\b --xxx-my-addr addr - slave-адрес для данного устройства. Если указан адрес 255 - ответ будет на любые сообщения.
\b --xxx-default-mbaddr addr1 - slave-адрес по умолчанию для данного устройства. Если указан адрес 255 - ответ будет на любые сообщения.
\b --xxx-timeout или \b timeout msec - таймаут на определение отсутсвия связи.
\b --xxx-timeout или \b timeout msec - таймаут на определение отсутсвия связи.
\b --xxx-reply-timeout msec - таймаут на формирование ответа.
......@@ -175,8 +178,11 @@
<sensors name="Sensors">
...
<item name="MySensor_S" textname="my sesnsor" iotype="DI"
mbs="1" mbreg="1"
mbs="1" mbs_mbaddr="0x02" mbs_mbreg="1"
/>
<item name="MySensor2_S" textname="my sesnsor 2" iotype="DI"
mbs="1" mbs_mbaddr="0x01" mbs_mbreg="1"
/>
...
</sensors>
\endcode
......@@ -184,6 +190,7 @@
\warning По умолчанию для свойств используется заданный в конструктроре префикс "mbs_".
К основным параметрам настройки датчиков относятся следующие (префикс \b mbs_ - для примера):
- \b mbs_mbadrr - адрес к которому относиться данный регистр. Если не используется параметр \b default_mbaddr.
- \b mbs_mbreg - запрашиваемый/записываемый регистр. Если не используется параметр \b reg_from_id.
Помимо этого можно задавать следующие параметры:
......@@ -430,11 +437,15 @@ class MBSlave:
// т.к. в функциях (much_real_read,nuch_real_write) рассчёт на отсортированность IOMap
// то использовать unordered_map нельзя
typedef std::map<ModbusRTU::RegID, IOProperty> IOMap;
IOMap iomap; /*!< список входов/выходов */
typedef std::map<ModbusRTU::RegID, IOProperty> RegMap;
typedef std::unordered_map<ModbusRTU::ModbusAddr,RegMap> IOMap;
IOMap iomap; /*!< список входов/выходов по адресам */
std::shared_ptr<ModbusServerSlot> mbslot;
ModbusRTU::ModbusAddr addr = { 0x01 }; /*!< адрес данного узла */
std::unordered_set<ModbusRTU::ModbusAddr> vaddr; /*!< адреса данного узла */
std::string default_mbaddr;
xmlNode* cnode;
std::string s_field;
......@@ -464,17 +475,17 @@ class MBSlave:
void readConfiguration();
bool check_item( UniXML::iterator& it );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn = 0 );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn = 0 );
ModbusRTU::mbErrCode much_real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode much_real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn = 0 );
ModbusRTU::mbErrCode real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_read( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn = 0 );
ModbusRTU::mbErrCode much_real_read( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode much_real_write( RegMap& rmap, const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_read_it( IOMap::iterator& it, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_read_it( RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_write_it( IOMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count );
ModbusRTU::mbErrCode real_write_it(RegMap& rmap, RegMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count );
ModbusRTU::mbErrCode real_bitreg_write_it( std::shared_ptr<BitRegProperty>& bp, const ModbusRTU::ModbusData val );
ModbusRTU::mbErrCode real_write_prop( IOProperty* p, ModbusRTU::ModbusData* dat, int& i, int count );
......@@ -483,6 +494,9 @@ class MBSlave:
UniSetTypes::uniset_rwmutex mutex_start;
std::shared_ptr< ThreadCreator<MBSlave> > thr;
std::mutex mutexStartNotify;
std::condition_variable startNotifyEvent;
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
......
......@@ -173,11 +173,13 @@ void MBTCPPersistentSlave::execute_tcp()
mbinfo << myname << "(execute_tcp): thread running.." << endl;
while( !cancelled )
{
try
{
sslot->waitQuery( addr, waitTimeout );
sslot->waitQuery( vaddr, waitTimeout );
// если слишком быстро обработали запрос
// то ничего не делаем..
......
......@@ -33,7 +33,7 @@
</History>
</SharedMemory>
<MBSlave1 addr="0x31" aftersend-pause="0" device="/dev/ttyS0" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
<MBSlave1 default_mbaddr="0x01" aftersend-pause="0" device="/dev/ttyS0" name="MBSlave1" poll_time="200" reply_timeout="60" speed="9600">
<filelist>
<!-- Список файлов разрешённых для передачи по modbus
directory - каталог где лежит файл. Можно не задавать
......@@ -199,6 +199,9 @@
<item id="2050" mbs="1" mbreg="259" iotype="AO" vtype="F2" name="Test_CountWrite10_F2" textname="Тестовый регистр для 0x10(F2)"/>
<item id="2051" mbs="1" mbreg="261" iotype="AO" vtype="F2" precision="1" name="Test_CountWrite10_F2prec" textname="Тестовый регистр для 0x10(F2)(prec)"/>
<item id="2053" mbs="1" mbaddr="0x02" mbreg="130" default="1" iotype="AO" name="Test_SlaveAddr2" textname="Тестовый регистр для проверки работы со вторым адресом (mbreg)"/>
<item id="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/>
......
......@@ -9,7 +9,8 @@
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
static ModbusRTU::ModbusAddr slaveaddr = 0x01;
static ModbusRTU::ModbusAddr slaveaddr2 = 0x02;
static int port = 20048; // conf->getArgInt("--mbs-inet-port");
static string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static ObjectId slaveID = 6004; // conf->getObjectID( conf->getArgParam("--mbs-name"));
......@@ -1179,4 +1180,19 @@ TEST_CASE("(0x10): write register outputs or memories [F2](precision)", "[modbus
REQUIRE( (float)r_f2 == 20.3f );
}
// -------------------------------------------------------------
TEST_CASE("Multi adress check", "[modbus][mbslave][multiaddress]")
{
using namespace VTypes;
InitTest();
ModbusRTU::ModbusData tREG = 130;
int num = 10;
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr, tREG, 1);
REQUIRE( ret.data[0] == 1 );
ModbusRTU::ReadOutputRetMessage ret2 = mb->read03(slaveaddr2, tREG, 1);
REQUIRE( ret2.data[0] == 1 );
}
// -------------------------------------------------------------
/*! \todo Доделать тесты на считывание с разными prop_prefix.. */
......@@ -9,9 +9,8 @@ cd ../../../Utilities/Admin/
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-name MBSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 20048 \
--mbs-askcount-id SVU_AskCount_AS --mbs-respond-id RespondRTU_S --mbs-respond-invert 1 \
--mbs-filter-field mbs --mbs-filter-value 1
# --dlog-add-levels any
#--mbs-check-mbfunc 1
#--dlog-add-levels any
#--mbs-log-add-levels any
\ No newline at end of file
......@@ -9,6 +9,6 @@ cd ../../../Utilities/Admin/
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-name MBSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 20048 \
--mbs-askcount-id SVU_AskCount_AS --mbs-respond-id RespondRTU_S --mbs-respond-invert 1 \
--mbs-filter-field mbs --mbs-filter-value 1
......@@ -3,6 +3,7 @@
#define ModbusRTUSlave_H_
// -------------------------------------------------------------------------
#include <string>
#include <unordered_set>
#include "Mutex.h"
#include "Debug.h"
#include "Configuration.h"
......@@ -31,7 +32,7 @@ class ModbusRTUSlave:
void setSpeed( const std::string& s );
ComPort::Speed getSpeed();
virtual ModbusRTU::mbErrCode receive( ModbusRTU::ModbusAddr addr, timeout_t msecTimeout ) override;
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout ) override;
virtual void cleanupChannel() override
{
......
......@@ -3,6 +3,7 @@
#define ModbusServer_H_
// -------------------------------------------------------------------------
#include <string>
#include <unordered_set>
#include "Debug.h"
#include "Mutex.h"
......@@ -22,12 +23,20 @@ class ModbusServer
/*! обработать очередное сообщение
\param addr - адрес для которого принимать сообщения
\param msecTimeout - время ожидания прихода очередного сообщения в мсек.
\param vaddr - вектор адресов для которых принимать сообщения
\param msecTimeout - время ожидания прихода очередного сообщения в мсек.
\return Возвращает код ошибки из ModbusRTU::mbErrCode
*/
virtual ModbusRTU::mbErrCode receive( ModbusRTU::ModbusAddr addr, timeout_t msecTimeout ) = 0;
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, timeout_t msecTimeout ) = 0;
/*! Проверка входит ли данный адрес в список
* \param vaddr - вектор адресов
* \param addr - адрес который ищем
* \return TRUE - если найден
* \warning Если addr=ModbusRTU::BroadcastAddr то всегда возвращается TRUE!
*/
static bool checkAddr( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, const ModbusRTU::ModbusAddr addr );
static std::string vaddr2str( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr );
/*! Установка паузы после посылки
\return старое значение
......@@ -245,7 +254,7 @@ class ModbusServer
virtual ModbusRTU::mbErrCode processing( ModbusRTU::ModbusMessage& buf );
/*! принять сообщение из канала */
ModbusRTU::mbErrCode recv( ModbusRTU::ModbusAddr addr, ModbusRTU::ModbusMessage& buf, timeout_t timeout );
ModbusRTU::mbErrCode recv(const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, ModbusRTU::ModbusMessage& buf, timeout_t timeout );
ModbusRTU::mbErrCode recv_pdu( ModbusRTU::ModbusMessage& rbuf, timeout_t timeout );
UniSetTypes::uniset_mutex recvMutex;
......
......@@ -24,13 +24,13 @@ class ModbusTCPServer:
virtual ~ModbusTCPServer();
/*! Однопоточная обработка (каждый запрос последовательно), с разрывом соединения в конце */
virtual ModbusRTU::mbErrCode receive( ModbusRTU::ModbusAddr mbaddr, timeout_t msecTimeout ) override;
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout ) override;
/*! Многопоточная обработка (создаётся по потоку для каждого "клиента")
\return TRUE - если запр*ос пришёл
\return TRUE - если запрос пришёл
\return FALSE - если timeout
*/
virtual bool waitQuery( ModbusRTU::ModbusAddr mbaddr, timeout_t msec = UniSetTimer::WaitUpTime );
virtual bool waitQuery( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msec = UniSetTimer::WaitUpTime );
void setMaxSessions( unsigned int num );
inline unsigned int getMaxSessions()
......
......@@ -4,6 +4,7 @@
// -------------------------------------------------------------------------
#include <string>
#include <queue>
#include <unordered_map>
#include <cc++/socket.h>
#include "ModbusServerSlot.h"
#include "ModbusServer.h"
......@@ -16,7 +17,7 @@ class ModbusTCPSession:
{
public:
ModbusTCPSession( ost::TCPSocket& server, ModbusRTU::ModbusAddr mbaddr, timeout_t timeout );
ModbusTCPSession( ost::TCPSocket& server, const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t timeout );
virtual ~ModbusTCPSession();
void cleanInputStream();
......@@ -27,7 +28,7 @@ class ModbusTCPSession:
}
virtual void terminate();
virtual ModbusRTU::mbErrCode receive( ModbusRTU::ModbusAddr addr, timeout_t msecTimeout );
virtual ModbusRTU::mbErrCode receive( const std::unordered_set<ModbusRTU::ModbusAddr>& vmbaddr, timeout_t msecTimeout );
typedef sigc::slot<void, ModbusTCPSession*> FinalSlot;
......@@ -99,7 +100,7 @@ class ModbusTCPSession:
private:
std::queue<unsigned char> qrecv;
ModbusTCP::MBAPHeader curQueryHeader;
ModbusRTU::ModbusAddr addr;
std::unordered_set<ModbusRTU::ModbusAddr> vaddr;
PassiveTimer ptTimeout;
timeout_t timeout;
ModbusRTU::ModbusMessage buf;
......
......@@ -63,7 +63,7 @@ ModbusRTUSlave::~ModbusRTUSlave()
delete port;
}
// -------------------------------------------------------------------------
mbErrCode ModbusRTUSlave::receive( ModbusRTU::ModbusAddr addr, timeout_t timeout )
mbErrCode ModbusRTUSlave::receive(const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t timeout )
{
uniset_mutex_lock lck(recvMutex, timeout);
......@@ -80,7 +80,7 @@ mbErrCode ModbusRTUSlave::receive( ModbusRTU::ModbusAddr addr, timeout_t timeout
do
{
res = recv(addr, buf, timeout);
res = recv(vmbaddr, buf, timeout);
if( res != erNoError && res != erBadReplyNodeAddress )
{
......@@ -94,9 +94,9 @@ mbErrCode ModbusRTUSlave::receive( ModbusRTU::ModbusAddr addr, timeout_t timeout
printProcessingTime();
}
// dlog->warn() << "(receive): " << mbErr2Str(res) << endl;
// cerr << "**** (receive): " << mbErr2Str(res) << endl;
usleep(10000);
if( aftersend_msec >= 0 )
msleep(aftersend_msec);
// usleep(10000);
return res;
}
......
......@@ -66,6 +66,26 @@ timeout_t ModbusServer::setAfterSendPause( timeout_t msec )
return old;
}
// --------------------------------------------------------------------------------
bool ModbusServer::checkAddr(const std::unordered_set<ModbusAddr>& vaddr, const ModbusRTU::ModbusAddr addr )
{
if( addr == ModbusRTU::BroadcastAddr )
return true;
auto i = vaddr.find(addr);
return (i!=vaddr.end());
}
// --------------------------------------------------------------------------------
std::string ModbusServer::vaddr2str( const std::unordered_set<ModbusAddr>& vaddr )
{
ostringstream s;
s << "[ ";
for( const auto& a: vaddr )
s << addr2str(a) << " ";
s <<"]";
return std::move(s.str());
}
// --------------------------------------------------------------------------------
mbErrCode ModbusServer::processing( ModbusMessage& buf )
{
if( buf.func == fnReadCoilStatus )
......@@ -540,7 +560,7 @@ mbErrCode ModbusServer::processing( ModbusMessage& buf )
}
// -------------------------------------------------------------------------
mbErrCode ModbusServer::recv( ModbusRTU::ModbusAddr addr, ModbusMessage& rbuf, timeout_t timeout )
mbErrCode ModbusServer::recv( const std::unordered_set<ModbusRTU::ModbusAddr>& vaddr, ModbusMessage& rbuf, timeout_t timeout )
{
assert(timeout);
......@@ -563,7 +583,7 @@ mbErrCode ModbusServer::recv( ModbusRTU::ModbusAddr addr, ModbusMessage& rbuf, t
{
bcnt = getNextData((unsigned char*)(&rbuf), sizeof(ModbusAddr));
if( bcnt > 0 && ( rbuf.addr == addr || (onBroadcast && rbuf.addr == BroadcastAddr) || addr == BroadcastAddr ) )
if( bcnt > 0 && checkAddr(vaddr,rbuf.addr) )
{
begin = true;
break;
......@@ -579,12 +599,12 @@ mbErrCode ModbusServer::recv( ModbusRTU::ModbusAddr addr, ModbusMessage& rbuf, t
// Lav: конечно стоит, нам же надо буфер чистить
*/
// Проверка кому адресован пакет... (только если не включён режим отвечать на любые адреса)
if( addr != BroadcastAddr && rbuf.addr != addr && rbuf.addr != BroadcastAddr )
if( !(onBroadcast && rbuf.addr == BroadcastAddr) && !checkAddr(vaddr,rbuf.addr) )
{
if( dlog->is_warn() )
{
ostringstream err;
err << "(recv): BadNodeAddress. my= " << addr2str(addr)
err << "(recv): BadNodeAddress. my= " << vaddr2str(vaddr)
<< " msg.addr=" << addr2str(rbuf.addr);
dlog->warn() << err.str() << endl;
}
......
......@@ -54,7 +54,7 @@ void ModbusTCPServer::setSessionTimeout( timeout_t msec )
sessTimeout = msec;
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::waitQuery( ModbusRTU::ModbusAddr mbaddr, timeout_t msec )
bool ModbusTCPServer::waitQuery(const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t msec )
{
if( msec == 0 )
msec = UniSetTimer::WaitUpTime;
......@@ -72,7 +72,7 @@ bool ModbusTCPServer::waitQuery( ModbusRTU::ModbusAddr mbaddr, timeout_t msec )
if( cancelled )
return false;
ModbusTCPSession* s = new ModbusTCPSession(*this, mbaddr, sessTimeout);
ModbusTCPSession* s = new ModbusTCPSession(*this, vmbaddr, sessTimeout);
s->connectReadCoil( sigc::mem_fun(this, &ModbusTCPServer::readCoilStatus) );
s->connectReadInputStatus( sigc::mem_fun(this, &ModbusTCPServer::readInputStatus) );
......@@ -118,7 +118,7 @@ bool ModbusTCPServer::waitQuery( ModbusRTU::ModbusAddr mbaddr, timeout_t msec )
return false;
}
// -------------------------------------------------------------------------
mbErrCode ModbusTCPServer::receive( ModbusRTU::ModbusAddr addr, timeout_t timeout )
mbErrCode ModbusTCPServer::receive(const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t timeout )
{
PassiveTimer ptTimeout(timeout);
ModbusMessage buf;
......@@ -171,46 +171,21 @@ mbErrCode ModbusTCPServer::receive( ModbusRTU::ModbusAddr addr, timeout_t timeou
}
}
if( !qrecv.empty() )
if( qrecv.empty() )
{
// check addr
unsigned char _addr = qrecv.front();
// для режима игнорирования RTU-адреса
// просто подменяем его на то который пришёл
// чтобы проверка всегда была успешной...
if( ignoreAddr )
addr = _addr;
else if( (onBroadcast && _addr == BroadcastAddr) || addr==ModbusRTU::BroadcastAddr )
{
// нормально обрабатываем..
}
else if( _addr != addr )
{
res = erTimeOut;
// На такие запросы просто не отвечаем...
/*
res = erBadReplyNodeAddress;
tmProcessing.setTiming(replyTimeout_ms);
ErrorRetMessage em( _addr, buf.func, res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
if( aftersend_msec >= 0 )
msleep(aftersend_msec);
*/
tcp.disconnect();
return res;
}
tcp.disconnect();
return erTimeOut;
}
res = recv( addr, buf, timeout );
unsigned char q_addr = qrecv.front();
res = recv( vmbaddr, buf, timeout );
if( res != erNoError ) // && res!=erBadReplyNodeAddress )
{
if( res < erInternalErrorCode )
{
ErrorRetMessage em( addr, buf.func, res );
ErrorRetMessage em( q_addr, buf.func, res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
......@@ -247,9 +222,10 @@ mbErrCode ModbusTCPServer::receive( ModbusRTU::ModbusAddr addr, timeout_t timeou
tcp.disconnect();
}
}
catch( ost::Exception& e )
catch( const ost::Exception& e )
{
cout << "(ModbusTCPServer): " << e.what() << endl;
if( dlog->is_crit() )
dlog->crit() << "(ModbusTCPServer): " << e.what() << endl;
return erInternalErrorCode;
}
......
......@@ -22,9 +22,9 @@ ModbusTCPSession::~ModbusTCPSession()
ost::Thread::join();
}
// -------------------------------------------------------------------------
ModbusTCPSession::ModbusTCPSession( ost::TCPSocket& server, ModbusRTU::ModbusAddr a, timeout_t timeout ):
ModbusTCPSession::ModbusTCPSession(ost::TCPSocket& server, const std::unordered_set<ModbusAddr>& a, timeout_t timeout ):
TCPSession(server),
addr(a),
vaddr(a),
timeout(timeout),
peername(""),
caddr(""),
......@@ -94,7 +94,7 @@ void ModbusTCPSession::run()
if( n == 0 )
break;
res = receive(addr, timeout);
res = receive(vaddr, timeout);
if( res == erSessionClosed )
break;
......@@ -118,7 +118,7 @@ void ModbusTCPSession::run()
dlog->info() << peername << "(run): thread stopping..." << endl;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode ModbusTCPSession::receive( ModbusRTU::ModbusAddr addr, timeout_t msec )
ModbusRTU::mbErrCode ModbusTCPSession::receive( const std::unordered_set<ModbusAddr>& vmbaddr, timeout_t msec )
{
ModbusRTU::mbErrCode res = erTimeOut;
ptTimeout.setTiming(msec);
......@@ -138,28 +138,16 @@ ModbusRTU::mbErrCode ModbusTCPSession::receive( ModbusRTU::ModbusAddr addr, time
return erTimeOut;
}
if( !qrecv.empty() )
{
// check addr
unsigned char _addr = qrecv.front();
// для режима игнорирования RTU-адреса
// просто подменяем его на то который пришёл
// чтобы проверка всегда была успешной...
if( ignoreAddr )
addr = _addr;
else if( _addr != addr )
{
// На такие запросы просто не отвечаем...
return erTimeOut;
}
}
if( qrecv.empty() )
return erTimeOut;
unsigned char q_addr = qrecv.front();
if( cancelled )
return erSessionClosed;
memset(&buf, 0, sizeof(buf));
res = recv( addr, buf, msec );
res = recv( vmbaddr, buf, msec );
if( cancelled )
return erSessionClosed;
......@@ -168,7 +156,7 @@ ModbusRTU::mbErrCode ModbusTCPSession::receive( ModbusRTU::ModbusAddr addr, time
{
if( res < erInternalErrorCode )
{
ErrorRetMessage em( addr, buf.func, res );
ErrorRetMessage em( q_addr, buf.func, res );
buf = em.transport_msg();
send(buf);
printProcessingTime();
......
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