Commit 6cfdf2fe authored by Pavel Vainerman's avatar Pavel Vainerman

add new realisation MBTCPMaster

parent b6dd259c
......@@ -3,7 +3,7 @@
Name: libuniset
Version: 0.96
Release: eter53
Release: eter56
Summary: UniSet - library for building distributed industrial control systems
License: GPL
Group: Development/C++
......@@ -175,6 +175,15 @@ rm -f %buildroot%_libdir/*.la
%exclude %_pkgconfigdir/libUniSet.pc
%changelog
* Mon Sep 07 2009 Pavel Vainerman <pv@altlinux.ru> 0.96-eter55
- new build
* Mon Sep 07 2009 Pavel Vainerman <pv@altlinux.ru> 0.96-eter54
- rebuild for new ModbusType parameters
* Mon Sep 07 2009 Pavel Vainerman <pv@altlinux.ru> 0.96-eter53
- rebuild for new MBTCPMaster
* Sun Sep 06 2009 Pavel Vainerman <pv@altlinux.ru> 0.96-eter52
- minor fixes in MBTCPMAster
......
// $Id: MBMaster.cc,v 1.11 2009/03/03 10:33:27 pv Exp $
// -----------------------------------------------------------------------------
#include <cmath>
#include <sstream>
#include "Exceptions.h"
#include "Extensions.h"
#include "MBMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
using namespace ModbusRTU;
// -----------------------------------------------------------------------------
MBMaster::MBMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic,
std::string prefix):
UniSetObject_LT(objId),
mbmap(100),
maxItem(0),
mb(0),
shm(0),
initPause(0),
mbregFromID(false),
force(false),
force_out(false),
activated(false),
prefix(prefix)
{
cout << "$Id: MBMaster.cc,v 1.11 2009/03/03 10:33:27 pv Exp $" << endl;
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(MBMaster): objId=-1?!! Use --mbtcp-name" );
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(MBMaster): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
//
s_field = conf->getArgParam("--" + prefix + "-filter-field");
s_fvalue = conf->getArgParam("--" + prefix + "-filter-value");
dlog[Debug::INFO] << myname << "(init): read s_field='" << s_field
<< "' s_fvalue='" << s_fvalue << "'" << endl;
// ---------- init MBTCP ----------
string pname("--" + prefix + "-iaddr");
iaddr = conf->getArgParam(pname,it.getProp("iaddr"));
if( iaddr.empty() )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet addr...(Use: " + pname +")" );
string tmp("--" + prefix + "-port");
port = conf->getArgInt(tmp,it.getProp("port"));
if( port <= 0 )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet port...(Use: " + tmp +")" );
recv_timeout = conf->getArgInt("--" + prefix + "-recv-timeout",it.getProp("recv_timeout"));
if( recv_timeout <= 0 )
recv_timeout = 2000;
string saddr = conf->getArgParam("--" + prefix + "-my-addr",it.getProp("addr"));
myaddr = ModbusRTU::str2mbAddr(saddr);
if( saddr.empty() )
myaddr = 0x00;
mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id",it.getProp("reg_from_id"));
dlog[Debug::INFO] << myname << "(init): mbregFromID=" << mbregFromID << endl;
polltime = conf->getArgInt("--" + prefix + "-polltime",it.getProp("polltime"));
if( !polltime )
polltime = 100;
initPause = conf->getArgInt("--" + prefix + "-initPause",it.getProp("initPause"));
if( !initPause )
initPause = 3000;
force = conf->getArgInt("--" + prefix + "-force",it.getProp("force"));
if( shm->isLocalwork() )
{
readConfiguration();
mbmap.resize(maxItem);
dlog[Debug::INFO] << myname << "(init): mbmap size = " << mbmap.size() << endl;
}
else
ic->addReadItem( sigc::mem_fun(this,&MBMaster::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix +"-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": 'HeartBeat' " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = conf->getArgInt("--" + prefix + "-heartbeat-max",it.getProp("heartbeat_max"));
if( maxHeartBeat <= 0 )
maxHeartBeat = 10;
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << ": test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
activateTimeout = conf->getArgInt("--" + prefix + "-activate-timeout");
if( activateTimeout <= 0 )
activateTimeout = 20000;
timeout_t msec = conf->getArgInt("--" + prefix + "-timeout",it.getProp("timeout"));
if( msec == 0 )
msec = 3000;
ptTimeout.setTiming(msec);
dlog[Debug::INFO] << myname << "(init): " << prefix << "-timeout=" << msec << " msec" << endl;
}
// -----------------------------------------------------------------------------
MBMaster::~MBMaster()
{
if( mb )
mb->disconnect();
delete mb;
}
// -----------------------------------------------------------------------------
void MBMaster::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = conf->getArgInt("--" + prefix + "-sm-ready-timeout","15000");
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): SharedMemory " << ready_timeout << " ";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void MBMaster::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
step();
}
// -----------------------------------------------------------------------------
void MBMaster::step()
{
{
uniset_mutex_lock l(pollMutex,2000);
try
{
poll();
}
catch(Exception& ex )
{
cerr << myname << "(step): " << ex << std::endl;
}
}
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void MBMaster::init_mb()
{
if( mb )
return;
try
{
ost::Thread::setException(ost::Thread::throwException);
ost::InetAddress ia(iaddr.c_str());
mb = new ModbusTCPMaster();
mb->connect(ia,port);
mb->setTimeout(recv_timeout);
mb->setLog(dlog);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << ": create 'ModbusMaster' failed: " << ex << endl;
throw;
}
dlog[Debug::INFO] << myname << "(init): myaddr=" << ModbusRTU::addr2str(myaddr)
<< " iaddr=" << iaddr << " port=" << port << endl;
}
// -----------------------------------------------------------------------------
void MBMaster::poll()
{
init_mb();
for( MBMap::iterator it=mbmap.begin(); it!=mbmap.end(); ++it )
{
if( !activated )
return;
if( it->mbaddr == 0 ) // || it->mbreg == 0 )
continue;
if( it->si.id == DefaultObjectId )
{
cerr << myname << "(poll): sid=DefaultObjectId?!" << endl;
continue;
}
IOBase* ib = &(*it);
try
{
if( it->stype == UniversalIO::AnalogInput )
{
long val = readReg(it);
IOBase::processingAsAI( ib, val, shm, force );
}
else if( it->stype == UniversalIO::DigitalInput )
{
bool set = readReg(it) ? true : false;
IOBase::processingAsDI( ib, set, shm, force );
}
else if( it->stype == UniversalIO::AnalogOutput )
{
long val = IOBase::processingAsAO(ib,shm,force_out);
writeReg(it,val);
}
else if( it->stype == UniversalIO::DigitalOutput )
{
long val = IOBase::processingAsDO(ib,shm,force_out) ? 1 : 0;
writeReg(it,val);
}
}
catch(ModbusRTU::mbException& ex )
{
dlog[Debug::LEVEL3] << myname << "(poll): " << ex << endl;
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(poll):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(poll):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(poll): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(poll): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(poll): ORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(poll): catch ..." << endl;
}
}
for( MBMap::iterator it=mbmap.begin(); it!=mbmap.end(); ++it )
IOBase::processingThreshold(&(*it),shm,force);
}
// -----------------------------------------------------------------------------
long MBMaster::readReg( MBMap::iterator& p )
{
try
{
if( p->mbfunc == ModbusRTU::fnReadInputRegisters )
{
// if( dlog.debugging(Debug::LEVEL3) )
// dlog[Debug::LEVEL3] << " read from " << ModbusRTU::addr2str(p->mbaddr) << " reg=" << ModbusRTU::dat2str(p->mbreg) << endl;
cerr << " read from " << ModbusRTU::addr2str(p->mbaddr) << " reg=" << ModbusRTU::dat2str(p->mbreg) << endl;
ModbusRTU::ReadInputRetMessage ret = mb->read04(p->mbaddr,p->mbreg,1);
return ret.data[0];
}
if( p->mbfunc == ModbusRTU::fnReadOutputRegisters )
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(p->mbaddr,p->mbreg,1);
return ret.data[0];
}
cerr << myname << "(readReg): " << (int)p->mbfunc << endl;
}
catch( ModbusRTU::mbException& ex )
{
dlog[Debug::CRIT] << "(readReg): " << ex << endl;
}
catch(SystemError& err)
{
dlog[Debug::CRIT] << "(readReg): " << err << endl;
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << "(readReg): " << ex << endl;
}
catch( ost::SockException& e )
{
dlog[Debug::CRIT] << "(readReg): " << e.getString() << ": " << e.getSystemErrorString() << endl;
}
return 0;
}
// -----------------------------------------------------------------------------
bool MBMaster::writeReg( MBMap::iterator& p, long val )
{
if( p->mbfunc == fnWriteOutputRegisters )
{
ModbusRTU::WriteOutputMessage msg(p->mbaddr,p->mbreg);
msg.addData(val);
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
return true;
}
if( p->mbfunc == ModbusRTU::fnForceSingleCoil )
{
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(p->mbaddr,p->mbreg,(bool)val);
return false;
}
if( p->mbfunc == fnWriteOutputSingleRegister )
{
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(p->mbaddr,p->mbreg,val);
return true;
}
if( p->mbfunc == fnForceMultipleCoils )
{
ModbusRTU::ForceCoilsMessage msg(p->mbaddr,p->mbreg);
msg.addBit( val ? true : false );
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
return true;
}
cerr << myname << "(writeReg): " << (int)p->mbfunc << endl;
return false;
}
// -----------------------------------------------------------------------------
void MBMaster::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
break;
}
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
raise(SIGTERM);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void MBMaster::sysCommand(UniSetTypes::SystemMessage *sm)
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
if( mbmap.empty() )
{
dlog[Debug::CRIT] << myname << "(sysCommand): mbmap EMPTY! terminated..." << endl;
raise(SIGTERM);
return;
}
waitSMReady();
// ģ
// . activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
initOutput();
}
askTimer(tmExchange,polltime);
//
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
break;
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ( )
// ģ
// (.. MBMaster SharedMemory2)
// WatchDog , .. ģ SM
// , SM , (MBMaster)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
initOutput();
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
}
break;
case SystemMessage::LogRotate:
{
//
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname.c_str());
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname.c_str());
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void MBMaster::initOutput()
{
}
// ------------------------------------------------------------------------------------------
void MBMaster::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): (work) SharedMemory "
<< activateTimeout << " ";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // () ...
throw SystemError(err.str());
}
MBMap::iterator it=mbmap.begin();
for( ; it!=mbmap.end(); ++it )
{
if( it->stype != UniversalIO::DigitalOutput && it->stype != UniversalIO::AnalogOutput )
continue;
if( it->safety == NoSafetyState )
continue;
try
{
shm->askSensor(it->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...){}
}
}
// ------------------------------------------------------------------------------------------
void MBMaster::sensorInfo( UniSetTypes::SensorMessage* sm )
{
MBMap::iterator it=mbmap.begin();
for( ; it!=mbmap.end(); ++it )
{
if( it->stype != UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
continue;
if( it->si.id == sm->id )
{
if( it->stype == UniversalIO::DigitalOutput )
{
uniset_spin_lock lock(it->val_lock);
it->value = sm->state ? 1 : 0;
}
else if( it->stype == UniversalIO::AnalogOutput )
{
uniset_spin_lock lock(it->val_lock);
it->value = sm->value;
}
break;
}
}
}
// ------------------------------------------------------------------------------------------
bool MBMaster::activateObject()
{
// Starsp
// ģ
// . sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBMaster::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
MBMap::iterator it=mbmap.begin();
for( ; it!=mbmap.end(); ++it )
{
if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
continue;
if( it->safety == NoSafetyState )
continue;
try
{
#warning ...
// ....
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
catch(...){}
}
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void MBMaster::readConfiguration()
{
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): <sensors> ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool MBMaster::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool MBMaster::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
bool MBMaster::initItem( UniXML_iterator& it )
{
MBProperty p;
if( !IOBase::initItem( static_cast<IOBase*>(&p),it,shm,&dlog,myname) )
return false;
string addr = it.getProp("mbaddr");
if( addr.empty() )
return true;
if( mbregFromID )
p.mbreg = p.si.id;
else
{
string r = it.getProp("mbreg");
if( r.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl;
return false;
}
p.mbreg = ModbusRTU::str2mbData(r);
}
p.mbaddr = ModbusRTU::str2mbAddr(addr);
string stype( it.getProp("mb_iotype") );
if( stype.empty() )
stype = it.getProp("iotype");
if( stype == "AI" )
{
p.stype = UniversalIO::AnalogInput;
p.mbfunc = ModbusRTU::fnReadInputRegisters;
}
else if ( stype == "DI" )
{
p.stype = UniversalIO::DigitalInput;
p.mbfunc = ModbusRTU::fnReadInputRegisters;
}
else if ( stype == "AO" )
{
p.stype = UniversalIO::AnalogOutput;
p.mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if ( stype == "DO" )
{
p.stype = UniversalIO::DigitalOutput;
p.mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
string f = it.getProp("mbfunc");
if( !f.empty() )
{
p.mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(f);
if( p.mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initItem): mbfunc ='" << f
<< "' " << it.getProp("name") << endl;
return false;
}
}
if( p.mbfunc == ModbusRTU::fnReadCoilStatus ||
p.mbfunc == ModbusRTU::fnReadInputStatus )
{
string nb = it.getProp("nbit");
if( nb.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown nbit. for "
<< it.getProp("name")
<< " mbfunc=" << p.mbfunc
<< endl;
return false;
}
p.nbit = UniSetTypes::uni_atoi(nb);
}
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(initItem): add " << p << endl;
//
// 10 ( )
// resize
//
if( maxItem >= mbmap.size() )
mbmap.resize(maxItem+10);
mbmap[maxItem] = p;
maxItem++;
return true;
}
// ------------------------------------------------------------------------------------------
void MBMaster::initIterators()
{
MBMap::iterator it=mbmap.begin();
for( ; it!=mbmap.end(); it++ )
{
shm->initDIterator(it->dit);
shm->initAIterator(it->ait);
}
shm->initAIterator(aitHeartBeat);
}
// -----------------------------------------------------------------------------
void MBMaster::help_print( int argc, const char* const* argv )
{
cout << "Default: prefix='mbtcp'" << endl;
cout << "--prefix-polltime msec - . 200 ." << endl;
cout << "--prefix-heartbeat-id - heartbeat-." << endl;
cout << "--prefix-heartbeat-max - heartbeat-ޣ . 10." << endl;
cout << "--prefix-ready-timeout - SM , . (-1 - '')" << endl;
cout << "--prefix-force - SM, , " << endl;
cout << "--prefix-initPause - ( )" << endl;
cout << "--prefix-notRespondSensor - " << endl;
cout << "--prefix-sm-ready-timeout - SM" << endl;
cout << " RS: " << endl;
cout << "--prefix-iadrr ip - IP" << endl;
cout << "--prefix-port port - Port." << endl;
cout << "--prefix-my-addr - " << endl;
cout << "--prefix-recv-timeout - ." << endl;
}
// -----------------------------------------------------------------------------
MBMaster* MBMaster::init_mbmaster( int argc, const char* const* argv, UniSetTypes::ObjectId shmID, SharedMemory* ic,
std::string prefix )
{
string name = conf->getArgParam("--" + prefix + "-name","MBTCPMaster1");
if( name.empty() )
{
cerr << "(mbtcpexchange): name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(mbtcpexchange): '" << name
<< "' . !"
<< " " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(mbtcpexchange): name = " << name << "(" << ID << ")" << endl;
return new MBMaster(ID,shmID,ic,prefix);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBMaster::MBProperty& p )
{
os << " mbaddr=(" << (int)p.mbaddr << ")" << ModbusRTU::addr2str(p.mbaddr)
<< " reg=" << ModbusRTU::dat2str(p.mbreg)
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " safety=" << p.safety
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AnalogInput || p.stype == UniversalIO::AnalogOutput )
{
os << " rmin=" << p.cal.minRaw
<< " rmax=" << p.cal.maxRaw
<< " cmin=" << p.cal.maxCal
<< " cmax=" << p.cal.maxCal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
// $Id: MBMaster.h,v 1.7 2009/03/03 10:33:27 pv Exp $
// -----------------------------------------------------------------------------
#ifndef _MBMaster_H_
#define _MBMaster_H_
// -----------------------------------------------------------------------------
#include <string>
#include <vector>
#include "UniSetObject_LT.h"
#include "IONotifyController.h"
#include "modbus/ModbusTCPMaster.h"
#include "PassiveTimer.h"
#include "Trigger.h"
#include "Mutex.h"
#include "SharedMemory.h"
#include "IOBase.h"
#include "SMInterface.h"
// -----------------------------------------------------------------------------
class MBMaster:
public UniSetObject_LT
{
public:
MBMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, SharedMemory* ic=0,
std::string prefix="mbtcp" );
virtual ~MBMaster();
/*! */
static MBMaster* init_mbmaster( int argc, const char* const* argv, UniSetTypes::ObjectId shmID, SharedMemory* ic=0,
std::string prefix="mbtcp" );
/*! help- */
static void help_print( int argc, const char* const* argv );
static const int NoSafetyState=-1;
enum Timer
{
tmExchange
};
struct MBProperty:
public IOBase
{
ModbusRTU::ModbusAddr mbaddr; /*!< */
ModbusRTU::ModbusData mbreg; /*!< */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< / */
short nbit; /*!< bit number (for func=[0x01,0x02]) */
MBProperty():
mbaddr(0),mbreg(0),
mbfunc(ModbusRTU::fnUnknown),nbit(0)
{}
friend std::ostream& operator<<( std::ostream& os, MBProperty& p );
};
protected:
typedef std::vector<MBProperty> MBMap;
MBMap mbmap; /*!< / */
unsigned int maxItem; /*!< ( ) */
ModbusTCPMaster* mb;
UniSetTypes::uniset_mutex mbMutex;
std::string iaddr;
int port;
int recv_timeout;
ModbusRTU::ModbusAddr myaddr;
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void step();
void poll();
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void timerInfo( UniSetTypes::TimerMessage *tm );
void askSensors( UniversalIO::UIOCommand cmd );
void initOutput();
void waitSMReady();
long readReg( MBMap::iterator& p );
bool writeReg( MBMap::iterator& p, long val );
virtual bool activateObject();
//
virtual void sigterm( int signo );
void init_mb();
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void readConfiguration();
bool check_item( UniXML_iterator& it );
private:
MBMaster();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
bool mbregFromID;
bool force; /*!< , SM, */
bool force_out; /*!< , */
int polltime; /*!< , [] */
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
UniSetTypes::uniset_mutex pollMutex;
Trigger trTimeout;
PassiveTimer ptTimeout;
bool activated;
int activateTimeout;
std::string prefix;
};
// -----------------------------------------------------------------------------
#endif // _MBMaster_H_
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
#include <cmath>
#include <sstream>
#include <Exceptions.h>
#include <extensions/Extensions.h>
#include "MBTCPMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
MBTCPMaster::MBTCPMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId,
SharedMemory* ic, const std::string prefix ):
UniSetObject_LT(objId),
mb(0),
shm(0),
initPause(0),
force(false),
force_out(false),
mbregFromID(false),
activated(false),
noQueryOptimization(false),
allNotRespond(false),
prefix(prefix)
{
// cout << "$ $" << endl;
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(MBTCPMaster): objId=-1?!! Use --" + prefix + "-name" );
// xmlNode* cnode = conf->getNode(myname);
cnode = conf->getNode(myname);
if( cnode == NULL )
throw UniSetTypes::SystemError("(MBTCPMaster): Not find conf-node for " + myname );
shm = new SMInterface(shmId,&ui,objId,ic);
UniXML_iterator it(cnode);
//
s_field = conf->getArgParam("--" + prefix + "-filter-field");
s_fvalue = conf->getArgParam("--" + prefix + "-filter-value");
dlog[Debug::INFO] << myname << "(init): read fileter-field='" << s_field
<< "' filter-value='" << s_fvalue << "'" << endl;
// ---------- init MBTCP ----------
string pname("--" + prefix + "-gateway-iaddr");
iaddr = conf->getArgParam(pname,it.getProp("gateway_iaddr"));
if( iaddr.empty() )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet addr...(Use: " + pname +")" );
string tmp("--" + prefix + "-gateway-port");
port = atoi(conf->getArgParam(tmp,it.getProp("gateway_port")).c_str());
if( port<=0 )
throw UniSetTypes::SystemError(myname+"(MBMaster): Unknown inet port...(Use: " + tmp +")" );
recv_timeout = atoi(conf->getArgParam("--" + prefix + "-recv-timeout",it.getProp("recv_timeout")).c_str());
if( recv_timeout <= 0 )
recv_timeout = 50;
int alltout = atoi(conf->getArgParam("--" + prefix + "-all-timeout",it.getProp("all_timeout")).c_str());
if( alltout <=0 )
alltout = 2000;
ptAllNotRespond.setTiming(alltout);
noQueryOptimization = atoi(conf->getArgParam("--" + prefix + "-no-query-optimization",it.getProp("no_query_optimization")).c_str());
mbregFromID = atoi(conf->getArgParam("--" + prefix + "-reg-from-id",it.getProp("reg_from_id")).c_str());
dlog[Debug::INFO] << myname << "(init): mbregFromID=" << mbregFromID << endl;
polltime = atoi(conf->getArgParam("--" + prefix + "-polltime",it.getProp("polltime")).c_str());
if( !polltime )
polltime = 100;
initPause = atoi(conf->getArgParam("--" + prefix + "-initPause",it.getProp("initPause")).c_str());
if( !initPause )
initPause = 3000;
force = atoi(conf->getArgParam("--" + prefix + "-force",it.getProp("force")).c_str());
force_out = atoi(conf->getArgParam("--" + prefix + "-force-out",it.getProp("force_out")).c_str());
if( shm->isLocalwork() )
{
readConfiguration();
rtuQueryOptimization(rmap);
initDeviceList();
}
else
ic->addReadItem( sigc::mem_fun(this,&MBTCPMaster::readItem) );
// ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix + "-heartbeat-id",it.getProp("heartbeat_id"));
if( !heart.empty() )
{
sidHeartBeat = conf->getSensorID(heart);
if( sidHeartBeat == DefaultObjectId )
{
ostringstream err;
err << myname << ": ID not found ('HeartBeat') for " << heart;
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
int heartbeatTime = getHeartBeatTime();
if( heartbeatTime )
ptHeartBeat.setTiming(heartbeatTime);
else
ptHeartBeat.setTiming(UniSetTimer::WaitUpTime);
maxHeartBeat = atoi(conf->getArgParam("--" + prefix + "-heartbeat-max",it.getProp("heartbeat_max")).c_str());
if( maxHeartBeat <=0 )
maxHeartBeat = 10;
test_id = sidHeartBeat;
}
else
{
test_id = conf->getSensorID("TestMode_S");
if( test_id == DefaultObjectId )
{
ostringstream err;
err << myname << "(init): test_id unknown. 'TestMode_S' not found...";
dlog[Debug::CRIT] << myname << "(init): " << err.str() << endl;
throw SystemError(err.str());
}
}
dlog[Debug::INFO] << myname << "(init): test_id=" << test_id << endl;
activateTimeout = atoi(conf->getArgParam("--" + prefix + "-activate-timeout").c_str());
if( activateTimeout<=0 )
activateTimeout = 20000;
initMB(false);
printMap(rmap);
// abort();
}
// -----------------------------------------------------------------------------
MBTCPMaster::~MBTCPMaster()
{
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
delete it->second;
delete it1->second;
}
delete mb;
delete shm;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::initMB( bool reopen )
{
if( mb )
{
if( !reopen )
return;
delete mb;
mb = 0;
}
try
{
ost::Thread::setException(ost::Thread::throwException);
mb = new ModbusTCPMaster();
ost::InetAddress ia(iaddr.c_str());
mb->connect(ia,port);
if( recv_timeout > 0 )
mb->setTimeout(recv_timeout);
dlog[Debug::INFO] << myname << "(init): ipaddr=" << iaddr << " port=" << port << endl;
}
catch( ModbusRTU::mbException& ex )
{
cerr << "(init): " << ex << endl;
}
catch(...)
{
if( mb )
delete mb;
mb = 0;
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::waitSMReady()
{
// waiting for SM is ready...
int ready_timeout = atoi(conf->getArgParam("--mbm-sm-ready-timeout","15000").c_str());
if( ready_timeout == 0 )
ready_timeout = 15000;
else if( ready_timeout < 0 )
ready_timeout = UniSetTimer::WaitUpTime;
if( !shm->waitSMready(ready_timeout,50) )
{
ostringstream err;
err << myname << "(waitSMReady): SharedMemory " << ready_timeout << " ";
dlog[Debug::CRIT] << err.str() << endl;
throw SystemError(err.str());
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
step();
}
// -----------------------------------------------------------------------------
void MBTCPMaster::step()
{
{
uniset_mutex_lock l(pollMutex,2000);
poll();
}
if( !activated )
return;
if( sidHeartBeat!=DefaultObjectId && ptHeartBeat.checkTime() )
{
try
{
shm->localSaveValue(aitHeartBeat,sidHeartBeat,maxHeartBeat,getId());
ptHeartBeat.reset();
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (hb) " << ex << std::endl;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::poll()
{
if( trAllNotRespond.hi(allNotRespond) )
ptAllNotRespond.reset();
if( allNotRespond && mb && ptAllNotRespond.checkTime() )
{
ptAllNotRespond.reset();
// initMB(true);
}
if( !mb )
{
initMB(false);
if( !mb )
{
for( MBTCPMaster::RTUDeviceMap::iterator it=rmap.begin(); it!=rmap.end(); ++it )
it->second->resp_real = false;
}
updateSM();
return;
}
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " regs=" << d->regmap.size() << endl;
d->resp_real = false;
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype==MBTCPMaster::dtRTU )
{
if( pollRTU(d,it) )
d->resp_real = true;
}
}
catch( ModbusRTU::mbException& ex )
{
if( d->resp_real )
{
dlog[Debug::CRIT] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " -> " << ex << endl;
// d->resp_real = false;
}
}
if( it==d->regmap.end() )
break;
}
// mb->disconnect();
}
// update SharedMemory...
updateSM();
// check thresholds
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
RegInfo* r(it->second);
for( PList::iterator i=r->slst.begin(); i!=r->slst.end(); ++i )
IOBase::processingThreshold( &(*i),shm,force);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname << "(pollRTU): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mboffset=" << p->offset
<< " mbfunc=" << p->mbfunc
<< " q_count=" << p->q_count
<< endl;
}
if( p->q_count == 0 )
{
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(pollRTU): q_count=0 for mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE register..." << endl;
return false;
}
switch( p->mbfunc )
{
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(dev->mbaddr,p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr, p->mbreg+p->offset,p->q_count);
for( int i=0; i<p->q_count; i++,it++ )
it->second->mbval = ret.data[i];
it--;
}
break;
case ModbusRTU::fnReadInputStatus:
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m=0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k];
}
it--;
}
break;
case ModbusRTU::fnReadCoilStatus:
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01(dev->mbaddr,p->mbreg+p->offset,p->q_count);
int m = 0;
for( int i=0; i<ret.bcnt; i++ )
{
ModbusRTU::DataBits b(ret.data[i]);
for( int k=0;k<ModbusRTU::BitsPerByte && m<p->q_count; k++,it++,m++ )
it->second->mbval = b[k] ? 1 : 0;
}
it--;
}
break;
case ModbusRTU::fnWriteOutputSingleRegister:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE WRITE SINGLE REGISTER (0x06) q_count=" << p->q_count << " ..." << endl;
return false;
}
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnWriteOutputRegisters:
{
ModbusRTU::WriteOutputMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
msg.addData(it->second->mbval);
it--;
ModbusRTU::WriteOutputRetMessage ret = mb->write10(msg);
}
break;
case ModbusRTU::fnForceSingleCoil:
{
if( p->q_count != 1 )
{
dlog[Debug::CRIT] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE FORCE SINGLE COIL (0x05) q_count=" << p->q_count << " ..." << endl;
return false;
}
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(dev->mbaddr,p->mbreg+p->offset,p->mbval);
}
break;
case ModbusRTU::fnForceMultipleCoils:
{
ModbusRTU::ForceCoilsMessage msg(dev->mbaddr,p->mbreg+p->offset);
for( int i=0; i<p->q_count; i++,it++ )
msg.addBit( (it->second->mbval ? true : false) );
it--;
// cerr << "*********** (write multiple): " << msg << endl;
ModbusRTU::ForceCoilsRetMessage ret = mb->write0F(msg);
}
break;
default:
{
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE mfunc=" << (int)p->mbfunc << " ..." << endl;
return false;
}
break;
}
return true;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::RTUDevice::checkRespond()
{
bool prev = resp_state;
if( resp_trTimeout.change(resp_real) )
{
if( resp_real )
resp_state = true;
resp_ptTimeout.reset();
}
if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
// ݣ SM
// true,
if( !resp_init )
{
resp_init = true;
return true;
}
return ( prev != resp_state );
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateSM()
{
allNotRespond = true;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
/*
cout << "check respond addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " respond=" << d->resp_id
<< " real=" << d->resp_real
<< " state=" << d->resp_state
<< endl;
*/
if( d->resp_real )
allNotRespond = false;
// update respond sensors...
if( d->checkRespond() && d->resp_id != DefaultObjectId )
{
try
{
bool set = d->resp_invert ? !d->resp_state : d->resp_state;
shm->localSaveState(d->resp_dit,d->resp_id,set,getId());
}
catch(Exception& ex)
{
dlog[Debug::CRIT] << myname
<< "(step): (respond) " << ex << std::endl;
}
}
// cerr << "*********** allNotRespond=" << allNotRespond << endl;
// update values...
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype == dtRTU )
updateRTU(it);
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateSM): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateSM): catch ..." << endl;
}
if( it==d->regmap.end() )
break;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::processingMessage(UniSetTypes::VoidMessage *msg)
{
try
{
switch(msg->type)
{
case UniSetTypes::Message::SysCommand:
{
UniSetTypes::SystemMessage sm( msg );
sysCommand( &sm );
}
break;
case Message::Timer:
{
TimerMessage tm(msg);
timerInfo(&tm);
}
break;
case Message::SensorInfo:
{
SensorMessage sm( msg );
sensorInfo(&sm);
}
break;
default:
break;
}
}
catch( SystemError& ex )
{
dlog[Debug::CRIT] << myname << "(SystemError): " << ex << std::endl;
// throw SystemError(ex);
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(processingMessage): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(processingMessage): catch ...\n";
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::sysCommand( UniSetTypes::SystemMessage *sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
if( rmap.empty() )
{
dlog[Debug::CRIT] << myname << "(sysCommand): ************* ITEM MAP EMPTY! terminated... *************" << endl;
raise(SIGTERM);
return;
}
if( dlog.debugging(Debug::INFO) )
dlog[Debug::INFO] << myname << "(sysCommand): device map size= " << rmap.size() << endl;
if( !shm->isLocalwork() )
initDeviceList();
waitSMReady();
// ģ
// . activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !activated && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( activated )
break;
}
if( !activated )
dlog[Debug::CRIT] << myname << "(sysCommand): ************* don`t activate?! ************" << endl;
{
UniSetTypes::uniset_mutex_lock l(mutex_start, 10000);
askSensors(UniversalIO::UIONotify);
initOutput();
}
//
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
askTimer(tmExchange,polltime);
break;
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ( )
// ģ
// (.. MBTCPMaster SharedMemory2)
// WatchDog , .. ģ SM
// , SM , (MBTCPMaster)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
initOutput();
if( !force )
{
uniset_mutex_lock l(pollMutex,2000);
force = true;
poll();
force = false;
}
}
break;
case SystemMessage::LogRotate:
{
//
unideb << myname << "(sysCommand): logRotate" << std::endl;
string fname = unideb.getLogFile();
if( !fname.empty() )
{
unideb.logFile(fname.c_str());
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname.c_str());
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::initOutput()
{
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::askSensors( UniversalIO::UIOCommand cmd )
{
if( !shm->waitSMworking(test_id,activateTimeout,50) )
{
ostringstream err;
err << myname
<< "(askSensors): (work) SharedMemory "
<< activateTimeout << " ";
dlog[Debug::CRIT] << err.str() << endl;
kill(SIGTERM,getpid()); // () ...
throw SystemError(err.str());
}
if( force_out )
return;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
try
{
shm->askSensor(i->si.id,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): catch..." << std::endl;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !isWriteFunction(it->second->mbfunc) )
continue;
for( PList::iterator i=it->second->slst.begin(); i!=it->second->slst.end(); ++i )
{
if( sm->id == i->si.id && sm->node == i->si.node )
{
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname<< "(sensorInfo): si.id=" << sm->id
<< " reg=" << ModbusRTU::dat2str(i->reg->mbreg)
<< " val=" << sm->value << endl;
}
i->value = sm->value;
updateRSProperty( &(*i),true);
return;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::activateObject()
{
// Starsp
// ģ
// . sysCommand()
{
activated = false;
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(rmap);
initIterators();
activated = true;
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::sigterm( int signo )
{
cerr << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
activated = false;
#warning ...
// ....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
if( it->safety == NoSafetyState )
continue;
try
{
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
catch(...){}
}
*/
UniSetObject_LT::sigterm(signo);
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::readConfiguration()
{
#warning !!!
// , ...
// readconf_ok = false;
xmlNode* root = conf->getXMLSensorsSection();
if(!root)
{
ostringstream err;
err << myname << "(readConfiguration): <sensors>";
throw SystemError(err.str());
}
UniXML_iterator it(root);
if( !it.goChildren() )
{
std::cerr << myname << "(readConfiguration): <sensors> ?!!\n";
return;
}
for( ;it.getCurrent(); it.goNext() )
{
if( check_item(it) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::check_item( UniXML_iterator& it )
{
if( s_field.empty() )
return true;
// field
if( s_fvalue.empty() && it.getProp(s_field).empty() )
return false;
// field = value
if( !s_fvalue.empty() && it.getProp(s_field)!=s_fvalue )
return false;
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec )
{
if( check_item(it) )
initItem(it);
return true;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RTUDevice* MBTCPMaster::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML_iterator& xmlit )
{
RTUDeviceMap::iterator it = mp.find(a);
if( it != mp.end() )
{
DeviceType dtype = getDeviceType(xmlit.getProp("tcp_mbtype"));
if( it->second->dtype != dtype )
{
dlog[Debug::CRIT] << myname << "(addDev): OTHER mbtype=" << dtype << " for " << xmlit.getProp("name")
<< ". Already used devtype=" << it->second->dtype
<< " for mbaddr=" << ModbusRTU::addr2str(it->second->mbaddr)
<< endl;
return 0;
}
dlog[Debug::INFO] << myname << "(addDev): device for addr=" << ModbusRTU::addr2str(a)
<< " already added. Ignore device params for " << xmlit.getProp("name") << " ..." << endl;
return it->second;
}
MBTCPMaster::RTUDevice* d = new MBTCPMaster::RTUDevice();
d->mbaddr = a;
if( !initRTUDevice(d,xmlit) )
{
delete d;
return 0;
}
mp.insert(RTUDeviceMap::value_type(a,d));
return d;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RegInfo* MBTCPMaster::addReg( RegMap& mp, ModbusRTU::ModbusData r,
UniXML_iterator& xmlit, MBTCPMaster::RTUDevice* dev,
MBTCPMaster::RegInfo* rcopy )
{
RegMap::iterator it = mp.find(r);
if( it != mp.end() )
{
if( !it->second->dev )
{
dlog[Debug::CRIT] << myname << "(addReg): for reg=" << ModbusRTU::dat2str(r)
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
dlog[Debug::CRIT] << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for reg=" << ModbusRTU::dat2str(r)
<< ". Already used devtype=" << it->second->dev->dtype << " for " << it->second->dev << endl;
return 0;
}
if( dlog.debugging(Debug::INFO) )
{
dlog[Debug::INFO] << myname << "(addReg): reg=" << ModbusRTU::dat2str(r)
<< " already added. Ignore register params for " << xmlit.getProp("name") << " ..." << endl;
}
it->second->rit = it;
return it->second;
}
MBTCPMaster::RegInfo* ri;
if( rcopy )
{
ri = new MBTCPMaster::RegInfo(*rcopy);
ri->slst.clear();
ri->mbreg = r;
}
else
{
ri = new MBTCPMaster::RegInfo();
if( !initRegInfo(ri,xmlit,dev) )
{
delete ri;
return 0;
}
ri->mbreg = r;
}
mp.insert(RegMap::value_type(r,ri));
ri->rit = mp.find(r);
return ri;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RSProperty* MBTCPMaster::addProp( PList& plist, RSProperty& p )
{
for( PList::iterator it=plist.begin(); it!=plist.end(); ++it )
{
if( it->si.id == p.si.id && it->si.node == p.si.node )
return &(*it);
}
plist.push_back(p);
PList::iterator it = plist.end();
it--;
return &(*it);
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRSProperty( RSProperty& p, UniXML_iterator& it )
{
if( !IOBase::initItem(&p,it,shm,&dlog,myname) )
return false;
if( it.getIntProp("tcp_rawdata") )
{
p.cal.minRaw = 0;
p.cal.maxRaw = 0;
p.cal.minCal = 0;
p.cal.maxCal = 0;
p.cal.precision = 0;
p.cdiagram = 0;
}
string stype( it.getProp("tcp_iotype") );
if( !stype.empty() )
{
p.stype = UniSetTypes::getIOType(stype);
if( p.stype == UniversalIO::UnknownIOType )
{
if( dlog )
dlog[Debug::CRIT] << myname << "(IOBase::readItem): iotype=: "
<< stype << " for " << it.getProp("name") << endl;
return false;
}
}
string sbit(it.getProp("tcp_nbit"));
if( !sbit.empty() )
{
p.nbit = UniSetTypes::uni_atoi(sbit.c_str());
if( p.nbit < 0 || p.nbit >= ModbusRTU::BitsPerData )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbit=" << p.nbit
<< ". (0 >= nbit < " << ModbusRTU::BitsPerData <<")." << endl;
return false;
}
}
if( p.nbit > 0 &&
( p.stype == UniversalIO::AnalogInput ||
p.stype == UniversalIO::AnalogOutput ) )
{
dlog[Debug::WARN] << "(initRSProperty): (ignore) uncorrect param`s nbit>1 (" << p.nbit << ")"
<< " but iotype=" << p.stype << " for " << it.getProp("name") << endl;
}
string sbyte(it.getProp("tcp_nbyte"));
if( !sbyte.empty() )
{
p.nbyte = UniSetTypes::uni_atoi(sbyte.c_str());
if( p.nbyte < 0 || p.nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): BAD nbyte=" << p.nbyte
<< ". (0 >= nbyte < " << VTypes::Byte::bsize << ")." << endl;
return false;
}
}
string vt(it.getProp("tcp_vtype"));
if( vt.empty() )
{
p.rnum = VTypes::wsize(VTypes::vtUnknown);
p.vType = VTypes::vtUnknown;
}
else
{
VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRSProperty): Unknown rtuVType=" << vt << " for "
<< it.getProp("name")
<< endl;
return false;
}
p.vType = v;
p.rnum = VTypes::wsize(v);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRegInfo( RegInfo* r, UniXML_iterator& it, MBTCPMaster::RTUDevice* dev )
{
r->dev = dev;
r->mbval = UniSetTypes::uni_atoi(it.getProp("default").c_str());
r->offset= UniSetTypes::uni_atoi(it.getProp("tcp_mboffset").c_str());
if( dev->dtype != MBTCPMaster::dtRTU )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbtype='" << dev->dtype
<< "' for " << it.getProp("name") << endl;
return false;
}
if( mbregFromID )
{
if( it.getProp("id").empty() )
r->mbreg = conf->getSensorID(it.getProp("name"));
else
r->mbreg = UniSetTypes::uni_atoi(it.getProp("id").c_str());
}
else
{
string sr = it.getProp("tcp_mbreg");
if( sr.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl;
return false;
}
r->mbreg = ModbusRTU::str2mbData(sr);
}
r->mbfunc = ModbusRTU::fnUnknown;
string f = it.getProp("tcp_mbfunc");
if( !f.empty() )
{
r->mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(f.c_str());
if( r->mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initRegInfo): Unknown mbfunc ='" << f
<< "' for " << it.getProp("name") << endl;
return false;
}
}
return true;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::DeviceType MBTCPMaster::getDeviceType( const std::string dtype )
{
if( dtype.empty() )
return dtUnknown;
if( dtype == "rtu" || dtype == "RTU" )
return dtRTU;
return dtUnknown;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initRTUDevice( RTUDevice* d, UniXML_iterator& it )
{
d->dtype = getDeviceType(it.getProp("tcp_mbtype"));
if( d->dtype == dtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown tcp_mbtype=" << it.getProp("tcp_mbtype")
<< ". Use: rtu "
<< " for " << it.getProp("name") << endl;
return false;
}
string addr = it.getProp("tcp_mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown mbaddr for " << it.getProp("name") << endl;
return false;
}
d->mbaddr = ModbusRTU::str2mbAddr(addr);
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initItem( UniXML_iterator& it )
{
RSProperty p;
if( !initRSProperty(p,it) )
return false;
string addr = it.getProp("tcp_mbaddr");
if( addr.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown mbaddr='" << addr << " for " << it.getProp("name") << endl;
return false;
}
ModbusRTU::ModbusAddr mbaddr = ModbusRTU::str2mbAddr(addr);
RTUDevice* dev = addDev(rmap,mbaddr,it);
if( !dev )
{
dlog[Debug::CRIT] << myname << "(initItem): " << it.getProp("name") << " CAN`T ADD for polling!" << endl;
return false;
}
ModbusRTU::ModbusData mbreg;
if( mbregFromID )
mbreg = p.si.id; // conf->getSensorID(it.getProp("name"));
else
{
string reg = it.getProp("tcp_mbreg");
if( reg.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
RegInfo* ri = addReg(dev->regmap,mbreg,it,dev);
if( !ri )
return false;
ri->dev = dev;
// ПРОВЕРКА!
// если функция на запись, то надо проверить
// что один и тотже регистр не перезапишут несколько датчиков
// это возможно только, если они пишут биты!!
// ИТОГ:
// Если для функций записи список датчиков на один регистр > 1
// значит в списке могут быть только битовые датчики
// и если идёт попытка внести в список не битовый датчик то ОШИБКА!
// И наоборот: если идёт попытка внести битовый датчик, а в списке
// уже сидит датчик занимающий целый регистр, то тоже ОШИБКА!
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
if( p.nbit<0 && ri->slst.size() > 1 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (not bit saving) to "
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
if( p.nbit >= 0 && ri->slst.size() == 1 )
{
PList::iterator it2 = ri->slst.begin();
if( it2->nbit < 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): FAILED! Sharing SAVE (mbreg="
<< ModbusRTU::dat2str(ri->mbreg) << " already used)!"
<< " IGNORE --> " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
}
}
RSProperty* p1 = addProp(ri->slst,p);
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
for( int i=1; i<p1->rnum; i++ )
addReg(dev->regmap,mbreg+i,it,dev,ri);
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::initIterators()
{
shm->initAIterator(aitHeartBeat);
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
shm->initDIterator(d->resp_dit);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
for( PList::iterator it2=it->second->slst.begin();it2!=it->second->slst.end(); ++it2 )
{
shm->initDIterator(it2->dit);
shm->initAIterator(it2->ait);
}
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::help_print( int argc, const char** argv )
{
cout << "--mbm-polltime msec - . 200 ." << endl;
cout << "--mbm-heartbeat-id - heartbeat-." << endl;
cout << "--mbm-heartbeat-max - heartbeat-ޣ . 10." << endl;
cout << "--mbm-ready-timeout - SM , . (-1 - '')" << endl;
cout << "--mbm-force - SM, , " << endl;
cout << "--mbm-initPause - ( )" << endl;
cout << "--mbm-sm-ready-timeout - SM" << endl;
cout << " RS: " << endl;
cout << "--mbm-dev devname - " << endl;
cout << "--mbm-speed - (9600,19920,38400,57600,115200)." << endl;
cout << "--mbm-my-addr - " << endl;
cout << "--mbm-recv-timeout - ." << endl;
}
// -----------------------------------------------------------------------------
MBTCPMaster* MBTCPMaster::init_mbmaster( int argc, const char** argv, UniSetTypes::ObjectId icID, SharedMemory* ic,
const std::string prefix )
{
string name = conf->getArgParam("--" + prefix + "-name","MBTCPMaster1");
if( name.empty() )
{
cerr << "(MBTCPMaster): name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
cerr << "(MBTCPMaster): '" << name
<< "' . !"
<< " " << conf->getObjectsSection() << endl;
return 0;
}
dlog[Debug::INFO] << "(MBTCPMaster): name = " << name << "(" << ID << ")" << endl;
return new MBTCPMaster(ID,icID,ic,prefix);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBTCPMaster::DeviceType& dt )
{
switch(dt)
{
case MBTCPMaster::dtRTU:
os << "RTU";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBTCPMaster::RSProperty& p )
{
os << " (" << ModbusRTU::dat2str(p.reg->mbreg) << ")"
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " nbit=" << p.nbit
<< " nbyte=" << p.nbyte
<< " rnum=" << p.rnum
<< " safety=" << p.safety
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AnalogInput || p.stype == UniversalIO::AnalogOutput )
{
os << " rmin=" << p.cal.minRaw
<< " rmax=" << p.cal.maxRaw
<< " cmin=" << p.cal.maxCal
<< " cmax=" << p.cal.maxCal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::initDeviceList()
{
xmlNode* respNode = conf->findNode(cnode,"DeviceList");
if( respNode )
{
UniXML_iterator it1(respNode);
if( it1.goChildren() )
{
for(;it1.getCurrent(); it1.goNext() )
{
ModbusRTU::ModbusAddr a = ModbusRTU::str2mbAddr(it1.getProp("addr"));
initDeviceInfo(rmap,a,it1);
}
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> empty section..." << endl;
}
else
dlog[Debug::WARN] << myname << "(init): <DeviceList> not found..." << endl;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it )
{
RTUDeviceMap::iterator d = m.find(a);
if( d == m.end() )
{
dlog[Debug::WARN] << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
d->second->resp_id = conf->getSensorID(it.getProp("respondSensor"));
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << it.getProp("respondSensor") << endl;
return false;
}
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = atoi(it.getProp("timeout").c_str());
if( tout > 0 )
d->second->resp_ptTimeout.setTiming(tout);
else
d->second->resp_ptTimeout.setTiming(UniSetTimer::WaitUpTime);
d->second->resp_invert = atoi(it.getProp("invert").c_str());
return true;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::printMap( MBTCPMaster::RTUDeviceMap& m )
{
cout << "devices: " << endl;
for( MBTCPMaster::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
cout << " " << *(it->second) << endl;
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( MBTCPMaster::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
os << " " << *(it->second) << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RTUDevice& d )
{
os << "addr=" << ModbusRTU::addr2str(d.mbaddr)
<< " type=" << d.dtype
<< " respond_id=" << d.resp_id
<< " respond_timeout=" << d.resp_ptTimeout.getInterval()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< endl;
os << " regs: " << endl;
for( MBTCPMaster::RegMap::iterator it=d.regmap.begin(); it!=d.regmap.end(); ++it )
os << " " << *(it->second) << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBTCPMaster::RegInfo& r )
{
os << " mbreg=" << ModbusRTU::dat2str(r.mbreg)
<< " mbfunc=" << r.mbfunc
<< " q_num=" << r.q_num
<< " q_count=" << r.q_count
<< " value=" << ModbusRTU::dat2str(r.mbval) << "(" << (int)r.mbval << ")"
<< endl;
for( MBTCPMaster::PList::iterator it=r.slst.begin(); it!=r.slst.end(); ++it )
os << " " << (*it) << endl;
return os;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::rtuQueryOptimization( RTUDeviceMap& m )
{
if( noQueryOptimization )
return;
dlog[Debug::INFO] << myname << "(rtuQueryOptimization): optimization..." << endl;
// MAXLEN/2 - это количество слов данных в ответе
// 10 - на всякие служебные заголовки
int maxcount = ModbusRTU::MAXLENPACKET/2 - 10;
for( MBTCPMaster::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
MBTCPMaster::RegMap::iterator beg = it;
ModbusRTU::ModbusData reg = it->second->mbreg + it->second->offset;
beg->second->q_num = 1;
beg->second->q_count = 1;
it++;
for( ;it!=d->regmap.end(); ++it )
{
if( (it->second->mbreg + it->second->offset - reg) > 1 )
break;
if( beg->second->mbfunc != it->second->mbfunc )
break;
beg->second->q_count++;
if( beg->second->q_count > maxcount )
break;
reg = it->second->mbreg + it->second->offset;
it->second->q_num = beg->second->q_count;
it->second->q_count = 0;
}
// check correct function...
if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnWriteOutputSingleRegister )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnWriteOutputSingleRegister
<< " <--> func=" << ModbusRTU::fnWriteOutputRegisters
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if( beg->second->q_count>1 && beg->second->mbfunc==ModbusRTU::fnForceSingleCoil )
{
dlog[Debug::WARN] << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnForceSingleCoil
<< " <--> func=" << ModbusRTU::fnForceMultipleCoils
<< " for mbaddr=" << ModbusRTU::addr2str(d->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->second->mbreg);
beg->second->mbfunc = ModbusRTU::fnForceMultipleCoils;
}
if( it==d->regmap.end() )
break;
it--;
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateRTU( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
updateRSProperty( &(*it),false );
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateRSProperty( RSProperty* p, bool write_only )
{
using namespace ModbusRTU;
RegInfo* r(p->reg->rit->second);
bool save = isWriteFunction( r->mbfunc );
if( !save && write_only )
return;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(r->mbval);
if( p->nbit >= 0 )
{
if( save )
{
bool set = IOBase::processingAsDO( p, shm, force_out );
b.set(p->nbit,set);
r->mbval = b.mdata();
}
else
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
}
return;
}
if( p->rnum <= 1 )
{
if( save )
r->mbval = IOBase::processingAsAO( p, shm, force_out );
else
IOBase::processingAsAI( p, r->mbval, shm, force );
return;
}
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: rnum=" << p->rnum
<< " > 1 ?!! for id=" << p->si.id << endl;
return;
}
else if( p->vType == VTypes::vtByte )
{
if( p->nbyte <= 0 || p->nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(updateRSProperty): IGNORE item: reg=" << ModbusRTU::dat2str(r->mbreg)
<< " vtype=" << p->vType << " but nbyte=" << p->nbyte << endl;
return;
}
if( save )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::Byte b(r->mbval);
b.raw.b[p->nbyte-1] = v;
r->mbval = b.raw.w;
}
else
{
VTypes::Byte b(r->mbval);
IOBase::processingAsAI( p, b.raw.b[p->nbyte-1], shm, force );
}
return;
}
else if( p->vType == VTypes::vtF2 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F2 f2(f);
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
i->second->mbval = f2.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F2::wsize()];
for( int k=0; k<VTypes::F2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F2 f(data,VTypes::F2::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
else if( p->vType == VTypes::vtF4 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
float f = IOBase::processingFasAO( p, shm, force_out );
VTypes::F4 f4(f);
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
i->second->mbval = f4.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::F4::wsize()];
for( int k=0; k<VTypes::F4::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::F4 f(data,VTypes::F4::wsize());
delete[] data;
IOBase::processingFasAI( p, (float)f, shm, force );
}
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateRSProperty): catch ..." << endl;
}
}
// -----------------------------------------------------------------------------
#ifndef _MBTCPMaster_H_
#define _MBTCPMaster_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <map>
#include <vector>
#include "IONotifyController.h"
#include "UniSetObject_LT.h"
#include "modbus/ModbusTCPMaster.h"
#include "PassiveTimer.h"
#include "Trigger.h"
#include "Mutex.h"
#include "Calibration.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "IOBase.h"
#include "VTypes.h"
// -----------------------------------------------------------------------------
/*!
Реализация Modbus TCP Master-а для работы со многими ModbusRTU устройствами,
но только через ОДИН ModbusTCP-шлюз.
*/
class MBTCPMaster:
public UniSetObject_LT
{
public:
MBTCPMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmID, SharedMemory* ic=0,
const std::string prefix="mbtcp" );
virtual ~MBTCPMaster();
/*! */
static MBTCPMaster* init_mbmaster( int argc, const char** argv,
UniSetTypes::ObjectId shmID, SharedMemory* ic=0,
const std::string prefix="mbtcp" );
/*! help- */
static void help_print( int argc, const char** argv );
static const int NoSafetyState=-1;
enum Timer
{
tmExchange
};
enum DeviceType
{
dtUnknown, /*!< */
dtRTU /*!< RTU (default) */
};
static DeviceType getDeviceType( const std::string dtype );
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
// -------------------------------------------------------------------------------
struct RTUDevice;
struct RegInfo;
struct RSProperty:
public IOBase
{
// only for RTU
short nbit; /*!< bit number) */
VTypes::VType vType; /*!< type of value */
short rnum; /*!< count of registers */
short nbyte; /*!< byte number (1-2) */
RSProperty():
nbit(-1),vType(VTypes::vtUnknown),
rnum(VTypes::wsize(VTypes::vtUnknown)),
nbyte(0),reg(0)
{}
RegInfo* reg;
};
friend std::ostream& operator<<( std::ostream& os, const RSProperty& p );
typedef std::list<RSProperty> PList;
typedef std::map<ModbusRTU::ModbusData,RegInfo*> RegMap;
struct RegInfo
{
RegInfo():
mbval(0),mbreg(0),mbfunc(ModbusRTU::fnUnknown),
dev(0),offset(0),
q_num(0),q_count(1)
{}
ModbusRTU::ModbusData mbval;
ModbusRTU::ModbusData mbreg; /*!< */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< / */
PList slst;
RTUDevice* dev;
int offset;
// optimization
int q_num; /*! number in query */
int q_count; /*! count registers for query */
RegMap::iterator rit;
};
friend std::ostream& operator<<( std::ostream& os, RegInfo& r );
struct RTUDevice
{
RTUDevice():
respnond(false),
mbaddr(0),
dtype(dtUnknown),
resp_id(UniSetTypes::DefaultObjectId),
resp_state(false),
resp_invert(false),
resp_real(true),
resp_init(false)
{
resp_trTimeout.change(false);
}
bool respnond;
ModbusRTU::ModbusAddr mbaddr; /*!< */
RegMap regmap;
DeviceType dtype; /*!< */
UniSetTypes::ObjectId resp_id;
IOController::DIOStateList::iterator resp_dit;
PassiveTimer resp_ptTimeout;
Trigger resp_trTimeout;
bool resp_state;
bool resp_invert;
bool resp_real;
bool resp_init;
// return TRUE if state changed
bool checkRespond();
};
friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
typedef std::map<ModbusRTU::ModbusAddr,RTUDevice*> RTUDeviceMap;
friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
void printMap(RTUDeviceMap& d);
// ----------------------------------
protected:
RTUDeviceMap rmap;
ModbusTCPMaster* mb;
UniSetTypes::uniset_mutex mbMutex;
std::string iaddr;
// ost::InetAddress* ia;
int port;
int recv_timeout;
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
SMInterface* shm;
void step();
void poll();
bool pollRTU( RTUDevice* dev, RegMap::iterator& it );
void updateSM();
void updateRTU(RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only=false );
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
void sysCommand( UniSetTypes::SystemMessage *msg );
void sensorInfo( UniSetTypes::SensorMessage*sm );
void timerInfo( UniSetTypes::TimerMessage *tm );
void askSensors( UniversalIO::UIOCommand cmd );
void initOutput();
void waitSMReady();
virtual bool activateObject();
//
virtual void sigterm( int signo );
void initMB( bool reopen=false );
void initIterators();
bool initItem( UniXML_iterator& it );
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
void initDeviceList();
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
RegInfo* addReg( RegMap& rmap, ModbusRTU::ModbusData r, UniXML_iterator& it,
RTUDevice* dev, RegInfo* rcopy=0 );
RSProperty* addProp( PList& plist, RSProperty& p );
bool initRSProperty( RSProperty& p, UniXML_iterator& it );
bool initRegInfo( RegInfo* r, UniXML_iterator& it, RTUDevice* dev );
bool initRTUDevice( RTUDevice* d, UniXML_iterator& it );
bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
void rtuQueryOptimization( RTUDeviceMap& m );
void readConfiguration();
bool check_item( UniXML_iterator& it );
private:
MBTCPMaster();
bool initPause;
UniSetTypes::uniset_mutex mutex_start;
bool force; /*!< , SM, */
bool force_out; /*!< , */
bool mbregFromID;
int polltime; /*!< , [] */
PassiveTimer ptHeartBeat;
UniSetTypes::ObjectId sidHeartBeat;
int maxHeartBeat;
IOController::AIOStateList::iterator aitHeartBeat;
UniSetTypes::ObjectId test_id;
UniSetTypes::uniset_mutex pollMutex;
bool activated;
int activateTimeout;
bool noQueryOptimization;
bool allNotRespond;
Trigger trAllNotRespond;
PassiveTimer ptAllNotRespond;
std::string prefix;
};
// -----------------------------------------------------------------------------
#endif // _MBTCPMaster_H_
// -----------------------------------------------------------------------------
......@@ -6,7 +6,7 @@ libUniSetMBTCPMaster_la_LIBADD = $(top_builddir)/lib/libUniSet.la \
$(top_builddir)/extensions/lib/libUniSetExtensions.la \
$(SIGC_LIBS)
libUniSetMBTCPMaster_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
libUniSetMBTCPMaster_la_SOURCES = MBMaster.cc
libUniSetMBTCPMaster_la_SOURCES = MBTCPMaster.cc
@PACKAGE@_mbtcpmaster_SOURCES = main.cc
@PACKAGE@_mbtcpmaster_LDADD = libUniSetMBTCPMaster.la $(top_builddir)/lib/libUniSet.la \
......
// $Id: rsexchange.cc,v 1.2 2008/06/06 11:03:32 pv Exp $
// -----------------------------------------------------------------------------
#include <sstream>
#include "MBMaster.h"
#include "MBTCPMaster.h"
#include "Configuration.h"
#include "Debug.h"
#include "ObjectsActivator.h"
......@@ -11,7 +11,7 @@ using namespace std;
using namespace UniSetTypes;
using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
int main( int argc, char** argv )
int main( int argc, const char** argv )
{
if( argc>1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) )
{
......@@ -19,7 +19,7 @@ int main( int argc, char** argv )
cout << "--confile filename - configuration file. Default: configure.xml" << endl;
cout << "--mbtcp-logfile filename - logfilename. Default: mbtcpmaster.log" << endl;
cout << endl;
MBMaster::help_print(argc, argv);
MBTCPMaster::help_print(argc, argv);
return 0;
}
......@@ -53,7 +53,7 @@ int main( int argc, char** argv )
return 1;
}
MBMaster* mb = MBMaster::init_mbmaster(argc,argv,shmID);
MBTCPMaster* mb = MBTCPMaster::init_mbmaster(argc,argv,shmID);
if( !mb )
{
dlog[Debug::CRIT] << "(mbmaster): init ۣ..." << endl;
......
#!/bin/sh
uniset-start.sh -f ./uniset-mbtcpmaster --mbtcp-name MBMaster1 --confile test.xml \
uniset-start.sh -f ./uniset-mbtcpmaster --mbtcp-name MBTCPExchange1 \
--dlog-add-levels info,crit,warn \
--mbtcp-iaddr 127.0.0.1 --mbtcp-port 2048
--mbtcp-filter-field CAN2sender \
--mbtcp-filter-value SYSTSNode \
--mbtcp-reg-from-id 1 \
--mbtcp-gateway-iaddr 127.0.0.1 \
--mbtcp-gateway-port 2048
#--mbtcp-filter-field mbtcp --mbtcp-filter-value 1
#--mbtcp-reg-from-id 1
\ No newline at end of file
......@@ -1622,6 +1622,10 @@ void RTUExchange::rtuQueryOptimization( RTUDeviceMap& m )
dlog[Debug::INFO] << myname << "(rtuQueryOptimization): optimization..." << endl;
// MAXLEN/2 - это количество слов данных в ответе
// 10 - на всякие служебные заголовки
int maxcount = ModbusRTU::MAXLENPACKET/2 - 10;
for( RTUExchange::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
......@@ -1642,6 +1646,9 @@ void RTUExchange::rtuQueryOptimization( RTUDeviceMap& m )
break;
beg->second->q_count++;
if( beg->second->q_count > maxcount )
break;
reg = it->second->mbreg + it->second->offset;
it->second->q_num = beg->second->q_count;
it->second->q_count = 0;
......
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