Commit d7368b50 authored by 潘栩锋's avatar 潘栩锋 🚴

修改 异步ModbusRTU, 分包使用15ms定时器。

parent 9ca3b355
......@@ -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.Restart();
timerTimeOut.Start();
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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment