Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Thick-Common
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
潘栩锋
Thick-Common
Commits
d7368b50
Commit
d7368b50
authored
Nov 24, 2022
by
潘栩锋
🚴
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改 异步ModbusRTU, 分包使用15ms定时器。
parent
9ca3b355
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
165 additions
and
39 deletions
+165
-39
ModbusRTUAsync.cs
GeneralGommunication/ModbusRTUAsync.cs
+165
-39
No files found.
GeneralGommunication/ModbusRTUAsync.cs
View file @
d7368b50
...
...
@@ -61,11 +61,6 @@ namespace GeneralGommunication
/// </summary>
Modbus_Transaction
currTran
;
/// <summary>
/// currTran 发送后,开始计时
/// </summary>
Stopwatch
stopwatch_timeOut
;
CommSpeedMeasuring
csm
=
new
CommSpeedMeasuring
();
/// <summary>
...
...
@@ -73,39 +68,43 @@ namespace GeneralGommunication
/// </summary>
int
retryCnt
=
0
;
System
.
Timers
.
Timer
timer3d5t
;
//通讯包的 3.5T 时间间隔。 实际只是 15ms定时而已
System
.
Timers
.
Timer
timerTimeOut
;
//等待回复超时
public
ModbusRTUAsync
()
{
Transactions
=
new
List
<
Modbus_Transaction
>();
stopwatch_timeOut
=
new
Stopwatch
();
timer3d5t
=
new
System
.
Timers
.
Timer
();
timer3d5t
.
Interval
=
15
;
//设得再小也没有用。 它只是用系统的15ms定时器触发而已。
timer3d5t
.
AutoReset
=
false
;
//触发一次
timer3d5t
.
Elapsed
+=
Timer3d5t_Elapsed
;
timerTimeOut
=
new
System
.
Timers
.
Timer
();
timerTimeOut
.
Interval
=
500
;
timerTimeOut
.
AutoReset
=
false
;
timerTimeOut
.
Elapsed
+=
TimerTimeOut_Elapsed
;
}
public
void
Init
()
{
private
void
Timer3d5t_Elapsed
(
object
sender
,
System
.
Timers
.
ElapsedEventArgs
e
)
{
ParsePack
();
}
/// <summary>
/// 发送指令的超时判断
/// </summary>
public
void
OnPoll_TimeOut
()
private
void
TimerTimeOut_Elapsed
(
object
sender
,
System
.
Timers
.
ElapsedEventArgs
e
)
{
//TODO 要处理 TimeOut / ParseFuncPack / GetSendMsg 线性同步问题
if
(!
IsConnected
)
return
;
if
(
currTran
==
null
)
return
;
//没有指令
if
(!
stopwatch_timeOut
.
IsRunning
)
return
;
//还没开始发送
if
(
stopwatch_timeOut
.
Elapsed
<
TimeSpan
.
FromSeconds
(
1
))
return
;
//发送到现在,还没到1秒,继续等
if
(
currTran
==
null
)
//没有数据需要发送
return
;
//大于1秒也没回复,异常
//重试3次
retryCnt
++;
stopwatch_timeOut
.
Stop
();
//停止,等下次发送
if
(
retryCnt
>=
3
)
{
...
...
@@ -119,6 +118,10 @@ namespace GeneralGommunication
}
else
{
//重新把指令放回队列
Transactions
.
Insert
(
0
,
currTran
);
currTran
=
null
;
//再发一次指令
SendMsgEvent
?.
Invoke
(
this
);
}
...
...
@@ -127,6 +130,10 @@ namespace GeneralGommunication
public
void
RecMsg
(
byte
[]
recBuf
)
{
IsConnected
=
true
;
//停止超时检查
timerTimeOut
.
Stop
();
csm
.
IncRec
(
recBuf
.
Count
());
currPack
.
AddRange
(
recBuf
);
if
(
logger
.
IsDebugEnabled
)
{
...
...
@@ -134,8 +141,9 @@ namespace GeneralGommunication
logger
.
Debug
(
$"REC
{
msg
}
"
);
}
ParsePack
();
//OnPoll_TimeOut();
//15ms后再处理。
timer3d5t
.
Stop
();
timer3d5t
.
Start
();
}
/// <summary>
...
...
@@ -161,8 +169,7 @@ namespace GeneralGommunication
else
{
//发送出去中,等待回复
if
(
stopwatch_timeOut
.
IsRunning
)
return
null
;
//已经发送了,计时器都启动了
return
null
;
}
...
...
@@ -179,9 +186,8 @@ namespace GeneralGommunication
//msg = bytes2hex(tran.sendBuf);
//logger.Debug($"SEND {msg}");
}
//开始计时
stopwatch_timeOut
.
Res
tart
();
timerTimeOut
.
S
tart
();
return
tran
.
sendBuf
.
ToArray
();
}
...
...
@@ -192,7 +198,8 @@ namespace GeneralGommunication
public
void
ResetMsg
()
{
currTran
=
null
;
stopwatch_timeOut
.
Stop
();
timer3d5t
.
Stop
();
timerTimeOut
.
Stop
();
csm
.
Reset
();
IsConnected
=
false
;
Transactions
.
Clear
();
...
...
@@ -209,11 +216,118 @@ namespace GeneralGommunication
}
///// <summary>
///// 包解析
///// </summary>
///// <param name="datas"></param>
//protected void ParsePack()
//{
// if (currTran == null)
// {
// //没有请求。。。
// currPack.Clear();
// return;
// }
// if (currPack.Count() < 3)
// {
// //数据太少
// return;
// }
// if (currPack[0] != currTran.deviceNo)
// {
// logger.Error($"ACK 接收的SLAVE地址{currPack[0]}与发送的{currTran.deviceNo}不一致");
// ErrCnt++;
// currPack.Clear();
// return;
// }
// if (currPack[1] != currTran.func)
// {
// logger.Error($"ACK 错误码:{currPack[1]} 异常码:{currPack[2]}");
// ErrCnt++;
// currPack.Clear();
// return;
// }
// if (currPack.Count() < currTran.expRecBytes)
// return;//数据还没收完
// UInt16 crc = currPack.CRC16(0, currTran.expRecBytes - 2);
// UInt16 rec_crc = currPack.ToUInt16_Little_Endian(currTran.expRecBytes - 2);
// if (crc != rec_crc)
// {
// logger.Error($"ACK 指令码:{currTran.func:X2} CRC 校验出错 接收:{rec_crc:X4} 计算:{crc:X4}");
// ErrCnt++;
// currPack.Clear();
// return;
// }
// //成功解析出一个包
// currTran.funcData.AddRange(currPack.Skip(2).Take(currTran.expRecBytes - 4));
// csm.IncPack(1);
// currPack.Clear();
// //收到数据,停止超时检测
// timerTimeOut.Stop();
// switch (currTran.func)
// {
// case 0x03:
// {
// List<UInt16> values = new List<UInt16>();
// int index = 1;
// while (index < currTran.funcData.Count())
// {
// values.Add(currTran.funcData.ToUInt16_Big_Endian(index));
// index += 2;
// }
// currTran.retData = currTran.parse16FuncPack(values);
// }
// break;
// }
// if (logger.IsDebugEnabled)
// {
// if (currTran.retData == null)
// logger.Debug($"ACK");
// else
// logger.Debug($"ACK {Newtonsoft.Json.JsonConvert.SerializeObject(currTran.retData)}");
// }
// //有很多指令是没有回复数据的, 回调只是通知 指令已经执行了而已
// //调用回调
// if (currTran.asyncDelegate != null)
// {
// if (Dispatcher != null)//线程同步执行
// {
// Dispatcher.BeginInvoke(currTran.asyncDelegate, currTran.asyncContext, currTran.retData);
// }
// else
// {
// currTran.asyncDelegate.Invoke(currTran.asyncContext, currTran.retData);
// }
// }
// //空出当前交易位置
// currTran = null;
// if (Transactions.Count() > 0)
// {
// //队列还有需要发送的指令,通知外部获取指令发送
// SendMsgEvent?.Invoke(this);
// }
//}
/// <summary>
/// 包解析
///
已经收完一份数据,不会再有更多,
包解析
/// </summary>
/// <param name="datas"></param>
protected
void
ParsePack
()
void
ParsePack
()
{
if
(
currTran
==
null
)
{
...
...
@@ -224,7 +338,11 @@ namespace GeneralGommunication
if
(
currPack
.
Count
()
<
3
)
{
//数据太少
//异常 数据太少 通知重发
logger
.
Error
(
$"ACK 接收数据小于3个byte"
);
ErrCnt
++;
currPack
.
Clear
();
TimerTimeOut_Elapsed
(
null
,
null
);
return
;
}
...
...
@@ -233,6 +351,7 @@ namespace GeneralGommunication
logger
.
Error
(
$"ACK 接收的SLAVE地址
{
currPack
[
0
]}
与发送的
{
currTran
.
deviceNo
}
不一致"
);
ErrCnt
++;
currPack
.
Clear
();
TimerTimeOut_Elapsed
(
null
,
null
);
return
;
}
...
...
@@ -241,11 +360,19 @@ namespace GeneralGommunication
logger
.
Error
(
$"ACK 错误码:
{
currPack
[
1
]}
异常码:
{
currPack
[
2
]}
"
);
ErrCnt
++;
currPack
.
Clear
();
TimerTimeOut_Elapsed
(
null
,
null
);
return
;
}
if
(
currPack
.
Count
()
<
currTran
.
expRecBytes
)
return
;
//数据还没收完
{
logger
.
Error
(
$"ACK 数据还没接收完"
);
ErrCnt
++;
currPack
.
Clear
();
TimerTimeOut_Elapsed
(
null
,
null
);
return
;
}
UInt16
crc
=
currPack
.
CRC16
(
0
,
currTran
.
expRecBytes
-
2
);
UInt16
rec_crc
=
currPack
.
ToUInt16_Little_Endian
(
currTran
.
expRecBytes
-
2
);
...
...
@@ -254,6 +381,7 @@ namespace GeneralGommunication
logger
.
Error
(
$"ACK 指令码:
{
currTran
.
func
:
X2
}
CRC 校验出错 接收:
{
rec_crc
:
X4
}
计算:
{
crc
:
X4
}
"
);
ErrCnt
++;
currPack
.
Clear
();
TimerTimeOut_Elapsed
(
null
,
null
);
return
;
}
...
...
@@ -262,8 +390,6 @@ namespace GeneralGommunication
csm
.
IncPack
(
1
);
currPack
.
Clear
();
//停止超时检测
stopwatch_timeOut
.
Stop
();
switch
(
currTran
.
func
)
{
...
...
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