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;
}
......
......@@ -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