Imports System.IO.Ports Imports System.Threading Imports NT_CAM_Controller.SendNode Public Class CommunicationProtocol '流程列表 Public Property FlowList As List(Of (String, SendNode)) Public IsFlowList As Boolean '执行流程任务线程 Public Property FlowThread As Task Public IsFlowThread As Boolean Public G_RichTextPrint As RichTextPrint Public G_Transmitter As SerialPort Public ControlDic As New Dictionary(Of Integer, Control) Sub New(RichTextPrint As RichTextPrint, gTransmitter As SerialPort) FlowList = New List(Of (String, SendNode)) G_RichTextPrint = RichTextPrint G_Transmitter = gTransmitter '初始化FlowThread IsFlowThread = True FlowThread = New Task(AddressOf FlowThreadRun) FlowThread.Start() IsFlowList = False ControlDic = New Dictionary(Of Integer, Control) End Sub '添加控件列表 Sub AddControlDic(ControlName As Integer, Control As Control) If IsNothing(ControlDic) Then ControlDic = New Dictionary(Of Integer, Control) If ControlDic.ContainsKey(ControlName) Then ControlDic.Item(ControlName) = Control Else ControlDic.Add(ControlName, Control) End If End Sub '关闭 Sub Close() If FlowThread Is Nothing OrElse Not FlowThread.IsCompleted Then Return FlowThread.Dispose() End Sub '关闭线程 Sub CloseThread() If FlowThread Is Nothing OrElse Not FlowThread.IsCompleted Then Return FlowThread.Dispose() End Sub '设置IsFlowThread Sub SetIsFlowThread(mIsFlowThread As Boolean) Me.IsFlowThread = mIsFlowThread End Sub Sub setIsFlowList(mIsFlowList As Boolean) Me.IsFlowList = mIsFlowList End Sub Public Function getIsFlowList() As Boolean Return False Return Me.IsFlowList End Function Public Function getIsFlowList1() As Boolean Return Me.IsFlowList End Function '执行流程任务 Sub FlowThreadRun() '流程节点执行状态 Dim isnode As Boolean Dim nli As New List(Of Integer) While IsFlowThread Thread.Sleep(1) If IsNothing(FlowList) OrElse FlowList.Count = 0 Then '延时100ms Thread.Sleep(100) Else If IsFlowList Then nli.Clear() Dim FlowListCount As Integer = FlowList.Count Console.WriteLine("FlowListCount:" & FlowListCount) ' For Each node In FlowList For i As Integer = 0 To FlowListCount - 1 If Not IsFlowList Then Exit For End If Dim node As (String, SendNode) = FlowList(i) '判断本包是否超时接收 If (node.Item2.SendCount >= node.Item2.MaxResendCount) OrElse node.Item2.RecvStatus = 1 Then nli.Add(i) Continue For End If If IsFlowThread = False Then Exit For While node.Item2.RecvStatus = SendNode.RecvStatusEnum.None If Not node.Item2.IsRecvData Then node.Item2.RecvRefresh(Nothing) End If If IsFlowThread = False Then Exit For '判断是什么类型命令 If node.Item2.CommandType = 0 Then '系统命令 isnode = SystemCommandSelector(node.Item1, node.Item2) If isnode = False Then 'MsgBox(node.Item2.TipInfo) G_RichTextPrint.AddQueue(New RichTextNodeConfig(node.Item2.TipInfo, Color.Red), 1) 'IsFlowList = False Exit While Else Exit While End If Else '自定义命令 isnode = CustomCommandSelector(node.Item1, node.Item2) If isnode = False Then nli.Add(i) 'MsgBox(node.Item2.TipInfo) 'G_RichTextPrint.AddQueue(New RichTextNodeConfig(node.Item2.TipInfo, Color.Red), 1) 'IsFlowList = False 'Else Exit While Else 'Exit While End If End If End While Next '从大到小删除 For Each i In nli.OrderByDescending(Function(x) x) If Not IsFlowList Then Exit For End If FlowList.RemoveAt(i) Next IsFlowList = False Console.WriteLine($"流程节点数量:{FlowList.Count}") End If End If End While End Sub '系统命令选择器 Public Function SystemCommandSelector(nodename As String, ByRef mSendNode As SendNode) As Boolean If mSendNode.SendData.Length > 0 Then Select Case mSendNode.SendData(0) Case 1 '系统延时 If mSendNode.SendData.Length > 1 Then mSendNode.ResendRefresh() Thread.Sleep(mSendNode.SendData(1)) mSendNode.RecvRefresh({mSendNode.SendData(1)}) mSendNode.SetTipInfo("执行延时完成!") Return True Else mSendNode.SetTipInfo($"{nodename}参数异常!") Return False End If End Select Else mSendNode.SetTipInfo("系统命令参数异常!") Return False End If End Function '自定义命令选择器 Public Function CustomCommandSelector(nodename As String, ByRef mSendNode As SendNode) As Boolean Dim sendbuf As Byte() If mSendNode.SendStatus = SendNode.SendStatusEnum.None Then sendbuf = SendPortData1(nodename, mSendNode) If IsNothing(sendbuf) OrElse sendbuf.Length = 0 Then Return False Else Return SendPortData(nodename, mSendNode, sendbuf, G_Transmitter) End If Else '判断节点是否需要重新发送 If mSendNode.NeedResend() Then sendbuf = SendPortData1(nodename, mSendNode) If IsNothing(sendbuf) OrElse sendbuf.Length = 0 Then Return False Else G_RichTextPrint.AddQueue(New RichTextNodeConfig($"第{mSendNode.SendCount}次重发数据", Color.Black), 1) Return SendPortData(nodename, mSendNode, sendbuf, G_Transmitter) End If Else If mSendNode.SendCount < mSendNode.MaxResendCount Then ElseIf mSendNode.SendCount = mSendNode.MaxResendCount Then If mSendNode.SendTime.AddMilliseconds(mSendNode.SendTimeout) < Now Then mSendNode.SendCount = mSendNode.SendCount + 1 Else End If Else mSendNode.RecvStatus = RecvStatusEnum.Timeout mSendNode.SendStatus = SendStatusEnum.Timeout ' IsRuningTest = False '退出流程 'RefreshCaptureText(Color.Red, $"节点:{node.Item1} :发送失败!") G_RichTextPrint.AddQueue(New RichTextNodeConfig($"发数据超时!", Color.Red), 1) mSendNode.SetTipInfo($"发数据超时!") Return False End If End If Return True End If End Function '获取发送数据 Public Function SendPortData1(nodename As String, Mysenddata As SendNode) As Byte() If IsNothing(Mysenddata) OrElse Mysenddata.SendData.Length = 0 Then Return Nothing Return Mysenddata.SendData End Function '发送数据 Public Function SendPortData(nodename As String, ByRef Mysenddata As SendNode, sendBytes As Byte(), mTransmitter As SerialPort) As Boolean If IsNothing(G_Transmitter) OrElse G_Transmitter.IsOpen = False Then G_RichTextPrint.AddQueue(New RichTextNodeConfig("发送器未打开!", Color.Red), 1) Return False End If Try '发送数据 Mysenddata.SetSendData(sendBytes, Mysenddata.SendTimeout) G_RichTextPrint.AddQueue(New RichTextNodeConfig("TX:", Color.Blue, New Font("宋体", 8), Mysenddata.SendData), 1) G_Transmitter.Write(Mysenddata.SendData, 0, Mysenddata.SendData.Length) '发送刷新对应数值 Mysenddata.ResendRefresh() Return True Catch ex As Exception G_RichTextPrint.AddQueue(New RichTextNodeConfig("发送器发送异常!", Color.Red), 1) Return False End Try End Function Public Function SendPortData(sendBytes As Byte(), mTransmitter As SerialPort) As Boolean If IsNothing(G_Transmitter) OrElse G_Transmitter.IsOpen = False Then G_RichTextPrint.AddQueue(New RichTextNodeConfig("发送器未打开!", Color.Red), 1) Return False End If Try '发送数据 G_RichTextPrint.AddQueue(New RichTextNodeConfig("TX:", Color.Blue, New Font("宋体", 8), sendBytes), 1) G_Transmitter.Write(sendBytes, 0, sendBytes.Length) '发送刷新对应数值 Return True Catch ex As Exception G_RichTextPrint.AddQueue(New RichTextNodeConfig("发送器发送异常!", Color.Red), 1) Return False End Try End Function '添加流程节点 Public Function AddFlowNode(nodename As String, Mysenddata As SendNode) As Boolean If FlowList Is Nothing Then Return False FlowList.Add((nodename, Mysenddata)) End Function '清空流程节点 Public Function ClearFlowNode(Optional isclear As Boolean = False) As Boolean If FlowList Is Nothing Then Return False If isclear Then FlowList.Clear() End If 'FlowList.Clear() End Function '处理接收到的数据 Public Function ProcessRecvData(RecvData() As Byte) As Boolean If FlowList Is Nothing Then Return False '判断数据包头是否合法 If NT_CAM.IsDataValid(RecvData) Then If RecvData(3) >= &HB0 Then Dim sendbuf = NT_CAM.PackData(RecvData(3), {0}) SendPortData(sendbuf, G_Transmitter) ElseIf RecvData(3) >= &H10 AndAlso RecvData(3) < &HA0 Then Select Case RecvData(3) Case &H18 Dim sendbuf = NT_CAM.PackData(RecvData(3), {0}) SendPortData(sendbuf, G_Transmitter) Dim mControl As Control = ControlDic.Item(&H18) If RecvData(6) = 0 Then SharedFunction.SetFromUI(mControl, "未连接", Color.Black, Color.Red) ElseIf RecvData(6) = 1 Then SharedFunction.SetFromUI(mControl, "已连接", Color.Black, Color.Green) Else SharedFunction.SetFromUI(mControl, "连接异常", Color.Black, Color.Red) End If Return True Case &H19 Dim mControl As Control = ControlDic.Item(&H19) Dim sendbuf = NT_CAM.PackData(RecvData(3), {0}) SendPortData(sendbuf, G_Transmitter) '获取数据长度 Dim len As Integer = RecvData(5) * 256 + RecvData(4) '判断数据长度是否合法 且长度能够取到 If len > 0 AndAlso len <= RecvData.Length - 6 Then '获取数据 Dim data As Byte() = New Byte(len - 1) {} Array.Copy(RecvData, 6, data, 0, len) '将数组转换为字符串 Dim str As String = SharedFunction.ByteToHexString(data) SharedFunction.SetFromUI(mControl, str, Color.Black, Color.White) End If Return True End Select Dim node As SendNode Dim nextNode As SendNode For i = 0 To FlowList.Count - 1 node = FlowList(i).Item2 If node.SendStatus = SendNode.SendStatusEnum.Send Then If node.RecvStatus = SendNode.RecvStatusEnum.None Then If RecvData(3) = node.SendData(3) Then node.RecvRefresh(RecvData) End If End If End If Next Else Dim node As SendNode Dim nextNode As SendNode For i = 0 To FlowList.Count - 1 node = FlowList(i).Item2 If node.SendStatus = SendNode.SendStatusEnum.Send Then If node.RecvStatus = SendNode.RecvStatusEnum.None Then If RecvData(3) = node.SendData(3) Then node.RecvRefresh(RecvData) End If End If End If Next End If End If End Function End Class Public Class SendNode '命令类型 Public Property CommandType As Integer '0:系统命令,1:自定义命令 '发送时间 Public Property SendTime As DateTime '发送数据 Public Property SendData As Byte() '重发次数 Public Property SendCount As Integer '重发间隔 Public Property SendInterval As Integer '超时时间 Public Property SendTimeout As Integer '发送状态 0:未发送 1:已发送 Public Property SendStatus As Integer '接收状态 Public Property RecvStatus As Integer '接收数据 Public Property RecvDataLisr As List(Of Byte()) '提示信息 Public Property TipInfo As String '最大重 发次数 Public Property MaxResendCount As Integer '是否接收数据 Public Property IsRecvData As Boolean '控件对象 Public Property Control As Control ''' ''' 命令 ''' ''' Sub New(mCommandType As Integer, Optional mMaxResendCoun As Integer = 3) CommandType = mCommandType RecvDataLisr = New List(Of Byte()) MaxResendCount = mMaxResendCoun IsRecvData = True End Sub '设置控件 Sub SetControl(mControl As Control) Control = mControl End Sub '发送状态枚举值 Enum SendStatusEnum '未发送 None = 0 '已发送 Send = 1 '发送超时 Timeout = 2 End Enum '接收状态枚举值 Enum RecvStatusEnum '未接收 None = 0 '已接收 Recv = 1 '接收超时 Timeout = 2 End Enum Sub New(Mysenddata() As Byte) SendData = Mysenddata SendInterval = 0 SendTimeout = 1000 RecvStatus = 0 SendStatus = 0 RecvDataLisr = New List(Of Byte()) End Sub '设置发送数据 Sub SetSendData(Mysenddata() As Byte, Optional gSendTimeout As Integer = 1000) SendData = Mysenddata SendInterval = 0 SendTimeout = gSendTimeout RecvStatus = 0 SendStatus = 0 End Sub '接收数据并添加到接收列表 Sub AddRecvData(RecvData() As Byte) If RecvDataLisr Is Nothing Then RecvDataLisr = New List(Of Byte()) End If RecvDataLisr.Add(RecvData) End Sub '判断需不需要重发 False 不需要重发 True 需要重发 Function NeedResend() As Boolean '如果接收状态为已加收, 则不需要重发 If SendStatus = 1 AndAlso RecvStatus = 1 Then Return False Else '如果发送状态为已发送,则判断是否超时,如果超时则返回True,否则返回False If SendStatus = 1 Then '判断是否到达最大重发次数 If SendCount < MaxResendCount Then If SendTime.AddMilliseconds(SendTimeout) < Now Then Return True Else Return False End If Else 'RecvStatus = RecvStatusEnum.Timeout 'SendStatus = SendStatusEnum.Timeout Return False End If Else Return True End If End If End Function '重发刷新对应数值 Sub ResendRefresh() SendStatus = 1 SendCount += 1 SendTime = Now End Sub '发送刷新对应数值 Sub SendRefresh() SendStatus = 1 SendTime = Now SendCount = 0 End Sub '接收刷新对应数值 Sub RecvRefresh(Mysenddata() As Byte) AddRecvData(Mysenddata) RecvStatus = 1 End Sub '设置提示信息 Sub SetTipInfo(Mysenddata As String) TipInfo = Mysenddata End Sub End Class