Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
U
uniset2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UniSet project repositories
uniset2
Commits
a15d2cc4
Commit
a15d2cc4
authored
Oct 31, 2011
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(Modbus): продолжаю работу над выносом общего кода в MBTCPMaster и RTUExchange
parent
dfb56568
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
2400 additions
and
2422 deletions
+2400
-2422
MBTCPMaster.cc
extensions/MBTCPMaster/MBTCPMaster.cc
+157
-2386
RTUExchange.h
extensions/RTUExchange/RTUExchange.h
+0
-2
MBExchange.cc
extensions/lib/MBExchange.cc
+2243
-34
No files found.
extensions/MBTCPMaster/MBTCPMaster.cc
View file @
a15d2cc4
...
...
@@ -12,48 +12,19 @@ using namespace UniSetExtensions;
// -----------------------------------------------------------------------------
MBTCPMaster
::
MBTCPMaster
(
UniSetTypes
::
ObjectId
objId
,
UniSetTypes
::
ObjectId
shmId
,
SharedMemory
*
ic
,
const
std
::
string
prefix
)
:
UniSetObject_LT
(
objId
),
allInitOK
(
false
),
mb
(
0
),
shm
(
0
),
initPause
(
0
),
force
(
false
),
force_out
(
false
),
mbregFromID
(
false
),
activated
(
false
),
noQueryOptimization
(
false
),
force_disconnect
(
false
),
allNotRespond
(
false
),
prefix
(
prefix
),
no_extimer
(
false
),
poll_count
(
0
)
MBExchange
(
objId
,
shmId
,
ic
,
prefix
),
force_disconnect
(
true
),
mbtcp
(
0
),
pollThread
(
0
)
{
// cout << "$ $" << endl;
prop_prefix
=
"tcp_"
;
if
(
objId
==
DefaultObjectId
)
throw
UniSetTypes
::
SystemError
(
"(MBTCPMaster): objId=-1?!! Use --"
+
prefix
+
"-name"
);
// xmlNode* cnode = conf->getNode(myname);
string
conf_name
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-confnode"
,
myname
);
cnode
=
conf
->
getNode
(
conf_name
);
if
(
cnode
==
NULL
)
throw
UniSetTypes
::
SystemError
(
"(MBTCPMaster): Not found node <"
+
conf_name
+
" ...> for "
+
myname
);
shm
=
new
SMInterface
(
shmId
,
&
ui
,
objId
,
ic
);
UniXML_iterator
it
(
cnode
);
// определяем фильтр
s_field
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-filter-field"
);
s_fvalue
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-filter-value"
);
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(init): read fileter-field='"
<<
s_field
<<
"' filter-value='"
<<
s_fvalue
<<
"'"
<<
endl
;
stat_time
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-statistic-sec"
,
it
.
getProp
(
"statistic_sec"
),
0
);
if
(
stat_time
>
0
)
ptStatistic
.
setTiming
(
stat_time
*
1000
);
// ---------- init MBTCP ----------
string
pname
(
"--"
+
prefix
+
"-gateway-iaddr"
);
iaddr
=
conf
->
getArgParam
(
pname
,
it
.
getProp
(
"gateway_iaddr"
));
...
...
@@ -66,26 +37,13 @@ poll_count(0)
throw
UniSetTypes
::
SystemError
(
myname
+
"(MBMaster): Unknown inet port...(Use: "
+
tmp
+
")"
);
recv_timeout
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-recv-timeout"
,
it
.
getProp
(
"recv_timeout"
),
50
);
int
alltout
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-all-timeout"
,
it
.
getProp
(
"all_timeout"
),
2000
);
ptAllNotRespond
.
setTiming
(
alltout
);
noQueryOptimization
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-no-query-optimization"
,
it
.
getProp
(
"no_query_optimization"
));
mbregFromID
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-reg-from-id"
,
it
.
getProp
(
"reg_from_id"
));
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(init): mbregFromID="
<<
mbregFromID
<<
endl
;
force_disconnect
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-persistent-connection"
,
it
.
getProp
(
"persistent_connection"
))
?
false
:
true
;
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(init): persisten-connection="
<<
(
!
force_disconnect
)
<<
endl
;
polltime
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-polltime"
,
it
.
getProp
(
"polltime"
),
1
00
);
recv_timeout
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-recv-timeout"
,
it
.
getProp
(
"recv_timeout"
),
5
00
);
initPause
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-initPause"
,
it
.
getProp
(
"initPause"
),
3000
);
sleepPause_usec
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-sleepPause-usec"
,
it
.
getProp
(
"slepePause"
),
100
);
force
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-force"
,
it
.
getProp
(
"force"
));
force_out
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-force-out"
,
it
.
getProp
(
"force_out"
));
force_disconnect
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-force-disconnect"
,
it
.
getProp
(
"force_disconnect"
));
int
tout
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-timeout"
,
it
.
getProp
(
"timeout"
),
5000
);
ptTimeout
.
setTiming
(
tout
);
if
(
shm
->
isLocalwork
()
)
{
...
...
@@ -96,50 +54,7 @@ poll_count(0)
else
ic
->
addReadItem
(
sigc
::
mem_fun
(
this
,
&
MBTCPMaster
::
readItem
)
);
// ********** HEARTBEAT *************
string
heart
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-heartbeat-id"
,
it
.
getProp
(
"heartbeat_id"
));
if
(
!
heart
.
empty
()
)
{
sidHeartBeat
=
conf
->
getSensorID
(
heart
);
if
(
sidHeartBeat
==
DefaultObjectId
)
{
ostringstream
err
;
err
<<
myname
<<
": ID not found ('HeartBeat') for "
<<
heart
;
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(init): "
<<
err
.
str
()
<<
endl
;
throw
SystemError
(
err
.
str
());
}
int
heartbeatTime
=
getHeartBeatTime
();
if
(
heartbeatTime
)
ptHeartBeat
.
setTiming
(
heartbeatTime
);
else
ptHeartBeat
.
setTiming
(
UniSetTimer
::
WaitUpTime
);
maxHeartBeat
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-heartbeat-max"
,
it
.
getProp
(
"heartbeat_max"
),
10
);
test_id
=
sidHeartBeat
;
}
else
{
test_id
=
conf
->
getSensorID
(
"TestMode_S"
);
if
(
test_id
==
DefaultObjectId
)
{
ostringstream
err
;
err
<<
myname
<<
"(init): test_id unknown. 'TestMode_S' not found..."
;
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(init): "
<<
err
.
str
()
<<
endl
;
throw
SystemError
(
err
.
str
());
}
}
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(init): test_id="
<<
test_id
<<
endl
;
activateTimeout
=
conf
->
getArgPInt
(
"--"
+
prefix
+
"-activate-timeout"
,
20000
);
// initMB(false);
printMap
(
rmap
);
// abort();
poll_count
=
-
1
;
pollThread
=
new
ThreadCreator
<
MBTCPMaster
>
(
this
,
&
MBTCPMaster
::
poll_thread
);
}
// -----------------------------------------------------------------------------
MBTCPMaster
::~
MBTCPMaster
()
...
...
@@ -153,2413 +68,270 @@ MBTCPMaster::~MBTCPMaster()
delete
it1
->
second
;
}
delete
mb
;
delete
shm
;
delete
pollThread
;
delete
mbtcp
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
initMB
(
bool
reopen
)
ModbusClient
*
MBTCPMaster
::
initMB
(
bool
reopen
)
{
if
(
mb
)
if
(
mb
tcp
)
{
if
(
!
reopen
)
return
;
return
mbtcp
;
delete
mb
;
delete
mb
tcp
;
mb
=
0
;
mbtcp
=
0
;
}
try
{
ost
::
Thread
::
setException
(
ost
::
Thread
::
throwException
);
mb
=
new
ModbusTCPMaster
();
mb
tcp
=
new
ModbusTCPMaster
();
ost
::
InetAddress
ia
(
iaddr
.
c_str
());
mb
->
connect
(
ia
,
port
);
mb
->
setForceDisconnect
(
force_disconnect
);
mb
tcp
->
connect
(
ia
,
port
);
mb
tcp
->
setForceDisconnect
(
force_disconnect
);
if
(
recv_timeout
>
0
)
mb
->
setTimeout
(
recv_timeout
);
mb
tcp
->
setTimeout
(
recv_timeout
);
mb
->
setSleepPause
(
sleepPause_usec
);
mb
tcp
->
setSleepPause
(
sleepPause_usec
);
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(init): ipaddr="
<<
iaddr
<<
" port="
<<
port
<<
endl
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL9
)
)
mb
->
setLog
(
dlog
);
mb
tcp
->
setLog
(
dlog
);
}
catch
(
ModbusRTU
::
mbException
&
ex
)
{
cerr
<<
"(init): "
<<
ex
<<
endl
;
dlog
[
Debug
::
WARN
]
<<
"(init): "
<<
ex
<<
endl
;
}
catch
(...)
{
if
(
mb
)
delete
mb
;
if
(
mb
tcp
)
delete
mb
tcp
;
mb
=
0
;
mbtcp
=
0
;
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
waitSMReady
()
{
// waiting for SM is ready...
int
ready_timeout
=
conf
->
getArgInt
(
"--"
+
prefix
+
"-sm-ready-timeout"
,
"15000"
);
if
(
ready_timeout
==
0
)
ready_timeout
=
15000
;
else
if
(
ready_timeout
<
0
)
ready_timeout
=
UniSetTimer
::
WaitUpTime
;
if
(
!
shm
->
waitSMready
(
ready_timeout
,
50
)
)
{
ostringstream
err
;
err
<<
myname
<<
"(waitSMReady): failed waiting SharedMemory "
<<
ready_timeout
<<
" msec"
;
dlog
[
Debug
::
CRIT
]
<<
err
.
str
()
<<
endl
;
throw
SystemError
(
err
.
str
());
}
mb
=
mbtcp
;
return
mbtcp
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
timerInfo
(
TimerMessage
*
t
m
)
void
MBTCPMaster
::
sysCommand
(
UniSetTypes
::
SystemMessage
*
s
m
)
{
if
(
tm
->
id
==
tmExchange
)
{
if
(
no_extimer
)
askTimer
(
tm
->
id
,
0
);
else
step
();
}
MBExchange
::
sysCommand
(
sm
);
if
(
sm
->
command
==
SystemMessage
::
StartUp
)
pollThread
->
start
();
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
step
()
{
{
uniset_mutex_lock
l
(
pollMutex
,
2000
);
poll
();
}
if
(
!
activated
)
return
;
if
(
sidHeartBeat
!=
DefaultObjectId
&&
ptHeartBeat
.
checkTime
()
)
{
try
{
shm
->
localSaveValue
(
aitHeartBeat
,
sidHeartBeat
,
maxHeartBeat
,
getId
());
ptHeartBeat
.
reset
();
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(step): (hb) "
<<
ex
<<
std
::
endl
;
}
}
updateRespondSensors
();
MBExchange
::
step
();
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
poll
()
void
MBTCPMaster
::
updateRespondSensors
()
{
if
(
trAllNotRespond
.
hi
(
allNotRespond
)
)
ptAllNotRespond
.
reset
();
if
(
allNotRespond
&&
mb
&&
ptAllNotRespond
.
checkTime
()
)
{
ptAllNotRespond
.
reset
();
// initMB(true);
}
if
(
!
mb
)
{
initMB
(
false
);
if
(
!
mb
)
bool
tcpIsTimeout
=
false
;
{
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it
=
rmap
.
begin
();
it
!=
rmap
.
end
();
++
it
)
it
->
second
->
resp_real
=
false
;
}
updateSM
();
allInitOK
=
false
;
return
;
uniset_mutex_lock
l
(
tcpMutex
);
tcpIsTimeout
=
pollActivated
&&
ptTimeout
.
checkTime
();
}
if
(
!
allInitOK
)
firstInitRegisters
()
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL4
)
)
dlog
[
Debug
::
LEVEL4
]
<<
myname
<<
": tcpTimeout="
<<
tcpIsTimeout
<<
endl
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(poll): ask addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" regs="
<<
d
->
regmap
.
size
()
<<
endl
;
if
(
tcpIsTimeout
)
d
->
resp_real
=
false
;
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
try
{
if
(
d
->
dtype
==
MBTCPMaster
::
dtRTU
||
d
->
dtype
==
MBTCPMaster
::
dtMTR
)
if
(
dlog
.
debugging
(
Debug
::
LEVEL4
)
)
{
if
(
pollRTU
(
d
,
it
)
)
d
->
resp_real
=
true
;
}
dlog
[
Debug
::
LEVEL4
]
<<
myname
<<
": check respond addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" respond_id="
<<
d
->
resp_id
<<
" real="
<<
d
->
resp_real
<<
" state="
<<
d
->
resp_state
<<
endl
;
}
catch
(
ModbusRTU
::
mbException
&
ex
)
if
(
d
->
checkRespond
()
&&
d
->
resp_id
!=
DefaultObjectId
)
{
// if( d->resp_real )
// {
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
try
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(poll): FAILED ask addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" reg="
<<
ModbusRTU
::
dat2str
(
it
->
second
->
mbreg
)
<<
" for sensors: "
;
print_plist
(
dlog
(
Debug
::
LEVEL3
),
it
->
second
->
slst
);
dlog
(
Debug
::
LEVEL3
)
<<
" err: "
<<
ex
<<
endl
;
}
// }
// d->resp_real = false;
if
(
ex
.
err
==
ModbusRTU
::
erTimeOut
&&
!
d
->
ask_every_reg
)
break
;
// если контроллер хоть что-то ответил, то вроде как связь есть..
if
(
ex
.
err
!=
ModbusRTU
::
erTimeOut
)
d
->
resp_real
=
true
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
}
if
(
stat_time
>
0
)
poll_count
++
;
bool
set
=
d
->
resp_invert
?
!
d
->
resp_state
:
d
->
resp_state
;
shm
->
localSaveState
(
d
->
resp_dit
,
d
->
resp_id
,
set
,
getId
());
}
if
(
stat_time
>
0
&&
ptStatistic
.
checkTime
()
)
catch
(
Exception
&
ex
)
{
cout
<<
endl
<<
"(poll statistic): number of calls is "
<<
poll_count
<<
" (poll time: "
<<
stat_time
<<
" sec)"
<<
endl
<<
endl
;
ptStatistic
.
reset
();
poll_count
=
0
;
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(step): (respond) "
<<
ex
<<
std
::
endl
;
}
// update SharedMemory...
updateSM
();
// check thresholds
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
RegInfo
*
r
(
it
->
second
);
for
(
PList
::
iterator
i
=
r
->
slst
.
begin
();
i
!=
r
->
slst
.
end
();
++
i
)
IOBase
::
processingThreshold
(
&
(
*
i
),
shm
,
force
);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
pollRTU
(
RTUDevice
*
dev
,
RegMap
::
iterator
&
it
)
void
MBTCPMaster
::
poll_thread
(
)
{
RegInfo
*
p
(
it
->
second
);
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): poll "
<<
" mbaddr="
<<
ModbusRTU
::
addr2str
(
dev
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" mbfunc="
<<
p
->
mbfunc
<<
" q_count="
<<
p
->
q_count
<<
" mb_initOK="
<<
p
->
mb_initOK
<<
" sm_initOK="
<<
p
->
sm_initOK
<<
" mbval="
<<
p
->
mbval
<<
endl
;
if
(
p
->
q_count
>
ModbusRTU
::
MAXDATALEN
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): count("
<<
p
->
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
}
if
(
p
->
q_count
==
0
)
{
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(pollRTU): q_count=0 for mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE register..."
<<
endl
;
return
false
;
uniset_mutex_lock
l
(
pollMutex
,
300
);
ptTimeout
.
reset
();
}
switch
(
p
->
mbfunc
)
while
(
checkProcActive
()
)
{
case
ModbusRTU
:
:
fnReadInputRegisters
:
try
{
ModbusRTU
::
ReadInputRetMessage
ret
=
mb
->
read04
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
it
->
second
->
mbval
=
ret
.
data
[
i
];
it
--
;
if
(
sidExchangeMode
!=
DefaultObjectId
&&
force_out
)
exchangeMode
=
shm
->
localGetValue
(
aitExchangeMode
,
sidExchangeMode
);
}
break
;
case
ModbusRTU
:
:
fnReadOutputRegisters
:
catch
(...){}
try
{
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
it
->
second
->
mbval
=
ret
.
data
[
i
];
it
--
;
poll
();
}
break
;
catch
(...){}
case
ModbusRTU
:
:
fnReadInputStatus
:
{
ModbusRTU
::
ReadInputStatusRetMessage
ret
=
mb
->
read02
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
p
->
q_count
;
k
++
,
it
++
,
m
++
)
it
->
second
->
mbval
=
b
[
k
];
}
it
--
;
}
if
(
!
checkProcActive
()
)
break
;
case
ModbusRTU
:
:
fnReadCoilStatus
:
{
ModbusRTU
::
ReadCoilRetMessage
ret
=
mb
->
read01
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
p
->
q_count
;
k
++
,
it
++
,
m
++
)
it
->
second
->
mbval
=
b
[
k
]
?
1
:
0
;
}
it
--
;
msleep
(
polltime
);
}
break
;
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
RTUDevice
::
checkRespond
()
{
bool
prev
=
resp_state
;
case
ModbusRTU
:
:
fnWriteOutputSingleRegister
:
{
if
(
p
->
q_count
!=
1
)
if
(
resp_ptTimeout
.
getInterval
()
<=
0
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE WRITE SINGLE REGISTER (0x06) q_count="
<<
p
->
q_count
<<
" ..."
<<
endl
;
return
false
;
resp_state
=
resp_real
;
return
(
prev
!=
resp_state
);
}
if
(
!
p
->
sm_initOK
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
if
(
resp_trTimeout
.
hi
(
resp_state
&&
!
resp_real
)
)
resp_ptTimeout
.
reset
();
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU
::
WriteSingleOutputRetMessage
ret
=
mb
->
write06
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
mbval
)
;
}
break
;
if
(
resp_real
)
resp_state
=
true
;
else
if
(
resp_state
&&
!
resp_real
&&
resp_ptTimeout
.
checkTime
()
)
resp_state
=
false
;
case
ModbusRTU
:
:
fnWriteOutputRegisters
:
{
if
(
!
p
->
sm_initOK
)
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if
(
!
resp_init
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
resp_state
=
resp_real
;
resp_init
=
true
;
prev
=
resp_state
;
return
true
;
}
ModbusRTU
::
WriteOutputMessage
msg
(
dev
->
mbaddr
,
p
->
mbreg
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
msg
.
addData
(
it
->
second
->
mbval
);
return
(
prev
!=
resp_state
);
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
sigterm
(
int
signo
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
": ********* SIGTERM("
<<
signo
<<
") ********"
<<
endl
;
setProcActive
(
false
);
it
--
;
ModbusRTU
::
WriteOutputRetMessage
ret
=
mb
->
write10
(
msg
);
}
break
;
/*! \todo Доделать выставление безопасного состояния на выходы.
И нужно ли это. Ведь может не хватить времени на "обмен"
*/
case
ModbusRTU
:
:
fnForceSingleCoil
:
{
if
(
p
->
q_count
!=
1
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE FORCE SINGLE COIL (0x05) q_count="
<<
p
->
q_count
<<
" ..."
<<
endl
;
return
false
;
}
if
(
!
p
->
sm_initOK
)
// выставление безопасного состояния на выходы....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU
::
ForceSingleCoilRetMessage
ret
=
mb
->
write05
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
mbval
);
}
break
;
if( it->safety == NoSafetyState )
continue;
case
ModbusRTU
:
:
fnForceMultipleCoils
:
{
if
(
!
p
->
sm_initOK
)
try
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
ModbusRTU
::
ForceCoilsMessage
msg
(
dev
->
mbaddr
,
p
->
mbreg
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
msg
.
addBit
(
(
it
->
second
->
mbval
?
true
:
false
)
);
it
--
;
// cerr << "*********** (write multiple): " << msg << endl;
ModbusRTU
::
ForceCoilsRetMessage
ret
=
mb
->
write0F
(
msg
);
}
break
;
default
:
catch( UniSetTypes::Exception& ex )
{
if
(
dlog
.
debugging
(
Debug
::
WARN
)
)
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE mfunc="
<<
(
int
)
p
->
mbfunc
<<
" ..."
<<
endl
;
return
false
;
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
break
;
catch(...){}
}
return
true
;
*/
UniSetObject_LT
::
sigterm
(
signo
);
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
help_print
(
int
argc
,
const
char
*
const
*
argv
)
{
cout
<<
"Default: prefix='mbtcp'"
<<
endl
;
MBExchange
::
help_print
(
argc
,
argv
);
// ---------- init MBTCP ----------
// cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
cout
<<
" Настройки протокола TCP: "
<<
endl
;
cout
<<
"--prefix-gateway hostname,IP - IP опрашиваемого узла"
<<
endl
;
cout
<<
"--prefix-gateway-port num - port на опрашиваемом узле"
<<
endl
;
cout
<<
"--prefix-recv-timeout msec - Таймаут на приём одного сообщения"
<<
endl
;
cout
<<
"--prefix-timeout msec - Таймаут для определения отсутсвия соединения"
<<
endl
;
cout
<<
"--prefix-persistent-connection 0,1 - Не закрывать соединение на каждом цикле опроса"
<<
endl
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
firstInitRegisters
()
MBTCPMaster
*
MBTCPMaster
::
init_mbmaster
(
int
argc
,
const
char
*
const
*
argv
,
UniSetTypes
::
ObjectId
icID
,
SharedMemory
*
ic
,
const
std
::
string
prefix
)
{
// если все вернут TRUE, значит OK.
allInitOK
=
true
;
for
(
InitList
::
iterator
it
=
initRegList
.
begin
();
it
!=
initRegList
.
end
();
++
it
)
{
try
string
name
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-name"
,
"MBTCPMaster1"
);
if
(
name
.
empty
()
)
{
it
->
initOK
=
preInitRead
(
it
)
;
allInitOK
=
it
->
initOK
;
dlog
[
Debug
::
CRIT
]
<<
"(MBTCPMaster): Не задан name'"
<<
endl
;
return
0
;
}
catch
(
ModbusRTU
::
mbException
&
ex
)
{
allInitOK
=
false
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
ObjectId
ID
=
conf
->
getObjectID
(
name
);
if
(
ID
==
UniSetTypes
::
DefaultObjectId
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): FAILED ask addr="
<<
ModbusRTU
::
addr2str
(
it
->
dev
->
mbaddr
)
<<
" reg="
<<
ModbusRTU
::
dat2str
(
it
->
mbreg
)
<<
" err: "
<<
ex
<<
endl
;
dlog
[
Debug
::
CRIT
]
<<
"(MBTCPMaster): идентификатор '"
<<
name
<<
"' не найден в конф. файле!"
<<
" в секции "
<<
conf
->
getObjectsSection
()
<<
endl
;
return
0
;
}
if
(
!
it
->
dev
->
ask_every_reg
)
break
;
}
}
dlog
[
Debug
::
INFO
]
<<
"(MBTCPMaster): name = "
<<
name
<<
"("
<<
ID
<<
")"
<<
endl
;
return
new
MBTCPMaster
(
ID
,
icID
,
ic
,
prefix
);
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
preInitRead
(
InitList
::
iterator
&
p
)
void
MBTCPMaster
::
execute
(
)
{
if
(
p
->
initOK
)
return
true
;
RTUDevice
*
dev
=
p
->
dev
;
int
q_count
=
p
->
p
.
rnum
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): poll "
<<
" mbaddr="
<<
ModbusRTU
::
addr2str
(
dev
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" mbfunc="
<<
p
->
mbfunc
<<
" q_count="
<<
q_count
<<
endl
;
no_extimer
=
true
;
if
(
q_count
>
ModbusRTU
::
MAXDATALEN
)
try
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): count("
<<
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
askTimer
(
tmExchange
,
0
);
}
catch
(...){}
switch
(
p
->
mbfunc
)
{
case
ModbusRTU
:
:
fnReadOutputRegisters
:
{
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
p
->
initOK
=
initSMValue
(
ret
.
data
,
ret
.
count
,
&
(
p
->
p
));
}
break
;
initMB
(
false
);
case
ModbusRTU
:
:
fnReadInputRegisters
:
{
ModbusRTU
::
ReadInputRetMessage
ret1
=
mb
->
read04
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
p
->
initOK
=
initSMValue
(
ret1
.
data
,
ret1
.
count
,
&
(
p
->
p
));
}
break
;
case
ModbusRTU
:
:
fnReadInputStatus
:
while
(
1
)
{
ModbusRTU
::
ReadInputStatusRetMessage
ret
=
mb
->
read02
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
ModbusRTU
::
ModbusData
*
dat
=
new
ModbusRTU
::
ModbusData
[
q_count
];
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
try
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
q_count
;
k
++
,
m
++
)
dat
[
m
]
=
b
[
k
];
}
p
->
initOK
=
initSMValue
(
dat
,
q_count
,
&
(
p
->
p
));
delete
[]
dat
;
step
();
}
break
;
case
ModbusRTU
:
:
fnReadCoilStatus
:
{
ModbusRTU
::
ReadCoilRetMessage
ret
=
mb
->
read01
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
ModbusRTU
::
ModbusData
*
dat
=
new
ModbusRTU
::
ModbusData
[
q_count
];
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
catch
(
Exception
&
ex
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
q_count
;
k
++
,
m
++
)
dat
[
m
]
=
b
[
k
];
}
p
->
initOK
=
initSMValue
(
dat
,
q_count
,
&
(
p
->
p
));
delete
[]
dat
;
}
break
;
default
:
p
->
initOK
=
false
;
break
;
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(execute): "
<<
ex
<<
std
::
endl
;
}
if
(
p
->
initOK
)
catch
(...)
{
p
->
ri
->
mb_initOK
=
true
;
p
->
ri
->
sm_initOK
=
false
;
bool
f_out
=
force_out
;
// выставляем флаг принудительного обновления
force_out
=
true
;
updateRTU
(
p
->
ri
->
rit
);
force_out
=
f_out
;
}
return
p
->
initOK
;
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
initSMValue
(
ModbusRTU
::
ModbusData
*
data
,
int
count
,
RSProperty
*
p
)
{
using
namespace
ModbusRTU
;
try
{
if
(
p
->
vType
==
VTypes
::
vtUnknown
)
{
ModbusRTU
::
DataBits16
b
(
data
[
0
]);
if
(
p
->
nbit
>=
0
)
{
bool
set
=
b
[
p
->
nbit
];
IOBase
::
processingAsDI
(
p
,
set
,
shm
,
force
);
return
true
;
}
if
(
p
->
rnum
<=
1
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
data
[
0
]),
shm
,
force
);
return
true
;
}
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initSMValue): IGNORE item: rnum="
<<
p
->
rnum
<<
" > 1 ?!! for id="
<<
p
->
si
.
id
<<
endl
;
return
false
;
}
else
if
(
p
->
vType
==
VTypes
::
vtSigned
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
data
[
0
]),
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtUnsigned
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
unsigned
short
)
data
[
0
],
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtByte
)
{
if
(
p
->
nbyte
<=
0
||
p
->
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initSMValue): IGNORE item: sid="
<<
ModbusRTU
::
dat2str
(
p
->
si
.
id
)
<<
" vtype="
<<
p
->
vType
<<
" but nbyte="
<<
p
->
nbyte
<<
endl
;
return
false
;
}
VTypes
::
Byte
b
(
data
[
0
]);
IOBase
::
processingAsAI
(
p
,
b
.
raw
.
b
[
p
->
nbyte
-
1
],
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtF2
)
{
VTypes
::
F2
f
(
data
,
VTypes
::
F2
::
wsize
());
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtF4
)
{
VTypes
::
F4
f
(
data
,
VTypes
::
F4
::
wsize
());
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtI2
)
{
VTypes
::
I2
i2
(
data
,
VTypes
::
I2
::
wsize
());
IOBase
::
processingAsAI
(
p
,
(
int
)
i2
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtU2
)
{
VTypes
::
U2
u2
(
data
,
VTypes
::
U2
::
wsize
());
IOBase
::
processingAsAI
(
p
,
(
unsigned
int
)
u2
,
shm
,
force
);
}
return
true
;
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): catch ..."
<<
endl
;
}
return
false
;
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
RTUDevice
::
checkRespond
()
{
bool
prev
=
resp_state
;
if
(
resp_trTimeout
.
hi
(
resp_real
)
)
{
if
(
resp_real
)
resp_state
=
true
;
resp_ptTimeout
.
reset
();
}
if
(
resp_state
&&
!
resp_real
&&
resp_ptTimeout
.
checkTime
()
)
resp_state
=
false
;
// если ещё не инициализировали значение в SM
// то возвращаем true, чтобы оно принудительно сохранилось
if
(
!
resp_init
)
{
resp_state
=
resp_real
;
resp_init
=
true
;
prev
=
resp_state
;
return
true
;
}
return
(
prev
!=
resp_state
);
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
updateSM
()
{
allNotRespond
=
true
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
if
(
dlog
.
debugging
(
Debug
::
LEVEL4
)
)
{
dlog
[
Debug
::
LEVEL4
]
<<
"check respond addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" respond="
<<
d
->
resp_id
<<
" real="
<<
d
->
resp_real
<<
" state="
<<
d
->
resp_state
<<
endl
;
}
if
(
d
->
resp_real
)
allNotRespond
=
false
;
// update respond sensors...
if
(
d
->
checkRespond
()
&&
d
->
resp_id
!=
DefaultObjectId
)
{
try
{
bool
set
=
d
->
resp_invert
?
!
d
->
resp_state
:
d
->
resp_state
;
shm
->
localSaveState
(
d
->
resp_dit
,
d
->
resp_id
,
set
,
getId
());
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(step): (respond) "
<<
ex
<<
std
::
endl
;
}
}
// cerr << "*********** allNotRespond=" << allNotRespond << endl;
// update values...
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
try
{
if
(
d
->
dtype
==
dtRTU
)
updateRTU
(
it
);
else
if
(
d
->
dtype
==
dtMTR
)
updateMTR
(
it
);
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): catch ..."
<<
endl
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
}
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
processingMessage
(
UniSetTypes
::
VoidMessage
*
msg
)
{
try
{
switch
(
msg
->
type
)
{
case
UniSetTypes
:
:
Message
::
SysCommand
:
{
UniSetTypes
::
SystemMessage
sm
(
msg
);
sysCommand
(
&
sm
);
}
break
;
case
Message
:
:
Timer
:
{
TimerMessage
tm
(
msg
);
timerInfo
(
&
tm
);
}
break
;
case
Message
:
:
SensorInfo
:
{
SensorMessage
sm
(
msg
);
sensorInfo
(
&
sm
);
}
break
;
default
:
break
;
}
}
catch
(
SystemError
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(SystemError): "
<<
ex
<<
std
::
endl
;
// throw SystemError(ex);
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(processingMessage): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(processingMessage): catch ...
\n
"
;
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
sysCommand
(
UniSetTypes
::
SystemMessage
*
sm
)
{
switch
(
sm
->
command
)
{
case
SystemMessage
:
:
StartUp
:
{
if
(
rmap
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(sysCommand): ************* ITEM MAP EMPTY! terminated... *************"
<<
endl
;
raise
(
SIGTERM
);
return
;
}
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(sysCommand): device map size= "
<<
rmap
.
size
()
<<
endl
;
if
(
!
shm
->
isLocalwork
()
)
initDeviceList
();
waitSMReady
();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep
(
initPause
);
PassiveTimer
ptAct
(
activateTimeout
);
while
(
!
activated
&&
!
ptAct
.
checkTime
()
)
{
cout
<<
myname
<<
"(sysCommand): wait activate..."
<<
endl
;
msleep
(
300
);
if
(
activated
)
break
;
}
if
(
!
activated
)
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(sysCommand): ************* don`t activate?! ************"
<<
endl
;
{
UniSetTypes
::
uniset_mutex_lock
l
(
mutex_start
,
10000
);
askSensors
(
UniversalIO
::
UIONotify
);
initOutput
();
}
// начальная инициализация
if
(
!
force
)
{
uniset_mutex_lock
l
(
pollMutex
,
2000
);
force
=
true
;
poll
();
force
=
false
;
}
askTimer
(
tmExchange
,
polltime
);
break
;
}
case
SystemMessage
:
:
FoldUp
:
case
SystemMessage
:
:
Finish
:
askSensors
(
UniversalIO
::
UIODontNotify
);
break
;
case
SystemMessage
:
:
WatchDog
:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. MBTCPMaster запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBTCPMaster)
if
(
shm
->
isLocalwork
()
)
break
;
askSensors
(
UniversalIO
::
UIONotify
);
initOutput
();
if
(
!
force
)
{
uniset_mutex_lock
l
(
pollMutex
,
2000
);
force
=
true
;
poll
();
force
=
false
;
}
}
break
;
case
SystemMessage
:
:
LogRotate
:
{
// переоткрываем логи
unideb
<<
myname
<<
"(sysCommand): logRotate"
<<
std
::
endl
;
string
fname
=
unideb
.
getLogFile
();
if
(
!
fname
.
empty
()
)
{
unideb
.
logFile
(
fname
);
unideb
<<
myname
<<
"(sysCommand): ***************** UNIDEB LOG ROTATE *****************"
<<
std
::
endl
;
}
dlog
<<
myname
<<
"(sysCommand): logRotate"
<<
std
::
endl
;
fname
=
dlog
.
getLogFile
();
if
(
!
fname
.
empty
()
)
{
dlog
.
logFile
(
fname
);
dlog
<<
myname
<<
"(sysCommand): ***************** dlog LOG ROTATE *****************"
<<
std
::
endl
;
}
}
break
;
default
:
break
;
}
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
initOutput
()
{
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
askSensors
(
UniversalIO
::
UIOCommand
cmd
)
{
if
(
!
shm
->
waitSMworking
(
test_id
,
activateTimeout
,
50
)
)
{
ostringstream
err
;
err
<<
myname
<<
"(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<<
activateTimeout
<<
" мсек"
;
dlog
[
Debug
::
CRIT
]
<<
err
.
str
()
<<
endl
;
kill
(
SIGTERM
,
getpid
());
// прерываем (перезапускаем) процесс...
throw
SystemError
(
err
.
str
());
}
if
(
force_out
)
return
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
isWriteFunction
(
it
->
second
->
mbfunc
)
)
continue
;
for
(
PList
::
iterator
i
=
it
->
second
->
slst
.
begin
();
i
!=
it
->
second
->
slst
.
end
();
++
i
)
{
try
{
shm
->
askSensor
(
i
->
si
.
id
,
cmd
);
}
catch
(
UniSetTypes
::
Exception
&
ex
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): catch..."
<<
std
::
endl
;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
sensorInfo
(
UniSetTypes
::
SensorMessage
*
sm
)
{
if
(
force_out
)
return
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
isWriteFunction
(
it
->
second
->
mbfunc
)
)
continue
;
for
(
PList
::
iterator
i
=
it
->
second
->
slst
.
begin
();
i
!=
it
->
second
->
slst
.
end
();
++
i
)
{
if
(
sm
->
id
==
i
->
si
.
id
&&
sm
->
node
==
i
->
si
.
node
)
{
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
{
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(sensorInfo): si.id="
<<
sm
->
id
<<
" reg="
<<
ModbusRTU
::
dat2str
(
i
->
reg
->
mbreg
)
<<
" val="
<<
sm
->
value
<<
" mb_initOK="
<<
i
->
reg
->
mb_initOK
<<
endl
;
}
if
(
!
i
->
reg
->
mb_initOK
)
continue
;
i
->
value
=
sm
->
value
;
updateRSProperty
(
&
(
*
i
),
true
);
return
;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
activateObject
()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
activated
=
false
;
UniSetTypes
::
uniset_mutex_lock
l
(
mutex_start
,
5000
);
UniSetObject_LT
::
activateObject
();
if
(
!
shm
->
isLocalwork
()
)
rtuQueryOptimization
(
rmap
);
initIterators
();
activated
=
true
;
}
return
true
;
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
sigterm
(
int
signo
)
{
cerr
<<
myname
<<
": ********* SIGTERM("
<<
signo
<<
") ********"
<<
endl
;
activated
=
false
;
/*! \todo Доделать выставление безопасного состояния на выходы.
И нужно ли это. Ведь может не хватить времени на "обмен"
*/
// выставление безопасного состояния на выходы....
/*
RSMap::iterator it=rsmap.begin();
for( ; it!=rsmap.end(); ++it )
{
// if( it->stype!=UniversalIO::DigitalOutput && it->stype!=UniversalIO::AnalogOutput )
// continue;
if( it->safety == NoSafetyState )
continue;
try
{
}
catch( UniSetTypes::Exception& ex )
{
dlog[Debug::WARN] << myname << "(sigterm): " << ex << std::endl;
}
catch(...){}
}
*/
UniSetObject_LT
::
sigterm
(
signo
);
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
readConfiguration
()
{
// readconf_ok = false;
xmlNode
*
root
=
conf
->
getXMLSensorsSection
();
if
(
!
root
)
{
ostringstream
err
;
err
<<
myname
<<
"(readConfiguration): не нашли корневого раздела <sensors>"
;
throw
SystemError
(
err
.
str
());
}
UniXML_iterator
it
(
root
);
if
(
!
it
.
goChildren
()
)
{
std
::
cerr
<<
myname
<<
"(readConfiguration): раздел <sensors> не содержит секций ?!!
\n
"
;
return
;
}
for
(
;
it
.
getCurrent
();
it
.
goNext
()
)
{
if
(
UniSetTypes
::
check_filter
(
it
,
s_field
,
s_fvalue
)
)
initItem
(
it
);
}
// readconf_ok = true;
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
readItem
(
UniXML
&
xml
,
UniXML_iterator
&
it
,
xmlNode
*
sec
)
{
if
(
UniSetTypes
::
check_filter
(
it
,
s_field
,
s_fvalue
)
)
initItem
(
it
);
return
true
;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster
::
RTUDevice
*
MBTCPMaster
::
addDev
(
RTUDeviceMap
&
mp
,
ModbusRTU
::
ModbusAddr
a
,
UniXML_iterator
&
xmlit
)
{
RTUDeviceMap
::
iterator
it
=
mp
.
find
(
a
);
if
(
it
!=
mp
.
end
()
)
{
DeviceType
dtype
=
getDeviceType
(
xmlit
.
getProp
(
"tcp_mbtype"
));
if
(
it
->
second
->
dtype
!=
dtype
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addDev): OTHER mbtype="
<<
dtype
<<
" for "
<<
xmlit
.
getProp
(
"name"
)
<<
". Already used devtype="
<<
it
->
second
->
dtype
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
it
->
second
->
mbaddr
)
<<
endl
;
return
0
;
}
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(addDev): device for addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
" already added. Ignore device params for "
<<
xmlit
.
getProp
(
"name"
)
<<
" ..."
<<
endl
;
return
it
->
second
;
}
MBTCPMaster
::
RTUDevice
*
d
=
new
MBTCPMaster
::
RTUDevice
();
d
->
mbaddr
=
a
;
if
(
!
initRTUDevice
(
d
,
xmlit
)
)
{
delete
d
;
return
0
;
}
mp
.
insert
(
RTUDeviceMap
::
value_type
(
a
,
d
));
return
d
;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster
::
RegInfo
*
MBTCPMaster
::
addReg
(
RegMap
&
mp
,
RegID
id
,
ModbusRTU
::
ModbusData
r
,
UniXML_iterator
&
xmlit
,
MBTCPMaster
::
RTUDevice
*
dev
,
MBTCPMaster
::
RegInfo
*
rcopy
)
{
RegMap
::
iterator
it
=
mp
.
find
(
id
);
if
(
it
!=
mp
.
end
()
)
{
if
(
!
it
->
second
->
dev
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addReg): for "
<<
xmlit
.
getProp
(
"name"
)
<<
" dev=0!!!! "
<<
endl
;
return
0
;
}
if
(
it
->
second
->
dev
->
dtype
!=
dev
->
dtype
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addReg): OTHER mbtype="
<<
dev
->
dtype
<<
" for "
<<
xmlit
.
getProp
(
"name"
)
<<
". Already used devtype="
<<
it
->
second
->
dev
->
dtype
<<
" for "
<<
it
->
second
->
dev
<<
endl
;
return
0
;
}
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
{
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(addReg): reg="
<<
ModbusRTU
::
dat2str
(
r
)
<<
" already added. Ignore register params for "
<<
xmlit
.
getProp
(
"name"
)
<<
" ..."
<<
endl
;
}
it
->
second
->
rit
=
it
;
return
it
->
second
;
}
MBTCPMaster
::
RegInfo
*
ri
;
if
(
rcopy
)
{
ri
=
new
MBTCPMaster
::
RegInfo
(
*
rcopy
);
ri
->
slst
.
clear
();
ri
->
mbreg
=
r
;
}
else
{
ri
=
new
MBTCPMaster
::
RegInfo
();
if
(
!
initRegInfo
(
ri
,
xmlit
,
dev
)
)
{
delete
ri
;
return
0
;
}
ri
->
mbreg
=
r
;
}
ri
->
id
=
id
;
mp
.
insert
(
RegMap
::
value_type
(
id
,
ri
));
ri
->
rit
=
mp
.
find
(
id
);
return
ri
;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster
::
RSProperty
*
MBTCPMaster
::
addProp
(
PList
&
plist
,
RSProperty
&
p
)
{
for
(
PList
::
iterator
it
=
plist
.
begin
();
it
!=
plist
.
end
();
++
it
)
{
if
(
it
->
si
.
id
==
p
.
si
.
id
&&
it
->
si
.
node
==
p
.
si
.
node
)
return
&
(
*
it
);
}
plist
.
push_back
(
p
);
PList
::
iterator
it
=
plist
.
end
();
it
--
;
return
&
(
*
it
);
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
initRSProperty
(
RSProperty
&
p
,
UniXML_iterator
&
it
)
{
if
(
!
IOBase
::
initItem
(
&
p
,
it
,
shm
,
&
dlog
,
myname
)
)
return
false
;
if
(
it
.
getIntProp
(
"tcp_rawdata"
)
)
{
p
.
cal
.
minRaw
=
0
;
p
.
cal
.
maxRaw
=
0
;
p
.
cal
.
minCal
=
0
;
p
.
cal
.
maxCal
=
0
;
p
.
cal
.
precision
=
0
;
p
.
cdiagram
=
0
;
}
string
stype
(
it
.
getProp
(
"tcp_iotype"
)
);
if
(
!
stype
.
empty
()
)
{
p
.
stype
=
UniSetTypes
::
getIOType
(
stype
);
if
(
p
.
stype
==
UniversalIO
::
UnknownIOType
)
{
if
(
dlog
)
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(IOBase::readItem): неизвестный iotype=: "
<<
stype
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
string
sbit
(
it
.
getProp
(
"tcp_nbit"
));
if
(
!
sbit
.
empty
()
)
{
p
.
nbit
=
UniSetTypes
::
uni_atoi
(
sbit
.
c_str
());
if
(
p
.
nbit
<
0
||
p
.
nbit
>=
ModbusRTU
::
BitsPerData
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): BAD nbit="
<<
p
.
nbit
<<
". (0 >= nbit < "
<<
ModbusRTU
::
BitsPerData
<<
")."
<<
endl
;
return
false
;
}
}
if
(
p
.
nbit
>
0
&&
(
p
.
stype
==
UniversalIO
::
AnalogInput
||
p
.
stype
==
UniversalIO
::
AnalogOutput
)
)
{
dlog
[
Debug
::
WARN
]
<<
"(initRSProperty): (ignore) uncorrect param`s nbit>1 ("
<<
p
.
nbit
<<
")"
<<
" but iotype="
<<
p
.
stype
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
}
string
sbyte
(
it
.
getProp
(
"tcp_nbyte"
));
if
(
!
sbyte
.
empty
()
)
{
p
.
nbyte
=
UniSetTypes
::
uni_atoi
(
sbyte
.
c_str
());
if
(
p
.
nbyte
<
0
||
p
.
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): BAD nbyte="
<<
p
.
nbyte
<<
". (0 >= nbyte < "
<<
VTypes
::
Byte
::
bsize
<<
")."
<<
endl
;
return
false
;
}
}
string
vt
(
it
.
getProp
(
"tcp_vtype"
));
if
(
vt
.
empty
()
)
{
p
.
rnum
=
VTypes
::
wsize
(
VTypes
::
vtUnknown
);
p
.
vType
=
VTypes
::
vtUnknown
;
}
else
{
VTypes
::
VType
v
(
VTypes
::
str2type
(
vt
));
if
(
v
==
VTypes
::
vtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): Unknown tcp_vtype='"
<<
vt
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
p
.
vType
=
v
;
p
.
rnum
=
VTypes
::
wsize
(
v
);
}
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
initRegInfo
(
RegInfo
*
r
,
UniXML_iterator
&
it
,
MBTCPMaster
::
RTUDevice
*
dev
)
{
r
->
dev
=
dev
;
r
->
mbval
=
it
.
getIntProp
(
"default"
);
if
(
dev
->
dtype
==
MBTCPMaster
::
dtRTU
)
{
// dlog[Debug::INFO] << myname << "(initRegInfo): init RTU.."
}
else
if
(
dev
->
dtype
==
MBTCPMaster
::
dtMTR
)
{
// only for MTR
if
(
!
initMTRitem
(
it
,
r
)
)
return
false
;
}
else
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRegInfo): Unknown mbtype='"
<<
dev
->
dtype
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
if
(
mbregFromID
)
{
if
(
it
.
getProp
(
"id"
).
empty
()
)
r
->
mbreg
=
conf
->
getSensorID
(
it
.
getProp
(
"name"
));
else
r
->
mbreg
=
it
.
getIntProp
(
"id"
);
}
else
{
string
sr
=
it
.
getProp
(
"tcp_mbreg"
);
if
(
sr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown 'mbreg' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
r
->
mbreg
=
ModbusRTU
::
str2mbData
(
sr
);
}
r
->
mbfunc
=
ModbusRTU
::
fnUnknown
;
string
f
=
it
.
getProp
(
"tcp_mbfunc"
);
if
(
!
f
.
empty
()
)
{
r
->
mbfunc
=
(
ModbusRTU
::
SlaveFunctionCode
)
UniSetTypes
::
uni_atoi
(
f
.
c_str
());
if
(
r
->
mbfunc
==
ModbusRTU
::
fnUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRegInfo): Unknown mbfunc ='"
<<
f
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
return
true
;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster
::
DeviceType
MBTCPMaster
::
getDeviceType
(
const
std
::
string
dtype
)
{
if
(
dtype
.
empty
()
)
return
dtUnknown
;
if
(
dtype
==
"mtr"
||
dtype
==
"MTR"
)
return
dtMTR
;
if
(
dtype
==
"rtu"
||
dtype
==
"RTU"
)
return
dtRTU
;
return
dtUnknown
;
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
initRTUDevice
(
RTUDevice
*
d
,
UniXML_iterator
&
it
)
{
d
->
dtype
=
getDeviceType
(
it
.
getProp
(
"tcp_mbtype"
));
if
(
d
->
dtype
==
dtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRTUDevice): Unknown tcp_mbtype="
<<
it
.
getProp
(
"tcp_mbtype"
)
<<
". Use: rtu "
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
string
addr
=
it
.
getProp
(
"tcp_mbaddr"
);
if
(
addr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRTUDevice): Unknown mbaddr for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
d
->
mbaddr
=
ModbusRTU
::
str2mbAddr
(
addr
);
return
true
;
}
// ------------------------------------------------------------------------------------------
MBTCPMaster
::
RegID
MBTCPMaster
::
genRegID
(
const
ModbusRTU
::
ModbusData
mbreg
,
const
int
fn
)
{
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
return
numeric_limits
<
ModbusRTU
::
ModbusData
>::
max
()
+
mbreg
+
fn
;
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
initItem
(
UniXML_iterator
&
it
)
{
RSProperty
p
;
if
(
!
initRSProperty
(
p
,
it
)
)
return
false
;
string
addr
=
it
.
getProp
(
"tcp_mbaddr"
);
if
(
addr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown mbaddr='"
<<
addr
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
ModbusRTU
::
ModbusAddr
mbaddr
=
ModbusRTU
::
str2mbAddr
(
addr
);
RTUDevice
*
dev
=
addDev
(
rmap
,
mbaddr
,
it
);
if
(
!
dev
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): "
<<
it
.
getProp
(
"name"
)
<<
" CAN`T ADD for polling!"
<<
endl
;
return
false
;
}
ModbusRTU
::
ModbusData
mbreg
;
if
(
mbregFromID
)
mbreg
=
p
.
si
.
id
;
// conf->getSensorID(it.getProp("name"));
else
{
string
reg
=
it
.
getProp
(
"tcp_mbreg"
);
if
(
reg
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): unknown mbreg for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
mbreg
=
ModbusRTU
::
str2mbData
(
reg
);
}
int
fn
=
it
.
getIntProp
(
"tcp_mbfunc"
);
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
RegID
rID
=
genRegID
(
mbreg
,
fn
);
RegInfo
*
ri
=
addReg
(
dev
->
regmap
,
rID
,
mbreg
,
it
,
dev
);
if
(
dev
->
dtype
==
dtMTR
)
{
p
.
rnum
=
MTR
::
wsize
(
ri
->
mtrType
);
if
(
p
.
rnum
<=
0
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): unknown word size for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
if
(
!
ri
)
return
false
;
ri
->
dev
=
dev
;
// ПРОВЕРКА!
// если функция на запись, то надо проверить
// что один и тотже регистр не перезапишут несколько датчиков
// это возможно только, если они пишут биты!!
// ИТОГ:
// Если для функций записи список датчиков для регистра > 1
// значит в списке могут быть только битовые датчики
// и если идёт попытка внести в список не битовый датчик то ОШИБКА!
// И наоборот: если идёт попытка внести битовый датчик, а в списке
// уже сидит датчик занимающий целый регистр, то тоже ОШИБКА!
if
(
ModbusRTU
::
isWriteFunction
(
ri
->
mbfunc
)
)
{
if
(
p
.
nbit
<
0
&&
ri
->
slst
.
size
()
>
1
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): FAILED! Sharing SAVE (not bit saving) to "
<<
" tcp_mbreg="
<<
ModbusRTU
::
dat2str
(
ri
->
mbreg
)
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
abort
();
// ABORT PROGRAM!!!!
return
false
;
}
if
(
p
.
nbit
>=
0
&&
ri
->
slst
.
size
()
==
1
)
{
PList
::
iterator
it2
=
ri
->
slst
.
begin
();
if
(
it2
->
nbit
<
0
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): FAILED! Sharing SAVE (mbreg="
<<
ModbusRTU
::
dat2str
(
ri
->
mbreg
)
<<
" already used)!"
<<
" IGNORE --> "
<<
it
.
getProp
(
"name"
)
<<
endl
;
abort
();
// ABORT PROGRAM!!!!
return
false
;
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri
->
sm_initOK
=
it
.
getIntProp
(
"tcp_sm_initOK"
);
ri
->
mb_initOK
=
true
;
// может быть переопределён если будет указан tcp_preinit="1" (см. ниже)
}
else
{
// Если это регистр для чтения, то сразу можно работать
// инициализировать не надо
ri
->
mb_initOK
=
true
;
ri
->
sm_initOK
=
true
;
}
RSProperty
*
p1
=
addProp
(
ri
->
slst
,
p
);
if
(
!
p1
)
return
false
;
p1
->
reg
=
ri
;
if
(
p1
->
rnum
>
1
)
{
for
(
int
i
=
1
;
i
<
p1
->
rnum
;
i
++
)
{
RegID
id1
=
genRegID
(
mbreg
+
i
,
fn
);
addReg
(
dev
->
regmap
,
id1
,
mbreg
+
i
,
it
,
dev
,
ri
);
}
}
// Фомируем список инициализации
bool
need_init
=
it
.
getIntProp
(
"tcp_preinit"
);
if
(
need_init
&&
ModbusRTU
::
isWriteFunction
(
ri
->
mbfunc
)
)
{
InitRegInfo
ii
;
ii
.
p
=
p
;
ii
.
dev
=
dev
;
ii
.
ri
=
ri
;
string
s_reg
(
it
.
getProp
(
"tcp_init_mbreg"
));
if
(
!
s_reg
.
empty
()
)
ii
.
mbreg
=
ModbusRTU
::
str2mbData
(
s_reg
);
else
ii
.
mbreg
=
ri
->
mbreg
;
string
s_mbfunc
(
it
.
getProp
(
"tcp_init_mbfunc"
));
if
(
!
s_mbfunc
.
empty
()
)
{
ii
.
mbfunc
=
(
ModbusRTU
::
SlaveFunctionCode
)
UniSetTypes
::
uni_atoi
(
s_mbfunc
);
if
(
ii
.
mbfunc
==
ModbusRTU
::
fnUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown tcp_init_mbfunc ='"
<<
s_mbfunc
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
else
{
switch
(
ri
->
mbfunc
)
{
case
ModbusRTU
:
:
fnWriteOutputSingleRegister
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
case
ModbusRTU
:
:
fnForceSingleCoil
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadCoilStatus
;
break
;
case
ModbusRTU
:
:
fnWriteOutputRegisters
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
case
ModbusRTU
:
:
fnForceMultipleCoils
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadCoilStatus
;
break
;
default
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
}
}
initRegList
.
push_back
(
ii
);
ri
->
mb_initOK
=
false
;
ri
->
sm_initOK
=
false
;
}
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBTCPMaster
::
initMTRitem
(
UniXML_iterator
&
it
,
RegInfo
*
p
)
{
p
->
mtrType
=
MTR
::
str2type
(
it
.
getProp
(
"mtrtype"
));
if
(
p
->
mtrType
==
MTR
::
mtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(readMTRItem): Unknown mtrtype '"
<<
it
.
getProp
(
"mtrtype"
)
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
return
true
;
}
// ------------------------------------------------------------------------------------------
void
MBTCPMaster
::
initIterators
()
{
shm
->
initAIterator
(
aitHeartBeat
);
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
shm
->
initDIterator
(
d
->
resp_dit
);
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
for
(
PList
::
iterator
it2
=
it
->
second
->
slst
.
begin
();
it2
!=
it
->
second
->
slst
.
end
();
++
it2
)
{
shm
->
initDIterator
(
it2
->
dit
);
shm
->
initAIterator
(
it2
->
ait
);
}
}
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
help_print
(
int
argc
,
const
char
*
const
*
argv
)
{
cout
<<
"Default: prefix='mbtcp'"
<<
endl
;
cout
<<
"--prefix-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек."
<<
endl
;
cout
<<
"--prefix-heartbeat-id - Данный процесс связан с указанным аналоговым heartbeat-дачиком."
<<
endl
;
cout
<<
"--prefix-heartbeat-max - Максимальное значение heartbeat-счётчика для данного процесса. По умолчанию 10."
<<
endl
;
cout
<<
"--prefix-ready-timeout - Время ожидания готовности SM к работе, мсек. (-1 - ждать 'вечно')"
<<
endl
;
cout
<<
"--prefix-force - Сохранять значения в SM, независимо от, того менялось ли значение"
<<
endl
;
cout
<<
"--prefix-initPause - Задержка перед инициализацией (время на активизация процесса)"
<<
endl
;
// cout << "--prefix-sm-ready-timeout - время на ожидание старта SM" << endl;
cout
<<
" Настройки протокола TCP: "
<<
endl
;
cout
<<
"--prefix-recv-timeout - Таймаут на ожидание ответа."
<<
endl
;
}
// -----------------------------------------------------------------------------
MBTCPMaster
*
MBTCPMaster
::
init_mbmaster
(
int
argc
,
const
char
*
const
*
argv
,
UniSetTypes
::
ObjectId
icID
,
SharedMemory
*
ic
,
const
std
::
string
prefix
)
{
string
name
=
conf
->
getArgParam
(
"--"
+
prefix
+
"-name"
,
"MBTCPMaster1"
);
if
(
name
.
empty
()
)
{
cerr
<<
"(MBTCPMaster): Не задан name'"
<<
endl
;
return
0
;
}
ObjectId
ID
=
conf
->
getObjectID
(
name
);
if
(
ID
==
UniSetTypes
::
DefaultObjectId
)
{
cerr
<<
"(MBTCPMaster): идентификатор '"
<<
name
<<
"' не найден в конф. файле!"
<<
" в секции "
<<
conf
->
getObjectsSection
()
<<
endl
;
return
0
;
}
dlog
[
Debug
::
INFO
]
<<
"(MBTCPMaster): name = "
<<
name
<<
"("
<<
ID
<<
")"
<<
endl
;
return
new
MBTCPMaster
(
ID
,
icID
,
ic
,
prefix
);
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBTCPMaster
::
DeviceType
&
dt
)
{
switch
(
dt
)
{
case
MBTCPMaster
:
:
dtRTU
:
os
<<
"RTU"
;
break
;
case
MBTCPMaster
:
:
dtMTR
:
os
<<
"MTR"
;
break
;
default
:
os
<<
"Unknown device type ("
<<
(
int
)
dt
<<
")"
;
break
;
}
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBTCPMaster
::
RSProperty
&
p
)
{
os
<<
" ("
<<
ModbusRTU
::
dat2str
(
p
.
reg
->
mbreg
)
<<
")"
<<
" sid="
<<
p
.
si
.
id
<<
" stype="
<<
p
.
stype
<<
" nbit="
<<
p
.
nbit
<<
" nbyte="
<<
p
.
nbyte
<<
" rnum="
<<
p
.
rnum
<<
" safety="
<<
p
.
safety
<<
" invert="
<<
p
.
invert
;
if
(
p
.
stype
==
UniversalIO
::
AnalogInput
||
p
.
stype
==
UniversalIO
::
AnalogOutput
)
{
os
<<
p
.
cal
<<
" cdiagram="
<<
(
p
.
cdiagram
?
"yes"
:
"no"
);
}
return
os
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
initDeviceList
()
{
xmlNode
*
respNode
=
conf
->
findNode
(
cnode
,
"DeviceList"
);
if
(
respNode
)
{
UniXML_iterator
it1
(
respNode
);
if
(
it1
.
goChildren
()
)
{
for
(;
it1
.
getCurrent
();
it1
.
goNext
()
)
{
ModbusRTU
::
ModbusAddr
a
=
ModbusRTU
::
str2mbAddr
(
it1
.
getProp
(
"addr"
));
initDeviceInfo
(
rmap
,
a
,
it1
);
}
}
else
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(init): <DeviceList> empty section..."
<<
endl
;
}
else
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(init): <DeviceList> not found..."
<<
endl
;
}
// -----------------------------------------------------------------------------
bool
MBTCPMaster
::
initDeviceInfo
(
RTUDeviceMap
&
m
,
ModbusRTU
::
ModbusAddr
a
,
UniXML_iterator
&
it
)
{
RTUDeviceMap
::
iterator
d
=
m
.
find
(
a
);
if
(
d
==
m
.
end
()
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(initDeviceInfo): not found device for addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
endl
;
return
false
;
}
d
->
second
->
ask_every_reg
=
it
.
getIntProp
(
"ask_every_reg"
);
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(initDeviceInfo): add addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
" ask_every_reg="
<<
d
->
second
->
ask_every_reg
<<
endl
;
string
s
(
it
.
getProp
(
"respondSensor"
));
if
(
!
s
.
empty
()
)
{
d
->
second
->
resp_id
=
conf
->
getSensorID
(
s
);
if
(
d
->
second
->
resp_id
==
DefaultObjectId
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initDeviceInfo): not found ID for noRespondSensor="
<<
s
<<
endl
;
return
false
;
}
}
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(initDeviceInfo): add addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
endl
;
int
tout
=
it
.
getPIntProp
(
"timeout"
,
UniSetTimer
::
WaitUpTime
);
d
->
second
->
resp_ptTimeout
.
setTiming
(
tout
);
d
->
second
->
resp_invert
=
it
.
getIntProp
(
"invert"
);
// d->second->no_clean_input = it.getIntProp("no_clean_input");
// dlog[Debug::INFO] << myname << "(initDeviceInfo): add " << d->second << endl;
return
true
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
printMap
(
MBTCPMaster
::
RTUDeviceMap
&
m
)
{
cout
<<
"devices: "
<<
endl
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it
=
m
.
begin
();
it
!=
m
.
end
();
++
it
)
{
cout
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
}
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBTCPMaster
::
RTUDeviceMap
&
m
)
{
os
<<
"devices: "
<<
endl
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it
=
m
.
begin
();
it
!=
m
.
end
();
++
it
)
{
os
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
}
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBTCPMaster
::
RTUDevice
&
d
)
{
os
<<
"addr="
<<
ModbusRTU
::
addr2str
(
d
.
mbaddr
)
<<
" type="
<<
d
.
dtype
<<
" respond_id="
<<
d
.
resp_id
<<
" respond_timeout="
<<
d
.
resp_ptTimeout
.
getInterval
()
<<
" respond_state="
<<
d
.
resp_state
<<
" respond_invert="
<<
d
.
resp_invert
<<
endl
;
os
<<
" regs: "
<<
endl
;
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
.
regmap
.
begin
();
it
!=
d
.
regmap
.
end
();
++
it
)
os
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBTCPMaster
::
RegInfo
&
r
)
{
os
<<
" id="
<<
r
.
id
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
r
.
mbreg
)
<<
" mbfunc="
<<
r
.
mbfunc
<<
" q_num="
<<
r
.
q_num
<<
" q_count="
<<
r
.
q_count
<<
" value="
<<
ModbusRTU
::
dat2str
(
r
.
mbval
)
<<
"("
<<
(
int
)
r
.
mbval
<<
")"
<<
" mtrType="
<<
MTR
::
type2str
(
r
.
mtrType
)
<<
endl
;
for
(
MBTCPMaster
::
PList
::
iterator
it
=
r
.
slst
.
begin
();
it
!=
r
.
slst
.
end
();
++
it
)
os
<<
" "
<<
(
*
it
)
<<
endl
;
return
os
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
rtuQueryOptimization
(
RTUDeviceMap
&
m
)
{
if
(
noQueryOptimization
)
return
;
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(rtuQueryOptimization): optimization..."
<<
endl
;
for
(
MBTCPMaster
::
RTUDeviceMap
::
iterator
it1
=
m
.
begin
();
it1
!=
m
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBTCPMaster
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
MBTCPMaster
::
RegMap
::
iterator
beg
=
it
;
ModbusRTU
::
ModbusData
reg
=
it
->
second
->
mbreg
;
beg
->
second
->
q_num
=
1
;
beg
->
second
->
q_count
=
1
;
it
++
;
for
(
;
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
(
it
->
second
->
mbreg
-
reg
)
>
1
)
break
;
if
(
beg
->
second
->
mbfunc
!=
it
->
second
->
mbfunc
)
break
;
beg
->
second
->
q_count
++
;
if
(
beg
->
second
->
q_count
>=
ModbusRTU
::
MAXDATALEN
)
break
;
reg
=
it
->
second
->
mbreg
;
it
->
second
->
q_num
=
beg
->
second
->
q_count
;
it
->
second
->
q_count
=
0
;
}
// check correct function...
if
(
beg
->
second
->
q_count
>
1
&&
beg
->
second
->
mbfunc
==
ModbusRTU
::
fnWriteOutputSingleRegister
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(rtuQueryOptimization): "
<<
" optimization change func="
<<
ModbusRTU
::
fnWriteOutputSingleRegister
<<
" <--> func="
<<
ModbusRTU
::
fnWriteOutputRegisters
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
beg
->
second
->
mbreg
);
beg
->
second
->
mbfunc
=
ModbusRTU
::
fnWriteOutputRegisters
;
}
else
if
(
beg
->
second
->
q_count
>
1
&&
beg
->
second
->
mbfunc
==
ModbusRTU
::
fnForceSingleCoil
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(rtuQueryOptimization): "
<<
" optimization change func="
<<
ModbusRTU
::
fnForceSingleCoil
<<
" <--> func="
<<
ModbusRTU
::
fnForceMultipleCoils
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
beg
->
second
->
mbreg
);
beg
->
second
->
mbfunc
=
ModbusRTU
::
fnForceMultipleCoils
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
it
--
;
}
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
updateRTU
(
RegMap
::
iterator
&
rit
)
{
RegInfo
*
r
(
rit
->
second
);
for
(
PList
::
iterator
it
=
r
->
slst
.
begin
();
it
!=
r
->
slst
.
end
();
++
it
)
updateRSProperty
(
&
(
*
it
),
false
);
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
updateRSProperty
(
RSProperty
*
p
,
bool
write_only
)
{
using
namespace
ModbusRTU
;
RegInfo
*
r
(
p
->
reg
->
rit
->
second
);
bool
save
=
isWriteFunction
(
r
->
mbfunc
);
if
(
!
save
&&
write_only
)
return
;
// если требуется инициализация и она ещё не произведена,
// то игнорируем
if
(
save
&&
!
r
->
mb_initOK
)
return
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
"updateP: sid="
<<
p
->
si
.
id
<<
" mbval="
<<
r
->
mbval
<<
" vtype="
<<
p
->
vType
<<
" rnum="
<<
p
->
rnum
<<
" nbit="
<<
p
->
nbit
<<
" save="
<<
save
<<
" ioype="
<<
p
->
stype
<<
" mb_initOK="
<<
r
->
mb_initOK
<<
" sm_initOK="
<<
r
->
sm_initOK
<<
endl
;
try
{
if
(
p
->
vType
==
VTypes
::
vtUnknown
)
{
ModbusRTU
::
DataBits16
b
(
r
->
mbval
);
if
(
p
->
nbit
>=
0
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
bool
set
=
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
b
.
set
(
p
->
nbit
,
set
);
r
->
mbval
=
b
.
mdata
();
r
->
sm_initOK
=
true
;
}
}
else
{
bool
set
=
b
[
p
->
nbit
];
IOBase
::
processingAsDI
(
p
,
set
,
shm
,
force
);
}
return
;
}
if
(
p
->
rnum
<=
1
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
r
->
mbval
),
shm
,
force
);
}
return
;
}
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(updateRSProperty): IGNORE item: rnum="
<<
p
->
rnum
<<
" > 1 ?!! for id="
<<
p
->
si
.
id
<<
endl
;
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtSigned
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
(
signed
short
)
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
(
signed
short
)
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
{
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
r
->
mbval
),
shm
,
force
);
}
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtUnsigned
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
(
unsigned
short
)
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
(
unsigned
short
)
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
{
IOBase
::
processingAsAI
(
p
,
(
unsigned
short
)
r
->
mbval
,
shm
,
force
);
}
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtByte
)
{
if
(
p
->
nbyte
<=
0
||
p
->
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(updateRSProperty): IGNORE item: reg="
<<
ModbusRTU
::
dat2str
(
r
->
mbreg
)
<<
" vtype="
<<
p
->
vType
<<
" but nbyte="
<<
p
->
nbyte
<<
endl
;
return
;
}
if
(
save
&&
r
->
sm_initOK
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
Byte
b
(
r
->
mbval
);
b
.
raw
.
b
[
p
->
nbyte
-
1
]
=
v
;
r
->
mbval
=
b
.
raw
.
w
;
r
->
sm_initOK
=
true
;
}
}
else
{
VTypes
::
Byte
b
(
r
->
mbval
);
IOBase
::
processingAsAI
(
p
,
b
.
raw
.
b
[
p
->
nbyte
-
1
],
shm
,
force
);
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtF2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
float
f
=
IOBase
::
processingFasAO
(
p
,
shm
,
force_out
);
VTypes
::
F2
f2
(
f
);
for
(
int
k
=
0
;
k
<
VTypes
::
F2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
F2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
F2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
F2
f
(
data
,
VTypes
::
F2
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtF4
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
float
f
=
IOBase
::
processingFasAO
(
p
,
shm
,
force_out
);
VTypes
::
F4
f4
(
f
);
for
(
int
k
=
0
;
k
<
VTypes
::
F4
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f4
.
raw
.
v
[
k
];
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
F4
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
F4
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
F4
f
(
data
,
VTypes
::
F4
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtI2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
I2
i2
(
v
);
for
(
int
k
=
0
;
k
<
VTypes
::
I2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
i2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
I2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
I2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
I2
i2
(
data
,
VTypes
::
I2
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
p
,
(
int
)
i2
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtU2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
U2
u2
(
v
);
for
(
int
k
=
0
;
k
<
VTypes
::
U2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
u2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
U2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
U2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
U2
u2
(
data
,
VTypes
::
U2
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
p
,
(
unsigned
int
)
u2
,
shm
,
force
);
}
}
return
;
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): catch ..."
<<
endl
;
}
// Если SM стала (или была) недоступна
// то флаг инициализации надо сбросить
r
->
sm_initOK
=
false
;
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
updateMTR
(
RegMap
::
iterator
&
rit
)
{
RegInfo
*
r
(
rit
->
second
);
using
namespace
ModbusRTU
;
bool
save
=
isWriteFunction
(
r
->
mbfunc
);
{
for
(
PList
::
iterator
it
=
r
->
slst
.
begin
();
it
!=
r
->
slst
.
end
();
++
it
)
{
try
{
if
(
r
->
mtrType
==
MTR
::
mtT1
)
{
if
(
save
)
r
->
mbval
=
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
);
else
{
MTR
::
T1
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT2
)
{
if
(
save
)
{
MTR
::
T2
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T2
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT3
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T3
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T3
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T3
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T3
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T3
t
(
data
,
MTR
::
T3
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
&
(
*
it
),
(
long
)
t
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT4
)
{
if
(
save
)
cerr
<<
myname
<<
"(updateMTR): write (T4) reg("
<<
dat2str
(
r
->
mbreg
)
<<
") to MTR NOT YET!!!"
<<
endl
;
else
{
MTR
::
T4
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
uni_atoi
(
t
.
sval
),
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT5
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T5
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T5
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T5
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T5
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T5
t
(
data
,
MTR
::
T5
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT6
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T6
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T6
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T6
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T6
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T6
t
(
data
,
MTR
::
T6
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT7
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T7
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T7
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T7
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T7
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T7
t
(
data
,
MTR
::
T7
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT16
)
{
if
(
save
)
{
MTR
::
T16
t
(
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T16
t
(
r
->
mbval
);
IOBase
::
processingFasAI
(
&
(
*
it
),
t
.
fval
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT17
)
{
if
(
save
)
{
MTR
::
T17
t
(
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T17
t
(
r
->
mbval
);
IOBase
::
processingFasAI
(
&
(
*
it
),
t
.
fval
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtF1
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
float
f
=
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
);
MTR
::
F1
f1
(
f
);
for
(
int
k
=
0
;
k
<
MTR
::
F1
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f1
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
F1
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
F1
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
F1
t
(
data
,
MTR
::
F1
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
,
shm
,
force
);
}
continue
;
}
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): catch ..."
<<
endl
;
}
}
}
}
// -----------------------------------------------------------------------------
void
MBTCPMaster
::
execute
()
{
no_extimer
=
true
;
try
{
askTimer
(
tmExchange
,
0
);
}
catch
(...){}
initMB
(
false
);
while
(
1
)
{
try
{
step
();
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(execute): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(execute): catch ..."
<<
endl
;
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(execute): catch ..."
<<
endl
;
}
msleep
(
polltime
);
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBTCPMaster::PList& lst )
std
::
ostream
&
MBTCPMaster
::
print_plist
(
std
::
ostream
&
os
,
MBTCPMaster
::
PList
&
lst
)
{
os
<<
"[ "
;
for
(
MBTCPMaster
::
PList
::
const_iterator
it
=
lst
.
begin
();
it
!=
lst
.
end
();
++
it
)
os
<<
"("
<<
it
->
si
.
id
<<
")"
<<
conf
->
oind
->
getBaseName
(
conf
->
oind
->
getMapName
(
it
->
si
.
id
))
<<
" "
;
os
<<
"]"
;
return
os
;
}
// -----------------------------------------------------------------------------
\ No newline at end of file
extensions/RTUExchange/RTUExchange.h
View file @
a15d2cc4
...
...
@@ -119,8 +119,6 @@ class RTUExchange:
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
RegInfo
&
r
);
struct
RTUDevice
{
RTUDevice
()
:
...
...
extensions/lib/MBExchange.cc
View file @
a15d2cc4
...
...
@@ -13,6 +13,7 @@ using namespace UniSetExtensions;
MBExchange
::
MBExchange
(
UniSetTypes
::
ObjectId
objId
,
UniSetTypes
::
ObjectId
shmId
,
SharedMemory
*
ic
,
const
std
::
string
prefix
)
:
UniSetObject_LT
(
objId
),
allInitOK
(
false
),
shm
(
0
),
initPause
(
0
),
force
(
false
),
...
...
@@ -21,7 +22,12 @@ mbregFromID(false),
sidExchangeMode
(
DefaultObjectId
),
activated
(
false
),
noQueryOptimization
(
false
),
prefix
(
prefix
)
no_extimer
(
false
),
prefix
(
prefix
),
poll_count
(
0
),
prop_prefix
(
""
),
mb
(
0
),
pollActivated
(
false
)
{
// cout << "$ $" << endl;
...
...
@@ -123,7 +129,7 @@ prefix(prefix)
// -----------------------------------------------------------------------------
void
MBExchange
::
help_print
(
int
argc
,
const
char
*
const
*
argv
)
{
cout
<<
"--prefix-name name - ObjectId (имя) процесса. По умолчанию: MB
TCPMaster
1"
<<
endl
;
cout
<<
"--prefix-name name - ObjectId (имя) процесса. По умолчанию: MB
Exchange
1"
<<
endl
;
cout
<<
"--prefix-confnode name - Настроечная секция в конф. файле <name>. "
<<
endl
;
cout
<<
"--prefix-polltime msec - Пауза между опросаом карт. По умолчанию 200 мсек."
<<
endl
;
cout
<<
"--prefix-heartbeat-id name - Данный процесс связан с указанным аналоговым heartbeat-дачиком."
<<
endl
;
...
...
@@ -196,20 +202,6 @@ void MBExchange::setProcActive( bool st )
activated
=
st
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
sensorInfo
(
UniSetTypes
::
SensorMessage
*
sm
)
{
if
(
force_out
)
return
;
if
(
sm
->
id
==
sidExchangeMode
)
{
exchangeMode
=
sm
->
value
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(sensorInfo): exchange MODE="
<<
sm
->
value
<<
std
::
endl
;
return
;
}
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
sigterm
(
int
signo
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
": ********* SIGTERM("
<<
signo
<<
") ********"
<<
endl
;
...
...
@@ -270,26 +262,19 @@ void MBExchange::initIterators()
{
shm
->
initAIterator
(
aitHeartBeat
);
shm
->
initAIterator
(
aitExchangeMode
);
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBExchange
::
DeviceType
&
dt
)
{
switch
(
dt
)
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
case
MBExchange
:
:
dtRTU
:
os
<<
"RTU"
;
break
;
case
MBExchange
:
:
dtMTR
:
os
<<
"MTR"
;
break
;
default
:
os
<<
"Unknown device type ("
<<
(
int
)
dt
<<
")"
;
break
;
RTUDevice
*
d
(
it1
->
second
);
shm
->
initDIterator
(
d
->
resp_dit
);
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
for
(
PList
::
iterator
it2
=
it
->
second
->
slst
.
begin
();
it2
!=
it
->
second
->
slst
.
end
();
++
it2
)
{
shm
->
initDIterator
(
it2
->
dit
);
shm
->
initAIterator
(
it2
->
ait
);
}
}
}
return
os
;
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
checkUpdateSM
(
bool
wrFunc
)
...
...
@@ -341,3 +326,2227 @@ bool MBExchange::checkPoll( bool wrFunc )
return
true
;
}
// -----------------------------------------------------------------------------
MBExchange
::
RegID
MBExchange
::
genRegID
(
const
ModbusRTU
::
ModbusData
mbreg
,
const
int
fn
)
{
// формула для вычисления ID
// требования:
// 1. ID > диапазона возможных регистров
// 2. одинаковые регистры, но разные функции должны давать разный ID
// 3. регистры идущие подряд, должна давать ID идущие тоже подряд
// Вообще диапазоны:
// mbreg: 0..65535
// fn: 0...255
int
max
=
numeric_limits
<
ModbusRTU
::
ModbusData
>::
max
();
// по идее 65535
int
fn_max
=
numeric_limits
<
ModbusRTU
::
ModbusByte
>::
max
();
// по идее 255
// fn необходимо привести к диапазону 0..max
return
max
+
mbreg
+
max
+
UniSetTypes
::
lcalibrate
(
fn
,
0
,
fn_max
,
0
,
max
,
false
);
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
printMap
(
MBExchange
::
RTUDeviceMap
&
m
)
{
cout
<<
"devices: "
<<
endl
;
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it
=
m
.
begin
();
it
!=
m
.
end
();
++
it
)
{
cout
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
}
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBExchange
::
RTUDeviceMap
&
m
)
{
os
<<
"devices: "
<<
endl
;
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it
=
m
.
begin
();
it
!=
m
.
end
();
++
it
)
{
os
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
}
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBExchange
::
RTUDevice
&
d
)
{
os
<<
"addr="
<<
ModbusRTU
::
addr2str
(
d
.
mbaddr
)
<<
" type="
<<
d
.
dtype
<<
" respond_id="
<<
d
.
resp_id
<<
" respond_timeout="
<<
d
.
resp_ptTimeout
.
getInterval
()
<<
" respond_state="
<<
d
.
resp_state
<<
" respond_invert="
<<
d
.
resp_invert
<<
endl
;
os
<<
" regs: "
<<
endl
;
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
.
regmap
.
begin
();
it
!=
d
.
regmap
.
end
();
++
it
)
os
<<
" "
<<
*
(
it
->
second
)
<<
endl
;
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
MBExchange
::
RegInfo
&
r
)
{
os
<<
" id="
<<
r
.
id
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
r
.
mbreg
)
<<
" mbfunc="
<<
r
.
mbfunc
<<
" q_num="
<<
r
.
q_num
<<
" q_count="
<<
r
.
q_count
<<
" value="
<<
ModbusRTU
::
dat2str
(
r
.
mbval
)
<<
"("
<<
(
int
)
r
.
mbval
<<
")"
<<
" mtrType="
<<
MTR
::
type2str
(
r
.
mtrType
)
<<
endl
;
for
(
MBExchange
::
PList
::
iterator
it
=
r
.
slst
.
begin
();
it
!=
r
.
slst
.
end
();
++
it
)
os
<<
" "
<<
(
*
it
)
<<
endl
;
return
os
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
rtuQueryOptimization
(
RTUDeviceMap
&
m
)
{
if
(
noQueryOptimization
)
return
;
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(rtuQueryOptimization): optimization..."
<<
endl
;
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
m
.
begin
();
it1
!=
m
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
// Вообще в map они уже лежат в нужном порядке, т.е. функция genRegID() гарантирует
// что регистры идущие подряд с одниковой функцией чтения/записи получат подряд идущие ID.
// так что оптимтизация это просто нахождение мест где id идут не подряд...
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
MBExchange
::
RegMap
::
iterator
beg
=
it
;
RegID
id
=
it
->
second
->
id
;
// или собственно it->first
beg
->
second
->
q_num
=
1
;
beg
->
second
->
q_count
=
1
;
it
++
;
for
(
;
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
(
it
->
second
->
id
-
id
)
>
1
)
{
it
--
;
// раз это регистр уже следующий, то надо вернуть на шаг обратно..
break
;
}
beg
->
second
->
q_count
++
;
if
(
beg
->
second
->
q_count
>=
ModbusRTU
::
MAXDATALEN
)
break
;
id
=
it
->
second
->
id
;
it
->
second
->
q_num
=
beg
->
second
->
q_count
;
it
->
second
->
q_count
=
0
;
}
// check correct function...
if
(
beg
->
second
->
q_count
>
1
&&
beg
->
second
->
mbfunc
==
ModbusRTU
::
fnWriteOutputSingleRegister
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(rtuQueryOptimization): "
<<
" optimization change func="
<<
ModbusRTU
::
fnWriteOutputSingleRegister
<<
" <--> func="
<<
ModbusRTU
::
fnWriteOutputRegisters
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
beg
->
second
->
mbreg
);
beg
->
second
->
mbfunc
=
ModbusRTU
::
fnWriteOutputRegisters
;
}
else
if
(
beg
->
second
->
q_count
>
1
&&
beg
->
second
->
mbfunc
==
ModbusRTU
::
fnForceSingleCoil
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(rtuQueryOptimization): "
<<
" optimization change func="
<<
ModbusRTU
::
fnForceSingleCoil
<<
" <--> func="
<<
ModbusRTU
::
fnForceMultipleCoils
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
beg
->
second
->
mbreg
);
beg
->
second
->
mbfunc
=
ModbusRTU
::
fnForceMultipleCoils
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
}
}
}
// -----------------------------------------------------------------------------
//std::ostream& operator<<( std::ostream& os, MBExchange::PList& lst )
std
::
ostream
&
MBExchange
::
print_plist
(
std
::
ostream
&
os
,
MBExchange
::
PList
&
lst
)
{
os
<<
"[ "
;
for
(
MBExchange
::
PList
::
const_iterator
it
=
lst
.
begin
();
it
!=
lst
.
end
();
++
it
)
os
<<
"("
<<
it
->
si
.
id
<<
")"
<<
conf
->
oind
->
getBaseName
(
conf
->
oind
->
getMapName
(
it
->
si
.
id
))
<<
" "
;
os
<<
"]"
;
return
os
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
firstInitRegisters
()
{
// если все вернут TRUE, значит OK.
allInitOK
=
true
;
for
(
InitList
::
iterator
it
=
initRegList
.
begin
();
it
!=
initRegList
.
end
();
++
it
)
{
try
{
it
->
initOK
=
preInitRead
(
it
);
allInitOK
=
it
->
initOK
;
}
catch
(
ModbusRTU
::
mbException
&
ex
)
{
allInitOK
=
false
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): FAILED ask addr="
<<
ModbusRTU
::
addr2str
(
it
->
dev
->
mbaddr
)
<<
" reg="
<<
ModbusRTU
::
dat2str
(
it
->
mbreg
)
<<
" err: "
<<
ex
<<
endl
;
}
if
(
!
it
->
dev
->
ask_every_reg
)
break
;
}
}
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
preInitRead
(
InitList
::
iterator
&
p
)
{
if
(
p
->
initOK
)
return
true
;
RTUDevice
*
dev
=
p
->
dev
;
int
q_count
=
p
->
p
.
rnum
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): poll "
<<
" mbaddr="
<<
ModbusRTU
::
addr2str
(
dev
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" mbfunc="
<<
p
->
mbfunc
<<
" q_count="
<<
q_count
<<
endl
;
if
(
q_count
>
ModbusRTU
::
MAXDATALEN
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(preInitRead): count("
<<
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
}
switch
(
p
->
mbfunc
)
{
case
ModbusRTU
:
:
fnReadOutputRegisters
:
{
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
p
->
initOK
=
initSMValue
(
ret
.
data
,
ret
.
count
,
&
(
p
->
p
));
}
break
;
case
ModbusRTU
:
:
fnReadInputRegisters
:
{
ModbusRTU
::
ReadInputRetMessage
ret1
=
mb
->
read04
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
p
->
initOK
=
initSMValue
(
ret1
.
data
,
ret1
.
count
,
&
(
p
->
p
));
}
break
;
case
ModbusRTU
:
:
fnReadInputStatus
:
{
ModbusRTU
::
ReadInputStatusRetMessage
ret
=
mb
->
read02
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
ModbusRTU
::
ModbusData
*
dat
=
new
ModbusRTU
::
ModbusData
[
q_count
];
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
q_count
;
k
++
,
m
++
)
dat
[
m
]
=
b
[
k
];
}
p
->
initOK
=
initSMValue
(
dat
,
q_count
,
&
(
p
->
p
));
delete
[]
dat
;
}
break
;
case
ModbusRTU
:
:
fnReadCoilStatus
:
{
ModbusRTU
::
ReadCoilRetMessage
ret
=
mb
->
read01
(
dev
->
mbaddr
,
p
->
mbreg
,
q_count
);
ModbusRTU
::
ModbusData
*
dat
=
new
ModbusRTU
::
ModbusData
[
q_count
];
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
q_count
;
k
++
,
m
++
)
dat
[
m
]
=
b
[
k
];
}
p
->
initOK
=
initSMValue
(
dat
,
q_count
,
&
(
p
->
p
));
delete
[]
dat
;
}
break
;
default
:
p
->
initOK
=
false
;
break
;
}
if
(
p
->
initOK
)
{
bool
f_out
=
force_out
;
// выставляем флаг принудительного обновления
force_out
=
true
;
p
->
ri
->
mb_initOK
=
true
;
p
->
ri
->
sm_initOK
=
false
;
updateRTU
(
p
->
ri
->
rit
);
force_out
=
f_out
;
}
return
p
->
initOK
;
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
initSMValue
(
ModbusRTU
::
ModbusData
*
data
,
int
count
,
RSProperty
*
p
)
{
using
namespace
ModbusRTU
;
try
{
if
(
p
->
vType
==
VTypes
::
vtUnknown
)
{
ModbusRTU
::
DataBits16
b
(
data
[
0
]);
if
(
p
->
nbit
>=
0
)
{
bool
set
=
b
[
p
->
nbit
];
IOBase
::
processingAsDI
(
p
,
set
,
shm
,
force
);
return
true
;
}
if
(
p
->
rnum
<=
1
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
data
[
0
]),
shm
,
force
);
return
true
;
}
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initSMValue): IGNORE item: rnum="
<<
p
->
rnum
<<
" > 1 ?!! for id="
<<
p
->
si
.
id
<<
endl
;
return
false
;
}
else
if
(
p
->
vType
==
VTypes
::
vtSigned
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
data
[
0
]),
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtUnsigned
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
data
[
0
],
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
unsigned
short
)
data
[
0
],
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtByte
)
{
if
(
p
->
nbyte
<=
0
||
p
->
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initSMValue): IGNORE item: sid="
<<
ModbusRTU
::
dat2str
(
p
->
si
.
id
)
<<
" vtype="
<<
p
->
vType
<<
" but nbyte="
<<
p
->
nbyte
<<
endl
;
return
false
;
}
VTypes
::
Byte
b
(
data
[
0
]);
IOBase
::
processingAsAI
(
p
,
b
.
raw
.
b
[
p
->
nbyte
-
1
],
shm
,
force
);
return
true
;
}
else
if
(
p
->
vType
==
VTypes
::
vtF2
)
{
VTypes
::
F2
f
(
data
,
VTypes
::
F2
::
wsize
());
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtF4
)
{
VTypes
::
F4
f
(
data
,
VTypes
::
F4
::
wsize
());
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtI2
)
{
VTypes
::
I2
i2
(
data
,
VTypes
::
I2
::
wsize
());
IOBase
::
processingAsAI
(
p
,
(
int
)
i2
,
shm
,
force
);
}
else
if
(
p
->
vType
==
VTypes
::
vtU2
)
{
VTypes
::
U2
u2
(
data
,
VTypes
::
U2
::
wsize
());
IOBase
::
processingAsAI
(
p
,
(
unsigned
int
)
u2
,
shm
,
force
);
}
return
true
;
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(initSMValue): catch ..."
<<
endl
;
}
return
false
;
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
pollRTU
(
RTUDevice
*
dev
,
RegMap
::
iterator
&
it
)
{
RegInfo
*
p
(
it
->
second
);
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): poll "
<<
" mbaddr="
<<
ModbusRTU
::
addr2str
(
dev
->
mbaddr
)
<<
" mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" mbfunc="
<<
p
->
mbfunc
<<
" q_count="
<<
p
->
q_count
<<
" mb_initOK="
<<
p
->
mb_initOK
<<
" sm_initOK="
<<
p
->
sm_initOK
<<
" mbval="
<<
p
->
mbval
<<
endl
;
if
(
p
->
q_count
>
ModbusRTU
::
MAXDATALEN
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): count("
<<
p
->
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
}
if
(
!
checkPoll
(
ModbusRTU
::
isWriteFunction
(
p
->
mbfunc
))
)
return
true
;
if
(
p
->
q_count
==
0
)
{
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(pollRTU): q_count=0 for mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE register..."
<<
endl
;
return
false
;
}
switch
(
p
->
mbfunc
)
{
case
ModbusRTU
:
:
fnReadInputRegisters
:
{
ModbusRTU
::
ReadInputRetMessage
ret
=
mb
->
read04
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
it
->
second
->
mbval
=
ret
.
data
[
i
];
it
--
;
}
break
;
case
ModbusRTU
:
:
fnReadOutputRegisters
:
{
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
it
->
second
->
mbval
=
ret
.
data
[
i
];
it
--
;
}
break
;
case
ModbusRTU
:
:
fnReadInputStatus
:
{
ModbusRTU
::
ReadInputStatusRetMessage
ret
=
mb
->
read02
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
p
->
q_count
;
k
++
,
it
++
,
m
++
)
it
->
second
->
mbval
=
b
[
k
];
}
it
--
;
}
break
;
case
ModbusRTU
:
:
fnReadCoilStatus
:
{
ModbusRTU
::
ReadCoilRetMessage
ret
=
mb
->
read01
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
int
m
=
0
;
for
(
int
i
=
0
;
i
<
ret
.
bcnt
;
i
++
)
{
ModbusRTU
::
DataBits
b
(
ret
.
data
[
i
]);
for
(
int
k
=
0
;
k
<
ModbusRTU
::
BitsPerByte
&&
m
<
p
->
q_count
;
k
++
,
it
++
,
m
++
)
it
->
second
->
mbval
=
b
[
k
]
?
1
:
0
;
}
it
--
;
}
break
;
case
ModbusRTU
:
:
fnWriteOutputSingleRegister
:
{
if
(
p
->
q_count
!=
1
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE WRITE SINGLE REGISTER (0x06) q_count="
<<
p
->
q_count
<<
" ..."
<<
endl
;
return
false
;
}
if
(
!
p
->
sm_initOK
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" slist="
<<
(
*
p
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
// cerr << "**** mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU
::
WriteSingleOutputRetMessage
ret
=
mb
->
write06
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
mbval
);
}
break
;
case
ModbusRTU
:
:
fnWriteOutputRegisters
:
{
if
(
!
p
->
sm_initOK
)
{
// может быть такая ситуация, что
// некоторые регистры уже инициализированы, а другие ещё нет
// при этом после оптимизации они попадают в один запрос
// поэтому здесь сделано так:
// если q_num > 1, значит этот регистр относится к предыдущему запросу
// и его просто надо пропустить..
if
(
p
->
q_num
>
1
)
return
true
;
// смещаем итератор, если данный запрос содержит много регистров
// if( q->count > 1 )
// {
// for( int i=0; i<p->q_count; i++ )
// it++;
// return true;
// }
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
ModbusRTU
::
WriteOutputMessage
msg
(
dev
->
mbaddr
,
p
->
mbreg
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
msg
.
addData
(
it
->
second
->
mbval
);
it
--
;
ModbusRTU
::
WriteOutputRetMessage
ret
=
mb
->
write10
(
msg
);
}
break
;
case
ModbusRTU
:
:
fnForceSingleCoil
:
{
if
(
p
->
q_count
!=
1
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE FORCE SINGLE COIL (0x05) q_count="
<<
p
->
q_count
<<
" ..."
<<
endl
;
return
false
;
}
if
(
!
p
->
sm_initOK
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
// cerr << "****(coil) mbreg=" << ModbusRTU::dat2str(p->mbreg) << " val=" << ModbusRTU::dat2str(p->mbval) << endl;
ModbusRTU
::
ForceSingleCoilRetMessage
ret
=
mb
->
write05
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
mbval
);
}
break
;
case
ModbusRTU
:
:
fnForceMultipleCoils
:
{
if
(
!
p
->
sm_initOK
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE...(sm_initOK=false)"
<<
endl
;
return
true
;
}
ModbusRTU
::
ForceCoilsMessage
msg
(
dev
->
mbaddr
,
p
->
mbreg
);
for
(
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
msg
.
addBit
(
(
it
->
second
->
mbval
?
true
:
false
)
);
it
--
;
// cerr << "*********** (write multiple): " << msg << endl;
ModbusRTU
::
ForceCoilsRetMessage
ret
=
mb
->
write0F
(
msg
);
}
break
;
default
:
{
if
(
dlog
.
debugging
(
Debug
::
WARN
)
)
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(pollRTU): mbreg="
<<
ModbusRTU
::
dat2str
(
p
->
mbreg
)
<<
" IGNORE mfunc="
<<
(
int
)
p
->
mbfunc
<<
" ..."
<<
endl
;
return
false
;
}
break
;
}
return
true
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
updateSM
()
{
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
// обновление датчиков связи происходит в другом потоке
// чтобы не зависеть от TCP таймаутов
// см. updateRespondSensors()
// update values...
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
try
{
if
(
d
->
dtype
==
dtRTU
)
updateRTU
(
it
);
else
if
(
d
->
dtype
==
dtMTR
)
updateMTR
(
it
);
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateSM): catch ..."
<<
endl
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
}
}
}
// -----------------------------------------------------------------------------
void
MBExchange
::
updateRTU
(
RegMap
::
iterator
&
rit
)
{
RegInfo
*
r
(
rit
->
second
);
for
(
PList
::
iterator
it
=
r
->
slst
.
begin
();
it
!=
r
->
slst
.
end
();
++
it
)
updateRSProperty
(
&
(
*
it
),
false
);
}
// -----------------------------------------------------------------------------
void
MBExchange
::
updateRSProperty
(
RSProperty
*
p
,
bool
write_only
)
{
using
namespace
ModbusRTU
;
RegInfo
*
r
(
p
->
reg
->
rit
->
second
);
bool
save
=
isWriteFunction
(
r
->
mbfunc
);
if
(
!
save
&&
write_only
)
return
;
if
(
!
checkUpdateSM
(
save
)
)
return
;
// если требуется инициализация и она ещё не произведена,
// то игнорируем
if
(
save
&&
!
r
->
mb_initOK
)
return
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
"updateP: sid="
<<
p
->
si
.
id
<<
" mbval="
<<
r
->
mbval
<<
" vtype="
<<
p
->
vType
<<
" rnum="
<<
p
->
rnum
<<
" nbit="
<<
p
->
nbit
<<
" save="
<<
save
<<
" ioype="
<<
p
->
stype
<<
" mb_initOK="
<<
r
->
mb_initOK
<<
" sm_initOK="
<<
r
->
sm_initOK
<<
endl
;
try
{
if
(
p
->
vType
==
VTypes
::
vtUnknown
)
{
ModbusRTU
::
DataBits16
b
(
r
->
mbval
);
if
(
p
->
nbit
>=
0
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
bool
set
=
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
b
.
set
(
p
->
nbit
,
set
);
r
->
mbval
=
b
.
mdata
();
r
->
sm_initOK
=
true
;
}
}
else
{
bool
set
=
b
[
p
->
nbit
];
IOBase
::
processingAsDI
(
p
,
set
,
shm
,
force
);
}
return
;
}
if
(
p
->
rnum
<=
1
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
r
->
mbval
),
shm
,
force
);
}
return
;
}
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(updateRSProperty): IGNORE item: rnum="
<<
p
->
rnum
<<
" > 1 ?!! for id="
<<
p
->
si
.
id
<<
endl
;
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtSigned
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
(
signed
short
)
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
(
signed
short
)
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
{
IOBase
::
processingAsAI
(
p
,
(
signed
short
)(
r
->
mbval
),
shm
,
force
);
}
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtUnsigned
)
{
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
r
->
mbval
=
(
unsigned
short
)
IOBase
::
processingAsDO
(
p
,
shm
,
force_out
);
}
else
r
->
mbval
=
(
unsigned
short
)
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
r
->
sm_initOK
=
true
;
}
}
else
{
if
(
p
->
stype
==
UniversalIO
::
DigitalInput
||
p
->
stype
==
UniversalIO
::
DigitalOutput
)
{
IOBase
::
processingAsDI
(
p
,
r
->
mbval
,
shm
,
force
);
}
else
{
IOBase
::
processingAsAI
(
p
,
(
unsigned
short
)
r
->
mbval
,
shm
,
force
);
}
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtByte
)
{
if
(
p
->
nbyte
<=
0
||
p
->
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(updateRSProperty): IGNORE item: reg="
<<
ModbusRTU
::
dat2str
(
r
->
mbreg
)
<<
" vtype="
<<
p
->
vType
<<
" but nbyte="
<<
p
->
nbyte
<<
endl
;
return
;
}
if
(
save
&&
r
->
sm_initOK
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
Byte
b
(
r
->
mbval
);
b
.
raw
.
b
[
p
->
nbyte
-
1
]
=
v
;
r
->
mbval
=
b
.
raw
.
w
;
r
->
sm_initOK
=
true
;
}
}
else
{
VTypes
::
Byte
b
(
r
->
mbval
);
IOBase
::
processingAsAI
(
p
,
b
.
raw
.
b
[
p
->
nbyte
-
1
],
shm
,
force
);
}
return
;
}
else
if
(
p
->
vType
==
VTypes
::
vtF2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
float
f
=
IOBase
::
processingFasAO
(
p
,
shm
,
force_out
);
VTypes
::
F2
f2
(
f
);
for
(
int
k
=
0
;
k
<
VTypes
::
F2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
F2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
F2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
F2
f
(
data
,
VTypes
::
F2
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtF4
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
float
f
=
IOBase
::
processingFasAO
(
p
,
shm
,
force_out
);
VTypes
::
F4
f4
(
f
);
for
(
int
k
=
0
;
k
<
VTypes
::
F4
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f4
.
raw
.
v
[
k
];
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
F4
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
F4
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
F4
f
(
data
,
VTypes
::
F4
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
p
,
(
float
)
f
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtI2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
I2
i2
(
v
);
for
(
int
k
=
0
;
k
<
VTypes
::
I2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
i2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
I2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
I2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
I2
i2
(
data
,
VTypes
::
I2
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
p
,
(
int
)
i2
,
shm
,
force
);
}
}
else
if
(
p
->
vType
==
VTypes
::
vtU2
)
{
RegMap
::
iterator
i
(
p
->
reg
->
rit
);
if
(
save
)
{
if
(
r
->
mb_initOK
)
{
long
v
=
IOBase
::
processingAsAO
(
p
,
shm
,
force_out
);
VTypes
::
U2
u2
(
v
);
for
(
int
k
=
0
;
k
<
VTypes
::
U2
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
u2
.
raw
.
v
[
k
];
r
->
sm_initOK
=
true
;
}
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
VTypes
::
U2
::
wsize
()];
for
(
int
k
=
0
;
k
<
VTypes
::
U2
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
VTypes
::
U2
u2
(
data
,
VTypes
::
U2
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
p
,
(
unsigned
int
)
u2
,
shm
,
force
);
}
}
return
;
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateRSProperty): catch ..."
<<
endl
;
}
// Если SM стала (или была) недоступна
// то флаг инициализации надо сбросить
r
->
sm_initOK
=
false
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
updateMTR
(
RegMap
::
iterator
&
rit
)
{
RegInfo
*
r
(
rit
->
second
);
using
namespace
ModbusRTU
;
bool
save
=
isWriteFunction
(
r
->
mbfunc
);
if
(
save
&&
exchangeMode
==
emReadOnly
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):"
<<
" skip... mode=emReadOnly "
<<
endl
;
return
;
}
if
(
!
save
&&
exchangeMode
==
emWriteOnly
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):"
<<
" skip... mode=emWriteOnly "
<<
endl
;
return
;
}
if
(
save
&&
exchangeMode
==
emSkipSaveToSM
)
{
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):"
<<
" skip... mode=emSkipSaveToSM "
<<
endl
;
return
;
}
{
for
(
PList
::
iterator
it
=
r
->
slst
.
begin
();
it
!=
r
->
slst
.
end
();
++
it
)
{
try
{
if
(
r
->
mtrType
==
MTR
::
mtT1
)
{
if
(
save
)
r
->
mbval
=
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
);
else
{
MTR
::
T1
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT2
)
{
if
(
save
)
{
MTR
::
T2
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T2
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT3
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T3
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T3
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T3
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T3
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T3
t
(
data
,
MTR
::
T3
::
wsize
());
delete
[]
data
;
IOBase
::
processingAsAI
(
&
(
*
it
),
(
long
)
t
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT4
)
{
if
(
save
)
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(updateMTR): write (T4) reg("
<<
dat2str
(
r
->
mbreg
)
<<
") to MTR NOT YET!!!"
<<
endl
;
else
{
MTR
::
T4
t
(
r
->
mbval
);
IOBase
::
processingAsAI
(
&
(
*
it
),
uni_atoi
(
t
.
sval
),
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT5
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T5
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T5
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T5
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T5
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T5
t
(
data
,
MTR
::
T5
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT6
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T6
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T6
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T6
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T6
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T6
t
(
data
,
MTR
::
T6
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT7
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
MTR
::
T7
t
(
IOBase
::
processingAsAO
(
&
(
*
it
),
shm
,
force_out
));
for
(
int
k
=
0
;
k
<
MTR
::
T7
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
t
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
T7
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
T7
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
T7
t
(
data
,
MTR
::
T7
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
.
val
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT16
)
{
if
(
save
)
{
MTR
::
T16
t
(
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T16
t
(
r
->
mbval
);
IOBase
::
processingFasAI
(
&
(
*
it
),
t
.
fval
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtT17
)
{
if
(
save
)
{
MTR
::
T17
t
(
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
));
r
->
mbval
=
t
.
val
;
}
else
{
MTR
::
T17
t
(
r
->
mbval
);
IOBase
::
processingFasAI
(
&
(
*
it
),
t
.
fval
,
shm
,
force
);
}
continue
;
}
if
(
r
->
mtrType
==
MTR
::
mtF1
)
{
RegMap
::
iterator
i
(
rit
);
if
(
save
)
{
float
f
=
IOBase
::
processingFasAO
(
&
(
*
it
),
shm
,
force_out
);
MTR
::
F1
f1
(
f
);
for
(
int
k
=
0
;
k
<
MTR
::
F1
::
wsize
();
k
++
,
i
++
)
i
->
second
->
mbval
=
f1
.
raw
.
v
[
k
];
}
else
{
ModbusRTU
::
ModbusData
*
data
=
new
ModbusRTU
::
ModbusData
[
MTR
::
F1
::
wsize
()];
for
(
int
k
=
0
;
k
<
MTR
::
F1
::
wsize
();
k
++
,
i
++
)
data
[
k
]
=
i
->
second
->
mbval
;
MTR
::
F1
t
(
data
,
MTR
::
F1
::
wsize
());
delete
[]
data
;
IOBase
::
processingFasAI
(
&
(
*
it
),
(
float
)
t
,
shm
,
force
);
}
continue
;
}
}
catch
(
IOController_i
::
NameNotFound
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):(NameNotFound) "
<<
ex
.
err
<<
endl
;
}
catch
(
IOController_i
::
IOBadParam
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR):(IOBadParam) "
<<
ex
.
err
<<
endl
;
}
catch
(
IONotifyController_i
::
BadRange
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): (BadRange)..."
<<
endl
;
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): "
<<
ex
<<
endl
;
}
catch
(
CORBA
::
SystemException
&
ex
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): CORBA::SystemException: "
<<
ex
.
NP_minorString
()
<<
endl
;
}
catch
(...)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(updateMTR): catch ..."
<<
endl
;
}
}
}
}
// -----------------------------------------------------------------------------
MBExchange
::
RTUDevice
*
MBExchange
::
addDev
(
RTUDeviceMap
&
mp
,
ModbusRTU
::
ModbusAddr
a
,
UniXML_iterator
&
xmlit
)
{
RTUDeviceMap
::
iterator
it
=
mp
.
find
(
a
);
if
(
it
!=
mp
.
end
()
)
{
DeviceType
dtype
=
getDeviceType
(
xmlit
.
getProp
(
prop_prefix
+
"mbtype"
));
if
(
it
->
second
->
dtype
!=
dtype
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addDev): OTHER mbtype="
<<
dtype
<<
" for "
<<
xmlit
.
getProp
(
"name"
)
<<
". Already used devtype="
<<
it
->
second
->
dtype
<<
" for mbaddr="
<<
ModbusRTU
::
addr2str
(
it
->
second
->
mbaddr
)
<<
endl
;
return
0
;
}
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(addDev): device for addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
" already added. Ignore device params for "
<<
xmlit
.
getProp
(
"name"
)
<<
" ..."
<<
endl
;
return
it
->
second
;
}
MBExchange
::
RTUDevice
*
d
=
new
MBExchange
::
RTUDevice
();
d
->
mbaddr
=
a
;
if
(
!
initRTUDevice
(
d
,
xmlit
)
)
{
delete
d
;
return
0
;
}
mp
.
insert
(
RTUDeviceMap
::
value_type
(
a
,
d
));
return
d
;
}
// ------------------------------------------------------------------------------------------
MBExchange
::
RegInfo
*
MBExchange
::
addReg
(
RegMap
&
mp
,
RegID
id
,
ModbusRTU
::
ModbusData
r
,
UniXML_iterator
&
xmlit
,
MBExchange
::
RTUDevice
*
dev
,
MBExchange
::
RegInfo
*
rcopy
)
{
RegMap
::
iterator
it
=
mp
.
find
(
id
);
if
(
it
!=
mp
.
end
()
)
{
if
(
!
it
->
second
->
dev
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addReg): for "
<<
xmlit
.
getProp
(
"name"
)
<<
" dev=0!!!! "
<<
endl
;
return
0
;
}
if
(
it
->
second
->
dev
->
dtype
!=
dev
->
dtype
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(addReg): OTHER mbtype="
<<
dev
->
dtype
<<
" for "
<<
xmlit
.
getProp
(
"name"
)
<<
". Already used devtype="
<<
it
->
second
->
dev
->
dtype
<<
" for "
<<
it
->
second
->
dev
<<
endl
;
return
0
;
}
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
{
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(addReg): reg="
<<
ModbusRTU
::
dat2str
(
r
)
<<
"(id="
<<
id
<<
")"
<<
" already added for "
<<
(
*
it
->
second
)
<<
" Ignore register params for "
<<
xmlit
.
getProp
(
"name"
)
<<
" ..."
<<
endl
;
}
it
->
second
->
rit
=
it
;
return
it
->
second
;
}
MBExchange
::
RegInfo
*
ri
;
if
(
rcopy
)
{
ri
=
new
MBExchange
::
RegInfo
(
*
rcopy
);
ri
->
slst
.
clear
();
ri
->
mbreg
=
r
;
}
else
{
ri
=
new
MBExchange
::
RegInfo
();
if
(
!
initRegInfo
(
ri
,
xmlit
,
dev
)
)
{
delete
ri
;
return
0
;
}
ri
->
mbreg
=
r
;
}
ri
->
id
=
id
;
mp
.
insert
(
RegMap
::
value_type
(
id
,
ri
));
ri
->
rit
=
mp
.
find
(
id
);
return
ri
;
}
// ------------------------------------------------------------------------------------------
MBExchange
::
RSProperty
*
MBExchange
::
addProp
(
PList
&
plist
,
RSProperty
&
p
)
{
for
(
PList
::
iterator
it
=
plist
.
begin
();
it
!=
plist
.
end
();
++
it
)
{
if
(
it
->
si
.
id
==
p
.
si
.
id
&&
it
->
si
.
node
==
p
.
si
.
node
)
return
&
(
*
it
);
}
plist
.
push_back
(
p
);
PList
::
iterator
it
=
plist
.
end
();
it
--
;
return
&
(
*
it
);
}
// ------------------------------------------------------------------------------------------
bool
MBExchange
::
initRSProperty
(
RSProperty
&
p
,
UniXML_iterator
&
it
)
{
if
(
!
IOBase
::
initItem
(
&
p
,
it
,
shm
,
&
dlog
,
myname
)
)
return
false
;
if
(
it
.
getIntProp
(
prop_prefix
+
"rawdata"
)
)
{
p
.
cal
.
minRaw
=
0
;
p
.
cal
.
maxRaw
=
0
;
p
.
cal
.
minCal
=
0
;
p
.
cal
.
maxCal
=
0
;
p
.
cal
.
precision
=
0
;
p
.
cdiagram
=
0
;
}
string
stype
(
it
.
getProp
(
prop_prefix
+
"iotype"
)
);
if
(
!
stype
.
empty
()
)
{
p
.
stype
=
UniSetTypes
::
getIOType
(
stype
);
if
(
p
.
stype
==
UniversalIO
::
UnknownIOType
)
{
if
(
dlog
)
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(IOBase::readItem): неизвестный iotype=: "
<<
stype
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
string
sbit
(
it
.
getProp
(
prop_prefix
+
"nbit"
));
if
(
!
sbit
.
empty
()
)
{
p
.
nbit
=
UniSetTypes
::
uni_atoi
(
sbit
.
c_str
());
if
(
p
.
nbit
<
0
||
p
.
nbit
>=
ModbusRTU
::
BitsPerData
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): BAD nbit="
<<
p
.
nbit
<<
". (0 >= nbit < "
<<
ModbusRTU
::
BitsPerData
<<
")."
<<
endl
;
return
false
;
}
}
if
(
p
.
nbit
>
0
&&
(
p
.
stype
==
UniversalIO
::
AnalogInput
||
p
.
stype
==
UniversalIO
::
AnalogOutput
)
)
{
dlog
[
Debug
::
WARN
]
<<
"(initRSProperty): (ignore) uncorrect param`s nbit>1 ("
<<
p
.
nbit
<<
")"
<<
" but iotype="
<<
p
.
stype
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
}
string
sbyte
(
it
.
getProp
(
prop_prefix
+
"nbyte"
));
if
(
!
sbyte
.
empty
()
)
{
p
.
nbyte
=
UniSetTypes
::
uni_atoi
(
sbyte
.
c_str
());
if
(
p
.
nbyte
<
0
||
p
.
nbyte
>
VTypes
::
Byte
::
bsize
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): BAD nbyte="
<<
p
.
nbyte
<<
". (0 >= nbyte < "
<<
VTypes
::
Byte
::
bsize
<<
")."
<<
endl
;
return
false
;
}
}
string
vt
(
it
.
getProp
(
prop_prefix
+
"vtype"
));
if
(
vt
.
empty
()
)
{
p
.
rnum
=
VTypes
::
wsize
(
VTypes
::
vtUnknown
);
p
.
vType
=
VTypes
::
vtUnknown
;
}
else
{
VTypes
::
VType
v
(
VTypes
::
str2type
(
vt
));
if
(
v
==
VTypes
::
vtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRSProperty): Unknown tcp_vtype='"
<<
vt
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
p
.
vType
=
v
;
p
.
rnum
=
VTypes
::
wsize
(
v
);
}
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBExchange
::
initRegInfo
(
RegInfo
*
r
,
UniXML_iterator
&
it
,
MBExchange
::
RTUDevice
*
dev
)
{
r
->
dev
=
dev
;
r
->
mbval
=
it
.
getIntProp
(
"default"
);
if
(
dev
->
dtype
==
MBExchange
::
dtRTU
)
{
// dlog[Debug::INFO] << myname << "(initRegInfo): init RTU.."
}
else
if
(
dev
->
dtype
==
MBExchange
::
dtMTR
)
{
// only for MTR
if
(
!
initMTRitem
(
it
,
r
)
)
return
false
;
}
else
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRegInfo): Unknown mbtype='"
<<
dev
->
dtype
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
if
(
mbregFromID
)
{
if
(
it
.
getProp
(
"id"
).
empty
()
)
r
->
mbreg
=
conf
->
getSensorID
(
it
.
getProp
(
"name"
));
else
r
->
mbreg
=
it
.
getIntProp
(
"id"
);
}
else
{
string
sr
=
it
.
getProp
(
prop_prefix
+
"mbreg"
);
if
(
sr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown 'mbreg' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
r
->
mbreg
=
ModbusRTU
::
str2mbData
(
sr
);
}
r
->
mbfunc
=
ModbusRTU
::
fnUnknown
;
string
f
=
it
.
getProp
(
prop_prefix
+
"mbfunc"
);
if
(
!
f
.
empty
()
)
{
r
->
mbfunc
=
(
ModbusRTU
::
SlaveFunctionCode
)
UniSetTypes
::
uni_atoi
(
f
.
c_str
());
if
(
r
->
mbfunc
==
ModbusRTU
::
fnUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRegInfo): Unknown mbfunc ='"
<<
f
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBExchange
::
initRTUDevice
(
RTUDevice
*
d
,
UniXML_iterator
&
it
)
{
d
->
dtype
=
getDeviceType
(
it
.
getProp
(
prop_prefix
+
"mbtype"
));
if
(
d
->
dtype
==
dtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRTUDevice): Unknown tcp_mbtype="
<<
it
.
getProp
(
prop_prefix
+
"mbtype"
)
<<
". Use: rtu "
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
string
addr
=
it
.
getProp
(
prop_prefix
+
"mbaddr"
);
if
(
addr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initRTUDevice): Unknown mbaddr for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
d
->
mbaddr
=
ModbusRTU
::
str2mbAddr
(
addr
);
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBExchange
::
initItem
(
UniXML_iterator
&
it
)
{
RSProperty
p
;
if
(
!
initRSProperty
(
p
,
it
)
)
return
false
;
string
addr
=
it
.
getProp
(
prop_prefix
+
"mbaddr"
);
if
(
addr
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown mbaddr='"
<<
addr
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
ModbusRTU
::
ModbusAddr
mbaddr
=
ModbusRTU
::
str2mbAddr
(
addr
);
RTUDevice
*
dev
=
addDev
(
rmap
,
mbaddr
,
it
);
if
(
!
dev
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): "
<<
it
.
getProp
(
"name"
)
<<
" CAN`T ADD for polling!"
<<
endl
;
return
false
;
}
ModbusRTU
::
ModbusData
mbreg
;
if
(
mbregFromID
)
mbreg
=
p
.
si
.
id
;
// conf->getSensorID(it.getProp("name"));
else
{
string
reg
=
it
.
getProp
(
prop_prefix
+
"mbreg"
);
if
(
reg
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): unknown mbreg for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
mbreg
=
ModbusRTU
::
str2mbData
(
reg
);
}
int
fn
=
it
.
getIntProp
(
prop_prefix
+
"mbfunc"
);
// формула для вычисления ID
// требования:
// - ID > диапазона возможных регитров
// - разные функции должны давать разный ID
RegID
rID
=
genRegID
(
mbreg
,
fn
);
RegInfo
*
ri
=
addReg
(
dev
->
regmap
,
rID
,
mbreg
,
it
,
dev
);
if
(
dev
->
dtype
==
dtMTR
)
{
p
.
rnum
=
MTR
::
wsize
(
ri
->
mtrType
);
if
(
p
.
rnum
<=
0
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): unknown word size for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
if
(
!
ri
)
return
false
;
ri
->
dev
=
dev
;
// ПРОВЕРКА!
// если функция на запись, то надо проверить
// что один и тотже регистр не перезапишут несколько датчиков
// это возможно только, если они пишут биты!!
// ИТОГ:
// Если для функций записи список датчиков для регистра > 1
// значит в списке могут быть только битовые датчики
// и если идёт попытка внести в список не битовый датчик то ОШИБКА!
// И наоборот: если идёт попытка внести битовый датчик, а в списке
// уже сидит датчик занимающий целый регистр, то тоже ОШИБКА!
if
(
ModbusRTU
::
isWriteFunction
(
ri
->
mbfunc
)
)
{
if
(
p
.
nbit
<
0
&&
ri
->
slst
.
size
()
>
1
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): FAILED! Sharing SAVE (not bit saving) to "
<<
" tcp_mbreg="
<<
ModbusRTU
::
dat2str
(
ri
->
mbreg
)
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
abort
();
// ABORT PROGRAM!!!!
return
false
;
}
if
(
p
.
nbit
>=
0
&&
ri
->
slst
.
size
()
==
1
)
{
PList
::
iterator
it2
=
ri
->
slst
.
begin
();
if
(
it2
->
nbit
<
0
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): FAILED! Sharing SAVE (mbreg="
<<
ModbusRTU
::
dat2str
(
ri
->
mbreg
)
<<
" already used)!"
<<
" IGNORE --> "
<<
it
.
getProp
(
"name"
)
<<
endl
;
abort
();
// ABORT PROGRAM!!!!
return
false
;
}
}
// Раз это регистр для записи, то как минимум надо сперва
// инициализировать значением из SM
ri
->
sm_initOK
=
it
.
getIntProp
(
prop_prefix
+
"sm_initOK"
);
ri
->
mb_initOK
=
true
;
// может быть переопределён если будет указан tcp_preinit="1" (см. ниже)
}
else
{
// Если это регистр для чтения, то сразу можно работать
// инициализировать не надо
ri
->
mb_initOK
=
true
;
ri
->
sm_initOK
=
true
;
}
RSProperty
*
p1
=
addProp
(
ri
->
slst
,
p
);
if
(
!
p1
)
return
false
;
p1
->
reg
=
ri
;
if
(
p1
->
rnum
>
1
)
{
ri
->
q_count
=
p1
->
rnum
;
ri
->
q_num
=
1
;
for
(
int
i
=
1
;
i
<
p1
->
rnum
;
i
++
)
{
RegID
id1
=
genRegID
(
mbreg
+
i
,
ri
->
mbfunc
);
RegInfo
*
r
=
addReg
(
dev
->
regmap
,
id1
,
mbreg
+
i
,
it
,
dev
,
ri
);
r
->
q_num
=
i
+
1
;
r
->
q_count
=
1
;
r
->
mbfunc
=
ri
->
mbfunc
;
r
->
mb_initOK
=
true
;
r
->
sm_initOK
=
true
;
if
(
ModbusRTU
::
isWriteFunction
(
ri
->
mbfunc
)
)
{
// Если занимает несколько регистров, а указана функция записи "одного",
// то это ошибка..
if
(
ri
->
mbfunc
!=
ModbusRTU
::
fnWriteOutputRegisters
&&
ri
->
mbfunc
!=
ModbusRTU
::
fnForceMultipleCoils
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Bad write function ='"
<<
ModbusRTU
::
fnWriteOutputSingleRegister
<<
"' for vtype='"
<<
p1
->
vType
<<
"'"
<<
" tcp_mbreg="
<<
ModbusRTU
::
dat2str
(
ri
->
mbreg
)
<<
" for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
abort
();
// ABORT PROGRAM!!!!
return
false
;
}
}
}
}
// Фомируем список инициализации
bool
need_init
=
it
.
getIntProp
(
prop_prefix
+
"preinit"
);
if
(
need_init
&&
ModbusRTU
::
isWriteFunction
(
ri
->
mbfunc
)
)
{
InitRegInfo
ii
;
ii
.
p
=
p
;
ii
.
dev
=
dev
;
ii
.
ri
=
ri
;
string
s_reg
(
it
.
getProp
(
prop_prefix
+
"init_mbreg"
));
if
(
!
s_reg
.
empty
()
)
ii
.
mbreg
=
ModbusRTU
::
str2mbData
(
s_reg
);
else
ii
.
mbreg
=
ri
->
mbreg
;
string
s_mbfunc
(
it
.
getProp
(
prop_prefix
+
"init_mbfunc"
));
if
(
!
s_mbfunc
.
empty
()
)
{
ii
.
mbfunc
=
(
ModbusRTU
::
SlaveFunctionCode
)
UniSetTypes
::
uni_atoi
(
s_mbfunc
);
if
(
ii
.
mbfunc
==
ModbusRTU
::
fnUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initItem): Unknown tcp_init_mbfunc ='"
<<
s_mbfunc
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
}
else
{
switch
(
ri
->
mbfunc
)
{
case
ModbusRTU
:
:
fnWriteOutputSingleRegister
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
case
ModbusRTU
:
:
fnForceSingleCoil
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadCoilStatus
;
break
;
case
ModbusRTU
:
:
fnWriteOutputRegisters
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
case
ModbusRTU
:
:
fnForceMultipleCoils
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadCoilStatus
;
break
;
default
:
ii
.
mbfunc
=
ModbusRTU
::
fnReadOutputRegisters
;
break
;
}
}
initRegList
.
push_back
(
ii
);
ri
->
mb_initOK
=
false
;
ri
->
sm_initOK
=
false
;
}
return
true
;
}
// ------------------------------------------------------------------------------------------
bool
MBExchange
::
initMTRitem
(
UniXML_iterator
&
it
,
RegInfo
*
p
)
{
p
->
mtrType
=
MTR
::
str2type
(
it
.
getProp
(
"mtrtype"
));
if
(
p
->
mtrType
==
MTR
::
mtUnknown
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(readMTRItem): Unknown mtrtype '"
<<
it
.
getProp
(
"mtrtype"
)
<<
"' for "
<<
it
.
getProp
(
"name"
)
<<
endl
;
return
false
;
}
return
true
;
}
// ------------------------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBExchange
::
DeviceType
&
dt
)
{
switch
(
dt
)
{
case
MBExchange
:
:
dtRTU
:
os
<<
"RTU"
;
break
;
case
MBExchange
:
:
dtMTR
:
os
<<
"MTR"
;
break
;
case
MBExchange
:
:
dtRTU188
:
os
<<
"RTU188"
;
break
;
default
:
os
<<
"Unknown device type ("
<<
(
int
)
dt
<<
")"
;
break
;
}
return
os
;
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBExchange
::
RSProperty
&
p
)
{
os
<<
" ("
<<
ModbusRTU
::
dat2str
(
p
.
reg
->
mbreg
)
<<
")"
<<
" sid="
<<
p
.
si
.
id
<<
" stype="
<<
p
.
stype
<<
" nbit="
<<
p
.
nbit
<<
" nbyte="
<<
p
.
nbyte
<<
" rnum="
<<
p
.
rnum
<<
" safety="
<<
p
.
safety
<<
" invert="
<<
p
.
invert
;
if
(
p
.
stype
==
UniversalIO
::
AnalogInput
||
p
.
stype
==
UniversalIO
::
AnalogOutput
)
{
os
<<
p
.
cal
<<
" cdiagram="
<<
(
p
.
cdiagram
?
"yes"
:
"no"
);
}
return
os
;
}
// -----------------------------------------------------------------------------
void
MBExchange
::
initDeviceList
()
{
xmlNode
*
respNode
=
conf
->
findNode
(
cnode
,
"DeviceList"
);
if
(
respNode
)
{
UniXML_iterator
it1
(
respNode
);
if
(
it1
.
goChildren
()
)
{
for
(;
it1
.
getCurrent
();
it1
.
goNext
()
)
{
ModbusRTU
::
ModbusAddr
a
=
ModbusRTU
::
str2mbAddr
(
it1
.
getProp
(
"addr"
));
initDeviceInfo
(
rmap
,
a
,
it1
);
}
}
else
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(init): <DeviceList> empty section..."
<<
endl
;
}
else
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(init): <DeviceList> not found..."
<<
endl
;
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
initDeviceInfo
(
RTUDeviceMap
&
m
,
ModbusRTU
::
ModbusAddr
a
,
UniXML_iterator
&
it
)
{
RTUDeviceMap
::
iterator
d
=
m
.
find
(
a
);
if
(
d
==
m
.
end
()
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(initDeviceInfo): not found device for addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
endl
;
return
false
;
}
d
->
second
->
ask_every_reg
=
it
.
getIntProp
(
"ask_every_reg"
);
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(initDeviceInfo): add addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
" ask_every_reg="
<<
d
->
second
->
ask_every_reg
<<
endl
;
string
s
(
it
.
getProp
(
"respondSensor"
));
if
(
!
s
.
empty
()
)
{
d
->
second
->
resp_id
=
conf
->
getSensorID
(
s
);
if
(
d
->
second
->
resp_id
==
DefaultObjectId
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(initDeviceInfo): not found ID for noRespondSensor="
<<
s
<<
endl
;
return
false
;
}
}
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(initDeviceInfo): add addr="
<<
ModbusRTU
::
addr2str
(
a
)
<<
endl
;
int
tout
=
it
.
getPIntProp
(
"timeout"
,
5000
);
d
->
second
->
resp_ptTimeout
.
setTiming
(
tout
);
d
->
second
->
resp_invert
=
it
.
getIntProp
(
"invert"
);
// d->second->no_clean_input = it.getIntProp("no_clean_input");
// dlog[Debug::INFO] << myname << "(initDeviceInfo): add " << (*d->second) << endl;
return
true
;
}
// -----------------------------------------------------------------------------
bool
MBExchange
::
activateObject
()
{
// блокирование обработки Starsp
// пока не пройдёт инициализация датчиков
// см. sysCommand()
{
setProcActive
(
false
);
UniSetTypes
::
uniset_mutex_lock
l
(
mutex_start
,
5000
);
UniSetObject_LT
::
activateObject
();
if
(
!
shm
->
isLocalwork
()
)
rtuQueryOptimization
(
rmap
);
initIterators
();
setProcActive
(
true
);
}
return
true
;
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
processingMessage
(
UniSetTypes
::
VoidMessage
*
msg
)
{
try
{
switch
(
msg
->
type
)
{
case
UniSetTypes
:
:
Message
::
SysCommand
:
{
UniSetTypes
::
SystemMessage
sm
(
msg
);
sysCommand
(
&
sm
);
}
break
;
case
Message
:
:
Timer
:
{
TimerMessage
tm
(
msg
);
timerInfo
(
&
tm
);
}
break
;
case
Message
:
:
SensorInfo
:
{
SensorMessage
sm
(
msg
);
sensorInfo
(
&
sm
);
}
break
;
default
:
break
;
}
}
catch
(
SystemError
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(SystemError): "
<<
ex
<<
std
::
endl
;
// throw SystemError(ex);
}
catch
(
Exception
&
ex
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(processingMessage): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(processingMessage): catch ...
\n
"
;
}
}
// -----------------------------------------------------------------------------
void
MBExchange
::
sysCommand
(
UniSetTypes
::
SystemMessage
*
sm
)
{
switch
(
sm
->
command
)
{
case
SystemMessage
:
:
StartUp
:
{
if
(
rmap
.
empty
()
)
{
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(sysCommand): ************* ITEM MAP EMPTY! terminated... *************"
<<
endl
;
raise
(
SIGTERM
);
return
;
}
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(sysCommand): device map size= "
<<
rmap
.
size
()
<<
endl
;
if
(
!
shm
->
isLocalwork
()
)
initDeviceList
();
waitSMReady
();
// подождать пока пройдёт инициализация датчиков
// см. activateObject()
msleep
(
initPause
);
PassiveTimer
ptAct
(
activateTimeout
);
while
(
!
activated
&&
!
ptAct
.
checkTime
()
)
{
cout
<<
myname
<<
"(sysCommand): wait activate..."
<<
endl
;
msleep
(
300
);
if
(
activated
)
break
;
}
if
(
!
activated
)
dlog
[
Debug
::
CRIT
]
<<
myname
<<
"(sysCommand): ************* don`t activate?! ************"
<<
endl
;
{
UniSetTypes
::
uniset_mutex_lock
l
(
mutex_start
,
10000
);
askSensors
(
UniversalIO
::
UIONotify
);
initOutput
();
}
askTimer
(
tmExchange
,
polltime
);
break
;
}
case
SystemMessage
:
:
FoldUp
:
case
SystemMessage
:
:
Finish
:
askSensors
(
UniversalIO
::
UIODontNotify
);
break
;
case
SystemMessage
:
:
WatchDog
:
{
// ОПТИМИЗАЦИЯ (защита от двойного перезаказа при старте)
// Если идёт локальная работа
// (т.е. MBExchange запущен в одном процессе с SharedMemory2)
// то обрабатывать WatchDog не надо, т.к. мы и так ждём готовности SM
// при заказе датчиков, а если SM вылетит, то вместе с этим процессом(MBExchange)
if
(
shm
->
isLocalwork
()
)
break
;
askSensors
(
UniversalIO
::
UIONotify
);
initOutput
();
if
(
!
force
)
{
uniset_mutex_lock
l
(
pollMutex
,
2000
);
force
=
true
;
poll
();
force
=
false
;
}
}
break
;
case
SystemMessage
:
:
LogRotate
:
{
// переоткрываем логи
unideb
<<
myname
<<
"(sysCommand): logRotate"
<<
std
::
endl
;
string
fname
=
unideb
.
getLogFile
();
if
(
!
fname
.
empty
()
)
{
unideb
.
logFile
(
fname
);
unideb
<<
myname
<<
"(sysCommand): ***************** UNIDEB LOG ROTATE *****************"
<<
std
::
endl
;
}
dlog
<<
myname
<<
"(sysCommand): logRotate"
<<
std
::
endl
;
fname
=
dlog
.
getLogFile
();
if
(
!
fname
.
empty
()
)
{
dlog
.
logFile
(
fname
);
dlog
<<
myname
<<
"(sysCommand): ***************** dlog LOG ROTATE *****************"
<<
std
::
endl
;
}
}
break
;
default
:
break
;
}
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
initOutput
()
{
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
askSensors
(
UniversalIO
::
UIOCommand
cmd
)
{
if
(
!
shm
->
waitSMworking
(
test_id
,
activateTimeout
,
50
)
)
{
ostringstream
err
;
err
<<
myname
<<
"(askSensors): Не дождались готовности(work) SharedMemory к работе в течение "
<<
activateTimeout
<<
" мсек"
;
dlog
[
Debug
::
CRIT
]
<<
err
.
str
()
<<
endl
;
kill
(
SIGTERM
,
getpid
());
// прерываем (перезапускаем) процесс...
throw
SystemError
(
err
.
str
());
}
if
(
force_out
)
return
;
try
{
if
(
sidExchangeMode
!=
DefaultObjectId
)
shm
->
askSensor
(
sidExchangeMode
,
cmd
);
}
catch
(
UniSetTypes
::
Exception
&
ex
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): 'sidExchangeMode' catch..."
<<
std
::
endl
;
}
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
isWriteFunction
(
it
->
second
->
mbfunc
)
)
continue
;
for
(
PList
::
iterator
i
=
it
->
second
->
slst
.
begin
();
i
!=
it
->
second
->
slst
.
end
();
++
i
)
{
try
{
shm
->
askSensor
(
i
->
si
.
id
,
cmd
);
}
catch
(
UniSetTypes
::
Exception
&
ex
)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): "
<<
ex
<<
std
::
endl
;
}
catch
(...)
{
dlog
[
Debug
::
WARN
]
<<
myname
<<
"(askSensors): catch..."
<<
std
::
endl
;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
sensorInfo
(
UniSetTypes
::
SensorMessage
*
sm
)
{
if
(
force_out
)
return
;
if
(
sm
->
id
==
sidExchangeMode
)
{
exchangeMode
=
sm
->
value
;
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(sensorInfo): exchange MODE="
<<
sm
->
value
<<
std
::
endl
;
return
;
}
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
isWriteFunction
(
it
->
second
->
mbfunc
)
)
continue
;
for
(
PList
::
iterator
i
=
it
->
second
->
slst
.
begin
();
i
!=
it
->
second
->
slst
.
end
();
++
i
)
{
if
(
sm
->
id
==
i
->
si
.
id
&&
sm
->
node
==
i
->
si
.
node
)
{
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
{
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(sensorInfo): si.id="
<<
sm
->
id
<<
" reg="
<<
ModbusRTU
::
dat2str
(
i
->
reg
->
mbreg
)
<<
" val="
<<
sm
->
value
<<
" mb_initOK="
<<
i
->
reg
->
mb_initOK
<<
endl
;
}
if
(
!
i
->
reg
->
mb_initOK
)
continue
;
i
->
value
=
sm
->
value
;
updateRSProperty
(
&
(
*
i
),
true
);
return
;
}
}
}
}
}
// ------------------------------------------------------------------------------------------
void
MBExchange
::
timerInfo
(
TimerMessage
*
tm
)
{
if
(
tm
->
id
==
tmExchange
)
{
if
(
no_extimer
)
askTimer
(
tm
->
id
,
0
);
else
step
();
}
}
// -----------------------------------------------------------------------------
void
MBExchange
::
poll
()
{
if
(
!
mb
)
{
{
uniset_mutex_lock
l
(
pollMutex
,
300
);
pollActivated
=
false
;
mb
=
initMB
(
false
);
if
(
!
mb
)
{
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it
=
rmap
.
begin
();
it
!=
rmap
.
end
();
++
it
)
it
->
second
->
resp_real
=
false
;
}
}
if
(
!
checkProcActive
()
)
return
;
updateSM
();
allInitOK
=
false
;
return
;
}
{
uniset_mutex_lock
l
(
pollMutex
);
pollActivated
=
true
;
ptTimeout
.
reset
();
}
if
(
!
allInitOK
)
firstInitRegisters
();
if
(
!
checkProcActive
()
)
return
;
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
if
(
dlog
.
debugging
(
Debug
::
INFO
)
)
dlog
[
Debug
::
INFO
]
<<
myname
<<
"(poll): ask addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" regs="
<<
d
->
regmap
.
size
()
<<
endl
;
d
->
resp_real
=
false
;
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
checkProcActive
()
)
return
;
try
{
if
(
d
->
dtype
==
MBExchange
::
dtRTU
||
d
->
dtype
==
MBExchange
::
dtMTR
)
{
if
(
pollRTU
(
d
,
it
)
)
d
->
resp_real
=
true
;
}
}
catch
(
ModbusRTU
::
mbException
&
ex
)
{
// if( d->resp_real )
// {
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
{
dlog
[
Debug
::
LEVEL3
]
<<
myname
<<
"(poll): FAILED ask addr="
<<
ModbusRTU
::
addr2str
(
d
->
mbaddr
)
<<
" reg="
<<
ModbusRTU
::
dat2str
(
it
->
second
->
mbreg
)
<<
" for sensors: "
;
print_plist
(
dlog
(
Debug
::
LEVEL3
),
it
->
second
->
slst
);
dlog
(
Debug
::
LEVEL3
)
<<
" err: "
<<
ex
<<
endl
;
}
// }
// d->resp_real = false;
if
(
ex
.
err
==
ModbusRTU
::
erTimeOut
&&
!
d
->
ask_every_reg
)
break
;
// если контроллер хоть что-то ответил, то вроде как связь есть..
if
(
ex
.
err
!=
ModbusRTU
::
erTimeOut
)
d
->
resp_real
=
true
;
}
if
(
it
==
d
->
regmap
.
end
()
)
break
;
if
(
!
checkProcActive
()
)
return
;
}
if
(
stat_time
>
0
)
poll_count
++
;
}
if
(
stat_time
>
0
&&
ptStatistic
.
checkTime
()
)
{
cout
<<
endl
<<
"(poll statistic): number of calls is "
<<
poll_count
<<
" (poll time: "
<<
stat_time
<<
" sec)"
<<
endl
<<
endl
;
ptStatistic
.
reset
();
poll_count
=
0
;
}
{
uniset_mutex_lock
l
(
pollMutex
);
pollActivated
=
false
;
}
if
(
!
checkProcActive
()
)
return
;
// update SharedMemory...
updateSM
();
// check thresholds
for
(
MBExchange
::
RTUDeviceMap
::
iterator
it1
=
rmap
.
begin
();
it1
!=
rmap
.
end
();
++
it1
)
{
RTUDevice
*
d
(
it1
->
second
);
for
(
MBExchange
::
RegMap
::
iterator
it
=
d
->
regmap
.
begin
();
it
!=
d
->
regmap
.
end
();
++
it
)
{
if
(
!
checkProcActive
()
)
return
;
RegInfo
*
r
(
it
->
second
);
for
(
PList
::
iterator
i
=
r
->
slst
.
begin
();
i
!=
r
->
slst
.
end
();
++
i
)
IOBase
::
processingThreshold
(
&
(
*
i
),
shm
,
force
);
}
}
// printMap(rmap);
}
// -----------------------------------------------------------------------------
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment