Commit bf45b890 authored by Pavel Vainerman's avatar Pavel Vainerman

(MBSlave):

- дореализовал обработку функции 0x01(readCoilStatus) - сделал обработку полей nbit (для функций 0x03,0x04) - различные небольшие правки
parent 7641f93c
......@@ -12,7 +12,7 @@
Name: libuniset2
Version: 2.0
Release: alt25
Release: alt26
Summary: UniSet - library for building distributed industrial control systems
......@@ -409,6 +409,11 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
# ..
%changelog
* Thu Apr 09 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt26
- (ModbusSlave): added support nbit
- (ModbusSlave): added support 0x01 (readCoilStatus) function
- (ModbusSlave): minor fixes
* Tue Apr 07 2015 Pavel Vainerman <pv@altlinux.ru> 2.0-alt25
- fixed bug in 'MBSlave' (thank`s Alexandr Hanadeev)
- add --xxx-set-prop-prefix for MBSlave
......
......@@ -171,7 +171,7 @@ void MBExchange::help_print( int argc, const char* const* argv )
{
cout << "--prefix-name name - ObjectId (имя) процесса. По умолчанию: MBExchange1" << endl;
cout << "--prefix-confnode name - Настроечная секция в конф. файле <name>. " << endl;
cout << "--prefix-polltime msec - Пауза между опросами. По умолчанию 200 мсек." << endl;
cout << "--prefix-polltime msec - Пауза между опросами. По умолчанию 100 мсек." << endl;
cout << "--prefix-recv-timeout msec - Таймаут на приём одного сообщения" << endl;
cout << "--prefix-timeout msec - Таймаут для определения отсутствия соединения" << endl;
cout << "--prefix-reopen-timeout msec - Таймаут для 'переоткрытия соединения' при отсутсвия соединения msec милисекунд. По умолчанию 10 сек." << endl;
......
......@@ -151,7 +151,7 @@ prop_prefix("")
else
throw UniSetTypes::SystemError(myname+"(MBSlave): Unknown slave type. Use: --mbs-type [RTU|TCP]");
// mbslot->connectReadCoil( sigc::mem_fun(this, &MBSlave::readCoilStatus) );
mbslot->connectReadCoil( sigc::mem_fun(this, &MBSlave::readCoilStatus) );
mbslot->connectReadInputStatus( sigc::mem_fun(this, &MBSlave::readInputStatus) );
mbslot->connectReadOutput( sigc::mem_fun(this, &MBSlave::readOutputRegisters) );
mbslot->connectReadInput( sigc::mem_fun(this, &MBSlave::readInputRegisters) );
......@@ -861,6 +861,63 @@ bool MBSlave::initItem( UniXML::iterator& it )
else if( am == "wo" )
p.amode = MBSlave::amWO;
int nbit = IOBase::initIntProp(it,"nbit",prop_prefix,false,-1);
if( nbit != -1 )
{
if( nbit<0 || nbit >= ModbusRTU::BitsPerData )
{
dcrit << myname << "(initItem): BAD " << prop_prefix << "nbit=" << nbit << ". Must be 0 <= nbit < " << ModbusRTU::BitsPerData
<< " for '"
<< it.getProp("name")
<< "'" << endl;
return false;
}
auto i = iomap.find(p.mbreg);
if( i != iomap.end() )
{
if( !i->second.bitreg )
{
dcrit << myname << "(initItem): BAD USE " << prop_prefix << "nbit=" << nbit
<< " (for '"
<< it.getProp("name")
<< "') SENSOR ALREADY ADDED sid='" << i->second.si.id << "'"
<< "(" << uniset_conf()->oind->getMapName(i->second.si.id) << ")"
<< endl;
return false;
}
if( i->second.bitreg->check(p.si) )
{
dcrit << myname << "(initItem): BIT " << prop_prefix << "nbit=" << nbit
<< " (for "
<< it.getProp("name")
<< ") ALREADY IN USE for sid='" << i->second.bitreg->bvec[nbit].si.id << "'"
<< "(" << uniset_conf()->oind->getMapName(i->second.bitreg->bvec[nbit].si.id) << ")"
<< endl;
return false;
}
i->second.bitreg->bvec[nbit] = std::move(p);
return true;
}
else
{
ModbusData mbreg = p.mbreg;
IOProperty p_dummy;
p_dummy.bitreg = make_shared<BitRegProperty>();
p_dummy.bitreg->mbreg = mbreg;
p.vtype = VTypes::vtUnknown;
p.wnum = 0;
p_dummy.bitreg->bvec[nbit] = std::move(p);
dinfo << myname << "(initItem): add bit register: " << p_dummy.bitreg.get() << endl;
iomap[mbreg] = std::move(p_dummy);
}
return true;
}
string vt(IOBase::initProp(it,"vtype",prop_prefix,false));
if( vt.empty() )
{
......@@ -914,11 +971,31 @@ bool MBSlave::initItem( UniXML::iterator& it )
return true;
}
// ------------------------------------------------------------------------------------------
bool MBSlave::BitRegProperty::check( const IOController_i::SensorInfo& si )
{
for( auto& i: bvec )
{
if( i.si.id == si.id && i.si.node == si.node )
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------
void MBSlave::initIterators()
{
auto it=iomap.begin();
for( ; it!=iomap.end(); ++it )
{
shm->initIterator(it->second.ioit);
if( it->second.bitreg )
{
auto b = it->second.bitreg;
for( auto i=b->bvec.begin(); i!= b->bvec.end(); ++ i )
shm->initIterator(i->ioit);
}
}
shm->initIterator(itHeartBeat);
shm->initIterator(itAskCount);
......@@ -986,12 +1063,28 @@ std::shared_ptr<MBSlave> MBSlave::init_mbslave( int argc, const char* const* arg
return make_shared<MBSlave>(ID,icID,ic,prefix);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBSlave::BitRegProperty* p )
{
return os << (*p);
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBSlave::BitRegProperty& p )
{
os << " reg=" << ModbusRTU::dat2str(p.mbreg) << "(" << (int)p.mbreg << ")[ ";
for( auto& i: p.bvec )
os << "'" << i.si.id << "' ";
os << "]";
return os;
}
// -----------------------------------------------------------------------------
std::ostream& operator<<( std::ostream& os, MBSlave::IOProperty& p )
{
os << " reg=" << ModbusRTU::dat2str(p.mbreg)
os << " reg=" << ModbusRTU::dat2str(p.mbreg) << "(" << (int)p.mbreg << ")"
<< " sid=" << p.si.id
<< " stype=" << p.stype
<< " wnum=" << p.wnum
<< " nbyte=" << p.nbyte
<< " safety=" << p.safety
<< " invert=" << p.invert;
......@@ -1060,7 +1153,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( ModbusRTU::ModbusData reg, Modbus
int count )
{
dinfo << myname << "(much_real_write): read mbID="
<< ModbusRTU::dat2str(reg) << " count=" << count << endl;
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ")" << " count=" << count << endl;
int i=0;
......@@ -1316,7 +1409,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR
int count )
{
dinfo << myname << "(much_real_read): read mbID="
<< ModbusRTU::dat2str(reg) << " count=" << count << endl;
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ") " << " count=" << count << endl;
auto it = iomap.end();
int i=0;
......@@ -1362,7 +1455,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( ModbusRTU::ModbusData reg, ModbusR
ModbusRTU::mbErrCode MBSlave::real_read( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val )
{
dinfo << myname << "(real_read): read mbID="
<< ModbusRTU::dat2str(reg) << endl;
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ")" << endl;
auto it = iomap.find(reg);
return real_read_it(it,val);
......@@ -1373,12 +1466,50 @@ ModbusRTU::mbErrCode MBSlave::real_read_it( IOMap::iterator& it, ModbusRTU::Modb
if( it == iomap.end() )
return ModbusRTU::erBadDataAddress;
try
{
dinfo << myname << "(real_read_it): read mbID="
<< ModbusRTU::dat2str(it->first) << endl;
<< ModbusRTU::dat2str(it->first) << "(" << (int)it->first << ")" << endl;
IOProperty* p(&it->second);
if( p->bitreg )
return real_bitreg_read_it(p->bitreg,val);
return real_read_prop(p,val);
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val )
{
dinfo << myname << "(real_bitreg_read_it): read mbID="
<< ModbusRTU::dat2str(bp->mbreg) << "(" << (int)bp->mbreg << ")" << endl;
ModbusRTU::DataBits16 d;
for( int i=0; i<ModbusRTU::BitsPerData; i++ )
{
IOProperty* p(&(bp->bvec[i]));
if( p->si.id == DefaultObjectId )
{
d.set(i,0);
continue;
}
ModbusRTU::ModbusData v = 0;
ModbusRTU::mbErrCode err = real_read_prop(p,v);
if( err == ModbusRTU::erNoError )
d.set(i,(bool)v);
else
d.set(i,0);
}
val = d.mdata();
return ModbusRTU::erNoError;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val )
{
try
{
val = 0;
if( p->amode == MBSlave::amWO )
......@@ -1563,8 +1694,62 @@ ModbusRTU::mbErrCode MBSlave::fileTransfer( ModbusRTU::FileTransferMessage& quer
ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query,
ReadCoilRetMessage& reply )
{
// cout << "(readInputStatus): " << query << endl;
return ModbusRTU::erOperationFailed;
dinfo << myname << "(readCoilStatus): " << query << endl;
try
{
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start,d);
reply.addData(0);
if( ret == ModbusRTU::erNoError )
reply.setBit(0,0,d);
else
reply.setBit(0,0,0);
pingOK = true;
return ret;
}
much_real_read(query.start,buf,query.count);
int bnum = 0;
unsigned int i=0;
while( i<query.count )
{
reply.addData(0);
for( auto nbit=0; nbit<BitsPerByte && i<query.count; nbit++,i++ )
reply.setBit(bnum,nbit,(bool)(buf[i]));
bnum++;
}
pingOK = true;
return ModbusRTU::erNoError;
}
catch( UniSetTypes::NameNotFound& ex )
{
dwarn << myname << "(readCoilStatus): " << ex << endl;
return ModbusRTU::erBadDataAddress;
}
catch( const Exception& ex )
{
if( pingOK )
dcrit << myname << "(readCoilStatus): " << ex << endl;
}
catch( const CORBA::SystemException& ex )
{
if( pingOK )
dcrit << myname << "(readCoilStatus): СORBA::SystemException: "
<< ex.NP_minorString() << endl;
}
catch(...)
{
if( pingOK )
dcrit << myname << "(readCoilStatus): catch ..." << endl;
}
pingOK = false;
return ModbusRTU::erTimeOut;
}
// -------------------------------------------------------------------------
ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
......@@ -1588,7 +1773,6 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
return ret;
}
// Фомирование ответа:
much_real_read(query.start,buf,query.count);
int bnum = 0;
unsigned int i=0;
......@@ -1596,7 +1780,7 @@ ModbusRTU::mbErrCode MBSlave::readInputStatus( ReadInputStatusMessage& query,
{
reply.addData(0);
for( auto nbit=0; nbit<BitsPerByte && i<query.count; nbit++,i++ )
reply.setBit(bnum,nbit,buf[i]);
reply.setBit(bnum,nbit,(bool)(buf[i]));
bnum++;
}
......
......@@ -278,6 +278,8 @@ class MBSlave:
amWO
};
struct BitRegProperty;
struct IOProperty:
public IOBase
{
......@@ -287,6 +289,7 @@ class MBSlave:
int wnum; /*!< номер слова (для типов с размеров больше 2х байт */
int nbyte; /*!< номер байта, который надо "сохранить" из "пришедщего в запросе" слова. [1-2] */
bool rawdata; /*!< флаг, что в SM просто сохраняются 4-байта (актуально для типа F4)*/
std::shared_ptr<BitRegProperty> bitreg; /*!< указатель, как признак является ли данный регистр "сборным" из битовых */
IOProperty():
mbreg(0),
......@@ -300,6 +303,23 @@ class MBSlave:
friend std::ostream& operator<<( std::ostream& os, IOProperty& p );
};
struct BitRegProperty
{
typedef std::vector<IOProperty> BitSensorMap;
ModbusRTU::ModbusData mbreg; /*!< к какому регистру относятся биты */
BitSensorMap bvec;
BitRegProperty():mbreg(0),bvec(ModbusRTU::BitsPerData){}
/*! проверка привязан ли данный датчик, к какому-либо биту в этом слове */
bool check( const IOController_i::SensorInfo& si );
friend std::ostream& operator<<( std::ostream& os, BitRegProperty& p );
friend std::ostream& operator<<( std::ostream& os, BitRegProperty* p );
};
inline long getAskCount(){ return askCount; }
protected:
......@@ -403,6 +423,10 @@ class MBSlave:
ModbusRTU::mbErrCode much_real_write( ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count );
ModbusRTU::mbErrCode real_read_it( IOMap::iterator& it, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_read_prop( IOProperty* p, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_write_it( IOMap::iterator& it, ModbusRTU::ModbusData* dat, int& i, int count );
MBSlave();
......
......@@ -153,6 +153,11 @@
<item id="2015" default="2222" accessmode="wo" mbs="1" mbreg="125" iotype="AI" name="TestAccessMode2" textname="Тестовый регистр для проверки access mode"/>
<item id="2016" default="1000" accessmode="rw" mbs="1" mbreg="126" iotype="AI" name="TestAccessMode3" textname="Тестовый регистр для проверки access mode"/>
<!-- nbit test -->
<item id="2017" default="1" mbs="1" mbreg="127" nbit="0" iotype="AI" name="Test nbit 0" textname="Тестовый регистр для проверки nbit"/>
<item id="2018" default="1" mbs="1" mbreg="127" nbit="1" iotype="DI" name="Test nbit 1" textname="Тестовый регистр для проверки nbit"/>
<item id="2019" default="1" mbs="1" mbreg="127" nbit="5" iotype="AI" name="Test nbit 5" textname="Тестовый регистр для проверки nbit"/>
<item id="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/>
</sensors>
......
......@@ -881,7 +881,7 @@ TEST_CASE("(0x66): file transfer")
}
#endif
// -------------------------------------------------------------
TEST_CASE("access mode","[modbus][mbslvae][mbtcpslave]")
{
SECTION("test 'RO' register")
......@@ -943,5 +943,33 @@ TEST_CASE("access mode","[modbus][mbslvae][mbtcpslave]")
REQUIRE( rret.data[0] == 555 );
}
}
// -------------------------------------------------------------
TEST_CASE("Read(0x03,0x04): nbit","[modbus][mbslave][mbtcpslave][nbit]")
{
using namespace VTypes;
InitTest();
SECTION("Test: read nbit..")
{
ModbusRTU::ModbusData tREG = 127;
SECTION("Test: read03")
{
ModbusRTU::ReadOutputRetMessage ret = mb->read03(slaveaddr,tREG,1);
ModbusRTU::DataBits16 d(ret.data[0]);
REQUIRE( d[0] == 1 );
REQUIRE( d[1] == 1 );
REQUIRE( d[5] == 1 );
}
SECTION("Test: read04")
{
ModbusRTU::ReadInputRetMessage ret = mb->read04(slaveaddr,tREG,1);
ModbusRTU::DataBits16 d(ret.data[0]);
REQUIRE( d[0] == 1 );
REQUIRE( d[1] == 1 );
REQUIRE( d[5] == 1 );
}
}
}
// -------------------------------------------------------------
/*! \todo Доделать тесты на считывание с разными prop_prefix.. */
......@@ -12,3 +12,5 @@ cd -
--mbs-name MBSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 20048 --mbs-my-addr 0x01 \
--mbs-askcount-id SVU_AskCount_AS --mbs-respond-id RespondRTU_S --mbs-respond-invert 1 \
--mbs-filter-field mbs --mbs-filter-value 1
# --dlog-add-levels any
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