Commit a4ae6319 authored by Pavel Vainerman's avatar Pavel Vainerman

Merge branch 'devel/mutex'

Conflicts: extensions/lib/VTypes.cc
parents 41e3b871 07b432db
......@@ -933,7 +933,6 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
}
it--;
}
break;
......
......@@ -309,7 +309,7 @@ class MBExchange:
UniSetTypes::ObjectId sidExchangeMode; /*!< иденидентификатор для датчика режима работы */
IOController::IOStateList::iterator itExchangeMode;
long exchangeMode; /*!< режим работы см. ExchangeMode */
long exchangeMode = {emNone}; /*!< режим работы см. ExchangeMode */
std::atomic_bool activated;
int activateTimeout;
......
......@@ -79,9 +79,9 @@ MBSlave::MBSlave( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, cons
// int recv_timeout = conf->getArgParam("--" + prefix + "-recv-timeout",it.getProp("recv_timeout")));
addr = ModbusRTU::str2mbAddr(conf->getArg2Param("--" + prefix + "-my-addr", it.getProp("addr"),"0x01"));
addr = ModbusRTU::str2mbAddr(conf->getArg2Param("--" + prefix + "-my-addr", it.getProp("addr"), "0x01"));
default_mbfunc = conf->getArgPInt("--" + prefix + "-default-mbfunc", it.getProp("default_mbfunc"),0);
default_mbfunc = conf->getArgPInt("--" + prefix + "-default-mbfunc", it.getProp("default_mbfunc"), 0);
mbregFromID = conf->getArgInt("--" + prefix + "-reg-from-id", it.getProp("reg_from_id"));
checkMBFunc = conf->getArgInt("--" + prefix + "-check-mbfunc", it.getProp("check_mbfunc"));
......@@ -90,7 +90,7 @@ MBSlave::MBSlave( UniSetTypes::ObjectId objId, UniSetTypes::ObjectId shmId, cons
respond_id = conf->getSensorID(conf->getArgParam("--" + prefix + "-respond-id", it.getProp("respond_id")));
respond_invert = conf->getArgInt("--" + prefix + "-respond-invert", it.getProp("respond_invert"));
timeout_t reply_tout = conf->getArgPInt("--" + prefix + "-reply-timeout", it.getProp("replyTimeout"),3000);
timeout_t reply_tout = conf->getArgPInt("--" + prefix + "-reply-timeout", it.getProp("replyTimeout"), 3000);
timeout_t aftersend_pause = conf->getArgInt("--" + prefix + "-aftersend-pause", it.getProp("afterSendPause"));
......@@ -899,7 +899,7 @@ bool MBSlave::initItem( UniXML::iterator& it )
int mbfunc = IOBase::initIntProp(it, "mbfunc", prop_prefix, false, default_mbfunc);
p.regID = ModbusRTU::genRegID(p.mbreg,mbfunc);
p.regID = ModbusRTU::genRegID(p.mbreg, mbfunc);
p.amode = MBSlave::amRW;
string am(IOBase::initProp(it, "accessmode", prop_prefix, false));
......@@ -958,18 +958,37 @@ bool MBSlave::initItem( UniXML::iterator& it )
IOProperty p_dummy;
p_dummy.bitreg = make_shared<BitRegProperty>();
p_dummy.bitreg->mbreg = mbreg;
p_dummy.regID = p.regID;
p.vtype = VTypes::vtUnknown;
p.wnum = 0;
p_dummy.bitreg->bvec[nbit] = std::move(p);
p_dummy.bitreg->bvec[nbit] = std::move(p); // после этого p использовать нельзя!
dinfo << myname << "(initItem): add bit register: " << p_dummy.bitreg.get() << endl;
iomap[p.regID] = std::move(p_dummy);
iomap[p_dummy.regID] = std::move(p_dummy);
}
return true;
}
auto i = iomap.find(p.regID);
if( i != iomap.end() )
{
ostringstream err;
err << myname << "(initItem): FAIL ADD sid='" << it.getProp("name") << "'(" << p.si.id << ")"
<< " reg='" << ModbusRTU::dat2str(p.mbreg) << "(" << (int)p.mbreg << ")"
<< " mbfunc=" << mbfunc << " --> regID=" << p.regID
<< " ALREADY ADDED! for sid='" << uniset_conf()->oind->getMapName(i->second.si.id) << "'("
<< i->second.si.id << ") regID=" << i->first
<< " reg='" << ModbusRTU::dat2str(i->second.mbreg) << "(" << (int)i->second.mbreg << ")"
<< " wnum=" << i->second.wnum;
dcrit << err.str() << endl;
//throw SystemError( err.str() );
abort();
}
string vt(IOBase::initProp(it, "vtype", prop_prefix, false));
if( vt.empty() )
......@@ -1015,13 +1034,37 @@ bool MBSlave::initItem( UniXML::iterator& it )
p.vtype = v;
p.wnum = 0;
for( auto i = 0; i < VTypes::wsize(p.vtype); i++ )
// копируем минимум полей, который нужен для обработки.. т.к. нам другие не понадобятся..
int p_wnum = 0;
ModbusData p_mbreg = p.mbreg;
IOController_i::SensorInfo p_si = p.si;
UniversalIO::IOType p_stype = p.stype;
VTypes::VType p_vtype = p.vtype;
int wsz = VTypes::wsize(p_vtype );
int p_regID = p.regID;
// после std::move p - использовать нельзя!
dinfo << myname << "(initItem): add " << p << endl;
iomap[p_regID] = std::move(p);
if( wsz > 1 )
{
p.mbreg += i;
p.wnum += i;
dinfo << myname << "(initItem): add " << p << endl;
p.regID = genRegID(p.mbreg,mbfunc);
iomap[p.regID] = std::move(p);
for( int i = 1; i < wsz; i++ )
{
IOProperty p_dummy;
p_dummy.mbreg = p_mbreg + i;
p_dummy.wnum = p_wnum + i;
p_dummy.si = p_si;
p_dummy.stype = p_stype;
p_dummy.vtype = p_vtype;
p_regID = genRegID(p_dummy.mbreg, mbfunc);
p_dummy.regID = p_regID;
dinfo << myname << "(initItem): add " << p_dummy << endl;
iomap[p_regID] = std::move(p_dummy);
}
}
}
......@@ -1232,7 +1275,7 @@ ModbusRTU::mbErrCode MBSlave::much_real_write( const ModbusRTU::ModbusData reg,
auto it = iomap.end();
int mbfunc = checkMBFunc ? fn : default_mbfunc;
ModbusRTU::RegID regID = genRegID(reg,mbfunc);
ModbusRTU::RegID regID = genRegID(reg, mbfunc);
for( ; i < count; i++ )
{
......@@ -1277,7 +1320,7 @@ ModbusRTU::mbErrCode MBSlave::real_write( const ModbusRTU::ModbusData reg, Modbu
<< " data=" << ModbusRTU::dat2str(mbval)
<< "(" << (int)mbval << ")" << endl;
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg,fn) : genRegID(reg,default_mbfunc);
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg, fn) : genRegID(reg, default_mbfunc);
auto it = iomap.find(regID);
return real_write_it(it, dat, i, count);
......@@ -1439,6 +1482,7 @@ ModbusRTU::mbErrCode MBSlave::real_write_prop( IOProperty* p, ModbusRTU::ModbusD
VTypes::F2 f2(d, VTypes::F2::wsize());
delete[] d;
IOBase::processingFasAI( p, (float)f2, shm, force );
}
else if( p->vtype == VTypes::vtF2r )
......@@ -1473,6 +1517,7 @@ ModbusRTU::mbErrCode MBSlave::real_write_prop( IOProperty* p, ModbusRTU::ModbusD
VTypes::F4 f4(d, VTypes::F4::wsize());
delete[] d;
IOBase::processingFasAI( p, (float)f4, shm, force );
}
else if( p->vtype == VTypes::vtByte )
......@@ -1539,11 +1584,12 @@ ModbusRTU::mbErrCode MBSlave::much_real_read( const ModbusRTU::ModbusData reg, M
auto it = iomap.end();
int i = 0;
ModbusRTU::RegID regID = genRegID(reg,mbfunc);
ModbusRTU::RegID regID = genRegID(reg, mbfunc);
for( ; i < count; i++ )
{
it = iomap.find(regID+i);
it = iomap.find(regID + i);
if( it != iomap.end() )
{
regID += i;
......@@ -1588,7 +1634,7 @@ ModbusRTU::mbErrCode MBSlave::real_read( const ModbusRTU::ModbusData reg, Modbus
dinfo << myname << "(real_read): read mbID="
<< ModbusRTU::dat2str(reg) << "(" << (int)reg << ")" << " fn=" << fn << endl;
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg,fn) : genRegID(reg,default_mbfunc);
ModbusRTU::RegID regID = checkMBFunc ? genRegID(reg, fn) : genRegID(reg, default_mbfunc);
auto it = iomap.find(regID);
return real_read_it(it, val);
......@@ -1779,7 +1825,7 @@ mbErrCode MBSlave::readInputRegisters( ReadInputMessage& query, ReadInputRetMess
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d,query.func);
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
if( ret == ModbusRTU::erNoError )
reply.addData(d);
......@@ -1838,7 +1884,7 @@ ModbusRTU::mbErrCode MBSlave::readCoilStatus( ReadCoilMessage& query,
if( query.count <= 1 )
{
ModbusRTU::ModbusData d = 0;
ModbusRTU::mbErrCode ret = real_read(query.start, d,query.func);
ModbusRTU::mbErrCode ret = real_read(query.start, d, query.func);
reply.addData(0);
if( ret == ModbusRTU::erNoError )
......
......@@ -127,6 +127,12 @@
- 1 - в качестве регистра использовать идентификатор датчика
- 0 - регистр брать из поля tcp_mbreg
\b --xxx-default-mbfunc или \b default_mbfunc [0...255] - Функция подставляемая по умолчанию, если не указан параметр mbfunc. Действует только если включён контроль функций (check-mbfunc).
\b --xxx-check-mbfunc [0|1] -
- 1 - включить контроль (обработку) свойства mbfunc. По умолчанию: отключёна. Если контроль включён то разрешено
использовать один и тот же регистр но \b для \b разных \b функций.
- 0 - игнорировать свойство mbfunc..
\b --xxx-heartbeat-id или \b heartbeat_id ID - идентификатор датчика "сердцебиения" (см. \ref sec_SM_HeartBeat)
\b --xxx-heartbeat-max или \b heartbeat_max val - сохраняемое значение счётчика "сердцебиения".
......@@ -415,7 +421,7 @@ class MBSlave:
xmlNode* cnode;
std::string s_field;
std::string s_fvalue;
int default_mbfunc={0}; // функция по умолчанию, для вычисления RegID
int default_mbfunc = {0}; // функция по умолчанию, для вычисления RegID
std::shared_ptr<SMInterface> shm;
......@@ -440,11 +446,11 @@ class MBSlave:
void readConfiguration();
bool check_item( UniXML::iterator& it );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn=0 );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn=0 );
ModbusRTU::mbErrCode real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn=0 );
ModbusRTU::mbErrCode much_real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn=0 );
ModbusRTU::mbErrCode much_real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn=0 );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData val, const int fn = 0 );
ModbusRTU::mbErrCode real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int& i, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData& val, const int fn = 0 );
ModbusRTU::mbErrCode much_real_read( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode much_real_write( const ModbusRTU::ModbusData reg, ModbusRTU::ModbusData* dat, int count, const int fn = 0 );
ModbusRTU::mbErrCode real_read_it( IOMap::iterator& it, ModbusRTU::ModbusData& val );
ModbusRTU::mbErrCode real_bitreg_read_it( std::shared_ptr<BitRegProperty>& bp, ModbusRTU::ModbusData& val );
......@@ -484,8 +490,8 @@ class MBSlave:
timeout_t wait_msec;
bool force; /*!< флаг означающий, что надо сохранять в SM, даже если значение не менялось */
bool mbregFromID={0};
bool checkMBFunc={0};
bool mbregFromID = {0};
bool checkMBFunc = {0};
typedef std::unordered_map<int, std::string> FileList;
FileList flist;
......
......@@ -146,7 +146,7 @@
<item id="2009" default="250000" precision="5" mbs="1" mbreg="114" iotype="AI" vtype="F4" name="TestVtype9" textname="Тестовый регистр для проверки vtype"/>
<item default="-100" id="2011" mbs="1" mbreg="118" iotype="AI" vtype="signed" name="TestVtype11" textname="Тестовый регистр для проверки vtype"/>
<item default="65534" id="2012" mbs="1" mbreg="119" iotype="AI" vtype="unsigned" name="TestVtype12" textname="Тестовый регистр для проверки vtype"/>
<item id="2013" rawdata="1" mbs="1" mbreg="120" iotype="AI" vtype="F4" name="TestVtype9" textname="Тестовый регистр для проверки vtype"/>
<item id="2013" rawdata="1" mbs="1" mbreg="120" iotype="AI" vtype="F4" name="TestVtype13" textname="Тестовый регистр для проверки записи vtype"/>
<!-- access mode test -->
<item id="2014" default="1002" accessmode="ro" mbs="1" mbreg="124" iotype="AI" name="TestAccessMode1" textname="Тестовый регистр для проверки access mode"/>
......
......@@ -1030,6 +1030,13 @@ TEST_CASE("Write(0x06,0x10): nbit", "[modbus][mbslave][mbtcpslave][writenbit]")
}
}
}
// -------------------------------------------------------------
TEST_CASE("check-mbfunc", "[modbus][mbslave][mbtcpslave][mbfunc]")
{
using namespace VTypes;
InitTest();
//...
}
// -------------------------------------------------------------
/*! \todo Доделать тесты на считывание с разными prop_prefix.. */
......@@ -11,5 +11,6 @@ cd -
./uniset2-start.sh -f ./tests-with-sm $* -- --confile mbslave-test-configure.xml --e-startup-pause 10 \
--mbs-name MBSlave1 --mbs-type TCP --mbs-inet-addr 127.0.0.1 --mbs-inet-port 20048 --mbs-my-addr 0x01 \
--mbs-askcount-id SVU_AskCount_AS --mbs-respond-id RespondRTU_S --mbs-respond-invert 1 \
--mbs-filter-field mbs --mbs-filter-value 1
--mbs-filter-field mbs --mbs-filter-value 1 --dlog-add-levels any
#--mbs-check-mbfunc 1
#--dlog-add-levels any
......@@ -372,8 +372,7 @@ long IOBase::processingAsAO( IOBase* it, const std::shared_ptr<SMInterface>& shm
if( cal && cal->maxRaw != cal->minRaw ) // задана калибровка
{
// Калибруем в обратную сторону!!!
val = UniSetTypes::lcalibrate(val,
cal->minCal, cal->maxCal, cal->minRaw, cal->maxRaw, it->calcrop );
val = UniSetTypes::lcalibrate(val, cal->minCal, cal->maxCal, cal->minRaw, cal->maxRaw, it->calcrop );
}
}
}
......@@ -521,7 +520,7 @@ bool IOBase::initItem( IOBase* b, UniXML::iterator& it, const std::shared_ptr<SM
if( sid == DefaultObjectId )
{
if( dlog && dlog->is_crit() )
dlog->crit() << myname << "(readItem): (" << DefaultObjectId << ") Не удалось получить ID для датчика: "
dlog->crit() << myname << "(readItem): (" << DefaultObjectId << ") Unknown Sensor ID for "
<< sname << endl;
return false;
......@@ -550,7 +549,6 @@ bool IOBase::initItem( IOBase* b, UniXML::iterator& it, const std::shared_ptr<SM
msec = initIntProp(it, "offdelay", prefix, init_prefix_only, UniSetTimer::WaitUpTime);
b->ptOffDelay.setTiming(msec);
b->front = false;
std::string front_t( initProp(it, "iofront", prefix, init_prefix_only) );
......@@ -583,8 +581,8 @@ bool IOBase::initItem( IOBase* b, UniXML::iterator& it, const std::shared_ptr<SM
if( b->stype == UniversalIO::UnknownIOType )
{
if( dlog && dlog->is_crit() )
dlog->crit() << myname << "(IOBase::readItem): неизвестный iotype=: "
<< initProp(it, "iotype", prefix, init_prefix_only) << " для " << sname << endl;
dlog->crit() << myname << "(IOBase::readItem): Unknown iotype=: "
<< initProp(it, "iotype", prefix, init_prefix_only) << " for " << sname << endl;
return false;
}
......
......@@ -82,7 +82,7 @@ namespace VTypes
return "vtUnknown";
}
// -------------------------------------------------------------------------
int wsize( VType t )
int wsize( const VType t )
{
if( t == vtByte )
return Byte::wsize();
......
......@@ -123,7 +123,7 @@ namespace UniSetTypes
private:
std::string nm;
friend class uniset_rwmutex_lock;
ost::ThreadLock m;
ost::ThreadLock m; // это рекурсивный mutex (!)
};
std::ostream& operator<<(std::ostream& os, uniset_rwmutex& m );
......
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <iostream>
#include <thread>
#include <future>
#include "Mutex.h"
#include "UniSetTypes.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
......@@ -173,3 +176,52 @@ TEST_CASE("uniset_rwmutex_{wr|r}lock", "[mutex][basic]" )
CHECK_FALSE( m.try_lock() );
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
uniset_rwmutex g_mutex;
bool writer_thread( int num )
{
uniset_rwmutex_wrlock l(g_mutex);
msleep(1000);
return true;
}
bool reader_thread( int num )
{
uniset_rwmutex_rlock l(g_mutex);
msleep(50);
return true;
}
// -----------------------------------------------------------------------------
TEST_CASE("uniset_rwmutex_{wr|r} thread lock", "[mutex][threadlock][basic]" )
{
g_mutex.rlock();
std::vector< std::future<bool> > vw(3);
for( int w=0; w<3; w++ )
vw.push_back( std::async(std::launch::async, writer_thread,w) );
std::vector< std::future<bool> > vr(3);
for( int r=0; r<5; r++ )
vr.push_back( std::async(std::launch::async, reader_thread,r) );
msleep(10);
// read захватывают сразу без задержек..
for( auto&& i: vr )
{
if( i.valid() )
REQUIRE( i.get() == true );
}
// теперь отпускаю mutex
g_mutex.unlock();
// проверяем что write-ы завершают работу.
for( auto& i: vw )
{
if( i.valid() )
REQUIRE( i.get() == true );
}
}
// -----------------------------------------------------------------------------
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