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
943e9dc2
Commit
943e9dc2
authored
Jan 08, 2015
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(ModbusMaster): добавил ещё ряд тестов, исправил обнаруженную ошибку
с "не выставлением" датчика связи в режиме emSkipExchange.. (не выставлялось "нет связи").
parent
d2fc81fa
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
888 additions
and
29 deletions
+888
-29
MBExchange.cc
extensions/ModbusMaster/MBExchange.cc
+46
-14
MBTCPTestServer.cc
extensions/ModbusMaster/tests/MBTCPTestServer.cc
+546
-0
MBTCPTestServer.h
extensions/ModbusMaster/tests/MBTCPTestServer.h
+135
-0
mbmaster-test-configure.xml
extensions/ModbusMaster/tests/mbmaster-test-configure.xml
+2
-1
test_mbtcpmaster.cc
extensions/ModbusMaster/tests/test_mbtcpmaster.cc
+156
-13
tests_with_sm.cc
extensions/ModbusMaster/tests/tests_with_sm.cc
+1
-0
tests_with_sm.sh
extensions/ModbusMaster/tests/tests_with_sm.sh
+2
-1
No files found.
extensions/ModbusMaster/MBExchange.cc
View file @
943e9dc2
...
...
@@ -340,7 +340,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc, long mdev )
if
(
exchangeMode
==
emSkipExchange
||
mdev
==
emSkipExchange
)
{
if
(
wrFunc
)
return
true
;
// данные для посылки, должны обновляться всегда (чтобы быть актуальными)
return
true
;
// данные для посылки, должны обновляться всегда (чтобы быть актуальными
, когда режим переключиться обратно..
)
dlog3
<<
"(checkUpdateSM):"
<<
" skip... mode='emSkipExchange' "
<<
endl
;
...
...
@@ -361,7 +361,7 @@ bool MBExchange::checkUpdateSM( bool wrFunc, long mdev )
return
false
;
}
if
(
wrFunc
&&
(
exchangeMode
==
emSkipSaveToSM
||
mdev
==
emSkipSaveToSM
)
)
if
(
!
wrFunc
&&
(
exchangeMode
==
emSkipSaveToSM
||
mdev
==
emSkipSaveToSM
)
)
{
dlog3
<<
"(checkUpdateSM):"
<<
" skip... mode='emSkipSaveToSM' "
<<
endl
;
...
...
@@ -385,6 +385,12 @@ bool MBExchange::checkPoll( bool wrFunc )
return
false
;
}
if
(
exchangeMode
==
emSkipExchange
)
{
dlog3
<<
myname
<<
"(checkPoll): skip.. poll mode='emSkipExchange'"
<<
endl
;
return
false
;
}
return
true
;
}
// -----------------------------------------------------------------------------
...
...
@@ -802,12 +808,12 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
{
RegInfo
*
p
(
it
->
second
);
if
(
dev
->
mode
==
emSkipExchange
)
if
(
dev
->
mode
==
emSkipExchange
)
{
dlog3
<<
myname
<<
"(pollRTU): SKIP EXCHANGE (mode=emSkipExchange) "
<<
" mbaddr="
<<
ModbusRTU
::
addr2str
(
dev
->
mbaddr
)
<<
endl
;
return
tru
e
;
return
fals
e
;
}
if
(
dlog
.
debugging
(
Debug
::
LEVEL3
)
)
...
...
@@ -822,13 +828,13 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
<<
" mbval="
<<
p
->
mbval
<<
endl
;
if
(
p
->
q_count
>
ModbusRTU
::
MAXDATALEN
)
{
dlog3
<<
myname
<<
"(pollRTU): count("
<<
p
->
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
if
(
p
->
q_count
>
ModbusRTU
::
MAXDATALEN
)
{
dlog3
<<
myname
<<
"(pollRTU): count("
<<
p
->
q_count
<<
") > MAXDATALEN("
<<
ModbusRTU
::
MAXDATALEN
<<
" ..ignore..."
<<
endl
;
}
}
if
(
!
checkPoll
(
ModbusRTU
::
isWriteFunction
(
p
->
mbfunc
))
)
...
...
@@ -854,7 +860,7 @@ bool MBExchange::pollRTU( RTUDevice* dev, RegMap::iterator& it )
case
ModbusRTU
:
:
fnReadOutputRegisters
:
{
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
ModbusRTU
::
ReadOutputRetMessage
ret
=
mb
->
read03
(
dev
->
mbaddr
,
p
->
mbreg
,
p
->
q_count
);
for
(
unsigned
int
i
=
0
;
i
<
p
->
q_count
;
i
++
,
it
++
)
it
->
second
->
mbval
=
ret
.
data
[
i
];
it
--
;
...
...
@@ -2769,6 +2775,12 @@ void MBExchange::poll()
if
(
!
checkProcActive
()
)
return
;
if
(
exchangeMode
==
emSkipExchange
)
{
d
->
resp_real
=
false
;
continue
;
}
try
{
if
(
d
->
dtype
==
MBExchange
::
dtRTU
||
d
->
dtype
==
MBExchange
::
dtMTR
)
...
...
@@ -2835,10 +2847,10 @@ void MBExchange::poll()
IOBase
::
processingThreshold
(
&
(
*
t
),
shm
,
force
);
}
if
(
trReopen
.
hi
(
allNotRespond
)
)
if
(
trReopen
.
hi
(
allNotRespond
&&
exchangeMode
!=
emSkipExchange
)
)
ptReopen
.
reset
();
if
(
allNotRespond
&&
ptReopen
.
checkTime
()
)
if
(
allNotRespond
&&
exchangeMode
!=
emSkipExchange
&&
ptReopen
.
checkTime
()
)
{
dwarn
<<
myname
<<
": REOPEN timeout..("
<<
ptReopen
.
getInterval
()
<<
")"
<<
endl
;
...
...
@@ -2947,3 +2959,23 @@ void MBExchange::execute()
}
}
// -----------------------------------------------------------------------------
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
MBExchange
::
ExchangeMode
&
em
)
{
if
(
em
==
MBExchange
::
emNone
)
return
os
<<
"emNone"
;
if
(
em
==
MBExchange
::
emWriteOnly
)
return
os
<<
"emWriteOnly"
;
if
(
em
==
MBExchange
::
emReadOnly
)
return
os
<<
"emReadOnly"
;
if
(
em
==
MBExchange
::
emSkipSaveToSM
)
return
os
<<
"emSkipSaveToSM"
;
if
(
em
==
MBExchange
::
emSkipExchange
)
return
os
<<
"emSkipExchange"
;
return
os
;
}
// -----------------------------------------------------------------------------
extensions/ModbusMaster/tests/MBTCPTestServer.cc
0 → 100644
View file @
943e9dc2
// -------------------------------------------------------------------------
#include <sstream>
#include <UniSetTypes.h>
#include "MBTCPTestServer.h"
#include "uniset-config.h"
// -------------------------------------------------------------------------
#ifndef PACKAGE_URL
#define PACKAGE_URL "http://git.etersoft.ru/projects/?p=asu/uniset.git;a=summary"
#endif
// -------------------------------------------------------------------------
using
namespace
std
;
using
namespace
UniSetTypes
;
using
namespace
ModbusRTU
;
// -------------------------------------------------------------------------
MBTCPTestServer
::
MBTCPTestServer
(
ModbusAddr
myaddr
,
const
string
&
inetaddr
,
int
port
,
bool
verb
)
:
sslot
(
NULL
),
addr
(
myaddr
),
verbose
(
verb
),
replyVal
(
-
1
),
forceSingleCoilCmd
(
false
),
lastWriteOutputSingleRegister
(
0
),
lastForceCoilsQ
(
0
,
0
),
lastWriteOutputQ
(
0
,
0
),
thr
(
0
),
isrunning
(
false
)
{
ost
::
InetAddress
ia
(
inetaddr
.
c_str
());
if
(
verbose
)
cout
<<
"(init): "
<<
" addr: "
<<
ia
<<
":"
<<
port
<<
endl
;
sslot
=
new
ModbusTCPServerSlot
(
ia
,
port
);
// sslot->initLog(conf,name,logfile);
sslot
->
connectReadCoil
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
readCoilStatus
)
);
sslot
->
connectReadInputStatus
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
readInputStatus
)
);
sslot
->
connectReadOutput
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
readOutputRegisters
)
);
sslot
->
connectReadInput
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
readInputRegisters
)
);
sslot
->
connectForceSingleCoil
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
forceSingleCoil
)
);
sslot
->
connectForceCoils
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
forceMultipleCoils
)
);
sslot
->
connectWriteOutput
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
writeOutputRegisters
)
);
sslot
->
connectWriteSingleOutput
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
writeOutputSingleRegister
)
);
sslot
->
connectDiagnostics
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
diagnostics
)
);
sslot
->
connectMEIRDI
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
read4314
)
);
sslot
->
connectJournalCommand
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
journalCommand
)
);
sslot
->
connectSetDateTime
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
setDateTime
)
);
sslot
->
connectRemoteService
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
remoteService
)
);
sslot
->
connectFileTransfer
(
sigc
::
mem_fun
(
this
,
&
MBTCPTestServer
::
fileTransfer
)
);
sslot
->
setRecvTimeout
(
6000
);
// sslot->setAfterSendPause(afterSend);
sslot
->
setReplyTimeout
(
10000
);
// build file list...
}
// -------------------------------------------------------------------------
MBTCPTestServer
::~
MBTCPTestServer
()
{
if
(
thr
)
{
thr
->
stop
();
if
(
thr
->
isRunning
()
)
thr
->
join
();
}
delete
sslot
;
}
// -------------------------------------------------------------------------
void
MBTCPTestServer
::
setLog
(
DebugStream
&
dlog
)
{
if
(
sslot
)
sslot
->
setLog
(
dlog
);
}
// -------------------------------------------------------------------------
void
MBTCPTestServer
::
runThread
()
{
thr
=
new
ThreadCreator
<
MBTCPTestServer
>
(
this
,
&
MBTCPTestServer
::
execute
);
thr
->
start
();
}
// -------------------------------------------------------------------------
void
MBTCPTestServer
::
execute
()
{
isrunning
=
true
;
cerr
<<
"******************** MBTCPTestServer running... "
<<
endl
;
// Работа...
while
(
1
)
{
ModbusRTU
::
mbErrCode
res
=
sslot
->
receive
(
addr
,
UniSetTimer
::
WaitUpTime
);
#if 0
// собираем статистику обмена
if( prev!=ModbusRTU::erTimeOut )
{
// с проверкой на переполнение
askCount = askCount>=numeric_limits<long>::max() ? 0 : askCount+1;
if( res!=ModbusRTU::erNoError )
++errmap[res];
prev = res;
}
#endif
if
(
verbose
&&
res
!=
ModbusRTU
::
erNoError
&&
res
!=
ModbusRTU
::
erTimeOut
)
cerr
<<
"(execute::receive): "
<<
ModbusRTU
::
mbErr2Str
(
res
)
<<
endl
;
}
isrunning
=
false
;
}
// -------------------------------------------------------------------------
void
MBTCPTestServer
::
sigterm
(
int
signo
)
{
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
readCoilStatus
(
ReadCoilMessage
&
query
,
ReadCoilRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(readCoilStatus): "
<<
query
<<
endl
;
ModbusRTU
::
DataBits
d
;
d
.
b
[
0
]
=
1
;
d
.
b
[
2
]
=
1
;
d
.
b
[
4
]
=
1
;
d
.
b
[
6
]
=
1
;
if
(
query
.
count
<=
1
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
d
);
return
ModbusRTU
::
erNoError
;
}
// Фомирование ответа:
int
num
=
0
;
// добавленное количество данных
ModbusData
reg
=
query
.
start
;
for
(
;
num
<
query
.
count
;
num
++
,
reg
++
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
d
);
}
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if
(
reply
.
bcnt
<
query
.
count
)
{
cerr
<<
"(readCoilStatus): Получили меньше чем ожидали. "
<<
" Запросили "
<<
query
.
count
<<
" получили "
<<
reply
.
bcnt
<<
endl
;
}
return
ModbusRTU
::
erNoError
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
readInputStatus
(
ReadInputStatusMessage
&
query
,
ReadInputStatusRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(readInputStatus): "
<<
query
<<
endl
;
ModbusRTU
::
DataBits
d
;
d
.
b
[
0
]
=
1
;
d
.
b
[
3
]
=
1
;
d
.
b
[
7
]
=
1
;
if
(
replyVal
==
-
1
)
{
int
bnum
=
0
;
int
i
=
0
;
while
(
i
<
query
.
count
)
{
reply
.
addData
(
0
);
for
(
auto
nbit
=
0
;
nbit
<
BitsPerByte
&&
i
<
query
.
count
;
nbit
++
,
i
++
)
reply
.
setBit
(
bnum
,
nbit
,
d
.
b
[
nbit
]);
bnum
++
;
}
}
else
{
int
bcnt
=
query
.
count
/
ModbusRTU
::
BitsPerByte
;
if
(
(
query
.
count
%
ModbusRTU
::
BitsPerByte
)
>
0
)
bcnt
++
;
for
(
auto
i
=
0
;
i
<
bcnt
;
i
++
)
reply
.
addData
(
replyVal
);
}
return
ModbusRTU
::
erNoError
;
}
// -------------------------------------------------------------------------
mbErrCode
MBTCPTestServer
::
readInputRegisters
(
ReadInputMessage
&
query
,
ReadInputRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(readInputRegisters): "
<<
query
<<
endl
;
if
(
query
.
count
<=
1
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
query
.
start
);
return
ModbusRTU
::
erNoError
;
}
// Фомирование ответа:
int
num
=
0
;
// добавленное количество данных
ModbusData
reg
=
query
.
start
;
for
(
;
num
<
query
.
count
;
num
++
,
reg
++
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
reg
);
}
// cerr << "************ reply: cnt=" << reply.count << endl;
// cerr << "reply: " << reply << endl;
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if
(
reply
.
count
<
query
.
count
)
{
cerr
<<
"(readInputRegisters): Получили меньше чем ожидали. "
<<
" Запросили "
<<
query
.
count
<<
" получили "
<<
reply
.
count
<<
endl
;
}
return
ModbusRTU
::
erNoError
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
readOutputRegisters
(
ModbusRTU
::
ReadOutputMessage
&
query
,
ModbusRTU
::
ReadOutputRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(readOutputRegisters): "
<<
query
<<
endl
;
if
(
query
.
count
<=
1
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
query
.
start
);
return
ModbusRTU
::
erNoError
;
}
// Фомирование ответа:
int
num
=
0
;
// добавленное количество данных
ModbusData
reg
=
query
.
start
;
for
(
;
num
<
query
.
count
;
num
++
,
reg
++
)
{
if
(
replyVal
!=-
1
)
reply
.
addData
(
replyVal
);
else
reply
.
addData
(
reg
);
}
// Если мы в начале проверили, что запрос входит в разрешёный диапазон
// то теоретически этой ситуации возникнуть не может...
if
(
reply
.
count
<
query
.
count
)
{
cerr
<<
"(readOutputRegisters): Получили меньше чем ожидали. "
<<
" Запросили "
<<
query
.
count
<<
" получили "
<<
reply
.
count
<<
endl
;
}
return
ModbusRTU
::
erNoError
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
forceMultipleCoils
(
ModbusRTU
::
ForceCoilsMessage
&
query
,
ModbusRTU
::
ForceCoilsRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(forceMultipleCoils): "
<<
query
<<
endl
;
ModbusRTU
::
mbErrCode
ret
=
ModbusRTU
::
erNoError
;
reply
.
set
(
query
.
start
,
query
.
quant
);
lastForceCoilsQ
=
query
;
return
ret
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
writeOutputRegisters
(
ModbusRTU
::
WriteOutputMessage
&
query
,
ModbusRTU
::
WriteOutputRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(writeOutputRegisters): "
<<
query
<<
endl
;
ModbusRTU
::
mbErrCode
ret
=
ModbusRTU
::
erNoError
;
reply
.
set
(
query
.
start
,
query
.
quant
);
lastWriteOutputQ
=
query
;
return
ret
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
writeOutputSingleRegister
(
ModbusRTU
::
WriteSingleOutputMessage
&
query
,
ModbusRTU
::
WriteSingleOutputRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(writeOutputSingleRegisters): "
<<
query
<<
endl
;
ModbusRTU
::
mbErrCode
ret
=
ModbusRTU
::
erNoError
;
lastWriteOutputSingleRegister
=
(
signed
short
)
query
.
data
;
reply
.
set
(
query
.
start
,
query
.
data
);
return
ret
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
forceSingleCoil
(
ModbusRTU
::
ForceSingleCoilMessage
&
query
,
ModbusRTU
::
ForceSingleCoilRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(forceSingleCoil): "
<<
query
<<
endl
;
ModbusRTU
::
mbErrCode
ret
=
ModbusRTU
::
erNoError
;
forceSingleCoilCmd
=
query
.
cmd
();
reply
.
set
(
query
.
start
,
query
.
cmd
());
return
ret
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
journalCommand
(
ModbusRTU
::
JournalCommandMessage
&
query
,
ModbusRTU
::
JournalCommandRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(journalCommand): "
<<
query
<<
endl
;
switch
(
query
.
cmd
)
{
case
0
:
{
if
(
reply
.
setData
(
(
ModbusRTU
::
ModbusByte
*
)(
&
query
.
num
),
sizeof
(
query
.
num
)
)
)
return
ModbusRTU
::
erNoError
;
return
ModbusRTU
::
erPacketTooLong
;
}
break
;
case
1
:
{
ModbusRTU
::
JournalCommandRetOK
::
set
(
reply
,
1
,
0
);
return
ModbusRTU
::
erNoError
;
}
break
;
case
2
:
// write по modbus пока не поддерживается
default
:
{
// формируем ответ
ModbusRTU
::
JournalCommandRetOK
::
set
(
reply
,
2
,
1
);
return
ModbusRTU
::
erNoError
;
}
break
;
}
return
ModbusRTU
::
erTimeOut
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
setDateTime
(
ModbusRTU
::
SetDateTimeMessage
&
query
,
ModbusRTU
::
SetDateTimeRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(setDateTime): "
<<
query
<<
endl
;
// подтверждаем сохранение
// в ответе возвращаем установленное время...
ModbusRTU
::
SetDateTimeRetMessage
::
cpy
(
reply
,
query
);
return
ModbusRTU
::
erNoError
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
remoteService
(
ModbusRTU
::
RemoteServiceMessage
&
query
,
ModbusRTU
::
RemoteServiceRetMessage
&
reply
)
{
cerr
<<
"(remoteService): "
<<
query
<<
endl
;
return
ModbusRTU
::
erOperationFailed
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
fileTransfer
(
ModbusRTU
::
FileTransferMessage
&
query
,
ModbusRTU
::
FileTransferRetMessage
&
reply
)
{
if
(
verbose
)
cout
<<
"(fileTransfer): "
<<
query
<<
endl
;
return
ModbusRTU
::
erOperationFailed
;
#if 0
FileList::iterator it = flist.find(query.numfile);
if( it == flist.end() )
return ModbusRTU::erBadDataValue;
std::string fname(it->second);
int fd = open(fname.c_str(), O_RDONLY | O_NONBLOCK );
if( fd <= 0 )
{
dwarn << "(fileTransfer): open '" << fname << "' with error: " << strerror(errno) << endl;
return ModbusRTU::erOperationFailed;
}
int seek = query.numpacket*ModbusRTU::FileTransferRetMessage::MaxDataLen;
(void)lseek(fd,seek,SEEK_SET);
ModbusRTU::ModbusByte buf[ModbusRTU::FileTransferRetMessage::MaxDataLen];
int ret = ::read(fd,&buf,sizeof(buf));
if( ret < 0 )
{
dwarn << "(fileTransfer): read from '" << fname << "' with error: " << strerror(errno) << endl;
close(fd);
return ModbusRTU::erOperationFailed;
}
// вычисляем общий размер файла в "пакетах"
// (void)lseek(fd,0,SEEK_END);
// int numpacks = lseek(fd,0,SEEK_CUR) / ModbusRTU::FileTransferRetMessage::MaxDataLen;
// if( lseek(fd,0,SEEK_CUR) % ModbusRTU::FileTransferRetMessage::MaxDataLen )
// numpacks++;
struct stat fs;
if( fstat(fd,&fs) < 0 )
{
dwarn << "(fileTransfer): fstat for '" << fname << "' with error: " << strerror(errno) << endl;
close(fd);
return ModbusRTU::erOperationFailed;
}
close(fd);
// cerr << "******************* ret = " << ret << " fsize = " << fs.st_size
// << " maxsize = " << ModbusRTU::FileTransferRetMessage::MaxDataLen << endl;
int numpacks = fs.st_size / ModbusRTU::FileTransferRetMessage::MaxDataLen;
if( fs.st_size % ModbusRTU::FileTransferRetMessage::MaxDataLen )
numpacks++;
if( !reply.set(query.numfile,numpacks,query.numpacket,buf,ret) )
{
dwarn << "(fileTransfer): set date failed..." << endl;
return ModbusRTU::erOperationFailed;
}
return ModbusRTU::erNoError;
#endif
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
diagnostics
(
ModbusRTU
::
DiagnosticMessage
&
query
,
ModbusRTU
::
DiagnosticRetMessage
&
reply
)
{
if
(
query
.
subf
==
ModbusRTU
::
subEcho
)
{
reply
=
query
;
return
ModbusRTU
::
erNoError
;
}
if
(
query
.
subf
==
ModbusRTU
::
dgBusErrCount
)
{
reply
=
query
;
reply
.
data
[
0
]
=
10
;
return
ModbusRTU
::
erNoError
;
}
if
(
query
.
subf
==
ModbusRTU
::
dgMsgSlaveCount
||
query
.
subf
==
ModbusRTU
::
dgBusMsgCount
)
{
reply
=
query
;
reply
.
data
[
0
]
=
10
;
return
ModbusRTU
::
erNoError
;
}
if
(
query
.
subf
==
ModbusRTU
::
dgSlaveNAKCount
)
{
reply
=
query
;
reply
.
data
[
0
]
=
10
;
return
ModbusRTU
::
erNoError
;
}
if
(
query
.
subf
==
ModbusRTU
::
dgClearCounters
)
{
reply
=
query
;
return
ModbusRTU
::
erNoError
;
}
return
ModbusRTU
::
erOperationFailed
;
}
// -------------------------------------------------------------------------
ModbusRTU
::
mbErrCode
MBTCPTestServer
::
read4314
(
ModbusRTU
::
MEIMessageRDI
&
query
,
ModbusRTU
::
MEIMessageRetRDI
&
reply
)
{
if
(
verbose
)
cout
<<
"(read4314): "
<<
query
<<
endl
;
if
(
query
.
devID
<=
rdevMinNum
||
query
.
devID
>=
rdevMaxNum
)
return
erOperationFailed
;
if
(
query
.
objID
==
rdiVendorName
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevBasicDevice
;
reply
.
addData
(
query
.
objID
,
"etersoft"
);
// reply.addData(rdiProductCode, PACKAGE_NAME);
// reply.addData(rdiMajorMinorRevision,PACKAGE_VERSION);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiProductCode
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevBasicDevice
;
reply
.
addData
(
query
.
objID
,
PACKAGE_NAME
);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiMajorMinorRevision
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevBasicDevice
;
reply
.
addData
(
query
.
objID
,
PACKAGE_VERSION
);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiVendorURL
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevRegularDevice
;
reply
.
addData
(
query
.
objID
,
PACKAGE_URL
);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiProductName
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevRegularDevice
;
reply
.
addData
(
query
.
objID
,
PACKAGE_NAME
);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiModelName
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevRegularDevice
;
reply
.
addData
(
query
.
objID
,
"MBTCPSlaveEcho"
);
return
erNoError
;
}
else
if
(
query
.
objID
==
rdiUserApplicationName
)
{
reply
.
mf
=
0xFF
;
reply
.
conformity
=
rdevRegularDevice
;
reply
.
addData
(
query
.
objID
,
"uniset-mbtcpslave-echo"
);
return
erNoError
;
}
return
ModbusRTU
::
erBadDataAddress
;
}
// -------------------------------------------------------------------------
extensions/ModbusMaster/tests/MBTCPTestServer.h
0 → 100644
View file @
943e9dc2
#ifndef MBTCPTestServer_H_
#define MBTCPTestServer_H_
// -------------------------------------------------------------------------
#include <string>
#include <atomic>
#include "ThreadCreator.h"
#include "modbus/ModbusTCPServerSlot.h"
// -------------------------------------------------------------------------
/*! Реализация MBTCPTestServer для тестирования */
class
MBTCPTestServer
{
public
:
MBTCPTestServer
(
ModbusRTU
::
ModbusAddr
myaddr
,
const
std
::
string
&
inetaddr
,
int
port
=
502
,
bool
verbose
=
false
);
~
MBTCPTestServer
();
inline
void
setVerbose
(
bool
state
)
{
verbose
=
state
;
}
inline
void
setReply
(
long
val
)
{
replyVal
=
val
;
}
inline
void
setIgnoreAddrMode
(
bool
state
)
{
if
(
sslot
)
sslot
->
setIgnoreAddrMode
(
state
);
}
void
runThread
();
/*!< запуск с отдельным потоком */
void
execute
();
/*!< основной цикл работы */
void
setLog
(
DebugStream
&
dlog
);
inline
bool
isRunning
(){
return
isrunning
;
}
inline
bool
getForceSingleCoilCmd
(){
return
forceSingleCoilCmd
;
}
inline
int
getLastWriteOutputSingleRegister
(){
return
lastWriteOutputSingleRegister
;
}
inline
ModbusRTU
::
ForceCoilsMessage
getLastForceCoilsQ
(){
return
lastForceCoilsQ
;
}
inline
ModbusRTU
::
WriteOutputMessage
getLastWriteOutput
(){
return
lastWriteOutputQ
;
}
protected
:
// действия при завершении работы
void
sigterm
(
int
signo
);
/*! обработка 0x01 */
ModbusRTU
::
mbErrCode
readCoilStatus
(
ModbusRTU
::
ReadCoilMessage
&
query
,
ModbusRTU
::
ReadCoilRetMessage
&
reply
);
/*! обработка 0x02 */
ModbusRTU
::
mbErrCode
readInputStatus
(
ModbusRTU
::
ReadInputStatusMessage
&
query
,
ModbusRTU
::
ReadInputStatusRetMessage
&
reply
);
/*! обработка 0x03 */
ModbusRTU
::
mbErrCode
readOutputRegisters
(
ModbusRTU
::
ReadOutputMessage
&
query
,
ModbusRTU
::
ReadOutputRetMessage
&
reply
);
/*! обработка 0x04 */
ModbusRTU
::
mbErrCode
readInputRegisters
(
ModbusRTU
::
ReadInputMessage
&
query
,
ModbusRTU
::
ReadInputRetMessage
&
reply
);
/*! обработка 0x05 */
ModbusRTU
::
mbErrCode
forceSingleCoil
(
ModbusRTU
::
ForceSingleCoilMessage
&
query
,
ModbusRTU
::
ForceSingleCoilRetMessage
&
reply
);
/*! обработка 0x0F */
ModbusRTU
::
mbErrCode
forceMultipleCoils
(
ModbusRTU
::
ForceCoilsMessage
&
query
,
ModbusRTU
::
ForceCoilsRetMessage
&
reply
);
/*! обработка 0x10 */
ModbusRTU
::
mbErrCode
writeOutputRegisters
(
ModbusRTU
::
WriteOutputMessage
&
query
,
ModbusRTU
::
WriteOutputRetMessage
&
reply
);
/*! обработка 0x06 */
ModbusRTU
::
mbErrCode
writeOutputSingleRegister
(
ModbusRTU
::
WriteSingleOutputMessage
&
query
,
ModbusRTU
::
WriteSingleOutputRetMessage
&
reply
);
ModbusRTU
::
mbErrCode
diagnostics
(
ModbusRTU
::
DiagnosticMessage
&
query
,
ModbusRTU
::
DiagnosticRetMessage
&
reply
);
ModbusRTU
::
mbErrCode
read4314
(
ModbusRTU
::
MEIMessageRDI
&
query
,
ModbusRTU
::
MEIMessageRetRDI
&
reply
);
/*! обработка запросов на чтение ошибок */
ModbusRTU
::
mbErrCode
journalCommand
(
ModbusRTU
::
JournalCommandMessage
&
query
,
ModbusRTU
::
JournalCommandRetMessage
&
reply
);
/*! обработка запроса на установку времени */
ModbusRTU
::
mbErrCode
setDateTime
(
ModbusRTU
::
SetDateTimeMessage
&
query
,
ModbusRTU
::
SetDateTimeRetMessage
&
reply
);
/*! обработка запроса удалённого сервиса */
ModbusRTU
::
mbErrCode
remoteService
(
ModbusRTU
::
RemoteServiceMessage
&
query
,
ModbusRTU
::
RemoteServiceRetMessage
&
reply
);
ModbusRTU
::
mbErrCode
fileTransfer
(
ModbusRTU
::
FileTransferMessage
&
query
,
ModbusRTU
::
FileTransferRetMessage
&
reply
);
/*! интерфейс ModbusSlave для обмена по RS */
ModbusTCPServerSlot
*
sslot
;
ModbusRTU
::
ModbusAddr
addr
;
/*!< адрес данного узла */
bool
verbose
;
long
replyVal
;
bool
forceSingleCoilCmd
;
int
lastWriteOutputSingleRegister
;
ModbusRTU
::
ForceCoilsMessage
lastForceCoilsQ
;
ModbusRTU
::
WriteOutputMessage
lastWriteOutputQ
;
#if 0
typedef std::map<ModbusRTU::mbErrCode,unsigned int> ExchangeErrorMap;
ExchangeErrorMap errmap; /*!< статистика обмена */
ModbusRTU::mbErrCode prev;
// можно было бы сделать unsigned, но аналоговые датчики у нас имеют
// тип long. А это число передаётся в графику в виде аналогового датчика
long askCount; /*!< количество принятых запросов */
typedef std::map<int,std::string> FileList;
FileList flist;
#endif
private
:
ThreadCreator
<
MBTCPTestServer
>*
thr
;
std
::
atomic_bool
isrunning
;
};
// -------------------------------------------------------------------------
#endif // MBTCPTestServer_H_
// -------------------------------------------------------------------------
extensions/ModbusMaster/tests/mbmaster-test-configure.xml
View file @
943e9dc2
...
...
@@ -27,7 +27,7 @@
<settings>
<SharedMemory
name=
"SharedMemory"
shmID=
"SharedMemory"
/>
<MBTCPMaster1
name=
"MBTCPMaster1"
>
<MBTCPMaster1
name=
"MBTCPMaster1"
exchangeModeID=
"MBTCPMaster_Mode_AS"
>
<DeviceList>
<item
addr=
"0x01"
invert=
"1"
respondSensor=
"Slave_Not_Respond_S"
timeout=
"1000"
/>
</DeviceList>
...
...
@@ -49,6 +49,7 @@
<sensors
name=
"Sensors"
>
<item
id=
"10"
iotype=
"DI"
name=
"Slave_Not_Respond_S"
textname=
"Наличие связи со Slave"
/>
<item
id=
"11"
iotype=
"AI"
name=
"MBTCPMaster_Mode_AS"
textname=
"Режим работы MBTCPMaster"
/>
<item
id=
"1000"
mb=
"1"
mbtype=
"rtu"
mbaddr=
"0x01"
mbreg=
"1"
mbfunc=
"0x01"
iotype=
"DI"
name=
"TestReadCoil1_S"
textname=
"Тестовый регистр для ReadCoil"
/>
<item
id=
"1001"
mb=
"1"
mbtype=
"rtu"
mbaddr=
"0x01"
mbreg=
"2"
mbfunc=
"0x01"
iotype=
"DI"
name=
"TestReadCoil2_S"
textname=
"Тестовый регистр для ReadCoil"
/>
...
...
extensions/ModbusMaster/tests/test_mbtcpmaster.cc
View file @
943e9dc2
...
...
@@ -17,8 +17,9 @@ static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static
shared_ptr
<
MBTCPTestServer
>
mbs
;
static
shared_ptr
<
UInterface
>
ui
;
static
ObjectId
mbID
=
6004
;
// MBTCPMaster1
static
int
polltime
=
30
0
;
// conf->getArgInt("--mbtcp-polltime");
static
int
polltime
=
5
0
;
// conf->getArgInt("--mbtcp-polltime");
static
ObjectId
slaveNotRespond
=
10
;
// Slave_Not_Respond_S
static
const
ObjectId
exchangeMode
=
11
;
// MBTCPMaster_Mode_AS
// -----------------------------------------------------------------------------
static
void
InitTest
()
{
...
...
@@ -355,43 +356,185 @@ TEST_CASE("MBTCPMaster: 0x10 (write register outputs or memories)","[modbus][0x1
}
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x14 (read file record"
,
"[modbus][0x14][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: exchangeMode"
,
"[modbus][exchangemode][mbmaster][mbtcpmaster]"
)
{
InitTest
();
SECTION
(
"None"
)
{
SECTION
(
"read"
)
{
mbs
->
setReply
(
10
);
msleep
(
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
==
10
);
}
SECTION
(
"write"
)
{
ui
->
setValue
(
1018
,
10
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
10
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
==
10
);
}
}
SECTION
(
"WriteOnly"
)
{
// emWriteOnly=1, /*!< "только посылка данных" (работают только write-функции) */
ui
->
setValue
(
exchangeMode
,
MBExchange
::
emWriteOnly
);
REQUIRE
(
ui
->
getValue
(
exchangeMode
)
==
MBExchange
::
emWriteOnly
);
SECTION
(
"read"
)
{
mbs
->
setReply
(
150
);
msleep
(
2
*
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
!=
150
);
mbs
->
setReply
(
-
10
);
msleep
(
2
*
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
!=
-
10
);
REQUIRE
(
ui
->
getValue
(
1003
)
!=
150
);
}
SECTION
(
"write"
)
{
ui
->
setValue
(
1018
,
150
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
150
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
==
150
);
ui
->
setValue
(
1018
,
155
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
155
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
==
155
);
}
}
SECTION
(
"ReadOnly"
)
{
// emReadOnly=2, /*!< "только чтение" (работают только read-функции) */
ui
->
setValue
(
exchangeMode
,
MBExchange
::
emReadOnly
);
REQUIRE
(
ui
->
getValue
(
exchangeMode
)
==
MBExchange
::
emReadOnly
);
SECTION
(
"read"
)
{
mbs
->
setReply
(
150
);
msleep
(
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
==
150
);
mbs
->
setReply
(
-
100
);
msleep
(
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
==
-
100
);
}
SECTION
(
"write"
)
{
ui
->
setValue
(
1018
,
50
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
50
);
msleep
(
2
*
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
!=
50
);
ui
->
setValue
(
1018
,
55
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
55
);
msleep
(
2
*
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
!=
55
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
!=
50
);
}
}
SECTION
(
"SkipSaveToSM"
)
{
// emSkipSaveToSM=3, /*!< не писать данные в SM (при этом работают и read и write функции */
ui
->
setValue
(
exchangeMode
,
MBExchange
::
emSkipSaveToSM
);
REQUIRE
(
ui
->
getValue
(
exchangeMode
)
==
MBExchange
::
emSkipSaveToSM
);
SECTION
(
"read"
)
{
mbs
->
setReply
(
50
);
msleep
(
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
!=
50
);
}
SECTION
(
"write"
)
{
// а write работает в этом режиме.. (а чем отличается от writeOnly?)
ui
->
setValue
(
1018
,
60
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
60
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
==
60
);
ui
->
setValue
(
1018
,
65
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
65
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
==
65
);
}
}
SECTION
(
"SkipExchange"
)
{
// emSkipExchange=4 /*!< отключить обмен */
ui
->
setValue
(
exchangeMode
,
MBExchange
::
emSkipExchange
);
REQUIRE
(
ui
->
getValue
(
exchangeMode
)
==
MBExchange
::
emSkipExchange
);
SECTION
(
"read"
)
{
mbs
->
setReply
(
70
);
msleep
(
polltime
+
100
);
REQUIRE
(
ui
->
getValue
(
1003
)
!=
70
);
}
SECTION
(
"write"
)
{
ui
->
setValue
(
1018
,
70
);
REQUIRE
(
ui
->
getValue
(
1018
)
==
70
);
msleep
(
polltime
+
100
);
REQUIRE
(
mbs
->
getLastWriteOutputSingleRegister
()
!=
70
);
}
SECTION
(
"check connection"
)
{
msleep
(
1100
);
CHECK
(
ui
->
getValue
(
slaveNotRespond
)
==
1
);
ui
->
setValue
(
exchangeMode
,
MBExchange
::
emNone
);
REQUIRE
(
ui
->
getValue
(
exchangeMode
)
==
MBExchange
::
emNone
);
msleep
(
1100
);
CHECK
(
ui
->
getValue
(
slaveNotRespond
)
==
0
);
}
}
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: iobase functions"
,
"[modbus][iobase][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of 'iobase functions'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: reconnection"
,
"[modbus][reconnection][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of 'reconnection'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x14 (read file record)"
,
"[modbus][0x14][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x14'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x15 (write file record"
,
"[modbus][0x15][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x15 (write file record
)
"
,
"[modbus][0x15][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x15'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x2B (Modbus Encapsulated Interface"
,
"[modbus][0x2B][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x2B (Modbus Encapsulated Interface
/ MEI /)
"
,
"[modbus][0x2B][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x2B'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x50 (set date and time"
,
"[modbus][0x50][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x50 (set date and time
)
"
,
"[modbus][0x50][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x50'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x53 (call remote service"
,
"[modbus][0x53][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x53 (call remote service
)
"
,
"[modbus][0x53][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x53'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x65 (read,write,delete alarm journal"
,
"[modbus][0x65][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x65 (read,write,delete alarm journal
)
"
,
"[modbus][0x65][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x65'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: 0x66 (file transfer"
,
"[modbus][0x66][mbmaster][mbtcpmaster]"
)
TEST_CASE
(
"MBTCPMaster: 0x66 (file transfer
)
"
,
"[modbus][0x66][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of '0x66'..not yet.. "
);
}
// -----------------------------------------------------------------------------
TEST_CASE
(
"MBTCPMaster: exchangeMode"
,
"[modbus][exchangemode][mbmaster][mbtcpmaster]"
)
{
WARN
(
"Test of 'exchangeMode'..not yet.. "
);
}
// -----------------------------------------------------------------------------
extensions/ModbusMaster/tests/tests_with_sm.cc
View file @
943e9dc2
...
...
@@ -33,6 +33,7 @@ int main(int argc, char* argv[] )
{
auto
conf
=
uniset_init
(
argc
,
argv
);
conf
->
initDebug
(
dlog
,
"dlog"
);
dlog
.
logFile
(
"./smtest.log"
);
bool
apart
=
findArgParam
(
"--apart"
,
argc
,
argv
)
!=
-
1
;
...
...
extensions/ModbusMaster/tests/tests_with_sm.sh
View file @
943e9dc2
...
...
@@ -15,7 +15,8 @@ cd -
--mbtcp-filter-value
1
\
--mbtcp-gateway-iaddr
localhost
\
--mbtcp-gateway-port
20048
\
--mbtcp-polltime
300
--mbtcp-recv-timeout
1000
--mbtcp-polltime
50
--mbtcp-recv-timeout
1000
#--dlog-add-levels any
#--mbtcp-force-out 1
#--dlog-add-levels any
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