Commit 78333cac authored by Pavel Vainerman's avatar Pavel Vainerman

(Modbus): продолжаю работу над выносом общего кода в MBTCPMaster и RTUExchange

parent 089e9ffb
......@@ -13,14 +13,12 @@ using namespace UniSetExtensions;
MBTCPMaster::MBTCPMaster( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId,
SharedMemory* ic, const std::string prefix ):
MBExchange(objId,shmId,ic,prefix),
allInitOK(false),
mb(0),
no_extimer(false),
force_disconnect(true),
poll_count(0),
mbtcp(0),
pollThread(0)
{
// cout << "$ $" << endl;
prop_prefix = "tcp_";
if( objId == DefaultObjectId )
throw UniSetTypes::SystemError("(MBTCPMaster): objId=-1?!! Use --" + prefix + "-name" );
......@@ -71,38 +69,39 @@ MBTCPMaster::~MBTCPMaster()
}
delete pollThread;
delete mb;
delete mbtcp;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::initMB( bool reopen )
ModbusClient* MBTCPMaster::initMB( bool reopen )
{
if( mb )
if( mbtcp )
{
if( !reopen )
return;
return mbtcp;
delete mb;
delete mbtcp;
mb = 0;
mbtcp = 0;
}
try
{
ost::Thread::setException(ost::Thread::throwException);
mb = new ModbusTCPMaster();
mbtcp = new ModbusTCPMaster();
ost::InetAddress ia(iaddr.c_str());
mb->connect(ia,port);
mb->setForceDisconnect(force_disconnect);
mbtcp->connect(ia,port);
mbtcp->setForceDisconnect(force_disconnect);
if( recv_timeout > 0 )
mb->setTimeout(recv_timeout);
mbtcp->setTimeout(recv_timeout);
mb->setSleepPause(sleepPause_usec);
mbtcp->setSleepPause(sleepPause_usec);
dlog[Debug::INFO] << myname << "(init): ipaddr=" << iaddr << " port=" << port << endl;
if( dlog.debugging(Debug::LEVEL9) )
mb->setLog(dlog);
mbtcp->setLog(dlog);
}
catch( ModbusRTU::mbException& ex )
{
......@@ -110,23 +109,21 @@ void MBTCPMaster::initMB( bool reopen )
}
catch(...)
{
if( mb )
delete mb;
if( mbtcp )
delete mbtcp;
mb = 0;
mbtcp = 0;
}
mb = mbtcp;
return mbtcp;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::timerInfo( TimerMessage *tm )
void MBTCPMaster::sysCommand( UniSetTypes::SystemMessage *sm )
{
if( tm->id == tmExchange )
{
if( no_extimer )
askTimer(tm->id,0);
else
step();
}
MBExchange::sysCommand(sm);
if( sm->command == SystemMessage::StartUp )
pollThread->start();
}
// -----------------------------------------------------------------------------
void MBTCPMaster::step()
......@@ -205,2365 +202,136 @@ void MBTCPMaster::poll_thread()
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::poll()
bool MBTCPMaster::RTUDevice::checkRespond()
{
if( !mb )
{
{
uniset_mutex_lock l(pollMutex, 300);
pollActivated = false;
initMB(false);
if( !mb )
{
for( MBTCPMaster::RTUDeviceMap::iterator it=rmap.begin(); it!=rmap.end(); ++it )
it->second->resp_real = false;
}
}
if( !checkProcActive() )
return;
updateSM();
allInitOK = false;
return;
}
{
uniset_mutex_lock l(pollMutex);
pollActivated = true;
ptTimeout.reset();
}
if( !allInitOK )
firstInitRegisters();
if( !checkProcActive() )
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 )
{
if( !checkProcActive() )
return;
try
{
if( d->dtype==MBTCPMaster::dtRTU || d->dtype==MBTCPMaster::dtMTR )
{
if( pollRTU(d,it) )
d->resp_real = true;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; print_plist(dlog(Debug::LEVEL3),it->second->slst);
dlog(Debug::LEVEL3) << " err: " << ex << endl;
}
// }
// d->resp_real = false;
if( ex.err == ModbusRTU::erTimeOut && !d->ask_every_reg )
break;
// если контроллер хоть что-то ответил, то вроде как связь есть..
if( ex.err != ModbusRTU::erTimeOut )
d->resp_real = true;
}
if( it==d->regmap.end() )
break;
if( !checkProcActive() )
return;
}
if( stat_time > 0 )
poll_count++;
}
if( stat_time > 0 && ptStatistic.checkTime() )
{
cout << endl << "(poll statistic): number of calls is " << poll_count << " (poll time: " << stat_time << " sec)" << endl << endl;
ptStatistic.reset();
poll_count=0;
}
bool prev = resp_state;
if( resp_ptTimeout.getInterval() <= 0 )
{
uniset_mutex_lock l(pollMutex);
pollActivated = false;
resp_state = resp_real;
return (prev != resp_state);
}
if( !checkProcActive() )
return;
// update SharedMemory...
updateSM();
// check thresholds
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
if( resp_trTimeout.hi(resp_state && !resp_real) )
resp_ptTimeout.reset();
if( resp_real )
resp_state = true;
else if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if( !resp_init )
{
RTUDevice* d(it1->second);
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !checkProcActive() )
return;
RegInfo* r(it->second);
for( PList::iterator i=r->slst.begin(); i!=r->slst.end(); ++i )
IOBase::processingThreshold( &(*i),shm,force);
}
resp_state = resp_real;
resp_init = true;
prev = resp_state;
return true;
}
// printMap(rmap);
return ( prev != resp_state );
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::pollRTU( RTUDevice* dev, RegMap::iterator& it )
void MBTCPMaster::sigterm( int signo )
{
RegInfo* p(it->second);
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mbfunc=" << p->mbfunc
<< " q_count=" << p->q_count
<< " mb_initOK=" << p->mb_initOK
<< " sm_initOK=" << p->sm_initOK
<< " mbval=" << p->mbval
<< endl;
if( p->q_count > ModbusRTU::MAXDATALEN )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
if( !checkPoll(ModbusRTU::isWriteFunction(p->mbfunc)) )
return true;
dlog[Debug::WARN] << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
setProcActive(false);
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;
}
/*! \todo Доделать выставление безопасного состояния на выходы.
И нужно ли это. Ведь может не хватить времени на "обмен"
*/
switch( p->mbfunc )
// выставление безопасного состояния на выходы....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(dev->mbaddr,p->mbreg,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->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->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->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;
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
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;
}
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " slist=" << (*p)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(dev->mbaddr,p->mbreg,p->mbval);
}
break;
case ModbusRTU::fnWriteOutputRegisters:
{
if( !p->sm_initOK )
{
// может быть такая ситуация, что
// некоторые регистры уже инициализированы, а другие ещё нет
// при этом после оптимизации они попадают в один запрос
// поэтому здесь сделано так:
// если q_num > 1, значит этот регистр относится к предыдущему запросу
// и его просто надо пропустить..
if( p->q_num > 1 )
return true;
// смещаем итератор, если данный запрос содержит много регистров
// if( q->count > 1 )
// {
// for( int i=0; i<p->q_count; i++ )
// it++;
// return true;
// }
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
ModbusRTU::WriteOutputMessage msg(dev->mbaddr,p->mbreg);
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;
}
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(dev->mbaddr,p->mbreg,p->mbval);
}
break;
if( it->safety == NoSafetyState )
continue;
case ModbusRTU::fnForceMultipleCoils:
try
{
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
ModbusRTU::ForceCoilsMessage msg(dev->mbaddr,p->mbreg);
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:
catch( UniSetTypes::Exception& ex )
{
if( dlog.debugging(Debug::WARN) )
dlog[Debug::WARN] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE mfunc=" << (int)p->mbfunc << " ..." << endl;
return false;
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
break;
catch(...){}
}
return true;
*/
UniSetObject_LT::sigterm(signo);
}
// -----------------------------------------------------------------------------
void MBTCPMaster::firstInitRegisters()
// ------------------------------------------------------------------------------------------
void MBTCPMaster::help_print( int argc, const char* const* argv )
{
// если все вернут TRUE, значит OK.
allInitOK = true;
for( InitList::iterator it=initRegList.begin(); it!=initRegList.end(); ++it )
{
try
{
it->initOK = preInitRead( it );
allInitOK = it->initOK;
}
catch( ModbusRTU::mbException& ex )
{
allInitOK = false;
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): FAILED ask addr=" << ModbusRTU::addr2str(it->dev->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->mbreg)
<< " err: " << ex << endl;
}
if( !it->dev->ask_every_reg )
break;
}
}
cout << "Default: prefix='mbtcp'" << endl;
MBExchange::help_print(argc,argv);
// ---------- init MBTCP ----------
// cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола TCP: " << endl;
cout << "--prefix-gateway hostname,IP - IP опрашиваемого узла" << endl;
cout << "--prefix-gateway-port num - port на опрашиваемом узле" << endl;
cout << "--prefix-recv-timeout msec - Таймаут на приём одного сообщения" << endl;
cout << "--prefix-timeout msec - Таймаут для определения отсутсвия соединения" << endl;
cout << "--prefix-persistent-connection 0,1 - Не закрывать соединение на каждом цикле опроса" << endl;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::preInitRead( InitList::iterator& p )
MBTCPMaster* MBTCPMaster::init_mbmaster( int argc, const char* const* argv,
UniSetTypes::ObjectId icID, SharedMemory* ic,
const std::string prefix )
{
if( p->initOK )
return true;
RTUDevice* dev = p->dev;
int q_count = p->p.rnum;
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mbfunc=" << p->mbfunc
<< " q_count=" << q_count
<< endl;
if( q_count > ModbusRTU::MAXDATALEN )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): count(" << q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
switch( p->mbfunc )
string name = conf->getArgParam("--" + prefix + "-name","MBTCPMaster1");
if( name.empty() )
{
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr,p->mbreg,q_count);
p->initOK = initSMValue(ret.data, ret.count,&(p->p));
}
break;
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret1 = mb->read04(dev->mbaddr,p->mbreg,q_count);
p->initOK = initSMValue(ret1.data,ret1.count, &(p->p));
}
break;
case ModbusRTU::fnReadInputStatus:
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02(dev->mbaddr,p->mbreg,q_count);
ModbusRTU::ModbusData* dat = new ModbusRTU::ModbusData[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<q_count; k++,m++ )
dat[m] = b[k];
}
p->initOK = initSMValue(dat,q_count, &(p->p));
delete[] dat;
}
break;
case ModbusRTU::fnReadCoilStatus:
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01(dev->mbaddr,p->mbreg,q_count);
ModbusRTU::ModbusData* dat = new ModbusRTU::ModbusData[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<q_count; k++,m++ )
dat[m] = b[k];
}
p->initOK = initSMValue(dat,q_count, &(p->p));
delete[] dat;
}
break;
default:
p->initOK = false;
break;
dlog[Debug::CRIT] << "(MBTCPMaster): Не задан name'" << endl;
return 0;
}
if( p->initOK )
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
bool f_out = force_out;
// выставляем флаг принудительного обновления
force_out = true;
p->ri->mb_initOK = true;
p->ri->sm_initOK = false;
updateRTU(p->ri->rit);
force_out = f_out;
dlog[Debug::CRIT] << "(MBTCPMaster): идентификатор '" << name
<< "' не найден в конф. файле!"
<< " в секции " << conf->getObjectsSection() << endl;
return 0;
}
return p->initOK;
dlog[Debug::INFO] << "(MBTCPMaster): name = " << name << "(" << ID << ")" << endl;
return new MBTCPMaster(ID,icID,ic,prefix);
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p )
void MBTCPMaster::execute()
{
using namespace ModbusRTU;
no_extimer = true;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(data[0]);
if( p->nbit >= 0 )
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
return true;
}
if( p->rnum <= 1 )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(data[0]), shm, force );
return true;
}
dlog[Debug::CRIT] << myname << "(initSMValue): IGNORE item: rnum=" << p->rnum
<< " > 1 ?!! for id=" << p->si.id << endl;
return false;
}
else if( p->vType == VTypes::vtSigned )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(data[0]), shm, force );
return true;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (unsigned short)data[0], shm, force );
return true;
}
else if( p->vType == VTypes::vtByte )
{
if( p->nbyte <= 0 || p->nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(initSMValue): IGNORE item: sid=" << ModbusRTU::dat2str(p->si.id)
<< " vtype=" << p->vType << " but nbyte=" << p->nbyte << endl;
return false;
}
askTimer(tmExchange,0);
}
catch(...){}
initMB(false);
VTypes::Byte b(data[0]);
IOBase::processingAsAI( p, b.raw.b[p->nbyte-1], shm, force );
return true;
}
else if( p->vType == VTypes::vtF2 )
{
VTypes::F2 f(data,VTypes::F2::wsize());
IOBase::processingFasAI( p, (float)f, shm, force );
}
else if( p->vType == VTypes::vtF4 )
while(1)
{
try
{
VTypes::F4 f(data,VTypes::F4::wsize());
IOBase::processingFasAI( p, (float)f, shm, force );
step();
}
else if( p->vType == VTypes::vtI2 )
catch( Exception& ex )
{
VTypes::I2 i2(data,VTypes::I2::wsize());
IOBase::processingAsAI( p, (int)i2, shm, force );
dlog[Debug::CRIT] << myname << "(execute): " << ex << std::endl;
}
else if( p->vType == VTypes::vtU2 )
catch(...)
{
VTypes::U2 u2(data,VTypes::U2::wsize());
IOBase::processingAsAI( p, (unsigned int)u2, shm, force );
dlog[Debug::CRIT] << myname << "(execute): catch ..." << endl;
}
return true;
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): catch ..." << endl;
}
return false;
}
// -----------------------------------------------------------------------------
bool MBTCPMaster::RTUDevice::checkRespond()
{
bool prev = resp_state;
if( resp_ptTimeout.getInterval() <= 0 )
{
resp_state = resp_real;
return (prev != resp_state);
}
if( resp_trTimeout.hi(resp_state && !resp_real) )
resp_ptTimeout.reset();
if( resp_real )
resp_state = true;
else if( resp_state && !resp_real && resp_ptTimeout.checkTime() )
resp_state = false;
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if( !resp_init )
{
resp_state = resp_real;
resp_init = true;
prev = resp_state;
return true;
}
return ( prev != resp_state );
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateSM()
{
for( MBTCPMaster::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
// обновление датчиков связи происходит в другом потоке
// чтобы не зависеть от TCP таймаутов
// см. updateRespondSensors()
// update values...
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype == dtRTU )
updateRTU(it);
else if( d->dtype == dtMTR )
updateMTR(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();
}
askTimer(tmExchange,polltime);
pollThread->start();
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);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
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;
try
{
if( sidExchangeMode != DefaultObjectId )
shm->askSensor(sidExchangeMode,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): 'sidExchangeMode' catch..." << std::endl;
}
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;
if( sm->id == sidExchangeMode )
{
exchangeMode = sm->value;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(sensorInfo): exchange MODE=" << sm->value << std::endl;
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
<< " mb_initOK=" << i->reg->mb_initOK << endl;
}
if( !i->reg->mb_initOK )
continue;
i->value = sm->value;
updateRSProperty( &(*i),true );
return;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
setProcActive(false);
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(rmap);
initIterators();
setProcActive(true);
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::sigterm( int signo )
{
dlog[Debug::WARN] << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
setProcActive(false);
/*! \todo Доделать выставление безопасного состояния на выходы.
И нужно ли это. Ведь может не хватить времени на "обмен"
*/
// выставление безопасного состояния на выходы....
/*
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);
}
// ------------------------------------------------------------------------------------------
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, RegID id, ModbusRTU::ModbusData r,
UniXML_iterator& xmlit, MBTCPMaster::RTUDevice* dev,
MBTCPMaster::RegInfo* rcopy )
{
RegMap::iterator it = mp.find(id);
if( it != mp.end() )
{
if( !it->second->dev )
{
dlog[Debug::CRIT] << myname << "(addReg): for " << xmlit.getProp("name")
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
dlog[Debug::CRIT] << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for " << xmlit.getProp("name")
<< ". 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)
<< "(id=" << id << ")"
<< " already added for " << (*it->second)
<< " 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;
}
ri->id = id;
mp.insert(RegMap::value_type(id,ri));
ri->rit = mp.find(id);
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 tcp_vtype='" << 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 = it.getIntProp("default");
if( dev->dtype == MBTCPMaster::dtRTU )
{
// dlog[Debug::INFO] << myname << "(initRegInfo): init RTU.."
}
else if( dev->dtype == MBTCPMaster::dtMTR )
{
// only for MTR
if( !initMTRitem(it,r) )
return false;
}
else
{
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 = it.getIntProp("id");
}
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;
}
// ------------------------------------------------------------------------------------------
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;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster::RegID MBTCPMaster::genRegID( const ModbusRTU::ModbusData mbreg, const int fn )
{
// формула для вычисления ID
// требования:
// 1. ID > диапазона возможных регистров
// 2. одинаковые регистры, но разные функции должны давать разный ID
// 3. регистры идущие подряд, должна давать ID идущий тоже подряд
// Вообще диапазоны:
// mbreg: 0..65535
// fn: 0...255
int max = numeric_limits<ModbusRTU::ModbusData>::max(); // по идее 65535
int fn_max = numeric_limits<ModbusRTU::ModbusByte>::max(); // по идее 255
// fn необходимо привести к диапазону 0..max
return max + mbreg + max + UniSetTypes::lcalibrate(fn,0,fn_max,0,max,false);
}
// ------------------------------------------------------------------------------------------
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);
}
int fn = it.getIntProp("tcp_mbfunc");
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
RegID rID = genRegID(mbreg,fn);
RegInfo* ri = addReg(dev->regmap,rID,mbreg,it,dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown word size for " << it.getProp("name") << endl;
return false;
}
}
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;
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri->sm_initOK = it.getIntProp("tcp_sm_initOK");
ri->mb_initOK = true; // может быть переопределён если будет указан tcp_preinit="1" (см. ниже)
}
else
{
// Если это регистр для чтения, то сразу можно работать
// инициализировать не надо
ri->mb_initOK = true;
ri->sm_initOK = true;
}
RSProperty* p1 = addProp(ri->slst,p);
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
ri->q_count = p1->rnum;
ri->q_num = 1;
for( int i=1; i<p1->rnum; i++ )
{
RegID id1 = genRegID(mbreg+i,ri->mbfunc);
RegInfo* r = addReg(dev->regmap,id1,mbreg+i,it,dev,ri);
r->q_num=i+1;
r->q_count=1;
r->mbfunc = ri->mbfunc;
r->mb_initOK = true;
r->sm_initOK = true;
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
// Если занимает несколько регистров, а указана функция записи "одного",
// то это ошибка..
if( ri->mbfunc != ModbusRTU::fnWriteOutputRegisters &&
ri->mbfunc != ModbusRTU::fnForceMultipleCoils )
{
dlog[Debug::CRIT] << myname << "(initItem): Bad write function ='" << ModbusRTU::fnWriteOutputSingleRegister
<< "' for vtype='" << p1->vType << "'"
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
}
}
}
// Фомируем список инициализации
bool need_init = it.getIntProp("tcp_preinit");
if( need_init && ModbusRTU::isWriteFunction(ri->mbfunc) )
{
InitRegInfo ii;
ii.p = p;
ii.dev = dev;
ii.ri = ri;
string s_reg(it.getProp("tcp_init_mbreg"));
if( !s_reg.empty() )
ii.mbreg = ModbusRTU::str2mbData(s_reg);
else
ii.mbreg = ri->mbreg;
string s_mbfunc(it.getProp("tcp_init_mbfunc"));
if( !s_mbfunc.empty() )
{
ii.mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(s_mbfunc);
if( ii.mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown tcp_init_mbfunc ='" << s_mbfunc
<< "' for " << it.getProp("name") << endl;
return false;
}
}
else
{
switch(ri->mbfunc)
{
case ModbusRTU::fnWriteOutputSingleRegister:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
case ModbusRTU::fnForceSingleCoil:
ii.mbfunc = ModbusRTU::fnReadCoilStatus;
break;
case ModbusRTU::fnWriteOutputRegisters:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
case ModbusRTU::fnForceMultipleCoils:
ii.mbfunc = ModbusRTU::fnReadCoilStatus;
break;
default:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
}
}
initRegList.push_back(ii);
ri->mb_initOK = false;
ri->sm_initOK = false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBTCPMaster::initMTRitem( UniXML_iterator& it, RegInfo* p )
{
p->mtrType = MTR::str2type(it.getProp("mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
dlog[Debug::CRIT] << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp("mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBTCPMaster::initIterators()
{
MBExchange::initIterators();
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* const* argv )
{
cout << "Default: prefix='mbtcp'" << endl;
MBExchange::help_print(argc,argv);
// ---------- init MBTCP ----------
// cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
cout << " Настройки протокола TCP: " << endl;
cout << "--prefix-gateway hostname,IP - IP опрашиваемого узла" << endl;
cout << "--prefix-gateway-port num - port на опрашиваемом узле" << endl;
cout << "--prefix-recv-timeout msec - Таймаут на приём одного сообщения" << endl;
cout << "--prefix-timeout msec - Таймаут для определения отсутсвия соединения" << endl;
cout << "--prefix-persistent-connection 0,1 - Не закрывать соединение на каждом цикле опроса" << endl;
}
// -----------------------------------------------------------------------------
MBTCPMaster* MBTCPMaster::init_mbmaster( int argc, const char* const* argv,
UniSetTypes::ObjectId icID, SharedMemory* ic,
const std::string prefix )
{
string name = conf->getArgParam("--" + prefix + "-name","MBTCPMaster1");
if( name.empty() )
{
dlog[Debug::CRIT] << "(MBTCPMaster): Не задан name'" << endl;
return 0;
}
ObjectId ID = conf->getObjectID(name);
if( ID == UniSetTypes::DefaultObjectId )
{
dlog[Debug::CRIT] << "(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;
case MBTCPMaster::dtMTR:
os << "MTR";
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 << p.cal
<< " 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->ask_every_reg = it.getIntProp("ask_every_reg");
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a)
<< " ask_every_reg=" << d->second->ask_every_reg << endl;
string s(it.getProp("respondSensor"));
if( !s.empty() )
{
d->second->resp_id = conf->getSensorID(s);
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << s << endl;
return false;
}
}
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout",5000);
d->second->resp_ptTimeout.setTiming(tout);
d->second->resp_invert = it.getIntProp("invert");
// d->second->no_clean_input = it.getIntProp("no_clean_input");
// dlog[Debug::INFO] << myname << "(initDeviceInfo): add " << (*d->second) << endl;
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 << " id=" << r.id
<< " 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 << ")"
<< " mtrType=" << MTR::type2str(r.mtrType)
<< 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;
for( MBTCPMaster::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
// Вообще в map они уже лежат в нужном порядке, т.е. функция genRegID() гарантирует
// что регистры идущие подряд с одниковой функцией чтения/записи получат подряд идущие ID.
// так что оптимтизация это просто нахождение мест где id идут не подряд...
for( MBTCPMaster::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
MBTCPMaster::RegMap::iterator beg = it;
RegID id = it->second->id; // или собственно it->first
beg->second->q_num = 1;
beg->second->q_count = 1;
it++;
for( ;it!=d->regmap.end(); ++it )
{
if( (it->second->id - id) > 1 )
{
it--; // раз это регистр уже следующий, то надо вернуть на шаг обратно..
break;
}
beg->second->q_count++;
if( beg->second->q_count >= ModbusRTU::MAXDATALEN )
break;
id = it->second->id;
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;
}
}
}
// -----------------------------------------------------------------------------
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;
if( !checkUpdateSM(save) )
return;
// если требуется инициализация и она ещё не произведена,
// то игнорируем
if( save && !r->mb_initOK )
return;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "updateP: sid=" << p->si.id
<< " mbval=" << r->mbval
<< " vtype=" << p->vType
<< " rnum=" << p->rnum
<< " nbit=" << p->nbit
<< " save=" << save
<< " ioype=" << p->stype
<< " mb_initOK=" << r->mb_initOK
<< " sm_initOK=" << r->sm_initOK
<< endl;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(r->mbval);
if( p->nbit >= 0 )
{
if( save )
{
if( r->mb_initOK )
{
bool set = IOBase::processingAsDO( p, shm, force_out );
b.set(p->nbit,set);
r->mbval = b.mdata();
r->sm_initOK = true;
}
}
else
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
}
return;
}
if( p->rnum <= 1 )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(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::vtSigned )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (signed short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (signed short)IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (signed short)(r->mbval), shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (unsigned short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (unsigned short)IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (unsigned short)r->mbval, shm, force );
}
}
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 && r->sm_initOK )
{
if( r->mb_initOK )
{
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;
r->sm_initOK = true;
}
}
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 )
{
if( r->mb_initOK )
{
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];
r->sm_initOK = true;
}
}
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 )
{
if( r->mb_initOK )
{
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 );
}
}
else if( p->vType == VTypes::vtI2 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
if( r->mb_initOK )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::I2 i2(v);
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
i->second->mbval = i2.raw.v[k];
r->sm_initOK = true;
}
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::I2::wsize()];
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::I2 i2(data,VTypes::I2::wsize());
delete[] data;
IOBase::processingAsAI( p, (int)i2, shm, force );
}
}
else if( p->vType == VTypes::vtU2 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
if( r->mb_initOK )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::U2 u2(v);
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
i->second->mbval = u2.raw.v[k];
r->sm_initOK = true;
}
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::U2::wsize()];
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::U2 u2(data,VTypes::U2::wsize());
delete[] data;
IOBase::processingAsAI( p, (unsigned int)u2, shm, force );
}
}
return;
}
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;
}
// Если SM стала (или была) недоступна
// то флаг инициализации надо сбросить
r->sm_initOK = false;
}
// -----------------------------------------------------------------------------
void MBTCPMaster::updateMTR( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
if( save && exchangeMode == emReadOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emReadOnly " << endl;
return;
}
if( !save && exchangeMode == emWriteOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emWriteOnly " << endl;
return;
}
if( save && exchangeMode == emSkipSaveToSM )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emSkipSaveToSM " << endl;
return;
}
{
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
{
try
{
if( r->mtrType == MTR::mtT1 )
{
if( save )
r->mbval = IOBase::processingAsAO( &(*it), shm, force_out );
else
{
MTR::T1 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT2 )
{
if( save )
{
MTR::T2 t(IOBase::processingAsAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T2 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT3 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T3 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T3::wsize()];
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T3 t(data,MTR::T3::wsize());
delete[] data;
IOBase::processingAsAI( &(*it), (long)t, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT4 )
{
if( save )
dlog[Debug::WARN] << myname << "(updateMTR): write (T4) reg(" << dat2str(r->mbreg) << ") to MTR NOT YET!!!" << endl;
else
{
MTR::T4 t(r->mbval);
IOBase::processingAsAI( &(*it), uni_atoi(t.sval), shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT5 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T5 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T5::wsize()];
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T5 t(data,MTR::T5::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT6 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T6 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T6::wsize()];
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T6 t(data,MTR::T6::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT7 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T7 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T7::wsize()];
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T7 t(data,MTR::T7::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT16 )
{
if( save )
{
MTR::T16 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T16 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT17 )
{
if( save )
{
MTR::T17 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T17 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtF1 )
{
RegMap::iterator i(rit);
if( save )
{
float f = IOBase::processingFasAO( &(*it), shm, force_out );
MTR::F1 f1(f);
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
i->second->mbval = f1.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::F1::wsize()];
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::F1 t(data,MTR::F1::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t, shm, force );
}
continue;
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): catch ..." << endl;
}
}
}
}
// -----------------------------------------------------------------------------
void MBTCPMaster::execute()
{
no_extimer = true;
try
{
askTimer(tmExchange,0);
}
catch(...){}
initMB(false);
while(1)
{
try
{
step();
}
catch( Exception& ex )
{
dlog[Debug::CRIT] << myname << "(execute): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::CRIT] << myname << "(execute): catch ..." << endl;
}
msleep(polltime);
msleep(polltime);
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBTCPMaster::PList& lst )
std::ostream& MBTCPMaster::print_plist( std::ostream& os, MBTCPMaster::PList& lst )
{
os << "[ ";
for( MBTCPMaster::PList::const_iterator it=lst.begin(); it!=lst.end(); ++it )
os << "(" << it->si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(it->si.id)) << " ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
\ No newline at end of file
......@@ -196,152 +196,9 @@ class MBTCPMaster:
void execute();
enum Timer
{
tmExchange
};
// -----------------------------------------------------
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;
static std::ostream& print_plist( std::ostream& os, PList& p );
typedef unsigned long RegID;
typedef std::map<RegID,RegInfo*> RegMap;
struct RegInfo
{
RegInfo():
mbval(0),mbreg(0),mbfunc(ModbusRTU::fnUnknown),
id(0),dev(0),mtrType(MTR::mtUnknown),
q_num(0),q_count(1),mb_initOK(true),sm_initOK(true)
{}
ModbusRTU::ModbusData mbval;
ModbusRTU::ModbusData mbreg; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< функция для чтения/записи */
PList slst;
RegID id;
RTUDevice* dev;
// only for MTR
MTR::MTRType mtrType; /*!< тип регистра (согласно спецификации на MTR) */
// optimization
int q_num; /*!< number in query */
int q_count; /*!< count registers for query */
RegMap::iterator rit;
// начальная инициалиазция для "записываемых" регистров
// Механизм:
// Если tcp_preinit="1", то сперва будет сделано чтение значения из устройства.
// при этом флаг mb_init=false пока не пройдёт успешной инициализации
// Если tcp_preinit="0", то флаг mb_init сразу выставляется в true.
bool mb_initOK; /*!< инициализировалось ли значение из устройства */
// Флаг sm_init означает, что писать в устройство нельзя, т.к. значение в "карте регистров"
// ещё не инициализировано из SM
bool sm_initOK; /*!< инициализировалось ли значение из SM */
};
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(false),
resp_init(false),
ask_every_reg(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;
bool ask_every_reg;
// 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);
// ----------------------------------
static RegID genRegID( const ModbusRTU::ModbusData r, const int fn );
protected:
struct InitRegInfo
{
InitRegInfo():
dev(0),mbreg(0),
mbfunc(ModbusRTU::fnUnknown),
initOK(false),ri(0)
{}
RSProperty p;
RTUDevice* dev;
ModbusRTU::ModbusData mbreg;
ModbusRTU::SlaveFunctionCode mbfunc;
bool initOK;
RegInfo* ri;
};
typedef std::list<InitRegInfo> InitList;
virtual void sysCommand( UniSetTypes::SystemMessage *sm );
void firstInitRegisters();
bool preInitRead( InitList::iterator& p );
bool initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p );
bool allInitOK;
RTUDeviceMap rmap;
InitList initRegList; /*!< список регистров для инициализации */
ModbusTCPMaster* mb;
UniSetTypes::uniset_mutex mbMutex;
std::string iaddr;
// ost::InetAddress* ia;
......@@ -349,62 +206,23 @@ class MBTCPMaster:
int recv_timeout;
virtual void step();
void poll_thread();
void poll();
bool pollRTU( RTUDevice* dev, RegMap::iterator& it );
virtual ModbusClient* initMB( bool reopen=false );
void updateSM();
void updateRTU(RegMap::iterator& it);
void updateMTR(RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only=false );
void poll_thread();
void updateRespondSensors();
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 initMB( bool reopen=false );
virtual bool activateObject();
virtual void sigterm( int signo );
virtual void initIterators();
virtual bool initItem( UniXML_iterator& it );
void initDeviceList();
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
RegInfo* addReg( RegMap& rmap, RegID id, ModbusRTU::ModbusData r, UniXML_iterator& it,
RTUDevice* dev, RegInfo* rcopy=0 );
RSProperty* addProp( PList& plist, RSProperty& p );
bool initMTRitem( UniXML_iterator& it, RegInfo* 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 );
bool no_extimer;
bool force_disconnect;
timeout_t stat_time; /*!< время сбора статистики обмена */
int poll_count;
PassiveTimer ptStatistic; /*!< таймер для сбора статистики обмена */
private:
MBTCPMaster();
ModbusTCPMaster* mbtcp;
// т.к. TCP может "зависнуть" на подключении к недоступному узлу
// делаем опрос в отдельном потоке
ThreadCreator<MBTCPMaster>* pollThread; /*!< поток опроса */
bool pollActivated;
UniSetTypes::uniset_mutex pollMutex;
// определение timeout для соединения
PassiveTimer ptTimeout;
UniSetTypes::uniset_mutex tcpMutex;
};
// -----------------------------------------------------------------------------
......
#!/bin/sh
./uniset-start.sh -f ./uniset-mbtcpmaster \
./uniset-start.sh -g ./uniset-mbtcpmaster \
--confile test.xml \
--mbtcp-name MBMaster1 \
--smemory-id SharedMemory \
......
......@@ -97,8 +97,6 @@ class RTUExchange:
friend std::ostream& operator<<( std::ostream& os, RegInfo& r );
struct RTUDevice
{
RTUDevice():
......
......@@ -17,6 +17,7 @@
#include "IOBase.h"
#include "VTypes.h"
#include "MTR.h"
#include "modbus/ModbusClient.h"
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
/*!
......@@ -56,14 +57,179 @@ class MBExchange:
static DeviceType getDeviceType( const std::string dtype );
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
protected:
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;
static std::ostream& print_plist( std::ostream& os, PList& p );
typedef unsigned long RegID;
typedef std::map<RegID,RegInfo*> RegMap;
struct RegInfo
{
RegInfo():
mbval(0),mbreg(0),mbfunc(ModbusRTU::fnUnknown),
id(0),dev(0),
// rtuJack(RTUStorage::nUnknown),rtuChan(0),
mtrType(MTR::mtUnknown),
q_num(0),q_count(1),mb_initOK(true),sm_initOK(true)
{}
ModbusRTU::ModbusData mbval;
ModbusRTU::ModbusData mbreg; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc; /*!< функция для чтения/записи */
PList slst;
RegID id;
RTUDevice* dev;
// only for RTU188
// RTUStorage::RTUJack rtuJack;
// int rtuChan;
// only for MTR
MTR::MTRType mtrType; /*!< тип регистра (согласно спецификации на MTR) */
// optimization
int q_num; /*!< number in query */
int q_count; /*!< count registers for query */
RegMap::iterator rit;
// начальная инициалиазция для "записываемых" регистров
// Механизм:
// Если tcp_preinit="1", то сперва будет сделано чтение значения из устройства.
// при этом флаг mb_init=false пока не пройдёт успешной инициализации
// Если tcp_preinit="0", то флаг mb_init сразу выставляется в true.
bool mb_initOK; /*!< инициализировалось ли значение из устройства */
// Флаг sm_init означает, что писать в устройство нельзя, т.к. значение в "карте регистров"
// ещё не инициализировано из SM
bool sm_initOK; /*!< инициализировалось ли значение из SM */
};
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(false),
resp_init(false),
ask_every_reg(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;
bool ask_every_reg;
// 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);
// ----------------------------------
static RegID genRegID( const ModbusRTU::ModbusData r, const int fn );
enum Timer
{
tmExchange
};
protected:
virtual void step();
virtual void sensorInfo( UniSetTypes::SensorMessage* sm );
virtual void processingMessage( UniSetTypes::VoidMessage *msg );
virtual void sysCommand( UniSetTypes::SystemMessage *msg );
virtual void sensorInfo( UniSetTypes::SensorMessage*sm );
virtual void timerInfo( UniSetTypes::TimerMessage *tm );
virtual void askSensors( UniversalIO::UIOCommand cmd );
virtual void initOutput();
virtual void sigterm( int signo );
virtual bool initItem( UniXML_iterator& it ){ return false; }
virtual bool activateObject();
virtual void initIterators();
struct InitRegInfo
{
InitRegInfo():
dev(0),mbreg(0),
mbfunc(ModbusRTU::fnUnknown),
initOK(false),ri(0)
{}
RSProperty p;
RTUDevice* dev;
ModbusRTU::ModbusData mbreg;
ModbusRTU::SlaveFunctionCode mbfunc;
bool initOK;
RegInfo* ri;
};
typedef std::list<InitRegInfo> InitList;
void firstInitRegisters();
bool preInitRead( InitList::iterator& p );
bool initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p );
bool allInitOK;
RTUDeviceMap rmap;
InitList initRegList; /*!< список регистров для инициализации */
UniSetTypes::uniset_mutex pollMutex;
virtual ModbusClient* initMB( bool reopen=false )=0;
void poll();
bool pollRTU( RTUDevice* dev, RegMap::iterator& it );
void updateSM();
void updateRTU(RegMap::iterator& it);
void updateMTR(RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only=false );
bool checkUpdateSM( bool wrFunc );
bool checkPoll( bool wrFunc );
......@@ -74,6 +240,22 @@ class MBExchange:
void readConfiguration();
bool readItem( UniXML& xml, UniXML_iterator& it, xmlNode* sec );
bool initItem( UniXML_iterator& it );
void initDeviceList();
void initOffsetList();
RTUDevice* addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML_iterator& it );
RegInfo* addReg( RegMap& rmap, RegID id, ModbusRTU::ModbusData r, UniXML_iterator& it,
RTUDevice* dev, RegInfo* rcopy=0 );
RSProperty* addProp( PList& plist, RSProperty& p );
bool initMTRitem( UniXML_iterator& it, RegInfo* 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 );
xmlNode* cnode;
std::string s_field;
......@@ -103,8 +285,8 @@ class MBExchange:
UniSetTypes::uniset_mutex actMutex;
bool activated;
int activateTimeout;
bool noQueryOptimization;
bool no_extimer;
std::string prefix;
......@@ -112,6 +294,14 @@ class MBExchange:
int poll_count;
PassiveTimer ptStatistic; /*!< таймер для сбора статистики обмена */
std::string prop_prefix; /*!< префикс для считывания параметров обмена */
ModbusClient* mb;
// определение timeout для соединения
PassiveTimer ptTimeout;
bool pollActivated;
private:
MBExchange();
......
......@@ -13,6 +13,7 @@ using namespace UniSetExtensions;
MBExchange::MBExchange( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId,
SharedMemory* ic, const std::string prefix ):
UniSetObject_LT(objId),
allInitOK(false),
shm(0),
initPause(0),
force(false),
......@@ -21,7 +22,12 @@ mbregFromID(false),
sidExchangeMode(DefaultObjectId),
activated(false),
noQueryOptimization(false),
prefix(prefix)
no_extimer(false),
prefix(prefix),
poll_count(0),
prop_prefix(""),
mb(0),
pollActivated(false)
{
// cout << "$ $" << endl;
......@@ -123,7 +129,7 @@ prefix(prefix)
// -----------------------------------------------------------------------------
void MBExchange::help_print( int argc, const char* const* argv )
{
cout << "--prefix-name name - ObjectId (имя) процесса. По умолчанию: MBTCPMaster1" << endl;
cout << "--prefix-name name - ObjectId (имя) процесса. По умолчанию: MBExchange1" << endl;
cout << "--prefix-confnode name - Настроечная секция в конф. файле <name>. " << endl;
cout << "--prefix-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек." << endl;
cout << "--prefix-heartbeat-id name - Данный процесс связан с указанным аналоговым heartbeat-дачиком." << endl;
......@@ -196,20 +202,6 @@ void MBExchange::setProcActive( bool st )
activated = st;
}
// -----------------------------------------------------------------------------
void MBExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
if( sm->id == sidExchangeMode )
{
exchangeMode = sm->value;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(sensorInfo): exchange MODE=" << sm->value << std::endl;
return;
}
}
// ------------------------------------------------------------------------------------------
void MBExchange::sigterm( int signo )
{
dlog[Debug::WARN] << myname << ": ********* SIGTERM(" << signo <<") ********" << endl;
......@@ -270,26 +262,19 @@ void MBExchange::initIterators()
{
shm->initAIterator(aitHeartBeat);
shm->initAIterator(aitExchangeMode);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::DeviceType& dt )
{
switch(dt)
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
case MBExchange::dtRTU:
os << "RTU";
break;
case MBExchange::dtMTR:
os << "MTR";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
RTUDevice* d(it1->second);
shm->initDIterator(d->resp_dit);
for( MBExchange::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);
}
}
}
return os;
}
// -----------------------------------------------------------------------------
bool MBExchange::checkUpdateSM( bool wrFunc )
......@@ -341,3 +326,2227 @@ bool MBExchange::checkPoll( bool wrFunc )
return true;
}
// -----------------------------------------------------------------------------
MBExchange::RegID MBExchange::genRegID( const ModbusRTU::ModbusData mbreg, const int fn )
{
// формула для вычисления ID
// требования:
// 1. ID > диапазона возможных регистров
// 2. одинаковые регистры, но разные функции должны давать разный ID
// 3. регистры идущие подряд, должна давать ID идущие тоже подряд
// Вообще диапазоны:
// mbreg: 0..65535
// fn: 0...255
int max = numeric_limits<ModbusRTU::ModbusData>::max(); // по идее 65535
int fn_max = numeric_limits<ModbusRTU::ModbusByte>::max(); // по идее 255
// fn необходимо привести к диапазону 0..max
return max + mbreg + max + UniSetTypes::lcalibrate(fn,0,fn_max,0,max,false);
}
// ------------------------------------------------------------------------------------------
void MBExchange::printMap( MBExchange::RTUDeviceMap& m )
{
cout << "devices: " << endl;
for( MBExchange::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
cout << " " << *(it->second) << endl;
}
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBExchange::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( MBExchange::RTUDeviceMap::iterator it=m.begin(); it!=m.end(); ++it )
{
os << " " << *(it->second) << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBExchange::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( MBExchange::RegMap::iterator it=d.regmap.begin(); it!=d.regmap.end(); ++it )
os << " " << *(it->second) << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBExchange::RegInfo& r )
{
os << " id=" << r.id
<< " 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 << ")"
<< " mtrType=" << MTR::type2str(r.mtrType)
<< endl;
for( MBExchange::PList::iterator it=r.slst.begin(); it!=r.slst.end(); ++it )
os << " " << (*it) << endl;
return os;
}
// -----------------------------------------------------------------------------
void MBExchange::rtuQueryOptimization( RTUDeviceMap& m )
{
if( noQueryOptimization )
return;
dlog[Debug::INFO] << myname << "(rtuQueryOptimization): optimization..." << endl;
for( MBExchange::RTUDeviceMap::iterator it1=m.begin(); it1!=m.end(); ++it1 )
{
RTUDevice* d(it1->second);
// Вообще в map они уже лежат в нужном порядке, т.е. функция genRegID() гарантирует
// что регистры идущие подряд с одниковой функцией чтения/записи получат подряд идущие ID.
// так что оптимтизация это просто нахождение мест где id идут не подряд...
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
MBExchange::RegMap::iterator beg = it;
RegID id = it->second->id; // или собственно it->first
beg->second->q_num = 1;
beg->second->q_count = 1;
it++;
for( ;it!=d->regmap.end(); ++it )
{
if( (it->second->id - id) > 1 )
{
it--; // раз это регистр уже следующий, то надо вернуть на шаг обратно..
break;
}
beg->second->q_count++;
if( beg->second->q_count >= ModbusRTU::MAXDATALEN )
break;
id = it->second->id;
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;
}
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBExchange::PList& lst )
std::ostream& MBExchange::print_plist( std::ostream& os, MBExchange::PList& lst )
{
os << "[ ";
for( MBExchange::PList::const_iterator it=lst.begin(); it!=lst.end(); ++it )
os << "(" << it->si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(it->si.id)) << " ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
void MBExchange::firstInitRegisters()
{
// если все вернут TRUE, значит OK.
allInitOK = true;
for( InitList::iterator it=initRegList.begin(); it!=initRegList.end(); ++it )
{
try
{
it->initOK = preInitRead(it);
allInitOK = it->initOK;
}
catch( ModbusRTU::mbException& ex )
{
allInitOK = false;
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): FAILED ask addr=" << ModbusRTU::addr2str(it->dev->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->mbreg)
<< " err: " << ex << endl;
}
if( !it->dev->ask_every_reg )
break;
}
}
}
// -----------------------------------------------------------------------------
bool MBExchange::preInitRead( InitList::iterator& p )
{
if( p->initOK )
return true;
RTUDevice* dev = p->dev;
int q_count = p->p.rnum;
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mbfunc=" << p->mbfunc
<< " q_count=" << q_count
<< endl;
if( q_count > ModbusRTU::MAXDATALEN )
{
dlog[Debug::LEVEL3] << myname << "(preInitRead): count(" << q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
switch( p->mbfunc )
{
case ModbusRTU::fnReadOutputRegisters:
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(dev->mbaddr,p->mbreg,q_count);
p->initOK = initSMValue(ret.data, ret.count,&(p->p));
}
break;
case ModbusRTU::fnReadInputRegisters:
{
ModbusRTU::ReadInputRetMessage ret1 = mb->read04(dev->mbaddr,p->mbreg,q_count);
p->initOK = initSMValue(ret1.data,ret1.count, &(p->p));
}
break;
case ModbusRTU::fnReadInputStatus:
{
ModbusRTU::ReadInputStatusRetMessage ret = mb->read02(dev->mbaddr,p->mbreg,q_count);
ModbusRTU::ModbusData* dat = new ModbusRTU::ModbusData[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<q_count; k++,m++ )
dat[m] = b[k];
}
p->initOK = initSMValue(dat,q_count, &(p->p));
delete[] dat;
}
break;
case ModbusRTU::fnReadCoilStatus:
{
ModbusRTU::ReadCoilRetMessage ret = mb->read01(dev->mbaddr,p->mbreg,q_count);
ModbusRTU::ModbusData* dat = new ModbusRTU::ModbusData[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<q_count; k++,m++ )
dat[m] = b[k];
}
p->initOK = initSMValue(dat,q_count, &(p->p));
delete[] dat;
}
break;
default:
p->initOK = false;
break;
}
if( p->initOK )
{
bool f_out = force_out;
// выставляем флаг принудительного обновления
force_out = true;
p->ri->mb_initOK = true;
p->ri->sm_initOK = false;
updateRTU(p->ri->rit);
force_out = f_out;
}
return p->initOK;
}
// -----------------------------------------------------------------------------
bool MBExchange::initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p )
{
using namespace ModbusRTU;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(data[0]);
if( p->nbit >= 0 )
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
return true;
}
if( p->rnum <= 1 )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(data[0]), shm, force );
return true;
}
dlog[Debug::CRIT] << myname << "(initSMValue): IGNORE item: rnum=" << p->rnum
<< " > 1 ?!! for id=" << p->si.id << endl;
return false;
}
else if( p->vType == VTypes::vtSigned )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(data[0]), shm, force );
return true;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, data[0], shm, force );
}
else
IOBase::processingAsAI( p, (unsigned short)data[0], shm, force );
return true;
}
else if( p->vType == VTypes::vtByte )
{
if( p->nbyte <= 0 || p->nbyte > VTypes::Byte::bsize )
{
dlog[Debug::CRIT] << myname << "(initSMValue): IGNORE item: sid=" << ModbusRTU::dat2str(p->si.id)
<< " vtype=" << p->vType << " but nbyte=" << p->nbyte << endl;
return false;
}
VTypes::Byte b(data[0]);
IOBase::processingAsAI( p, b.raw.b[p->nbyte-1], shm, force );
return true;
}
else if( p->vType == VTypes::vtF2 )
{
VTypes::F2 f(data,VTypes::F2::wsize());
IOBase::processingFasAI( p, (float)f, shm, force );
}
else if( p->vType == VTypes::vtF4 )
{
VTypes::F4 f(data,VTypes::F4::wsize());
IOBase::processingFasAI( p, (float)f, shm, force );
}
else if( p->vType == VTypes::vtI2 )
{
VTypes::I2 i2(data,VTypes::I2::wsize());
IOBase::processingAsAI( p, (int)i2, shm, force );
}
else if( p->vType == VTypes::vtU2 )
{
VTypes::U2 u2(data,VTypes::U2::wsize());
IOBase::processingAsAI( p, (unsigned int)u2, shm, force );
}
return true;
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(initSMValue): catch ..." << endl;
}
return false;
}
// -----------------------------------------------------------------------------
bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo* p(it->second);
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): poll "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " mbfunc=" << p->mbfunc
<< " q_count=" << p->q_count
<< " mb_initOK=" << p->mb_initOK
<< " sm_initOK=" << p->sm_initOK
<< " mbval=" << p->mbval
<< endl;
if( p->q_count > ModbusRTU::MAXDATALEN )
{
dlog[Debug::LEVEL3] << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << ModbusRTU::MAXDATALEN
<< " ..ignore..."
<< endl;
}
}
if( !checkPoll(ModbusRTU::isWriteFunction(p->mbfunc)) )
return true;
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->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->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->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->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;
}
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " slist=" << (*p)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::WriteSingleOutputRetMessage ret = mb->write06(dev->mbaddr,p->mbreg,p->mbval);
}
break;
case ModbusRTU::fnWriteOutputRegisters:
{
if( !p->sm_initOK )
{
// может быть такая ситуация, что
// некоторые регистры уже инициализированы, а другие ещё нет
// при этом после оптимизации они попадают в один запрос
// поэтому здесь сделано так:
// если q_num > 1, значит этот регистр относится к предыдущему запросу
// и его просто надо пропустить..
if( p->q_num > 1 )
return true;
// смещаем итератор, если данный запрос содержит много регистров
// if( q->count > 1 )
// {
// for( int i=0; i<p->q_count; i++ )
// it++;
// return true;
// }
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
ModbusRTU::WriteOutputMessage msg(dev->mbaddr,p->mbreg);
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;
}
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU::ForceSingleCoilRetMessage ret = mb->write05(dev->mbaddr,p->mbreg,p->mbval);
}
break;
case ModbusRTU::fnForceMultipleCoils:
{
if( !p->sm_initOK )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(pollRTU): mbreg=" << ModbusRTU::dat2str(p->mbreg)
<< " IGNORE...(sm_initOK=false)" << endl;
return true;
}
ModbusRTU::ForceCoilsMessage msg(dev->mbaddr,p->mbreg);
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;
}
// -----------------------------------------------------------------------------
void MBExchange::updateSM()
{
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
// обновление датчиков связи происходит в другом потоке
// чтобы не зависеть от TCP таймаутов
// см. updateRespondSensors()
// update values...
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
try
{
if( d->dtype == dtRTU )
updateRTU(it);
else if( d->dtype == dtMTR )
updateMTR(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 MBExchange::updateRTU( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
updateRSProperty( &(*it),false );
}
// -----------------------------------------------------------------------------
void MBExchange::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;
if( !checkUpdateSM(save) )
return;
// если требуется инициализация и она ещё не произведена,
// то игнорируем
if( save && !r->mb_initOK )
return;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << "updateP: sid=" << p->si.id
<< " mbval=" << r->mbval
<< " vtype=" << p->vType
<< " rnum=" << p->rnum
<< " nbit=" << p->nbit
<< " save=" << save
<< " ioype=" << p->stype
<< " mb_initOK=" << r->mb_initOK
<< " sm_initOK=" << r->sm_initOK
<< endl;
try
{
if( p->vType == VTypes::vtUnknown )
{
ModbusRTU::DataBits16 b(r->mbval);
if( p->nbit >= 0 )
{
if( save )
{
if( r->mb_initOK )
{
bool set = IOBase::processingAsDO( p, shm, force_out );
b.set(p->nbit,set);
r->mbval = b.mdata();
r->sm_initOK = true;
}
}
else
{
bool set = b[p->nbit];
IOBase::processingAsDI( p, set, shm, force );
}
return;
}
if( p->rnum <= 1 )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
IOBase::processingAsAI( p, (signed short)(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::vtSigned )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (signed short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (signed short)IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (signed short)(r->mbval), shm, force );
}
}
return;
}
else if( p->vType == VTypes::vtUnsigned )
{
if( save )
{
if( r->mb_initOK )
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
r->mbval = (unsigned short)IOBase::processingAsDO( p, shm, force_out );
}
else
r->mbval = (unsigned short)IOBase::processingAsAO( p, shm, force_out );
r->sm_initOK = true;
}
}
else
{
if( p->stype == UniversalIO::DigitalInput ||
p->stype == UniversalIO::DigitalOutput )
{
IOBase::processingAsDI( p, r->mbval, shm, force );
}
else
{
IOBase::processingAsAI( p, (unsigned short)r->mbval, shm, force );
}
}
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 && r->sm_initOK )
{
if( r->mb_initOK )
{
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;
r->sm_initOK = true;
}
}
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 )
{
if( r->mb_initOK )
{
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];
r->sm_initOK = true;
}
}
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 )
{
if( r->mb_initOK )
{
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 );
}
}
else if( p->vType == VTypes::vtI2 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
if( r->mb_initOK )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::I2 i2(v);
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
i->second->mbval = i2.raw.v[k];
r->sm_initOK = true;
}
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::I2::wsize()];
for( int k=0; k<VTypes::I2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::I2 i2(data,VTypes::I2::wsize());
delete[] data;
IOBase::processingAsAI( p, (int)i2, shm, force );
}
}
else if( p->vType == VTypes::vtU2 )
{
RegMap::iterator i(p->reg->rit);
if( save )
{
if( r->mb_initOK )
{
long v = IOBase::processingAsAO( p, shm, force_out );
VTypes::U2 u2(v);
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
i->second->mbval = u2.raw.v[k];
r->sm_initOK = true;
}
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[VTypes::U2::wsize()];
for( int k=0; k<VTypes::U2::wsize(); k++, i++ )
data[k] = i->second->mbval;
VTypes::U2 u2(data,VTypes::U2::wsize());
delete[] data;
IOBase::processingAsAI( p, (unsigned int)u2, shm, force );
}
}
return;
}
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;
}
// Если SM стала (или была) недоступна
// то флаг инициализации надо сбросить
r->sm_initOK = false;
}
// -----------------------------------------------------------------------------
void MBExchange::updateMTR( RegMap::iterator& rit )
{
RegInfo* r(rit->second);
using namespace ModbusRTU;
bool save = isWriteFunction( r->mbfunc );
if( save && exchangeMode == emReadOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emReadOnly " << endl;
return;
}
if( !save && exchangeMode == emWriteOnly )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emWriteOnly " << endl;
return;
}
if( save && exchangeMode == emSkipSaveToSM )
{
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(updateMTR):"
<< " skip... mode=emSkipSaveToSM " << endl;
return;
}
{
for( PList::iterator it=r->slst.begin(); it!=r->slst.end(); ++it )
{
try
{
if( r->mtrType == MTR::mtT1 )
{
if( save )
r->mbval = IOBase::processingAsAO( &(*it), shm, force_out );
else
{
MTR::T1 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT2 )
{
if( save )
{
MTR::T2 t(IOBase::processingAsAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T2 t(r->mbval);
IOBase::processingAsAI( &(*it), t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT3 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T3 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T3::wsize()];
for( int k=0; k<MTR::T3::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T3 t(data,MTR::T3::wsize());
delete[] data;
IOBase::processingAsAI( &(*it), (long)t, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT4 )
{
if( save )
dlog[Debug::WARN] << myname << "(updateMTR): write (T4) reg(" << dat2str(r->mbreg) << ") to MTR NOT YET!!!" << endl;
else
{
MTR::T4 t(r->mbval);
IOBase::processingAsAI( &(*it), uni_atoi(t.sval), shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT5 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T5 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T5::wsize()];
for( int k=0; k<MTR::T5::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T5 t(data,MTR::T5::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT6 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T6 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T6::wsize()];
for( int k=0; k<MTR::T6::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T6 t(data,MTR::T6::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT7 )
{
RegMap::iterator i(rit);
if( save )
{
MTR::T7 t(IOBase::processingAsAO( &(*it), shm, force_out ));
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
i->second->mbval = t.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::T7::wsize()];
for( int k=0; k<MTR::T7::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::T7 t(data,MTR::T7::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t.val, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT16 )
{
if( save )
{
MTR::T16 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T16 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtT17 )
{
if( save )
{
MTR::T17 t(IOBase::processingFasAO( &(*it), shm, force_out ));
r->mbval = t.val;
}
else
{
MTR::T17 t(r->mbval);
IOBase::processingFasAI( &(*it), t.fval, shm, force );
}
continue;
}
if( r->mtrType == MTR::mtF1 )
{
RegMap::iterator i(rit);
if( save )
{
float f = IOBase::processingFasAO( &(*it), shm, force_out );
MTR::F1 f1(f);
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
i->second->mbval = f1.raw.v[k];
}
else
{
ModbusRTU::ModbusData* data = new ModbusRTU::ModbusData[MTR::F1::wsize()];
for( int k=0; k<MTR::F1::wsize(); k++, i++ )
data[k] = i->second->mbval;
MTR::F1 t(data,MTR::F1::wsize());
delete[] data;
IOBase::processingFasAI( &(*it), (float)t, shm, force );
}
continue;
}
}
catch(IOController_i::NameNotFound &ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(NameNotFound) " << ex.err << endl;
}
catch(IOController_i::IOBadParam& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR):(IOBadParam) " << ex.err << endl;
}
catch(IONotifyController_i::BadRange )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): (BadRange)..." << endl;
}
catch( Exception& ex )
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): " << ex << endl;
}
catch(CORBA::SystemException& ex)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): CORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
dlog[Debug::LEVEL3] << myname << "(updateMTR): catch ..." << endl;
}
}
}
}
// -----------------------------------------------------------------------------
MBExchange::RTUDevice* MBExchange::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML_iterator& xmlit )
{
RTUDeviceMap::iterator it = mp.find(a);
if( it != mp.end() )
{
DeviceType dtype = getDeviceType(xmlit.getProp(prop_prefix + "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;
}
MBExchange::RTUDevice* d = new MBExchange::RTUDevice();
d->mbaddr = a;
if( !initRTUDevice(d,xmlit) )
{
delete d;
return 0;
}
mp.insert(RTUDeviceMap::value_type(a,d));
return d;
}
// ------------------------------------------------------------------------------------------
MBExchange::RegInfo* MBExchange::addReg( RegMap& mp, RegID id, ModbusRTU::ModbusData r,
UniXML_iterator& xmlit, MBExchange::RTUDevice* dev,
MBExchange::RegInfo* rcopy )
{
RegMap::iterator it = mp.find(id);
if( it != mp.end() )
{
if( !it->second->dev )
{
dlog[Debug::CRIT] << myname << "(addReg): for " << xmlit.getProp("name")
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
dlog[Debug::CRIT] << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for " << xmlit.getProp("name")
<< ". 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)
<< "(id=" << id << ")"
<< " already added for " << (*it->second)
<< " Ignore register params for " << xmlit.getProp("name") << " ..." << endl;
}
it->second->rit = it;
return it->second;
}
MBExchange::RegInfo* ri;
if( rcopy )
{
ri = new MBExchange::RegInfo(*rcopy);
ri->slst.clear();
ri->mbreg = r;
}
else
{
ri = new MBExchange::RegInfo();
if( !initRegInfo(ri,xmlit,dev) )
{
delete ri;
return 0;
}
ri->mbreg = r;
}
ri->id = id;
mp.insert(RegMap::value_type(id,ri));
ri->rit = mp.find(id);
return ri;
}
// ------------------------------------------------------------------------------------------
MBExchange::RSProperty* MBExchange::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 MBExchange::initRSProperty( RSProperty& p, UniXML_iterator& it )
{
if( !IOBase::initItem(&p,it,shm,&dlog,myname) )
return false;
if( it.getIntProp(prop_prefix + "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(prop_prefix + "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(prop_prefix + "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(prop_prefix + "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(prop_prefix + "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 tcp_vtype='" << vt << "' for "
<< it.getProp("name")
<< endl;
return false;
}
p.vType = v;
p.rnum = VTypes::wsize(v);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initRegInfo( RegInfo* r, UniXML_iterator& it, MBExchange::RTUDevice* dev )
{
r->dev = dev;
r->mbval = it.getIntProp("default");
if( dev->dtype == MBExchange::dtRTU )
{
// dlog[Debug::INFO] << myname << "(initRegInfo): init RTU.."
}
else if( dev->dtype == MBExchange::dtMTR )
{
// only for MTR
if( !initMTRitem(it,r) )
return false;
}
else
{
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 = it.getIntProp("id");
}
else
{
string sr = it.getProp(prop_prefix + "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(prop_prefix + "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;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initRTUDevice( RTUDevice* d, UniXML_iterator& it )
{
d->dtype = getDeviceType(it.getProp(prop_prefix + "mbtype"));
if( d->dtype == dtUnknown )
{
dlog[Debug::CRIT] << myname << "(initRTUDevice): Unknown tcp_mbtype=" << it.getProp(prop_prefix + "mbtype")
<< ". Use: rtu "
<< " for " << it.getProp("name") << endl;
return false;
}
string addr = it.getProp(prop_prefix + "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 MBExchange::initItem( UniXML_iterator& it )
{
RSProperty p;
if( !initRSProperty(p,it) )
return false;
string addr = it.getProp(prop_prefix + "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(prop_prefix + "mbreg");
if( reg.empty() )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown mbreg for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
int fn = it.getIntProp(prop_prefix + "mbfunc");
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
RegID rID = genRegID(mbreg,fn);
RegInfo* ri = addReg(dev->regmap,rID,mbreg,it,dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
dlog[Debug::CRIT] << myname << "(initItem): unknown word size for " << it.getProp("name") << endl;
return false;
}
}
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;
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri->sm_initOK = it.getIntProp(prop_prefix + "sm_initOK");
ri->mb_initOK = true; // может быть переопределён если будет указан tcp_preinit="1" (см. ниже)
}
else
{
// Если это регистр для чтения, то сразу можно работать
// инициализировать не надо
ri->mb_initOK = true;
ri->sm_initOK = true;
}
RSProperty* p1 = addProp(ri->slst,p);
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
ri->q_count = p1->rnum;
ri->q_num = 1;
for( int i=1; i<p1->rnum; i++ )
{
RegID id1 = genRegID(mbreg+i,ri->mbfunc);
RegInfo* r = addReg(dev->regmap,id1,mbreg+i,it,dev,ri);
r->q_num=i+1;
r->q_count=1;
r->mbfunc = ri->mbfunc;
r->mb_initOK = true;
r->sm_initOK = true;
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
// Если занимает несколько регистров, а указана функция записи "одного",
// то это ошибка..
if( ri->mbfunc != ModbusRTU::fnWriteOutputRegisters &&
ri->mbfunc != ModbusRTU::fnForceMultipleCoils )
{
dlog[Debug::CRIT] << myname << "(initItem): Bad write function ='" << ModbusRTU::fnWriteOutputSingleRegister
<< "' for vtype='" << p1->vType << "'"
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name") << endl;
abort(); // ABORT PROGRAM!!!!
return false;
}
}
}
}
// Фомируем список инициализации
bool need_init = it.getIntProp(prop_prefix + "preinit");
if( need_init && ModbusRTU::isWriteFunction(ri->mbfunc) )
{
InitRegInfo ii;
ii.p = p;
ii.dev = dev;
ii.ri = ri;
string s_reg(it.getProp(prop_prefix + "init_mbreg"));
if( !s_reg.empty() )
ii.mbreg = ModbusRTU::str2mbData(s_reg);
else
ii.mbreg = ri->mbreg;
string s_mbfunc(it.getProp(prop_prefix + "init_mbfunc"));
if( !s_mbfunc.empty() )
{
ii.mbfunc = (ModbusRTU::SlaveFunctionCode)UniSetTypes::uni_atoi(s_mbfunc);
if( ii.mbfunc == ModbusRTU::fnUnknown )
{
dlog[Debug::CRIT] << myname << "(initItem): Unknown tcp_init_mbfunc ='" << s_mbfunc
<< "' for " << it.getProp("name") << endl;
return false;
}
}
else
{
switch(ri->mbfunc)
{
case ModbusRTU::fnWriteOutputSingleRegister:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
case ModbusRTU::fnForceSingleCoil:
ii.mbfunc = ModbusRTU::fnReadCoilStatus;
break;
case ModbusRTU::fnWriteOutputRegisters:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
case ModbusRTU::fnForceMultipleCoils:
ii.mbfunc = ModbusRTU::fnReadCoilStatus;
break;
default:
ii.mbfunc = ModbusRTU::fnReadOutputRegisters;
break;
}
}
initRegList.push_back(ii);
ri->mb_initOK = false;
ri->sm_initOK = false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initMTRitem( UniXML_iterator& it, RegInfo* p )
{
p->mtrType = MTR::str2type(it.getProp("mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
dlog[Debug::CRIT] << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp("mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::DeviceType& dt )
{
switch(dt)
{
case MBExchange::dtRTU:
os << "RTU";
break;
case MBExchange::dtMTR:
os << "MTR";
break;
case MBExchange::dtRTU188:
os << "RTU188";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::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 << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void MBExchange::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 MBExchange::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->ask_every_reg = it.getIntProp("ask_every_reg");
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a)
<< " ask_every_reg=" << d->second->ask_every_reg << endl;
string s(it.getProp("respondSensor"));
if( !s.empty() )
{
d->second->resp_id = conf->getSensorID(s);
if( d->second->resp_id == DefaultObjectId )
{
dlog[Debug::CRIT] << myname << "(initDeviceInfo): not found ID for noRespondSensor=" << s << endl;
return false;
}
}
dlog[Debug::INFO] << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout",5000);
d->second->resp_ptTimeout.setTiming(tout);
d->second->resp_invert = it.getIntProp("invert");
// d->second->no_clean_input = it.getIntProp("no_clean_input");
// dlog[Debug::INFO] << myname << "(initDeviceInfo): add " << (*d->second) << endl;
return true;
}
// -----------------------------------------------------------------------------
bool MBExchange::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
setProcActive(false);
UniSetTypes::uniset_mutex_lock l(mutex_start, 5000);
UniSetObject_LT::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(rmap);
initIterators();
setProcActive(true);
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBExchange::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 MBExchange::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();
}
askTimer(tmExchange,polltime);
break;
}
case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
case SystemMessage::WatchDog:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. MBExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBExchange)
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);
unideb << myname << "(sysCommand): ***************** UNIDEB LOG ROTATE *****************" << std::endl;
}
dlog << myname << "(sysCommand): logRotate" << std::endl;
fname = dlog.getLogFile();
if( !fname.empty() )
{
dlog.logFile(fname);
dlog << myname << "(sysCommand): ***************** dlog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void MBExchange::initOutput()
{
}
// ------------------------------------------------------------------------------------------
void MBExchange::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;
try
{
if( sidExchangeMode != DefaultObjectId )
shm->askSensor(sidExchangeMode,cmd);
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(askSensors): " << ex << std::endl;
}
catch(...)
{
dlog[Debug::WARN] << myname << "(askSensors): 'sidExchangeMode' catch..." << std::endl;
}
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBExchange::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 MBExchange::sensorInfo( UniSetTypes::SensorMessage* sm )
{
if( force_out )
return;
if( sm->id == sidExchangeMode )
{
exchangeMode = sm->value;
if( dlog.debugging(Debug::LEVEL3) )
dlog[Debug::LEVEL3] << myname << "(sensorInfo): exchange MODE=" << sm->value << std::endl;
return;
}
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBExchange::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
<< " mb_initOK=" << i->reg->mb_initOK << endl;
}
if( !i->reg->mb_initOK )
continue;
i->value = sm->value;
updateRSProperty( &(*i),true );
return;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void MBExchange::timerInfo( TimerMessage *tm )
{
if( tm->id == tmExchange )
{
if( no_extimer )
askTimer(tm->id,0);
else
step();
}
}
// -----------------------------------------------------------------------------
void MBExchange::poll()
{
if( !mb )
{
{
uniset_mutex_lock l(pollMutex, 300);
pollActivated = false;
mb = initMB(false);
if( !mb )
{
for( MBExchange::RTUDeviceMap::iterator it=rmap.begin(); it!=rmap.end(); ++it )
it->second->resp_real = false;
}
}
if( !checkProcActive() )
return;
updateSM();
allInitOK = false;
return;
}
{
uniset_mutex_lock l(pollMutex);
pollActivated = true;
ptTimeout.reset();
}
if( !allInitOK )
firstInitRegisters();
if( !checkProcActive() )
return;
for( MBExchange::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( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !checkProcActive() )
return;
try
{
if( d->dtype==MBExchange::dtRTU || d->dtype==MBExchange::dtMTR )
{
if( pollRTU(d,it) )
d->resp_real = true;
}
}
catch( ModbusRTU::mbException& ex )
{
// if( d->resp_real )
// {
if( dlog.debugging(Debug::LEVEL3) )
{
dlog[Debug::LEVEL3] << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; print_plist(dlog(Debug::LEVEL3),it->second->slst);
dlog(Debug::LEVEL3) << " err: " << ex << endl;
}
// }
// d->resp_real = false;
if( ex.err == ModbusRTU::erTimeOut && !d->ask_every_reg )
break;
// если контроллер хоть что-то ответил, то вроде как связь есть..
if( ex.err != ModbusRTU::erTimeOut )
d->resp_real = true;
}
if( it==d->regmap.end() )
break;
if( !checkProcActive() )
return;
}
if( stat_time > 0 )
poll_count++;
}
if( stat_time > 0 && ptStatistic.checkTime() )
{
cout << endl << "(poll statistic): number of calls is " << poll_count << " (poll time: " << stat_time << " sec)" << endl << endl;
ptStatistic.reset();
poll_count=0;
}
{
uniset_mutex_lock l(pollMutex);
pollActivated = false;
}
if( !checkProcActive() )
return;
// update SharedMemory...
updateSM();
// check thresholds
for( MBExchange::RTUDeviceMap::iterator it1=rmap.begin(); it1!=rmap.end(); ++it1 )
{
RTUDevice* d(it1->second);
for( MBExchange::RegMap::iterator it=d->regmap.begin(); it!=d->regmap.end(); ++it )
{
if( !checkProcActive() )
return;
RegInfo* r(it->second);
for( PList::iterator i=r->slst.begin(); i!=r->slst.end(); ++i )
IOBase::processingThreshold( &(*i),shm,force);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
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