Commit 95a8e54d authored by Pavel Vainerman's avatar Pavel Vainerman

backported to p8 as 2.7-alt14.M80P.15 (with rpmbph script)

parents 2a7ac403 c889f396
......@@ -50,6 +50,7 @@ interface IOController_i : UniSetManager_i
*/
exception Undefined
{
long value; // текущее значение (может быть специальным undefined_value)
};
/*! Информация о датчике */
......
......@@ -34,6 +34,7 @@ static struct option longopts[] =
{ "speed", required_argument, 0, 's' },
{ "use485F", no_argument, 0, 'y' },
{ "num-cycles", required_argument, 0, 'l' },
{ "polltime", required_argument, 0, 'p' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
......@@ -67,6 +68,7 @@ static void print_help()
printf("[-a|--myaddr] addr - Modbus address for master. Default: 0x01.\n");
printf("[-s|--speed] speed - 9600,14400,19200,38400,57600,115200. Default: 38400.\n");
printf("[-t|--timeout] msec - Timeout. Default: 2000.\n");
printf("[-p|--polltime] msec - Polling time. Default: 200 msec.\n");
printf("[-l|--num-cycles] num - Number of cycles of exchange. Default: -1 - infinitely.\n");
printf("[-v|--verbose] - Print all messages to stdout\n");
}
......@@ -119,6 +121,7 @@ int main( int argc, char** argv )
string tofile("");
int use485 = 0;
int ncycles = -1;
int polltime = 200;
ModbusRTU::ModbusByte devID = 0;
ModbusRTU::ModbusByte objID = 0;
......@@ -126,7 +129,7 @@ int main( int argc, char** argv )
{
while(1)
{
opt = getopt_long(argc, argv, "hva:w:z:m:r:x:c:b:d:s:t:qn:u:yl:t:o:e:", longopts, &optindex);
opt = getopt_long(argc, argv, "hva:w:z:m:r:x:c:b:d:s:t:qn:u:yl:t:o:e:p:", longopts, &optindex);
if( opt == -1 )
break;
......@@ -274,6 +277,10 @@ int main( int argc, char** argv )
tout = uni_atoi(optarg);
break;
case 'p':
polltime = uni_atoi(optarg);
break;
case 'a':
myaddr = ModbusRTU::str2mbAddr(optarg);
break;
......@@ -298,7 +305,7 @@ int main( int argc, char** argv )
}
}
break;
#if 0
case 'g':
{
if( cmd == cmdNOP )
......@@ -318,7 +325,7 @@ int main( int argc, char** argv )
}
}
break;
#endif
case 'v':
verb = 1;
break;
......@@ -739,7 +746,7 @@ int main( int argc, char** argv )
break;
}
msleep(200);
msleep(polltime);
}
}
catch( ModbusRTU::mbException& ex )
......
......@@ -21,6 +21,7 @@ Usage: ${0##*/} [options] programm [arguments]
Valid options are:
-h, --help display help screen
-o, --omni-port print default omni port for current user
-f, --foreground start programm on foreground. Default 'background'.
-g, --gdb start programm with gdb
......@@ -39,15 +40,22 @@ EOF
#parse command line options
case "$1" in
-h|--help) print_usage 0;;
-f|--foreground) FG=1;;
-f|--foreground) FG=1;;
-o|--omni-port) OPORT="omni-port";;
-vmem|--vg-memcheck) DBG="mem";;
-vcall|--vg-callgrind) DBG="call";;
-vcache|--vg-cachegrind) DBG="cache";;
-vhel|--vg-helgrind) DBG="hel";;
-vhel|--vg-helgrind) DBG="hel";;
-g|--gdb) DBG="gdb";;
esac
shift
if [ -n "$OPORT" ]
then
echo "Uniset default omni port for user '$USER': $OMNIPORT"
exit 0
fi
if [ -n "$DBG" ]
then
COMLINE="$* --uniset-port $OMNIPORT"
......
......@@ -26,7 +26,7 @@
Name: libuniset2
Version: 2.7
Release: alt13.M80P.14
Release: alt14.M80P.15
Summary: UniSet - library for building distributed industrial control systems
License: LGPL
......@@ -546,9 +546,19 @@ rm -f %buildroot%_docdir/%oname/html/*.md5
# history of current unpublished changes
%changelog
* Thu Aug 02 2018 Pavel Vainerman <pv@altlinux.ru> 2.7-alt13.M80P.14
* Tue Sep 04 2018 Pavel Vainerman <pv@altlinux.ru> 2.7-alt14.M80P.15
- backport to ALTLinux p8 (by rpmbph script)
* Tue Sep 04 2018 Pavel Vainerman <pv@altlinux.ru> 2.7-alt15
- (mtr): fix bug for read from 'serial device'
- (UNet): added "undefined_value" property
- (SM): added undefined value for IOController
- (RTU): minor fixes (catch exceptions)
- (UNetUDP): check byte order
- (UNetUDP): encoding is not used if the byte order is the same as the system
- (ComPort485F): added error handling for read
- (mbrtutest): added 'polltime' option eterbug #13154
* Thu Aug 02 2018 Pavel Vainerman <pv@altlinux.ru> 2.7-alt14
- remove deprecated classes
- (SM): fixed bug 'uninitialized time value'
......
......@@ -193,9 +193,23 @@ void RTUExchange::step()
}
catch(...) {}
poll();
try
{
poll();
}
catch( std::exception& ex )
{
mbwarn << myname << "(step): poll error: " << ex.what() << endl;
}
MBExchange::step();
try
{
MBExchange::step();
}
catch( std::exception& ex )
{
mbwarn << myname << "(step): MBExchange::step error: " << ex.what() << endl;
}
}
// -----------------------------------------------------------------------------
bool RTUExchange::poll()
......@@ -298,7 +312,7 @@ bool RTUExchange::poll()
<< " reg=" << ModbusRTU::dat2str(it->second->mbreg)
<< " for sensors: ";
print_plist(dlog()->level3(), it->second->slst);
dlog()->level3() << " err: " << ex << endl;
dlog()->level3(false) << " err: " << ex << endl;
}
if( it == rmap->end() )
......
......@@ -98,7 +98,7 @@ int main( int argc, char** argv )
int use485 = 0;
int ncycles = -1;
MTR::MTRType mtrtype = MTR::mtUnknown;
string iaddr("127.0.0.1");
std::string iaddr;
int port = 502;
bool ignoreErrors = false;
......
......@@ -131,6 +131,9 @@
<item id="1064" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="208" mbfunc="0x03" vtype="F2" iotype="AI" name="TestQueryOptimization5_F2" textname="F2: Тестовый регистр для 0x03"/>
<item id="1065" mb="1" mbtype="rtu" mbaddr="0x01" mbreg="210" mbfunc="0x03" vtype="F2" iotype="AI" name="TestQueryOptimization6_F2" textname="F2: Тестовый регистр для 0x03"/>
<!-- 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="10000" iotype="DI" name="TestMode_S" textname="Тестовый датчик"/>
</sensors>
......
......@@ -15,7 +15,7 @@ cd -
--mbtcp-filter-value 1 \
--mbtcp-gateway-iaddr localhost \
--mbtcp-gateway-port 20048 \
--mbtcp-polltime 50 --mbtcp-recv-timeout 500
--mbtcp-polltime 50 --mbtcp-recv-timeout 500
#--mbtcp-log-add-levels any
#--mbtcp-default-mbinit-ok 1
#--dlog-add-levels any
......
......@@ -741,6 +741,31 @@ TEST_CASE("MBTCPMaster: safe mode (resetIfNotRespond)", "[modbus][safemode][mbma
REQUIRE( ui->getValue(1054) == 1 );
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: udefined value", "[modbus][undefined][mbmaster][mbtcpmaster]")
{
InitTest();
mbs->setReply(120);
msleep(polltime + 200);
REQUIRE( ui->getValue(1070) == 120 );
mbs->setReply(10);
msleep(polltime + 200);
try
{
ui->getValue(1070);
}
catch( IOController_i::Undefined& ex )
{
REQUIRE( ex.value == 65535 );
}
mbs->setReply(120);
msleep(polltime + 200);
REQUIRE( ui->getValue(1070) == 120 );
}
// -----------------------------------------------------------------------------
#if 0
// -----------------------------------------------------------------------------
static bool init_iobase( IOBase* ib, const std::string& sensor )
......
......@@ -221,5 +221,35 @@ TEST_CASE("MBTCPMaster: safe mode (resetIfNotRespond)", "[modbus][safemode][mbma
msleep(5000);
REQUIRE( ui->getValue(1053) == 53 );
REQUIRE( ui->getValue(1054) == 1 );
mbs1->setReply(0);
mbs2->setReply(0);
}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMaster: udefined value", "[modbus][undefined][mbmaster][mbtcpmaster]")
{
InitTest();
mbs1->setReply(120);
mbs2->setReply(120);
msleep(polltime + 200);
REQUIRE( ui->getValue(1070) == 120 );
mbs1->setReply(10);
mbs2->setReply(10);
msleep(polltime + 200);
try
{
ui->getValue(1070);
}
catch( IOController_i::Undefined& ex )
{
REQUIRE( ex.value == 65535 );
}
mbs1->setReply(120);
mbs2->setReply(120);
msleep(polltime + 200);
REQUIRE( ui->getValue(1070) == 120 );
}
// -----------------------------------------------------------------------------
......@@ -769,7 +769,8 @@ namespace uniset
}
catch( IOController_i::Undefined& ex )
{
hit.add( numeric_limits<long>::max(), it.size );
hit.add( ex.value, it.size );
// hit.add( numeric_limits<long>::max(), it.size );
}
catch(...) {}
}
......
......@@ -14,16 +14,42 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// -------------------------------------------------------------------------
#include <cstdint>
#include <endian.h>
#include "UDPPacket.h"
// -------------------------------------------------------------------------
// сделано так, чтобы макросы раскрывались в "пустоту" если не требуется преобразование
// поэтому использование выглядит как LE_TO_H( myvar ), а не
// myvar = LE_TO_H(myvar)
// -------------------------------------------------------------------------
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LE_TO_H(x) {}
#elif INTPTR_MAX == INT64_MAX
#define LE_TO_H(x) x = le64toh(x)
#elif INTPTR_MAX == INT32_MAX
#define LE_TO_H(x) x = le32toh(x)
#else
#error UNET(LE_TO_H): Unknown byte order or size of pointer
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define BE_TO_H(x) {}
#elif INTPTR_MAX == INT64_MAX
#define BE_TO_H(x) x = be64toh(x)
#elif INTPTR_MAX == INT32_MAX
#define BE_TO_H(x) x = be32toh(x)
#else
#error UNET(BE_TO_H): Unknown byte order or size of pointer
#endif
// -------------------------------------------------------------------------
namespace uniset
{
// -----------------------------------------------------------------------------
// ---------------------------------------------------------------------
using namespace std;
using namespace UniSetUDP;
// -----------------------------------------------------------------------------
// ---------------------------------------------------------------------
#define USE_CRC_TAB 1 // при расчёте использовать таблицы
// -------------------------------------------------------------------------
// ---------------------------------------------------------------------
#ifdef USE_CRC_TAB
static unsigned short crc_16_tab[] =
{
......@@ -291,6 +317,37 @@ namespace uniset
memcpy(&m, &(p.data[i]), sizeof(UDPHeader));
i += sizeof(UDPHeader);
// byte order from packet
u_char be_order = m._be_order;
if( be_order )
{
BE_TO_H(m.magic);
BE_TO_H(m.num);
BE_TO_H(m.procID);
BE_TO_H(m.nodeID);
BE_TO_H(m.dcount);
BE_TO_H(m.acount);
}
else
{
LE_TO_H(m.magic);
LE_TO_H(m.num);
LE_TO_H(m.procID);
LE_TO_H(m.nodeID);
LE_TO_H(m.dcount);
LE_TO_H(m.acount);
}
// set host byte order
#if __BYTE_ORDER == __LITTLE_ENDIAN
m._be_order = 0;
#elif __BYTE_ORDER == __BIG_ENDIAN
m. be_order = 1;
#else
#error UNET(getMessage): Unknown byte order!
#endif
// проверяем наш ли пакет..
if( m.magic != UniSetUDP::UNETUDP_MAGICNUM )
{
......@@ -326,6 +383,34 @@ namespace uniset
memcpy(m.d_dat, &(p.data[i]), sz);
// CONVERT DATA TO HOST BYTE ORDER
// -------------------------------
for( size_t n = 0; n < m.acount; n++ )
{
if( be_order )
{
BE_TO_H(m.a_dat[n].id);
BE_TO_H(m.a_dat[n].val);
}
else
{
LE_TO_H(m.a_dat[n].id);
LE_TO_H(m.a_dat[n].val);
}
}
for( size_t n = 0; n < m.dcount; n++ )
{
if( be_order )
{
BE_TO_H(m.d_id[n]);
}
else
{
LE_TO_H(m.d_id[n]);
}
}
return i + sz;
}
// -----------------------------------------------------------------------------
......@@ -337,5 +422,22 @@ namespace uniset
crc[2] = makeCRC( (unsigned char*)(d_dat), sizeof(d_dat) );
return makeCRC( (unsigned char*)(&crc), sizeof(crc) );
}
UDPHeader::UDPHeader() noexcept
: magic(UNETUDP_MAGICNUM)
#if __BYTE_ORDER == __LITTLE_ENDIAN
, _be_order(0)
#elif __BYTE_ORDER == __BIG_ENDIAN
, _be_order(1)
#else
#error UNET: Unknown byte order!
#endif
, num(0)
, nodeID(0)
, procID(0)
, dcount(0)
, acount(0)
{}
// -----------------------------------------------------------------------------
} // end of namespace uniset
......@@ -38,14 +38,24 @@ namespace uniset
\warning ТЕКУЩАЯ ВЕРСИЯ ПРОТОКОЛА НЕ БУДЕТ РАБОТАТЬ МЕЖДУ 32-битными и 64-битными системами (из-за отличия в типе long).
т.к. это не сильно актуально, пока не переделываю.
"ByteOrder"
============
В текущей версии протокола. В UDPHeader содержиться информации о порядке байт.
Поэтому логика следующая:
- Узел который посылает, ничего не перекодирует и просто посылает данные так как хранит
(информация о порядке байт, если специально не выставить, будет выставлена при компиляции, см. конструктор)
- Узел который принимает данные, декодирует их, если на его узле порядок байт не совпадает.
Т.е. если все узлы будут иметь одинаковый порядок байт, фактического перекодирования не будет.
*/
const uint32_t UNETUDP_MAGICNUM = 0x1337A1D; // идентификатор протокола
const uint32_t UNETUDP_MAGICNUM = 0x133EF54; // идентификатор протокола
struct UDPHeader
{
UDPHeader() noexcept: magic(UNETUDP_MAGICNUM), num(0), nodeID(0), procID(0), dcount(0), acount(0) {}
UDPHeader() noexcept;
uint32_t magic;
u_char _be_order; // 1 - BE byte order, 0 - LE byte order
size_t num;
long nodeID;
long procID;
......@@ -74,6 +84,8 @@ namespace uniset
// Теоретический размер данных в UDP пакете (исключая заголовки) 65507
// Фактически желательно не вылезать за размер MTU (обычно 1500) - заголовки = 1432 байта
// т.е. надо чтобы sizeof(UDPPacket) < 1432
// с другой стороны в текущей реализации
// в сеть посылается фактическое количество данных, а не sizeof(UDPPacket).
// При текущих настройках sizeof(UDPPacket) = 32654 (!)
static const size_t MaxACount = 1500;
......
......@@ -103,7 +103,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const
nodes = conf->findNode(xml->getFirstNode(), nconfname);
}
unetinfo << myname << "(init): init from <" << nconfname << ">" << endl;
unetinfo << myname << "(init): init from <" << nconfname << ">" << endl;
if( !nodes )
throw uniset::SystemError("(UNetExchange): Not found confnode <" + nconfname + ">");
......
......@@ -152,8 +152,25 @@ namespace uniset
for( auto && it : items )
{
UItem& i = it.second;
long value = shm->localGetValue(i.ioit, i.id);
updateItem(i, value);
try
{
long value = shm->localGetValue(i.ioit, i.id);
updateItem(i, value);
}
catch( IOController_i::Undefined& ex )
{
unetwarn << myname << "(updateFromSM): sid=" << i.id
<< " undefined state (value=" << ex.value << ")." << endl;
updateItem( i, ex.value );
}
catch( std::exception& ex )
{
unetwarn << myname << "(updateFromSM): " << ex.what() << endl;
if( i.undefined_value != not_specified_value )
updateItem( i, i.undefined_value );
}
}
}
// -----------------------------------------------------------------------------
......@@ -293,7 +310,6 @@ namespace uniset
if( packetnum == 0 )
packetnum = 1;
if( !udp || !udp->poll( UniSetTimer::millisecToPoco(writeTimeout), Poco::Net::Socket::SELECT_WRITE) )
return;
......@@ -399,6 +415,9 @@ namespace uniset
p.iotype = uniset::getIOType(it.getProp("iotype"));
p.pack_sendfactor = priority;
if( !it.getProp("undefined_value").empty() )
p.undefined_value = it.getIntProp("undefined_value");
if( p.iotype == UniversalIO::UnknownIOType )
{
unetcrit << myname << "(readItem): Unknown iotype for sid=" << sid << endl;
......
......@@ -20,6 +20,7 @@
#include <ostream>
#include <string>
#include <vector>
#include <limits>
#include <unordered_map>
#include "UniSetObject.h"
#include "Trigger.h"
......@@ -76,6 +77,8 @@ namespace uniset
typedef size_t sendfactor_t;
static const long not_specified_value = { std::numeric_limits<long>::max() };
struct UItem
{
UItem():
......@@ -91,6 +94,7 @@ namespace uniset
size_t pack_num;
size_t pack_ind;
sendfactor_t pack_sendfactor = { 0 };
long undefined_value = { not_specified_value };
friend std::ostream& operator<<( std::ostream& os, UItem& p );
};
......
......@@ -56,7 +56,7 @@ void InitTest()
// -----------------------------------------------------------------------------
// pnum - минималный номер ожидаемого пакета ( 0 - любой пришедщий )
// ncycle - сколько пакетов разрешено "пропустить" прежде чем дождёмся нужного.. (чтобы не ждать бесконечно)
static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 2000, int ncycle = 10 )
static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 2000, int ncycle = 20 )
{
UniSetUDP::UDPMessage pack;
UniSetUDP::UDPPacket buf;
......@@ -76,6 +76,9 @@ static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 20
ncycle--;
}
// if( pnum > 0 && pack.num < pnum )
// return UniSetUDP::UDPMessage(); // empty message
return pack;
}
// -----------------------------------------------------------------------------
......@@ -300,7 +303,7 @@ TEST_CASE("[UNetUDP]: check receiver", "[unetudp][receiver]")
REQUIRE( ui->getValue(11) == 0 );
send(pack);
msleep(500);
msleep(600);
REQUIRE( ui->getValue(8) == 100 );
REQUIRE( ui->getValue(9) == -100 );
REQUIRE( ui->getValue(10) == 1 );
......@@ -318,7 +321,7 @@ TEST_CASE("[UNetUDP]: check receiver", "[unetudp][receiver]")
pack.addDData(10, false);
pack.addDData(11, true);
send(pack);
msleep(500);
msleep(600);
REQUIRE( ui->getValue(8) == 10 );
REQUIRE( ui->getValue(9) == -10 );
REQUIRE( ui->getValue(10) == 0 );
......@@ -468,3 +471,42 @@ TEST_CASE("[UNetUDP]: switching channels", "[unetudp][chswitch]")
REQUIRE( ui->getValue(node1_numchannel_as) == 1 );
}
// -----------------------------------------------------------------------------
TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][sender]")
{
InitTest();
UniSetUDP::UDPMessage pack0 = receive();
ui->setValue(2, 110);
REQUIRE( ui->getValue(2) == 110 );
msleep(600);
UniSetUDP::UDPMessage pack = receive( pack0.num + 1, 2000, 40 );
REQUIRE( pack.num != 0 );
REQUIRE( pack.asize() == 4 );
REQUIRE( pack.dsize() == 2 );
REQUIRE( pack.a_dat[0].val == 110 );
IOController_i::SensorInfo si;
si.id = 2;
si.node = uniset_conf()->getLocalNode();
ui->setUndefinedState(si, true, 6000 /* TestProc */ );
msleep(600);
pack = receive(pack.num + 1);
REQUIRE( pack.num != 0 );
REQUIRE( pack.asize() == 4 );
REQUIRE( pack.dsize() == 2 );
REQUIRE( pack.a_dat[0].val == 65635 );
ui->setUndefinedState(si, false, 6000 /* TestProc */ );
msleep(600);
pack = receive(pack.num + 1);
REQUIRE( pack.num != 0 );
REQUIRE( pack.asize() == 4 );
REQUIRE( pack.dsize() == 2 );
REQUIRE( pack.a_dat[0].val == 110 );
}
// -----------------------------------------------------------------------------
......@@ -43,7 +43,7 @@
<item id="100" iotype="DI" name="TestMode_S" textname="Test sensor"/>
<item id="1" iotype="DI" name="Node1_Not_Respond_S" textname="Node1 not respond"/>
<item id="2" iotype="AI" name="AI1_S" textname="AI sensor 1" unet="1" default="1"/>
<item id="2" iotype="AI" name="AI1_S" textname="AI sensor 1" unet="1" default="1" undefined_value="65635"/>
<item id="3" iotype="AI" name="AI2_S" textname="AI sensor 2" unet="1" default="2"/>
<item id="4" iotype="AI" name="AI3_S" textname="AI sensor 3" unet="1" default="3"/>
<item id="5" iotype="AI" name="AI4_S" textname="AI sensor 4" unet="1" default="4"/>
......
......@@ -24,6 +24,7 @@
//---------------------------------------------------------------------------
#include <unordered_map>
#include <list>
#include <limits>
#include <sigc++/sigc++.h>
#include "IOController_i.hh"
#include "UniSetTypes.h"
......@@ -59,15 +60,14 @@ namespace uniset
virtual uniset::SimpleInfo* getInfo( const char* userparam = "" ) override;
// ----------------------------------------------------------------
// Публичный (IDL) интерфейс IOController_i
// ----------------------------------------------------------------
virtual CORBA::Long getValue( uniset::ObjectId sid ) override;
// -------------------- !!!!!!!!! ---------------------------------
// Реализуются конкретным i/o контроллером
// Не забывайте писать реализацию этих функций
virtual void setValue( uniset::ObjectId sid, CORBA::Long value,
uniset::ObjectId sup_id = uniset::DefaultObjectId ) override;
// ----------------------------------------------------------------
virtual void setUndefinedState( uniset::ObjectId sid,
CORBA::Boolean undefined,
uniset::ObjectId sup_id = uniset::DefaultObjectId ) override;
......@@ -116,6 +116,8 @@ namespace uniset
struct USensorInfo;
typedef std::unordered_map<uniset::ObjectId, std::shared_ptr<USensorInfo>> IOStateList;
static const long not_specified_value = { std::numeric_limits<long>::max() };
// ================== Достпуные сигналы =================
/*!
// \warning В сигнале напрямую передаётся указатель на внутреннюю структуру!
......@@ -330,6 +332,8 @@ namespace uniset
size_t nchanges = { 0 }; // количество изменений датчика
long undef_value = { not_specified_value }; // значение для "неопределённого состояния датчика"
// функция обработки информации об изменении состояния датчика, от которого зависит данный
void checkDepend( std::shared_ptr<USensorInfo>& d_usi, IOController* );
......
......@@ -125,6 +125,9 @@ unsigned char ComPort485F::m_receiveByte( bool wait )
{
rc = ::read(fd, tbuf, sizeof(tbuf));
if( rc < 0 && errno != EAGAIN )
break;
if( rc > 0 )
{
if( remove_echo(tbuf, rc) )
......@@ -144,6 +147,9 @@ unsigned char ComPort485F::m_receiveByte( bool wait )
{
rc = ::read(fd, tbuf, sizeof(tbuf));
if( rc < 0 && errno != EAGAIN )
break;
if( rc > 0 )
{
if( remove_echo(tbuf, rc) )
......@@ -302,6 +308,9 @@ void ComPort485F::m_read( timeout_t tmsec )
{
rc = ::read(fd, tbuf, sizeof(tbuf));
if( rc < 0 && errno != EAGAIN )
break;
if( rc > 0 )
{
if( remove_echo(tbuf, rc) )
......
......@@ -213,6 +213,9 @@ namespace uniset
inf->undefined = false;
inf->real_value = inf->value;
if( !it.getProp("undefined_value").empty() )
inf->undef_value = it.getIntProp("undefined_value");
string d_txt( it.getProp("depend") );
if( !d_txt.empty() )
......
......@@ -163,7 +163,11 @@ long IOController::localGetValue( std::shared_ptr<USensorInfo>& usi )
uniset_rwmutex_rlock lock(usi->val_lock);
if( usi->undefined )
throw IOController_i::Undefined();
{
auto ex = IOController_i::Undefined();
ex.value = usi->value;
throw ex;
}
return usi->value;
}
......@@ -198,10 +202,19 @@ void IOController::localSetUndefinedState( IOStateList::iterator& li,
bool changed = false;
{
auto usi = li->second;
// lock
uniset_rwmutex_wrlock lock(li->second->val_lock);
changed = (li->second->undefined != undefined);
li->second->undefined = undefined;
uniset_rwmutex_wrlock lock(usi->val_lock);
changed = (usi->undefined != undefined);
usi->undefined = undefined;
if( usi->undef_value != not_specified_value )
{
if( undefined )
usi->value = usi->undef_value;
else
usi->value = usi->real_value;
}
} // unlock
// сперва локальные события...
......
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