Commit cc15c224 authored by Pavel Vainerman's avatar Pavel Vainerman Committed by Pavel Vainerman

[modbusmaster][reload config]: first prototype

parent b16c96bf
/*
* Copyright (c) 2020 Pavel Vainerman.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// -------------------------------------------------------------------------
#include <cmath>
#include <limits>
#include <sstream>
#include <Exceptions.h>
#include <UniSetTypes.h>
#include <extensions/Extensions.h>
#include <ORepHelpers.h>
#include "MBConfig.h"
#include "modbus/MBLogSugar.h"
// -------------------------------------------------------------------------
namespace uniset
{
// -----------------------------------------------------------------------------
using namespace std;
using namespace uniset::extensions;
// -----------------------------------------------------------------------------
MBConfig::MBConfig(const std::shared_ptr<uniset::Configuration>& _conf
, xmlNode* _cnode
, std::shared_ptr<SMInterface> _shm ):
cnode(_cnode),
conf(_conf),
shm(_shm)
{
}
// -----------------------------------------------------------------------------
MBConfig::~MBConfig()
{
}
// -----------------------------------------------------------------------------
void MBConfig::cloneParams( const std::shared_ptr<MBConfig>& mbconf )
{
s_field = mbconf->s_field;
s_fvalue = mbconf->s_fvalue;
defaultMBtype = mbconf->defaultMBtype;
defaultMBaddr = mbconf->defaultMBaddr;
defaultMBinitOK = mbconf->defaultMBinitOK;
mblog = mbconf->mblog;
myname = mbconf->myname;
noQueryOptimization = mbconf->noQueryOptimization;
maxQueryCount = mbconf->maxQueryCount;
recv_timeout = mbconf->recv_timeout;
default_timeout = mbconf->default_timeout;
aftersend_pause = mbconf->aftersend_pause;
polltime = mbconf->polltime;
sleepPause_msec = mbconf->sleepPause_msec;
prefix = mbconf->prefix;
prop_prefix = mbconf->prop_prefix;
mbregFromID = mbconf->mbregFromID;
}
// -----------------------------------------------------------------------------
void MBConfig::loadConfig( const std::shared_ptr<uniset::UniXML>& xml, UniXML::iterator sensorsSection )
{
readConfiguration(xml, sensorsSection);
if( !noQueryOptimization )
rtuQueryOptimization(devices, maxQueryCount);
initDeviceList(xml);
}
// ------------------------------------------------------------------------------------------
void MBConfig::readConfiguration( const std::shared_ptr<uniset::UniXML>& xml, UniXML::iterator sensorsSection )
{
UniXML::iterator it = sensorsSection;
if( !it.getCurrent() )
{
it = xml->findNode(xml->getFirstNode(), "sensors");
if(!it)
{
ostringstream err;
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
}
if( !it.goChildren() )
{
mbcrit << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n";
return;
}
for( ; it.getCurrent(); it.goNext() )
{
if( uniset::check_filter(it, s_field, s_fvalue) )
initItem(it);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
MBConfig::DeviceType MBConfig::getDeviceType( const std::string& dtype ) noexcept
{
if( dtype.empty() )
return dtUnknown;
if( dtype == "mtr" || dtype == "MTR" )
return dtMTR;
if( dtype == "rtu" || dtype == "RTU" )
return dtRTU;
if( dtype == "rtu188" || dtype == "RTU188" )
return dtRTU188;
return dtUnknown;
}
// -----------------------------------------------------------------------------
void MBConfig::printMap( MBConfig::RTUDeviceMap& m )
{
cout << "devices: " << endl;
for( auto it = m.begin(); it != m.end(); ++it )
cout << " " << *(it->second) << endl;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBConfig::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( auto it = m.begin(); it != m.end(); ++it )
os << " " << *(it->second) << endl;
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBConfig::RTUDevice& d )
{
os << "addr=" << ModbusRTU::addr2str(d.mbaddr)
<< " type=" << d.dtype
<< " respond_id=" << d.resp_id
<< " respond_timeout=" << d.resp_Delay.getOffDelay()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< " safeMode=" << (MBConfig::SafeMode)d.safeMode
<< endl;
os << " regs: " << endl;
for( const auto& m : d.pollmap )
{
for( const auto& it : * (m.second) )
os << " " << it.second << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBConfig::RegInfo* r )
{
return os << (*r);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBConfig::RegInfo& r )
{
os << " id=" << r.regID
<< " 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( const auto& s : r.slst )
os << " " << s << endl;
return os;
}
// -----------------------------------------------------------------------------
void MBConfig::rtuQueryOptimization( RTUDeviceMap& dm, size_t maxQueryCount )
{
// mbinfo << myname << "(rtuQueryOptimization): optimization..." << endl;
for( const auto& d : dm )
rtuQueryOptimizationForDevice(d.second, maxQueryCount);
}
// -----------------------------------------------------------------------------
void MBConfig::rtuQueryOptimizationForDevice( const std::shared_ptr<RTUDevice>& d, size_t maxQueryCount )
{
// mbinfo << myname << "(rtuQueryOptimizationForDevice): dev addr="
// << ModbusRTU::addr2str(d->mbaddr) << " optimization..." << endl;
for( const auto& m : d->pollmap )
rtuQueryOptimizationForRegMap(m.second, maxQueryCount);
}
// -----------------------------------------------------------------------------
void MBConfig::rtuQueryOptimizationForRegMap( const std::shared_ptr<RegMap>& regmap, size_t maxQueryCount )
{
if( regmap->size() <= 1 )
return;
// Вообще в map они уже лежат в нужном порядке, т.е. функция genRegID() гарантирует
// что регистры идущие подряд с одниковой функцией чтения/записи получат подряд идущие RegID.
// так что оптимтизация это просто нахождение мест где RegID идут не подряд...
for( auto it = regmap->begin(); it != regmap->end(); ++it )
{
auto& beg = it->second;
ModbusRTU::RegID regID = beg->regID;
beg->q_count = 1;
beg->q_num = 0;
++it;
// склеиваем регистры идущие подряд
for( ; it != regmap->end(); ++it )
{
if( (it->second->regID - regID) > 1 )
{
// этот регистр должен войти уже в следующий запрос,
// надо вернуть на шаг обратно..
--it;
break;
}
beg->q_count++;
regID = it->second->regID;
it->second->q_num = beg->q_count - 1;
it->second->q_count = 0;
if( beg->q_count >= maxQueryCount )
break;
}
// Корректировка типа функции, в случае необходимости...
if( beg->q_count > 1 && beg->mbfunc == ModbusRTU::fnWriteOutputSingleRegister )
{
// mbwarn << myname << "(rtuQueryOptimization): "
// << " optimization change func=" << ModbusRTU::fnWriteOutputSingleRegister
// << " <--> func=" << ModbusRTU::fnWriteOutputRegisters
// << " for mbaddr=" << ModbusRTU::addr2str(beg->dev->mbaddr)
// << " mbreg=" << ModbusRTU::dat2str(beg->mbreg);
beg->mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if( beg->q_count > 1 && beg->mbfunc == ModbusRTU::fnForceSingleCoil )
{
// mbwarn << myname << "(rtuQueryOptimization): "
// << " optimization change func=" << ModbusRTU::fnForceSingleCoil
// << " <--> func=" << ModbusRTU::fnForceMultipleCoils
// << " for mbaddr=" << ModbusRTU::addr2str(beg->dev->mbaddr)
// << " mbreg=" << ModbusRTU::dat2str(beg->mbreg);
beg->mbfunc = ModbusRTU::fnForceMultipleCoils;
}
// надо до внешнего цикла, где будет ++it
// проверить условие.. (т.к. мы во внутреннем цикле итерировались
if( it == regmap->end() )
break;
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBConfig::PList& lst )
std::ostream& MBConfig::print_plist( std::ostream& os, const MBConfig::PList& lst )
{
os << "[ ";
for( const auto& p : lst )
os << "(" << p.si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(p.si.id)) << " ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
std::shared_ptr<MBConfig::RTUDevice> MBConfig::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML::iterator& xmlit )
{
auto it = mp.find(a);
if( it != mp.end() )
{
string s_dtype(xmlit.getProp(prop_prefix + "mbtype"));
if( s_dtype.empty() )
s_dtype = defaultMBtype;
DeviceType dtype = getDeviceType(s_dtype);
if( it->second->dtype != dtype )
{
mbcrit << myname << "(addDev): OTHER mbtype=" << dtype << " for " << xmlit.getProp("name")
<< " prop='" << prop_prefix + "mbtype" << "'"
<< ". Already used devtype=" << it->second->dtype
<< " for mbaddr=" << ModbusRTU::addr2str(it->second->mbaddr)
<< endl;
return 0;
}
mbinfo << myname << "(addDev): device for addr=" << ModbusRTU::addr2str(a)
<< " already added. Ignore device params for " << xmlit.getProp("name") << " ..." << endl;
return it->second;
}
auto d = make_shared<MBConfig::RTUDevice>();
d->mbaddr = a;
if( !initRTUDevice(d, xmlit) )
{
d.reset();
return 0;
}
mp.insert( std::make_pair(a, d) );
return d;
}
// ------------------------------------------------------------------------------------------
std::shared_ptr<MBConfig::RegInfo> MBConfig::addReg( std::shared_ptr<RegMap>& mp, ModbusRTU::RegID regID, ModbusRTU::ModbusData r,
UniXML::iterator& xmlit, std::shared_ptr<MBConfig::RTUDevice> dev )
{
auto it = mp->find(regID);
if( it != mp->end() )
{
if( !it->second->dev )
{
mbcrit << myname << "(addReg): for " << xmlit.getProp("name")
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{
mbcrit << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for " << xmlit.getProp("name")
<< ". Already used devtype=" << it->second->dev->dtype << " for " << it->second->dev << endl;
return 0;
}
mbinfo << myname << "(addReg): reg=" << ModbusRTU::dat2str(r)
<< "(regID=" << regID << ")"
<< " already added for " << (*it->second)
<< " Ignore register params for " << xmlit.getProp("name") << " ..." << endl;
it->second->rit = it;
return it->second;
}
auto ri = make_shared<MBConfig::RegInfo>();
if( !initRegInfo(ri, xmlit, dev) )
return 0;
ri->mbreg = r;
ri->regID = regID;
mp->insert( std::make_pair(regID, ri) );
ri->rit = mp->find(regID);
mbinfo << myname << "(addReg): reg=" << ModbusRTU::dat2str(r) << "(regID=" << regID << ")" << endl;
return ri;
}
// ------------------------------------------------------------------------------------------
MBConfig::RSProperty* MBConfig::addProp( PList& plist, RSProperty&& p )
{
for( auto&& it : plist )
{
if( it.si.id == p.si.id && it.si.node == p.si.node )
return &it;
}
plist.emplace_back( std::move(p) );
auto it = plist.end();
--it;
return &(*it);
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initRSProperty( RSProperty& p, UniXML::iterator& it )
{
if( !IOBase::initItem(&p, it, shm, prop_prefix, false, mblog, myname) )
return false;
// проверяем не пороговый ли это датчик (т.е. не связанный с обменом)
// тогда заносим его в отдельный список
if( p.t_ai != DefaultObjectId )
{
thrlist.emplace_back( std::move(p) );
return true;
}
const string sbit(IOBase::initProp(it, "nbit", prop_prefix, false));
if( !sbit.empty() )
{
p.nbit = uniset::uni_atoi(sbit.c_str());
if( p.nbit < 0 || p.nbit >= ModbusRTU::BitsPerData )
{
mbcrit << myname << "(initRSProperty): BAD nbit=" << (int)p.nbit
<< ". (0 >= nbit < " << ModbusRTU::BitsPerData << ")." << endl;
return false;
}
}
if( p.nbit > 0 &&
( p.stype == UniversalIO::AI ||
p.stype == UniversalIO::AO ) )
{
mbwarn << "(initRSProperty): (ignore) uncorrect param`s nbit!=0(" << p.nbit << ")"
<< " for iotype=" << p.stype << " for " << it.getProp("name") << endl;
}
const string sbyte(IOBase::initProp(it, "nbyte", prop_prefix, false) );
if( !sbyte.empty() )
{
p.nbyte = uniset::uni_atoi(sbyte.c_str());
if( p.nbyte > VTypes::Byte::bsize )
{
mbwarn << myname << "(initRSProperty): BAD nbyte=" << p.nbyte
<< ". (0 >= nbyte < " << VTypes::Byte::bsize << ")." << endl;
return false;
}
}
const string vt( IOBase::initProp(it, "vtype", prop_prefix, false) );
if( vt.empty() )
{
p.rnum = VTypes::wsize(VTypes::vtUnknown);
p.vType = VTypes::vtUnknown;
}
else
{
VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown )
{
mbcrit << myname << "(initRSProperty): Unknown tcp_vtype='" << vt << "' for "
<< it.getProp("name")
<< endl;
return false;
}
p.vType = v;
p.rnum = VTypes::wsize(v);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initRegInfo( std::shared_ptr<RegInfo>& r, UniXML::iterator& it, std::shared_ptr<MBConfig::RTUDevice>& dev )
{
r->dev = dev;
r->mbval = IOBase::initIntProp(it, "default", prop_prefix, false);
if( dev->dtype == MBConfig::dtRTU )
{
// mblog.info() << myname << "(initRegInfo): init RTU.."
}
else if( dev->dtype == MBConfig::dtMTR )
{
// only for MTR
if( !initMTRitem(it, r) )
return false;
}
else if( dev->dtype == MBConfig::dtRTU188 )
{
// only for RTU188
if( !initRTU188item(it, r) )
return false;
UniversalIO::IOType t = uniset::getIOType(IOBase::initProp(it, "iotype", prop_prefix, false));
r->mbreg = RTUStorage::getRegister(r->rtuJack, r->rtuChan, t);
r->mbfunc = RTUStorage::getFunction(r->rtuJack, r->rtuChan, t);
// т.к. с RTU188 свой обмен
// mbreg и mbfunc поля не используются
return true;
}
else
{
mbcrit << 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
{
const string sr( IOBase::initProp(it, "mbreg", prop_prefix, false) );
if( sr.empty() )
{
mbcrit << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl;
return false;
}
r->mbreg = ModbusRTU::str2mbData(sr);
}
r->mbfunc = ModbusRTU::fnUnknown;
const string f( IOBase::initProp(it, "mbfunc", prop_prefix, false) );
if( !f.empty() )
{
r->mbfunc = (ModbusRTU::SlaveFunctionCode)uniset::uni_atoi(f.c_str());
if( r->mbfunc == ModbusRTU::fnUnknown )
{
mbcrit << myname << "(initRegInfo): Unknown mbfunc ='" << f
<< "' for " << it.getProp("name") << endl;
return false;
}
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initRTUDevice( std::shared_ptr<RTUDevice>& d, UniXML::iterator& it )
{
string mbtype(IOBase::initProp(it, "mbtype", prop_prefix, false));
if(mbtype.empty())
mbtype = defaultMBtype;
d->dtype = getDeviceType(mbtype);
if( d->dtype == dtUnknown )
{
mbcrit << myname << "(initRTUDevice): Unknown tcp_mbtype='" << mbtype << "'"
<< ". Use: rtu "
<< " for " << it.getProp("name") << endl;
return false;
}
string addr( IOBase::initProp(it, "mbaddr", prop_prefix, false) );
if( addr.empty() )
addr = defaultMBaddr;
if( addr.empty() )
{
mbcrit << myname << "(initRTUDevice): Unknown mbaddr for " << it.getProp("name") << endl;
return false;
}
d->mbaddr = ModbusRTU::str2mbAddr(addr);
if( d->dtype == MBConfig::dtRTU188 )
{
if( !d->rtu188 )
d->rtu188 = make_shared<RTUStorage>(d->mbaddr);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initItem( UniXML::iterator& it )
{
RSProperty p;
if( !initRSProperty(p, it) )
return false;
if( p.t_ai != DefaultObjectId ) // пороговые датчики в список обмена вносить не надо.
return true;
string addr( IOBase::initProp(it, "mbaddr", prop_prefix, false) );
if( addr.empty() )
addr = defaultMBaddr;
if( addr.empty() )
{
mbcrit << myname << "(initItem): Unknown mbaddr(" << IOBase::initProp(it, "mbaddr", prop_prefix, false) << ")='" << addr << "' for " << it.getProp("name") << endl;
return false;
}
ModbusRTU::ModbusAddr mbaddr = ModbusRTU::str2mbAddr(addr);
auto dev = addDev(devices, mbaddr, it);
if( !dev )
{
mbcrit << myname << "(initItem): " << it.getProp("name") << " CAN`T ADD for polling!" << endl;
return false;
}
ModbusRTU::ModbusData mbreg = 0;
int fn = IOBase::initIntProp(it, "mbfunc", prop_prefix, false);
if( dev->dtype == dtRTU188 )
{
auto r_tmp = make_shared<RegInfo>();
if( !initRTU188item(it, r_tmp) )
{
mbcrit << myname << "(initItem): init RTU188 failed for " << it.getProp("name") << endl;
r_tmp.reset();
return false;
}
mbreg = RTUStorage::getRegister(r_tmp->rtuJack, r_tmp->rtuChan, p.stype);
fn = RTUStorage::getFunction(r_tmp->rtuJack, r_tmp->rtuChan, p.stype);
}
else
{
if( mbregFromID )
mbreg = p.si.id; // conf->getSensorID(it.getProp("name"));
else
{
const string reg( IOBase::initProp(it, "mbreg", prop_prefix, false) );
if( reg.empty() )
{
mbcrit << myname << "(initItem): unknown mbreg(" << prop_prefix << ") for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
if( p.nbit != -1 )
{
if( fn == ModbusRTU::fnReadCoilStatus || fn == ModbusRTU::fnReadInputStatus )
{
mbcrit << myname << "(initItem): MISMATCHED CONFIGURATION! nbit=" << (int)p.nbit << " func=" << fn
<< " for " << it.getProp("name") << endl;
return false;
}
}
}
/*! приоритет опроса:
* 1...n - задаёт "частоту" опроса. Т.е. каждые 1...n циклов
*/
size_t pollfactor = IOBase::initIntProp(it, "pollfactor", prop_prefix, false, 0);
std::shared_ptr<RegMap> rmap;
auto rit = dev->pollmap.find(pollfactor);
if( rit == dev->pollmap.end() )
{
rmap = make_shared<RegMap>();
dev->pollmap.emplace(pollfactor, rmap);
}
else
rmap = rit->second;
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
ModbusRTU::RegID rID = ModbusRTU::genRegID(mbreg, fn);
auto ri = addReg(rmap, rID, mbreg, it, dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
mbcrit << 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 )
{
ostringstream sl;
sl << "[ ";
for( const auto& i : ri->slst )
sl << ORepHelpers::getShortName(conf->oind->getMapName(i.si.id)) << ",";
sl << "]";
ostringstream err;
err << myname << "(initItem): FAILED! Sharing SAVE (not bit saving) to "
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg) << "(" << (int)ri->mbreg << ")"
<< " conflict with sensors " << sl.str();
mbcrit << err.str() << endl;
throw uniset::SystemError(err.str());
}
if( p.nbit >= 0 && ri->slst.size() == 1 )
{
auto it2 = ri->slst.begin();
if( it2->nbit < 0 )
{
ostringstream err;
err << myname << "(initItem): FAILED! Sharing SAVE (mbreg="
<< ModbusRTU::dat2str(ri->mbreg) << "(" << (int)ri->mbreg << ") already used)!"
<< " IGNORE --> " << it.getProp("name");
mbcrit << err.str() << endl;
throw uniset::SystemError(err.str());
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri->sm_initOK = IOBase::initIntProp(it, "sm_initOK", prop_prefix, false);
ri->mb_initOK = true;
}
else
{
ri->mb_initOK = defaultMBinitOK;
ri->sm_initOK = false;
}
RSProperty* p1 = addProp(ri->slst, std::move(p) );
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
ri->q_count = p1->rnum;
ri->q_num = 1;
for( auto i = 1; i < p1->rnum; i++ )
{
ModbusRTU::RegID id1 = ModbusRTU::genRegID(mbreg + i, ri->mbfunc);
auto r = addReg(rmap, id1, mbreg + i, it, dev);
r->q_num = i + 1;
r->q_count = 1;
r->mbfunc = ri->mbfunc;
r->mb_initOK = defaultMBinitOK;
r->sm_initOK = false;
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
// Если занимает несколько регистров, а указана функция записи "одного",
// то это ошибка..
if( ri->mbfunc != ModbusRTU::fnWriteOutputRegisters &&
ri->mbfunc != ModbusRTU::fnForceMultipleCoils )
{
ostringstream err;
err << myname << "(initItem): Bad write function ='" << ModbusRTU::fnWriteOutputSingleRegister
<< "' for vtype='" << p1->vType << "'"
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg)
<< " for " << it.getProp("name");
mbcrit << err.str() << endl;
throw uniset::SystemError(err.str());
}
}
}
}
// Фомируем список инициализации
bool need_init = IOBase::initIntProp(it, "preinit", prop_prefix, false);
if( need_init && ModbusRTU::isWriteFunction(ri->mbfunc) )
{
InitRegInfo ii;
ii.p = std::move(p);
ii.dev = dev;
ii.ri = ri;
const string s_reg(IOBase::initProp(it, "init_mbreg", prop_prefix, false));
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)uniset::uni_atoi(s_mbfunc);
if( ii.mbfunc == ModbusRTU::fnUnknown )
{
mbcrit << 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.emplace_back( std::move(ii) );
ri->mb_initOK = false;
ri->sm_initOK = false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initMTRitem( UniXML::iterator& it, std::shared_ptr<RegInfo>& p )
{
p->mtrType = MTR::str2type(it.getProp(prop_prefix + "mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
mbcrit << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp(prop_prefix + "mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBConfig::initRTU188item( UniXML::iterator& it, std::shared_ptr<RegInfo>& p )
{
const string jack(IOBase::initProp(it, "jack", prop_prefix, false));
const string chan(IOBase::initProp(it, "channel", prop_prefix, false));
if( jack.empty() )
{
mbcrit << myname << "(readRTU188Item): Unknown " << prop_prefix << "jack='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuJack = RTUStorage::s2j(jack);
if( p->rtuJack == RTUStorage::nUnknown )
{
mbcrit << myname << "(readRTU188Item): Unknown " << prop_prefix << "jack=" << jack
<< " for " << it.getProp("name") << endl;
return false;
}
if( chan.empty() )
{
mbcrit << myname << "(readRTU188Item): Unknown channel='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuChan = uniset::uni_atoi(chan);
mblog2 << myname << "(readRTU188Item): add jack='" << jack << "'"
<< " channel='" << p->rtuChan << "'" << endl;
return true;
}
// ------------------------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBConfig::DeviceType& dt )
{
switch(dt)
{
case MBConfig::dtRTU:
os << "RTU";
break;
case MBConfig::dtMTR:
os << "MTR";
break;
case MBConfig::dtRTU188:
os << "RTU188";
break;
default:
os << "Unknown device type (" << (int)dt << ")";
break;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBConfig::RSProperty& p )
{
os << " (" << ModbusRTU::dat2str(p.reg->mbreg) << ")"
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " nbit=" << (int)p.nbit
<< " nbyte=" << p.nbyte
<< " rnum=" << p.rnum
<< " safeval=" << p.safeval
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AI || p.stype == UniversalIO::AO )
{
os << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void MBConfig::initDeviceList(const std::shared_ptr<UniXML>& xml )
{
xmlNode* respNode = 0;
if( xml )
respNode = xml->extFindNode(cnode, 1, 1, "DeviceList");
if( respNode )
{
UniXML::iterator it1(respNode);
if( it1.goChildren() )
{
for(; it1.getCurrent(); it1.goNext() )
{
ModbusRTU::ModbusAddr a = ModbusRTU::str2mbAddr(it1.getProp("addr"));
initDeviceInfo(devices, a, it1);
}
}
else
mbwarn << myname << "(init): <DeviceList> empty section..." << endl;
}
else
mbwarn << myname << "(init): <DeviceList> not found..." << endl;
}
// -----------------------------------------------------------------------------
bool MBConfig::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it )
{
auto d = m.find(a);
if( d == m.end() )
{
mbwarn << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
auto& dev = d->second;
dev->ask_every_reg = it.getIntProp("ask_every_reg");
mbinfo << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a)
<< " ask_every_reg=" << dev->ask_every_reg << endl;
string s(it.getProp("respondSensor"));
if( !s.empty() )
{
dev->resp_id = conf->getSensorID(s);
if( dev->resp_id == DefaultObjectId )
{
mbinfo << myname << "(initDeviceInfo): not found ID for respondSensor=" << s << endl;
return false;
}
}
const string mod(it.getProp("modeSensor"));
if( !mod.empty() )
{
dev->mode_id = conf->getSensorID(mod);
if( dev->mode_id == DefaultObjectId )
{
mbcrit << myname << "(initDeviceInfo): not found ID for modeSensor=" << mod << endl;
return false;
}
UniversalIO::IOType m_iotype = conf->getIOType(dev->mode_id);
if( m_iotype != UniversalIO::AI )
{
mbcrit << myname << "(initDeviceInfo): modeSensor='" << mod << "' must be 'AI'" << endl;
return false;
}
}
// сперва проверим не задан ли режим "safemodeResetIfNotRespond"
if( it.getIntProp("safemodeResetIfNotRespond") )
dev->safeMode = MBConfig::safeResetIfNotRespond;
// потом проверим датчик для "safeExternalControl"
const string safemode = it.getProp("safemodeSensor");
if( !safemode.empty() )
{
dev->safemode_id = conf->getSensorID(safemode);
if( dev->safemode_id == DefaultObjectId )
{
mbcrit << myname << "(initDeviceInfo): not found ID for safemodeSensor=" << safemode << endl;
return false;
}
const string safemodeValue(it.getProp("safemodeValue"));
if( !safemodeValue.empty() )
dev->safemode_value = uni_atoi(safemodeValue);
dev->safeMode = MBConfig::safeExternalControl;
}
mbinfo << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout", default_timeout );
dev->resp_Delay.set(0, tout);
dev->resp_invert = it.getIntProp("invert");
dev->resp_force = it.getIntProp("force");
int init_tout = it.getPIntProp("respondInitTimeout", tout);
dev->resp_ptInit.setTiming(init_tout);
s = it.getProp("speed");
if( !s.empty() )
{
d->second->speed = ComPort::getSpeed(s);
if( d->second->speed == ComPort::ComSpeed0 )
{
// d->second->speed = defSpeed;
mbcrit << myname << "(initDeviceInfo): Unknown speed=" << s <<
" for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
}
return true;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBConfig::ExchangeMode& em )
{
if( em == MBConfig::emNone )
return os << "emNone";
if( em == MBConfig::emWriteOnly )
return os << "emWriteOnly";
if( em == MBConfig::emReadOnly )
return os << "emReadOnly";
if( em == MBConfig::emSkipSaveToSM )
return os << "emSkipSaveToSM";
if( em == MBConfig::emSkipExchange )
return os << "emSkipExchange";
return os;
}
// -----------------------------------------------------------------------------
std::string to_string( const MBConfig::SafeMode& m )
{
if( m == MBConfig::safeNone )
return "safeNone";
if( m == MBConfig::safeResetIfNotRespond )
return "safeResetIfNotRespond";
if( m == MBConfig::safeExternalControl )
return "safeExternalControl";
return "";
}
ostream& operator<<( ostream& os, const MBConfig::SafeMode& m )
{
return os << to_string(m);
}
// -----------------------------------------------------------------------------
bool MBConfig::RTUDevice::checkRespond( std::shared_ptr<DebugStream>& mblog )
{
bool prev = resp_state;
resp_state = resp_Delay.check( prev_numreply != numreply ) && numreply != 0;
mblog4 << "(checkRespond): addr=" << ModbusRTU::addr2str(mbaddr)
<< " respond_id=" << resp_id
<< " state=" << resp_state
<< " check=" << (prev_numreply != numreply)
<< " delay_check=" << resp_Delay.get()
<< " [ timeout=" << resp_Delay.getOffDelay()
<< " numreply=" << numreply
<< " prev_numreply=" << prev_numreply
<< " resp_ptInit=" << resp_ptInit.checkTime()
<< " ]"
<< endl;
// если только что прошла "инициализация" возвращаем true
// чтобы датчик в SM обновился..
if( trInitOK.hi(resp_ptInit.checkTime()) )
return true;
return ((prev != resp_state || resp_force ) && trInitOK.get() );
}
// -----------------------------------------------------------------------------
std::string MBConfig::RTUDevice::getShortInfo() const
{
ostringstream s;
s << "mbaddr=" << ModbusRTU::addr2str(mbaddr) << ":"
<< " resp_state=" << resp_state
<< " (resp_id=" << resp_id << " resp_force=" << resp_force
<< " resp_invert=" << resp_invert
<< " numreply=" << numreply
<< " timeout=" << resp_Delay.getOffDelay()
<< " type=" << dtype
<< " ask_every_reg=" << ask_every_reg
<< ")" << endl;
return s.str();
}
// -----------------------------------------------------------------------------
} // end of namespace uniset
/*
* Copyright (c) 2020 Pavel Vainerman.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// -----------------------------------------------------------------------------
#ifndef _MBConfig_H_
#define _MBConfig_H_
// -----------------------------------------------------------------------------
#include <ostream>
#include <string>
#include <map>
#include <unordered_map>
#include <memory>
#include "IONotifyController.h"
#include "Calibration.h"
#include "DelayTimer.h"
#include "SMInterface.h"
#include "SharedMemory.h"
#include "IOBase.h"
#include "VTypes.h"
#include "MTR.h"
#include "RTUStorage.h"
#include "modbus/ModbusClient.h"
#include "Configuration.h"
// -------------------------------------------------------------------------
namespace uniset
{
// -----------------------------------------------------------------------------
/*! Конфигурация для ModbusMaster */
class MBConfig
{
public:
MBConfig(const std::shared_ptr<uniset::Configuration>& conf
, xmlNode* cnode
, std::shared_ptr<SMInterface> _shm );
~MBConfig();
/*! Режимы работы процесса обмена */
enum ExchangeMode
{
emNone = 0, /*!< нормальная работа (по умолчанию) */
emWriteOnly = 1, /*!< "только посылка данных" (работают только write-функции) */
emReadOnly = 2, /*!< "только чтение" (работают только read-функции) */
emSkipSaveToSM = 3, /*!< не писать данные в SM (при этом работают и read и write функции) */
emSkipExchange = 4 /*!< отключить обмен */
};
friend std::ostream& operator<<( std::ostream& os, const ExchangeMode& em );
/*! Режимы работы процесса обмена */
enum SafeMode
{
safeNone = 0, /*!< не использовать безопасный режим (по умолчанию) */
safeResetIfNotRespond = 1, /*!< выставлять безопасное значение, если пропала связь с устройством */
safeExternalControl = 2 /*!< управление сбросом по внешнему датчику */
};
friend std::string to_string( const SafeMode& m );
friend std::ostream& operator<<( std::ostream& os, const SafeMode& m );
enum DeviceType
{
dtUnknown, /*!< неизвестный */
dtRTU, /*!< RTU (default) */
dtMTR, /*!< MTR (DEIF) */
dtRTU188 /*!< RTU188 (Fastwell) */
};
static DeviceType getDeviceType( const std::string& dtype ) noexcept;
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
struct RTUDevice;
struct RegInfo;
struct RSProperty:
public IOBase
{
// only for RTU
int8_t nbit; /*!< bit number (-1 - not used) */
VTypes::VType vType; /*!< type of value */
uint16_t rnum; /*!< count of registers */
uint8_t nbyte; /*!< byte number (1-2) */
RSProperty():
nbit(-1), vType(VTypes::vtUnknown),
rnum(VTypes::wsize(VTypes::vtUnknown)),
nbyte(0)
{}
// т.к. IOBase содержит rwmutex с запрещённым конструктором копирования
// приходится здесь тоже объявлять разрешенными только операции "перемещения"
RSProperty( const RSProperty& r ) = delete;
RSProperty& operator=(const RSProperty& r) = delete;
RSProperty( RSProperty&& r ) = default;
RSProperty& operator=(RSProperty&& r) = default;
std::shared_ptr<RegInfo> reg;
};
friend std::ostream& operator<<( std::ostream& os, const RSProperty& p );
typedef std::list<RSProperty> PList;
std::ostream& print_plist( std::ostream& os, const PList& p );
typedef std::map<ModbusRTU::RegID, std::shared_ptr<RegInfo>> RegMap;
struct RegInfo
{
// т.к. RSProperty содержит rwmutex с запрещённым конструктором копирования
// приходится здесь тоже объявлять разрешенными только операции "перемещения"
RegInfo( const RegInfo& r ) = default;
RegInfo& operator=(const RegInfo& r) = delete;
RegInfo( RegInfo&& r ) = delete;
RegInfo& operator=(RegInfo&& r) = default;
RegInfo() = default;
ModbusRTU::ModbusData mbval = { 0 };
ModbusRTU::ModbusData mbreg = { 0 }; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc = { ModbusRTU::fnUnknown }; /*!< функция для чтения/записи */
PList slst;
ModbusRTU::RegID regID = { 0 };
std::shared_ptr<RTUDevice> dev;
// only for RTU188
RTUStorage::RTUJack rtuJack = { RTUStorage::nUnknown };
int rtuChan = { 0 };
// only for MTR
MTR::MTRType mtrType = { MTR::mtUnknown }; /*!< тип регистра (согласно спецификации на MTR) */
// optimization
size_t q_num = { 0 }; /*!< number in query */
size_t q_count = { 1 }; /*!< count registers for query */
RegMap::iterator rit;
// начальная инициализация для "записываемых" регистров
// Механизм:
// Если tcp_preinit="1", то сперва будет сделано чтение значения из устройства.
// при этом флаг mb_init=false пока не пройдёт успешной инициализации
// Если tcp_preinit="0", то флаг mb_init сразу выставляется в true.
bool mb_initOK = { false }; /*!< инициализировалось ли значение из устройства */
// Флаг sm_init означает, что писать в устройство нельзя, т.к. значение в "карте регистров"
// ещё не инициализировано из SM
bool sm_initOK = { false }; /*!< инициализировалось ли значение из SM */
};
friend std::ostream& operator<<( std::ostream& os, const RegInfo& r );
friend std::ostream& operator<<( std::ostream& os, const RegInfo* r );
struct RTUDevice
{
ModbusRTU::ModbusAddr mbaddr = { 0 }; /*!< адрес устройства */
std::unordered_map<size_t, std::shared_ptr<RegMap>> pollmap;
DeviceType dtype = { dtUnknown }; /*!< тип устройства */
// resp - respond..(контроль наличия связи)
uniset::ObjectId resp_id = { uniset::DefaultObjectId };
IOController::IOStateList::iterator resp_it;
DelayTimer resp_Delay; // таймер для формирования задержки на отпускание (пропадание связи)
PassiveTimer resp_ptInit; // таймер для формирования задержки на инициализацию связи (задержка на выставление датчика связи после запуска)
bool resp_state = { false };
bool resp_invert = { false };
bool resp_force = { false };
Trigger trInitOK; // триггер для "инициализации"
std::atomic<size_t> numreply = { 0 }; // количество успешных запросов..
std::atomic<size_t> prev_numreply = { 0 };
//
bool ask_every_reg = { false }; /*!< опрашивать ли каждый регистр, независимо от результата опроса предыдущего. По умолчанию false - прервать опрос при первом же timeout */
// режим работы
uniset::ObjectId mode_id = { uniset::DefaultObjectId };
IOController::IOStateList::iterator mode_it;
long mode = { emNone }; // режим работы с устройством (см. ExchangeMode)
// safe mode
long safeMode = { safeNone }; /*!< режим безопасного состояния см. SafeMode */
uniset::ObjectId safemode_id = { uniset::DefaultObjectId }; /*!< идентификатор для датчика безопасного режима */
IOController::IOStateList::iterator safemode_it;
long safemode_value = { 1 };
// return TRUE if state changed
bool checkRespond( std::shared_ptr<DebugStream>& log );
// специфические поля для RS
ComPort::Speed speed = { ComPort::ComSpeed38400 };
std::shared_ptr<RTUStorage> rtu188;
std::string getShortInfo() const;
};
friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
typedef std::unordered_map<ModbusRTU::ModbusAddr, std::shared_ptr<RTUDevice>> RTUDeviceMap;
friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
static void printMap(RTUDeviceMap& d);
typedef std::list<IOBase> ThresholdList;
struct InitRegInfo
{
InitRegInfo():
dev(0), mbreg(0),
mbfunc(ModbusRTU::fnUnknown),
initOK(false)
{}
RSProperty p;
std::shared_ptr<RTUDevice> dev;
ModbusRTU::ModbusData mbreg;
ModbusRTU::SlaveFunctionCode mbfunc;
bool initOK;
std::shared_ptr<RegInfo> ri;
};
typedef std::list<InitRegInfo> InitList;
static void rtuQueryOptimization( RTUDeviceMap& m, size_t maxQueryCount );
static void rtuQueryOptimizationForDevice( const std::shared_ptr<RTUDevice>& d, size_t maxQueryCount );
static void rtuQueryOptimizationForRegMap( const std::shared_ptr<RegMap>& regmap, size_t maxQueryCount );
// т.к. пороговые датчики не связаны напрямую с обменом, создаём для них отдельный список
// и отдельно его проверяем потом
ThresholdList thrlist;
RTUDeviceMap devices;
InitList initRegList; /*!< список регистров для инициализации */
void loadConfig( const std::shared_ptr<uniset::UniXML>& xml, UniXML::iterator sensorsSection );
void initDeviceList( const std::shared_ptr<UniXML>& xml );
bool initItem( UniXML::iterator& it );
std::string s_field;
std::string s_fvalue;
// определение timeout для соединения
timeout_t recv_timeout = { 500 }; // msec
timeout_t default_timeout = { 5000 }; // msec
timeout_t aftersend_pause = { 0 };
timeout_t polltime = { 100 }; /*!< периодичность обновления данных, [мсек] */
timeout_t sleepPause_msec = { 10 };
size_t maxQueryCount = { ModbusRTU::MAXDATALEN }; /*!< максимальное количество регистров для одного запроса */
xmlNode* cnode = { 0 };
std::shared_ptr<DebugStream> mblog;
std::string myname;
std::string prefix;
std::string prop_prefix; /*!< префикс для считывания параметров обмена */
std::string defaultMBtype;
std::string defaultMBaddr;
bool mbregFromID = { false };
bool defaultMBinitOK = { false }; // флаг определяющий нужно ли ждать "первого обмена" или при запуске сохранять в SM значение default.
bool noQueryOptimization = { false };
std::shared_ptr<uniset::Configuration> conf;
std::shared_ptr<SMInterface> shm;
void cloneParams( const std::shared_ptr<MBConfig>& conf );
protected:
bool initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p );
void readConfiguration(const std::shared_ptr<uniset::UniXML>& xml, UniXML::iterator sensorsSection );
void initOffsetList();
std::shared_ptr<RTUDevice> addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
std::shared_ptr<RegInfo> addReg(std::shared_ptr<RegMap>& devices, ModbusRTU::RegID id, ModbusRTU::ModbusData r, UniXML::iterator& it, std::shared_ptr<RTUDevice> dev );
RSProperty* addProp( PList& plist, RSProperty&& p );
bool initMTRitem(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
bool initRTU188item(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
bool initRSProperty( RSProperty& p, UniXML::iterator& it );
bool initRegInfo(std::shared_ptr<RegInfo>& r, UniXML::iterator& it, std::shared_ptr<RTUDevice>& dev );
bool initRTUDevice( std::shared_ptr<RTUDevice>& d, UniXML::iterator& it );
bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
};
// --------------------------------------------------------------------------
} // end of namespace uniset
// -----------------------------------------------------------------------------
#endif // _MBConfig_H_
// -----------------------------------------------------------------------------
...@@ -34,18 +34,13 @@ namespace uniset ...@@ -34,18 +34,13 @@ namespace uniset
const std::shared_ptr<SharedMemory>& _ic, const std::string& prefix ): const std::shared_ptr<SharedMemory>& _ic, const std::string& prefix ):
UniSetObject(objId), UniSetObject(objId),
allInitOK(false), allInitOK(false),
initPause(3000),
force(false), force(false),
force_out(false), force_out(false),
mbregFromID(false),
sidExchangeMode(DefaultObjectId), sidExchangeMode(DefaultObjectId),
exchangeMode(emNone), exchangeMode(MBConfig::emNone),
activated(false), activated(false),
noQueryOptimization(false),
notUseExchangeTimer(false), notUseExchangeTimer(false),
prefix(prefix),
poll_count(0), poll_count(0),
prop_prefix(""),
mb(nullptr), mb(nullptr),
ic(_ic) ic(_ic)
{ {
...@@ -53,7 +48,7 @@ namespace uniset ...@@ -53,7 +48,7 @@ namespace uniset
throw uniset::SystemError("(MBExchange): objId=-1?!! Use --" + prefix + "-name" ); throw uniset::SystemError("(MBExchange): objId=-1?!! Use --" + prefix + "-name" );
auto conf = uniset_conf(); auto conf = uniset_conf();
mutex_start.setName(myname + "_mutex_start"); mutex_start.setName(myname + "_mutgc7vdgchex_start");
string conf_name(conf->getArgParam("--" + prefix + "-confnode", myname)); string conf_name(conf->getArgParam("--" + prefix + "-confnode", myname));
...@@ -63,10 +58,13 @@ namespace uniset ...@@ -63,10 +58,13 @@ namespace uniset
throw uniset::SystemError("(MBExchange): Not found node <" + conf_name + " ...> for " + myname ); throw uniset::SystemError("(MBExchange): Not found node <" + conf_name + " ...> for " + myname );
shm = make_shared<SMInterface>(shmId, ui, objId, ic); shm = make_shared<SMInterface>(shmId, ui, objId, ic);
mbconf = make_shared<MBConfig>(conf, cnode, shm);
mblog = make_shared<DebugStream>(); mblog = make_shared<DebugStream>();
mblog->setLogName(myname); mblog->setLogName(myname);
conf->initLogStream(mblog, prefix + "-log"); conf->initLogStream(mblog, prefix + "-log");
mbconf->mblog = mblog;
mbconf->myname = myname;
loga = make_shared<LogAgregator>(myname + "-loga"); loga = make_shared<LogAgregator>(myname + "-loga");
loga->add(mblog); loga->add(mblog);
...@@ -88,16 +86,12 @@ namespace uniset ...@@ -88,16 +86,12 @@ namespace uniset
ic->logAgregator()->add(loga); ic->logAgregator()->add(loga);
// определяем фильтр // определяем фильтр
s_field = conf->getArgParam("--" + prefix + "-filter-field"); mbconf->s_field = conf->getArgParam("--" + prefix + "-filter-field");
s_fvalue = conf->getArgParam("--" + prefix + "-filter-value"); mbconf->s_fvalue = conf->getArgParam("--" + prefix + "-filter-value");
mbinfo << myname << "(init): read fileter-field='" << s_field mbinfo << myname << "(init): read fileter-field='" << mbconf->s_field
<< "' filter-value='" << s_fvalue << "'" << endl; << "' filter-value='" << mbconf->s_fvalue << "'" << endl;
vmonit(s_field); mbconf->prop_prefix = initPropPrefix(mbconf->s_field, "");
vmonit(s_fvalue);
prop_prefix = initPropPrefix();
vmonit(prop_prefix);
stat_time = conf->getArgPInt("--" + prefix + "-statistic-sec", it.getProp("statistic_sec"), 0); stat_time = conf->getArgPInt("--" + prefix + "-statistic-sec", it.getProp("statistic_sec"), 0);
vmonit(stat_time); vmonit(stat_time);
...@@ -105,50 +99,44 @@ namespace uniset ...@@ -105,50 +99,44 @@ namespace uniset
if( stat_time > 0 ) if( stat_time > 0 )
ptStatistic.setTiming(stat_time * 1000); ptStatistic.setTiming(stat_time * 1000);
recv_timeout = conf->getArgPInt("--" + prefix + "-recv-timeout", it.getProp("recv_timeout"), 500); mbconf->recv_timeout = conf->getArgPInt("--" + prefix + "-recv-timeout", it.getProp("recv_timeout"), 500);
vmonit(recv_timeout); // vmonit(recv_timeout);
default_timeout = conf->getArgPInt("--" + prefix + "-timeout", it.getProp("timeout"), 5000); mbconf->default_timeout = conf->getArgPInt("--" + prefix + "-timeout", it.getProp("timeout"), 5000);
vmonit(default_timeout); // vmonit(default_timeout);
int tout = conf->getArgPInt("--" + prefix + "-reopen-timeout", it.getProp("reopen_timeout"), default_timeout * 2); int tout = conf->getArgPInt("--" + prefix + "-reopen-timeout", it.getProp("reopen_timeout"), mbconf->default_timeout * 2);
ptReopen.setTiming(tout); ptReopen.setTiming(tout);
int reinit_tout = conf->getArgPInt("--" + prefix + "-reinit-timeout", it.getProp("reinit_timeout"), default_timeout); int reinit_tout = conf->getArgPInt("--" + prefix + "-reinit-timeout", it.getProp("reinit_timeout"), mbconf->default_timeout);
ptInitChannel.setTiming(reinit_tout); ptInitChannel.setTiming(reinit_tout);
aftersend_pause = conf->getArgPInt("--" + prefix + "-aftersend-pause", it.getProp("aftersend_pause"), 0); mbconf->aftersend_pause = conf->getArgPInt("--" + prefix + "-aftersend-pause", it.getProp("aftersend_pause"), 0);
vmonit(aftersend_pause); // vmonit(aftersend_pause);
noQueryOptimization = conf->getArgInt("--" + prefix + "-no-query-optimization", it.getProp("no_query_optimization")); mbconf->noQueryOptimization = conf->getArgInt("--" + prefix + "-no-query-optimization", it.getProp("no_query_optimization"));
vmonit(noQueryOptimization); // vmonit(noQueryOptimization);
mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id", it.getProp("reg_from_id")); mbconf->mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id", it.getProp("reg_from_id"));
mbinfo << myname << "(init): mbregFromID=" << mbregFromID << endl; mbinfo << myname << "(init): mbregFromID=" << mbconf->mbregFromID << endl;
vmonit(mbregFromID); // vmonit(mbregFromID);
polltime = conf->getArgPInt("--" + prefix + "-polltime", it.getProp("polltime"), 100); mbconf->polltime = conf->getArgPInt("--" + prefix + "-polltime", it.getProp("polltime"), 100);
vmonit(polltime); // vmonit(polltime);
initPause = conf->getArgPInt("--" + prefix + "-initPause", it.getProp("initPause"), 3000); initPause = conf->getArgPInt("--" + prefix + "-initPause", it.getProp("initPause"), 3000);
sleepPause_msec = conf->getArgPInt("--" + prefix + "-sleepPause-msec", it.getProp("sleepPause"), 10); mbconf->sleepPause_msec = conf->getArgPInt("--" + prefix + "-sleepPause-msec", it.getProp("sleepPause"), 10);
force = conf->getArgInt("--" + prefix + "-force", it.getProp("force")); force = conf->getArgInt("--" + prefix + "-force", it.getProp("force"));
force_out = conf->getArgInt("--" + prefix + "-force-out", it.getProp("force_out")); force_out = conf->getArgInt("--" + prefix + "-force-out", it.getProp("force_out"));
vmonit(force); vmonit(force);
vmonit(force_out); vmonit(force_out);
defaultMBtype = conf->getArg2Param("--" + prefix + "-default-mbtype", it.getProp("default_mbtype"), "rtu"); mbconf->defaultMBtype = conf->getArg2Param("--" + prefix + "-default-mbtype", it.getProp("default_mbtype"), "rtu");
defaultMBaddr = conf->getArg2Param("--" + prefix + "-default-mbaddr", it.getProp("default_mbaddr"), ""); mbconf->defaultMBaddr = conf->getArg2Param("--" + prefix + "-default-mbaddr", it.getProp("default_mbaddr"), "");
mbconf->defaultMBinitOK = conf->getArgPInt("--" + prefix + "-default-mbinit-ok", it.getProp("default_mbinitOK"), 0);
vmonit(defaultMBtype); mbconf->maxQueryCount = conf->getArgPInt("--" + prefix + "-query-max-count", it.getProp("queryMaxCount"), ModbusRTU::MAXDATALEN);
vmonit(defaultMBaddr);
defaultMBinitOK = conf->getArgPInt("--" + prefix + "-default-mbinit-ok", it.getProp("default_mbinitOK"), 0);
maxQueryCount = conf->getArgPInt("--" + prefix + "-query-max-count", it.getProp("queryMaxCount"), ModbusRTU::MAXDATALEN);
vmonit(defaultMBinitOK);
// ********** HEARTBEAT ************* // ********** HEARTBEAT *************
string heart = conf->getArgParam("--" + prefix + "-heartbeat-id", it.getProp("heartbeat_id")); string heart = conf->getArgParam("--" + prefix + "-heartbeat-id", it.getProp("heartbeat_id"));
...@@ -210,29 +198,27 @@ namespace uniset ...@@ -210,29 +198,27 @@ namespace uniset
vmonit(allInitOK); vmonit(allInitOK);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
std::string MBExchange::initPropPrefix( const std::string& def_prop_prefix ) std::string MBExchange::initPropPrefix( const std::string& s_field,
const std::string& def_prop_prefix )
{ {
auto conf = uniset_conf(); auto conf = uniset_conf();
string pp(def_prop_prefix); string pp = def_prop_prefix;
// если задано поле для "фильтрации" // если задано поле для "фильтрации"
// то в качестве префикса используем его // то в качестве префикса используем его
if( !s_field.empty() ) if( !s_field.empty() )
pp = s_field + "_"; pp = s_field + "_";
// если "принудительно" задан префикс // если "принудительно" задан префикс используем его.
// используем его. const string p = "--" + mbconf->prefix + "-set-prop-prefix";
{ const string v = conf->getArgParam(p, "");
string p("--" + prefix + "-set-prop-prefix");
string v = conf->getArgParam(p, "");
if( !v.empty() && v[0] != '-' ) if( !v.empty() && v[0] != '-' )
pp = v; pp = v;
// если параметр всё-таки указан, считаем, что это попытка задать "пустой" префикс // если параметр всё-таки указан, считаем, что это попытка задать "пустой" префикс
else if( findArgParam(p, conf->getArgc(), conf->getArgv()) != -1 ) else if( findArgParam(p, conf->getArgc(), conf->getArgv()) != -1 )
pp = ""; pp = "";
}
return pp; return pp;
} }
...@@ -287,7 +273,7 @@ namespace uniset ...@@ -287,7 +273,7 @@ namespace uniset
bool MBExchange::waitSMReady() bool MBExchange::waitSMReady()
{ {
// waiting for SM is ready... // waiting for SM is ready...
int tout = uniset_conf()->getArgInt("--" + prefix + "-sm-ready-timeout", ""); int tout = uniset_conf()->getArgInt("--" + mbconf->prefix + "-sm-ready-timeout", "");
timeout_t ready_timeout = uniset_conf()->getNCReadyTimeout(); timeout_t ready_timeout = uniset_conf()->getNCReadyTimeout();
if( tout > 0 ) if( tout > 0 )
...@@ -354,67 +340,30 @@ namespace uniset ...@@ -354,67 +340,30 @@ namespace uniset
return UniSetObject::deactivateObject(); return UniSetObject::deactivateObject();
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
void MBExchange::readConfiguration() bool MBExchange::readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec )
{ {
// readconf_ok = false; if( uniset::check_filter(it, mbconf->s_field, mbconf->s_fvalue) )
xmlNode* root = uniset_conf()->getXMLSensorsSection();
if(!root)
{ {
ostringstream err; try
err << myname << "(readConfiguration): не нашли корневого раздела <sensors>";
throw SystemError(err.str());
}
UniXML::iterator it(root);
if( !it.goChildren() )
{ {
mbcrit << myname << "(readConfiguration): раздел <sensors> не содержит секций ?!!\n"; mbconf->initItem(it);
return;
} }
catch( std::exception& ex )
for( ; it.getCurrent(); it.goNext() )
{ {
if( uniset::check_filter(it, s_field, s_fvalue) ) cerr << ex.what() << endl;
initItem(it); std::abort();
} }
// readconf_ok = true;
} }
// ------------------------------------------------------------------------------------------
bool MBExchange::readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec )
{
if( uniset::check_filter(it, s_field, s_fvalue) )
initItem(it);
return true; return true;
} }
// ------------------------------------------------------------------------------------------
MBExchange::DeviceType MBExchange::getDeviceType( const std::string& dtype ) noexcept
{
if( dtype.empty() )
return dtUnknown;
if( dtype == "mtr" || dtype == "MTR" )
return dtMTR;
if( dtype == "rtu" || dtype == "RTU" )
return dtRTU;
if( dtype == "rtu188" || dtype == "RTU188" )
return dtRTU188;
return dtUnknown;
}
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
void MBExchange::initIterators() void MBExchange::initIterators()
{ {
shm->initIterator(itHeartBeat); shm->initIterator(itHeartBeat);
shm->initIterator(itExchangeMode); shm->initIterator(itExchangeMode);
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto d = it1->second; auto d = it1->second;
shm->initIterator(d->resp_it); shm->initIterator(d->resp_it);
...@@ -435,7 +384,7 @@ namespace uniset ...@@ -435,7 +384,7 @@ namespace uniset
} }
} }
for( auto t = thrlist.begin(); t != thrlist.end(); ++t ) for( auto t = mbconf->thrlist.begin(); t != mbconf->thrlist.end(); ++t )
{ {
shm->initIterator(t->ioit); shm->initIterator(t->ioit);
shm->initIterator(t->t_ait); shm->initIterator(t->t_ait);
...@@ -444,7 +393,7 @@ namespace uniset ...@@ -444,7 +393,7 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::initValues() void MBExchange::initValues()
{ {
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto d = it1->second; auto d = it1->second;
...@@ -464,7 +413,7 @@ namespace uniset ...@@ -464,7 +413,7 @@ namespace uniset
} }
} }
for( auto t = thrlist.begin(); t != thrlist.end(); ++t ) for( auto t = mbconf->thrlist.begin(); t != mbconf->thrlist.end(); ++t )
{ {
t->value = shm->localGetValue(t->ioit, t->si.id); t->value = shm->localGetValue(t->ioit, t->si.id);
} }
...@@ -472,7 +421,7 @@ namespace uniset ...@@ -472,7 +421,7 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::isUpdateSM( bool wrFunc, long mdev ) const noexcept bool MBExchange::isUpdateSM( bool wrFunc, long mdev ) const noexcept
{ {
if( exchangeMode == emSkipExchange || mdev == emSkipExchange ) if( exchangeMode == MBConfig::emSkipExchange || mdev == MBConfig::emSkipExchange )
{ {
if( wrFunc ) if( wrFunc )
return true; // данные для посылки, должны обновляться всегда (чтобы быть актуальными, когда режим переключиться обратно..) return true; // данные для посылки, должны обновляться всегда (чтобы быть актуальными, когда режим переключиться обратно..)
...@@ -482,21 +431,21 @@ namespace uniset ...@@ -482,21 +431,21 @@ namespace uniset
return false; return false;
} }
if( wrFunc && (exchangeMode == emReadOnly || mdev == emReadOnly) ) if( wrFunc && (exchangeMode == MBConfig::emReadOnly || mdev == MBConfig::emReadOnly) )
{ {
mblog3 << "(checkUpdateSM):" mblog3 << "(checkUpdateSM):"
<< " skip... mode='emReadOnly' " << endl; << " skip... mode='emReadOnly' " << endl;
return false; return false;
} }
if( !wrFunc && (exchangeMode == emWriteOnly || mdev == emWriteOnly) ) if( !wrFunc && (exchangeMode == MBConfig::emWriteOnly || mdev == MBConfig::emWriteOnly) )
{ {
mblog3 << "(checkUpdateSM):" mblog3 << "(checkUpdateSM):"
<< " skip... mode='emWriteOnly' " << endl; << " skip... mode='emWriteOnly' " << endl;
return false; return false;
} }
if( !wrFunc && (exchangeMode == emSkipSaveToSM || mdev == emSkipSaveToSM) ) if( !wrFunc && (exchangeMode == MBConfig::emSkipSaveToSM || mdev == MBConfig::emSkipSaveToSM) )
{ {
mblog3 << "(checkUpdateSM):" mblog3 << "(checkUpdateSM):"
<< " skip... mode='emSkipSaveToSM' " << endl; << " skip... mode='emSkipSaveToSM' " << endl;
...@@ -508,19 +457,19 @@ namespace uniset ...@@ -508,19 +457,19 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::isPollEnabled( bool wrFunc ) const noexcept bool MBExchange::isPollEnabled( bool wrFunc ) const noexcept
{ {
if( exchangeMode == emWriteOnly && !wrFunc ) if( exchangeMode == MBConfig::emWriteOnly && !wrFunc )
{ {
mblog3 << myname << "(checkPoll): skip.. mode='emWriteOnly'" << endl; mblog3 << myname << "(checkPoll): skip.. mode='emWriteOnly'" << endl;
return false; return false;
} }
if( exchangeMode == emReadOnly && wrFunc ) if( exchangeMode == MBConfig::emReadOnly && wrFunc )
{ {
mblog3 << myname << "(checkPoll): skip.. poll mode='emReadOnly'" << endl; mblog3 << myname << "(checkPoll): skip.. poll mode='emReadOnly'" << endl;
return false; return false;
} }
if( exchangeMode == emSkipExchange ) if( exchangeMode == MBConfig::emSkipExchange )
{ {
mblog3 << myname << "(checkPoll): skip.. poll mode='emSkipExchange'" << endl; mblog3 << myname << "(checkPoll): skip.. poll mode='emSkipExchange'" << endl;
return false; return false;
...@@ -529,7 +478,7 @@ namespace uniset ...@@ -529,7 +478,7 @@ namespace uniset
return true; return true;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::isSafeMode( std::shared_ptr<MBExchange::RTUDevice>& dev ) const noexcept bool MBExchange::isSafeMode( std::shared_ptr<MBConfig::RTUDevice>& dev ) const noexcept
{ {
if( !dev ) if( !dev )
return false; return false;
...@@ -538,173 +487,10 @@ namespace uniset ...@@ -538,173 +487,10 @@ namespace uniset
// то проверяем таймер // то проверяем таймер
// resp_Delay - это задержка на отпускание "пропадание" связи, // resp_Delay - это задержка на отпускание "пропадание" связи,
// поэтому проверка на "0" (0 - связи нет), а значит должен включиться safeMode // поэтому проверка на "0" (0 - связи нет), а значит должен включиться safeMode
if( dev->safeMode == safeResetIfNotRespond ) if( dev->safeMode == MBConfig::safeResetIfNotRespond )
return !dev->resp_Delay.get(); return !dev->resp_Delay.get();
return ( dev->safeMode != safeNone ); return ( dev->safeMode != MBConfig::safeNone );
}
// -----------------------------------------------------------------------------
void MBExchange::printMap( MBExchange::RTUDeviceMap& m )
{
cout << "devices: " << endl;
for( auto it = m.begin(); it != m.end(); ++it )
cout << " " << *(it->second) << endl;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBExchange::RTUDeviceMap& m )
{
os << "devices: " << endl;
for( auto 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_Delay.getOffDelay()
<< " respond_state=" << d.resp_state
<< " respond_invert=" << d.resp_invert
<< " safeMode=" << (MBExchange::SafeMode)d.safeMode
<< endl;
os << " regs: " << endl;
for( const auto& m : d.pollmap )
{
for( const auto& it : * (m.second) )
os << " " << it.second << endl;
}
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::RegInfo* r )
{
return os << (*r);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::RegInfo& r )
{
os << " id=" << r.regID
<< " 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( const auto& s : r.slst )
os << " " << s << endl;
return os;
}
// -----------------------------------------------------------------------------
void MBExchange::rtuQueryOptimization( RTUDeviceMap& dm )
{
mbinfo << myname << "(rtuQueryOptimization): optimization..." << endl;
for( const auto& d : dm )
rtuQueryOptimizationForDevice(d.second);
// printMap(dm);
// assert(false);
}
// -----------------------------------------------------------------------------
void MBExchange::rtuQueryOptimizationForDevice( const std::shared_ptr<RTUDevice>& d )
{
mbinfo << myname << "(rtuQueryOptimizationForDevice): dev addr="
<< ModbusRTU::addr2str(d->mbaddr) << " optimization..." << endl;
for( const auto& m : d->pollmap )
rtuQueryOptimizationForRegMap(m.second);
}
// -----------------------------------------------------------------------------
void MBExchange::rtuQueryOptimizationForRegMap( const std::shared_ptr<RegMap>& regmap )
{
if( regmap->size() <= 1 )
return;
// Вообще в map они уже лежат в нужном порядке, т.е. функция genRegID() гарантирует
// что регистры идущие подряд с одниковой функцией чтения/записи получат подряд идущие RegID.
// так что оптимтизация это просто нахождение мест где RegID идут не подряд...
for( auto it = regmap->begin(); it != regmap->end(); ++it )
{
auto& beg = it->second;
ModbusRTU::RegID regID = beg->regID;
beg->q_count = 1;
beg->q_num = 0;
++it;
// склеиваем регистры идущие подряд
for( ; it != regmap->end(); ++it )
{
if( (it->second->regID - regID) > 1 )
{
// этот регистр должен войти уже в следующий запрос,
// надо вернуть на шаг обратно..
--it;
break;
}
beg->q_count++;
regID = it->second->regID;
it->second->q_num = beg->q_count - 1;
it->second->q_count = 0;
if( beg->q_count >= maxQueryCount )
break;
}
// Корректировка типа функции, в случае необходимости...
if( beg->q_count > 1 && beg->mbfunc == ModbusRTU::fnWriteOutputSingleRegister )
{
mbwarn << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnWriteOutputSingleRegister
<< " <--> func=" << ModbusRTU::fnWriteOutputRegisters
<< " for mbaddr=" << ModbusRTU::addr2str(beg->dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->mbreg);
beg->mbfunc = ModbusRTU::fnWriteOutputRegisters;
}
else if( beg->q_count > 1 && beg->mbfunc == ModbusRTU::fnForceSingleCoil )
{
mbwarn << myname << "(rtuQueryOptimization): "
<< " optimization change func=" << ModbusRTU::fnForceSingleCoil
<< " <--> func=" << ModbusRTU::fnForceMultipleCoils
<< " for mbaddr=" << ModbusRTU::addr2str(beg->dev->mbaddr)
<< " mbreg=" << ModbusRTU::dat2str(beg->mbreg);
beg->mbfunc = ModbusRTU::fnForceMultipleCoils;
}
// надо до внешнего цикла, где будет ++it
// проверить условие.. (т.к. мы во внутреннем цикле итерировались
if( it == regmap->end() )
break;
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBExchange::PList& lst )
std::ostream& MBExchange::print_plist( std::ostream& os, const MBExchange::PList& lst )
{
auto conf = uniset_conf();
os << "[ ";
for( const auto& p : lst )
os << "(" << p.si.id << ")" << conf->oind->getBaseName(conf->oind->getMapName(p.si.id)) << " ";
os << "]";
return os;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::firstInitRegisters() void MBExchange::firstInitRegisters()
...@@ -712,7 +498,7 @@ namespace uniset ...@@ -712,7 +498,7 @@ namespace uniset
// если все вернут TRUE, значит OK. // если все вернут TRUE, значит OK.
allInitOK = true; allInitOK = true;
for( auto it = initRegList.begin(); it != initRegList.end(); ++it ) for( auto it = mbconf->initRegList.begin(); it != mbconf->initRegList.end(); ++it )
{ {
try try
{ {
...@@ -732,8 +518,10 @@ namespace uniset ...@@ -732,8 +518,10 @@ namespace uniset
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::preInitRead( InitList::iterator& p ) bool MBExchange::preInitRead( MBConfig::InitList::iterator& p )
{ {
mbinfo << "init mbreg=" << ModbusRTU::dat2str(p->mbreg) << " initOK=" << p->initOK << endl;
if( p->initOK ) if( p->initOK )
return true; return true;
...@@ -749,10 +537,10 @@ namespace uniset ...@@ -749,10 +537,10 @@ namespace uniset
<< " q_count=" << q_count << " q_count=" << q_count
<< endl; << endl;
if( q_count > maxQueryCount /* ModbusRTU::MAXDATALEN */ ) if( q_count > mbconf->maxQueryCount /* ModbusRTU::MAXDATALEN */ )
{ {
mblog3 << myname << "(preInitRead): count(" << q_count mblog3 << myname << "(preInitRead): count(" << q_count
<< ") > MAXDATALEN(" << maxQueryCount /* ModbusRTU::MAXDATALEN */ << ") > MAXDATALEN(" << mbconf->maxQueryCount /* ModbusRTU::MAXDATALEN */
<< " ..ignore..." << " ..ignore..."
<< endl; << endl;
} }
...@@ -829,7 +617,7 @@ namespace uniset ...@@ -829,7 +617,7 @@ namespace uniset
return p->initOK; return p->initOK;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p ) bool MBExchange::initSMValue( ModbusRTU::ModbusData* data, int count, MBConfig::RSProperty* p )
{ {
using namespace ModbusRTU; using namespace ModbusRTU;
...@@ -968,11 +756,11 @@ namespace uniset ...@@ -968,11 +756,11 @@ namespace uniset
return false; return false;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::pollRTU( std::shared_ptr<RTUDevice>& dev, RegMap::iterator& it ) bool MBExchange::pollRTU( std::shared_ptr<MBConfig::RTUDevice>& dev, MBConfig::RegMap::iterator& it )
{ {
auto p = it->second; auto p = it->second;
if( dev->mode == emSkipExchange ) if( dev->mode == MBConfig::emSkipExchange )
{ {
mblog3 << myname << "(pollRTU): SKIP EXCHANGE (mode=emSkipExchange) " mblog3 << myname << "(pollRTU): SKIP EXCHANGE (mode=emSkipExchange) "
<< " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr) << " mbaddr=" << ModbusRTU::addr2str(dev->mbaddr)
...@@ -992,10 +780,10 @@ namespace uniset ...@@ -992,10 +780,10 @@ namespace uniset
<< " mbval=" << p->mbval << " mbval=" << p->mbval
<< endl; << endl;
if( p->q_count > maxQueryCount /* ModbusRTU::MAXDATALEN */ ) if( p->q_count > mbconf->maxQueryCount /* ModbusRTU::MAXDATALEN */ )
{ {
mblog3 << myname << "(pollRTU): count(" << p->q_count mblog3 << myname << "(pollRTU): count(" << p->q_count
<< ") > MAXDATALEN(" << maxQueryCount /* ModbusRTU::MAXDATALEN */ << ") > MAXDATALEN(" << mbconf->maxQueryCount /* ModbusRTU::MAXDATALEN */
<< " ..ignore..." << " ..ignore..."
<< endl; << endl;
} }
...@@ -1188,7 +976,7 @@ namespace uniset ...@@ -1188,7 +976,7 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::updateSM() void MBExchange::updateSM()
{ {
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto d = it1->second; auto d = it1->second;
...@@ -1232,9 +1020,9 @@ namespace uniset ...@@ -1232,9 +1020,9 @@ namespace uniset
if( !shm->isLocalwork() ) if( !shm->isLocalwork() )
{ {
if( shm->localGetValue(d->safemode_it, d->safemode_id) == d->safemode_value ) if( shm->localGetValue(d->safemode_it, d->safemode_id) == d->safemode_value )
d->safeMode = safeExternalControl; d->safeMode = MBConfig::safeExternalControl;
else else
d->safeMode = safeNone; d->safeMode = MBConfig::safeNone;
} }
} }
catch(IOController_i::NameNotFound& ex) catch(IOController_i::NameNotFound& ex)
...@@ -1278,11 +1066,11 @@ namespace uniset ...@@ -1278,11 +1066,11 @@ namespace uniset
{ {
try try
{ {
if( d->dtype == dtRTU ) if( d->dtype == MBConfig::dtRTU )
updateRTU(it); updateRTU(it);
else if( d->dtype == dtMTR ) else if( d->dtype == MBConfig::dtMTR )
updateMTR(it); updateMTR(it);
else if( d->dtype == dtRTU188 ) else if( d->dtype == MBConfig::dtRTU188 )
updateRTU188(it); updateRTU188(it);
} }
catch(IOController_i::NameNotFound& ex) catch(IOController_i::NameNotFound& ex)
...@@ -1320,7 +1108,7 @@ namespace uniset ...@@ -1320,7 +1108,7 @@ namespace uniset
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::updateRTU( RegMap::iterator& rit ) void MBExchange::updateRTU( MBConfig::RegMap::iterator& rit )
{ {
auto& r = rit->second; auto& r = rit->second;
...@@ -1329,7 +1117,7 @@ namespace uniset ...@@ -1329,7 +1117,7 @@ namespace uniset
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::updateRSProperty( RSProperty* p, bool write_only ) void MBExchange::updateRSProperty( MBConfig::RSProperty* p, bool write_only )
{ {
using namespace ModbusRTU; using namespace ModbusRTU;
auto& r = p->reg->rit->second; auto& r = p->reg->rit->second;
...@@ -1781,7 +1569,7 @@ namespace uniset ...@@ -1781,7 +1569,7 @@ namespace uniset
r->sm_initOK = false; r->sm_initOK = false;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::updateMTR( RegMap::iterator& rit ) void MBExchange::updateMTR( MBConfig::RegMap::iterator& rit )
{ {
auto& r = rit->second; auto& r = rit->second;
...@@ -2118,7 +1906,7 @@ namespace uniset ...@@ -2118,7 +1906,7 @@ namespace uniset
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MBExchange::updateRTU188( RegMap::iterator& rit ) void MBExchange::updateRTU188( MBConfig::RegMap::iterator& rit )
{ {
auto& r = rit->second; auto& r = rit->second;
...@@ -2185,925 +1973,204 @@ namespace uniset ...@@ -2185,925 +1973,204 @@ namespace uniset
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::activateObject()
std::shared_ptr<MBExchange::RTUDevice> MBExchange::addDev( RTUDeviceMap& mp, ModbusRTU::ModbusAddr a, UniXML::iterator& xmlit )
{
auto it = mp.find(a);
if( it != mp.end() )
{ {
string s_dtype(xmlit.getProp(prop_prefix + "mbtype")); // блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
if( s_dtype.empty() ) // см. sysCommand()
s_dtype = defaultMBtype;
DeviceType dtype = getDeviceType(s_dtype);
if( it->second->dtype != dtype )
{ {
mbcrit << myname << "(addDev): OTHER mbtype=" << dtype << " for " << xmlit.getProp("name") setProcActive(false);
<< ". Already used devtype=" << it->second->dtype uniset::uniset_rwmutex_rlock l(mutex_start);
<< " for mbaddr=" << ModbusRTU::addr2str(it->second->mbaddr) UniSetObject::activateObject();
<< endl;
return 0;
}
mbinfo << myname << "(addDev): device for addr=" << ModbusRTU::addr2str(a)
<< " already added. Ignore device params for " << xmlit.getProp("name") << " ..." << endl;
return it->second;
}
auto d = make_shared<MBExchange::RTUDevice>(); if( !shm->isLocalwork() )
d->mbaddr = a; MBConfig::rtuQueryOptimization(mbconf->devices, mbconf->maxQueryCount);
if( !initRTUDevice(d, xmlit) ) initIterators();
{ setProcActive(true);
d.reset();
return 0;
} }
mp.insert( std::make_pair(a, d) ); return true;
return d;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
std::shared_ptr<MBExchange::RegInfo> MBExchange::addReg( std::shared_ptr<RegMap>& mp, ModbusRTU::RegID regID, ModbusRTU::ModbusData r, void MBExchange::sysCommand( const uniset::SystemMessage* sm )
UniXML::iterator& xmlit, std::shared_ptr<MBExchange::RTUDevice> dev )
{ {
auto it = mp->find(regID); switch( sm->command )
if( it != mp->end() )
{ {
if( !it->second->dev ) case SystemMessage::StartUp:
{ {
mbcrit << myname << "(addReg): for " << xmlit.getProp("name") if( !logserv_host.empty() && logserv_port != 0 && !logserv->isRunning() )
<< " dev=0!!!! " << endl;
return 0;
}
if( it->second->dev->dtype != dev->dtype )
{ {
mbcrit << myname << "(addReg): OTHER mbtype=" << dev->dtype << " for " << xmlit.getProp("name") mbinfo << myname << "(init): run log server " << logserv_host << ":" << logserv_port << endl;
<< ". Already used devtype=" << it->second->dev->dtype << " for " << it->second->dev << endl; logserv->async_run(logserv_host, logserv_port);
return 0;
} }
mbinfo << myname << "(addReg): reg=" << ModbusRTU::dat2str(r) if( mbconf->devices.empty() )
<< "(id=" << regID << ")" {
<< " already added for " << (*it->second) mbcrit << myname << "(sysCommand): ************* ITEM MAP EMPTY! terminated... *************" << endl << flush;
<< " Ignore register params for " << xmlit.getProp("name") << " ..." << endl; // std::terminate();
uterminate();
it->second->rit = it; return;
return it->second;
} }
auto ri = make_shared<MBExchange::RegInfo>(); mbinfo << myname << "(sysCommand): device map size= " << mbconf->devices.size() << endl;
if( !initRegInfo(ri, xmlit, dev) ) if( !shm->isLocalwork() )
return 0; mbconf->initDeviceList(uniset_conf()->getConfXML());
ri->mbreg = r; if( !waitSMReady() )
ri->regID = regID; {
if( !canceled )
uterminate();
mp->insert( std::make_pair(regID, ri) ); return;
ri->rit = mp->find(regID); }
mbinfo << myname << "(addReg): reg=" << ModbusRTU::dat2str(r) << "(id=" << regID << ")" << endl; // подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
return ri; while( !isProcActive() && !ptAct.checkTime() )
}
// ------------------------------------------------------------------------------------------
MBExchange::RSProperty* MBExchange::addProp( PList& plist, RSProperty&& p )
{
for( auto&& it : plist )
{ {
if( it.si.id == p.si.id && it.si.node == p.si.node ) cout << myname << "(sysCommand): wait activate..." << endl;
return &it; msleep(300);
}
plist.emplace_back( std::move(p) ); if( isProcActive() )
auto it = plist.end(); break;
--it;
return &(*it);
} }
// ------------------------------------------------------------------------------------------
bool MBExchange::initRSProperty( RSProperty& p, UniXML::iterator& it )
{
if( !IOBase::initItem(&p, it, shm, prop_prefix, false, mblog, myname) )
return false;
// проверяем не пороговый ли это датчик (т.е. не связанный с обменом) if( !isProcActive() )
// тогда заносим его в отдельный список
if( p.t_ai != DefaultObjectId )
{ {
thrlist.emplace_back( std::move(p) ); mbcrit << myname << "(sysCommand): ************* don`t activate?! ************" << endl << flush;
return true; uterminate();
return;
} }
string sbit(IOBase::initProp(it, "nbit", prop_prefix, false));
if( !sbit.empty() )
{
p.nbit = uniset::uni_atoi(sbit.c_str());
if( p.nbit < 0 || p.nbit >= ModbusRTU::BitsPerData )
{ {
mbcrit << myname << "(initRSProperty): BAD nbit=" << (int)p.nbit uniset::uniset_rwmutex_rlock l(mutex_start);
<< ". (0 >= nbit < " << ModbusRTU::BitsPerData << ")." << endl; askSensors(UniversalIO::UIONotify);
return false; initOutput();
}
} }
if( p.nbit > 0 && initValues();
( p.stype == UniversalIO::AI || updateSM();
p.stype == UniversalIO::AO ) ) askTimer(tmExchange, mbconf->polltime);
{ break;
mbwarn << "(initRSProperty): (ignore) uncorrect param`s nbit!=0(" << p.nbit << ")"
<< " for iotype=" << p.stype << " for " << it.getProp("name") << endl;
} }
string sbyte(IOBase::initProp(it, "nbyte", prop_prefix, false) ); case SystemMessage::FoldUp:
case SystemMessage::Finish:
askSensors(UniversalIO::UIODontNotify);
break;
if( !sbyte.empty() ) case SystemMessage::WatchDog:
{ {
p.nbyte = uniset::uni_atoi(sbyte.c_str()); // ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. MBExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBExchange)
if( shm->isLocalwork() )
break;
askSensors(UniversalIO::UIONotify);
initOutput();
initValues();
if( p.nbyte > VTypes::Byte::bsize ) if( !force )
{ {
mbwarn << myname << "(initRSProperty): BAD nbyte=" << p.nbyte force = true;
<< ". (0 >= nbyte < " << VTypes::Byte::bsize << ")." << endl; poll();
return false; force = false;
} }
} }
break;
string vt( IOBase::initProp(it, "vtype", prop_prefix, false) ); case SystemMessage::LogRotate:
{
mblogany << myname << "(sysCommand): logRotate" << std::endl;
string fname = mblog->getLogFile();
if( vt.empty() ) if( !fname.empty() )
{ {
p.rnum = VTypes::wsize(VTypes::vtUnknown); mblog->logFile(fname, true);
p.vType = VTypes::vtUnknown; mblogany << myname << "(sysCommand): ***************** mblog LOG ROTATE *****************" << std::endl;
} }
else }
{ break;
VTypes::VType v(VTypes::str2type(vt));
if( v == VTypes::vtUnknown ) case SystemMessage::ReConfiguration:
{ {
mbcrit << myname << "(initRSProperty): Unknown tcp_vtype='" << vt << "' for " mblogany << myname << "(sysCommand): reconfig" << std::endl;
<< it.getProp("name") reconfigure(uniset_conf()->getConfFileName());
<< endl;
return false;
} }
break;
p.vType = v; default:
p.rnum = VTypes::wsize(v); break;
} }
return true;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
bool MBExchange::initRegInfo( std::shared_ptr<RegInfo>& r, UniXML::iterator& it, std::shared_ptr<MBExchange::RTUDevice>& dev ) bool MBExchange::reconfigure( const std::string& confile )
{ {
r->dev = dev; mbinfo << myname << ": reconfigure from " << confile << endl;
r->mbval = IOBase::initIntProp(it, "default", prop_prefix, false);
if( dev->dtype == MBExchange::dtRTU ) uniset::uniset_rwmutex_wrlock lock(mutex_conf);
{
// mblog.info() << myname << "(initRegInfo): init RTU.."
}
else if( dev->dtype == MBExchange::dtMTR )
{
// only for MTR
if( !initMTRitem(it, r) )
return false;
}
else if( dev->dtype == MBExchange::dtRTU188 )
{
// only for RTU188
if( !initRTU188item(it, r) )
return false;
UniversalIO::IOType t = uniset::getIOType(IOBase::initProp(it, "iotype", prop_prefix, false)); auto oldConf = mbconf;
r->mbreg = RTUStorage::getRegister(r->rtuJack, r->rtuChan, t);
r->mbfunc = RTUStorage::getFunction(r->rtuJack, r->rtuChan, t);
// т.к. с RTU188 свой обмен std::shared_ptr<MBConfig> newConf;
// mbreg и mbfunc поля не используются
return true;
} try
else
{ {
mbcrit << myname << "(initRegInfo): Unknown mbtype='" << dev->dtype auto xml = make_shared<UniXML>(confile);
<< "' for " << it.getProp("name") << endl;
return false;
}
if( mbregFromID ) string conf_name(uniset_conf()->getArgParam("--" + mbconf->prefix + "-confnode", myname));
{ xmlNode* newCnode = xml->findNode(xml->getFirstNode(), conf_name);
if( it.getProp("id").empty() )
r->mbreg = uniset_conf()->getSensorID(it.getProp("name"));
else
r->mbreg = it.getIntProp("id");
}
else
{
string sr( IOBase::initProp(it, "mbreg", prop_prefix, false) );
if( sr.empty() ) if( newCnode == NULL )
{ {
mbcrit << myname << "(initItem): Unknown 'mbreg' for " << it.getProp("name") << endl; mbcrit << myname << "(reconfigure): reload config from '" << confile
<< "' FAILED: not found conf node '" << conf_name
<< "'" << endl;
return false; return false;
} }
r->mbreg = ModbusRTU::str2mbData(sr); newConf = make_shared<MBConfig>(mbconf->conf, newCnode, mbconf->shm);
newConf->cloneParams(mbconf);
newConf->loadConfig(xml, nullptr);
MBConfig::rtuQueryOptimization(newConf->devices, newConf->maxQueryCount);
if( newConf->devices.empty() )
{
mbcrit << myname << "(reconfigure): reload config from '" << confile << "' FAILED: empty devices list" << std::endl;
return false;
} }
r->mbfunc = ModbusRTU::fnUnknown; mbconf = newConf;
string f( IOBase::initProp(it, "mbfunc", prop_prefix, false) );
if( !f.empty() ) if( !shm->isLocalwork() )
{ initIterators();
r->mbfunc = (ModbusRTU::SlaveFunctionCode)uniset::uni_atoi(f.c_str());
if( r->mbfunc == ModbusRTU::fnUnknown ) allInitOK = false;
{ initOutput();
mbcrit << myname << "(initRegInfo): Unknown mbfunc ='" << f initValues();
<< "' for " << it.getProp("name") << endl; updateSM();
return false; ptInitChannel.reset();
ptReopen.reset();
return true;
} }
catch( std::exception& ex )
{
mbcrit << myname << "(sysCommand): reload config from '" << confile << "' FAILED: " << ex.what() << std::endl;
} }
return true; mbconf = oldConf;
return false;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
bool MBExchange::initRTUDevice( std::shared_ptr<RTUDevice>& d, UniXML::iterator& it ) void MBExchange::initOutput()
{
string mbtype(IOBase::initProp(it, "mbtype", prop_prefix, false));
if(mbtype.empty())
mbtype = defaultMBtype;
d->dtype = getDeviceType(mbtype);
if( d->dtype == dtUnknown )
{
mbcrit << myname << "(initRTUDevice): Unknown tcp_mbtype='" << mbtype << "'"
<< ". Use: rtu "
<< " for " << it.getProp("name") << endl;
return false;
}
string addr( IOBase::initProp(it, "mbaddr", prop_prefix, false) );
if( addr.empty() )
addr = defaultMBaddr;
if( addr.empty() )
{
mbcrit << myname << "(initRTUDevice): Unknown mbaddr for " << it.getProp("name") << endl;
return false;
}
d->mbaddr = ModbusRTU::str2mbAddr(addr);
if( d->dtype == MBExchange::dtRTU188 )
{
if( !d->rtu188 )
d->rtu188 = make_shared<RTUStorage>(d->mbaddr);
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initItem( UniXML::iterator& it )
{
RSProperty p;
if( !initRSProperty(p, it) )
return false;
if( p.t_ai != DefaultObjectId ) // пороговые датчики в список обмена вносить не надо.
return true;
string addr( IOBase::initProp(it, "mbaddr", prop_prefix, false) );
if( addr.empty() )
addr = defaultMBaddr;
if( addr.empty() )
{
mbcrit << myname << "(initItem): Unknown mbaddr(" << IOBase::initProp(it, "mbaddr", prop_prefix, false) << ")='" << addr << "' for " << it.getProp("name") << endl;
return false;
}
ModbusRTU::ModbusAddr mbaddr = ModbusRTU::str2mbAddr(addr);
auto dev = addDev(devices, mbaddr, it);
if( !dev )
{
mbcrit << myname << "(initItem): " << it.getProp("name") << " CAN`T ADD for polling!" << endl;
return false;
}
ModbusRTU::ModbusData mbreg = 0;
int fn = IOBase::initIntProp(it, "mbfunc", prop_prefix, false);
if( dev->dtype == dtRTU188 )
{
auto r_tmp = make_shared<RegInfo>();
if( !initRTU188item(it, r_tmp) )
{
mbcrit << myname << "(initItem): init RTU188 failed for " << it.getProp("name") << endl;
r_tmp.reset();
return false;
}
mbreg = RTUStorage::getRegister(r_tmp->rtuJack, r_tmp->rtuChan, p.stype);
fn = RTUStorage::getFunction(r_tmp->rtuJack, r_tmp->rtuChan, p.stype);
}
else
{
if( mbregFromID )
mbreg = p.si.id; // conf->getSensorID(it.getProp("name"));
else
{
string reg( IOBase::initProp(it, "mbreg", prop_prefix, false) );
if( reg.empty() )
{
mbcrit << myname << "(initItem): unknown mbreg(" << prop_prefix << ") for " << it.getProp("name") << endl;
return false;
}
mbreg = ModbusRTU::str2mbData(reg);
}
if( p.nbit != -1 )
{
if( fn == ModbusRTU::fnReadCoilStatus || fn == ModbusRTU::fnReadInputStatus )
{
mbcrit << myname << "(initItem): MISMATCHED CONFIGURATION! nbit=" << (int)p.nbit << " func=" << fn
<< " for " << it.getProp("name") << endl;
return false;
}
}
}
/*! приоритет опроса:
* 1...n - задаёт "частоту" опроса. Т.е. каждые 1...n циклов
*/
size_t pollfactor = IOBase::initIntProp(it, "pollfactor", prop_prefix, false, 0);
std::shared_ptr<RegMap> rmap;
auto rit = dev->pollmap.find(pollfactor);
if( rit == dev->pollmap.end() )
{
rmap = make_shared<RegMap>();
dev->pollmap.emplace(pollfactor, rmap);
}
else
rmap = rit->second;
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
ModbusRTU::RegID rID = ModbusRTU::genRegID(mbreg, fn);
auto ri = addReg(rmap, rID, mbreg, it, dev);
if( dev->dtype == dtMTR )
{
p.rnum = MTR::wsize(ri->mtrType);
if( p.rnum <= 0 )
{
mbcrit << 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 )
{
auto conf = uniset_conf();
ostringstream sl;
sl << "[ ";
for( const auto& i : ri->slst )
sl << ORepHelpers::getShortName(conf->oind->getMapName(i.si.id)) << ",";
sl << "]";
mbcrit << myname << "(initItem): FAILED! Sharing SAVE (not bit saving) to "
<< " tcp_mbreg=" << ModbusRTU::dat2str(ri->mbreg) << "(" << (int)ri->mbreg << ")"
<< " conflict with sensors " << sl.str() << endl;
std::abort(); // ABORT PROGRAM!!!!
return false;
}
if( p.nbit >= 0 && ri->slst.size() == 1 )
{
auto it2 = ri->slst.begin();
if( it2->nbit < 0 )
{
mbcrit << myname << "(initItem): FAILED! Sharing SAVE (mbreg="
<< ModbusRTU::dat2str(ri->mbreg) << "(" << (int)ri->mbreg << ") already used)!"
<< " IGNORE --> " << it.getProp("name") << endl;
std::abort(); // ABORT PROGRAM!!!!
return false;
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri->sm_initOK = IOBase::initIntProp(it, "sm_initOK", prop_prefix, false);
ri->mb_initOK = true;
}
else
{
ri->mb_initOK = defaultMBinitOK;
ri->sm_initOK = false;
}
RSProperty* p1 = addProp(ri->slst, std::move(p) );
if( !p1 )
return false;
p1->reg = ri;
if( p1->rnum > 1 )
{
ri->q_count = p1->rnum;
ri->q_num = 1;
for( auto i = 1; i < p1->rnum; i++ )
{
ModbusRTU::RegID id1 = ModbusRTU::genRegID(mbreg + i, ri->mbfunc);
auto r = addReg(rmap, id1, mbreg + i, it, dev);
r->q_num = i + 1;
r->q_count = 1;
r->mbfunc = ri->mbfunc;
r->mb_initOK = defaultMBinitOK;
r->sm_initOK = false;
if( ModbusRTU::isWriteFunction(ri->mbfunc) )
{
// Если занимает несколько регистров, а указана функция записи "одного",
// то это ошибка..
if( ri->mbfunc != ModbusRTU::fnWriteOutputRegisters &&
ri->mbfunc != ModbusRTU::fnForceMultipleCoils )
{
mbcrit << 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 = IOBase::initIntProp(it, "preinit", prop_prefix, false);
if( need_init && ModbusRTU::isWriteFunction(ri->mbfunc) )
{
InitRegInfo ii;
ii.p = std::move(p);
ii.dev = dev;
ii.ri = ri;
string s_reg(IOBase::initProp(it, "init_mbreg", prop_prefix, false));
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)uniset::uni_atoi(s_mbfunc);
if( ii.mbfunc == ModbusRTU::fnUnknown )
{
mbcrit << 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.emplace_back( std::move(ii) );
ri->mb_initOK = false;
ri->sm_initOK = false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initMTRitem( UniXML::iterator& it, std::shared_ptr<RegInfo>& p )
{
p->mtrType = MTR::str2type(it.getProp(prop_prefix + "mtrtype"));
if( p->mtrType == MTR::mtUnknown )
{
mbcrit << myname << "(readMTRItem): Unknown mtrtype '"
<< it.getProp(prop_prefix + "mtrtype")
<< "' for " << it.getProp("name") << endl;
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------
bool MBExchange::initRTU188item( UniXML::iterator& it, std::shared_ptr<RegInfo>& p )
{
string jack(IOBase::initProp(it, "jakc", prop_prefix, false));
string chan(IOBase::initProp(it, "channel", prop_prefix, false));
if( jack.empty() )
{
mbcrit << myname << "(readRTU188Item): Unknown " << prop_prefix << "jack='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuJack = RTUStorage::s2j(jack);
if( p->rtuJack == RTUStorage::nUnknown )
{
mbcrit << myname << "(readRTU188Item): Unknown " << prop_prefix << "jack=" << jack
<< " for " << it.getProp("name") << endl;
return false;
}
if( chan.empty() )
{
mbcrit << myname << "(readRTU188Item): Unknown channel='' "
<< " for " << it.getProp("name") << endl;
return false;
}
p->rtuChan = uniset::uni_atoi(chan);
mblog2 << myname << "(readRTU188Item): add jack='" << jack << "'"
<< " channel='" << p->rtuChan << "'" << endl;
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=" << (int)p.nbit
<< " nbyte=" << p.nbyte
<< " rnum=" << p.rnum
<< " safeval=" << p.safeval
<< " invert=" << p.invert;
if( p.stype == UniversalIO::AI || p.stype == UniversalIO::AO )
{
os << p.cal
<< " cdiagram=" << ( p.cdiagram ? "yes" : "no" );
}
return os;
}
// -----------------------------------------------------------------------------
void MBExchange::initDeviceList()
{
auto conf = uniset_conf();
xmlNode* respNode = 0;
const std::shared_ptr<UniXML> xml = conf->getConfXML();
if( xml )
respNode = xml->extFindNode(cnode, 1, 1, "DeviceList");
if( respNode )
{
UniXML::iterator it1(respNode);
if( it1.goChildren() )
{
for(; it1.getCurrent(); it1.goNext() )
{
ModbusRTU::ModbusAddr a = ModbusRTU::str2mbAddr(it1.getProp("addr"));
initDeviceInfo(devices, a, it1);
}
}
else
mbwarn << myname << "(init): <DeviceList> empty section..." << endl;
}
else
mbwarn << myname << "(init): <DeviceList> not found..." << endl;
}
// -----------------------------------------------------------------------------
bool MBExchange::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it )
{
auto d = m.find(a);
if( d == m.end() )
{
mbwarn << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
auto& dev = d->second;
dev->ask_every_reg = it.getIntProp("ask_every_reg");
mbinfo << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a)
<< " ask_every_reg=" << dev->ask_every_reg << endl;
string s(it.getProp("respondSensor"));
if( !s.empty() )
{
dev->resp_id = uniset_conf()->getSensorID(s);
if( dev->resp_id == DefaultObjectId )
{
mbinfo << myname << "(initDeviceInfo): not found ID for respondSensor=" << s << endl;
return false;
}
}
auto conf = uniset_conf();
string mod(it.getProp("modeSensor"));
if( !mod.empty() )
{
dev->mode_id = conf->getSensorID(mod);
if( dev->mode_id == DefaultObjectId )
{
mbcrit << myname << "(initDeviceInfo): not found ID for modeSensor=" << mod << endl;
return false;
}
UniversalIO::IOType m_iotype = conf->getIOType(dev->mode_id);
if( m_iotype != UniversalIO::AI )
{
mbcrit << myname << "(initDeviceInfo): modeSensor='" << mod << "' must be 'AI'" << endl;
return false;
}
}
// сперва проверим не задан ли режим "safemodeResetIfNotRespond"
if( it.getIntProp("safemodeResetIfNotRespond") )
dev->safeMode = MBExchange::safeResetIfNotRespond;
// потом проверим датчик для "safeExternalControl"
string safemode = it.getProp("safemodeSensor");
if( !safemode.empty() )
{
dev->safemode_id = conf->getSensorID(safemode);
if( dev->safemode_id == DefaultObjectId )
{
mbcrit << myname << "(initDeviceInfo): not found ID for safemodeSensor=" << safemode << endl;
return false;
}
string safemodeValue(it.getProp("safemodeValue"));
if( !safemodeValue.empty() )
dev->safemode_value = uni_atoi(safemodeValue);
dev->safeMode = MBExchange::safeExternalControl;
}
mbinfo << myname << "(initDeviceInfo): add addr=" << ModbusRTU::addr2str(a) << endl;
int tout = it.getPIntProp("timeout", default_timeout );
dev->resp_Delay.set(0, tout);
dev->resp_invert = it.getIntProp("invert");
dev->resp_force = it.getIntProp("force");
int init_tout = it.getPIntProp("respondInitTimeout", tout);
dev->resp_ptInit.setTiming(init_tout);
return true;
}
// -----------------------------------------------------------------------------
bool MBExchange::activateObject()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
setProcActive(false);
uniset::uniset_rwmutex_rlock l(mutex_start);
UniSetObject::activateObject();
if( !shm->isLocalwork() )
rtuQueryOptimization(devices);
initIterators();
setProcActive(true);
}
return true;
}
// ------------------------------------------------------------------------------------------
void MBExchange::sysCommand( const uniset::SystemMessage* sm )
{
switch( sm->command )
{
case SystemMessage::StartUp:
{
if( !logserv_host.empty() && logserv_port != 0 && !logserv->isRunning() )
{
mbinfo << myname << "(init): run log server " << logserv_host << ":" << logserv_port << endl;
logserv->async_run(logserv_host, logserv_port);
}
if( devices.empty() )
{
mbcrit << myname << "(sysCommand): ************* ITEM MAP EMPTY! terminated... *************" << endl << flush;
// std::terminate();
uterminate();
return;
}
mbinfo << myname << "(sysCommand): device map size= " << devices.size() << endl;
if( !shm->isLocalwork() )
initDeviceList();
if( !waitSMReady() )
{
if( !canceled )
uterminate();
return;
}
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep(initPause);
PassiveTimer ptAct(activateTimeout);
while( !isProcActive() && !ptAct.checkTime() )
{
cout << myname << "(sysCommand): wait activate..." << endl;
msleep(300);
if( isProcActive() )
break;
}
if( !isProcActive() )
{
mbcrit << myname << "(sysCommand): ************* don`t activate?! ************" << endl << flush;
uterminate();
return;
}
{
uniset::uniset_rwmutex_rlock l(mutex_start);
askSensors(UniversalIO::UIONotify);
initOutput();
}
initValues();
updateSM();
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();
initValues();
if( !force )
{
force = true;
poll();
force = false;
}
}
break;
case SystemMessage::LogRotate:
{
mblogany << myname << "(sysCommand): logRotate" << std::endl;
string fname = mblog->getLogFile();
if( !fname.empty() )
{
mblog->logFile(fname, true);
mblogany << myname << "(sysCommand): ***************** mblog LOG ROTATE *****************" << std::endl;
}
}
break;
default:
break;
}
}
// ------------------------------------------------------------------------------------------
void MBExchange::initOutput()
{ {
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
...@@ -3136,7 +2203,7 @@ namespace uniset ...@@ -3136,7 +2203,7 @@ namespace uniset
mbwarn << myname << "(askSensors): 'sidExchangeMode' catch..." << std::endl; mbwarn << myname << "(askSensors): 'sidExchangeMode' catch..." << std::endl;
} }
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto d = it1->second; auto d = it1->second;
...@@ -3202,7 +2269,7 @@ namespace uniset ...@@ -3202,7 +2269,7 @@ namespace uniset
//return; // этот датчик может встречаться и в списке обмена.. поэтому делать return нельзя. //return; // этот датчик может встречаться и в списке обмена.. поэтому делать return нельзя.
} }
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto& d(it1->second); auto& d(it1->second);
...@@ -3212,9 +2279,9 @@ namespace uniset ...@@ -3212,9 +2279,9 @@ namespace uniset
if( sm->id == d->safemode_id ) if( sm->id == d->safemode_id )
{ {
if( sm->value == d->safemode_value ) if( sm->value == d->safemode_value )
d->safeMode = safeExternalControl; d->safeMode = MBConfig::safeExternalControl;
else else
d->safeMode = safeNone; d->safeMode = MBConfig::safeNone;
} }
if( force_out ) if( force_out )
...@@ -3264,6 +2331,8 @@ namespace uniset ...@@ -3264,6 +2331,8 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::poll() bool MBExchange::poll()
{ {
uniset::uniset_rwmutex_rlock lock(mutex_conf);
if( !mb ) if( !mb )
{ {
mb = initMB(false); mb = initMB(false);
...@@ -3277,7 +2346,7 @@ namespace uniset ...@@ -3277,7 +2346,7 @@ namespace uniset
if( !mb ) if( !mb )
return false; return false;
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
it1->second->resp_ptInit.reset(); it1->second->resp_ptInit.reset();
} }
...@@ -3290,11 +2359,11 @@ namespace uniset ...@@ -3290,11 +2359,11 @@ namespace uniset
ncycle++; ncycle++;
bool allNotRespond = true; bool allNotRespond = true;
for( auto it1 = devices.begin(); it1 != devices.end(); ++it1 ) for( auto it1 = mbconf->devices.begin(); it1 != mbconf->devices.end(); ++it1 )
{ {
auto d(it1->second); auto d(it1->second);
if( d->mode_id != DefaultObjectId && d->mode == emSkipExchange ) if( d->mode_id != DefaultObjectId && d->mode == MBConfig::emSkipExchange )
continue; continue;
mblog3 << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr) mblog3 << myname << "(poll): ask addr=" << ModbusRTU::addr2str(d->mbaddr)
...@@ -3314,12 +2383,12 @@ namespace uniset ...@@ -3314,12 +2383,12 @@ namespace uniset
if( !isProcActive() ) if( !isProcActive() )
return false; return false;
if( exchangeMode == emSkipExchange ) if( exchangeMode == MBConfig::emSkipExchange )
continue; continue;
try try
{ {
if( d->dtype == MBExchange::dtRTU || d->dtype == MBExchange::dtMTR ) if( d->dtype == MBConfig::dtRTU || d->dtype == MBConfig::dtMTR )
{ {
if( pollRTU(d, it) ) if( pollRTU(d, it) )
{ {
...@@ -3333,7 +2402,7 @@ namespace uniset ...@@ -3333,7 +2402,7 @@ namespace uniset
mblog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr) mblog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg) << " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; << " for sensors: ";
print_plist(mblog->level3(), it->second->slst) mbconf->print_plist( (*mblog)(Debug::LEVEL3), it->second->slst)
<< endl << " err: " << ex << endl; << endl << " err: " << ex << endl;
if( ex.err == ModbusRTU::erTimeOut && !d->ask_every_reg ) if( ex.err == ModbusRTU::erTimeOut && !d->ask_every_reg )
...@@ -3369,7 +2438,7 @@ namespace uniset ...@@ -3369,7 +2438,7 @@ namespace uniset
updateSM(); updateSM();
// check thresholds // check thresholds
for( auto t = thrlist.begin(); t != thrlist.end(); ++t ) for( auto t = mbconf->thrlist.begin(); t != mbconf->thrlist.end(); ++t )
{ {
if( !isProcActive() ) if( !isProcActive() )
return false; return false;
...@@ -3377,10 +2446,10 @@ namespace uniset ...@@ -3377,10 +2446,10 @@ namespace uniset
IOBase::processingThreshold(&(*t), shm, force); IOBase::processingThreshold(&(*t), shm, force);
} }
if( trReopen.hi(allNotRespond && exchangeMode != emSkipExchange) ) if( trReopen.hi(allNotRespond && exchangeMode != MBConfig::emSkipExchange) )
ptReopen.reset(); ptReopen.reset();
if( allNotRespond && exchangeMode != emSkipExchange && ptReopen.checkTime() ) if( allNotRespond && exchangeMode != MBConfig::emSkipExchange && ptReopen.checkTime() )
{ {
mbwarn << myname << ": REOPEN timeout..(" << ptReopen.getInterval() << ")" << endl; mbwarn << myname << ": REOPEN timeout..(" << ptReopen.getInterval() << ")" << endl;
...@@ -3388,39 +2457,14 @@ namespace uniset ...@@ -3388,39 +2457,14 @@ namespace uniset
ptReopen.reset(); ptReopen.reset();
} }
// printMap(rmap);
return !allNotRespond; return !allNotRespond;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool MBExchange::RTUDevice::checkRespond( std::shared_ptr<DebugStream>& mblog )
{
bool prev = resp_state;
resp_state = resp_Delay.check( prev_numreply != numreply ) && numreply != 0;
mblog4 << "(checkRespond): addr=" << ModbusRTU::addr2str(mbaddr)
<< " respond_id=" << resp_id
<< " state=" << resp_state
<< " check=" << (prev_numreply != numreply)
<< " delay_check=" << resp_Delay.get()
<< " [ timeout=" << resp_Delay.getOffDelay()
<< " numreply=" << numreply
<< " prev_numreply=" << prev_numreply
<< " resp_ptInit=" << resp_ptInit.checkTime()
<< " ]"
<< endl;
// если только что прошла "инициализация" возвращаем true
// чтобы датчик в SM обновился..
if( trInitOK.hi(resp_ptInit.checkTime()) )
return true;
return ((prev != resp_state || resp_force ) && trInitOK.get() );
}
// -----------------------------------------------------------------------------
void MBExchange::updateRespondSensors() void MBExchange::updateRespondSensors()
{ {
for( const auto& it1 : devices ) uniset::uniset_rwmutex_rlock lock(mutex_conf);
for( const auto& it1 : mbconf->devices )
{ {
auto d(it1.second); auto d(it1.second);
...@@ -3480,47 +2524,8 @@ namespace uniset ...@@ -3480,47 +2524,8 @@ namespace uniset
mbcrit << myname << "(execute): catch: " << ex.what() << endl; mbcrit << myname << "(execute): catch: " << ex.what() << endl;
} }
msleep(polltime); msleep(mbconf->polltime);
}
} }
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, const MBExchange::ExchangeMode& em )
{
if( em == MBExchange::emNone )
return os << "emNone";
if( em == MBExchange::emWriteOnly )
return os << "emWriteOnly";
if( em == MBExchange::emReadOnly )
return os << "emReadOnly";
if( em == MBExchange::emSkipSaveToSM )
return os << "emSkipSaveToSM";
if( em == MBExchange::emSkipExchange )
return os << "emSkipExchange";
return os;
}
// -----------------------------------------------------------------------------
std::string to_string( const MBExchange::SafeMode& m )
{
if( m == MBExchange::safeNone )
return "safeNone";
if( m == MBExchange::safeResetIfNotRespond )
return "safeResetIfNotRespond";
if( m == MBExchange::safeExternalControl )
return "safeExternalControl";
return "";
}
ostream& operator<<( ostream& os, const MBExchange::SafeMode& m )
{
return os << to_string(m);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
uniset::SimpleInfo* MBExchange::getInfo( const char* userparam ) uniset::SimpleInfo* MBExchange::getInfo( const char* userparam )
...@@ -3541,27 +2546,11 @@ namespace uniset ...@@ -3541,27 +2546,11 @@ namespace uniset
inf << "Devices: " << endl; inf << "Devices: " << endl;
for( const auto& it : devices ) for( const auto& it : mbconf->devices )
inf << " " << it.second->getShortInfo() << endl; inf << " " << it.second->getShortInfo() << endl;
i->info = inf.str().c_str(); i->info = inf.str().c_str();
return i._retn(); return i._retn();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
std::string MBExchange::RTUDevice::getShortInfo() const
{
ostringstream s;
s << "mbaddr=" << ModbusRTU::addr2str(mbaddr) << ":"
<< " resp_state=" << resp_state
<< " (resp_id=" << resp_id << " resp_force=" << resp_force
<< " resp_invert=" << resp_invert
<< " numreply=" << numreply
<< " timeout=" << resp_Delay.getOffDelay()
<< " type=" << dtype
<< " ask_every_reg=" << ask_every_reg
<< ")" << endl;
return s.str();
}
// ----------------------------------------------------------------------------
} // end of namespace uniset } // end of namespace uniset
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "LogServer.h" #include "LogServer.h"
#include "LogAgregator.h" #include "LogAgregator.h"
#include "VMonitor.h" #include "VMonitor.h"
#include "MBConfig.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#ifndef vmonit #ifndef vmonit
#define vmonit( var ) vmon.add( #var, var ) #define vmonit( var ) vmon.add( #var, var )
...@@ -63,170 +64,6 @@ namespace uniset ...@@ -63,170 +64,6 @@ namespace uniset
/*! глобальная функция для вывода help-а */ /*! глобальная функция для вывода help-а */
static void help_print( int argc, const char* const* argv ); static void help_print( int argc, const char* const* argv );
/*! Режимы работы процесса обмена */
enum ExchangeMode
{
emNone = 0, /*!< нормальная работа (по умолчанию) */
emWriteOnly = 1, /*!< "только посылка данных" (работают только write-функции) */
emReadOnly = 2, /*!< "только чтение" (работают только read-функции) */
emSkipSaveToSM = 3, /*!< не писать данные в SM (при этом работают и read и write функции) */
emSkipExchange = 4 /*!< отключить обмен */
};
friend std::ostream& operator<<( std::ostream& os, const ExchangeMode& em );
/*! Режимы работы процесса обмена */
enum SafeMode
{
safeNone = 0, /*!< не использовать безопасный режим (по умолчанию) */
safeResetIfNotRespond = 1, /*!< выставлять безопасное значение, если пропала связь с устройством */
safeExternalControl = 2 /*!< управление сбросом по внешнему датчику */
};
friend std::string to_string( const SafeMode& m );
friend std::ostream& operator<<( std::ostream& os, const SafeMode& m );
enum DeviceType
{
dtUnknown, /*!< неизвестный */
dtRTU, /*!< RTU (default) */
dtMTR, /*!< MTR (DEIF) */
dtRTU188 /*!< RTU188 (Fastwell) */
};
static DeviceType getDeviceType( const std::string& dtype ) noexcept;
friend std::ostream& operator<<( std::ostream& os, const DeviceType& dt );
struct RTUDevice;
struct RegInfo;
struct RSProperty:
public IOBase
{
// only for RTU
int8_t nbit; /*!< bit number (-1 - not used) */
VTypes::VType vType; /*!< type of value */
uint16_t rnum; /*!< count of registers */
uint8_t nbyte; /*!< byte number (1-2) */
RSProperty():
nbit(-1), vType(VTypes::vtUnknown),
rnum(VTypes::wsize(VTypes::vtUnknown)),
nbyte(0)
{}
// т.к. IOBase содержит rwmutex с запрещённым конструктором копирования
// приходится здесь тоже объявлять разрешенными только операции "перемещения"
RSProperty( const RSProperty& r ) = delete;
RSProperty& operator=(const RSProperty& r) = delete;
RSProperty( RSProperty&& r ) = default;
RSProperty& operator=(RSProperty&& r) = default;
std::shared_ptr<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, const PList& p );
typedef std::map<ModbusRTU::RegID, std::shared_ptr<RegInfo>> RegMap;
struct RegInfo
{
// т.к. RSProperty содержит rwmutex с запрещённым конструктором копирования
// приходится здесь тоже объявлять разрешенными только операции "перемещения"
RegInfo( const RegInfo& r ) = default;
RegInfo& operator=(const RegInfo& r) = delete;
RegInfo( RegInfo&& r ) = delete;
RegInfo& operator=(RegInfo&& r) = default;
RegInfo() = default;
ModbusRTU::ModbusData mbval = { 0 };
ModbusRTU::ModbusData mbreg = { 0 }; /*!< регистр */
ModbusRTU::SlaveFunctionCode mbfunc = { ModbusRTU::fnUnknown }; /*!< функция для чтения/записи */
PList slst;
ModbusRTU::RegID regID = { 0 };
std::shared_ptr<RTUDevice> dev;
// only for RTU188
RTUStorage::RTUJack rtuJack = { RTUStorage::nUnknown };
int rtuChan = { 0 };
// only for MTR
MTR::MTRType mtrType = { MTR::mtUnknown }; /*!< тип регистра (согласно спецификации на MTR) */
// optimization
size_t q_num = { 0 }; /*!< number in query */
size_t q_count = { 1 }; /*!< count registers for query */
RegMap::iterator rit;
// начальная инициализация для "записываемых" регистров
// Механизм:
// Если tcp_preinit="1", то сперва будет сделано чтение значения из устройства.
// при этом флаг mb_init=false пока не пройдёт успешной инициализации
// Если tcp_preinit="0", то флаг mb_init сразу выставляется в true.
bool mb_initOK = { false }; /*!< инициализировалось ли значение из устройства */
// Флаг sm_init означает, что писать в устройство нельзя, т.к. значение в "карте регистров"
// ещё не инициализировано из SM
bool sm_initOK = { false }; /*!< инициализировалось ли значение из SM */
};
friend std::ostream& operator<<( std::ostream& os, const RegInfo& r );
friend std::ostream& operator<<( std::ostream& os, const RegInfo* r );
struct RTUDevice
{
ModbusRTU::ModbusAddr mbaddr = { 0 }; /*!< адрес устройства */
std::unordered_map<size_t, std::shared_ptr<RegMap>> pollmap;
DeviceType dtype = { dtUnknown }; /*!< тип устройства */
// resp - respond..(контроль наличия связи)
uniset::ObjectId resp_id = { uniset::DefaultObjectId };
IOController::IOStateList::iterator resp_it;
DelayTimer resp_Delay; // таймер для формирования задержки на отпускание (пропадание связи)
PassiveTimer resp_ptInit; // таймер для формирования задержки на инициализацию связи (задержка на выставление датчика связи после запуска)
bool resp_state = { false };
bool resp_invert = { false };
bool resp_force = { false };
Trigger trInitOK; // триггер для "инициализации"
std::atomic<size_t> numreply = { 0 }; // количество успешных запросов..
std::atomic<size_t> prev_numreply = { 0 };
//
bool ask_every_reg = { false }; /*!< опрашивать ли каждый регистр, независимо от результата опроса предыдущего. По умолчанию false - прервать опрос при первом же timeout */
// режим работы
uniset::ObjectId mode_id = { uniset::DefaultObjectId };
IOController::IOStateList::iterator mode_it;
long mode = { emNone }; // режим работы с устройством (см. ExchangeMode)
// safe mode
long safeMode = { safeNone }; /*!< режим безопасного состояния см. SafeMode */
uniset::ObjectId safemode_id = { uniset::DefaultObjectId }; /*!< идентификатор для датчика безопасного режима */
IOController::IOStateList::iterator safemode_it;
long safemode_value = { 1 };
// return TRUE if state changed
bool checkRespond( std::shared_ptr<DebugStream>& log );
// специфические поля для RS
ComPort::Speed speed = { ComPort::ComSpeed38400 };
std::shared_ptr<RTUStorage> rtu188;
std::string getShortInfo() const;
};
friend std::ostream& operator<<( std::ostream& os, RTUDevice& d );
typedef std::unordered_map<ModbusRTU::ModbusAddr, std::shared_ptr<RTUDevice>> RTUDeviceMap;
friend std::ostream& operator<<( std::ostream& os, RTUDeviceMap& d );
void printMap(RTUDeviceMap& d);
// ---------------------------------- // ----------------------------------
enum Timer enum Timer
{ {
...@@ -246,6 +83,8 @@ namespace uniset ...@@ -246,6 +83,8 @@ namespace uniset
virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override; virtual uniset::SimpleInfo* getInfo( const char* userparam = 0 ) override;
bool reconfigure( const std::string& confile );
protected: protected:
virtual void step(); virtual void step();
virtual void sysCommand( const uniset::SystemMessage* msg ) override; virtual void sysCommand( const uniset::SystemMessage* msg ) override;
...@@ -258,80 +97,41 @@ namespace uniset ...@@ -258,80 +97,41 @@ namespace uniset
virtual void initIterators(); virtual void initIterators();
virtual void initValues(); virtual void initValues();
struct InitRegInfo
{
InitRegInfo():
dev(0), mbreg(0),
mbfunc(ModbusRTU::fnUnknown),
initOK(false)
{}
RSProperty p;
std::shared_ptr<RTUDevice> dev;
ModbusRTU::ModbusData mbreg;
ModbusRTU::SlaveFunctionCode mbfunc;
bool initOK;
std::shared_ptr<RegInfo> ri;
};
typedef std::list<InitRegInfo> InitList;
void firstInitRegisters(); void firstInitRegisters();
bool preInitRead( InitList::iterator& p ); bool preInitRead( MBConfig::InitList::iterator& p );
bool initSMValue( ModbusRTU::ModbusData* data, int count, RSProperty* p ); bool initSMValue( ModbusRTU::ModbusData* data, int count, MBConfig::RSProperty* p );
bool allInitOK; bool allInitOK;
RTUDeviceMap devices;
InitList initRegList; /*!< список регистров для инициализации */
virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) = 0; virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) = 0;
virtual bool poll(); virtual bool poll();
bool pollRTU( std::shared_ptr<RTUDevice>& dev, RegMap::iterator& it ); bool pollRTU( std::shared_ptr<MBConfig::RTUDevice>& dev, MBConfig::RegMap::iterator& it );
void updateSM(); void updateSM();
// в функции передаётся итератор, // в функции передаётся итератор,
// т.к. в них идёт итерирование в случае если запрос в несколько регистров // т.к. в них идёт итерирование в случае если запрос в несколько регистров
void updateRTU(RegMap::iterator& it); void updateRTU(MBConfig::RegMap::iterator& it);
void updateMTR(RegMap::iterator& it); void updateMTR(MBConfig::RegMap::iterator& it);
void updateRTU188(RegMap::iterator& it); void updateRTU188(MBConfig::RegMap::iterator& it);
void updateRSProperty( RSProperty* p, bool write_only = false ); void updateRSProperty( MBConfig::RSProperty* p, bool write_only = false );
virtual void updateRespondSensors(); virtual void updateRespondSensors();
bool isUpdateSM( bool wrFunc, long devMode ) const noexcept; bool isUpdateSM( bool wrFunc, long devMode ) const noexcept;
bool isPollEnabled( bool wrFunc ) const noexcept; bool isPollEnabled( bool wrFunc ) const noexcept;
bool isSafeMode( std::shared_ptr<RTUDevice>& dev ) const noexcept; bool isSafeMode( std::shared_ptr<MBConfig::RTUDevice>& dev ) const noexcept;
bool isProcActive() const; bool isProcActive() const;
void setProcActive( bool st ); void setProcActive( bool st );
bool waitSMReady(); bool waitSMReady();
void readConfiguration(); // void readConfiguration();
bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec ); bool readItem( const std::shared_ptr<UniXML>& xml, UniXML::iterator& it, xmlNode* sec );
bool initItem( UniXML::iterator& it ); bool initItem( UniXML::iterator& it );
void initDeviceList();
void initOffsetList(); void initOffsetList();
std::string initPropPrefix( const std::string& s_filed, const std::string& def_prop_prefix );
std::shared_ptr<RTUDevice> addDev( RTUDeviceMap& dmap, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
std::shared_ptr<RegInfo> addReg(std::shared_ptr<RegMap>& devices, ModbusRTU::RegID id, ModbusRTU::ModbusData r, UniXML::iterator& it, std::shared_ptr<RTUDevice> dev );
RSProperty* addProp( PList& plist, RSProperty&& p );
bool initMTRitem(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
bool initRTU188item(UniXML::iterator& it, std::shared_ptr<RegInfo>& p );
bool initRSProperty( RSProperty& p, UniXML::iterator& it );
bool initRegInfo(std::shared_ptr<RegInfo>& r, UniXML::iterator& it, std::shared_ptr<RTUDevice>& dev );
bool initRTUDevice( std::shared_ptr<RTUDevice>& d, UniXML::iterator& it );
virtual bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it );
std::string initPropPrefix( const std::string& def_prop_prefix = "" );
void rtuQueryOptimization( RTUDeviceMap& m );
void rtuQueryOptimizationForDevice( const std::shared_ptr<RTUDevice>& d );
void rtuQueryOptimizationForRegMap( const std::shared_ptr<RegMap>& regmap );
xmlNode* cnode = { 0 }; xmlNode* cnode = { 0 };
std::string s_field;
std::string s_fvalue;
std::shared_ptr<SMInterface> shm; std::shared_ptr<SMInterface> shm;
timeout_t initPause = { 3000 }; timeout_t initPause = { 3000 };
...@@ -339,10 +139,6 @@ namespace uniset ...@@ -339,10 +139,6 @@ namespace uniset
bool force = { false }; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */ bool force = { false }; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */
bool force_out = { false }; /*!< флаг означающий, принудительного чтения выходов */ bool force_out = { false }; /*!< флаг означающий, принудительного чтения выходов */
bool mbregFromID = { false };
timeout_t polltime = { 100 }; /*!< периодичность обновления данных, [мсек] */
timeout_t sleepPause_msec = { 10 };
size_t maxQueryCount = { ModbusRTU::MAXDATALEN }; /*!< максимальное количество регистров для одного запроса */
PassiveTimer ptHeartBeat; PassiveTimer ptHeartBeat;
uniset::ObjectId sidHeartBeat = { uniset::DefaultObjectId }; uniset::ObjectId sidHeartBeat = { uniset::DefaultObjectId };
...@@ -352,31 +148,20 @@ namespace uniset ...@@ -352,31 +148,20 @@ namespace uniset
uniset::ObjectId sidExchangeMode = { uniset::DefaultObjectId }; /*!< идентификатор для датчика режима работы */ uniset::ObjectId sidExchangeMode = { uniset::DefaultObjectId }; /*!< идентификатор для датчика режима работы */
IOController::IOStateList::iterator itExchangeMode; IOController::IOStateList::iterator itExchangeMode;
long exchangeMode = { emNone }; /*!< режим работы см. ExchangeMode */ long exchangeMode = { MBConfig::emNone }; /*!< режим работы см. ExchangeMode */
std::atomic_bool activated = { false }; std::atomic_bool activated = { false };
std::atomic_bool canceled = { false }; std::atomic_bool canceled = { false };
timeout_t activateTimeout = { 20000 }; // msec timeout_t activateTimeout = { 20000 }; // msec
bool noQueryOptimization = { false };
bool notUseExchangeTimer = { false }; bool notUseExchangeTimer = { false };
std::string prefix;
timeout_t stat_time = { 0 }; /*!< время сбора статистики обмена, 0 - отключена */ timeout_t stat_time = { 0 }; /*!< время сбора статистики обмена, 0 - отключена */
size_t poll_count = { 0 }; size_t poll_count = { 0 };
PassiveTimer ptStatistic; /*!< таймер для сбора статистики обмена */ PassiveTimer ptStatistic; /*!< таймер для сбора статистики обмена */
std::string statInfo = { "" }; std::string statInfo = { "" };
std::string prop_prefix; /*!< префикс для считывания параметров обмена */
std::shared_ptr<ModbusClient> mb; std::shared_ptr<ModbusClient> mb;
// определение timeout для соединения
timeout_t recv_timeout = { 500 }; // msec
timeout_t default_timeout = { 5000 }; // msec
timeout_t aftersend_pause = { 0 };
PassiveTimer ptReopen; /*!< таймер для переоткрытия соединения */ PassiveTimer ptReopen; /*!< таймер для переоткрытия соединения */
Trigger trReopen; Trigger trReopen;
...@@ -397,11 +182,20 @@ namespace uniset ...@@ -397,11 +182,20 @@ namespace uniset
std::string logserv_host = {""}; std::string logserv_host = {""};
int logserv_port = {0}; int logserv_port = {0};
const std::shared_ptr<SharedMemory> ic; const std::shared_ptr<SharedMemory> ic;
std::shared_ptr<LogAgregator> loga;
std::shared_ptr<DebugStream> mblog;
std::shared_ptr<LogServer> logserv;
std::string logserv_host = {""};
int logserv_port = {0};
const std::shared_ptr<SharedMemory> ic;
VMonitor vmon; VMonitor vmon;
size_t ncycle = { 0 }; /*!< текущий номер цикла опроса */ size_t ncycle = { 0 }; /*!< текущий номер цикла опроса */
std::shared_ptr<uniset::MBConfig> mbconf;
uniset::uniset_rwmutex mutex_conf;
private: private:
MBExchange(); MBExchange();
......
...@@ -38,8 +38,8 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId, ...@@ -38,8 +38,8 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId,
auto conf = uniset_conf(); auto conf = uniset_conf();
// префикс для "свойств" - по умолчанию "tcp_"; // префикс для "свойств" - по умолчанию "tcp_";
prop_prefix = initPropPrefix("tcp_"); mbconf->prop_prefix = initPropPrefix(mbconf->s_field, "tcp_");
mbinfo << myname << "(init): prop_prefix=" << prop_prefix << endl; mbinfo << myname << "(init): prop_prefix=" << mbconf->prop_prefix << endl;
UniXML::iterator it(cnode); UniXML::iterator it(cnode);
...@@ -62,14 +62,7 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId, ...@@ -62,14 +62,7 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId,
mbinfo << myname << "(init): persisten-connection=" << (!force_disconnect) << endl; mbinfo << myname << "(init): persisten-connection=" << (!force_disconnect) << endl;
if( shm->isLocalwork() ) if( shm->isLocalwork() )
{ mbconf->loadConfig(conf->getConfXML(), conf->getXMLSensorsSection());
readConfiguration();
if( !noQueryOptimization )
rtuQueryOptimization(devices);
initDeviceList();
}
else else
ic->addReadItem( sigc::mem_fun(this, &MBTCPMaster::readItem) ); ic->addReadItem( sigc::mem_fun(this, &MBTCPMaster::readItem) );
...@@ -77,7 +70,7 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId, ...@@ -77,7 +70,7 @@ MBTCPMaster::MBTCPMaster(uniset::ObjectId objId, uniset::ObjectId shmId,
pollThread->setFinalAction(this, &MBTCPMaster::final_thread); pollThread->setFinalAction(this, &MBTCPMaster::final_thread);
if( mblog->is_info() ) if( mblog->is_info() )
printMap(devices); MBConfig::printMap(mbconf->devices);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
MBTCPMaster::~MBTCPMaster() MBTCPMaster::~MBTCPMaster()
...@@ -112,11 +105,11 @@ std::shared_ptr<ModbusClient> MBTCPMaster::initMB( bool reopen ) ...@@ -112,11 +105,11 @@ std::shared_ptr<ModbusClient> MBTCPMaster::initMB( bool reopen )
mbtcp->connect(iaddr, port); mbtcp->connect(iaddr, port);
mbtcp->setForceDisconnect(force_disconnect); mbtcp->setForceDisconnect(force_disconnect);
if( recv_timeout > 0 ) if( mbconf->recv_timeout > 0 )
mbtcp->setTimeout(recv_timeout); mbtcp->setTimeout(mbconf->recv_timeout);
mbtcp->setSleepPause(sleepPause_msec); mbtcp->setSleepPause(mbconf->sleepPause_msec);
mbtcp->setAfterSendPause(aftersend_pause); mbtcp->setAfterSendPause(mbconf->aftersend_pause);
mbinfo << myname << "(init): ipaddr=" << iaddr << " port=" << port mbinfo << myname << "(init): ipaddr=" << iaddr << " port=" << port
<< " connection=" << (mbtcp->isConnection() ? "OK" : "FAIL" ) << endl; << " connection=" << (mbtcp->isConnection() ? "OK" : "FAIL" ) << endl;
...@@ -182,7 +175,7 @@ void MBTCPMaster::poll_thread() ...@@ -182,7 +175,7 @@ void MBTCPMaster::poll_thread()
if( !isProcActive() ) if( !isProcActive() )
break; break;
msleep(polltime); msleep(mbconf->polltime);
} }
dinfo << myname << "(poll_thread): thread finished.." << endl; dinfo << myname << "(poll_thread): thread finished.." << endl;
......
...@@ -38,8 +38,8 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm ...@@ -38,8 +38,8 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm
auto conf = uniset_conf(); auto conf = uniset_conf();
prop_prefix = initPropPrefix("tcp_"); mbconf->prop_prefix = initPropPrefix(mbconf->s_field, "tcp_");
mbinfo << myname << "(init): prop_prefix=" << prop_prefix << endl; mbinfo << myname << "(init): prop_prefix=" << mbconf->prop_prefix << endl;
UniXML::iterator it(cnode); UniXML::iterator it(cnode);
...@@ -50,7 +50,7 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm ...@@ -50,7 +50,7 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm
// Т.к. при "многоканальном" доступе к slave, смена канала должна происходит сразу после // Т.к. при "многоканальном" доступе к slave, смена канала должна происходит сразу после
// неудачной попытки запросов по одному из каналов, то ПЕРЕОПРЕДЕЛЯЕМ reopen, на channel-timeout.. // неудачной попытки запросов по одному из каналов, то ПЕРЕОПРЕДЕЛЯЕМ reopen, на channel-timeout..
int channelTimeout = conf->getArgPInt("--" + prefix + "-default-channel-timeout", it.getProp("channelTimeout"), default_timeout); int channelTimeout = conf->getArgPInt("--" + prefix + "-default-channel-timeout", it.getProp("channelTimeout"), mbconf->default_timeout);
ptReopen.setTiming(channelTimeout); ptReopen.setTiming(channelTimeout);
UniXML::iterator it1(it); UniXML::iterator it1(it);
...@@ -118,9 +118,9 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm ...@@ -118,9 +118,9 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm
sinf->mbtcp = std::make_shared<ModbusTCPMaster>(); sinf->mbtcp = std::make_shared<ModbusTCPMaster>();
sinf->ptIgnoreTimeout.setTiming( it1.getPIntProp("ignore_timeout", ignore_timeout) ); sinf->ptIgnoreTimeout.setTiming( it1.getPIntProp("ignore_timeout", ignore_timeout) );
sinf->recv_timeout = it1.getPIntProp("recv_timeout", recv_timeout); sinf->recv_timeout = it1.getPIntProp("recv_timeout", mbconf->recv_timeout);
sinf->aftersend_pause = it1.getPIntProp("aftersend_pause", aftersend_pause); sinf->aftersend_pause = it1.getPIntProp("aftersend_pause", mbconf->aftersend_pause);
sinf->sleepPause_usec = it1.getPIntProp("sleepPause_msec", sleepPause_msec); sinf->sleepPause_usec = it1.getPIntProp("sleepPause_msec", mbconf->sleepPause_msec);
sinf->respond_invert = it1.getPIntProp("invert", 0); sinf->respond_invert = it1.getPIntProp("invert", 0);
sinf->respond_force = it1.getPIntProp("force", 0); sinf->respond_force = it1.getPIntProp("force", 0);
...@@ -179,14 +179,7 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm ...@@ -179,14 +179,7 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm
(*mbi)->setUse(true); (*mbi)->setUse(true);
if( shm->isLocalwork() ) if( shm->isLocalwork() )
{ mbconf->loadConfig(conf->getConfXML(), conf->getXMLSensorsSection());
readConfiguration();
if( !noQueryOptimization )
rtuQueryOptimization(devices);
initDeviceList();
}
else else
ic->addReadItem( sigc::mem_fun(this, &MBTCPMultiMaster::readItem) ); ic->addReadItem( sigc::mem_fun(this, &MBTCPMultiMaster::readItem) );
...@@ -197,11 +190,11 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm ...@@ -197,11 +190,11 @@ MBTCPMultiMaster::MBTCPMultiMaster( uniset::ObjectId objId, uniset::ObjectId shm
// Т.к. при "многоканальном" доступе к slave, смена канала должна происходит сразу после // Т.к. при "многоканальном" доступе к slave, смена канала должна происходит сразу после
// неудачной попытки запросов по одному из каналов, то ПЕРЕОПРЕДЕЛЯЕМ reopen, на channel-timeout.. // неудачной попытки запросов по одному из каналов, то ПЕРЕОПРЕДЕЛЯЕМ reopen, на channel-timeout..
int tout = conf->getArgPInt("--" + prefix + "-default-channel-timeout", it.getProp("channelTimeout"), default_timeout); int tout = conf->getArgPInt("--" + prefix + "-default-channel-timeout", it.getProp("channelTimeout"), mbconf->default_timeout);
ptReopen.setTiming(tout); ptReopen.setTiming(tout);
if( mblog->is_info() ) if( mblog->is_info() )
printMap(devices); MBConfig::printMap(mbconf->devices);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
MBTCPMultiMaster::~MBTCPMultiMaster() MBTCPMultiMaster::~MBTCPMultiMaster()
...@@ -493,7 +486,7 @@ void MBTCPMultiMaster::poll_thread() ...@@ -493,7 +486,7 @@ void MBTCPMultiMaster::poll_thread()
if( !isProcActive() ) if( !isProcActive() )
break; break;
msleep(polltime); msleep(mbconf->polltime);
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -574,7 +567,6 @@ void MBTCPMultiMaster::check_thread() ...@@ -574,7 +567,6 @@ void MBTCPMultiMaster::check_thread()
void MBTCPMultiMaster::initIterators() void MBTCPMultiMaster::initIterators()
{ {
MBExchange::initIterators(); MBExchange::initIterators();
for( auto&& it : mblist ) for( auto&& it : mblist )
shm->initIterator(it->respond_it); shm->initIterator(it->respond_it);
} }
...@@ -607,7 +599,7 @@ void MBTCPMultiMaster::initCheckConnectionParameters() ...@@ -607,7 +599,7 @@ void MBTCPMultiMaster::initCheckConnectionParameters()
{ {
auto conf = uniset_conf(); auto conf = uniset_conf();
bool initFromRegMap = ( findArgParam("--" + prefix + "-check-init-from-regmap", conf->getArgc(), conf->getArgv()) != -1 ); bool initFromRegMap = ( findArgParam("--" + mbconf->prefix + "-check-init-from-regmap", conf->getArgc(), conf->getArgv()) != -1 );
if( !initFromRegMap ) if( !initFromRegMap )
return; return;
...@@ -623,18 +615,16 @@ void MBTCPMultiMaster::initCheckConnectionParameters() ...@@ -623,18 +615,16 @@ void MBTCPMultiMaster::initCheckConnectionParameters()
ModbusRTU::ModbusAddr checkAddr = { 0x00 }; ModbusRTU::ModbusAddr checkAddr = { 0x00 };
ModbusRTU::ModbusData checkReg = { 0 }; ModbusRTU::ModbusData checkReg = { 0 };
if( devices.empty() ) if( mbconf->devices.empty() )
{ {
mbwarn << myname << "(init): devices list empty?!" << endl; mbwarn << myname << "(init): devices list empty?!" << endl;
return; return;
} }
// идём по устройствам // идём по устройствам
for( const auto& d : devices ) for( const auto& d : mbconf->devices )
{ {
checkAddr = d.second->mbaddr; checkAddr = d.second->mbaddr;
if( d.second->pollmap.empty() ) if( d.second->pollmap.empty() )
continue; continue;
......
...@@ -4,7 +4,7 @@ libMBMaster_la_LIBADD = $(top_builddir)/lib/libUniSet2.la \ ...@@ -4,7 +4,7 @@ libMBMaster_la_LIBADD = $(top_builddir)/lib/libUniSet2.la \
$(top_builddir)/extensions/lib/libUniSet2Extensions.la \ $(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(SIGC_LIBS) $(SIGC_LIBS)
libMBMaster_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) libMBMaster_la_CXXFLAGS = -I$(top_builddir)/extensions/include -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS)
libMBMaster_la_SOURCES = MBExchange.cc RTUStorage.cc libMBMaster_la_SOURCES = MBExchange.cc MBConfig.cc RTUStorage.cc
bin_PROGRAMS = @PACKAGE@-mbtcpmaster @PACKAGE@-mbtcpmultimaster @PACKAGE@-rtuexchange @PACKAGE@-mtr-conv @PACKAGE@-rtu188-state @PACKAGE@-vtconv @PACKAGE@-mtr-setup @PACKAGE@-mtr-read bin_PROGRAMS = @PACKAGE@-mbtcpmaster @PACKAGE@-mbtcpmultimaster @PACKAGE@-rtuexchange @PACKAGE@-mtr-conv @PACKAGE@-rtu188-state @PACKAGE@-vtconv @PACKAGE@-mtr-setup @PACKAGE@-mtr-read
lib_LTLIBRARIES = libUniSet2MBTCPMaster.la libUniSet2RTU.la lib_LTLIBRARIES = libUniSet2MBTCPMaster.la libUniSet2RTU.la
......
...@@ -34,70 +34,62 @@ RTUExchange::RTUExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const s ...@@ -34,70 +34,62 @@ RTUExchange::RTUExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const s
rs_pre_clean(false) rs_pre_clean(false)
{ {
if( objId == DefaultObjectId ) if( objId == DefaultObjectId )
throw uniset::SystemError("(RTUExchange): objId=-1?!! Use --" + prefix + "-name" ); throw uniset::SystemError("(RTUExchange): objId=-1?!! Use --" + mbconf->prefix + "-name" );
auto conf = uniset_conf(); auto conf = uniset_conf();
// префикс для "свойств" - по умолчанию // префикс для "свойств" - по умолчанию
prop_prefix = ""; mbconf->prop_prefix = "";
// если задано поле для "фильтрации" // если задано поле для "фильтрации"
// то в качестве префикса используем его // то в качестве префикса используем его
if( !s_field.empty() ) if( !mbconf->s_field.empty() )
prop_prefix = s_field + "_"; mbconf->prop_prefix = mbconf->s_field + "_";
// если "принудительно" задан префикс // если "принудительно" задан префикс
// используем его. // используем его.
{ {
string p("--" + prefix + "-set-prop-prefix"); string p("--" + mbconf->prefix + "-set-prop-prefix");
string v = conf->getArgParam(p, ""); string v = conf->getArgParam(p, "");
if( !v.empty() && v[0] != '-' ) if( !v.empty() && v[0] != '-' )
prop_prefix = v; mbconf->prop_prefix = v;
// если параметр всё-таки указан, считаем, что это попытка задать "пустой" префикс // если параметр всё-таки указан, считаем, что это попытка задать "пустой" префикс
else if( findArgParam(p, conf->getArgc(), conf->getArgv()) != -1 ) else if( findArgParam(p, conf->getArgc(), conf->getArgv()) != -1 )
prop_prefix = ""; mbconf->prop_prefix = "";
} }
mbinfo << myname << "(init): prop_prefix=" << prop_prefix << endl; mbinfo << myname << "(init): prop_prefix=" << mbconf->prop_prefix << endl;
UniXML::iterator it(cnode); UniXML::iterator it(cnode);
// ---------- init RS ---------- // ---------- init RS ----------
devname = conf->getArgParam("--" + prefix + "-dev", it.getProp("device")); devname = conf->getArgParam("--" + mbconf->prefix + "-dev", it.getProp("device"));
if( devname.empty() ) if( devname.empty() )
throw uniset::SystemError(myname + "(RTUExchange): Unknown device..." ); throw uniset::SystemError(myname + "(RTUExchange): Unknown device..." );
string speed = conf->getArgParam("--" + prefix + "-speed", it.getProp("speed")); string speed = conf->getArgParam("--" + mbconf->prefix + "-speed", it.getProp("speed"));
if( speed.empty() ) if( speed.empty() )
speed = "38400"; speed = "38400";
use485F = conf->getArgInt("--" + prefix + "-use485F", it.getProp("use485F")); use485F = conf->getArgInt("--" + mbconf->prefix + "-use485F", it.getProp("use485F"));
transmitCtl = conf->getArgInt("--" + prefix + "-transmit-ctl", it.getProp("transmitCtl")); transmitCtl = conf->getArgInt("--" + mbconf->prefix + "-transmit-ctl", it.getProp("transmitCtl"));
defSpeed = ComPort::getSpeed(speed); defSpeed = ComPort::getSpeed(speed);
sleepPause_msec = conf->getArgPInt("--" + prefix + "-sleepPause-usec", it.getProp("slepePause"), 100); mbconf->sleepPause_msec = conf->getArgPInt("--" + mbconf->prefix + "-sleepPause-usec", it.getProp("slepePause"), 100);
rs_pre_clean = conf->getArgInt("--" + prefix + "-pre-clean", it.getProp("pre_clean")); rs_pre_clean = conf->getArgInt("--" + mbconf->prefix + "-pre-clean", it.getProp("pre_clean"));
if( shm->isLocalwork() ) if( shm->isLocalwork() )
{ mbconf->loadConfig(conf->getConfXML(), conf->getXMLSensorsSection());
readConfiguration();
if( !noQueryOptimization )
rtuQueryOptimization(devices);
initDeviceList();
}
else else
ic->addReadItem( sigc::mem_fun(this, &RTUExchange::readItem) ); ic->addReadItem( sigc::mem_fun(this, &RTUExchange::readItem) );
initMB(false); initMB(false);
if( dlog()->is_info() ) if( dlog()->is_info() )
printMap(devices); MBConfig::printMap(mbconf->devices);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void RTUExchange::help_print( int argc, const char* const* argv ) void RTUExchange::help_print( int argc, const char* const* argv )
...@@ -155,11 +147,11 @@ std::shared_ptr<ModbusClient> RTUExchange::initMB( bool reopen ) ...@@ -155,11 +147,11 @@ std::shared_ptr<ModbusClient> RTUExchange::initMB( bool reopen )
if( ic ) if( ic )
ic->logAgregator()->add(loga); ic->logAgregator()->add(loga);
if( recv_timeout > 0 ) if( mbconf->recv_timeout > 0 )
mbrtu->setTimeout(recv_timeout); mbrtu->setTimeout(mbconf->recv_timeout);
mbrtu->setSleepPause(sleepPause_msec); mbrtu->setSleepPause(mbconf->sleepPause_msec);
mbrtu->setAfterSendPause(aftersend_pause); mbrtu->setAfterSendPause(mbconf->aftersend_pause);
mbinfo << myname << "(init): dev=" << devname << " speed=" << ComPort::getSpeed( mbrtu->getSpeed() ) << endl; mbinfo << myname << "(init): dev=" << devname << " speed=" << ComPort::getSpeed( mbrtu->getSpeed() ) << endl;
} }
...@@ -236,11 +228,11 @@ bool RTUExchange::poll() ...@@ -236,11 +228,11 @@ bool RTUExchange::poll()
bool allNotRespond = true; bool allNotRespond = true;
ComPort::Speed s = mbrtu->getSpeed(); ComPort::Speed s = mbrtu->getSpeed();
for( auto it1 : devices ) for( auto it1 : mbconf->devices )
{ {
auto d = it1.second; auto d = it1.second;
if( d->mode_id != DefaultObjectId && d->mode == emSkipExchange ) if( d->mode_id != DefaultObjectId && d->mode == MBConfig::emSkipExchange )
continue; continue;
if( d->speed != s ) if( d->speed != s )
...@@ -251,7 +243,7 @@ bool RTUExchange::poll() ...@@ -251,7 +243,7 @@ bool RTUExchange::poll()
d->prev_numreply.store(d->numreply); d->prev_numreply.store(d->numreply);
if( d->dtype == MBExchange::dtRTU188 ) if( d->dtype == MBConfig::dtRTU188 )
{ {
if( !d->rtu188 ) if( !d->rtu188 )
continue; continue;
...@@ -294,7 +286,7 @@ bool RTUExchange::poll() ...@@ -294,7 +286,7 @@ bool RTUExchange::poll()
{ {
try try
{ {
if( d->dtype == RTUExchange::dtRTU || d->dtype == RTUExchange::dtMTR ) if( d->dtype == MBConfig::dtRTU || d->dtype == MBConfig::dtMTR )
{ {
if( rs_pre_clean ) if( rs_pre_clean )
mb->cleanupChannel(); mb->cleanupChannel();
...@@ -311,7 +303,7 @@ bool RTUExchange::poll() ...@@ -311,7 +303,7 @@ bool RTUExchange::poll()
dlog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr) dlog3 << myname << "(poll): FAILED ask addr=" << ModbusRTU::addr2str(d->mbaddr)
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg) << " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: "; << " for sensors: ";
print_plist(dlog()->level3(), it->second->slst); mbconf->print_plist(dlog()->level3(), it->second->slst);
dlog()->level3(false) << " err: " << ex << endl; dlog()->level3(false) << " err: " << ex << endl;
} }
...@@ -329,7 +321,7 @@ bool RTUExchange::poll() ...@@ -329,7 +321,7 @@ bool RTUExchange::poll()
updateSM(); updateSM();
// check thresholds // check thresholds
for( auto&& t : thrlist ) for( auto&& t : mbconf->thrlist )
{ {
if( !isProcActive() ) if( !isProcActive() )
return false; return false;
...@@ -379,36 +371,3 @@ std::shared_ptr<RTUExchange> RTUExchange::init_rtuexchange(int argc, const char* ...@@ -379,36 +371,3 @@ std::shared_ptr<RTUExchange> RTUExchange::init_rtuexchange(int argc, const char*
return make_shared<RTUExchange>(ID, icID, ic, prefix); return make_shared<RTUExchange>(ID, icID, ic, prefix);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool RTUExchange::initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it )
{
if( !MBExchange::initDeviceInfo(m, a, it) )
return false;
auto d = m.find(a);
if( d == m.end() )
{
mbwarn << myname << "(initDeviceInfo): not found device for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
string s = it.getProp("speed");
if( !s.empty() )
{
d->second->speed = ComPort::getSpeed(s);
if( d->second->speed == ComPort::ComSpeed0 )
{
d->second->speed = defSpeed;
mbcrit << myname << "(initDeviceInfo): Unknown speed=" << s <<
" for addr=" << ModbusRTU::addr2str(a) << endl;
return false;
}
}
else
d->second->speed = defSpeed;
return true;
}
// -----------------------------------------------------------------------------
...@@ -53,9 +53,7 @@ namespace uniset ...@@ -53,9 +53,7 @@ namespace uniset
virtual void step() override; virtual void step() override;
virtual bool poll() override; virtual bool poll() override;
virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) override; virtual std::shared_ptr<ModbusClient> initMB( bool reopen = false ) override;
virtual bool initDeviceInfo( RTUDeviceMap& m, ModbusRTU::ModbusAddr a, UniXML::iterator& it ) override;
private: private:
RTUExchange(); RTUExchange();
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
--mbtcp-persistent-connection 1 \ --mbtcp-persistent-connection 1 \
--ulog-add-levels system \ --ulog-add-levels system \
--mbtcp-run-logserver \ --mbtcp-run-logserver \
--mbtcp-log-add-levels any \
$* $*
#--mbtcp-log-add-levels level4,level3 \ #--mbtcp-log-add-levels level4,level3 \
......
...@@ -24,12 +24,6 @@ class MBTCPTestServer ...@@ -24,12 +24,6 @@ class MBTCPTestServer
replyVal = val; replyVal = val;
} }
inline void setIgnoreAddrMode( bool state )
{
if( sslot )
sslot->setIgnoreAddrMode(state);
}
void execute(); /*!< основной цикл работы */ void execute(); /*!< основной цикл работы */
void setLog( std::shared_ptr<DebugStream> dlog ); void setLog( std::shared_ptr<DebugStream> dlog );
......
...@@ -134,6 +134,8 @@ ...@@ -134,6 +134,8 @@
<!-- undefined state --> <!-- undefined state -->
<item id="1070" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="240" mbfunc="0x03" default="150" undefined_value="65535" breaklim="100" name="UndefinedState_FS" iotype="AI" textname="Тестирование неопределённого состояния"/> <item id="1070" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="240" mbfunc="0x03" default="150" undefined_value="65535" breaklim="100" name="UndefinedState_FS" iotype="AI" textname="Тестирование неопределённого состояния"/>
<item id="1080" default="1080" name="Reload1_FS" iotype="AI" textname="Тестирование перезагрузки конфига"/>
<item id="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/> <item id="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/>
</sensors> </sensors>
......
<?xml version="1.0" encoding="utf-8"?>
<UNISETPLC xmlns:xi="http://www.w3.org/2001/XInclude">
<UserData/>
<!-- Общие(стартовые) параметры по UniSet -->
<UniSet>
<NameService host="localhost" port="2809"/>
<LocalNode name="LocalhostNode"/>
<RootSection name="UNISET_PLC"/>
<CountOfNet name="1"/>
<RepeatCount name="3"/>
<RepeatTimeoutMS name="50"/>
<WatchDogTime name="0"/>
<PingNodeTime name="0"/>
<AutoStartUpTime name="1"/>
<DumpStateTime name="10"/>
<SleepTickMS name="500"/>
<UniSetDebug levels="" name="ulog"/>
<ConfDir name="./"/>
<DataDir name="./"/>
<BinDir name="./"/>
<LogDir name="./"/>
<DocDir name="./"/>
<LockDir name="./"/>
<Services></Services>
</UniSet>
<dlog name="dlog"/>
<settings>
<SharedMemory name="SharedMemory" shmID="SharedMemory"/>
<MBTCPMaster1 name="MBTCPMaster1" exchangeModeID="MBTCPMaster_Mode_AS">
<DeviceList>
<item addr="0x01" timeout="1000" invert="1" respondSensor="Slave_Not_Respond_S" safemodeSensor="Slave1_SafemodeSensor_S" safemodeValue="42"/>
<item addr="0x02" timeout="1000" safemodeResetIfNotRespond="1"/>
<item addr="0x03" timeout="500"/>
</DeviceList>
</MBTCPMaster1>
<MBTCPMultiMaster1 name="MBTCPMultiMaster1" poll_time="200" reply_timeout="60">
<DeviceList>
<item addr="0x01" invert="1" respondSensor="Slave_Not_Respond_S" timeout="1000" safemodeSensor="Slave1_SafemodeSensor_S" safemodeValue="42" />
<item addr="0x02" timeout="1000" safemodeResetIfNotRespond="1"/>
</DeviceList>
<GateList>
<item ip="127.0.0.1" port="20053" recv_timeout="200" invert="1" respondSensor="Slave1_Not_Respond_S"/>
<item ip="127.0.0.1" port="20055" recv_timeout="200" invert="1" respondSensor="Slave2_Not_Respond_S"/>
</GateList>
</MBTCPMultiMaster1>
</settings>
<ObjectsMap idfromfile="1">
<!--
Краткие пояснения к полям секции 'sensors'
==========================================
node - узел на котором физически находится данный датчик
iotype - тип датчика
priority - приоритет сообщения об изменении данного датчика
textname - текстовое имя датчика
-->
<nodes port="2809">
<item id="3000" infserver="InfoServer" ip="127.0.0.1" name="LocalhostNode" textname="Локальный узел"/>
</nodes>
<!-- ************************ Датчики ********************** -->
<sensors name="Sensors">
<!-- reload conf -->
<item id="1080" mb="1" mbtype="rtu" mbaddr="0x03" mbreg="340" mbfunc="0x03" name="Reload1_FS" iotype="AI" textname="Тестирование перезагрузки конфига"/>
</sensors>
<thresholds/>
<controllers name="Controllers">
<item id="5000" name="SharedMemory"/>
</controllers>
<!-- ******************* Идентификаторы сервисов ***************** -->
<services name="Services">
</services>
<!-- ******************* Идентификаторы объектов ***************** -->
<objects name="UniObjects">
<item id="6000" name="TestProc"/>
<item id="6004" name="MBTCPMaster1"/>
<item id="6005" name="MBTCPMultiMaster1"/>
</objects>
</ObjectsMap>
<messages idfromfile="1" name="messages"/>
</UNISETPLC>
...@@ -15,6 +15,7 @@ using namespace uniset; ...@@ -15,6 +15,7 @@ using namespace uniset;
using namespace uniset::extensions; using namespace uniset::extensions;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
std::shared_ptr<SharedMemory> shm; std::shared_ptr<SharedMemory> shm;
std::shared_ptr<MBTCPMaster> mbm;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
int main( int argc, const char* argv[] ) int main( int argc, const char* argv[] )
{ {
...@@ -46,15 +47,14 @@ int main( int argc, const char* argv[] ) ...@@ -46,15 +47,14 @@ int main( int argc, const char* argv[] )
if( !shm ) if( !shm )
return 1; return 1;
auto mb = MBTCPMaster::init_mbmaster(argc, argv, shm->getId(), (apart ? nullptr : shm )); mbm = MBTCPMaster::init_mbmaster(argc, argv, shm->getId(), (apart ? nullptr : shm ));
if( !mb ) if( !mbm )
return 1; return 1;
auto act = UniSetActivator::Instance(); auto act = UniSetActivator::Instance();
act->add(shm); act->add(shm);
act->add(mb); act->add(mbm);
SystemMessage sm(SystemMessage::StartUp); SystemMessage sm(SystemMessage::StartUp);
act->broadcast( sm.transport_msg() ); act->broadcast( sm.transport_msg() );
......
...@@ -16,7 +16,7 @@ cd - ...@@ -16,7 +16,7 @@ cd -
--mbtcp-gateway-iaddr localhost \ --mbtcp-gateway-iaddr localhost \
--mbtcp-gateway-port 20048 \ --mbtcp-gateway-port 20048 \
--mbtcp-polltime 50 --mbtcp-recv-timeout 500 --mbtcp-polltime 50 --mbtcp-recv-timeout 500
#--mbtcp-log-add-levels any # --mbtcp-log-add-levels any
#--mbtcp-default-mbinit-ok 1 #--mbtcp-default-mbinit-ok 1
#--dlog-add-levels any #--dlog-add-levels any
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "UniSetTypes.h" #include "UniSetTypes.h"
#include "MBTCPTestServer.h" #include "MBTCPTestServer.h"
#include "MBTCPMultiMaster.h" #include "MBTCPMultiMaster.h"
#include "MBTCPMaster.h"
#include "UniSetActivator.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
using namespace std; using namespace std;
using namespace uniset; using namespace uniset;
...@@ -15,7 +17,7 @@ using namespace uniset; ...@@ -15,7 +17,7 @@ using namespace uniset;
static ModbusRTU::ModbusAddr slaveADDR = 0x01; // conf->getArgInt("--mbs-my-addr"); static ModbusRTU::ModbusAddr slaveADDR = 0x01; // conf->getArgInt("--mbs-my-addr");
static int port = 20048; // conf->getArgInt("--mbs-inet-port"); static int port = 20048; // conf->getArgInt("--mbs-inet-port");
static string iaddr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr"); static string iaddr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static unordered_set<ModbusRTU::ModbusAddr> vaddr = { slaveADDR, 0x02 }; static unordered_set<ModbusRTU::ModbusAddr> vaddr = { slaveADDR, 0x02, 0x03 };
static shared_ptr<MBTCPTestServer> mbs; static shared_ptr<MBTCPTestServer> mbs;
static shared_ptr<UInterface> ui; static shared_ptr<UInterface> ui;
static std::shared_ptr<SMInterface> smi; static std::shared_ptr<SMInterface> smi;
...@@ -23,8 +25,10 @@ static ObjectId mbID = 6004; // MBTCPMaster1 ...@@ -23,8 +25,10 @@ static ObjectId mbID = 6004; // MBTCPMaster1
static int polltime = 100; // conf->getArgInt("--mbtcp-polltime"); static int polltime = 100; // conf->getArgInt("--mbtcp-polltime");
static ObjectId slaveNotRespond = 10; // Slave_Not_Respond_S static ObjectId slaveNotRespond = 10; // Slave_Not_Respond_S
static const ObjectId exchangeMode = 11; // MBTCPMaster_Mode_AS static const ObjectId exchangeMode = 11; // MBTCPMaster_Mode_AS
static const string confile2 = "mbmaster-test-configure2.xml";
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
extern std::shared_ptr<SharedMemory> shm; extern std::shared_ptr<SharedMemory> shm;
extern std::shared_ptr<MBTCPMaster> mbm;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static void InitTest() static void InitTest()
{ {
...@@ -81,6 +85,8 @@ static void InitTest() ...@@ -81,6 +85,8 @@ static void InitTest()
msleep(2000); msleep(2000);
CHECK( ui->getValue(slaveNotRespond) == 0 ); CHECK( ui->getValue(slaveNotRespond) == 0 );
} }
REQUIRE( mbm != nullptr );
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: reconnect", "[modbus][mbmaster][mbtcpmaster]") TEST_CASE("MBTCPMaster: reconnect", "[modbus][mbmaster][mbtcpmaster]")
...@@ -508,8 +514,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma ...@@ -508,8 +514,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
SECTION("WriteOnly") SECTION("WriteOnly")
{ {
// emWriteOnly=1, /*!< "только посылка данных" (работают только write-функции) */ // emWriteOnly=1, /*!< "только посылка данных" (работают только write-функции) */
ui->setValue(exchangeMode, MBExchange::emWriteOnly ); ui->setValue(exchangeMode, MBConfig::emWriteOnly );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emWriteOnly ); REQUIRE( ui->getValue(exchangeMode) == MBConfig::emWriteOnly );
SECTION("read") SECTION("read")
{ {
...@@ -537,8 +543,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma ...@@ -537,8 +543,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
SECTION("ReadOnly") SECTION("ReadOnly")
{ {
// emReadOnly=2, /*!< "только чтение" (работают только read-функции) */ // emReadOnly=2, /*!< "только чтение" (работают только read-функции) */
ui->setValue(exchangeMode, MBExchange::emReadOnly ); ui->setValue(exchangeMode, MBConfig::emReadOnly );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emReadOnly ); REQUIRE( ui->getValue(exchangeMode) == MBConfig::emReadOnly );
SECTION("read") SECTION("read")
{ {
...@@ -566,8 +572,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma ...@@ -566,8 +572,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
SECTION("SkipSaveToSM") SECTION("SkipSaveToSM")
{ {
// emSkipSaveToSM=3, /*!< не писать данные в SM (при этом работают и read и write функции */ // emSkipSaveToSM=3, /*!< не писать данные в SM (при этом работают и read и write функции */
ui->setValue(exchangeMode, MBExchange::emSkipSaveToSM ); ui->setValue(exchangeMode, MBConfig::emSkipSaveToSM );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emSkipSaveToSM ); REQUIRE( ui->getValue(exchangeMode) == MBConfig::emSkipSaveToSM );
SECTION("read") SECTION("read")
{ {
...@@ -592,8 +598,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma ...@@ -592,8 +598,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
SECTION("SkipExchange") SECTION("SkipExchange")
{ {
// emSkipExchange=4 /*!< отключить обмен */ // emSkipExchange=4 /*!< отключить обмен */
ui->setValue(exchangeMode, MBExchange::emSkipExchange ); ui->setValue(exchangeMode, MBConfig::emSkipExchange );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emSkipExchange ); REQUIRE( ui->getValue(exchangeMode) == MBConfig::emSkipExchange );
SECTION("read") SECTION("read")
{ {
...@@ -613,8 +619,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma ...@@ -613,8 +619,8 @@ TEST_CASE("MBTCPMaster: exchangeMode", "[modbus][exchangemode][mbmaster][mbtcpma
{ {
msleep(1100); msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 1 ); CHECK( ui->getValue(slaveNotRespond) == 1 );
ui->setValue(exchangeMode, MBExchange::emNone ); ui->setValue(exchangeMode, MBConfig::emNone );
REQUIRE( ui->getValue(exchangeMode) == MBExchange::emNone ); REQUIRE( ui->getValue(exchangeMode) == MBConfig::emNone );
msleep(1100); msleep(1100);
CHECK( ui->getValue(slaveNotRespond) == 0 ); CHECK( ui->getValue(slaveNotRespond) == 0 );
} }
...@@ -766,6 +772,23 @@ TEST_CASE("MBTCPMaster: udefined value", "[modbus][undefined][mbmaster][mbtcpmas ...@@ -766,6 +772,23 @@ TEST_CASE("MBTCPMaster: udefined value", "[modbus][undefined][mbmaster][mbtcpmas
REQUIRE( ui->getValue(1070) == 120 ); REQUIRE( ui->getValue(1070) == 120 );
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: reload config", "[modbus][reload][mbmaster][mbtcpmaster]")
{
InitTest();
mbs->setReply(160);
msleep(polltime + 200);
REQUIRE( ui->getValue(1070) == 160 );
REQUIRE( ui->getValue(1080) == 1080 );
// add new mbreg
REQUIRE( mbm->reconfigure(confile2) );
msleep(polltime + 600);
REQUIRE( ui->getValue(1080) == 160 );
}
// -----------------------------------------------------------------------------
#if 0 #if 0
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static bool init_iobase( IOBase* ib, const std::string& sensor ) static bool init_iobase( IOBase* ib, const std::string& sensor )
......
...@@ -187,7 +187,7 @@ class UObject_SK: ...@@ -187,7 +187,7 @@ class UObject_SK:
virtual void httpGetUserData( Poco::JSON::Object::Ptr& jdata ) {} /*!< для пользовательских данных в httpGet() */ virtual void httpGetUserData( Poco::JSON::Object::Ptr& jdata ) {} /*!< для пользовательских данных в httpGet() */
virtual Poco::JSON::Object::Ptr httpDumpIO(); virtual Poco::JSON::Object::Ptr httpDumpIO();
virtual Poco::JSON::Object::Ptr httpRequestLog( const Poco::URI::QueryParameters& p ); virtual Poco::JSON::Object::Ptr httpRequestLog( const Poco::URI::QueryParameters& p );
virtual Poco::JSON::Object::Ptr request_conf_set( const std::string& req, const Poco::URI::QueryParameters& p ); virtual Poco::JSON::Object::Ptr request_conf_set( const std::string& req, const Poco::URI::QueryParameters& p ) override;
#endif #endif
// Выполнение очередного шага программы // Выполнение очередного шага программы
......
...@@ -705,12 +705,47 @@ Poco::JSON::Object::Ptr UObject_SK::httpRequestLog( const Poco::URI::QueryParame ...@@ -705,12 +705,47 @@ Poco::JSON::Object::Ptr UObject_SK::httpRequestLog( const Poco::URI::QueryParame
Poco::JSON::Object::Ptr UObject_SK::request_conf_set( const std::string& req, const Poco::URI::QueryParameters& params ) Poco::JSON::Object::Ptr UObject_SK::request_conf_set( const std::string& req, const Poco::URI::QueryParameters& params )
{ {
Poco::JSON::Object::Ptr jret = new Poco::JSON::Object(); Poco::JSON::Object::Ptr jret = new Poco::JSON::Object();
Poco::JSON::Array::Ptr jupdated = uniset::json::make_child_array(jret, "updated");
for( const auto& p: params ) for( const auto& p: params )
{ {
if( p.first == "sleep_msec" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
sleep_msec = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "resetMsgTime" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
resetMsgTime = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
if( p.first == "forceOut" )
{
int val = uni_atoi(p.second);
if( val > 0 )
{
forceOut = uni_atoi(p.second);
jupdated->add(p.first);
}
continue;
}
} }
jret->set("Result","OK"); jret->set("Result", (jupdated->size() > 0 ? "OK" : "FAIL") );
return jret; return jret;
} }
#endif #endif
......
...@@ -60,9 +60,6 @@ namespace uniset ...@@ -60,9 +60,6 @@ namespace uniset
/*! текущее количество подключений */ /*! текущее количество подключений */
size_t getCountSessions() const noexcept; size_t getCountSessions() const noexcept;
void setIgnoreAddrMode( bool st );
bool getIgnoreAddrMode() const noexcept;
// Сбор статистики по соединениям... // Сбор статистики по соединениям...
struct SessionInfo struct SessionInfo
{ {
......
...@@ -81,16 +81,6 @@ namespace uniset ...@@ -81,16 +81,6 @@ namespace uniset
return sessCount; return sessCount;
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void ModbusTCPServer::setIgnoreAddrMode(bool st)
{
ignoreAddr = st;
}
// -------------------------------------------------------------------------
bool ModbusTCPServer::getIgnoreAddrMode() const noexcept
{
return ignoreAddr;
}
// -------------------------------------------------------------------------
void ModbusTCPServer::setSessionTimeout( timeout_t msec ) void ModbusTCPServer::setSessionTimeout( timeout_t msec )
{ {
sessTimeout = msec; sessTimeout = msec;
......
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++cc-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/gcc-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++cc-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/gcc-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++cc-config-1/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++cc-config-1/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++-config-1/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/130ac2dc34760443befdd3f2a25f8d40/g++-config-1/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/30c6834cc1e9802742e33de4efa3917c/g++cc-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/30c6834cc1e9802742e33de4efa3917c/g++cc-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/30c6834cc1e9802742e33de4efa3917c/g++-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/30c6834cc1e9802742e33de4efa3917c/g++-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/4d02eb73c555e8f07e4124fe33c80de2/g++cc-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/4d02eb73c555e8f07e4124fe33c80de2/g++cc-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/4d02eb73c555e8f07e4124fe33c80de2/g++-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/4d02eb73c555e8f07e4124fe33c80de2/g++-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/4db70a7a9c958929fa315f4c9243d800/g++cc-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/4db70a7a9c958929fa315f4c9243d800/g++cc-config-0/coverity-macro-compat.h
./cov-int/emit/pvbook.localdomain/config/4db70a7a9c958929fa315f4c9243d800/g++-config-0/coverity-compiler-compat.h
./cov-int/emit/pvbook.localdomain/config/4db70a7a9c958929fa315f4c9243d800/g++-config-0/coverity-macro-compat.h
./docs/Makefile.am ./docs/Makefile.am
./extensions/Backend-OpenTSDB/BackendOpenTSDB.cc ./extensions/Backend-OpenTSDB/BackendOpenTSDB.cc
./extensions/Backend-OpenTSDB/BackendOpenTSDB.h ./extensions/Backend-OpenTSDB/BackendOpenTSDB.h
...@@ -132,6 +110,8 @@ ...@@ -132,6 +110,8 @@
./extensions/Makefile.am ./extensions/Makefile.am
./extensions/ModbusMaster/main.cc ./extensions/ModbusMaster/main.cc
./extensions/ModbusMaster/Makefile.am ./extensions/ModbusMaster/Makefile.am
./extensions/ModbusMaster/MBConfig.cc
./extensions/ModbusMaster/MBConfig.h
./extensions/ModbusMaster/MBExchange.cc ./extensions/ModbusMaster/MBExchange.cc
./extensions/ModbusMaster/MBExchange.h ./extensions/ModbusMaster/MBExchange.h
./extensions/ModbusMaster/mb-perf-test.cc ./extensions/ModbusMaster/mb-perf-test.cc
......
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